Overview
AVAX Balance
AVAX Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 3,683 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Deploy | 30096058 | 707 days ago | IN | 0 AVAX | 0.03901669 | ||||
Queue | 30008353 | 710 days ago | IN | 0 AVAX | 0.0019739 | ||||
Cast Vote | 30006958 | 710 days ago | IN | 0 AVAX | 0.00134463 | ||||
Cast Vote | 30006941 | 710 days ago | IN | 0 AVAX | 0.00134453 | ||||
Cast Vote | 30006796 | 710 days ago | IN | 0 AVAX | 0.00134553 | ||||
Cast Vote | 30006782 | 710 days ago | IN | 0 AVAX | 0.001345 | ||||
Cast Vote | 30006646 | 710 days ago | IN | 0 AVAX | 0.00134437 | ||||
Cast Vote | 30006523 | 710 days ago | IN | 0 AVAX | 0.00130059 | ||||
Cast Vote | 30006486 | 710 days ago | IN | 0 AVAX | 0.00134474 | ||||
Cast Vote | 30006474 | 710 days ago | IN | 0 AVAX | 0.00134357 | ||||
Cast Vote | 30006448 | 710 days ago | IN | 0 AVAX | 0.00134447 | ||||
Cast Vote | 30006107 | 710 days ago | IN | 0 AVAX | 0.00134402 | ||||
Cast Vote | 30006088 | 710 days ago | IN | 0 AVAX | 0.00134636 | ||||
Cast Vote | 30005541 | 710 days ago | IN | 0 AVAX | 0.00134527 | ||||
Cast Vote | 30005393 | 710 days ago | IN | 0 AVAX | 0.00134384 | ||||
Cast Vote | 30005334 | 710 days ago | IN | 0 AVAX | 0.00134447 | ||||
Cast Vote | 30005290 | 710 days ago | IN | 0 AVAX | 0.00134495 | ||||
Cast Vote | 30005262 | 710 days ago | IN | 0 AVAX | 0.00136593 | ||||
Cast Vote | 30005219 | 710 days ago | IN | 0 AVAX | 0.0013458 | ||||
Cast Vote | 30004668 | 710 days ago | IN | 0 AVAX | 0.00134442 | ||||
Cast Vote | 30004013 | 710 days ago | IN | 0 AVAX | 0.00133985 | ||||
Cast Vote | 30003942 | 710 days ago | IN | 0 AVAX | 0.00134527 | ||||
Cast Vote | 30003883 | 710 days ago | IN | 0 AVAX | 0.00134447 | ||||
Cast Vote | 30001714 | 710 days ago | IN | 0 AVAX | 0.00132235 | ||||
Cast Vote | 29999532 | 710 days ago | IN | 0 AVAX | 0.00134437 |
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
30096058 | 707 days ago | Contract Creation | 0 AVAX |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
CommunityDeployer
Compiler Version
v0.8.9+commit.e5eed63a
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache-2.0 pragma solidity =0.8.9; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "../Factory.sol"; import "../interfaces/IFactory.sol"; import "../interfaces/IVAMM.sol"; import "../interfaces/IMarginEngine.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; /// @notice // we are unable to deploy both the master vamm and the master margin engine in this contract since in that scenario it would // exceed the maximum contract size limit, instead we deploy the master margin engine and master vamm separately and link their addresses // to the community deployer // verify with etherscan contract CommunityDeployer { /// @notice Timelock Period In Seconds, once the deployment is queued, 2 days need to pass in order to make deployment of the Voltz Factory possible uint256 public constant TIMELOCK_PERIOD_IN_SECONDS = 2 days; /// @notice Multisig owner address address public ownerAddress; /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed uint256 public quorumVotes; /// @notice Master Margine Engine of Voltz Protocol IMarginEngine public masterMarginEngine; /// @notice Master VAMM of Voltz Protocol IVAMM public masterVAMM; /// @notice Total number of votes in favour of deploying voltz protocol uint256 public yesVoteCount; /// @notice Total number of votes against the deployment of voltz protocol uint256 public noVoteCount; /// @notice mapping of voltz genesis token ids to a boolean, if true that means the token id has already voted mapping(uint256 => bool) public hasTokenIdVoted; /// @notice voting end block timestamp (once this contract is deployed, voting is considered to be officially started) uint256 public blockTimestampVotingEnd; /// @notice timelock end block timestamp (once the proposal is queued, the timelock period pre-deployment is considered to be officially started) uint256 public blockTimestampTimelockEnd; /// @notice isQueued needs to be true in order for the timelock period to start in advance of the deployment bool public isQueued; /// @notice isDeployed makes sure contract is deploying at most one Factory bool public isDeployed; /// @notice Voltz Factory to be deployed in a scenario where a successful vote is followed by the queue and deployment IFactory public voltzFactory; // Merkle Tree bytes32 public merkleRoot; // This is a packed array of booleans. mapping(uint256 => uint256) private votedBitMap; // This event is triggered whenever a call to cast a vote succeeds event Voted( uint256 index, address account, uint256 numberOfVotes, bool yesVote ); constructor( IVAMM _masterVAMM, IMarginEngine _masterMarginEngine, uint256 _quorumVotes, address _ownerAddress, bytes32 _merkleRoot, uint256 _blockTimestampVotingEnd ) { blockTimestampVotingEnd = _blockTimestampVotingEnd; masterVAMM = _masterVAMM; masterMarginEngine = _masterMarginEngine; quorumVotes = _quorumVotes; ownerAddress = _ownerAddress; merkleRoot = _merkleRoot; } function hasVoted(uint256 index) public view returns (bool) { uint256 votedWordIndex = index / 256; uint256 votedBitIndex = index % 256; uint256 votedWord = votedBitMap[votedWordIndex]; uint256 mask = (1 << votedBitIndex); return votedWord & mask == mask; } function _setVoted(uint256 index) private { uint256 votedWordIndex = index / 256; uint256 votedBitIndex = index % 256; votedBitMap[votedWordIndex] = votedBitMap[votedWordIndex] | (1 << votedBitIndex); } /// @notice Deploy the Voltz Factory by passing the masterVAMM and the masterMarginEngine into the Factory constructor function deploy() external { require(isQueued, "not queued"); require( block.timestamp > blockTimestampTimelockEnd, "timelock is ongoing" ); require(isDeployed == false, "already deployed"); voltzFactory = new Factory(masterMarginEngine, masterVAMM); isDeployed = true; Ownable(address(voltzFactory)).transferOwnership(ownerAddress); } /// @notice Queue the deployment of the Voltz Factory function queue() external { require(block.timestamp > blockTimestampVotingEnd, "voting is ongoing"); require(yesVoteCount >= quorumVotes, "quorum not reached"); require(yesVoteCount > noVoteCount, "no >= yes"); require(isQueued == false, "already queued"); isQueued = true; blockTimestampTimelockEnd = block.timestamp + TIMELOCK_PERIOD_IN_SECONDS; } /// @notice Vote for the proposal to deploy the Voltz Factory contract /// @param _index index of the voter /// @param _numberOfVotes number of voltz genesis nfts held by the msg.sender before the snapshot was taken /// @param _yesVote if this boolean is true then the msg.sender is casting a yes vote, if the boolean is false the msg.sender is casting a no vote /// @param _merkleProof merkle proof that needs to be verified against the merkle root to check the msg.sender against the snapshot function castVote( uint256 _index, uint256 _numberOfVotes, bool _yesVote, bytes32[] calldata _merkleProof ) external { require( block.timestamp <= blockTimestampVotingEnd, "voting period over" ); // check if msg.sender has already voted require(!hasVoted(_index), "duplicate vote"); // verify the merkle proof bytes32 _node = keccak256( abi.encodePacked(_index, msg.sender, _numberOfVotes) ); require( MerkleProof.verify(_merkleProof, merkleRoot, _node), "invalid merkle proof" ); // mark hasVoted _setVoted(_index); // cast the vote if (_yesVote) { yesVoteCount += _numberOfVotes; } else { noVoteCount += _numberOfVotes; } // emit an event emit Voted(_index, msg.sender, _numberOfVotes, _yesVote); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.0; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol) pragma solidity ^0.8.0; import "../Proxy.sol"; import "./ERC1967Upgrade.sol"; /** * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an * implementation address that can be changed. This address is stored in storage in the location specified by * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the * implementation behind the proxy. */ contract ERC1967Proxy is Proxy, ERC1967Upgrade { /** * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`. * * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded * function call, and allows initializing the storage of the proxy like a Solidity constructor. */ constructor(address _logic, bytes memory _data) payable { _upgradeToAndCall(_logic, _data, false); } /** * @dev Returns the current implementation address. */ function _implementation() internal view virtual override returns (address impl) { return ERC1967Upgrade._getImplementation(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; import "../beacon/IBeacon.sol"; import "../../interfaces/draft-IERC1822.sol"; import "../../utils/Address.sol"; import "../../utils/StorageSlot.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ * * @custom:oz-upgrades-unsafe-allow delegatecall */ abstract contract ERC1967Upgrade { // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall( address newImplementation, bytes memory data, bool forceCall ) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { Address.functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallUUPS( address newImplementation, bytes memory data, bool forceCall ) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Emitted when the beacon is upgraded. */ event BeaconUpgraded(address indexed beacon); /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( Address.isContract(IBeacon(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall( address newBeacon, bytes memory data, bool forceCall ) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol) pragma solidity ^0.8.0; /** * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to * be specified by overriding the virtual {_implementation} function. * * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a * different contract through the {_delegate} function. * * The success and return data of the delegated call will be returned back to the caller of the proxy. */ abstract contract Proxy { /** * @dev Delegates the current call to `implementation`. * * This function does not return to its internal call site, it will return directly to the external caller. */ function _delegate(address implementation) internal virtual { assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize()) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize()) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } /** * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function * and {_fallback} should delegate. */ function _implementation() internal view virtual returns (address); /** * @dev Delegates the current call to the address returned by `_implementation()`. * * This function does not return to its internal call site, it will return directly to the external caller. */ function _fallback() internal virtual { _beforeFallback(); _delegate(_implementation()); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other * function in the contract matches the call data. */ fallback() external payable virtual { _fallback(); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data * is empty. */ receive() external payable virtual { _fallback(); } /** * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback` * call, or as part of the Solidity `fallback` or `receive` functions. * * If overridden should call `super._beforeFallback()`. */ function _beforeFallback() internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/ERC721.sol) pragma solidity ^0.8.0; import "./IERC721.sol"; import "./IERC721Receiver.sol"; import "./extensions/IERC721Metadata.sol"; import "../../utils/Address.sol"; import "../../utils/Context.sol"; import "../../utils/Strings.sol"; import "../../utils/introspection/ERC165.sol"; /** * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including * the Metadata extension, but not including the Enumerable extension, which is available separately as * {ERC721Enumerable}. */ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { using Address for address; using Strings for uint256; // Token name string private _name; // Token symbol string private _symbol; // Mapping from token ID to owner address mapping(uint256 => address) private _owners; // Mapping owner address to token count mapping(address => uint256) private _balances; // Mapping from token ID to approved address mapping(uint256 => address) private _tokenApprovals; // Mapping from owner to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals; /** * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721-balanceOf}. */ function balanceOf(address owner) public view virtual override returns (uint256) { require(owner != address(0), "ERC721: address zero is not a valid owner"); return _balances[owner]; } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view virtual override returns (address) { address owner = _owners[tokenId]; require(owner != address(0), "ERC721: invalid token ID"); return owner; } /** * @dev See {IERC721Metadata-name}. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { _requireMinted(tokenId); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, can be overridden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ""; } /** * @dev See {IERC721-approve}. */ function approve(address to, uint256 tokenId) public virtual override { address owner = ERC721.ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); require( _msgSender() == owner || isApprovedForAll(owner, _msgSender()), "ERC721: approve caller is not token owner nor approved for all" ); _approve(to, tokenId); } /** * @dev See {IERC721-getApproved}. */ function getApproved(uint256 tokenId) public view virtual override returns (address) { _requireMinted(tokenId); return _tokenApprovals[tokenId]; } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual override { _setApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom( address from, address to, uint256 tokenId ) public virtual override { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner nor approved"); _transfer(from, to, tokenId); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId ) public virtual override { safeTransferFrom(from, to, tokenId, ""); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory data ) public virtual override { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner nor approved"); _safeTransfer(from, to, tokenId, data); } /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * `data` is additional data, it has no specified format and it is sent in call to `to`. * * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. * implement alternative mechanisms to perform token transfer, such as signature-based. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeTransfer( address from, address to, uint256 tokenId, bytes memory data ) internal virtual { _transfer(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Returns whether `tokenId` exists. * * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. * * Tokens start existing when they are minted (`_mint`), * and stop existing when they are burned (`_burn`). */ function _exists(uint256 tokenId) internal view virtual returns (bool) { return _owners[tokenId] != address(0); } /** * @dev Returns whether `spender` is allowed to manage `tokenId`. * * Requirements: * * - `tokenId` must exist. */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { address owner = ERC721.ownerOf(tokenId); return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender); } /** * @dev Safely mints `tokenId` and transfers it to `to`. * * Requirements: * * - `tokenId` must not exist. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeMint(address to, uint256 tokenId) internal virtual { _safeMint(to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeMint( address to, uint256 tokenId, bytes memory data ) internal virtual { _mint(to, tokenId); require( _checkOnERC721Received(address(0), to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer" ); } /** * @dev Mints `tokenId` and transfers it to `to`. * * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible * * Requirements: * * - `tokenId` must not exist. * - `to` cannot be the zero address. * * Emits a {Transfer} event. */ function _mint(address to, uint256 tokenId) internal virtual { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); _beforeTokenTransfer(address(0), to, tokenId); _balances[to] += 1; _owners[tokenId] = to; emit Transfer(address(0), to, tokenId); _afterTokenTransfer(address(0), to, tokenId); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId) internal virtual { address owner = ERC721.ownerOf(tokenId); _beforeTokenTransfer(owner, address(0), tokenId); // Clear approvals _approve(address(0), tokenId); _balances[owner] -= 1; delete _owners[tokenId]; emit Transfer(owner, address(0), tokenId); _afterTokenTransfer(owner, address(0), tokenId); } /** * @dev Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. */ function _transfer( address from, address to, uint256 tokenId ) internal virtual { require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); require(to != address(0), "ERC721: transfer to the zero address"); _beforeTokenTransfer(from, to, tokenId); // Clear approvals from the previous owner _approve(address(0), tokenId); _balances[from] -= 1; _balances[to] += 1; _owners[tokenId] = to; emit Transfer(from, to, tokenId); _afterTokenTransfer(from, to, tokenId); } /** * @dev Approve `to` to operate on `tokenId` * * Emits an {Approval} event. */ function _approve(address to, uint256 tokenId) internal virtual { _tokenApprovals[tokenId] = to; emit Approval(ERC721.ownerOf(tokenId), to, tokenId); } /** * @dev Approve `operator` to operate on all of `owner` tokens * * Emits an {ApprovalForAll} event. */ function _setApprovalForAll( address owner, address operator, bool approved ) internal virtual { require(owner != operator, "ERC721: approve to caller"); _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); } /** * @dev Reverts if the `tokenId` has not been minted yet. */ function _requireMinted(uint256 tokenId) internal view virtual { require(_exists(tokenId), "ERC721: invalid token ID"); } /** * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. * The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param data bytes optional data to send along with the call * @return bool whether the call correctly returned the expected magic value */ function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory data ) private returns (bool) { if (to.isContract()) { try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) { return retval == IERC721Receiver.onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert("ERC721: transfer to non ERC721Receiver implementer"); } else { /// @solidity memory-safe-assembly assembly { revert(add(32, reason), mload(reason)) } } } } else { return true; } } /** * @dev Hook that is called before any token transfer. This includes minting * and burning. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, ``from``'s `tokenId` will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 tokenId ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 tokenId ) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol) pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ``` * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol) pragma solidity ^0.8.0; /** * @dev These functions deal with verification of Merkle Tree proofs. * * The proofs can be generated using the JavaScript library * https://github.com/miguelmota/merkletreejs[merkletreejs]. * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled. * * See `test/utils/cryptography/MerkleProof.test.js` for some examples. * * WARNING: You should avoid using leaf values that are 64 bytes long prior to * hashing, or use a hash function other than keccak256 for hashing leaves. * This is because the concatenation of a sorted pair of internal nodes in * the merkle tree could be reinterpreted as a leaf value. */ library MerkleProof { /** * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree * defined by `root`. For this, a `proof` must be provided, containing * sibling hashes on the branch from the leaf to the root of the tree. Each * pair of leaves and each pair of pre-images are assumed to be sorted. */ function verify( bytes32[] memory proof, bytes32 root, bytes32 leaf ) internal pure returns (bool) { return processProof(proof, leaf) == root; } /** * @dev Calldata version of {verify} * * _Available since v4.7._ */ function verifyCalldata( bytes32[] calldata proof, bytes32 root, bytes32 leaf ) internal pure returns (bool) { return processProofCalldata(proof, leaf) == root; } /** * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt * hash matches the root of the tree. When processing the proof, the pairs * of leafs & pre-images are assumed to be sorted. * * _Available since v4.4._ */ function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Calldata version of {processProof} * * _Available since v4.7._ */ function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}. * * _Available since v4.7._ */ function multiProofVerify( bytes32[] memory proof, bool[] memory proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProof(proof, proofFlags, leaves) == root; } /** * @dev Calldata version of {multiProofVerify} * * _Available since v4.7._ */ function multiProofVerifyCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProofCalldata(proof, proofFlags, leaves) == root; } /** * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`, * consuming from one or the other at each step according to the instructions given by * `proofFlags`. * * _Available since v4.7._ */ function processMultiProof( bytes32[] memory proof, bool[] memory proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the merkle tree. uint256 leavesLen = leaves.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof"); // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { return hashes[totalHashes - 1]; } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } /** * @dev Calldata version of {processMultiProof} * * _Available since v4.7._ */ function processMultiProofCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the merkle tree. uint256 leavesLen = leaves.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof"); // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { return hashes[totalHashes - 1]; } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) { return a < b ? _efficientHash(a, b) : _efficientHash(b, a); } function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { /// @solidity memory-safe-assembly assembly { mstore(0x00, a) mstore(0x20, b) value := keccak256(0x00, 0x40) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/math/SafeCast.sol) pragma solidity ^0.8.0; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing * all math on `uint256` and `int256` and then downcasting. */ library SafeCast { /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toUint248(uint256 value) internal pure returns (uint248) { require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits"); return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toUint240(uint256 value) internal pure returns (uint240) { require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits"); return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toUint232(uint256 value) internal pure returns (uint232) { require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits"); return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.2._ */ function toUint224(uint256 value) internal pure returns (uint224) { require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits"); return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toUint216(uint256 value) internal pure returns (uint216) { require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits"); return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toUint208(uint256 value) internal pure returns (uint208) { require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits"); return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toUint200(uint256 value) internal pure returns (uint200) { require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits"); return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toUint192(uint256 value) internal pure returns (uint192) { require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits"); return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toUint184(uint256 value) internal pure returns (uint184) { require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits"); return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toUint176(uint256 value) internal pure returns (uint176) { require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits"); return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toUint168(uint256 value) internal pure returns (uint168) { require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits"); return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toUint160(uint256 value) internal pure returns (uint160) { require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits"); return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toUint152(uint256 value) internal pure returns (uint152) { require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits"); return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toUint144(uint256 value) internal pure returns (uint144) { require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits"); return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toUint136(uint256 value) internal pure returns (uint136) { require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits"); return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v2.5._ */ function toUint128(uint256 value) internal pure returns (uint128) { require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toUint120(uint256 value) internal pure returns (uint120) { require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits"); return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toUint112(uint256 value) internal pure returns (uint112) { require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits"); return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toUint104(uint256 value) internal pure returns (uint104) { require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits"); return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.2._ */ function toUint96(uint256 value) internal pure returns (uint96) { require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits"); return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toUint88(uint256 value) internal pure returns (uint88) { require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits"); return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toUint80(uint256 value) internal pure returns (uint80) { require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits"); return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toUint72(uint256 value) internal pure returns (uint72) { require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits"); return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v2.5._ */ function toUint64(uint256 value) internal pure returns (uint64) { require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toUint56(uint256 value) internal pure returns (uint56) { require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits"); return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toUint48(uint256 value) internal pure returns (uint48) { require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits"); return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toUint40(uint256 value) internal pure returns (uint40) { require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits"); return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v2.5._ */ function toUint32(uint256 value) internal pure returns (uint32) { require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toUint24(uint256 value) internal pure returns (uint24) { require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits"); return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v2.5._ */ function toUint16(uint256 value) internal pure returns (uint16) { require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits"); return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v2.5._ */ function toUint8(uint256 value) internal pure returns (uint8) { require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits"); return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. * * _Available since v3.0._ */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toInt248(int256 value) internal pure returns (int248) { require(value >= type(int248).min && value <= type(int248).max, "SafeCast: value doesn't fit in 248 bits"); return int248(value); } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toInt240(int256 value) internal pure returns (int240) { require(value >= type(int240).min && value <= type(int240).max, "SafeCast: value doesn't fit in 240 bits"); return int240(value); } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toInt232(int256 value) internal pure returns (int232) { require(value >= type(int232).min && value <= type(int232).max, "SafeCast: value doesn't fit in 232 bits"); return int232(value); } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.7._ */ function toInt224(int256 value) internal pure returns (int224) { require(value >= type(int224).min && value <= type(int224).max, "SafeCast: value doesn't fit in 224 bits"); return int224(value); } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toInt216(int256 value) internal pure returns (int216) { require(value >= type(int216).min && value <= type(int216).max, "SafeCast: value doesn't fit in 216 bits"); return int216(value); } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toInt208(int256 value) internal pure returns (int208) { require(value >= type(int208).min && value <= type(int208).max, "SafeCast: value doesn't fit in 208 bits"); return int208(value); } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toInt200(int256 value) internal pure returns (int200) { require(value >= type(int200).min && value <= type(int200).max, "SafeCast: value doesn't fit in 200 bits"); return int200(value); } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toInt192(int256 value) internal pure returns (int192) { require(value >= type(int192).min && value <= type(int192).max, "SafeCast: value doesn't fit in 192 bits"); return int192(value); } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toInt184(int256 value) internal pure returns (int184) { require(value >= type(int184).min && value <= type(int184).max, "SafeCast: value doesn't fit in 184 bits"); return int184(value); } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toInt176(int256 value) internal pure returns (int176) { require(value >= type(int176).min && value <= type(int176).max, "SafeCast: value doesn't fit in 176 bits"); return int176(value); } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toInt168(int256 value) internal pure returns (int168) { require(value >= type(int168).min && value <= type(int168).max, "SafeCast: value doesn't fit in 168 bits"); return int168(value); } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toInt160(int256 value) internal pure returns (int160) { require(value >= type(int160).min && value <= type(int160).max, "SafeCast: value doesn't fit in 160 bits"); return int160(value); } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toInt152(int256 value) internal pure returns (int152) { require(value >= type(int152).min && value <= type(int152).max, "SafeCast: value doesn't fit in 152 bits"); return int152(value); } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toInt144(int256 value) internal pure returns (int144) { require(value >= type(int144).min && value <= type(int144).max, "SafeCast: value doesn't fit in 144 bits"); return int144(value); } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toInt136(int256 value) internal pure returns (int136) { require(value >= type(int136).min && value <= type(int136).max, "SafeCast: value doesn't fit in 136 bits"); return int136(value); } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v3.1._ */ function toInt128(int256 value) internal pure returns (int128) { require(value >= type(int128).min && value <= type(int128).max, "SafeCast: value doesn't fit in 128 bits"); return int128(value); } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toInt120(int256 value) internal pure returns (int120) { require(value >= type(int120).min && value <= type(int120).max, "SafeCast: value doesn't fit in 120 bits"); return int120(value); } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toInt112(int256 value) internal pure returns (int112) { require(value >= type(int112).min && value <= type(int112).max, "SafeCast: value doesn't fit in 112 bits"); return int112(value); } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toInt104(int256 value) internal pure returns (int104) { require(value >= type(int104).min && value <= type(int104).max, "SafeCast: value doesn't fit in 104 bits"); return int104(value); } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.7._ */ function toInt96(int256 value) internal pure returns (int96) { require(value >= type(int96).min && value <= type(int96).max, "SafeCast: value doesn't fit in 96 bits"); return int96(value); } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toInt88(int256 value) internal pure returns (int88) { require(value >= type(int88).min && value <= type(int88).max, "SafeCast: value doesn't fit in 88 bits"); return int88(value); } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toInt80(int256 value) internal pure returns (int80) { require(value >= type(int80).min && value <= type(int80).max, "SafeCast: value doesn't fit in 80 bits"); return int80(value); } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toInt72(int256 value) internal pure returns (int72) { require(value >= type(int72).min && value <= type(int72).max, "SafeCast: value doesn't fit in 72 bits"); return int72(value); } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v3.1._ */ function toInt64(int256 value) internal pure returns (int64) { require(value >= type(int64).min && value <= type(int64).max, "SafeCast: value doesn't fit in 64 bits"); return int64(value); } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toInt56(int256 value) internal pure returns (int56) { require(value >= type(int56).min && value <= type(int56).max, "SafeCast: value doesn't fit in 56 bits"); return int56(value); } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toInt48(int256 value) internal pure returns (int48) { require(value >= type(int48).min && value <= type(int48).max, "SafeCast: value doesn't fit in 48 bits"); return int48(value); } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toInt40(int256 value) internal pure returns (int40) { require(value >= type(int40).min && value <= type(int40).max, "SafeCast: value doesn't fit in 40 bits"); return int40(value); } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v3.1._ */ function toInt32(int256 value) internal pure returns (int32) { require(value >= type(int32).min && value <= type(int32).max, "SafeCast: value doesn't fit in 32 bits"); return int32(value); } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toInt24(int256 value) internal pure returns (int24) { require(value >= type(int24).min && value <= type(int24).max, "SafeCast: value doesn't fit in 24 bits"); return int24(value); } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v3.1._ */ function toInt16(int256 value) internal pure returns (int16) { require(value >= type(int16).min && value <= type(int16).max, "SafeCast: value doesn't fit in 16 bits"); return int16(value); } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v3.1._ */ function toInt8(int256 value) internal pure returns (int8) { require(value >= type(int8).min && value <= type(int8).max, "SafeCast: value doesn't fit in 8 bits"); return int8(value); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. * * _Available since v3.0._ */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256"); return int256(value); } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity =0.8.9; import "./interfaces/IFactory.sol"; import "./interfaces/IPeriphery.sol"; import "./interfaces/rate_oracles/IRateOracle.sol"; import "./interfaces/IMarginEngine.sol"; import "./interfaces/IVAMM.sol"; import "./interfaces/fcms/IFCM.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import "./utils/CustomErrors.sol"; contract VoltzERC1967Proxy is ERC1967Proxy, CustomErrors { constructor(address _logic, bytes memory _data) payable ERC1967Proxy(_logic, _data) {} } /// @title Voltz Factory Contract /// @notice Deploys Voltz VAMMs and MarginEngines and manages ownership and control over amm protocol fees // Following this example https://github.com/OriginProtocol/minimal-proxy-example/blob/master/contracts/PairFactory.sol contract Factory is IFactory, Ownable { /// @dev master MarginEngine implementation that MarginEngine proxies can delegate call to IMarginEngine public override masterMarginEngine; /// @dev master VAMM implementation that VAMM proxies can delegate call to IVAMM public override masterVAMM; /// @dev yieldBearingProtocolID --> master FCM implementation for the underlying yield bearing protocol with the corresponding id mapping(uint8 => IFCM) public override masterFCMs; /// @dev owner --> integration contract address --> isApproved /// @dev if an owner wishes to allow a given intergration contract to act on thir behalf with Voltz Core /// @dev they need to set the approval via the setApproval function mapping(address => mapping(address => bool)) private _isApproved; /// @dev Voltz Periphery IPeriphery public override periphery; function setApproval(address intAddress, bool allowIntegration) external override { _isApproved[msg.sender][intAddress] = allowIntegration; emit Approval(msg.sender, intAddress, allowIntegration); } function isApproved(address _owner, address _intAddress) override view public returns (bool) { require(_owner != address(0), "owner does not exist"); require(_intAddress != address(0), "int does not exist"); /// @dev Voltz periphery is always approved to act on behalf of the owner if (_intAddress == address(periphery)) { return true; } else { return _isApproved[_owner][_intAddress]; } } constructor(IMarginEngine _masterMarginEngine, IVAMM _masterVAMM) { require(address(_masterMarginEngine) != address(0), "master me must exist"); require(address(_masterVAMM) != address(0), "master vamm must exist"); masterMarginEngine = _masterMarginEngine; masterVAMM = _masterVAMM; } function setMasterFCM(IFCM _masterFCM, uint8 _yieldBearingProtocolID) external override onlyOwner { require(address(_masterFCM) != address(0), "master fcm must exist"); masterFCMs[_yieldBearingProtocolID] = _masterFCM; emit MasterFCM(_masterFCM, _yieldBearingProtocolID); } function setMasterMarginEngine(IMarginEngine _masterMarginEngine) external override onlyOwner { require(address(_masterMarginEngine) != address(0), "master me must exist"); if (address(masterMarginEngine) != address(_masterMarginEngine)) { masterMarginEngine = _masterMarginEngine; } } function setMasterVAMM(IVAMM _masterVAMM) external override onlyOwner { require(address(_masterVAMM) != address(0), "master vamm must exist"); if (address(masterVAMM) != address(_masterVAMM)) { masterVAMM = _masterVAMM; } } function setPeriphery(IPeriphery _periphery) external override onlyOwner { require(address(_periphery) != address(0), "periphery must exist"); if (address(periphery) != address(_periphery)) { periphery = _periphery; emit PeripheryUpdate(periphery); } } function deployIrsInstance(IERC20Minimal _underlyingToken, IRateOracle _rateOracle, uint256 _termStartTimestampWad, uint256 _termEndTimestampWad, int24 _tickSpacing) external override onlyOwner returns (IMarginEngine marginEngineProxy, IVAMM vammProxy, IFCM fcmProxy) { IMarginEngine marginEngine = IMarginEngine(address(new VoltzERC1967Proxy(address(masterMarginEngine), ""))); IVAMM vamm = IVAMM(address(new VoltzERC1967Proxy(address(masterVAMM), ""))); marginEngine.initialize(_underlyingToken, _rateOracle, _termStartTimestampWad, _termEndTimestampWad); vamm.initialize(marginEngine, _tickSpacing); marginEngine.setVAMM(vamm); IRateOracle r = IRateOracle(_rateOracle); require(r.underlying() == _underlyingToken, "Tokens do not match"); uint8 yieldBearingProtocolID = r.UNDERLYING_YIELD_BEARING_PROTOCOL_ID(); IFCM _masterFCM = masterFCMs[yieldBearingProtocolID]; IFCM fcm; if (address(_masterFCM) != address(0)) { fcm = IFCM(address(new VoltzERC1967Proxy(address(_masterFCM), ""))); fcm.initialize(vamm, marginEngine); marginEngine.setFCM(fcm); Ownable(address(fcm)).transferOwnership(msg.sender); } uint8 underlyingTokenDecimals = _underlyingToken.decimals(); emit IrsInstance(_underlyingToken, _rateOracle, _termStartTimestampWad, _termEndTimestampWad, _tickSpacing, marginEngine, vamm, fcm, yieldBearingProtocolID, underlyingTokenDecimals); // Transfer ownership of all instances to the factory owner Ownable(address(vamm)).transferOwnership(msg.sender); Ownable(address(marginEngine)).transferOwnership(msg.sender); return(marginEngine, vamm, fcm); } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity =0.8.9; import "prb-math/contracts/PRBMathSD59x18.sol"; import "prb-math/contracts/PRBMathUD60x18.sol"; import "./Time.sol"; /// @title A utility library for mathematics of fixed and variable token amounts. library FixedAndVariableMath { using PRBMathSD59x18 for int256; using PRBMathUD60x18 for uint256; /// @notice Number of wei-seconds in a year /// @dev Ignoring leap years since we're only using it to calculate the eventual APY rate uint256 public constant SECONDS_IN_YEAR_IN_WAD = 31536000e18; uint256 public constant ONE_HUNDRED_IN_WAD = 100e18; /// @notice Caclulate the remaining cashflow to settle a position /// @param fixedTokenBalance The current balance of the fixed side of the position /// @param variableTokenBalance The current balance of the variable side of the position /// @param termStartTimestampWad When did the position begin, in seconds /// @param termEndTimestampWad When does the position reach maturity, in seconds /// @param variableFactorToMaturityWad What factor expresses the current remaining variable rate, up to position maturity? (in wad) /// @return cashflow The remaining cashflow of the position function calculateSettlementCashflow( int256 fixedTokenBalance, int256 variableTokenBalance, uint256 termStartTimestampWad, uint256 termEndTimestampWad, uint256 variableFactorToMaturityWad ) internal view returns (int256 cashflow) { /// @dev convert fixed and variable token balances to their respective fixed token representations int256 fixedTokenBalanceWad = fixedTokenBalance.fromInt(); int256 variableTokenBalanceWad = variableTokenBalance.fromInt(); int256 fixedCashflowWad = fixedTokenBalanceWad.mul( int256( fixedFactor(true, termStartTimestampWad, termEndTimestampWad) ) ); int256 variableCashflowWad = variableTokenBalanceWad.mul( int256(variableFactorToMaturityWad) ); int256 cashflowWad = fixedCashflowWad + variableCashflowWad; /// @dev convert back to non-fixed point representation cashflow = cashflowWad.toInt(); } /// @notice Divide a given time in seconds by the number of seconds in a year /// @param timeInSecondsAsWad A time in seconds in Wad (i.e. scaled up by 10^18) /// @return timeInYearsWad An annualised factor of timeInSeconds, also in Wad function accrualFact(uint256 timeInSecondsAsWad) internal pure returns (uint256 timeInYearsWad) { timeInYearsWad = timeInSecondsAsWad.div(SECONDS_IN_YEAR_IN_WAD); } /// @notice Calculate the fixed factor for a position - that is, the percentage earned over /// the specified period of time, assuming 1% per year /// @param atMaturity Whether to calculate the factor at maturity (true), or now (false) /// @param termStartTimestampWad When does the period of time begin, in wei-seconds /// @param termEndTimestampWad When does the period of time end, in wei-seconds /// @return fixedFactorValueWad The fixed factor for the position (in Wad) function fixedFactor( bool atMaturity, uint256 termStartTimestampWad, uint256 termEndTimestampWad ) internal view returns (uint256 fixedFactorValueWad) { require(termEndTimestampWad > termStartTimestampWad, "E<=S"); uint256 currentTimestampWad = Time.blockTimestampScaled(); require(currentTimestampWad >= termStartTimestampWad, "B.T<S"); uint256 timeInSecondsWad; if (atMaturity || (currentTimestampWad >= termEndTimestampWad)) { timeInSecondsWad = termEndTimestampWad - termStartTimestampWad; } else { timeInSecondsWad = currentTimestampWad - termStartTimestampWad; } fixedFactorValueWad = accrualFact(timeInSecondsWad).div( ONE_HUNDRED_IN_WAD ); } /// @notice Calculate the fixed token balance for a position over a timespan /// @param amountFixedWad A fixed amount /// @param excessBalanceWad Cashflows accrued to the fixed and variable token amounts since the inception of the IRS AMM /// @param termStartTimestampWad When does the period of time begin, in wei-seconds /// @param termEndTimestampWad When does the period of time end, in wei-seconds /// @return fixedTokenBalanceWad The fixed token balance for that time period function calculateFixedTokenBalance( int256 amountFixedWad, int256 excessBalanceWad, uint256 termStartTimestampWad, uint256 termEndTimestampWad ) internal view returns (int256 fixedTokenBalanceWad) { require(termEndTimestampWad > termStartTimestampWad, "E<=S"); return amountFixedWad - excessBalanceWad.div( int256( fixedFactor( true, termStartTimestampWad, termEndTimestampWad ) ) ); } /// @notice Calculate the excess balance of both sides of a position in Wad /// @param amountFixedWad A fixed balance /// @param amountVariableWad A variable balance /// @param accruedVariableFactorWad An annualised factor in wei-years /// @param termStartTimestampWad When does the period of time begin, in wei-seconds /// @param termEndTimestampWad When does the period of time end, in wei-seconds /// @return excessBalanceWad The excess balance in wad function getExcessBalance( int256 amountFixedWad, int256 amountVariableWad, uint256 accruedVariableFactorWad, uint256 termStartTimestampWad, uint256 termEndTimestampWad ) internal view returns (int256) { /// @dev cashflows accrued since the inception of the IRS AMM return amountFixedWad.mul( int256( fixedFactor( false, termStartTimestampWad, termEndTimestampWad ) ) ) + amountVariableWad.mul(int256(accruedVariableFactorWad)); } /// @notice Calculate the fixed token balance given both fixed and variable balances /// @param amountFixed A fixed balance /// @param amountVariable A variable balance /// @param accruedVariableFactorWad An annualised factor in wei-years /// @param termStartTimestampWad When does the period of time begin, in wei-seconds /// @param termEndTimestampWad When does the period of time end, in wei-seconds /// @return fixedTokenBalance The fixed token balance for that time period function getFixedTokenBalance( int256 amountFixed, int256 amountVariable, uint256 accruedVariableFactorWad, uint256 termStartTimestampWad, uint256 termEndTimestampWad ) internal view returns (int256 fixedTokenBalance) { require(termEndTimestampWad > termStartTimestampWad, "E<=S"); if (amountFixed == 0 && amountVariable == 0) return 0; int256 amountFixedWad = amountFixed.fromInt(); int256 amountVariableWad = amountVariable.fromInt(); int256 excessBalanceWad = getExcessBalance( amountFixedWad, amountVariableWad, accruedVariableFactorWad, termStartTimestampWad, termEndTimestampWad ); int256 fixedTokenBalanceWad = calculateFixedTokenBalance( amountFixedWad, excessBalanceWad, termStartTimestampWad, termEndTimestampWad ); fixedTokenBalance = fixedTokenBalanceWad.toInt(); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.8.9; import "../utils/LiquidityMath.sol"; import "../utils/FixedPoint128.sol"; import "../core_libraries/Tick.sol"; import "../utils/FullMath.sol"; import "prb-math/contracts/PRBMathSD59x18.sol"; import "prb-math/contracts/PRBMathUD60x18.sol"; import "@openzeppelin/contracts/utils/math/SafeCast.sol"; /// @title Position /// @notice Positions represent an owner address' liquidity between a lower and upper tick boundary /// @dev Positions store additional state for tracking fees owed to the position as well as their fixed and variable token balances library Position { using Position for Info; // info stored for each user's position struct Info { // has the position been already burned // a burned position can no longer support new IRS contracts but still needs to cover settlement cash-flows of on-going IRS contracts it entered // bool isBurned;, equivalent to having zero liquidity // is position settled bool isSettled; // the amount of liquidity owned by this position uint128 _liquidity; // current margin of the position in terms of the underlyingToken int256 margin; // fixed token growth per unit of liquidity as of the last update to liquidity or fixed/variable token balance int256 fixedTokenGrowthInsideLastX128; // variable token growth per unit of liquidity as of the last update to liquidity or fixed/variable token balance int256 variableTokenGrowthInsideLastX128; // current Fixed Token balance of the position, 1 fixed token can be redeemed for 1% APY * (annualised amm term) at the maturity of the amm // assuming 1 token worth of notional "deposited" in the underlying pool at the inception of the amm // can be negative/positive/zero int256 fixedTokenBalance; // current Variable Token Balance of the position, 1 variable token can be redeemed for underlyingPoolAPY*(annualised amm term) at the maturity of the amm // assuming 1 token worth of notional "deposited" in the underlying pool at the inception of the amm // can be negative/positive/zero int256 variableTokenBalance; // fee growth per unit of liquidity as of the last update to liquidity or fees owed (via the margin) uint256 feeGrowthInsideLastX128; // amount of variable tokens at the initiation of liquidity uint256 rewardPerAmount; // amount of fees accumulated uint256 accumulatedFees; } /// @notice Returns the Info struct of a position, given an owner and position boundaries /// @param self The mapping containing all user positions /// @param owner The address of the position owner /// @param tickLower The lower tick boundary of the position /// @param tickUpper The upper tick boundary of the position /// @return position The position info struct of the given owners' position function get( mapping(bytes32 => Info) storage self, address owner, int24 tickLower, int24 tickUpper ) internal view returns (Position.Info storage position) { Tick.checkTicks(tickLower, tickUpper); position = self[ keccak256(abi.encodePacked(owner, tickLower, tickUpper)) ]; } function settlePosition(Info storage self) internal { require(!self.isSettled, "already settled"); self.isSettled = true; } /// @notice Updates the Info struct of a position by changing the amount of margin according to marginDelta /// @param self Position Info Struct of the Liquidity Provider /// @param marginDelta Change in the margin account of the position (in wei) function updateMarginViaDelta(Info storage self, int256 marginDelta) internal { self.margin += marginDelta; } /// @notice Updates the Info struct of a position by changing the fixed and variable token balances of the position /// @param self Position Info struct of the liquidity provider /// @param fixedTokenBalanceDelta Change in the number of fixed tokens in the position's fixed token balance /// @param variableTokenBalanceDelta Change in the number of variable tokens in the position's variable token balance function updateBalancesViaDeltas( Info storage self, int256 fixedTokenBalanceDelta, int256 variableTokenBalanceDelta ) internal { if (fixedTokenBalanceDelta | variableTokenBalanceDelta != 0) { self.fixedTokenBalance += fixedTokenBalanceDelta; self.variableTokenBalance += variableTokenBalanceDelta; } } /// @notice Returns Fee Delta = (feeGrowthInside-feeGrowthInsideLast) * liquidity of the position /// @param self position info struct represeting a liquidity provider /// @param feeGrowthInsideX128 fee growth per unit of liquidity as of now /// @return _feeDelta Fee Delta function calculateFeeDelta(Info storage self, uint256 feeGrowthInsideX128) internal pure returns (uint256 _feeDelta) { Info memory _self = self; /// @dev 0xZenus: The multiplication overflows, need to wrap the below expression in an unchecked block. unchecked { _feeDelta = FullMath.mulDiv( feeGrowthInsideX128 - _self.feeGrowthInsideLastX128, _self._liquidity, FixedPoint128.Q128 ); } } /// @notice Returns Fixed and Variable Token Deltas /// @param self position info struct represeting a liquidity provider /// @param fixedTokenGrowthInsideX128 fixed token growth per unit of liquidity as of now (in wei) /// @param variableTokenGrowthInsideX128 variable token growth per unit of liquidity as of now (in wei) /// @return _fixedTokenDelta = (fixedTokenGrowthInside-fixedTokenGrowthInsideLast) * liquidity of a position /// @return _variableTokenDelta = (variableTokenGrowthInside-variableTokenGrowthInsideLast) * liquidity of a position function calculateFixedAndVariableDelta( Info storage self, int256 fixedTokenGrowthInsideX128, int256 variableTokenGrowthInsideX128 ) internal pure returns (int256 _fixedTokenDelta, int256 _variableTokenDelta) { Info memory _self = self; int256 fixedTokenGrowthInsideDeltaX128 = fixedTokenGrowthInsideX128 - _self.fixedTokenGrowthInsideLastX128; _fixedTokenDelta = FullMath.mulDivSigned( fixedTokenGrowthInsideDeltaX128, _self._liquidity, FixedPoint128.Q128 ); int256 variableTokenGrowthInsideDeltaX128 = variableTokenGrowthInsideX128 - _self.variableTokenGrowthInsideLastX128; _variableTokenDelta = FullMath.mulDivSigned( variableTokenGrowthInsideDeltaX128, _self._liquidity, FixedPoint128.Q128 ); } /// @notice Updates fixedTokenGrowthInsideLast and variableTokenGrowthInsideLast to the current values /// @param self position info struct represeting a liquidity provider /// @param fixedTokenGrowthInsideX128 fixed token growth per unit of liquidity as of now /// @param variableTokenGrowthInsideX128 variable token growth per unit of liquidity as of now function updateFixedAndVariableTokenGrowthInside( Info storage self, int256 fixedTokenGrowthInsideX128, int256 variableTokenGrowthInsideX128 ) internal { self.fixedTokenGrowthInsideLastX128 = fixedTokenGrowthInsideX128; self.variableTokenGrowthInsideLastX128 = variableTokenGrowthInsideX128; } /// @notice Updates feeGrowthInsideLast to the current value /// @param self position info struct represeting a liquidity provider /// @param feeGrowthInsideX128 fee growth per unit of liquidity as of now function updateFeeGrowthInside( Info storage self, uint256 feeGrowthInsideX128 ) internal { self.feeGrowthInsideLastX128 = feeGrowthInsideX128; } /// @notice Updates position's liqudity following either mint or a burn /// @param self The individual position to update /// @param liquidityDelta The change in pool liquidity as a result of the position update function updateLiquidity(Info storage self, int128 liquidityDelta) internal { Info memory _self = self; if (liquidityDelta == 0) { require(_self._liquidity > 0, "NP"); // disallow pokes for 0 liquidity positions } else { self._liquidity = LiquidityMath.addDelta( _self._liquidity, liquidityDelta ); } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.8.9; import "../utils/LiquidityMath.sol"; import "../utils/TickMath.sol"; import "../utils/SafeCastUni.sol"; /// @title Tick /// @notice Contains functions for managing tick processes and relevant calculations library Tick { using SafeCastUni for int256; using SafeCastUni for uint256; int24 public constant MAXIMUM_TICK_SPACING = 16384; // info stored for each initialized individual tick struct Info { /// @dev the total position liquidity that references this tick (either as tick lower or tick upper) uint128 liquidityGross; /// @dev amount of net liquidity added (subtracted) when tick is crossed from left to right (right to left), int128 liquidityNet; /// @dev fee growth per unit of liquidity on the _other_ side of this tick (relative to the current tick) /// @dev only has relative meaning, not absolute — the value depends on when the tick is initialized int256 fixedTokenGrowthOutsideX128; int256 variableTokenGrowthOutsideX128; uint256 feeGrowthOutsideX128; /// @dev true iff the tick is initialized, i.e. the value is exactly equivalent to the expression liquidityGross != 0 /// @dev these 8 bits are set to prevent fresh sstores when crossing newly initialized ticks bool initialized; } /// @notice Derives max liquidity per tick from given tick spacing /// @dev Executed within the pool constructor /// @param tickSpacing The amount of required tick separation, realized in multiples of `tickSpacing` /// e.g., a tickSpacing of 3 requires ticks to be initialized every 3rd tick i.e., ..., -6, -3, 0, 3, 6, ... /// @return The max liquidity per tick function tickSpacingToMaxLiquidityPerTick(int24 tickSpacing) internal pure returns (uint128) { int24 minTick = TickMath.MIN_TICK - (TickMath.MIN_TICK % tickSpacing); int24 maxTick = -minTick; uint24 numTicks = uint24((maxTick - minTick) / tickSpacing) + 1; return type(uint128).max / numTicks; } /// @dev Common checks for valid tick inputs. function checkTicks(int24 tickLower, int24 tickUpper) internal pure { require(tickLower < tickUpper, "TLU"); require(tickLower >= TickMath.MIN_TICK, "TLM"); require(tickUpper <= TickMath.MAX_TICK, "TUM"); } struct FeeGrowthInsideParams { int24 tickLower; int24 tickUpper; int24 tickCurrent; uint256 feeGrowthGlobalX128; } function _getGrowthInside( int24 _tickLower, int24 _tickUpper, int24 _tickCurrent, int256 _growthGlobalX128, int256 _lowerGrowthOutsideX128, int256 _upperGrowthOutsideX128 ) private pure returns (int256) { // calculate the growth below int256 _growthBelowX128; if (_tickCurrent >= _tickLower) { _growthBelowX128 = _lowerGrowthOutsideX128; } else { _growthBelowX128 = _growthGlobalX128 - _lowerGrowthOutsideX128; } // calculate the growth above int256 _growthAboveX128; if (_tickCurrent < _tickUpper) { _growthAboveX128 = _upperGrowthOutsideX128; } else { _growthAboveX128 = _growthGlobalX128 - _upperGrowthOutsideX128; } int256 _growthInsideX128; _growthInsideX128 = _growthGlobalX128 - (_growthBelowX128 + _growthAboveX128); return _growthInsideX128; } function getFeeGrowthInside( mapping(int24 => Tick.Info) storage self, FeeGrowthInsideParams memory params ) internal view returns (uint256 feeGrowthInsideX128) { unchecked { Info storage lower = self[params.tickLower]; Info storage upper = self[params.tickUpper]; feeGrowthInsideX128 = uint256( _getGrowthInside( params.tickLower, params.tickUpper, params.tickCurrent, params.feeGrowthGlobalX128.toInt256(), lower.feeGrowthOutsideX128.toInt256(), upper.feeGrowthOutsideX128.toInt256() ) ); } } struct VariableTokenGrowthInsideParams { int24 tickLower; int24 tickUpper; int24 tickCurrent; int256 variableTokenGrowthGlobalX128; } function getVariableTokenGrowthInside( mapping(int24 => Tick.Info) storage self, VariableTokenGrowthInsideParams memory params ) internal view returns (int256 variableTokenGrowthInsideX128) { Info storage lower = self[params.tickLower]; Info storage upper = self[params.tickUpper]; variableTokenGrowthInsideX128 = _getGrowthInside( params.tickLower, params.tickUpper, params.tickCurrent, params.variableTokenGrowthGlobalX128, lower.variableTokenGrowthOutsideX128, upper.variableTokenGrowthOutsideX128 ); } struct FixedTokenGrowthInsideParams { int24 tickLower; int24 tickUpper; int24 tickCurrent; int256 fixedTokenGrowthGlobalX128; } function getFixedTokenGrowthInside( mapping(int24 => Tick.Info) storage self, FixedTokenGrowthInsideParams memory params ) internal view returns (int256 fixedTokenGrowthInsideX128) { Info storage lower = self[params.tickLower]; Info storage upper = self[params.tickUpper]; // do we need an unchecked block in here (given we are dealing with an int256)? fixedTokenGrowthInsideX128 = _getGrowthInside( params.tickLower, params.tickUpper, params.tickCurrent, params.fixedTokenGrowthGlobalX128, lower.fixedTokenGrowthOutsideX128, upper.fixedTokenGrowthOutsideX128 ); } /// @notice Updates a tick and returns true if the tick was flipped from initialized to uninitialized, or vice versa /// @param self The mapping containing all tick information for initialized ticks /// @param tick The tick that will be updated /// @param tickCurrent The current tick /// @param liquidityDelta A new amount of liquidity to be added (subtracted) when tick is crossed from left to right (right to left) /// @param fixedTokenGrowthGlobalX128 The fixed token growth accumulated per unit of liquidity for the entire life of the vamm /// @param variableTokenGrowthGlobalX128 The variable token growth accumulated per unit of liquidity for the entire life of the vamm /// @param upper true for updating a position's upper tick, or false for updating a position's lower tick /// @param maxLiquidity The maximum liquidity allocation for a single tick /// @return flipped Whether the tick was flipped from initialized to uninitialized, or vice versa function update( mapping(int24 => Tick.Info) storage self, int24 tick, int24 tickCurrent, int128 liquidityDelta, int256 fixedTokenGrowthGlobalX128, int256 variableTokenGrowthGlobalX128, uint256 feeGrowthGlobalX128, bool upper, uint128 maxLiquidity ) internal returns (bool flipped) { Tick.Info storage info = self[tick]; uint128 liquidityGrossBefore = info.liquidityGross; require( int128(info.liquidityGross) + liquidityDelta >= 0, "not enough liquidity to burn" ); uint128 liquidityGrossAfter = LiquidityMath.addDelta( liquidityGrossBefore, liquidityDelta ); require(liquidityGrossAfter <= maxLiquidity, "LO"); flipped = (liquidityGrossAfter == 0) != (liquidityGrossBefore == 0); if (liquidityGrossBefore == 0) { // by convention, we assume that all growth before a tick was initialized happened _below_ the tick if (tick <= tickCurrent) { info.feeGrowthOutsideX128 = feeGrowthGlobalX128; info.fixedTokenGrowthOutsideX128 = fixedTokenGrowthGlobalX128; info .variableTokenGrowthOutsideX128 = variableTokenGrowthGlobalX128; } info.initialized = true; } /// check shouldn't we unintialize the tick if liquidityGrossAfter = 0? info.liquidityGross = liquidityGrossAfter; /// add comments // when the lower (upper) tick is crossed left to right (right to left), liquidity must be added (removed) info.liquidityNet = upper ? info.liquidityNet - liquidityDelta : info.liquidityNet + liquidityDelta; } /// @notice Clears tick data /// @param self The mapping containing all initialized tick information for initialized ticks /// @param tick The tick that will be cleared function clear(mapping(int24 => Tick.Info) storage self, int24 tick) internal { delete self[tick]; } /// @notice Transitions to next tick as needed by price movement /// @param self The mapping containing all tick information for initialized ticks /// @param tick The destination tick of the transition /// @param fixedTokenGrowthGlobalX128 The fixed token growth accumulated per unit of liquidity for the entire life of the vamm /// @param variableTokenGrowthGlobalX128 The variable token growth accumulated per unit of liquidity for the entire life of the vamm /// @param feeGrowthGlobalX128 The fee growth collected per unit of liquidity for the entire life of the vamm /// @return liquidityNet The amount of liquidity added (subtracted) when tick is crossed from left to right (right to left) function cross( mapping(int24 => Tick.Info) storage self, int24 tick, int256 fixedTokenGrowthGlobalX128, int256 variableTokenGrowthGlobalX128, uint256 feeGrowthGlobalX128 ) internal returns (int128 liquidityNet) { Tick.Info storage info = self[tick]; info.feeGrowthOutsideX128 = feeGrowthGlobalX128 - info.feeGrowthOutsideX128; info.fixedTokenGrowthOutsideX128 = fixedTokenGrowthGlobalX128 - info.fixedTokenGrowthOutsideX128; info.variableTokenGrowthOutsideX128 = variableTokenGrowthGlobalX128 - info.variableTokenGrowthOutsideX128; liquidityNet = info.liquidityNet; } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity =0.8.9; import "prb-math/contracts/PRBMathUD60x18.sol"; library Time { /// @notice Calculate block.timestamp to wei precision /// @return Current timestamp in wei-seconds (1/1e18) function blockTimestampScaled() internal view returns (uint256) { // solhint-disable-next-line not-rely-on-time return PRBMathUD60x18.fromUint(block.timestamp); } /// @dev Returns the block timestamp truncated to 32 bits, checking for overflow. function blockTimestampTruncated() internal view returns (uint32) { return timestampAsUint32(block.timestamp); } function timestampAsUint32(uint256 _timestamp) internal pure returns (uint32 timestamp) { require((timestamp = uint32(_timestamp)) == _timestamp, "TSOFLOW"); } function isCloseToMaturityOrBeyondMaturity( uint256 termEndTimestampWad, uint256 maturityBufferWad ) internal view returns (bool vammInactive) { return Time.blockTimestampScaled() + maturityBufferWad >= termEndTimestampWad; } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity =0.8.9; import "./FixedAndVariableMath.sol"; /// @title Trader library TraderWithYieldBearingAssets { // info stored for each user's position struct Info { // For Aave v2 The scaled balance is the sum of all the updated stored balances in the // underlying token, divided by the reserve's liquidity index at the moment of the update // // For componund, the scaled balance is the sum of all the updated stored balances in the // underlying token, divided by the cToken exchange rate at the moment of the update. // This is simply the number of cTokens! uint256 marginInScaledYieldBearingTokens; int256 fixedTokenBalance; int256 variableTokenBalance; bool isSettled; } function updateMarginInScaledYieldBearingTokens( Info storage self, uint256 _marginInScaledYieldBearingTokens ) internal { self .marginInScaledYieldBearingTokens = _marginInScaledYieldBearingTokens; } function settleTrader(Info storage self) internal { require(!self.isSettled, "already settled"); self.isSettled = true; } function updateBalancesViaDeltas( Info storage self, int256 fixedTokenBalanceDelta, int256 variableTokenBalanceDelta ) internal returns (int256 _fixedTokenBalance, int256 _variableTokenBalance) { _fixedTokenBalance = self.fixedTokenBalance + fixedTokenBalanceDelta; _variableTokenBalance = self.variableTokenBalance + variableTokenBalanceDelta; self.fixedTokenBalance = _fixedTokenBalance; self.variableTokenBalance = _variableTokenBalance; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.8.9; /// @title Minimal ERC20 interface for Voltz /// @notice Contains a subset of the full ERC20 interface that is used in Voltz interface IERC20Minimal { /// @notice Returns the balance of a token /// @param account The account for which to look up the number of tokens it has, i.e. its balance /// @return The number of tokens held by the account function balanceOf(address account) external view returns (uint256); /// @notice Transfers the amount of token from the `msg.sender` to the recipient /// @param recipient The account that will receive the amount transferred /// @param amount The number of tokens to send from the sender to the recipient /// @return Returns true for a successful transfer, false for an unsuccessful transfer function transfer(address recipient, uint256 amount) external returns (bool); /// @notice Returns the current allowance given to a spender by an owner /// @param owner The account of the token owner /// @param spender The account of the token spender /// @return The current allowance granted by `owner` to `spender` function allowance(address owner, address spender) external view returns (uint256); /// @notice Sets the allowance of a spender from the `msg.sender` to the value `amount` /// @param spender The account which will be allowed to spend a given amount of the owners tokens /// @param amount The amount of tokens allowed to be used by `spender` /// @return Returns true for a successful approval, false for unsuccessful function approve(address spender, uint256 amount) external returns (bool); /// @notice Transfers `amount` tokens from `sender` to `recipient` up to the allowance given to the `msg.sender` /// @param sender The account from which the transfer will be initiated /// @param recipient The recipient of the transfer /// @param amount The amount of the transfer /// @return Returns true for a successful transfer, false for unsuccessful function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /// @dev Returns the number of decimals used to get its user representation. // For example, if decimals equals 2, a balance of 505 tokens should be displayed to a user as 5,05 (505 / 10 ** 2). // Tokens usually opt for a value of 18, imitating the relationship between Ether and Wei. function decimals() external view returns (uint8); /// @notice Event emitted when tokens are transferred from one address to another, either via `#transfer` or `#transferFrom`. /// @param from The account from which the tokens were sent, i.e. the balance decreased /// @param to The account to which the tokens were sent, i.e. the balance increased /// @param value The amount of tokens that were transferred event Transfer(address indexed from, address indexed to, uint256 value); /// @notice Event emitted when the approval amount for the spender of a given owner's tokens changes. /// @param owner The account that approved spending of its tokens /// @param spender The account for which the spending allowance was modified /// @param value The new allowance from the owner to the spender event Approval( address indexed owner, address indexed spender, uint256 value ); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity =0.8.9; import "../utils/CustomErrors.sol"; import "./rate_oracles/IRateOracle.sol"; import "./IMarginEngine.sol"; import "./IVAMM.sol"; import "./fcms/IFCM.sol"; import "./IERC20Minimal.sol"; import "./IPeriphery.sol"; /// @title The interface for the Voltz AMM Factory /// @notice The AMM Factory facilitates creation of Voltz AMMs interface IFactory is CustomErrors { event IrsInstance( IERC20Minimal indexed underlyingToken, IRateOracle indexed rateOracle, uint256 termStartTimestampWad, uint256 termEndTimestampWad, int24 tickSpacing, IMarginEngine marginEngine, IVAMM vamm, IFCM fcm, uint8 yieldBearingProtocolID, uint8 underlyingTokenDecimals ); event MasterFCM(IFCM masterFCMAddress, uint8 yieldBearingProtocolID); event Approval( address indexed owner, address indexed intAddress, bool indexed isApproved ); event PeripheryUpdate(IPeriphery periphery); // view functions function isApproved(address _owner, address intAddress) external view returns (bool); function masterVAMM() external view returns (IVAMM); function masterMarginEngine() external view returns (IMarginEngine); function periphery() external view returns (IPeriphery); // settters function setApproval(address intAddress, bool allowIntegration) external; function setMasterFCM(IFCM masterFCM, uint8 yieldBearingProtocolID) external; function setMasterVAMM(IVAMM _masterVAMM) external; function setMasterMarginEngine(IMarginEngine _masterMarginEngine) external; function setPeriphery(IPeriphery _periphery) external; /// @notice Deploys the contracts required for a new Interest Rate Swap instance function deployIrsInstance( IERC20Minimal _underlyingToken, IRateOracle _rateOracle, uint256 _termStartTimestampWad, uint256 _termEndTimestampWad, int24 _tickSpacing ) external returns ( IMarginEngine marginEngineProxy, IVAMM vammProxy, IFCM fcmProxy ); function masterFCMs(uint8 yieldBearingProtocolID) external view returns (IFCM masterFCM); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity =0.8.9; import "./IVAMM.sol"; import "./IPositionStructs.sol"; import "../core_libraries/Position.sol"; import "./rate_oracles/IRateOracle.sol"; import "./fcms/IFCM.sol"; import "./IFactory.sol"; import "./IERC20Minimal.sol"; import "../utils/CustomErrors.sol"; interface IMarginEngine is IPositionStructs, CustomErrors { // structs function setPausability(bool state) external; struct MarginCalculatorParameters { /// @dev Upper bound of the underlying pool (e.g. Aave v2 USDC lending pool) APY from the initiation of the IRS AMM and until its maturity (18 decimals fixed point number) uint256 apyUpperMultiplierWad; /// @dev Lower bound of the underlying pool (e.g. Aave v2 USDC lending pool) APY from the initiation of the IRS AMM and until its maturity (18 decimals) uint256 apyLowerMultiplierWad; /// @dev The volatility of the underlying pool APY (settable by the owner of the Margin Engine) (18 decimals) int256 sigmaSquaredWad; /// @dev Margin Engine Parameter estimated via CIR model calibration (for details refer to litepaper) (18 decimals) int256 alphaWad; /// @dev Margin Engine Parameter estimated via CIR model calibration (for details refer to litepaper) (18 decimals) int256 betaWad; /// @dev Standard normal critical value used in the computation of the Upper APY Bound of the underlying pool int256 xiUpperWad; /// @dev Standard normal critical value used in the computation of the Lower APY Bound of the underlying pool int256 xiLowerWad; /// @dev Max term possible for a Voltz IRS AMM in seconds (18 decimals) int256 tMaxWad; /// @dev Margin Engine Parameter used for initial minimum margin requirement uint256 etaIMWad; /// @dev Margin Engine Parameter used for initial minimum margin requirement uint256 etaLMWad; /// @dev Gap uint256 gap1; /// @dev Gap uint256 gap2; /// @dev Gap uint256 gap3; /// @dev Gap uint256 gap4; /// @dev Gap uint256 gap5; /// @dev Gap uint256 gap6; /// @dev Gap uint256 gap7; /// @dev settable parameter that ensures that minimumMarginRequirement is always above or equal to the minMarginToIncentiviseLiquidators which ensures there is always sufficient incentive for liquidators to liquidate positions given the fact their income is a proportion of position margin uint256 minMarginToIncentiviseLiquidators; } // Events event HistoricalApyWindowSetting(uint256 secondsAgo); event CacheMaxAgeSetting(uint256 cacheMaxAgeInSeconds); event RateOracle(uint256 cacheMaxAgeInSeconds); event ProtocolCollection( address sender, address indexed recipient, uint256 amount ); event LiquidatorRewardSetting(uint256 liquidatorRewardWad); event VAMMSetting(IVAMM indexed vamm); event RateOracleSetting(IRateOracle indexed rateOracle); event FCMSetting(IFCM indexed fcm); event MarginCalculatorParametersSetting( MarginCalculatorParameters marginCalculatorParameters ); event PositionMarginUpdate( address sender, address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, int256 marginDelta ); event HistoricalApy(uint256 value); event PositionSettlement( address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, int256 settlementCashflow ); event PositionLiquidation( address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, address liquidator, int256 notionalUnwound, uint256 liquidatorReward ); event PositionUpdate( address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 _liquidity, int256 margin, int256 fixedTokenBalance, int256 variableTokenBalance, uint256 accumulatedFees ); /// @dev emitted after the _isAlpha boolean is updated by the owner of the Margin Engine /// @dev _isAlpha boolean dictates whether the Margin Engine is in the Alpha State, i.e. margin updates can only be done via the periphery /// @dev additionally, the periphery has the logic to take care of lp margin caps in the Alpha State phase of the Margin Engine /// @dev __isAlpha is the newly set value for the _isAlpha boolean event IsAlpha(bool __isAlpha); // immutables /// @notice The Full Collateralisation Module (FCM) /// @dev The FCM is a smart contract that acts as an intermediary Position between the Voltz Core and traders who wish to take fully collateralised fixed taker positions /// @dev An example FCM is the AaveFCM.sol module which inherits from the IFCM interface, it lets fixed takers deposit underlying yield bearing tokens (e.g.) aUSDC as margin to enter into a fixed taker swap without the need to worry about liquidations /// @dev since the MarginEngine is confident the FCM is always fully collateralised, it does not let liquidators liquidate the FCM Position /// @return The Full Collateralisation Module linked to the MarginEngine function fcm() external view returns (IFCM); /// @notice The Factory /// @dev the factory that deployed the master Margin Engine function factory() external view returns (IFactory); /// @notice The address of the underlying (non-yield bearing) token - e.g. USDC /// @return The underlying ERC20 token (e.g. USDC) function underlyingToken() external view returns (IERC20Minimal); /// @notice The rateOracle contract which lets the protocol access historical apys in the yield bearing pools it is built on top of /// @return The underlying ERC20 token (e.g. USDC) function rateOracle() external view returns (IRateOracle); /// @notice The unix termStartTimestamp of the MarginEngine in Wad /// @return Term Start Timestamp in Wad function termStartTimestampWad() external view returns (uint256); /// @notice The unix termEndTimestamp of the MarginEngine in Wad /// @return Term End Timestamp in Wad function termEndTimestampWad() external view returns (uint256); function marginEngineParameters() external view returns (MarginCalculatorParameters memory); /// @dev "constructor" for proxy instances function initialize( IERC20Minimal __underlyingToken, IRateOracle __rateOracle, uint256 __termStartTimestampWad, uint256 __termEndTimestampWad ) external; // view functions /// @notice The liquidator Reward Percentage (in Wad) /// @dev liquidatorReward (in wad) is the percentage of the margin (of a liquidated position) that is sent to the liquidator /// @dev following a successful liquidation that results in a trader/position unwind; example value: 2 * 10**16 => 2% of position margin is used to cover liquidator reward /// @return Liquidator Reward in Wad function liquidatorRewardWad() external view returns (uint256); /// @notice VAMM (Virtual Automated Market Maker) linked to the MarginEngine /// @dev The VAMM is responsible for pricing only (determining the effective fixed rate at which a given Interest Rate Swap notional will be executed) /// @return The VAMM function vamm() external view returns (IVAMM); /// @return If true, the Margin Engine Proxy is currently in alpha state, hence margin updates of LPs can only be done via the periphery. If false, lps can directly update their margin via Margin Engine. function isAlpha() external view returns (bool); /// @notice Returns the information about a position by the position's key /// @param _owner The address of the position owner /// @param _tickLower The lower tick boundary of the position /// @param _tickUpper The upper tick boundary of the position /// Returns position The Position.Info corresponding to the requested position function getPosition( address _owner, int24 _tickLower, int24 _tickUpper ) external returns (Position.Info memory position); /// @notice Gets the look-back window size that's used to request the historical APY from the rate Oracle /// @dev The historical APY of the Rate Oracle is necessary for MarginEngine computations /// @dev The look-back window is seconds from the current timestamp /// @dev This value is only settable by the the Factory owner and may be unique for each MarginEngine /// @dev When setting secondAgo, the setter needs to take into consideration the underlying volatility of the APYs in the reference yield-bearing pool (e.g. Aave v2 USDC) function lookbackWindowInSeconds() external view returns (uint256); // non-view functions /// @notice Sets secondsAgo: The look-back window size used to calculate the historical APY for margin purposes /// @param _secondsAgo the duration of the lookback window in seconds /// @dev Can only be set by the Factory Owner function setLookbackWindowInSeconds(uint256 _secondsAgo) external; /// @notice Set the MarginCalculatorParameters (each margin engine can have its own custom set of margin calculator parameters) /// @param _marginCalculatorParameters the MarginCalculatorParameters to set /// @dev marginCalculatorParameteres is of type MarginCalculatorParameters (refer to the definition of the struct for elaboration on what each parameter means) function setMarginCalculatorParameters( MarginCalculatorParameters memory _marginCalculatorParameters ) external; /// @notice Sets the liquidator reward: proportion of liquidated position's margin paid as a reward to the liquidator function setLiquidatorReward(uint256 _liquidatorRewardWad) external; /// @notice Function that sets the _isAlpha state variable, if it is set to true the protocol is in the Alpha State /// @dev if the Margin Engine is at the alpha state, lp margin updates can only be done via the periphery which in turn takes care of margin caps for the LPs /// @dev this function can only be called by the owner of the VAMM function setIsAlpha(bool __isAlpha) external; /// @notice updates the margin account of a position which can be uniquily identified with its _owner, tickLower, tickUpper /// @dev if the position has positive liquidity then before the margin update, we call the updatePositionTokenBalancesAndAccountForFees functon that calculates up to date /// @dev margin, fixed and variable token balances by taking into account the fee income from their tick range and fixed and variable deltas settled along their tick range /// @dev marginDelta is the delta applied to the current margin of a position, if the marginDelta is negative, the position is withdrawing margin, if the marginDelta is positive, the position is depositing funds in terms of the underlying tokens /// @dev if marginDelta is negative, we need to check if the msg.sender is either the _owner of the position or the msg.sender is apporved by the _owner to act on their behalf in Voltz Protocol /// @dev the approval logic is implemented in the Factory.sol /// @dev if marginDelta is negative, we additionally need to check if post the initial margin requirement is still satisfied post withdrawal /// @dev if marginDelta is positive, the depositor of the margin is either the msg.sender or the owner who interacted through an approved peripheral contract function updatePositionMargin( address _owner, int24 _tickLower, int24 _tickUpper, int256 marginDelta ) external; /// @notice Settles a Position /// @dev Can be called by anyone /// @dev A position cannot be settled before maturity /// @dev Steps to settle a position: /// @dev 1. Retrieve the current fixed and variable token growth inside the tick range of a position /// @dev 2. Calculate accumulated fixed and variable balances of the position since the last mint/poke/burn /// @dev 3. Update the postion's fixed and variable token balances /// @dev 4. Update the postion's fixed and varaible token growth inside last to enable future updates /// @dev 5. Calculates the settlement cashflow from all of the IRS contracts the position has entered since entering the AMM /// @dev 6. Updates the fixed and variable token balances of the position to be zero, adds the settlement cashflow to the position's current margin function settlePosition( address _owner, int24 _tickLower, int24 _tickUpper ) external; /// @notice Liquidate a Position /// @dev Steps to liquidate: update position's fixed and variable token balances to account for balances accumulated throughout the trades made since the last mint/burn/poke, /// @dev Check if the position is liquidatable by calling the isLiquidatablePosition function of the calculator, revert if that is not the case, /// @dev Calculate the liquidation reward = current margin of the position * liquidatorReward, subtract the liquidator reward from the position margin, /// @dev Burn the position's liquidity, unwind unnetted fixed and variable balances of a position, transfer the reward to the liquidator function liquidatePosition( address _owner, int24 _tickLower, int24 _tickUpper ) external returns (uint256); /// @notice Update a Position post VAMM induced mint or burn /// @dev Steps taken: /// @dev 1. Update position liquidity based on params.liquidityDelta /// @dev 2. Update fixed and variable token balances of the position based on how much has been accumulated since the last mint/burn/poke /// @dev 3. Update position's margin by taking into account the position accumulated fees since the last mint/burn/poke /// @dev 4. Update fixed and variable token growth + fee growth in the position info struct for future interactions with the position /// @param _params necessary for the purposes of referencing the position being updated (owner, tickLower, tickUpper, _) and the liquidity delta that needs to be applied to position._liquidity function updatePositionPostVAMMInducedMintBurn( IPositionStructs.ModifyPositionParams memory _params ) external returns (int256 _positionMarginRequirement); // @notive Update a position post VAMM induced swap /// @dev Since every position can also engage in swaps with the VAMM, this function needs to be invoked after non-external calls are made to the VAMM's swap function /// @dev This purpose of this function is to: /// @dev 1. updatePositionTokenBalancesAndAccountForFees /// @dev 2. update position margin to account for fees paid to execute the swap /// @dev 3. calculate the position margin requrement given the swap, check if the position marigin satisfies the most up to date requirement /// @dev 4. if all the requirements are satisfied then position gets updated to take into account the swap that it just entered, if the minimum margin requirement is not satisfied then the transaction will revert function updatePositionPostVAMMInducedSwap( address _owner, int24 _tickLower, int24 _tickUpper, int256 _fixedTokenDelta, int256 _variableTokenDelta, uint256 _cumulativeFeeIncurred, int256 _fixedTokenDeltaUnbalanced ) external returns (int256 _positionMarginRequirement); /// @notice function that can only be called by the owner enables collection of protocol generated fees from any give margin engine /// @param _recipient the address which collects the protocol generated fees /// @param _amount the amount in terms of underlying tokens collected from the protocol's earnings function collectProtocol(address _recipient, uint256 _amount) external; /// @notice sets the Virtual Automated Market Maker (VAMM) attached to the MarginEngine /// @dev the VAMM is responsible for price discovery, whereas the management of the underlying collateral and liquidations are handled by the Margin Engine function setVAMM(IVAMM _vAMM) external; /// @notice sets the Virtual Automated Market Maker (VAMM) attached to the MarginEngine /// @dev the VAMM is responsible for price discovery, whereas the management of the underlying collateral and liquidations are handled by the Margin Engine function setRateOracle(IRateOracle __rateOracle) external; /// @notice sets the Full Collateralisation Module function setFCM(IFCM _newFCM) external; /// @notice transfers margin in terms of underlying tokens to a trader from the Full Collateralisation Module /// @dev post maturity date of the MarginEngine, the traders from the Full Collateralisation module will be able to settle with the MarginEngine /// @dev to ensure their fixed yield is guaranteed, in order to collect the funds from the MarginEngine, the FCM needs to invoke the transferMarginToFCMTrader function whcih is only callable by the FCM attached to a particular Margin Engine function transferMarginToFCMTrader(address _account, uint256 _marginDelta) external; /// @notice Gets the maximum age of the cached historical APY value can be without being refreshed function cacheMaxAgeInSeconds() external view returns (uint256); /// @notice Sets the maximum age that the cached historical APY value /// @param _cacheMaxAgeInSeconds The new maximum age that the historical APY cache can be before being considered stale function setCacheMaxAgeInSeconds(uint256 _cacheMaxAgeInSeconds) external; /// @notice Get Historical APY /// @dev The lookback window used by this function is determined by `lookbackWindowInSeconds` /// @dev refresh the historical apy cache if necessary /// @return historicalAPY (Wad) function getHistoricalApy() external returns (uint256); /// @notice Computes the historical APY value of the RateOracle, without updating the cached value /// @dev The lookback window used by this function is determined by `lookbackWindowInSeconds` function getHistoricalApyReadOnly() external view returns (uint256); function getPositionMarginRequirement( address _recipient, int24 _tickLower, int24 _tickUpper, bool _isLM ) external returns (uint256); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity =0.8.9; import "../interfaces/IMarginEngine.sol"; import "../interfaces/IVAMM.sol"; import "../utils/CustomErrors.sol"; import "../interfaces/IWETH.sol"; interface IPeriphery is CustomErrors { // structs for events struct PositionDetails { IMarginEngine marginEngine; address owner; int24 tickLower; int24 tickUpper; } struct SwapOutput { int256 fixedTokenDelta; int256 variableTokenDelta; uint256 cumulativeFeeIncurred; int256 fixedTokenDeltaUnbalanced; int256 marginRequirement; } // events /// @dev emitted after new lp margin cap is set event MarginCap(IVAMM vamm, int256 lpMarginCapNew); /// @dev emitted when new lp margin cumulative is set event MarginCumulative(IVAMM vamm, int256 lpMarginCumulative); /// @dev emitted when position is settled and all margin withdrawn event SettlePositionAndWithdrawMargin(PositionDetails position); /// @dev emitted when position margin is updated event UpdatePositionMargin( PositionDetails position, int256 marginDelta, bool fullyWithdraw ); /// @dev emitted when liquidity is minted or burnt event MintOrBurn( PositionDetails position, uint256 notional, bool isMint, int256 positionMarginRequirement ); /// @dev emitted when swap happens event Swap( PositionDetails position, bool isFT, uint256 notional, SwapOutput output ); /// @dev emitted when position is rolled over with mint event RolloverWithMint( PositionDetails oldPosition, PositionDetails newPosition, uint256 notional, bool isMint, int256 newPositionMarginRequirement ); /// @dev emitted when position is rolled over with swap event RolloverWithSwap( PositionDetails oldPosition, PositionDetails newPosition, bool isFT, uint256 notional, SwapOutput output ); // structs struct MintOrBurnParams { IMarginEngine marginEngine; int24 tickLower; int24 tickUpper; uint256 notional; bool isMint; int256 marginDelta; } struct SwapPeripheryParams { IMarginEngine marginEngine; bool isFT; uint256 notional; uint160 sqrtPriceLimitX96; int24 tickLower; int24 tickUpper; int256 marginDelta; } /// @dev "constructor" for proxy instances function initialize(IWETH weth_) external; // view functions function getCurrentTick(IMarginEngine marginEngine) external view returns (int24 currentTick); /// @param vamm VAMM for which to get the lp cap in underlying tokens /// @return Notional Cap for liquidity providers that mint or burn via periphery (enforced in the core if isAlpha is set to true) function lpMarginCaps(IVAMM vamm) external view returns (int256); /// @param vamm VAMM for which to get the lp notional cumulative in underlying tokens /// @return Total amount of notional supplied by the LPs to a given VAMM via the periphery function lpMarginCumulatives(IVAMM vamm) external view returns (int256); function weth() external view returns (IWETH); // non-view functions function mintOrBurn(MintOrBurnParams memory params) external payable returns (int256 positionMarginRequirement); function swap(SwapPeripheryParams memory params) external payable returns ( int256 _fixedTokenDelta, int256 _variableTokenDelta, uint256 _cumulativeFeeIncurred, int256 _fixedTokenDeltaUnbalanced, int256 _marginRequirement, int24 _tickAfter, int256 marginDelta ); /// @dev Ensures a fully collateralised VT swap given that a proper value of the variable factor is passed. /// @param params Parameters to be passed to the swap function in the periphery. /// @param variableFactorFromStartToNowWad The variable factor between pool's start date and present (in wad). function fullyCollateralisedVTSwap( SwapPeripheryParams memory params, uint256 variableFactorFromStartToNowWad ) external payable returns ( int256 _fixedTokenDelta, int256 _variableTokenDelta, uint256 _cumulativeFeeIncurred, int256 _fixedTokenDeltaUnbalanced, int256 _marginRequirement, int24 _tickAfter, int256 marginDelta ); function updatePositionMargin( IMarginEngine marginEngine, int24 tickLower, int24 tickUpper, int256 marginDelta, bool fullyWithdraw ) external payable returns (int256); function setLPMarginCap(IVAMM vamm, int256 lpMarginCapNew) external; function setLPMarginCumulative(IVAMM vamm, int256 lpMarginCumulative) external; function settlePositionAndWithdrawMargin( IMarginEngine marginEngine, address owner, int24 tickLower, int24 tickUpper ) external; function rolloverWithMint( IMarginEngine marginEngine, address owner, int24 tickLower, int24 tickUpper, MintOrBurnParams memory paramsNewPosition ) external payable returns (int256 newPositionMarginRequirement); function rolloverWithSwap( IMarginEngine marginEngine, address owner, int24 tickLower, int24 tickUpper, SwapPeripheryParams memory paramsNewPosition ) external payable returns ( int256 _fixedTokenDelta, int256 _variableTokenDelta, uint256 _cumulativeFeeIncurred, int256 _fixedTokenDeltaUnbalanced, int256 _marginRequirement, int24 _tickAfter ); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.8.9; interface IPositionStructs { struct ModifyPositionParams { // the address that owns the position address owner; // the lower and upper tick of the position int24 tickLower; int24 tickUpper; // any change in liquidity int128 liquidityDelta; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.8.9; import "./IMarginEngine.sol"; import "./IFactory.sol"; import "./IPositionStructs.sol"; import "../core_libraries/Tick.sol"; import "../utils/CustomErrors.sol"; import "./rate_oracles/IRateOracle.sol"; interface IVAMM is IPositionStructs, CustomErrors { function setPausability(bool state) external; // events event Swap( address sender, address indexed recipient, int24 indexed tickLower, int24 indexed tickUpper, int256 desiredNotional, uint160 sqrtPriceLimitX96, uint256 cumulativeFeeIncurred, int256 fixedTokenDelta, int256 variableTokenDelta, int256 fixedTokenDeltaUnbalanced ); /// @dev emitted after a given vamm is successfully initialized event VAMMInitialization(uint160 sqrtPriceX96, int24 tick); /// @dev emitted after a successful minting of a given LP position event Mint( address sender, address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount ); /// @dev emitted after a successful burning of a given LP position event Burn( address sender, address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount ); /// @dev emitted after setting feeProtocol event FeeProtocol(uint8 feeProtocol); /// @dev emitted after fee is set event Fee(uint256 feeWad); /// @dev emitted after the _isAlpha boolean is updated by the owner of the VAMM /// @dev _isAlpha boolean dictates whether the VAMM is in the Alpha State, i.e. mints can only be done via the periphery /// @dev additionally, the periphery has the logic to take care of lp notional caps in the Alpha State phase of VAMM /// @dev __isAlpha is the newly set value for the _isAlpha boolean event IsAlpha(bool __isAlpha); event VAMMPriceChange(int24 tick); // structs struct VAMMVars { /// @dev The current price of the pool as a sqrt(variableToken/fixedToken) Q64.96 value uint160 sqrtPriceX96; /// @dev The current tick of the vamm, i.e. according to the last tick transition that was run. int24 tick; // the current protocol fee as a percentage of the swap fee taken on withdrawal // represented as an integer denominator (1/x) uint8 feeProtocol; } struct SwapParams { /// @dev Address of the trader initiating the swap address recipient; /// @dev The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative) int256 amountSpecified; /// @dev The Q64.96 sqrt price limit. If !isFT, the price cannot be less than this uint160 sqrtPriceLimitX96; /// @dev lower tick of the position int24 tickLower; /// @dev upper tick of the position int24 tickUpper; } struct SwapCache { /// @dev liquidity at the beginning of the swap uint128 liquidityStart; // the current protocol fee as a percentage of the swap fee taken on withdrawal // represented as an integer denominator (1/x)% uint8 feeProtocol; } /// @dev the top level state of the swap, the results of which are recorded in storage at the end struct SwapState { /// @dev the amount remaining to be swapped in/out of the input/output asset int256 amountSpecifiedRemaining; /// @dev the amount already swapped out/in of the output/input asset int256 amountCalculated; /// @dev current sqrt(price) uint160 sqrtPriceX96; /// @dev the tick associated with the current price int24 tick; /// @dev the global fixed token growth int256 fixedTokenGrowthGlobalX128; /// @dev the global variable token growth int256 variableTokenGrowthGlobalX128; /// @dev the current liquidity in range uint128 liquidity; /// @dev the global fee growth of the underlying token uint256 feeGrowthGlobalX128; /// @dev amount of underlying token paid as protocol fee uint256 protocolFee; /// @dev cumulative fee incurred while initiating a swap uint256 cumulativeFeeIncurred; /// @dev fixedTokenDelta that will be applied to the fixed token balance of the position executing the swap (recipient) int256 fixedTokenDeltaCumulative; /// @dev variableTokenDelta that will be applied to the variable token balance of the position executing the swap (recipient) int256 variableTokenDeltaCumulative; /// @dev fixed token delta cumulative but without rebalancings applied int256 fixedTokenDeltaUnbalancedCumulative; uint256 variableFactorWad; } struct StepComputations { /// @dev the price at the beginning of the step uint160 sqrtPriceStartX96; /// @dev the next tick to swap to from the current tick in the swap direction int24 tickNext; /// @dev whether tickNext is initialized or not bool initialized; /// @dev sqrt(price) for the next tick (1/0) uint160 sqrtPriceNextX96; /// @dev how much is being swapped in in this step uint256 amountIn; /// @dev how much is being swapped out uint256 amountOut; /// @dev how much fee is being paid in (underlying token) uint256 feeAmount; /// @dev ... uint256 feeProtocolDelta; /// @dev ... int256 fixedTokenDeltaUnbalanced; // for LP /// @dev ... int256 fixedTokenDelta; // for LP /// @dev ... int256 variableTokenDelta; // for LP } /// @dev "constructor" for proxy instances function initialize(IMarginEngine __marginEngine, int24 __tickSpacing) external; // immutables /// @notice The vamm's fee (proportion) in wad /// @return The fee in wad function feeWad() external view returns (uint256); /// @notice The vamm tick spacing /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ... /// This value is an int24 to avoid casting even though it is always positive. /// @return The tick spacing function tickSpacing() external view returns (int24); /// @notice The maximum amount of position liquidity that can use any tick in the range /// @dev This parameter should be enforced per tick (when setting) to prevent liquidity from overflowing a uint128 at any point, and /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to the vamm /// @return The max amount of liquidity per tick function maxLiquidityPerTick() external view returns (uint128); // state variables /// @return The current VAMM Vars (see struct definition for semantics) function vammVars() external view returns (VAMMVars memory); /// @return If true, the VAMM Proxy is currently in alpha state, hence minting can only be done via the periphery. If false, minting can be done directly via VAMM. function isAlpha() external view returns (bool); /// @return gap represented in WAD seconds between the maturity timestamp and end of pool trading function maturityBufferWad() external view returns (uint256); /// @notice The fixed token growth accumulated per unit of liquidity for the entire life of the vamm /// @dev This value can overflow the uint256 function fixedTokenGrowthGlobalX128() external view returns (int256); /// @notice The variable token growth accumulated per unit of liquidity for the entire life of the vamm /// @dev This value can overflow the uint256 function variableTokenGrowthGlobalX128() external view returns (int256); /// @notice The fee growth collected per unit of liquidity for the entire life of the vamm /// @dev This value can overflow the uint256 function feeGrowthGlobalX128() external view returns (uint256); /// @notice The currently in range liquidity available to the vamm function liquidity() external view returns (uint128); /// @notice The amount underlying token that are owed to the protocol /// @dev Protocol fees will never exceed uint256 function protocolFees() external view returns (uint256); function marginEngine() external view returns (IMarginEngine); function factory() external view returns (IFactory); /// @notice Function that sets the feeProtocol of the vamm /// @dev the current protocol fee as a percentage of the swap fee taken on withdrawal // represented as an integer denominator (1/x) function setFeeProtocol(uint8 feeProtocol) external; /// @notice Function that sets the _isAlpha state variable, if it is set to true the protocol is in the Alpha State /// @dev if the VAMM is at the alpha state, mints can only be done via the periphery which in turn takes care of notional caps for the LPs /// @dev this function can only be called by the owner of the VAMM function setIsAlpha(bool __isAlpha) external; /// @notice Function that sets buffer between maturity and time of last possible trade function setMaturityBuffer(uint256 __maturityBufferWad) external; /// @notice Function that sets fee of the vamm /// @dev The vamm's fee (proportion) in wad function setFee(uint256 _fee) external; /// @notice Updates internal accounting to reflect a collection of protocol fees. The actual transfer of fees must happen separately in the AMM /// @dev can only be done via the collectProtocol function of the parent AMM of the vamm function updateProtocolFees(uint256 protocolFeesCollected) external; /// @notice Sets the initial price for the vamm /// @dev Price is represented as a sqrt(amountVariableToken/amountFixedToken) Q64.96 value /// @param sqrtPriceX96 the initial sqrt price of the vamm as a Q64.96 function initializeVAMM(uint160 sqrtPriceX96) external; /// @notice removes liquidity given recipient/tickLower/tickUpper of the position /// @param recipient The address for which the liquidity will be removed /// @param tickLower The lower tick of the position in which to remove liquidity /// @param tickUpper The upper tick of the position in which to remove liqudiity /// @param amount The amount of liquidity to burn function burn( address recipient, int24 tickLower, int24 tickUpper, uint128 amount ) external returns (int256 positionMarginRequirement); /// @notice Adds liquidity for the given recipient/tickLower/tickUpper position /// @param recipient The address for which the liquidity will be created /// @param tickLower The lower tick of the position in which to add liquidity /// @param tickUpper The upper tick of the position in which to add liquidity /// @param amount The amount of liquidity to mint function mint( address recipient, int24 tickLower, int24 tickUpper, uint128 amount ) external returns (int256 positionMarginRequirement); /// @notice Initiate an Interest Rate Swap /// @param params SwapParams necessary to initiate an Interest Rate Swap /// @return fixedTokenDelta Fixed Token Delta /// @return variableTokenDelta Variable Token Delta /// @return cumulativeFeeIncurred Cumulative Fee Incurred function swap(SwapParams memory params) external returns ( int256 fixedTokenDelta, int256 variableTokenDelta, uint256 cumulativeFeeIncurred, int256 fixedTokenDeltaUnbalanced, int256 marginRequirement ); /// @notice Look up information about a specific tick in the amm /// @param tick The tick to look up /// @return liquidityGross: the total amount of position liquidity that uses the vamm either as tick lower or tick upper, /// liquidityNet: how much liquidity changes when the vamm price crosses the tick, /// feeGrowthOutsideX128: the fee growth on the other side of the tick from the current tick in underlying token. i.e. if liquidityGross is greater than 0. In addition, these values are only relative. function ticks(int24 tick) external view returns (Tick.Info memory); /// @notice Returns 256 packed tick initialized boolean values. See TickBitmap for more information function tickBitmap(int16 wordPosition) external view returns (uint256); /// @notice Computes the current fixed and variable token growth inside a given tick range given the current tick in the vamm /// @param tickLower The lower tick of the position /// @param tickUpper The upper tick of the position /// @return fixedTokenGrowthInsideX128 Fixed Token Growth inside the given tick range /// @return variableTokenGrowthInsideX128 Variable Token Growth inside the given tick range /// @return feeGrowthInsideX128 Fee Growth Inside given tick range function computeGrowthInside(int24 tickLower, int24 tickUpper) external view returns ( int256 fixedTokenGrowthInsideX128, int256 variableTokenGrowthInsideX128, uint256 feeGrowthInsideX128 ); /// @notice refreshes the Rate Oracle attached to the Margin Engine function refreshRateOracle() external; /// @notice The rateOracle contract which lets the protocol access historical apys in the yield bearing pools it is built on top of /// @return The underlying ERC20 token (e.g. USDC) function getRateOracle() external view returns (IRateOracle); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity =0.8.9; import "../interfaces/IERC20Minimal.sol"; interface IWETH { function deposit() external payable; function withdraw(uint256 amount) external; }
// SPDX-License-Identifier: Apache-2.0 pragma solidity =0.8.9; import "../IMarginEngine.sol"; import "../../utils/CustomErrors.sol"; import "../IERC20Minimal.sol"; import "../../core_libraries/TraderWithYieldBearingAssets.sol"; import "../IVAMM.sol"; import "../rate_oracles/IRateOracle.sol"; interface IFCM is CustomErrors { function setPausability(bool state) external; function getTraderWithYieldBearingAssets(address trader) external view returns (TraderWithYieldBearingAssets.Info memory traderInfo); /// @notice Initiate a Fully Collateralised Fixed Taker Swap /// @param notional amount of notional (in terms of the underlying token) to trade /// @param sqrtPriceLimitX96 the sqrtPriceLimit (in binary fixed point math notation) beyond which swaps won't be executed /// @dev An example of an initiated fully collateralised fixed taker swap is a scenario where a trader with 100 aTokens wishes to get a fixed return on them /// @dev they can choose to deposit their 100aTokens into the FCM (enter into a fixed taker position with a notional of 100) to swap variable cashflows from the aTokens /// @dev with the fixed cashflows from the variable takers function initiateFullyCollateralisedFixedTakerSwap( uint256 notional, uint160 sqrtPriceLimitX96 ) external returns (int256 fixedTokenDelta, int256 variableTokenDelta, uint256 cumulativeFeeIncurred, int256 fixedTokenDeltaUnbalanced); /// @notice Unwind a Fully Collateralised Fixed Taker Swap /// @param notionalToUnwind The amount of notional of the original Fully Collateralised Fixed Taker swap to be unwound at the current VAMM fixed rates /// @param sqrtPriceLimitX96 the sqrtPriceLimit (in binary fixed point math notation) beyond which the unwind swaps won't be executed /// @dev The purpose of this function is to let fully collateralised fixed takers to exist their swaps by entering into variable taker positions against the VAMM /// @dev thus effectively releasing the margin in yield bearing tokens from the fixed swap contract function unwindFullyCollateralisedFixedTakerSwap( uint256 notionalToUnwind, uint160 sqrtPriceLimitX96 ) external returns (int256 fixedTokenDelta, int256 variableTokenDelta, uint256 cumulativeFeeIncurred, int256 fixedTokenDeltaUnbalanced); /// @notice Settle Trader /// @dev this function in the fcm let's traders settle with the MarginEngine based on their settlement cashflows which is a functon of their fixed and variable token balances function settleTrader() external returns (int256); /// @notice /// @param account address of the position owner from the MarginEngine who wishes to settle with the FCM in underlying tokens /// @param marginDeltaInUnderlyingTokens amount in terms of underlying tokens that needs to be settled with the trader from the MarginEngine function transferMarginToMarginEngineTrader( address account, uint256 marginDeltaInUnderlyingTokens ) external; /// @notice initialize is the constructor for the proxy instances of the FCM /// @dev "constructor" for proxy instances /// @dev in the initialize function we set the vamm and the margiEngine associated with the fcm /// @dev different FCM implementations are free to have different implementations for the initialisation logic function initialize(IVAMM __vamm, IMarginEngine __marginEngine) external; /// @notice Margine Engine linked to the Full Collateralisation Module /// @return marginEngine Margine Engine linked to the Full Collateralisation Module function marginEngine() external view returns (IMarginEngine); /// @notice VAMM linked to the Full Collateralisation Module /// @return VAMM linked to the Full Collateralisation Module function vamm() external view returns (IVAMM); /// @notice Rate Oracle linked to the Full Collateralisation Module /// @return Rate Oracle linked to the Full Collateralisation Module function rateOracle() external view returns (IRateOracle); event FullyCollateralisedSwap( address indexed trader, uint256 desiredNotional, uint160 sqrtPriceLimitX96, uint256 cumulativeFeeIncurred, int256 fixedTokenDelta, int256 variableTokenDelta, int256 fixedTokenDeltaUnbalanced ); event FullyCollateralisedUnwind( address indexed trader, uint256 desiredNotional, uint160 sqrtPriceLimitX96, uint256 cumulativeFeeIncurred, int256 fixedTokenDelta, int256 variableTokenDelta, int256 fixedTokenDeltaUnbalanced ); event fcmPositionSettlement( address indexed trader, int256 settlementCashflow ); event FCMTraderUpdate( address indexed trader, uint256 marginInScaledYieldBearingTokens, int256 fixedTokenBalance, int256 variableTokenBalance ); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity =0.8.9; import "../../utils/CustomErrors.sol"; import "../IERC20Minimal.sol"; /// @dev The RateOracle is used for two purposes on the Voltz Protocol /// @dev Settlement: in order to be able to settle IRS positions after the termEndTimestamp of a given AMM /// @dev Margin Engine Computations: getApyFromTo is used by the MarginEngine /// @dev It is necessary to produce margin requirements for Trader and Liquidity Providers interface IRateOracle is CustomErrors { // events event MinSecondsSinceLastUpdate(uint256 _minSecondsSinceLastUpdate); event OracleBufferUpdate( uint256 blockTimestampScaled, address source, uint16 index, uint32 blockTimestamp, uint256 observedValue, uint16 cardinality, uint16 cardinalityNext ); /// @notice Emitted by the rate oracle for increases to the number of observations that can be stored /// @param observationCardinalityNextNew The updated value of the next observation cardinality event RateCardinalityNext( uint16 observationCardinalityNextNew ); // view functions /// @notice Gets minimum number of seconds that need to pass since the last update to the rates array /// @dev This is a throttling mechanic that needs to ensure we don't run out of space in the rates array /// @dev The maximum size of the rates array is 65535 entries // AB: as long as this doesn't affect the termEndTimestamp rateValue too much // AB: can have a different minSecondsSinceLastUpdate close to termEndTimestamp to have more granularity for settlement purposes /// @return minSecondsSinceLastUpdate in seconds function minSecondsSinceLastUpdate() external view returns (uint256); /// @notice Gets the address of the underlying token of the RateOracle /// @dev may be unset (`address(0)`) if the underlying is ETH /// @return underlying The address of the underlying token function underlying() external view returns (IERC20Minimal); /// @notice Gets the variable factor between termStartTimestamp and termEndTimestamp /// @return result The variable factor /// @dev If the current block timestamp is beyond the maturity of the AMM, then the variableFactor is getRateFromTo(termStartTimestamp, termEndTimestamp). Term end timestamps are cached for quick retrieval later. /// @dev If the current block timestamp is before the maturity of the AMM, then the variableFactor is getRateFromTo(termStartTimestamp,Time.blockTimestampScaled()); /// @dev if queried before maturity then returns the rate of return between pool initiation and current timestamp (in wad) /// @dev if queried after maturity then returns the rate of return between pool initiation and maturity timestamp (in wad) function variableFactor(uint256 termStartTimestamp, uint256 termEndTimestamp) external returns(uint256 result); /// @notice Gets the variable factor between termStartTimestamp and termEndTimestamp /// @return result The variable factor /// @dev If the current block timestamp is beyond the maturity of the AMM, then the variableFactor is getRateFromTo(termStartTimestamp, termEndTimestamp). No caching takes place. /// @dev If the current block timestamp is before the maturity of the AMM, then the variableFactor is getRateFromTo(termStartTimestamp,Time.blockTimestampScaled()); function variableFactorNoCache(uint256 termStartTimestamp, uint256 termEndTimestamp) external view returns(uint256 result); /// @notice Calculates the observed interest returned by the underlying in a given period /// @dev Reverts if we have no data point for `_from` /// @param _from The timestamp of the start of the period, in seconds /// @return The "floating rate" expressed in Wad, e.g. 4% is encoded as 0.04*10**18 = 4*10**16 function getRateFrom(uint256 _from) external view returns (uint256); /// @notice Calculates the observed interest returned by the underlying in a given period /// @dev Reverts if we have no data point for either timestamp /// @param _from The timestamp of the start of the period, in seconds /// @param _to The timestamp of the end of the period, in seconds /// @return The "floating rate" expressed in Wad, e.g. 4% is encoded as 0.04*10**18 = 4*10**16 function getRateFromTo(uint256 _from, uint256 _to) external view returns (uint256); /// @notice Calculates the observed APY returned by the rate oracle between the given timestamp and the current time /// @param from The timestamp of the start of the period, in seconds /// @dev Reverts if we have no data point for `from` /// @return apyFromTo The "floating rate" expressed in Wad, e.g. 4% is encoded as 0.04*10**18 = 4*10**16 function getApyFrom(uint256 from) external view returns (uint256 apyFromTo); /// @notice Calculates the observed APY returned by the rate oracle in a given period /// @param from The timestamp of the start of the period, in seconds /// @param to The timestamp of the end of the period, in seconds /// @dev Reverts if we have no data point for either timestamp /// @return apyFromTo The "floating rate" expressed in Wad, e.g. 4% is encoded as 0.04*10**18 = 4*10**16 function getApyFromTo(uint256 from, uint256 to) external view returns (uint256 apyFromTo); // non-view functions /// @notice Sets minSecondsSinceLastUpdate: The minimum number of seconds that need to pass since the last update to the rates array /// @dev Can only be set by the Factory Owner function setMinSecondsSinceLastUpdate(uint256 _minSecondsSinceLastUpdate) external; /// @notice Increase the maximum number of rates observations that this RateOracle will store /// @dev This method is no-op if the RateOracle already has an observationCardinalityNext greater than or equal to /// the input observationCardinalityNext. /// @param rateCardinalityNext The desired minimum number of observations for the pool to store function increaseObservationCardinalityNext(uint16 rateCardinalityNext) external; /// @notice Writes a rate observation to the rates array given the current rate cardinality, rate index and rate cardinality next /// Write oracle entry is called whenever a new position is minted via the vamm or when a swap is initiated via the vamm /// That way the gas costs of Rate Oracle updates can be distributed across organic interactions with the protocol function writeOracleEntry() external; /// @notice unique ID of the underlying yield bearing protocol (e.g. Aave v2 has id 1) /// @return yieldBearingProtocolID unique id of the underlying yield bearing protocol function UNDERLYING_YIELD_BEARING_PROTOCOL_ID() external view returns(uint8 yieldBearingProtocolID); /// @notice returns the last change in rate and time /// Gets the last two observations and returns the change in rate and time. /// This can help us to extrapolate an estiamte of the current rate from recent known rates. function getLastRateSlope() external view returns (uint256 rateChange, uint32 timeChange); /// @notice Get the current "rate" in Ray at the current timestamp. /// This might be a direct reading if real-time readings are available, or it might be an extrapolation from recent known rates. /// The source and expected values of "rate" may differ by rate oracle type. All that /// matters is that we can divide one "rate" by another "rate" to get the factor of growth between the two timestamps. /// For example if we have rates of { (t=0, rate=5), (t=100, rate=5.5) }, we can divide 5.5 by 5 to get a growth factor /// of 1.1, suggesting that 10% growth in capital was experienced between timesamp 0 and timestamp 100. /// @dev For convenience, the rate is normalised to Ray for storage, so that we can perform consistent math across all rates. /// @dev This function should revert if a valid rate cannot be discerned /// @return currentRate the rate in Ray (decimal scaled up by 10^27 for storage in a uint256) function getCurrentRateInRay() external view returns (uint256 currentRate); /// @notice returns the last change in block number and timestamp /// Some implementations may use this data to estimate timestamps for recent rate readings, if we only know the block number function getBlockSlope() external view returns (uint256 blockChange, uint32 timeChange); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity =0.8.9; interface CustomErrors { /// @dev No need to unwind a net zero position error PositionNetZero(); error DebugError(uint256 x, uint256 y); /// @dev Cannot have less margin than the minimum requirement error MarginLessThanMinimum(int256 marginRequirement); /// @dev We can't withdraw more margin than we have error WithdrawalExceedsCurrentMargin(); /// @dev Position must be settled after AMM has reached maturity error PositionNotSettled(); /// The resulting margin does not meet minimum requirements error MarginRequirementNotMet( int256 marginRequirement, int24 tick, int256 fixedTokenDelta, int256 variableTokenDelta, uint256 cumulativeFeeIncurred, int256 fixedTokenDeltaUnbalanced ); /// The position/trader needs to be below the liquidation threshold to be liquidated error CannotLiquidate(); /// Only the position/trade owner can update the LP/Trader margin error OnlyOwnerCanUpdatePosition(); error OnlyVAMM(); error OnlyFCM(); /// Margin delta must not equal zero error InvalidMarginDelta(); /// Positions and Traders cannot be settled before the applicable interest rate swap has matured error CannotSettleBeforeMaturity(); error closeToOrBeyondMaturity(); /// @dev There are not enough funds available for the requested operation error NotEnoughFunds(uint256 requested, uint256 available); /// @dev The two values were expected to have oppostite sigs, but do not error ExpectedOppositeSigns(int256 amount0, int256 amount1); /// @dev Error which is reverted if the sqrt price of the vamm is non-zero before a vamm is initialized error ExpectedSqrtPriceZeroBeforeInit(uint160 sqrtPriceX96); /// @dev Error which ensures the liquidity delta is positive if a given LP wishes to mint further liquidity in the vamm error LiquidityDeltaMustBePositiveInMint(uint128 amount); /// @dev Error which ensures the liquidity delta is positive if a given LP wishes to burn liquidity in the vamm error LiquidityDeltaMustBePositiveInBurn(uint128 amount); /// @dev Error which ensures the amount of notional specified when initiating an IRS contract (via the swap function in the vamm) is non-zero error IRSNotionalAmountSpecifiedMustBeNonZero(); /// @dev Error which ensures the VAMM is unlocked error CanOnlyTradeIfUnlocked(bool unlocked); /// @dev only the margin engine can run a certain function error OnlyMarginEngine(); /// The resulting margin does not meet minimum requirements error MarginRequirementNotMetFCM(int256 marginRequirement); /// @dev getReserveNormalizedIncome() returned zero for underlying asset. Oracle only supports active Aave-V2 assets. error AavePoolGetReserveNormalizedIncomeReturnedZero(); /// @dev getReserveNormalizedIncome() returned zero for underlying asset. Oracle only supports active Aave-V3 assets. error AaveV3PoolGetReserveNormalizedIncomeReturnedZero(); /// @dev getReserveNormalizedVariableDebt() returned zero for underlying asset. Oracle only supports active Aave-V2 assets. error AavePoolGetReserveNormalizedVariableDebtReturnedZero(); /// @dev getReserveNormalizedVariableDebt() returned zero for underlying asset. Oracle only supports active Aave-V3 assets. error AaveV3PoolGetReserveNormalizedVariableDebtReturnedZero(); /// @dev getPooledEthByShares() returned zero for Lido's stETH. error LidoGetPooledEthBySharesReturnedZero(); /// @dev getEthValue() returned zero for RocketPool's RETH. error RocketPoolGetEthValueReturnedZero(); /// @dev ctoken.exchangeRateStored() returned zero for a given Compound ctoken. Oracle only supports active Compound assets. error CTokenExchangeRateReturnedZero(); /// @dev GMX's GLP returned unordered rewards value. error GlpRewardTrackerUnorderedRate(); /// @dev currentTime < queriedTime error OOO(); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.8.9; /// @title FixedPoint128 /// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format) library FixedPoint128 { uint256 internal constant Q128 = 0x100000000000000000000000000000000; }
// SPDX-License-Identifier: MIT // solhint-disable no-inline-assembly pragma solidity =0.8.9; /// @title Contains 512-bit math functions /// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision /// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits library FullMath { /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return result The 256-bit result /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv function mulDivSigned( int256 a, uint256 b, uint256 denominator ) internal pure returns (int256 result) { if (a < 0) return -int256(mulDiv(uint256(-a), b, denominator)); return int256(mulDiv(uint256(a), b, denominator)); } function mulDiv( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { // 512-bit multiply [prod1 prod0] = a * b // Compute the product mod 2**256 and mod 2**256 - 1 // then use the Chinese Remainder Theorem to reconstruct // the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2**256 + prod0 uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product unchecked { assembly { let mm := mulmod(a, b, not(0)) prod0 := mul(a, b) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division if (prod1 == 0) { require(denominator > 0, "Division by zero"); assembly { result := div(prod0, denominator) } return result; } // Make sure the result is less than 2**256. // Also prevents denominator == 0 require(denominator > prod1, "overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0] // Compute remainder using mulmod uint256 remainder; assembly { remainder := mulmod(a, b, denominator) } // Subtract 256 bit number from 512 bit number assembly { prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator // Compute largest power of two divisor of denominator. // Always >= 1. // uint256 twos = -denominator & denominator; // https://ethereum.stackexchange.com/questions/96642/unary-operator-cannot-be-applied-to-type-uint256 uint256 twos = (type(uint256).max - denominator + 1) & denominator; // Divide denominator by power of two assembly { denominator := div(denominator, twos) } // Divide [prod1 prod0] by the factors of two assembly { prod0 := div(prod0, twos) } // Shift in bits from prod1 into prod0. For this we need // to flip `twos` such that it is 2**256 / twos. // If twos is zero, then it becomes one assembly { twos := add(div(sub(0, twos), twos), 1) } prod0 |= prod1 * twos; // Invert denominator mod 2**256 // Now that denominator is an odd number, it has an inverse // modulo 2**256 such that denominator * inv = 1 mod 2**256. // Compute the inverse by starting with a seed that is correct // correct for four bits. That is, denominator * inv = 1 mod 2**4 uint256 inv = (3 * denominator) ^ 2; // Now use Newton-Raphson iteration to improve the precision. // Thanks to Hensel's lifting lemma, this also works in modular // arithmetic, doubling the correct bits in each step. inv *= 2 - denominator * inv; // inverse mod 2**8 inv *= 2 - denominator * inv; // inverse mod 2**16 inv *= 2 - denominator * inv; // inverse mod 2**32 inv *= 2 - denominator * inv; // inverse mod 2**64 inv *= 2 - denominator * inv; // inverse mod 2**128 inv *= 2 - denominator * inv; // inverse mod 2**256 // Because the division is now exact we can divide by multiplying // with the modular inverse of denominator. This will give us the // correct result modulo 2**256. Since the precoditions guarantee // that the outcome is less than 2**256, this is the final result. // We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inv; return result; } } /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return result The 256-bit result function mulDivRoundingUp( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { result = mulDiv(a, b, denominator); if (mulmod(a, b, denominator) > 0) { require(result < type(uint256).max, "overflow"); result++; } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.8.9; /// @title Math library for liquidity library LiquidityMath { /// @notice Add a signed liquidity delta to liquidity and revert if it overflows or underflows /// @param x The liquidity before change /// @param y The delta by which liquidity should be changed /// @return z The liquidity delta function addDelta(uint128 x, int128 y) internal pure returns (uint128 z) { if (y < 0) { uint128 yAbsolute; unchecked { yAbsolute = uint128(-y); } z = x - yAbsolute; } else { z = x + uint128(y); } } }
// SPDX-License-Identifier: BUSL-1.1 // With contributions from OpenZeppelin Contracts v4.4.0 (utils/math/SafeCast.sol) pragma solidity =0.8.9; /// @title Safe casting methods /// @notice Contains methods for safely casting between types library SafeCastUni { /// @notice Cast a uint256 to a uint160, revert on overflow /// @param y The uint256 to be downcasted /// @return z The downcasted integer, now type uint160 function toUint160(uint256 y) internal pure returns (uint160 z) { require((z = uint160(y)) == y, "toUint160 oflo"); } /// @notice Cast a int256 to a int128, revert on overflow or underflow /// @param y The int256 to be downcasted /// @return z The downcasted integer, now type int128 function toInt128(int256 y) internal pure returns (int128 z) { require((z = int128(y)) == y, "toInt128 oflo"); } /// @notice Cast a uint256 to a int256, revert on overflow /// @param y The uint256 to be casted /// @return z The casted integer, now type int256 function toInt256(uint256 y) internal pure returns (int256 z) { require(y < 2**255, "toInt256 oflo"); z = int256(y); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "toUint256 < 0"); return uint256(value); } }
// SPDX-License-Identifier: BUSL-1.1 // solhint-disable no-inline-assembly pragma solidity =0.8.9; /// @title Math library for computing sqrt prices from ticks and vice versa /// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports /// prices between 2**-128 and 2**128 library TickMath { /// @dev MIN_TICK corresponds to an annualized fixed rate of 1000% /// @dev MAX_TICK corresponds to an annualized fixed rate of 0.001% /// @dev MIN and MAX TICKs can't be safely changed without reinstating getSqrtRatioAtTick removed lines of code from original /// TickMath.sol implementation in uniswap v3 /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128 int24 internal constant MIN_TICK = -69100; /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128 int24 internal constant MAX_TICK = -MIN_TICK; /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK) uint160 internal constant MIN_SQRT_RATIO = 2503036416286949174936592462; /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK) uint160 internal constant MAX_SQRT_RATIO = 2507794810551837817144115957740; /// @notice Calculates sqrt(1.0001^tick) * 2^96 /// @dev Throws if |tick| > max tick /// @param tick The input tick for the above formula /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0) /// at the given tick function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) { uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick)); require(absTick <= uint256(int256(MAX_TICK)), "T"); uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000; if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128; if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128; if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128; if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128; if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128; if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128; if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128; if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128; if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128; if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128; if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128; if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128; if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128; if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128; if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128; if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128; if (tick > 0) ratio = type(uint256).max / ratio; // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96. // we then downcast because we know the result always fits within 160 bits due to our tick input constraint // we round up in the division so getTickAtSqrtRatio of the output price is always consistent sqrtPriceX96 = uint160( (ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1) ); } /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may /// ever return. /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96 /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio function getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) { // second inequality must be < because the price can never reach the price at the max tick require( sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, "R" ); uint256 ratio = uint256(sqrtPriceX96) << 32; uint256 r = ratio; uint256 msb = 0; assembly { let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(5, gt(r, 0xFFFFFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(4, gt(r, 0xFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(3, gt(r, 0xFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(2, gt(r, 0xF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(1, gt(r, 0x3)) msb := or(msb, f) r := shr(f, r) } assembly { let f := gt(r, 0x1) msb := or(msb, f) } if (msb >= 128) r = ratio >> (msb - 127); else r = ratio << (127 - msb); // solhint-disable-next-line var-name-mixedcase int256 log_2 = (int256(msb) - 128) << 64; assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(63, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(62, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(61, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(60, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(59, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(58, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(57, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(56, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(55, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(54, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(53, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(52, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(51, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(50, f)) } // solhint-disable-next-line var-name-mixedcase int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number int24 tickLow = int24( (log_sqrt10001 - 3402992956809132418596140100660247210) >> 128 ); int24 tickHi = int24( (log_sqrt10001 + 291339464771989622907027621153398088495) >> 128 ); tick = tickLow == tickHi ? tickLow : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow; } }
// SPDX-License-Identifier: Unlicense pragma solidity >=0.8.4; /// @notice Emitted when the result overflows uint256. error PRBMath__MulDivFixedPointOverflow(uint256 prod1); /// @notice Emitted when the result overflows uint256. error PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator); /// @notice Emitted when one of the inputs is type(int256).min. error PRBMath__MulDivSignedInputTooSmall(); /// @notice Emitted when the intermediary absolute result overflows int256. error PRBMath__MulDivSignedOverflow(uint256 rAbs); /// @notice Emitted when the input is MIN_SD59x18. error PRBMathSD59x18__AbsInputTooSmall(); /// @notice Emitted when ceiling a number overflows SD59x18. error PRBMathSD59x18__CeilOverflow(int256 x); /// @notice Emitted when one of the inputs is MIN_SD59x18. error PRBMathSD59x18__DivInputTooSmall(); /// @notice Emitted when one of the intermediary unsigned results overflows SD59x18. error PRBMathSD59x18__DivOverflow(uint256 rAbs); /// @notice Emitted when the input is greater than 133.084258667509499441. error PRBMathSD59x18__ExpInputTooBig(int256 x); /// @notice Emitted when the input is greater than 192. error PRBMathSD59x18__Exp2InputTooBig(int256 x); /// @notice Emitted when flooring a number underflows SD59x18. error PRBMathSD59x18__FloorUnderflow(int256 x); /// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18. error PRBMathSD59x18__FromIntOverflow(int256 x); /// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18. error PRBMathSD59x18__FromIntUnderflow(int256 x); /// @notice Emitted when the product of the inputs is negative. error PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y); /// @notice Emitted when multiplying the inputs overflows SD59x18. error PRBMathSD59x18__GmOverflow(int256 x, int256 y); /// @notice Emitted when the input is less than or equal to zero. error PRBMathSD59x18__LogInputTooSmall(int256 x); /// @notice Emitted when one of the inputs is MIN_SD59x18. error PRBMathSD59x18__MulInputTooSmall(); /// @notice Emitted when the intermediary absolute result overflows SD59x18. error PRBMathSD59x18__MulOverflow(uint256 rAbs); /// @notice Emitted when the intermediary absolute result overflows SD59x18. error PRBMathSD59x18__PowuOverflow(uint256 rAbs); /// @notice Emitted when the input is negative. error PRBMathSD59x18__SqrtNegativeInput(int256 x); /// @notice Emitted when the calculating the square root overflows SD59x18. error PRBMathSD59x18__SqrtOverflow(int256 x); /// @notice Emitted when addition overflows UD60x18. error PRBMathUD60x18__AddOverflow(uint256 x, uint256 y); /// @notice Emitted when ceiling a number overflows UD60x18. error PRBMathUD60x18__CeilOverflow(uint256 x); /// @notice Emitted when the input is greater than 133.084258667509499441. error PRBMathUD60x18__ExpInputTooBig(uint256 x); /// @notice Emitted when the input is greater than 192. error PRBMathUD60x18__Exp2InputTooBig(uint256 x); /// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18. error PRBMathUD60x18__FromUintOverflow(uint256 x); /// @notice Emitted when multiplying the inputs overflows UD60x18. error PRBMathUD60x18__GmOverflow(uint256 x, uint256 y); /// @notice Emitted when the input is less than 1. error PRBMathUD60x18__LogInputTooSmall(uint256 x); /// @notice Emitted when the calculating the square root overflows UD60x18. error PRBMathUD60x18__SqrtOverflow(uint256 x); /// @notice Emitted when subtraction underflows UD60x18. error PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y); /// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library /// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point /// representation. When it does not, it is explicitly mentioned in the NatSpec documentation. library PRBMath { /// STRUCTS /// struct SD59x18 { int256 value; } struct UD60x18 { uint256 value; } /// STORAGE /// /// @dev How many trailing decimals can be represented. uint256 internal constant SCALE = 1e18; /// @dev Largest power of two divisor of SCALE. uint256 internal constant SCALE_LPOTD = 262144; /// @dev SCALE inverted mod 2^256. uint256 internal constant SCALE_INVERSE = 78156646155174841979727994598816262306175212592076161876661_508869554232690281; /// FUNCTIONS /// /// @notice Calculates the binary exponent of x using the binary fraction method. /// @dev Has to use 192.64-bit fixed-point numbers. /// See https://ethereum.stackexchange.com/a/96594/24693. /// @param x The exponent as an unsigned 192.64-bit fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function exp2(uint256 x) internal pure returns (uint256 result) { unchecked { // Start from 0.5 in the 192.64-bit fixed-point format. result = 0x800000000000000000000000000000000000000000000000; // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows // because the initial result is 2^191 and all magic factors are less than 2^65. if (x & 0x8000000000000000 > 0) { result = (result * 0x16A09E667F3BCC909) >> 64; } if (x & 0x4000000000000000 > 0) { result = (result * 0x1306FE0A31B7152DF) >> 64; } if (x & 0x2000000000000000 > 0) { result = (result * 0x1172B83C7D517ADCE) >> 64; } if (x & 0x1000000000000000 > 0) { result = (result * 0x10B5586CF9890F62A) >> 64; } if (x & 0x800000000000000 > 0) { result = (result * 0x1059B0D31585743AE) >> 64; } if (x & 0x400000000000000 > 0) { result = (result * 0x102C9A3E778060EE7) >> 64; } if (x & 0x200000000000000 > 0) { result = (result * 0x10163DA9FB33356D8) >> 64; } if (x & 0x100000000000000 > 0) { result = (result * 0x100B1AFA5ABCBED61) >> 64; } if (x & 0x80000000000000 > 0) { result = (result * 0x10058C86DA1C09EA2) >> 64; } if (x & 0x40000000000000 > 0) { result = (result * 0x1002C605E2E8CEC50) >> 64; } if (x & 0x20000000000000 > 0) { result = (result * 0x100162F3904051FA1) >> 64; } if (x & 0x10000000000000 > 0) { result = (result * 0x1000B175EFFDC76BA) >> 64; } if (x & 0x8000000000000 > 0) { result = (result * 0x100058BA01FB9F96D) >> 64; } if (x & 0x4000000000000 > 0) { result = (result * 0x10002C5CC37DA9492) >> 64; } if (x & 0x2000000000000 > 0) { result = (result * 0x1000162E525EE0547) >> 64; } if (x & 0x1000000000000 > 0) { result = (result * 0x10000B17255775C04) >> 64; } if (x & 0x800000000000 > 0) { result = (result * 0x1000058B91B5BC9AE) >> 64; } if (x & 0x400000000000 > 0) { result = (result * 0x100002C5C89D5EC6D) >> 64; } if (x & 0x200000000000 > 0) { result = (result * 0x10000162E43F4F831) >> 64; } if (x & 0x100000000000 > 0) { result = (result * 0x100000B1721BCFC9A) >> 64; } if (x & 0x80000000000 > 0) { result = (result * 0x10000058B90CF1E6E) >> 64; } if (x & 0x40000000000 > 0) { result = (result * 0x1000002C5C863B73F) >> 64; } if (x & 0x20000000000 > 0) { result = (result * 0x100000162E430E5A2) >> 64; } if (x & 0x10000000000 > 0) { result = (result * 0x1000000B172183551) >> 64; } if (x & 0x8000000000 > 0) { result = (result * 0x100000058B90C0B49) >> 64; } if (x & 0x4000000000 > 0) { result = (result * 0x10000002C5C8601CC) >> 64; } if (x & 0x2000000000 > 0) { result = (result * 0x1000000162E42FFF0) >> 64; } if (x & 0x1000000000 > 0) { result = (result * 0x10000000B17217FBB) >> 64; } if (x & 0x800000000 > 0) { result = (result * 0x1000000058B90BFCE) >> 64; } if (x & 0x400000000 > 0) { result = (result * 0x100000002C5C85FE3) >> 64; } if (x & 0x200000000 > 0) { result = (result * 0x10000000162E42FF1) >> 64; } if (x & 0x100000000 > 0) { result = (result * 0x100000000B17217F8) >> 64; } if (x & 0x80000000 > 0) { result = (result * 0x10000000058B90BFC) >> 64; } if (x & 0x40000000 > 0) { result = (result * 0x1000000002C5C85FE) >> 64; } if (x & 0x20000000 > 0) { result = (result * 0x100000000162E42FF) >> 64; } if (x & 0x10000000 > 0) { result = (result * 0x1000000000B17217F) >> 64; } if (x & 0x8000000 > 0) { result = (result * 0x100000000058B90C0) >> 64; } if (x & 0x4000000 > 0) { result = (result * 0x10000000002C5C860) >> 64; } if (x & 0x2000000 > 0) { result = (result * 0x1000000000162E430) >> 64; } if (x & 0x1000000 > 0) { result = (result * 0x10000000000B17218) >> 64; } if (x & 0x800000 > 0) { result = (result * 0x1000000000058B90C) >> 64; } if (x & 0x400000 > 0) { result = (result * 0x100000000002C5C86) >> 64; } if (x & 0x200000 > 0) { result = (result * 0x10000000000162E43) >> 64; } if (x & 0x100000 > 0) { result = (result * 0x100000000000B1721) >> 64; } if (x & 0x80000 > 0) { result = (result * 0x10000000000058B91) >> 64; } if (x & 0x40000 > 0) { result = (result * 0x1000000000002C5C8) >> 64; } if (x & 0x20000 > 0) { result = (result * 0x100000000000162E4) >> 64; } if (x & 0x10000 > 0) { result = (result * 0x1000000000000B172) >> 64; } if (x & 0x8000 > 0) { result = (result * 0x100000000000058B9) >> 64; } if (x & 0x4000 > 0) { result = (result * 0x10000000000002C5D) >> 64; } if (x & 0x2000 > 0) { result = (result * 0x1000000000000162E) >> 64; } if (x & 0x1000 > 0) { result = (result * 0x10000000000000B17) >> 64; } if (x & 0x800 > 0) { result = (result * 0x1000000000000058C) >> 64; } if (x & 0x400 > 0) { result = (result * 0x100000000000002C6) >> 64; } if (x & 0x200 > 0) { result = (result * 0x10000000000000163) >> 64; } if (x & 0x100 > 0) { result = (result * 0x100000000000000B1) >> 64; } if (x & 0x80 > 0) { result = (result * 0x10000000000000059) >> 64; } if (x & 0x40 > 0) { result = (result * 0x1000000000000002C) >> 64; } if (x & 0x20 > 0) { result = (result * 0x10000000000000016) >> 64; } if (x & 0x10 > 0) { result = (result * 0x1000000000000000B) >> 64; } if (x & 0x8 > 0) { result = (result * 0x10000000000000006) >> 64; } if (x & 0x4 > 0) { result = (result * 0x10000000000000003) >> 64; } if (x & 0x2 > 0) { result = (result * 0x10000000000000001) >> 64; } if (x & 0x1 > 0) { result = (result * 0x10000000000000001) >> 64; } // We're doing two things at the same time: // // 1. Multiply the result by 2^n + 1, where "2^n" is the integer part and the one is added to account for // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191 // rather than 192. // 2. Convert the result to the unsigned 60.18-decimal fixed-point format. // // This works because 2^(191-ip) = 2^ip / 2^191, where "ip" is the integer part "2^n". result *= SCALE; result >>= (191 - (x >> 64)); } } /// @notice Finds the zero-based index of the first one in the binary representation of x. /// @dev See the note on msb in the "Find First Set" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set /// @param x The uint256 number for which to find the index of the most significant bit. /// @return msb The index of the most significant bit as an uint256. function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) { if (x >= 2**128) { x >>= 128; msb += 128; } if (x >= 2**64) { x >>= 64; msb += 64; } if (x >= 2**32) { x >>= 32; msb += 32; } if (x >= 2**16) { x >>= 16; msb += 16; } if (x >= 2**8) { x >>= 8; msb += 8; } if (x >= 2**4) { x >>= 4; msb += 4; } if (x >= 2**2) { x >>= 2; msb += 2; } if (x >= 2**1) { // No need to shift x any more. msb += 1; } } /// @notice Calculates floor(x*y÷denominator) with full precision. /// /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv. /// /// Requirements: /// - The denominator cannot be zero. /// - The result must fit within uint256. /// /// Caveats: /// - This function does not work with fixed-point numbers. /// /// @param x The multiplicand as an uint256. /// @param y The multiplier as an uint256. /// @param denominator The divisor as an uint256. /// @return result The result as an uint256. function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { unchecked { result = prod0 / denominator; } return result; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (prod1 >= denominator) { revert PRBMath__MulDivOverflow(prod1, denominator); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. unchecked { // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 lpotdod = denominator & (~denominator + 1); assembly { // Divide denominator by lpotdod. denominator := div(denominator, lpotdod) // Divide [prod1 prod0] by lpotdod. prod0 := div(prod0, lpotdod) // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one. lpotdod := add(div(sub(0, lpotdod), lpotdod), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * lpotdod; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /// @notice Calculates floor(x*y÷1e18) with full precision. /// /// @dev Variant of "mulDiv" with constant folding, i.e. in which the denominator is always 1e18. Before returning the /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of /// being rounded to 1e-18. See "Listing 6" and text above it at https://accu.org/index.php/journals/1717. /// /// Requirements: /// - The result must fit within uint256. /// /// Caveats: /// - The body is purposely left uncommented; see the NatSpec comments in "PRBMath.mulDiv" to understand how this works. /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations: /// 1. x * y = type(uint256).max * SCALE /// 2. (x * y) % SCALE >= SCALE / 2 /// /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number. /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) { uint256 prod0; uint256 prod1; assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } if (prod1 >= SCALE) { revert PRBMath__MulDivFixedPointOverflow(prod1); } uint256 remainder; uint256 roundUpUnit; assembly { remainder := mulmod(x, y, SCALE) roundUpUnit := gt(remainder, 499999999999999999) } if (prod1 == 0) { unchecked { result = (prod0 / SCALE) + roundUpUnit; return result; } } assembly { result := add( mul( or( div(sub(prod0, remainder), SCALE_LPOTD), mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1)) ), SCALE_INVERSE ), roundUpUnit ) } } /// @notice Calculates floor(x*y÷denominator) with full precision. /// /// @dev An extension of "mulDiv" for signed numbers. Works by computing the signs and the absolute values separately. /// /// Requirements: /// - None of the inputs can be type(int256).min. /// - The result must fit within int256. /// /// @param x The multiplicand as an int256. /// @param y The multiplier as an int256. /// @param denominator The divisor as an int256. /// @return result The result as an int256. function mulDivSigned( int256 x, int256 y, int256 denominator ) internal pure returns (int256 result) { if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) { revert PRBMath__MulDivSignedInputTooSmall(); } // Get hold of the absolute values of x, y and the denominator. uint256 ax; uint256 ay; uint256 ad; unchecked { ax = x < 0 ? uint256(-x) : uint256(x); ay = y < 0 ? uint256(-y) : uint256(y); ad = denominator < 0 ? uint256(-denominator) : uint256(denominator); } // Compute the absolute value of (x*y)÷denominator. The result must fit within int256. uint256 rAbs = mulDiv(ax, ay, ad); if (rAbs > uint256(type(int256).max)) { revert PRBMath__MulDivSignedOverflow(rAbs); } // Get the signs of x, y and the denominator. uint256 sx; uint256 sy; uint256 sd; assembly { sx := sgt(x, sub(0, 1)) sy := sgt(y, sub(0, 1)) sd := sgt(denominator, sub(0, 1)) } // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs. // If yes, the result should be negative. result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs); } /// @notice Calculates the square root of x, rounding down. /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// /// Caveats: /// - This function does not work with fixed-point numbers. /// /// @param x The uint256 number for which to calculate the square root. /// @return result The result as an uint256. function sqrt(uint256 x) internal pure returns (uint256 result) { if (x == 0) { return 0; } // Set the initial guess to the least power of two that is greater than or equal to sqrt(x). uint256 xAux = uint256(x); result = 1; if (xAux >= 0x100000000000000000000000000000000) { xAux >>= 128; result <<= 64; } if (xAux >= 0x10000000000000000) { xAux >>= 64; result <<= 32; } if (xAux >= 0x100000000) { xAux >>= 32; result <<= 16; } if (xAux >= 0x10000) { xAux >>= 16; result <<= 8; } if (xAux >= 0x100) { xAux >>= 8; result <<= 4; } if (xAux >= 0x10) { xAux >>= 4; result <<= 2; } if (xAux >= 0x8) { result <<= 1; } // The operations can never overflow because the result is max 2^127 when it enters this block. unchecked { result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; // Seven iterations should be enough uint256 roundedDownResult = x / result; return result >= roundedDownResult ? roundedDownResult : result; } } }
// SPDX-License-Identifier: Unlicense pragma solidity >=0.8.4; import "./PRBMath.sol"; /// @title PRBMathSD59x18 /// @author Paul Razvan Berg /// @notice Smart contract library for advanced fixed-point math that works with int256 numbers considered to have 18 /// trailing decimals. We call this number representation signed 59.18-decimal fixed-point, since the numbers can have /// a sign and there can be up to 59 digits in the integer part and up to 18 decimals in the fractional part. The numbers /// are bound by the minimum and the maximum values permitted by the Solidity type int256. library PRBMathSD59x18 { /// @dev log2(e) as a signed 59.18-decimal fixed-point number. int256 internal constant LOG2_E = 1_442695040888963407; /// @dev Half the SCALE number. int256 internal constant HALF_SCALE = 5e17; /// @dev The maximum value a signed 59.18-decimal fixed-point number can have. int256 internal constant MAX_SD59x18 = 57896044618658097711785492504343953926634992332820282019728_792003956564819967; /// @dev The maximum whole value a signed 59.18-decimal fixed-point number can have. int256 internal constant MAX_WHOLE_SD59x18 = 57896044618658097711785492504343953926634992332820282019728_000000000000000000; /// @dev The minimum value a signed 59.18-decimal fixed-point number can have. int256 internal constant MIN_SD59x18 = -57896044618658097711785492504343953926634992332820282019728_792003956564819968; /// @dev The minimum whole value a signed 59.18-decimal fixed-point number can have. int256 internal constant MIN_WHOLE_SD59x18 = -57896044618658097711785492504343953926634992332820282019728_000000000000000000; /// @dev How many trailing decimals can be represented. int256 internal constant SCALE = 1e18; /// INTERNAL FUNCTIONS /// /// @notice Calculate the absolute value of x. /// /// @dev Requirements: /// - x must be greater than MIN_SD59x18. /// /// @param x The number to calculate the absolute value for. /// @param result The absolute value of x. function abs(int256 x) internal pure returns (int256 result) { unchecked { if (x == MIN_SD59x18) { revert PRBMathSD59x18__AbsInputTooSmall(); } result = x < 0 ? -x : x; } } /// @notice Calculates the arithmetic average of x and y, rounding down. /// @param x The first operand as a signed 59.18-decimal fixed-point number. /// @param y The second operand as a signed 59.18-decimal fixed-point number. /// @return result The arithmetic average as a signed 59.18-decimal fixed-point number. function avg(int256 x, int256 y) internal pure returns (int256 result) { // The operations can never overflow. unchecked { int256 sum = (x >> 1) + (y >> 1); if (sum < 0) { // If at least one of x and y is odd, we add 1 to the result. This is because shifting negative numbers to the // right rounds down to infinity. assembly { result := add(sum, and(or(x, y), 1)) } } else { // If both x and y are odd, we add 1 to the result. This is because if both numbers are odd, the 0.5 // remainder gets truncated twice. result = sum + (x & y & 1); } } } /// @notice Yields the least greatest signed 59.18 decimal fixed-point number greater than or equal to x. /// /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts. /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions. /// /// Requirements: /// - x must be less than or equal to MAX_WHOLE_SD59x18. /// /// @param x The signed 59.18-decimal fixed-point number to ceil. /// @param result The least integer greater than or equal to x, as a signed 58.18-decimal fixed-point number. function ceil(int256 x) internal pure returns (int256 result) { if (x > MAX_WHOLE_SD59x18) { revert PRBMathSD59x18__CeilOverflow(x); } unchecked { int256 remainder = x % SCALE; if (remainder == 0) { result = x; } else { // Solidity uses C fmod style, which returns a modulus with the same sign as x. result = x - remainder; if (x > 0) { result += SCALE; } } } } /// @notice Divides two signed 59.18-decimal fixed-point numbers, returning a new signed 59.18-decimal fixed-point number. /// /// @dev Variant of "mulDiv" that works with signed numbers. Works by computing the signs and the absolute values separately. /// /// Requirements: /// - All from "PRBMath.mulDiv". /// - None of the inputs can be MIN_SD59x18. /// - The denominator cannot be zero. /// - The result must fit within int256. /// /// Caveats: /// - All from "PRBMath.mulDiv". /// /// @param x The numerator as a signed 59.18-decimal fixed-point number. /// @param y The denominator as a signed 59.18-decimal fixed-point number. /// @param result The quotient as a signed 59.18-decimal fixed-point number. function div(int256 x, int256 y) internal pure returns (int256 result) { if (x == MIN_SD59x18 || y == MIN_SD59x18) { revert PRBMathSD59x18__DivInputTooSmall(); } // Get hold of the absolute values of x and y. uint256 ax; uint256 ay; unchecked { ax = x < 0 ? uint256(-x) : uint256(x); ay = y < 0 ? uint256(-y) : uint256(y); } // Compute the absolute value of (x*SCALE)÷y. The result must fit within int256. uint256 rAbs = PRBMath.mulDiv(ax, uint256(SCALE), ay); if (rAbs > uint256(MAX_SD59x18)) { revert PRBMathSD59x18__DivOverflow(rAbs); } // Get the signs of x and y. uint256 sx; uint256 sy; assembly { sx := sgt(x, sub(0, 1)) sy := sgt(y, sub(0, 1)) } // XOR over sx and sy. This is basically checking whether the inputs have the same sign. If yes, the result // should be positive. Otherwise, it should be negative. result = sx ^ sy == 1 ? -int256(rAbs) : int256(rAbs); } /// @notice Returns Euler's number as a signed 59.18-decimal fixed-point number. /// @dev See https://en.wikipedia.org/wiki/E_(mathematical_constant). function e() internal pure returns (int256 result) { result = 2_718281828459045235; } /// @notice Calculates the natural exponent of x. /// /// @dev Based on the insight that e^x = 2^(x * log2(e)). /// /// Requirements: /// - All from "log2". /// - x must be less than 133.084258667509499441. /// /// Caveats: /// - All from "exp2". /// - For any x less than -41.446531673892822322, the result is zero. /// /// @param x The exponent as a signed 59.18-decimal fixed-point number. /// @return result The result as a signed 59.18-decimal fixed-point number. function exp(int256 x) internal pure returns (int256 result) { // Without this check, the value passed to "exp2" would be less than -59.794705707972522261. if (x < -41_446531673892822322) { return 0; } // Without this check, the value passed to "exp2" would be greater than 192. if (x >= 133_084258667509499441) { revert PRBMathSD59x18__ExpInputTooBig(x); } // Do the fixed-point multiplication inline to save gas. unchecked { int256 doubleScaleProduct = x * LOG2_E; result = exp2((doubleScaleProduct + HALF_SCALE) / SCALE); } } /// @notice Calculates the binary exponent of x using the binary fraction method. /// /// @dev See https://ethereum.stackexchange.com/q/79903/24693. /// /// Requirements: /// - x must be 192 or less. /// - The result must fit within MAX_SD59x18. /// /// Caveats: /// - For any x less than -59.794705707972522261, the result is zero. /// /// @param x The exponent as a signed 59.18-decimal fixed-point number. /// @return result The result as a signed 59.18-decimal fixed-point number. function exp2(int256 x) internal pure returns (int256 result) { // This works because 2^(-x) = 1/2^x. if (x < 0) { // 2^59.794705707972522262 is the maximum number whose inverse does not truncate down to zero. if (x < -59_794705707972522261) { return 0; } // Do the fixed-point inversion inline to save gas. The numerator is SCALE * SCALE. unchecked { result = 1e36 / exp2(-x); } } else { // 2^192 doesn't fit within the 192.64-bit format used internally in this function. if (x >= 192e18) { revert PRBMathSD59x18__Exp2InputTooBig(x); } unchecked { // Convert x to the 192.64-bit fixed-point format. uint256 x192x64 = (uint256(x) << 64) / uint256(SCALE); // Safe to convert the result to int256 directly because the maximum input allowed is 192. result = int256(PRBMath.exp2(x192x64)); } } } /// @notice Yields the greatest signed 59.18 decimal fixed-point number less than or equal to x. /// /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts. /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions. /// /// Requirements: /// - x must be greater than or equal to MIN_WHOLE_SD59x18. /// /// @param x The signed 59.18-decimal fixed-point number to floor. /// @param result The greatest integer less than or equal to x, as a signed 58.18-decimal fixed-point number. function floor(int256 x) internal pure returns (int256 result) { if (x < MIN_WHOLE_SD59x18) { revert PRBMathSD59x18__FloorUnderflow(x); } unchecked { int256 remainder = x % SCALE; if (remainder == 0) { result = x; } else { // Solidity uses C fmod style, which returns a modulus with the same sign as x. result = x - remainder; if (x < 0) { result -= SCALE; } } } } /// @notice Yields the excess beyond the floor of x for positive numbers and the part of the number to the right /// of the radix point for negative numbers. /// @dev Based on the odd function definition. https://en.wikipedia.org/wiki/Fractional_part /// @param x The signed 59.18-decimal fixed-point number to get the fractional part of. /// @param result The fractional part of x as a signed 59.18-decimal fixed-point number. function frac(int256 x) internal pure returns (int256 result) { unchecked { result = x % SCALE; } } /// @notice Converts a number from basic integer form to signed 59.18-decimal fixed-point representation. /// /// @dev Requirements: /// - x must be greater than or equal to MIN_SD59x18 divided by SCALE. /// - x must be less than or equal to MAX_SD59x18 divided by SCALE. /// /// @param x The basic integer to convert. /// @param result The same number in signed 59.18-decimal fixed-point representation. function fromInt(int256 x) internal pure returns (int256 result) { unchecked { if (x < MIN_SD59x18 / SCALE) { revert PRBMathSD59x18__FromIntUnderflow(x); } if (x > MAX_SD59x18 / SCALE) { revert PRBMathSD59x18__FromIntOverflow(x); } result = x * SCALE; } } /// @notice Calculates geometric mean of x and y, i.e. sqrt(x * y), rounding down. /// /// @dev Requirements: /// - x * y must fit within MAX_SD59x18, lest it overflows. /// - x * y cannot be negative. /// /// @param x The first operand as a signed 59.18-decimal fixed-point number. /// @param y The second operand as a signed 59.18-decimal fixed-point number. /// @return result The result as a signed 59.18-decimal fixed-point number. function gm(int256 x, int256 y) internal pure returns (int256 result) { if (x == 0) { return 0; } unchecked { // Checking for overflow this way is faster than letting Solidity do it. int256 xy = x * y; if (xy / x != y) { revert PRBMathSD59x18__GmOverflow(x, y); } // The product cannot be negative. if (xy < 0) { revert PRBMathSD59x18__GmNegativeProduct(x, y); } // We don't need to multiply by the SCALE here because the x*y product had already picked up a factor of SCALE // during multiplication. See the comments within the "sqrt" function. result = int256(PRBMath.sqrt(uint256(xy))); } } /// @notice Calculates 1 / x, rounding toward zero. /// /// @dev Requirements: /// - x cannot be zero. /// /// @param x The signed 59.18-decimal fixed-point number for which to calculate the inverse. /// @return result The inverse as a signed 59.18-decimal fixed-point number. function inv(int256 x) internal pure returns (int256 result) { unchecked { // 1e36 is SCALE * SCALE. result = 1e36 / x; } } /// @notice Calculates the natural logarithm of x. /// /// @dev Based on the insight that ln(x) = log2(x) / log2(e). /// /// Requirements: /// - All from "log2". /// /// Caveats: /// - All from "log2". /// - This doesn't return exactly 1 for 2718281828459045235, for that we would need more fine-grained precision. /// /// @param x The signed 59.18-decimal fixed-point number for which to calculate the natural logarithm. /// @return result The natural logarithm as a signed 59.18-decimal fixed-point number. function ln(int256 x) internal pure returns (int256 result) { // Do the fixed-point multiplication inline to save gas. This is overflow-safe because the maximum value that log2(x) // can return is 195205294292027477728. unchecked { result = (log2(x) * SCALE) / LOG2_E; } } /// @notice Calculates the common logarithm of x. /// /// @dev First checks if x is an exact power of ten and it stops if yes. If it's not, calculates the common /// logarithm based on the insight that log10(x) = log2(x) / log2(10). /// /// Requirements: /// - All from "log2". /// /// Caveats: /// - All from "log2". /// /// @param x The signed 59.18-decimal fixed-point number for which to calculate the common logarithm. /// @return result The common logarithm as a signed 59.18-decimal fixed-point number. function log10(int256 x) internal pure returns (int256 result) { if (x <= 0) { revert PRBMathSD59x18__LogInputTooSmall(x); } // Note that the "mul" in this block is the assembly mul operation, not the "mul" function defined in this contract. // prettier-ignore assembly { switch x case 1 { result := mul(SCALE, sub(0, 18)) } case 10 { result := mul(SCALE, sub(1, 18)) } case 100 { result := mul(SCALE, sub(2, 18)) } case 1000 { result := mul(SCALE, sub(3, 18)) } case 10000 { result := mul(SCALE, sub(4, 18)) } case 100000 { result := mul(SCALE, sub(5, 18)) } case 1000000 { result := mul(SCALE, sub(6, 18)) } case 10000000 { result := mul(SCALE, sub(7, 18)) } case 100000000 { result := mul(SCALE, sub(8, 18)) } case 1000000000 { result := mul(SCALE, sub(9, 18)) } case 10000000000 { result := mul(SCALE, sub(10, 18)) } case 100000000000 { result := mul(SCALE, sub(11, 18)) } case 1000000000000 { result := mul(SCALE, sub(12, 18)) } case 10000000000000 { result := mul(SCALE, sub(13, 18)) } case 100000000000000 { result := mul(SCALE, sub(14, 18)) } case 1000000000000000 { result := mul(SCALE, sub(15, 18)) } case 10000000000000000 { result := mul(SCALE, sub(16, 18)) } case 100000000000000000 { result := mul(SCALE, sub(17, 18)) } case 1000000000000000000 { result := 0 } case 10000000000000000000 { result := SCALE } case 100000000000000000000 { result := mul(SCALE, 2) } case 1000000000000000000000 { result := mul(SCALE, 3) } case 10000000000000000000000 { result := mul(SCALE, 4) } case 100000000000000000000000 { result := mul(SCALE, 5) } case 1000000000000000000000000 { result := mul(SCALE, 6) } case 10000000000000000000000000 { result := mul(SCALE, 7) } case 100000000000000000000000000 { result := mul(SCALE, 8) } case 1000000000000000000000000000 { result := mul(SCALE, 9) } case 10000000000000000000000000000 { result := mul(SCALE, 10) } case 100000000000000000000000000000 { result := mul(SCALE, 11) } case 1000000000000000000000000000000 { result := mul(SCALE, 12) } case 10000000000000000000000000000000 { result := mul(SCALE, 13) } case 100000000000000000000000000000000 { result := mul(SCALE, 14) } case 1000000000000000000000000000000000 { result := mul(SCALE, 15) } case 10000000000000000000000000000000000 { result := mul(SCALE, 16) } case 100000000000000000000000000000000000 { result := mul(SCALE, 17) } case 1000000000000000000000000000000000000 { result := mul(SCALE, 18) } case 10000000000000000000000000000000000000 { result := mul(SCALE, 19) } case 100000000000000000000000000000000000000 { result := mul(SCALE, 20) } case 1000000000000000000000000000000000000000 { result := mul(SCALE, 21) } case 10000000000000000000000000000000000000000 { result := mul(SCALE, 22) } case 100000000000000000000000000000000000000000 { result := mul(SCALE, 23) } case 1000000000000000000000000000000000000000000 { result := mul(SCALE, 24) } case 10000000000000000000000000000000000000000000 { result := mul(SCALE, 25) } case 100000000000000000000000000000000000000000000 { result := mul(SCALE, 26) } case 1000000000000000000000000000000000000000000000 { result := mul(SCALE, 27) } case 10000000000000000000000000000000000000000000000 { result := mul(SCALE, 28) } case 100000000000000000000000000000000000000000000000 { result := mul(SCALE, 29) } case 1000000000000000000000000000000000000000000000000 { result := mul(SCALE, 30) } case 10000000000000000000000000000000000000000000000000 { result := mul(SCALE, 31) } case 100000000000000000000000000000000000000000000000000 { result := mul(SCALE, 32) } case 1000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 33) } case 10000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 34) } case 100000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 35) } case 1000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 36) } case 10000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 37) } case 100000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 38) } case 1000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 39) } case 10000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 40) } case 100000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 41) } case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 42) } case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 43) } case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 44) } case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 45) } case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 46) } case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 47) } case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 48) } case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 49) } case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 50) } case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 51) } case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 52) } case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 53) } case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 54) } case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 55) } case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 56) } case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 57) } case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 58) } default { result := MAX_SD59x18 } } if (result == MAX_SD59x18) { // Do the fixed-point division inline to save gas. The denominator is log2(10). unchecked { result = (log2(x) * SCALE) / 3_321928094887362347; } } } /// @notice Calculates the binary logarithm of x. /// /// @dev Based on the iterative approximation algorithm. /// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation /// /// Requirements: /// - x must be greater than zero. /// /// Caveats: /// - The results are not perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation. /// /// @param x The signed 59.18-decimal fixed-point number for which to calculate the binary logarithm. /// @return result The binary logarithm as a signed 59.18-decimal fixed-point number. function log2(int256 x) internal pure returns (int256 result) { if (x <= 0) { revert PRBMathSD59x18__LogInputTooSmall(x); } unchecked { // This works because log2(x) = -log2(1/x). int256 sign; if (x >= SCALE) { sign = 1; } else { sign = -1; // Do the fixed-point inversion inline to save gas. The numerator is SCALE * SCALE. assembly { x := div(1000000000000000000000000000000000000, x) } } // Calculate the integer part of the logarithm and add it to the result and finally calculate y = x * 2^(-n). uint256 n = PRBMath.mostSignificantBit(uint256(x / SCALE)); // The integer part of the logarithm as a signed 59.18-decimal fixed-point number. The operation can't overflow // because n is maximum 255, SCALE is 1e18 and sign is either 1 or -1. result = int256(n) * SCALE; // This is y = x * 2^(-n). int256 y = x >> n; // If y = 1, the fractional part is zero. if (y == SCALE) { return result * sign; } // Calculate the fractional part via the iterative approximation. // The "delta >>= 1" part is equivalent to "delta /= 2", but shifting bits is faster. for (int256 delta = int256(HALF_SCALE); delta > 0; delta >>= 1) { y = (y * y) / SCALE; // Is y^2 > 2 and so in the range [2,4)? if (y >= 2 * SCALE) { // Add the 2^(-m) factor to the logarithm. result += delta; // Corresponds to z/2 on Wikipedia. y >>= 1; } } result *= sign; } } /// @notice Multiplies two signed 59.18-decimal fixed-point numbers together, returning a new signed 59.18-decimal /// fixed-point number. /// /// @dev Variant of "mulDiv" that works with signed numbers and employs constant folding, i.e. the denominator is /// always 1e18. /// /// Requirements: /// - All from "PRBMath.mulDivFixedPoint". /// - None of the inputs can be MIN_SD59x18 /// - The result must fit within MAX_SD59x18. /// /// Caveats: /// - The body is purposely left uncommented; see the NatSpec comments in "PRBMath.mulDiv" to understand how this works. /// /// @param x The multiplicand as a signed 59.18-decimal fixed-point number. /// @param y The multiplier as a signed 59.18-decimal fixed-point number. /// @return result The product as a signed 59.18-decimal fixed-point number. function mul(int256 x, int256 y) internal pure returns (int256 result) { if (x == MIN_SD59x18 || y == MIN_SD59x18) { revert PRBMathSD59x18__MulInputTooSmall(); } unchecked { uint256 ax; uint256 ay; ax = x < 0 ? uint256(-x) : uint256(x); ay = y < 0 ? uint256(-y) : uint256(y); uint256 rAbs = PRBMath.mulDivFixedPoint(ax, ay); if (rAbs > uint256(MAX_SD59x18)) { revert PRBMathSD59x18__MulOverflow(rAbs); } uint256 sx; uint256 sy; assembly { sx := sgt(x, sub(0, 1)) sy := sgt(y, sub(0, 1)) } result = sx ^ sy == 1 ? -int256(rAbs) : int256(rAbs); } } /// @notice Returns PI as a signed 59.18-decimal fixed-point number. function pi() internal pure returns (int256 result) { result = 3_141592653589793238; } /// @notice Raises x to the power of y. /// /// @dev Based on the insight that x^y = 2^(log2(x) * y). /// /// Requirements: /// - All from "exp2", "log2" and "mul". /// - z cannot be zero. /// /// Caveats: /// - All from "exp2", "log2" and "mul". /// - Assumes 0^0 is 1. /// /// @param x Number to raise to given power y, as a signed 59.18-decimal fixed-point number. /// @param y Exponent to raise x to, as a signed 59.18-decimal fixed-point number. /// @return result x raised to power y, as a signed 59.18-decimal fixed-point number. function pow(int256 x, int256 y) internal pure returns (int256 result) { if (x == 0) { result = y == 0 ? SCALE : int256(0); } else { result = exp2(mul(log2(x), y)); } } /// @notice Raises x (signed 59.18-decimal fixed-point number) to the power of y (basic unsigned integer) using the /// famous algorithm "exponentiation by squaring". /// /// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring /// /// Requirements: /// - All from "abs" and "PRBMath.mulDivFixedPoint". /// - The result must fit within MAX_SD59x18. /// /// Caveats: /// - All from "PRBMath.mulDivFixedPoint". /// - Assumes 0^0 is 1. /// /// @param x The base as a signed 59.18-decimal fixed-point number. /// @param y The exponent as an uint256. /// @return result The result as a signed 59.18-decimal fixed-point number. function powu(int256 x, uint256 y) internal pure returns (int256 result) { uint256 xAbs = uint256(abs(x)); // Calculate the first iteration of the loop in advance. uint256 rAbs = y & 1 > 0 ? xAbs : uint256(SCALE); // Equivalent to "for(y /= 2; y > 0; y /= 2)" but faster. uint256 yAux = y; for (yAux >>= 1; yAux > 0; yAux >>= 1) { xAbs = PRBMath.mulDivFixedPoint(xAbs, xAbs); // Equivalent to "y % 2 == 1" but faster. if (yAux & 1 > 0) { rAbs = PRBMath.mulDivFixedPoint(rAbs, xAbs); } } // The result must fit within the 59.18-decimal fixed-point representation. if (rAbs > uint256(MAX_SD59x18)) { revert PRBMathSD59x18__PowuOverflow(rAbs); } // Is the base negative and the exponent an odd number? bool isNegative = x < 0 && y & 1 == 1; result = isNegative ? -int256(rAbs) : int256(rAbs); } /// @notice Returns 1 as a signed 59.18-decimal fixed-point number. function scale() internal pure returns (int256 result) { result = SCALE; } /// @notice Calculates the square root of x, rounding down. /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// /// Requirements: /// - x cannot be negative. /// - x must be less than MAX_SD59x18 / SCALE. /// /// @param x The signed 59.18-decimal fixed-point number for which to calculate the square root. /// @return result The result as a signed 59.18-decimal fixed-point . function sqrt(int256 x) internal pure returns (int256 result) { unchecked { if (x < 0) { revert PRBMathSD59x18__SqrtNegativeInput(x); } if (x > MAX_SD59x18 / SCALE) { revert PRBMathSD59x18__SqrtOverflow(x); } // Multiply x by the SCALE to account for the factor of SCALE that is picked up when multiplying two signed // 59.18-decimal fixed-point numbers together (in this case, those two numbers are both the square root). result = int256(PRBMath.sqrt(uint256(x * SCALE))); } } /// @notice Converts a signed 59.18-decimal fixed-point number to basic integer form, rounding down in the process. /// @param x The signed 59.18-decimal fixed-point number to convert. /// @return result The same number in basic integer form. function toInt(int256 x) internal pure returns (int256 result) { unchecked { result = x / SCALE; } } }
// SPDX-License-Identifier: Unlicense pragma solidity >=0.8.4; import "./PRBMath.sol"; /// @title PRBMathUD60x18 /// @author Paul Razvan Berg /// @notice Smart contract library for advanced fixed-point math that works with uint256 numbers considered to have 18 /// trailing decimals. We call this number representation unsigned 60.18-decimal fixed-point, since there can be up to 60 /// digits in the integer part and up to 18 decimals in the fractional part. The numbers are bound by the minimum and the /// maximum values permitted by the Solidity type uint256. library PRBMathUD60x18 { /// @dev Half the SCALE number. uint256 internal constant HALF_SCALE = 5e17; /// @dev log2(e) as an unsigned 60.18-decimal fixed-point number. uint256 internal constant LOG2_E = 1_442695040888963407; /// @dev The maximum value an unsigned 60.18-decimal fixed-point number can have. uint256 internal constant MAX_UD60x18 = 115792089237316195423570985008687907853269984665640564039457_584007913129639935; /// @dev The maximum whole value an unsigned 60.18-decimal fixed-point number can have. uint256 internal constant MAX_WHOLE_UD60x18 = 115792089237316195423570985008687907853269984665640564039457_000000000000000000; /// @dev How many trailing decimals can be represented. uint256 internal constant SCALE = 1e18; /// @notice Calculates the arithmetic average of x and y, rounding down. /// @param x The first operand as an unsigned 60.18-decimal fixed-point number. /// @param y The second operand as an unsigned 60.18-decimal fixed-point number. /// @return result The arithmetic average as an unsigned 60.18-decimal fixed-point number. function avg(uint256 x, uint256 y) internal pure returns (uint256 result) { // The operations can never overflow. unchecked { // The last operand checks if both x and y are odd and if that is the case, we add 1 to the result. We need // to do this because if both numbers are odd, the 0.5 remainder gets truncated twice. result = (x >> 1) + (y >> 1) + (x & y & 1); } } /// @notice Yields the least unsigned 60.18 decimal fixed-point number greater than or equal to x. /// /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts. /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions. /// /// Requirements: /// - x must be less than or equal to MAX_WHOLE_UD60x18. /// /// @param x The unsigned 60.18-decimal fixed-point number to ceil. /// @param result The least integer greater than or equal to x, as an unsigned 60.18-decimal fixed-point number. function ceil(uint256 x) internal pure returns (uint256 result) { if (x > MAX_WHOLE_UD60x18) { revert PRBMathUD60x18__CeilOverflow(x); } assembly { // Equivalent to "x % SCALE" but faster. let remainder := mod(x, SCALE) // Equivalent to "SCALE - remainder" but faster. let delta := sub(SCALE, remainder) // Equivalent to "x + delta * (remainder > 0 ? 1 : 0)" but faster. result := add(x, mul(delta, gt(remainder, 0))) } } /// @notice Divides two unsigned 60.18-decimal fixed-point numbers, returning a new unsigned 60.18-decimal fixed-point number. /// /// @dev Uses mulDiv to enable overflow-safe multiplication and division. /// /// Requirements: /// - The denominator cannot be zero. /// /// @param x The numerator as an unsigned 60.18-decimal fixed-point number. /// @param y The denominator as an unsigned 60.18-decimal fixed-point number. /// @param result The quotient as an unsigned 60.18-decimal fixed-point number. function div(uint256 x, uint256 y) internal pure returns (uint256 result) { result = PRBMath.mulDiv(x, SCALE, y); } /// @notice Returns Euler's number as an unsigned 60.18-decimal fixed-point number. /// @dev See https://en.wikipedia.org/wiki/E_(mathematical_constant). function e() internal pure returns (uint256 result) { result = 2_718281828459045235; } /// @notice Calculates the natural exponent of x. /// /// @dev Based on the insight that e^x = 2^(x * log2(e)). /// /// Requirements: /// - All from "log2". /// - x must be less than 133.084258667509499441. /// /// @param x The exponent as an unsigned 60.18-decimal fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function exp(uint256 x) internal pure returns (uint256 result) { // Without this check, the value passed to "exp2" would be greater than 192. if (x >= 133_084258667509499441) { revert PRBMathUD60x18__ExpInputTooBig(x); } // Do the fixed-point multiplication inline to save gas. unchecked { uint256 doubleScaleProduct = x * LOG2_E; result = exp2((doubleScaleProduct + HALF_SCALE) / SCALE); } } /// @notice Calculates the binary exponent of x using the binary fraction method. /// /// @dev See https://ethereum.stackexchange.com/q/79903/24693. /// /// Requirements: /// - x must be 192 or less. /// - The result must fit within MAX_UD60x18. /// /// @param x The exponent as an unsigned 60.18-decimal fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function exp2(uint256 x) internal pure returns (uint256 result) { // 2^192 doesn't fit within the 192.64-bit format used internally in this function. if (x >= 192e18) { revert PRBMathUD60x18__Exp2InputTooBig(x); } unchecked { // Convert x to the 192.64-bit fixed-point format. uint256 x192x64 = (x << 64) / SCALE; // Pass x to the PRBMath.exp2 function, which uses the 192.64-bit fixed-point number representation. result = PRBMath.exp2(x192x64); } } /// @notice Yields the greatest unsigned 60.18 decimal fixed-point number less than or equal to x. /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts. /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions. /// @param x The unsigned 60.18-decimal fixed-point number to floor. /// @param result The greatest integer less than or equal to x, as an unsigned 60.18-decimal fixed-point number. function floor(uint256 x) internal pure returns (uint256 result) { assembly { // Equivalent to "x % SCALE" but faster. let remainder := mod(x, SCALE) // Equivalent to "x - remainder * (remainder > 0 ? 1 : 0)" but faster. result := sub(x, mul(remainder, gt(remainder, 0))) } } /// @notice Yields the excess beyond the floor of x. /// @dev Based on the odd function definition https://en.wikipedia.org/wiki/Fractional_part. /// @param x The unsigned 60.18-decimal fixed-point number to get the fractional part of. /// @param result The fractional part of x as an unsigned 60.18-decimal fixed-point number. function frac(uint256 x) internal pure returns (uint256 result) { assembly { result := mod(x, SCALE) } } /// @notice Converts a number from basic integer form to unsigned 60.18-decimal fixed-point representation. /// /// @dev Requirements: /// - x must be less than or equal to MAX_UD60x18 divided by SCALE. /// /// @param x The basic integer to convert. /// @param result The same number in unsigned 60.18-decimal fixed-point representation. function fromUint(uint256 x) internal pure returns (uint256 result) { unchecked { if (x > MAX_UD60x18 / SCALE) { revert PRBMathUD60x18__FromUintOverflow(x); } result = x * SCALE; } } /// @notice Calculates geometric mean of x and y, i.e. sqrt(x * y), rounding down. /// /// @dev Requirements: /// - x * y must fit within MAX_UD60x18, lest it overflows. /// /// @param x The first operand as an unsigned 60.18-decimal fixed-point number. /// @param y The second operand as an unsigned 60.18-decimal fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function gm(uint256 x, uint256 y) internal pure returns (uint256 result) { if (x == 0) { return 0; } unchecked { // Checking for overflow this way is faster than letting Solidity do it. uint256 xy = x * y; if (xy / x != y) { revert PRBMathUD60x18__GmOverflow(x, y); } // We don't need to multiply by the SCALE here because the x*y product had already picked up a factor of SCALE // during multiplication. See the comments within the "sqrt" function. result = PRBMath.sqrt(xy); } } /// @notice Calculates 1 / x, rounding toward zero. /// /// @dev Requirements: /// - x cannot be zero. /// /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the inverse. /// @return result The inverse as an unsigned 60.18-decimal fixed-point number. function inv(uint256 x) internal pure returns (uint256 result) { unchecked { // 1e36 is SCALE * SCALE. result = 1e36 / x; } } /// @notice Calculates the natural logarithm of x. /// /// @dev Based on the insight that ln(x) = log2(x) / log2(e). /// /// Requirements: /// - All from "log2". /// /// Caveats: /// - All from "log2". /// - This doesn't return exactly 1 for 2.718281828459045235, for that we would need more fine-grained precision. /// /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the natural logarithm. /// @return result The natural logarithm as an unsigned 60.18-decimal fixed-point number. function ln(uint256 x) internal pure returns (uint256 result) { // Do the fixed-point multiplication inline to save gas. This is overflow-safe because the maximum value that log2(x) // can return is 196205294292027477728. unchecked { result = (log2(x) * SCALE) / LOG2_E; } } /// @notice Calculates the common logarithm of x. /// /// @dev First checks if x is an exact power of ten and it stops if yes. If it's not, calculates the common /// logarithm based on the insight that log10(x) = log2(x) / log2(10). /// /// Requirements: /// - All from "log2". /// /// Caveats: /// - All from "log2". /// /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the common logarithm. /// @return result The common logarithm as an unsigned 60.18-decimal fixed-point number. function log10(uint256 x) internal pure returns (uint256 result) { if (x < SCALE) { revert PRBMathUD60x18__LogInputTooSmall(x); } // Note that the "mul" in this block is the assembly multiplication operation, not the "mul" function defined // in this contract. // prettier-ignore assembly { switch x case 1 { result := mul(SCALE, sub(0, 18)) } case 10 { result := mul(SCALE, sub(1, 18)) } case 100 { result := mul(SCALE, sub(2, 18)) } case 1000 { result := mul(SCALE, sub(3, 18)) } case 10000 { result := mul(SCALE, sub(4, 18)) } case 100000 { result := mul(SCALE, sub(5, 18)) } case 1000000 { result := mul(SCALE, sub(6, 18)) } case 10000000 { result := mul(SCALE, sub(7, 18)) } case 100000000 { result := mul(SCALE, sub(8, 18)) } case 1000000000 { result := mul(SCALE, sub(9, 18)) } case 10000000000 { result := mul(SCALE, sub(10, 18)) } case 100000000000 { result := mul(SCALE, sub(11, 18)) } case 1000000000000 { result := mul(SCALE, sub(12, 18)) } case 10000000000000 { result := mul(SCALE, sub(13, 18)) } case 100000000000000 { result := mul(SCALE, sub(14, 18)) } case 1000000000000000 { result := mul(SCALE, sub(15, 18)) } case 10000000000000000 { result := mul(SCALE, sub(16, 18)) } case 100000000000000000 { result := mul(SCALE, sub(17, 18)) } case 1000000000000000000 { result := 0 } case 10000000000000000000 { result := SCALE } case 100000000000000000000 { result := mul(SCALE, 2) } case 1000000000000000000000 { result := mul(SCALE, 3) } case 10000000000000000000000 { result := mul(SCALE, 4) } case 100000000000000000000000 { result := mul(SCALE, 5) } case 1000000000000000000000000 { result := mul(SCALE, 6) } case 10000000000000000000000000 { result := mul(SCALE, 7) } case 100000000000000000000000000 { result := mul(SCALE, 8) } case 1000000000000000000000000000 { result := mul(SCALE, 9) } case 10000000000000000000000000000 { result := mul(SCALE, 10) } case 100000000000000000000000000000 { result := mul(SCALE, 11) } case 1000000000000000000000000000000 { result := mul(SCALE, 12) } case 10000000000000000000000000000000 { result := mul(SCALE, 13) } case 100000000000000000000000000000000 { result := mul(SCALE, 14) } case 1000000000000000000000000000000000 { result := mul(SCALE, 15) } case 10000000000000000000000000000000000 { result := mul(SCALE, 16) } case 100000000000000000000000000000000000 { result := mul(SCALE, 17) } case 1000000000000000000000000000000000000 { result := mul(SCALE, 18) } case 10000000000000000000000000000000000000 { result := mul(SCALE, 19) } case 100000000000000000000000000000000000000 { result := mul(SCALE, 20) } case 1000000000000000000000000000000000000000 { result := mul(SCALE, 21) } case 10000000000000000000000000000000000000000 { result := mul(SCALE, 22) } case 100000000000000000000000000000000000000000 { result := mul(SCALE, 23) } case 1000000000000000000000000000000000000000000 { result := mul(SCALE, 24) } case 10000000000000000000000000000000000000000000 { result := mul(SCALE, 25) } case 100000000000000000000000000000000000000000000 { result := mul(SCALE, 26) } case 1000000000000000000000000000000000000000000000 { result := mul(SCALE, 27) } case 10000000000000000000000000000000000000000000000 { result := mul(SCALE, 28) } case 100000000000000000000000000000000000000000000000 { result := mul(SCALE, 29) } case 1000000000000000000000000000000000000000000000000 { result := mul(SCALE, 30) } case 10000000000000000000000000000000000000000000000000 { result := mul(SCALE, 31) } case 100000000000000000000000000000000000000000000000000 { result := mul(SCALE, 32) } case 1000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 33) } case 10000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 34) } case 100000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 35) } case 1000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 36) } case 10000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 37) } case 100000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 38) } case 1000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 39) } case 10000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 40) } case 100000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 41) } case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 42) } case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 43) } case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 44) } case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 45) } case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 46) } case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 47) } case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 48) } case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 49) } case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 50) } case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 51) } case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 52) } case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 53) } case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 54) } case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 55) } case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 56) } case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 57) } case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 58) } case 100000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 59) } default { result := MAX_UD60x18 } } if (result == MAX_UD60x18) { // Do the fixed-point division inline to save gas. The denominator is log2(10). unchecked { result = (log2(x) * SCALE) / 3_321928094887362347; } } } /// @notice Calculates the binary logarithm of x. /// /// @dev Based on the iterative approximation algorithm. /// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation /// /// Requirements: /// - x must be greater than or equal to SCALE, otherwise the result would be negative. /// /// Caveats: /// - The results are nor perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation. /// /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the binary logarithm. /// @return result The binary logarithm as an unsigned 60.18-decimal fixed-point number. function log2(uint256 x) internal pure returns (uint256 result) { if (x < SCALE) { revert PRBMathUD60x18__LogInputTooSmall(x); } unchecked { // Calculate the integer part of the logarithm and add it to the result and finally calculate y = x * 2^(-n). uint256 n = PRBMath.mostSignificantBit(x / SCALE); // The integer part of the logarithm as an unsigned 60.18-decimal fixed-point number. The operation can't overflow // because n is maximum 255 and SCALE is 1e18. result = n * SCALE; // This is y = x * 2^(-n). uint256 y = x >> n; // If y = 1, the fractional part is zero. if (y == SCALE) { return result; } // Calculate the fractional part via the iterative approximation. // The "delta >>= 1" part is equivalent to "delta /= 2", but shifting bits is faster. for (uint256 delta = HALF_SCALE; delta > 0; delta >>= 1) { y = (y * y) / SCALE; // Is y^2 > 2 and so in the range [2,4)? if (y >= 2 * SCALE) { // Add the 2^(-m) factor to the logarithm. result += delta; // Corresponds to z/2 on Wikipedia. y >>= 1; } } } } /// @notice Multiplies two unsigned 60.18-decimal fixed-point numbers together, returning a new unsigned 60.18-decimal /// fixed-point number. /// @dev See the documentation for the "PRBMath.mulDivFixedPoint" function. /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number. /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number. /// @return result The product as an unsigned 60.18-decimal fixed-point number. function mul(uint256 x, uint256 y) internal pure returns (uint256 result) { result = PRBMath.mulDivFixedPoint(x, y); } /// @notice Returns PI as an unsigned 60.18-decimal fixed-point number. function pi() internal pure returns (uint256 result) { result = 3_141592653589793238; } /// @notice Raises x to the power of y. /// /// @dev Based on the insight that x^y = 2^(log2(x) * y). /// /// Requirements: /// - All from "exp2", "log2" and "mul". /// /// Caveats: /// - All from "exp2", "log2" and "mul". /// - Assumes 0^0 is 1. /// /// @param x Number to raise to given power y, as an unsigned 60.18-decimal fixed-point number. /// @param y Exponent to raise x to, as an unsigned 60.18-decimal fixed-point number. /// @return result x raised to power y, as an unsigned 60.18-decimal fixed-point number. function pow(uint256 x, uint256 y) internal pure returns (uint256 result) { if (x == 0) { result = y == 0 ? SCALE : uint256(0); } else { result = exp2(mul(log2(x), y)); } } /// @notice Raises x (unsigned 60.18-decimal fixed-point number) to the power of y (basic unsigned integer) using the /// famous algorithm "exponentiation by squaring". /// /// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring /// /// Requirements: /// - The result must fit within MAX_UD60x18. /// /// Caveats: /// - All from "mul". /// - Assumes 0^0 is 1. /// /// @param x The base as an unsigned 60.18-decimal fixed-point number. /// @param y The exponent as an uint256. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function powu(uint256 x, uint256 y) internal pure returns (uint256 result) { // Calculate the first iteration of the loop in advance. result = y & 1 > 0 ? x : SCALE; // Equivalent to "for(y /= 2; y > 0; y /= 2)" but faster. for (y >>= 1; y > 0; y >>= 1) { x = PRBMath.mulDivFixedPoint(x, x); // Equivalent to "y % 2 == 1" but faster. if (y & 1 > 0) { result = PRBMath.mulDivFixedPoint(result, x); } } } /// @notice Returns 1 as an unsigned 60.18-decimal fixed-point number. function scale() internal pure returns (uint256 result) { result = SCALE; } /// @notice Calculates the square root of x, rounding down. /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// /// Requirements: /// - x must be less than MAX_UD60x18 / SCALE. /// /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the square root. /// @return result The result as an unsigned 60.18-decimal fixed-point . function sqrt(uint256 x) internal pure returns (uint256 result) { unchecked { if (x > MAX_UD60x18 / SCALE) { revert PRBMathUD60x18__SqrtOverflow(x); } // Multiply x by the SCALE to account for the factor of SCALE that is picked up when multiplying two unsigned // 60.18-decimal fixed-point numbers together (in this case, those two numbers are both the square root). result = PRBMath.sqrt(x * SCALE); } } /// @notice Converts a unsigned 60.18-decimal fixed-point number to basic integer form, rounding down in the process. /// @param x The unsigned 60.18-decimal fixed-point number to convert. /// @return result The same number in basic integer form. function toUint(uint256 x) internal pure returns (uint256 result) { unchecked { result = x / SCALE; } } }
{ "evmVersion": "london", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 10 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IVAMM","name":"_masterVAMM","type":"address"},{"internalType":"contract IMarginEngine","name":"_masterMarginEngine","type":"address"},{"internalType":"uint256","name":"_quorumVotes","type":"uint256"},{"internalType":"address","name":"_ownerAddress","type":"address"},{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"},{"internalType":"uint256","name":"_blockTimestampVotingEnd","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"numberOfVotes","type":"uint256"},{"indexed":false,"internalType":"bool","name":"yesVote","type":"bool"}],"name":"Voted","type":"event"},{"inputs":[],"name":"TIMELOCK_PERIOD_IN_SECONDS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blockTimestampTimelockEnd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blockTimestampVotingEnd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"},{"internalType":"uint256","name":"_numberOfVotes","type":"uint256"},{"internalType":"bool","name":"_yesVote","type":"bool"},{"internalType":"bytes32[]","name":"_merkleProof","type":"bytes32[]"}],"name":"castVote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"hasTokenIdVoted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"hasVoted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isDeployed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isQueued","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"masterMarginEngine","outputs":[{"internalType":"contract IMarginEngine","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"masterVAMM","outputs":[{"internalType":"contract IVAMM","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"merkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"noVoteCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ownerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"queue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"quorumVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"voltzFactory","outputs":[{"internalType":"contract IFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"yesVoteCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b5060405161246a38038061246a83398101604081905261002f91610096565b600755600380546001600160a01b03199081166001600160a01b039788161790915560028054821695871695909517909455600192909255600080549093169316929092179055600a556100ff565b6001600160a01b038116811461009357600080fd5b50565b60008060008060008060c087890312156100af57600080fd5b86516100ba8161007e565b60208801519096506100cb8161007e565b6040880151606089015191965094506100e38161007e565b809350506080870151915060a087015190509295509295509295565b61235c8061010e6000396000f3fe608060405234801561001057600080fd5b50600436106100e65760003560e01c80631b25de8f146100eb57806324bc1a641461010d5780632eb4a7ab1461012457806344a0b3e71461012d578063775c300c1461013657806378d177c0146101405780638f84aa091461014a578063916e62f31461016a57806392c7abb7146101735780639fe1b35414610186578063b4395f8314610199578063b5550397146101a2578063b8f2145f146101ab578063c52046de146101ce578063e10d29ee146101e0578063ecca031f146101e8578063fe3b9591146101fb578063febfe75e14610214575b600080fd5b6009546100f89060ff1681565b60405190151581526020015b60405180910390f35b61011660015481565b604051908152602001610104565b610116600a5481565b61011660045481565b61013e610227565b005b6101166202a30081565b60005461015d906001600160a01b031681565b6040516101049190610826565b61011660055481565b61013e61018136600461083a565b6103e9565b60025461015d906001600160a01b031681565b61011660075481565b61011660085481565b6100f86101b93660046108d7565b60066020526000908152604090205460ff1681565b6009546100f890610100900460ff1681565b61013e6105d4565b6100f86101f63660046108d7565b610704565b60095461015d906201000090046001600160a01b031681565b60035461015d906001600160a01b031681565b60095460ff1661026b5760405162461bcd60e51b815260206004820152600a6024820152691b9bdd081c5d595d595960b21b60448201526064015b60405180910390fd5b60085442116102b25760405162461bcd60e51b815260206004820152601360248201527274696d656c6f636b206973206f6e676f696e6760681b6044820152606401610262565b600954610100900460ff16156102fd5760405162461bcd60e51b815260206004820152601060248201526f185b1c9958591e4819195c1b1bde595960821b6044820152606401610262565b6002546003546040516001600160a01b03928316929091169061031f90610818565b6001600160a01b03928316815291166020820152604001604051809103906000f080158015610352573d6000803e3d6000fd5b5060098054610100610100600160b01b0319909116620100006001600160a01b03948516810261ff00191691909117919091179182905560005460405163f2fde38b60e01b81529190920483169263f2fde38b926103b592911690600401610826565b600060405180830381600087803b1580156103cf57600080fd5b505af11580156103e3573d6000803e3d6000fd5b50505050565b6007544211156104305760405162461bcd60e51b81526020600482015260126024820152713b37ba34b733903832b934b7b21037bb32b960711b6044820152606401610262565b61043985610704565b156104775760405162461bcd60e51b815260206004820152600e60248201526d6475706c696361746520766f746560901b6044820152606401610262565b60408051602081018790526001600160601b03193360601b1691810191909152605481018590526000906074016040516020818303038152906040528051906020012090506104fd83838080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050600a549150849050610745565b6105405760405162461bcd60e51b815260206004820152601460248201527334b73b30b634b21036b2b935b63290383937b7b360611b6044820152606401610262565b6105498661075b565b831561056c5784600460008282546105619190610906565b909155506105849050565b846005600082825461057e9190610906565b90915550505b6040805187815233602082015290810186905284151560608201527fb7086a9dd618ffa688aa9500720dfe31d3b288daba445664cecceaed4a1562c39060800160405180910390a1505050505050565b60075442116106195760405162461bcd60e51b8152602060048201526011602482015270766f74696e67206973206f6e676f696e6760781b6044820152606401610262565b60015460045410156106625760405162461bcd60e51b81526020600482015260126024820152711c5d5bdc9d5b481b9bdd081c995858da195960721b6044820152606401610262565b600554600454116106a15760405162461bcd60e51b81526020600482015260096024820152686e6f203e3d2079657360b81b6044820152606401610262565b60095460ff16156106e55760405162461bcd60e51b815260206004820152600e60248201526d185b1c9958591e481c5d595d595960921b6044820152606401610262565b6009805460ff191660011790556106ff6202a30042610906565b600855565b60008061071361010084610934565b9050600061072361010085610948565b6000928352600b602052604090922054600190921b9182169091149392505050565b6000826107528584610799565b14949350505050565b600061076961010083610934565b9050600061077961010084610948565b6000928352600b60205260409092208054600190931b9092179091555050565b600081815b84518110156107de576107ca828683815181106107bd576107bd61095c565b60200260200101516107e6565b9150806107d681610972565b91505061079e565b509392505050565b6000818310610802576000828152602084905260409020610811565b60008381526020839052604090205b9392505050565b611999806200098e83390190565b6001600160a01b0391909116815260200190565b60008060008060006080868803121561085257600080fd5b85359450602086013593506040860135801515811461087057600080fd5b925060608601356001600160401b038082111561088c57600080fd5b818801915088601f8301126108a057600080fd5b8135818111156108af57600080fd5b8960208260051b85010111156108c457600080fd5b9699959850939650602001949392505050565b6000602082840312156108e957600080fd5b5035919050565b634e487b7160e01b600052601160045260246000fd5b60008219821115610919576109196108f0565b500190565b634e487b7160e01b600052601260045260246000fd5b6000826109435761094361091e565b500490565b6000826109575761095761091e565b500690565b634e487b7160e01b600052603260045260246000fd5b6000600019821415610986576109866108f0565b506001019056fe60806040523480156200001157600080fd5b50604051620019993803806200199983398101604081905262000034916200018e565b6200003f3362000125565b6001600160a01b0382166200009b5760405162461bcd60e51b815260206004820152601460248201527f6d6173746572206d65206d75737420657869737400000000000000000000000060448201526064015b60405180910390fd5b6001600160a01b038116620000f35760405162461bcd60e51b815260206004820152601660248201527f6d61737465722076616d6d206d75737420657869737400000000000000000000604482015260640162000092565b600180546001600160a01b039384166001600160a01b03199182161790915560028054929093169116179055620001cd565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146200018b57600080fd5b50565b60008060408385031215620001a257600080fd5b8251620001af8162000175565b6020840151909250620001c28162000175565b809150509250929050565b6117bc80620001dd6000396000f3fe60806040523480156200001157600080fd5b5060043610620000ca5760003560e01c80630e8a064814620000cf578063715018a6146200011557806377aace1a14620001215780638da5cb5b146200014457806394a9b1f7146200014e57806395858f981462000165578063973cd931146200017c5780639fe1b3541462000193578063a389783e14620001a7578063aeb2293414620001cf578063ca5183b714620001e6578063db9b71701462000212578063f2fde38b1462000229578063febfe75e1462000240575b600080fd5b620000e6620000e036600462000e81565b62000254565b604080516001600160a01b03948516815292841660208401529216918101919091526060015b60405180910390f35b6200011f6200090a565b005b60055462000135906001600160a01b031681565b6040516200010c919062000eed565b6200013562000922565b6200011f6200015f36600462000f01565b62000931565b6200011f6200017636600462000f38565b620009c1565b6200011f6200018d36600462000f01565b62000a88565b60015462000135906001600160a01b031681565b620001be620001b836600462000f76565b62000b17565b60405190151581526020016200010c565b6200011f620001e036600462000f01565b62000c06565b62000135620001f736600462000fa9565b6003602052600090815260409020546001600160a01b031681565b6200011f6200022336600462000fc9565b62000cce565b6200011f6200023a36600462000f01565b62000d2e565b60025462000135906001600160a01b031681565b60008060006200026362000daa565b6001546040516000916001600160a01b031690620002819062000e5d565b6200028d919062001000565b604051809103906000f080158015620002aa573d6000803e3d6000fd5b506002546040519192506000916001600160a01b0390911690620002ce9062000e5d565b620002da919062001000565b604051809103906000f080158015620002f7573d6000803e3d6000fd5b5060405163eb990c5960e01b81526001600160a01b038c811660048301528b81166024830152604482018b9052606482018a90529192509083169063eb990c5990608401600060405180830381600087803b1580156200035657600080fd5b505af11580156200036b573d6000803e3d6000fd5b5050604051631b325b2160e31b81526001600160a01b03858116600483015260028a900b60248301528416925063d992d9089150604401600060405180830381600087803b158015620003bd57600080fd5b505af1158015620003d2573d6000803e3d6000fd5b50506040516331d81ea760e21b81526001600160a01b038516925063c7607a9c91506200040490849060040162000eed565b600060405180830381600087803b1580156200041f57600080fd5b505af115801562000434573d6000803e3d6000fd5b5050505060008990508a6001600160a01b0316816001600160a01b0316636f307dc36040518163ffffffff1660e01b815260040160206040518083038186803b1580156200048157600080fd5b505afa15801562000496573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004bc919062001023565b6001600160a01b0316146200050e5760405162461bcd60e51b81526020600482015260136024820152720a8ded6cadce640c8de40dcdee840dac2e8c6d606b1b60448201526064015b60405180910390fd5b6000816001600160a01b03166322ff65686040518163ffffffff1660e01b815260040160206040518083038186803b1580156200054a57600080fd5b505afa1580156200055f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000585919062001043565b60ff81166000908152600360205260408120549192506001600160a01b03909116908115620007155781604051620005bd9062000e5d565b620005c9919062001000565b604051809103906000f080158015620005e6573d6000803e3d6000fd5b5060405163485cc95560e01b81526001600160a01b03878116600483015288811660248301529192509082169063485cc95590604401600060405180830381600087803b1580156200063757600080fd5b505af11580156200064c573d6000803e3d6000fd5b505060405163534d337560e01b81526001600160a01b038916925063534d337591506200067e90849060040162000eed565b600060405180830381600087803b1580156200069957600080fd5b505af1158015620006ae573d6000803e3d6000fd5b505060405163f2fde38b60e01b81526001600160a01b038416925063f2fde38b9150620006e090339060040162000eed565b600060405180830381600087803b158015620006fb57600080fd5b505af115801562000710573d6000803e3d6000fd5b505050505b60008e6001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156200075157600080fd5b505afa15801562000766573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200078c919062001043565b90508d6001600160a01b03168f6001600160a01b03167fe134804702afa0f02bd7f0687d4c2f662a1790b4904d1c2cd6f41fcffbfc05c38f8f8f8c8c898c8a60405162000826989796959493929190978852602088019690965260029490940b60408701526001600160a01b03928316606087015290821660808601521660a084015260ff90811660c08401521660e08201526101000190565b60405180910390a360405163f2fde38b60e01b81526001600160a01b0387169063f2fde38b906200085c90339060040162000eed565b600060405180830381600087803b1580156200087757600080fd5b505af11580156200088c573d6000803e3d6000fd5b505060405163f2fde38b60e01b81526001600160a01b038a16925063f2fde38b9150620008be90339060040162000eed565b600060405180830381600087803b158015620008d957600080fd5b505af1158015620008ee573d6000803e3d6000fd5b50989b5096995091975050505050505050955095509592505050565b6200091462000daa565b62000920600062000e0d565b565b6000546001600160a01b031690565b6200093b62000daa565b6001600160a01b0381166200098c5760405162461bcd60e51b81526020600482015260166024820152751b585cdd195c881d985b5b481b5d5cdd08195e1a5cdd60521b604482015260640162000505565b6002546001600160a01b03828116911614620009be57600280546001600160a01b0319166001600160a01b0383161790555b50565b620009cb62000daa565b6001600160a01b03821662000a1b5760405162461bcd60e51b81526020600482015260156024820152741b585cdd195c881998db481b5d5cdd08195e1a5cdd605a1b604482015260640162000505565b60ff811660008181526003602090815260409182902080546001600160a01b0319166001600160a01b0387169081179091558251908152908101929092527fcece9976caa53e350e3311c87df72b4ed94d768ba03a4688cdf331121bf613c2910160405180910390a15050565b62000a9262000daa565b6001600160a01b03811662000ae15760405162461bcd60e51b81526020600482015260146024820152731b585cdd195c881b59481b5d5cdd08195e1a5cdd60621b604482015260640162000505565b6001546001600160a01b03828116911614620009be57600180546001600160a01b0383166001600160a01b031990911617905550565b60006001600160a01b03831662000b685760405162461bcd60e51b81526020600482015260146024820152731bdddb995c88191bd95cc81b9bdd08195e1a5cdd60621b604482015260640162000505565b6001600160a01b03821662000bb55760405162461bcd60e51b81526020600482015260126024820152711a5b9d08191bd95cc81b9bdd08195e1a5cdd60721b604482015260640162000505565b6005546001600160a01b038381169116141562000bd55750600162000c00565b506001600160a01b0380831660009081526004602090815260408083209385168352929052205460ff165b92915050565b62000c1062000daa565b6001600160a01b03811662000c5f5760405162461bcd60e51b81526020600482015260146024820152731c195c9a5c1a195c9e481b5d5cdd08195e1a5cdd60621b604482015260640162000505565b6005546001600160a01b03828116911614620009be57600580546001600160a01b0319166001600160a01b0383169081179091556040517f9d41c928e1b7d55eb20c9906b2cc3223035dd4dc2c59e5fcd2282e857db1b0509162000cc39162000eed565b60405180910390a150565b3360008181526004602090815260408083206001600160a01b0387168085529252808320805460ff19168615159081179091559051909391927f1d3e246ebbc933bf65d3290db9f93d67ab91a12d2b19308a35806e04d1c174c591a45050565b62000d3862000daa565b6001600160a01b03811662000d9f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840162000505565b620009be8162000e0d565b3362000db562000922565b6001600160a01b031614620009205760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000505565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610723806200106483390190565b6001600160a01b0381168114620009be57600080fd5b600080600080600060a0868803121562000e9a57600080fd5b853562000ea78162000e6b565b9450602086013562000eb98162000e6b565b935060408601359250606086013591506080860135600281900b811462000edf57600080fd5b809150509295509295909350565b6001600160a01b0391909116815260200190565b60006020828403121562000f1457600080fd5b813562000f218162000e6b565b9392505050565b60ff81168114620009be57600080fd5b6000806040838503121562000f4c57600080fd5b823562000f598162000e6b565b9150602083013562000f6b8162000f28565b809150509250929050565b6000806040838503121562000f8a57600080fd5b823562000f978162000e6b565b9150602083013562000f6b8162000e6b565b60006020828403121562000fbc57600080fd5b813562000f218162000f28565b6000806040838503121562000fdd57600080fd5b823562000fea8162000e6b565b91506020830135801515811462000f6b57600080fd5b6001600160a01b0391909116815260406020820181905260009082015260600190565b6000602082840312156200103657600080fd5b815162000f218162000e6b565b6000602082840312156200105657600080fd5b815162000f218162000f2856fe608060405260405161072338038061072383398101604081905261002291610318565b818161003082826000610039565b50505050610435565b6100428361006f565b60008251118061004f5750805b1561006a5761006883836100af60201b6100291760201c565b505b505050565b610078816100db565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606100d483836040518060600160405280602781526020016106fc602791396101ad565b9392505050565b6100ee8161028b60201b6100551760201c565b6101555760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084015b60405180910390fd5b8061018c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b61029a60201b6100641760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b60606001600160a01b0384163b6102155760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b606482015260840161014c565b600080856001600160a01b03168560405161023091906103e6565b600060405180830381855af49150503d806000811461026b576040519150601f19603f3d011682016040523d82523d6000602084013e610270565b606091505b50909250905061028182828661029d565b9695505050505050565b6001600160a01b03163b151590565b90565b606083156102ac5750816100d4565b8251156102bc5782518084602001fd5b8160405162461bcd60e51b815260040161014c9190610402565b634e487b7160e01b600052604160045260246000fd5b60005b838110156103075781810151838201526020016102ef565b838111156100685750506000910152565b6000806040838503121561032b57600080fd5b82516001600160a01b038116811461034257600080fd5b60208401519092506001600160401b038082111561035f57600080fd5b818501915085601f83011261037357600080fd5b815181811115610385576103856102d6565b604051601f8201601f19908116603f011681019083821181831017156103ad576103ad6102d6565b816040528281528860208487010111156103c657600080fd5b6103d78360208301602088016102ec565b80955050505050509250929050565b600082516103f88184602087016102ec565b9190910192915050565b60208152600082518060208401526104218160408501602087016102ec565b601f01601f19169190910160400192915050565b6102b8806104446000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610067565b61009f565b565b606061004e838360405180606001604052806027815260200161025c602791396100c3565b9392505050565b6001600160a01b03163b151590565b90565b600061009a7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156100be573d6000f35b3d6000fd5b60606100ce84610055565b61012e5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084015b60405180910390fd5b600080856001600160a01b031685604051610149919061020c565b600060405180830381855af49150503d8060008114610184576040519150601f19603f3d011682016040523d82523d6000602084013e610189565b606091505b50915091506101998282866101a3565b9695505050505050565b606083156101b257508161004e565b8251156101c25782518084602001fd5b8160405162461bcd60e51b81526004016101259190610228565b60005b838110156101f75781810151838201526020016101df565b83811115610206576000848401525b50505050565b6000825161021e8184602087016101dc565b9190910192915050565b60208152600082518060208401526102478160408501602087016101dc565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212205900c4b1e4be3fa6e785862c2a2fc141c5d1b152a07412fc06b0e42539965fa164736f6c63430008090033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220ca048125c922f198e3ace29abfec79bca150eff5e84c623a8f009fb2c3067d7964736f6c63430008090033a2646970667358221220c9051e3f098a146ec31744becde155cbd8685c79b125ca1e90de6c63fbc412ed64736f6c634300080900330000000000000000000000009f30ec6903f1728ca250f48f664e48c3f15038ed00000000000000000000000036e3d9e6f22d9e02039fa6ec1cd073216e4d3e8c00000000000000000000000000000000000000000000000000000000000006850000000000000000000000007d48f1ac18e3b60387271535e29258da26c020308f91da6b9e4daa5d43fbd3837cd350305e979cdbaee3217471f8feea38ccdcf7000000000000000000000000000000000000000000000000000000006460cd40
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100e65760003560e01c80631b25de8f146100eb57806324bc1a641461010d5780632eb4a7ab1461012457806344a0b3e71461012d578063775c300c1461013657806378d177c0146101405780638f84aa091461014a578063916e62f31461016a57806392c7abb7146101735780639fe1b35414610186578063b4395f8314610199578063b5550397146101a2578063b8f2145f146101ab578063c52046de146101ce578063e10d29ee146101e0578063ecca031f146101e8578063fe3b9591146101fb578063febfe75e14610214575b600080fd5b6009546100f89060ff1681565b60405190151581526020015b60405180910390f35b61011660015481565b604051908152602001610104565b610116600a5481565b61011660045481565b61013e610227565b005b6101166202a30081565b60005461015d906001600160a01b031681565b6040516101049190610826565b61011660055481565b61013e61018136600461083a565b6103e9565b60025461015d906001600160a01b031681565b61011660075481565b61011660085481565b6100f86101b93660046108d7565b60066020526000908152604090205460ff1681565b6009546100f890610100900460ff1681565b61013e6105d4565b6100f86101f63660046108d7565b610704565b60095461015d906201000090046001600160a01b031681565b60035461015d906001600160a01b031681565b60095460ff1661026b5760405162461bcd60e51b815260206004820152600a6024820152691b9bdd081c5d595d595960b21b60448201526064015b60405180910390fd5b60085442116102b25760405162461bcd60e51b815260206004820152601360248201527274696d656c6f636b206973206f6e676f696e6760681b6044820152606401610262565b600954610100900460ff16156102fd5760405162461bcd60e51b815260206004820152601060248201526f185b1c9958591e4819195c1b1bde595960821b6044820152606401610262565b6002546003546040516001600160a01b03928316929091169061031f90610818565b6001600160a01b03928316815291166020820152604001604051809103906000f080158015610352573d6000803e3d6000fd5b5060098054610100610100600160b01b0319909116620100006001600160a01b03948516810261ff00191691909117919091179182905560005460405163f2fde38b60e01b81529190920483169263f2fde38b926103b592911690600401610826565b600060405180830381600087803b1580156103cf57600080fd5b505af11580156103e3573d6000803e3d6000fd5b50505050565b6007544211156104305760405162461bcd60e51b81526020600482015260126024820152713b37ba34b733903832b934b7b21037bb32b960711b6044820152606401610262565b61043985610704565b156104775760405162461bcd60e51b815260206004820152600e60248201526d6475706c696361746520766f746560901b6044820152606401610262565b60408051602081018790526001600160601b03193360601b1691810191909152605481018590526000906074016040516020818303038152906040528051906020012090506104fd83838080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050600a549150849050610745565b6105405760405162461bcd60e51b815260206004820152601460248201527334b73b30b634b21036b2b935b63290383937b7b360611b6044820152606401610262565b6105498661075b565b831561056c5784600460008282546105619190610906565b909155506105849050565b846005600082825461057e9190610906565b90915550505b6040805187815233602082015290810186905284151560608201527fb7086a9dd618ffa688aa9500720dfe31d3b288daba445664cecceaed4a1562c39060800160405180910390a1505050505050565b60075442116106195760405162461bcd60e51b8152602060048201526011602482015270766f74696e67206973206f6e676f696e6760781b6044820152606401610262565b60015460045410156106625760405162461bcd60e51b81526020600482015260126024820152711c5d5bdc9d5b481b9bdd081c995858da195960721b6044820152606401610262565b600554600454116106a15760405162461bcd60e51b81526020600482015260096024820152686e6f203e3d2079657360b81b6044820152606401610262565b60095460ff16156106e55760405162461bcd60e51b815260206004820152600e60248201526d185b1c9958591e481c5d595d595960921b6044820152606401610262565b6009805460ff191660011790556106ff6202a30042610906565b600855565b60008061071361010084610934565b9050600061072361010085610948565b6000928352600b602052604090922054600190921b9182169091149392505050565b6000826107528584610799565b14949350505050565b600061076961010083610934565b9050600061077961010084610948565b6000928352600b60205260409092208054600190931b9092179091555050565b600081815b84518110156107de576107ca828683815181106107bd576107bd61095c565b60200260200101516107e6565b9150806107d681610972565b91505061079e565b509392505050565b6000818310610802576000828152602084905260409020610811565b60008381526020839052604090205b9392505050565b611999806200098e83390190565b6001600160a01b0391909116815260200190565b60008060008060006080868803121561085257600080fd5b85359450602086013593506040860135801515811461087057600080fd5b925060608601356001600160401b038082111561088c57600080fd5b818801915088601f8301126108a057600080fd5b8135818111156108af57600080fd5b8960208260051b85010111156108c457600080fd5b9699959850939650602001949392505050565b6000602082840312156108e957600080fd5b5035919050565b634e487b7160e01b600052601160045260246000fd5b60008219821115610919576109196108f0565b500190565b634e487b7160e01b600052601260045260246000fd5b6000826109435761094361091e565b500490565b6000826109575761095761091e565b500690565b634e487b7160e01b600052603260045260246000fd5b6000600019821415610986576109866108f0565b506001019056fe60806040523480156200001157600080fd5b50604051620019993803806200199983398101604081905262000034916200018e565b6200003f3362000125565b6001600160a01b0382166200009b5760405162461bcd60e51b815260206004820152601460248201527f6d6173746572206d65206d75737420657869737400000000000000000000000060448201526064015b60405180910390fd5b6001600160a01b038116620000f35760405162461bcd60e51b815260206004820152601660248201527f6d61737465722076616d6d206d75737420657869737400000000000000000000604482015260640162000092565b600180546001600160a01b039384166001600160a01b03199182161790915560028054929093169116179055620001cd565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146200018b57600080fd5b50565b60008060408385031215620001a257600080fd5b8251620001af8162000175565b6020840151909250620001c28162000175565b809150509250929050565b6117bc80620001dd6000396000f3fe60806040523480156200001157600080fd5b5060043610620000ca5760003560e01c80630e8a064814620000cf578063715018a6146200011557806377aace1a14620001215780638da5cb5b146200014457806394a9b1f7146200014e57806395858f981462000165578063973cd931146200017c5780639fe1b3541462000193578063a389783e14620001a7578063aeb2293414620001cf578063ca5183b714620001e6578063db9b71701462000212578063f2fde38b1462000229578063febfe75e1462000240575b600080fd5b620000e6620000e036600462000e81565b62000254565b604080516001600160a01b03948516815292841660208401529216918101919091526060015b60405180910390f35b6200011f6200090a565b005b60055462000135906001600160a01b031681565b6040516200010c919062000eed565b6200013562000922565b6200011f6200015f36600462000f01565b62000931565b6200011f6200017636600462000f38565b620009c1565b6200011f6200018d36600462000f01565b62000a88565b60015462000135906001600160a01b031681565b620001be620001b836600462000f76565b62000b17565b60405190151581526020016200010c565b6200011f620001e036600462000f01565b62000c06565b62000135620001f736600462000fa9565b6003602052600090815260409020546001600160a01b031681565b6200011f6200022336600462000fc9565b62000cce565b6200011f6200023a36600462000f01565b62000d2e565b60025462000135906001600160a01b031681565b60008060006200026362000daa565b6001546040516000916001600160a01b031690620002819062000e5d565b6200028d919062001000565b604051809103906000f080158015620002aa573d6000803e3d6000fd5b506002546040519192506000916001600160a01b0390911690620002ce9062000e5d565b620002da919062001000565b604051809103906000f080158015620002f7573d6000803e3d6000fd5b5060405163eb990c5960e01b81526001600160a01b038c811660048301528b81166024830152604482018b9052606482018a90529192509083169063eb990c5990608401600060405180830381600087803b1580156200035657600080fd5b505af11580156200036b573d6000803e3d6000fd5b5050604051631b325b2160e31b81526001600160a01b03858116600483015260028a900b60248301528416925063d992d9089150604401600060405180830381600087803b158015620003bd57600080fd5b505af1158015620003d2573d6000803e3d6000fd5b50506040516331d81ea760e21b81526001600160a01b038516925063c7607a9c91506200040490849060040162000eed565b600060405180830381600087803b1580156200041f57600080fd5b505af115801562000434573d6000803e3d6000fd5b5050505060008990508a6001600160a01b0316816001600160a01b0316636f307dc36040518163ffffffff1660e01b815260040160206040518083038186803b1580156200048157600080fd5b505afa15801562000496573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004bc919062001023565b6001600160a01b0316146200050e5760405162461bcd60e51b81526020600482015260136024820152720a8ded6cadce640c8de40dcdee840dac2e8c6d606b1b60448201526064015b60405180910390fd5b6000816001600160a01b03166322ff65686040518163ffffffff1660e01b815260040160206040518083038186803b1580156200054a57600080fd5b505afa1580156200055f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000585919062001043565b60ff81166000908152600360205260408120549192506001600160a01b03909116908115620007155781604051620005bd9062000e5d565b620005c9919062001000565b604051809103906000f080158015620005e6573d6000803e3d6000fd5b5060405163485cc95560e01b81526001600160a01b03878116600483015288811660248301529192509082169063485cc95590604401600060405180830381600087803b1580156200063757600080fd5b505af11580156200064c573d6000803e3d6000fd5b505060405163534d337560e01b81526001600160a01b038916925063534d337591506200067e90849060040162000eed565b600060405180830381600087803b1580156200069957600080fd5b505af1158015620006ae573d6000803e3d6000fd5b505060405163f2fde38b60e01b81526001600160a01b038416925063f2fde38b9150620006e090339060040162000eed565b600060405180830381600087803b158015620006fb57600080fd5b505af115801562000710573d6000803e3d6000fd5b505050505b60008e6001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156200075157600080fd5b505afa15801562000766573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200078c919062001043565b90508d6001600160a01b03168f6001600160a01b03167fe134804702afa0f02bd7f0687d4c2f662a1790b4904d1c2cd6f41fcffbfc05c38f8f8f8c8c898c8a60405162000826989796959493929190978852602088019690965260029490940b60408701526001600160a01b03928316606087015290821660808601521660a084015260ff90811660c08401521660e08201526101000190565b60405180910390a360405163f2fde38b60e01b81526001600160a01b0387169063f2fde38b906200085c90339060040162000eed565b600060405180830381600087803b1580156200087757600080fd5b505af11580156200088c573d6000803e3d6000fd5b505060405163f2fde38b60e01b81526001600160a01b038a16925063f2fde38b9150620008be90339060040162000eed565b600060405180830381600087803b158015620008d957600080fd5b505af1158015620008ee573d6000803e3d6000fd5b50989b5096995091975050505050505050955095509592505050565b6200091462000daa565b62000920600062000e0d565b565b6000546001600160a01b031690565b6200093b62000daa565b6001600160a01b0381166200098c5760405162461bcd60e51b81526020600482015260166024820152751b585cdd195c881d985b5b481b5d5cdd08195e1a5cdd60521b604482015260640162000505565b6002546001600160a01b03828116911614620009be57600280546001600160a01b0319166001600160a01b0383161790555b50565b620009cb62000daa565b6001600160a01b03821662000a1b5760405162461bcd60e51b81526020600482015260156024820152741b585cdd195c881998db481b5d5cdd08195e1a5cdd605a1b604482015260640162000505565b60ff811660008181526003602090815260409182902080546001600160a01b0319166001600160a01b0387169081179091558251908152908101929092527fcece9976caa53e350e3311c87df72b4ed94d768ba03a4688cdf331121bf613c2910160405180910390a15050565b62000a9262000daa565b6001600160a01b03811662000ae15760405162461bcd60e51b81526020600482015260146024820152731b585cdd195c881b59481b5d5cdd08195e1a5cdd60621b604482015260640162000505565b6001546001600160a01b03828116911614620009be57600180546001600160a01b0383166001600160a01b031990911617905550565b60006001600160a01b03831662000b685760405162461bcd60e51b81526020600482015260146024820152731bdddb995c88191bd95cc81b9bdd08195e1a5cdd60621b604482015260640162000505565b6001600160a01b03821662000bb55760405162461bcd60e51b81526020600482015260126024820152711a5b9d08191bd95cc81b9bdd08195e1a5cdd60721b604482015260640162000505565b6005546001600160a01b038381169116141562000bd55750600162000c00565b506001600160a01b0380831660009081526004602090815260408083209385168352929052205460ff165b92915050565b62000c1062000daa565b6001600160a01b03811662000c5f5760405162461bcd60e51b81526020600482015260146024820152731c195c9a5c1a195c9e481b5d5cdd08195e1a5cdd60621b604482015260640162000505565b6005546001600160a01b03828116911614620009be57600580546001600160a01b0319166001600160a01b0383169081179091556040517f9d41c928e1b7d55eb20c9906b2cc3223035dd4dc2c59e5fcd2282e857db1b0509162000cc39162000eed565b60405180910390a150565b3360008181526004602090815260408083206001600160a01b0387168085529252808320805460ff19168615159081179091559051909391927f1d3e246ebbc933bf65d3290db9f93d67ab91a12d2b19308a35806e04d1c174c591a45050565b62000d3862000daa565b6001600160a01b03811662000d9f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840162000505565b620009be8162000e0d565b3362000db562000922565b6001600160a01b031614620009205760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000505565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610723806200106483390190565b6001600160a01b0381168114620009be57600080fd5b600080600080600060a0868803121562000e9a57600080fd5b853562000ea78162000e6b565b9450602086013562000eb98162000e6b565b935060408601359250606086013591506080860135600281900b811462000edf57600080fd5b809150509295509295909350565b6001600160a01b0391909116815260200190565b60006020828403121562000f1457600080fd5b813562000f218162000e6b565b9392505050565b60ff81168114620009be57600080fd5b6000806040838503121562000f4c57600080fd5b823562000f598162000e6b565b9150602083013562000f6b8162000f28565b809150509250929050565b6000806040838503121562000f8a57600080fd5b823562000f978162000e6b565b9150602083013562000f6b8162000e6b565b60006020828403121562000fbc57600080fd5b813562000f218162000f28565b6000806040838503121562000fdd57600080fd5b823562000fea8162000e6b565b91506020830135801515811462000f6b57600080fd5b6001600160a01b0391909116815260406020820181905260009082015260600190565b6000602082840312156200103657600080fd5b815162000f218162000e6b565b6000602082840312156200105657600080fd5b815162000f218162000f2856fe608060405260405161072338038061072383398101604081905261002291610318565b818161003082826000610039565b50505050610435565b6100428361006f565b60008251118061004f5750805b1561006a5761006883836100af60201b6100291760201c565b505b505050565b610078816100db565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606100d483836040518060600160405280602781526020016106fc602791396101ad565b9392505050565b6100ee8161028b60201b6100551760201c565b6101555760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084015b60405180910390fd5b8061018c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b61029a60201b6100641760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b60606001600160a01b0384163b6102155760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b606482015260840161014c565b600080856001600160a01b03168560405161023091906103e6565b600060405180830381855af49150503d806000811461026b576040519150601f19603f3d011682016040523d82523d6000602084013e610270565b606091505b50909250905061028182828661029d565b9695505050505050565b6001600160a01b03163b151590565b90565b606083156102ac5750816100d4565b8251156102bc5782518084602001fd5b8160405162461bcd60e51b815260040161014c9190610402565b634e487b7160e01b600052604160045260246000fd5b60005b838110156103075781810151838201526020016102ef565b838111156100685750506000910152565b6000806040838503121561032b57600080fd5b82516001600160a01b038116811461034257600080fd5b60208401519092506001600160401b038082111561035f57600080fd5b818501915085601f83011261037357600080fd5b815181811115610385576103856102d6565b604051601f8201601f19908116603f011681019083821181831017156103ad576103ad6102d6565b816040528281528860208487010111156103c657600080fd5b6103d78360208301602088016102ec565b80955050505050509250929050565b600082516103f88184602087016102ec565b9190910192915050565b60208152600082518060208401526104218160408501602087016102ec565b601f01601f19169190910160400192915050565b6102b8806104446000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610067565b61009f565b565b606061004e838360405180606001604052806027815260200161025c602791396100c3565b9392505050565b6001600160a01b03163b151590565b90565b600061009a7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156100be573d6000f35b3d6000fd5b60606100ce84610055565b61012e5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084015b60405180910390fd5b600080856001600160a01b031685604051610149919061020c565b600060405180830381855af49150503d8060008114610184576040519150601f19603f3d011682016040523d82523d6000602084013e610189565b606091505b50915091506101998282866101a3565b9695505050505050565b606083156101b257508161004e565b8251156101c25782518084602001fd5b8160405162461bcd60e51b81526004016101259190610228565b60005b838110156101f75781810151838201526020016101df565b83811115610206576000848401525b50505050565b6000825161021e8184602087016101dc565b9190910192915050565b60208152600082518060208401526102478160408501602087016101dc565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212205900c4b1e4be3fa6e785862c2a2fc141c5d1b152a07412fc06b0e42539965fa164736f6c63430008090033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220ca048125c922f198e3ace29abfec79bca150eff5e84c623a8f009fb2c3067d7964736f6c63430008090033a2646970667358221220c9051e3f098a146ec31744becde155cbd8685c79b125ca1e90de6c63fbc412ed64736f6c63430008090033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000009f30ec6903f1728ca250f48f664e48c3f15038ed00000000000000000000000036e3d9e6f22d9e02039fa6ec1cd073216e4d3e8c00000000000000000000000000000000000000000000000000000000000006850000000000000000000000007d48f1ac18e3b60387271535e29258da26c020308f91da6b9e4daa5d43fbd3837cd350305e979cdbaee3217471f8feea38ccdcf7000000000000000000000000000000000000000000000000000000006460cd40
-----Decoded View---------------
Arg [0] : _masterVAMM (address): 0x9f30Ec6903F1728ca250f48f664e48c3f15038eD
Arg [1] : _masterMarginEngine (address): 0x36E3d9E6f22D9E02039FA6ec1CD073216E4D3E8C
Arg [2] : _quorumVotes (uint256): 1669
Arg [3] : _ownerAddress (address): 0x7D48F1AC18E3b60387271535E29258da26C02030
Arg [4] : _merkleRoot (bytes32): 0x8f91da6b9e4daa5d43fbd3837cd350305e979cdbaee3217471f8feea38ccdcf7
Arg [5] : _blockTimestampVotingEnd (uint256): 1684065600
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000009f30ec6903f1728ca250f48f664e48c3f15038ed
Arg [1] : 00000000000000000000000036e3d9e6f22d9e02039fa6ec1cd073216e4d3e8c
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000685
Arg [3] : 0000000000000000000000007d48f1ac18e3b60387271535e29258da26c02030
Arg [4] : 8f91da6b9e4daa5d43fbd3837cd350305e979cdbaee3217471f8feea38ccdcf7
Arg [5] : 000000000000000000000000000000000000000000000000000000006460cd40
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.