Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
19560886 | 285 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
NFTDropMarket
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
Yes with 1337000 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
/* ・ * ★ ・ 。 ・ ゚☆ 。 * ★ ゚・。 * 。 * ☆ 。・゚*.。 ゚ *.。☆。★ ・ ` .-:::::-.` `-::---...``` `-:` .:+ssssoooo++//:.` .-/+shhhhhhhhhhhhhyyyssooo: .--::. .+ossso+/////++/:://-` .////+shhhhhhhhhhhhhhhhhhhhhy `-----::. `/+////+++///+++/:--:/+/- -////+shhhhhhhhhhhhhhhhhhhhhy `------:::-` `//-.``.-/+ooosso+:-.-/oso- -////+shhhhhhhhhhhhhhhhhhhhhy .--------:::-` :+:.` .-/osyyyyyyso++syhyo.-////+shhhhhhhhhhhhhhhhhhhhhy `-----------:::-. +o+:-.-:/oyhhhhhhdhhhhhdddy:-////+shhhhhhhhhhhhhhhhhhhhhy .------------::::-- `oys+/::/+shhhhhhhdddddddddy/-////+shhhhhhhhhhhhhhhhhhhhhy .--------------:::::-` +ys+////+yhhhhhhhddddddddhy:-////+yhhhhhhhhhhhhhhhhhhhhhy `----------------::::::-`.ss+/:::+oyhhhhhhhhhhhhhhho`-////+shhhhhhhhhhhhhhhhhhhhhy .------------------:::::::.-so//::/+osyyyhhhhhhhhhys` -////+shhhhhhhhhhhhhhhhhhhhhy `.-------------------::/:::::..+o+////+oosssyyyyyyys+` .////+shhhhhhhhhhhhhhhhhhhhhy .--------------------::/:::.` -+o++++++oooosssss/. `-//+shhhhhhhhhhhhhhhhhhhhyo .------- ``````.......--` `-/+ooooosso+/-` `./++++///:::--...``hhhhyo ````` * ・ 。 ・ ゚☆ 。 * ★ ゚・。 * 。 * ☆ 。・゚*.。 ゚ *.。☆。★ ・ * ゚。·*・。 ゚* ☆゚・。°*. ゚ ・ ゚*。・゚★。 ・ *゚。 * ・゚*。★・ ☆∴。 * ・ 。 */ // SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; import { ContextUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import { INFTDropMarketDeprecatedEvents } from "./interfaces/internal/deprecated/INFTDropMarketDeprecatedEvents.sol"; import { FETHNode } from "./mixins/shared/FETHNode.sol"; import { FoundationTreasuryNodeV1 } from "./mixins/shared/FoundationTreasuryNodeV1.sol"; import { Gap1000 } from "./mixins/shared/Gap1000.sol"; import { Gap8500 } from "./mixins/shared/Gap8500.sol"; import { MarketFees } from "./mixins/shared/MarketFees.sol"; import { MarketSharedCore } from "./mixins/shared/MarketSharedCore.sol"; import { WorldsNftNode } from "./mixins/shared/WorldsNftNode.sol"; import { RouterContextSingle } from "./mixins/shared/RouterContextSingle.sol"; import { SendValueWithFallbackWithdraw } from "./mixins/shared/SendValueWithFallbackWithdraw.sol"; import { TxDeadline } from "./mixins/shared/TxDeadline.sol"; import { NFTDropMarketCore } from "./mixins/nftDropMarket/NFTDropMarketCore.sol"; import { NFTDropMarketDutchAuction } from "./mixins/nftDropMarket/NFTDropMarketDutchAuction.sol"; import { NFTDropMarketExhibitionGap } from "./mixins/nftDropMarket/NFTDropMarketExhibitionGap.sol"; import { NFTDropMarketFixedPriceSale } from "./mixins/nftDropMarket/NFTDropMarketFixedPriceSale.sol"; error NFTDropMarket_NFT_Already_Minted(); /** * @title A market for minting NFTs with Foundation. * @author batu-inal & HardlyDifficult & philbirt & reggieag */ contract NFTDropMarket is INFTDropMarketDeprecatedEvents, TxDeadline, Initializable, FoundationTreasuryNodeV1, ContextUpgradeable, RouterContextSingle, WorldsNftNode, FETHNode, MarketSharedCore, Gap1000, ReentrancyGuardUpgradeable, SendValueWithFallbackWithdraw, MarketFees, Gap8500, NFTDropMarketCore, NFTDropMarketExhibitionGap, NFTDropMarketFixedPriceSale, NFTDropMarketDutchAuction { //////////////////////////////////////////////////////////////// // Setup //////////////////////////////////////////////////////////////// /** * @notice Set immutable variables for the implementation contract. * @dev Using immutable instead of constants allows us to use different values on testnet. * @param treasury The Foundation Treasury contract address. * @param feth The FETH ERC-20 token contract address. * @param router The trusted router contract address. * @param marketUtils The MarketUtils contract address. * @param worldsNft The Worlds NFT contract address. */ constructor( address payable treasury, address feth, address router, address marketUtils, address worldsNft ) FoundationTreasuryNodeV1(treasury) FETHNode(feth) WorldsNftNode(worldsNft) MarketFees( /* protocolFeeInBasisPoints: */ 0, marketUtils, /* assumePrimarySale: */ true ) RouterContextSingle(router) { _disableInitializers(); } /** * @notice Called once to configure the contract after the initial proxy deployment. * @dev This farms the initialize call out to inherited contracts as needed to initialize mutable variables. */ function initialize() external initializer { ReentrancyGuardUpgradeable.__ReentrancyGuard_init(); } //////////////////////////////////////////////////////////////// // Seller getters //////////////////////////////////////////////////////////////// /** * @inheritdoc MarketSharedCore * @dev Returns address(0) if the NFT has already been sold, otherwise checks for a listing in this market. */ function _getSellerOf( address nftContract, uint256 tokenId ) internal view override(MarketSharedCore, NFTDropMarketCore) returns (address payable seller) { seller = super._getSellerOf(nftContract, tokenId); } function _getSellerOfCollection( address nftContract ) internal view override(NFTDropMarketCore, NFTDropMarketFixedPriceSale, NFTDropMarketDutchAuction) returns (address payable seller) { seller = super._getSellerOfCollection(nftContract); } /** * @inheritdoc MarketSharedCore * @dev Reverts if the NFT has already been sold, otherwise checks for a listing in this market. */ function _getSellerOrOwnerOf( address nftContract, uint256 tokenId ) internal view override returns (address payable sellerOrOwner) { // Check the current owner first in case it has been sold. try IERC721(nftContract).ownerOf(tokenId) returns (address owner) { if (owner != address(0)) { // Once an NFT has been minted, it cannot be sold through this contract. revert NFTDropMarket_NFT_Already_Minted(); } } catch { // Fall through } sellerOrOwner = super._getSellerOf(nftContract, tokenId); } //////////////////////////////////////////////////////////////// // Inheritance Requirements // (no-ops to avoid compile errors) //////////////////////////////////////////////////////////////// /** * @inheritdoc RouterContextSingle */ function _msgSender() internal view override(ContextUpgradeable, RouterContextSingle) returns (address sender) { sender = super._msgSender(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @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 * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, "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"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, 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) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, 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) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or 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 { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // 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 (last updated v4.9.4) (utils/Context.sol) pragma solidity ^0.8.0; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @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 ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.20; /** * @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. */ library SafeCast { /** * @dev Value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); /** * @dev An int value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedIntToUint(int256 value); /** * @dev Value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedIntDowncast(uint8 bits, int256 value); /** * @dev An uint value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedUintToInt(uint256 value); /** * @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 */ function toUint248(uint256 value) internal pure returns (uint248) { if (value > type(uint248).max) { revert SafeCastOverflowedUintDowncast(248, value); } 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 */ function toUint240(uint256 value) internal pure returns (uint240) { if (value > type(uint240).max) { revert SafeCastOverflowedUintDowncast(240, value); } 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 */ function toUint232(uint256 value) internal pure returns (uint232) { if (value > type(uint232).max) { revert SafeCastOverflowedUintDowncast(232, value); } 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 */ function toUint224(uint256 value) internal pure returns (uint224) { if (value > type(uint224).max) { revert SafeCastOverflowedUintDowncast(224, value); } 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 */ function toUint216(uint256 value) internal pure returns (uint216) { if (value > type(uint216).max) { revert SafeCastOverflowedUintDowncast(216, value); } 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 */ function toUint208(uint256 value) internal pure returns (uint208) { if (value > type(uint208).max) { revert SafeCastOverflowedUintDowncast(208, value); } 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 */ function toUint200(uint256 value) internal pure returns (uint200) { if (value > type(uint200).max) { revert SafeCastOverflowedUintDowncast(200, value); } 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 */ function toUint192(uint256 value) internal pure returns (uint192) { if (value > type(uint192).max) { revert SafeCastOverflowedUintDowncast(192, value); } 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 */ function toUint184(uint256 value) internal pure returns (uint184) { if (value > type(uint184).max) { revert SafeCastOverflowedUintDowncast(184, value); } 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 */ function toUint176(uint256 value) internal pure returns (uint176) { if (value > type(uint176).max) { revert SafeCastOverflowedUintDowncast(176, value); } 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 */ function toUint168(uint256 value) internal pure returns (uint168) { if (value > type(uint168).max) { revert SafeCastOverflowedUintDowncast(168, value); } 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 */ function toUint160(uint256 value) internal pure returns (uint160) { if (value > type(uint160).max) { revert SafeCastOverflowedUintDowncast(160, value); } 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 */ function toUint152(uint256 value) internal pure returns (uint152) { if (value > type(uint152).max) { revert SafeCastOverflowedUintDowncast(152, value); } 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 */ function toUint144(uint256 value) internal pure returns (uint144) { if (value > type(uint144).max) { revert SafeCastOverflowedUintDowncast(144, value); } 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 */ function toUint136(uint256 value) internal pure returns (uint136) { if (value > type(uint136).max) { revert SafeCastOverflowedUintDowncast(136, value); } 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 */ function toUint128(uint256 value) internal pure returns (uint128) { if (value > type(uint128).max) { revert SafeCastOverflowedUintDowncast(128, value); } 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 */ function toUint120(uint256 value) internal pure returns (uint120) { if (value > type(uint120).max) { revert SafeCastOverflowedUintDowncast(120, value); } 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 */ function toUint112(uint256 value) internal pure returns (uint112) { if (value > type(uint112).max) { revert SafeCastOverflowedUintDowncast(112, value); } 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 */ function toUint104(uint256 value) internal pure returns (uint104) { if (value > type(uint104).max) { revert SafeCastOverflowedUintDowncast(104, value); } 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 */ function toUint96(uint256 value) internal pure returns (uint96) { if (value > type(uint96).max) { revert SafeCastOverflowedUintDowncast(96, value); } 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 */ function toUint88(uint256 value) internal pure returns (uint88) { if (value > type(uint88).max) { revert SafeCastOverflowedUintDowncast(88, value); } 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 */ function toUint80(uint256 value) internal pure returns (uint80) { if (value > type(uint80).max) { revert SafeCastOverflowedUintDowncast(80, value); } 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 */ function toUint72(uint256 value) internal pure returns (uint72) { if (value > type(uint72).max) { revert SafeCastOverflowedUintDowncast(72, value); } 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 */ function toUint64(uint256 value) internal pure returns (uint64) { if (value > type(uint64).max) { revert SafeCastOverflowedUintDowncast(64, value); } 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 */ function toUint56(uint256 value) internal pure returns (uint56) { if (value > type(uint56).max) { revert SafeCastOverflowedUintDowncast(56, value); } 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 */ function toUint48(uint256 value) internal pure returns (uint48) { if (value > type(uint48).max) { revert SafeCastOverflowedUintDowncast(48, value); } 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 */ function toUint40(uint256 value) internal pure returns (uint40) { if (value > type(uint40).max) { revert SafeCastOverflowedUintDowncast(40, value); } 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 */ function toUint32(uint256 value) internal pure returns (uint32) { if (value > type(uint32).max) { revert SafeCastOverflowedUintDowncast(32, value); } 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 */ function toUint24(uint256 value) internal pure returns (uint24) { if (value > type(uint24).max) { revert SafeCastOverflowedUintDowncast(24, value); } 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 */ function toUint16(uint256 value) internal pure returns (uint16) { if (value > type(uint16).max) { revert SafeCastOverflowedUintDowncast(16, value); } 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 */ function toUint8(uint256 value) internal pure returns (uint8) { if (value > type(uint8).max) { revert SafeCastOverflowedUintDowncast(8, value); } return uint8(value); } /** * @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) { if (value < 0) { revert SafeCastOverflowedIntToUint(value); } 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 */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(248, 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 */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(240, 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 */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(232, 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 */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(224, 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 */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(216, 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 */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(208, 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 */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(200, 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 */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(192, 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 */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(184, 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 */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(176, 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 */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(168, 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 */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(160, 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 */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(152, 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 */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(144, 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 */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(136, 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 */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(128, 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 */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(120, 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 */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(112, 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 */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(104, 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 */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(96, 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 */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(88, 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 */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(80, 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 */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(72, 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 */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(64, 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 */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(56, 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 */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(48, 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 */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(40, 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 */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(32, 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 */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(24, 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 */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(16, 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 */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(8, value); } } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive if (value > uint256(type(int256).max)) { revert SafeCastOverflowedUintToInt(value); } return int256(value); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.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: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * 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.9.2) (utils/cryptography/MerkleProof.sol) pragma solidity ^0.8.0; /** * @dev These functions deal with verification of Merkle Tree proofs. * * The tree and the proofs can be generated using our * https://github.com/OpenZeppelin/merkle-tree[JavaScript library]. * You will find a quickstart guide in the readme. * * 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. * OpenZeppelin's JavaScript library generates merkle trees that are safe * against this attack out of the box. */ 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 simultaneously proven to be a part of a merkle tree defined by * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}. * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _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} * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _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 sibling nodes in `proof`. The reconstruction * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false * respectively. * * CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer). * * _Available since v4.7._ */ function processMultiProof( bytes32[] memory proof, bool[] memory proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuilds 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 proofLen = proof.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proofLen - 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 from 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) { require(proofPos == proofLen, "MerkleProof: invalid multiproof"); unchecked { return hashes[totalHashes - 1]; } } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } /** * @dev Calldata version of {processMultiProof}. * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _Available since v4.7._ */ function processMultiProofCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuilds 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 proofLen = proof.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proofLen - 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 from 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) { require(proofPos == proofLen, "MerkleProof: invalid multiproof"); unchecked { 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 (last updated v4.9.0) (utils/introspection/ERC165Checker.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Library used to query support of an interface declared via {IERC165}. * * Note that these functions return the actual result of the query: they do not * `revert` if an interface is not supported. It is up to the caller to decide * what to do in these cases. */ library ERC165Checker { // As per the EIP-165 spec, no interface should ever match 0xffffffff bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff; /** * @dev Returns true if `account` supports the {IERC165} interface. */ function supportsERC165(address account) internal view returns (bool) { // Any contract that implements ERC165 must explicitly indicate support of // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid return supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) && !supportsERC165InterfaceUnchecked(account, _INTERFACE_ID_INVALID); } /** * @dev Returns true if `account` supports the interface defined by * `interfaceId`. Support for {IERC165} itself is queried automatically. * * See {IERC165-supportsInterface}. */ function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) { // query support of both ERC165 as per the spec and support of _interfaceId return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId); } /** * @dev Returns a boolean array where each value corresponds to the * interfaces passed in and whether they're supported or not. This allows * you to batch check interfaces for a contract where your expectation * is that some interfaces may not be supported. * * See {IERC165-supportsInterface}. * * _Available since v3.4._ */ function getSupportedInterfaces( address account, bytes4[] memory interfaceIds ) internal view returns (bool[] memory) { // an array of booleans corresponding to interfaceIds and whether they're supported or not bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length); // query support of ERC165 itself if (supportsERC165(account)) { // query support of each interface in interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]); } } return interfaceIdsSupported; } /** * @dev Returns true if `account` supports all the interfaces defined in * `interfaceIds`. Support for {IERC165} itself is queried automatically. * * Batch-querying can lead to gas savings by skipping repeated checks for * {IERC165} support. * * See {IERC165-supportsInterface}. */ function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) { // query support of ERC165 itself if (!supportsERC165(account)) { return false; } // query support of each interface in interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) { return false; } } // all interfaces supported return true; } /** * @notice Query if a contract implements an interface, does not check ERC165 support * @param account The address of the contract to query for support of an interface * @param interfaceId The interface identifier, as specified in ERC-165 * @return true if the contract at account indicates support of the interface with * identifier interfaceId, false otherwise * @dev Assumes that account contains a contract that supports ERC165, otherwise * the behavior of this method is undefined. This precondition can be checked * with {supportsERC165}. * * Some precompiled contracts will falsely indicate support for a given interface, so caution * should be exercised when using this function. * * Interface identification is specified in ERC-165. */ function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) { // prepare call bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId); // perform static call bool success; uint256 returnSize; uint256 returnValue; assembly { success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20) returnSize := returndatasize() returnValue := mload(0x00) } return success && returnSize >= 0x20 && returnValue > 0; } }
// 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 OR Apache-2.0 pragma solidity ^0.8.18; /** * @title Historical (currently deprecated) events. * @notice The events are preserved to keep the ABI backwards compatible for all historical events. */ interface INFTDropMarketDeprecatedEvents { /** * @notice [DEPRECATED] This event was updated to include totalFees and creatorRev. See MintFromDutchAuctionV2. * Emitted when a buyer mints one or more NFTs from a dutch auction sale. * @param nftContract The address of the NFT collection. * @param buyer The account which minted the NFT(s). * @param pricePaidPerNft The price per NFT paid by the buyer at the time of minting. * @param count The number of NFTs minted. * @param firstTokenId The tokenId for the first NFT minted. * The other minted tokens are assigned sequentially, so `firstTokenId` - `firstTokenId + count - 1` were minted. */ event MintFromDutchAuction( address indexed nftContract, address indexed buyer, uint256 pricePaidPerNft, uint256 count, uint256 firstTokenId ); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; /** * @notice Interface for functions the market uses in FETH. * @author batu-inal & HardlyDifficult */ interface IFethMarket { function depositFor(address account) external payable; function marketLockupFor(address account, uint256 amount) external payable returns (uint256 expiration); function marketWithdrawFrom(address from, uint256 amount) external; function marketWithdrawLocked(address account, uint256 expiration, uint256 amount) external; function marketUnlockFor(address account, uint256 expiration, uint256 amount) external; function marketChangeLockup( address unlockFrom, uint256 unlockExpiration, uint256 unlockAmount, address lockupFor, uint256 lockupAmount ) external payable returns (uint256 expiration); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; import "../../mixins/shared/MarketStructs.sol"; interface IMarketUtils { function getTransactionBreakdown( MarketTransactionOptions calldata options ) external view returns ( uint256 protocolFeeAmount, address payable[] memory creatorRecipients, uint256[] memory creatorShares, uint256 sellerRev, uint256 buyReferrerFee, uint256 sellerReferrerFee ); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; /** * @title The required interface for collections to support minting from the NFTDropMarket. * @dev This interface must be registered as a ERC165 supported interface. * @author batu-inal & HardlyDifficult */ interface INFTLazyMintedCollectionMintCountTo { function mintCountTo(uint16 count, address to) external returns (uint256 firstTokenId); /** * @notice Get the number of tokens which can still be minted. * @return count The max number of additional NFTs that can be minted by this collection. */ function numberOfTokensAvailableToMint() external view returns (uint256 count); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; /** * @title Allows an approved minter to lock down supply changes for a limited period of time. * @dev This is used to help ensure minting access and token supply are not manipulated during an active minting period. * @author HardlyDifficult */ interface INFTSupplyLock { /** * @notice Request a supply lock for a limited period of time. * @param expiration The date/time when the lock expires, in seconds since the Unix epoch. * @dev The caller must already be an approved minter. * If a lock has already been requested, it may be cleared by the lock holder by passing 0 for the expiration. */ function minterAcquireSupplyLock(uint256 expiration) external; /** * @notice Get the current supply lock holder and expiration, if applicable. * @return supplyLockHolder The address of with lock access, or the zero address if supply is not locked. * @return supplyLockExpiration The date/time when the lock expires, in seconds since the Unix epoch. Returns 0 if a * lock has not been requested or if it has already expired. */ function getSupplyLock() external view returns (address supplyLockHolder, uint256 supplyLockExpiration); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; interface IWorldsDropMarket { function soldInWorldByCollection( address seller, address nftContract, uint256 count, uint256 totalSalePrice ) external returns (uint256 worldId, address payable worldPaymentAddress, uint16 takeRateInBasisPoints); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; /** * @notice Interface for AdminRole which wraps the default admin role from * OpenZeppelin's AccessControl for easy integration. * @author batu-inal & HardlyDifficult */ interface IAdminRole { function isAdmin(address account) external view returns (bool); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; /** * @notice Interface for OperatorRole which wraps a role from * OpenZeppelin's AccessControl for easy integration. * @author batu-inal & HardlyDifficult */ interface IOperatorRole { function isOperator(address account) external view returns (bool); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; interface INFTDropMarketDutchAuction { function createLinearDutchAuctionV2( address nftContract, uint256 maxPrice, uint256 minPrice, uint256 limitPerAccount, uint256 startTime, uint256 saleDuration ) external; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; /** * @title Interface for routing calls to the NFT Drop Market to create fixed price sales. * @author HardlyDifficult & reggieag */ interface INFTDropMarketFixedPriceSale { function createFixedPriceSale( address nftContract, uint256 price, uint256 limitPerAccount, uint256 generalAvailabilityStartTime, uint256 txDeadlineTime ) external; function createFixedPriceSaleWithEarlyAccessAllowlist( address nftContract, uint256 price, uint256 limitPerAccount, uint256 generalAvailabilityStartTime, uint256 earlyAccessStartTime, bytes32 merkleRoot, string calldata merkleTreeUri, uint256 txDeadlineTime ) external; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; /** * @title A library for calculating price for time based auctions. * @author HardlyDifficult & reggieag */ library AuctionPriceFunctions { /** * @notice Calculates the price from a linear curve at the given time. * @param maxPrice The maximum price per NFT, used at the start of the auction. * @param minPrice The minimum price per NFT which is slowly reached overtime, and becomes a fixed price after the * rest time has been reached. * @param startTime The start time of the auction. * @param endTime The time at which the auction reaches the final minPrice and no longer continues to decline, in * seconds since Unix epoch. * @param time The time at which to calculate the price. */ function getLinearlyDecreasingPriceAtTime( uint256 maxPrice, uint256 minPrice, uint256 startTime, uint256 endTime, uint256 time ) internal pure returns (uint256 price) { if (time <= startTime) { // Before an auction starts, return the initial price point. price = maxPrice; } else if (time >= endTime) { // After the auction ends, the price holds at the final minPrice. price = minPrice; } else { // During the auction, calculate the price from a linear curve. // price range price = maxPrice - minPrice; uint256 timeRemaining; unchecked { // Safe math not required, if endTime >= time then one of the ifs above would have been true. timeRemaining = endTime - time; } // price range * time remaining price *= timeRemaining; unchecked { // price range * time remaining / duration // Safe math not required, if startTime >= endTime then one of the ifs above would have been true. price /= endTime - startTime; } // price range * time remaining / duration + minPrice price += minPrice; } } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; /** * @title Helper library for interacting with Merkle trees & proofs. * @author batu-inal & HardlyDifficult & reggieag */ library MerkleAddressLibrary { using MerkleProof for bytes32[]; /** * @notice Gets the root for a merkle tree comprised only of addresses. */ function getMerkleRootForAddress(address user, bytes32[] calldata proof) internal pure returns (bytes32 root) { bytes32 leaf = keccak256(abi.encodePacked(user)); root = proof.processProofCalldata(leaf); } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; error RouteCallLibrary_Call_Failed_Without_Revert_Reason(); /** * @title A library for calling external contracts with an address appended to the calldata. * @author HardlyDifficult */ library RouteCallLibrary { /** * @notice Routes a call to the specified contract, appending the from address to the end of the calldata. * If the call reverts, this will revert the transaction and the original reason is bubbled up. * @param from The address to use as the msg sender when calling the contract. * @param to The contract address to call. * @param callData The call data to use when calling the contract, without the sender appended. */ function routeCallTo(address from, address to, bytes memory callData) internal returns (bytes memory returnData) { // Forward the call, with the packed from address appended, to the specified contract. bool success; (success, returnData) = tryRouteCallTo(from, to, callData); // If the call failed, bubble up the revert reason. if (!success) { revertWithError(returnData); } } /** * @notice Routes a call to the specified contract, appending the from address to the end of the calldata. * This will not revert even if the external call fails. * @param from The address to use as the msg sender when calling the contract. * @param to The contract address to call. * @param callData The call data to use when calling the contract, without the sender appended. * @dev Consumers should look for positive confirmation that if the transaction is not successful, the returned revert * reason is expected as an acceptable reason to ignore. Generically ignoring reverts will lead to out-of-gas errors * being ignored and result in unexpected behavior. */ function tryRouteCallTo( address from, address to, bytes memory callData ) internal returns (bool success, bytes memory returnData) { // Forward the call, with the packed from address appended, to the specified contract. // solhint-disable-next-line avoid-low-level-calls (success, returnData) = to.call(abi.encodePacked(callData, from)); } /** * @notice Bubbles up the original revert reason of a low-level call failure where possible. * @dev Copied from OZ's `Address.sol` library, with a minor modification to the final revert scenario. * This should only be used when a low-level call fails. */ function revertWithError(bytes memory returnData) internal pure { // 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 RouteCallLibrary_Call_Failed_Without_Revert_Reason(); } } /** * @notice Extracts the appended sender address from the calldata. * @dev This uses the last 20 bytes of the calldata, with no guarantees that an address has indeed been appended. * If this is used for a call that was not routed with `routeCallTo`, the address returned will be incorrect (and * may be address(0)). */ function extractAppendedSenderAddress() internal pure returns (address sender) { assembly { // The router appends the msg.sender to the end of the calldata // source: https://github.com/opengsn/gsn/blob/v3.0.0-beta.3/packages/contracts/src/ERC2771Recipient.sol#L48 sender := shr(96, calldataload(sub(calldatasize(), 20))) } } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; /** * @title Helpers for working with time. * @author batu-inal & HardlyDifficult */ library TimeLibrary { /** * @notice Checks if the given timestamp is in the past. * @dev This helper ensures a consistent interpretation of expiry across the codebase. * This is different than `hasBeenReached` in that it will return false if the expiry is now. */ function hasExpired(uint256 expiry) internal view returns (bool) { return expiry < block.timestamp; } /** * @notice Checks if the given timestamp is now or in the past. * @dev This helper ensures a consistent interpretation of expiry across the codebase. * This is different from `hasExpired` in that it will return true if the timestamp is now. */ function hasBeenReached(uint256 timestamp) internal view returns (bool) { return timestamp <= block.timestamp; } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; import "@openzeppelin/contracts/access/IAccessControl.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; import "../../interfaces/internal/INFTLazyMintedCollectionMintCountTo.sol"; import "../shared/Constants.sol"; import "../shared/MarketFees.sol"; error NFTDropMarketCore_Collection_Already_Listed_For_Sale(); error NFTDropMarketCore_Invalid_Merkle_Root(); error NFTDropMarketCore_Invalid_Merkle_Tree_URI(); error NFTDropMarketCore_Mint_Permission_Required(); error NFTDropMarketCore_Must_Have_Available_Supply(); error NFTDropMarketCore_Must_Support_Collection_Mint_Interface(); error NFTDropMarketCore_Must_Support_ERC721(); error NFTDropMarketCore_Only_Callable_By_Collection_Owner(); error NFTDropMarketCore_Time_Too_Far_In_The_Future(uint256 maxTime); /** * @title A place for common modifiers and functions used by various market mixins, if any. * @dev This also leaves a gap which can be used to add a new mixin to the top of the inheritance tree. * @author batu-inal & HardlyDifficult */ abstract contract NFTDropMarketCore is ContextUpgradeable, MarketFees { using ERC165Checker for address; /** * @notice The `role` type used to validate drop collections have granted this market access to mint. * @return `keccak256("MINTER_ROLE")` */ bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); modifier notListed(address nftContract) { if (_getSellerOfCollection(nftContract) != address(0)) { revert NFTDropMarketCore_Collection_Already_Listed_For_Sale(); } _; } /// @notice Requires the given NFT contract can mint at least 1 more NFT. modifier notSoldOut(address nftContract) { if (INFTLazyMintedCollectionMintCountTo(nftContract).numberOfTokensAvailableToMint() == 0) { revert NFTDropMarketCore_Must_Have_Available_Supply(); } _; } /// @notice Requires the msg.sender has the admin role on the given NFT contract. modifier onlyCollectionAdmin(address nftContract) { if (!IAccessControl(nftContract).hasRole(DEFAULT_ADMIN_ROLE, _msgSender())) { revert NFTDropMarketCore_Only_Callable_By_Collection_Owner(); } _; } /// @notice Requires the given NFT contract supports the interfaces currently required by this market for minting, /// and that it has granted this market the MINTER_ROLE. modifier onlySupportedCollectionType(address nftContract) { if (!nftContract.supportsInterface(type(INFTLazyMintedCollectionMintCountTo).interfaceId)) { // Must support the mint interface this market depends on. revert NFTDropMarketCore_Must_Support_Collection_Mint_Interface(); } if (!nftContract.supportsERC165InterfaceUnchecked(type(IERC721).interfaceId)) { // Must be an ERC-721 NFT collection. revert NFTDropMarketCore_Must_Support_ERC721(); } if (!IAccessControl(nftContract).hasRole(MINTER_ROLE, address(this))) { revert NFTDropMarketCore_Mint_Permission_Required(); } _; } /// @notice Requires the merkle params have been assigned non-zero values. modifier onlyValidMerkle(bytes32 merkleRoot, string calldata merkleTreeUri) { if (merkleRoot == bytes32(0)) { revert NFTDropMarketCore_Invalid_Merkle_Root(); } if (bytes(merkleTreeUri).length == 0) { revert NFTDropMarketCore_Invalid_Merkle_Tree_URI(); } _; } /// @notice Requires that the time provided is not more than 2 years in the future. modifier onlyValidScheduledTime(uint256 time) { // timestamp + 2 years can never realistically overflow 256 bits. unchecked { if (time > block.timestamp + MAX_SCHEDULED_TIME_IN_THE_FUTURE) { // Prevent arbitrarily large values from accidentally being set. revert NFTDropMarketCore_Time_Too_Far_In_The_Future(block.timestamp + MAX_SCHEDULED_TIME_IN_THE_FUTURE); } } _; } function _getSellerOf( address nftContract, uint256 /* tokenId */ ) internal view virtual override returns (address payable seller) { seller = _getSellerOfCollection(nftContract); } /** * @notice Returns the seller which listed a collection for sale, or address(0) if not listed. * @param nftContract The NFT collection to check. */ function _getSellerOfCollection(address nftContract) internal view virtual returns (address payable seller) { // Returns address(0) by default. } /** * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[1_000] private __gap; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; import "@openzeppelin/contracts-v5/utils/math/SafeCast.sol"; import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; import "../../interfaces/internal/INFTSupplyLock.sol"; import { INFTDropMarketDutchAuction } from "../../interfaces/internal/routes/INFTDropMarketDutchAuction.sol"; import { IWorldsDropMarket } from "../../interfaces/internal/IWorldsDropMarket.sol"; import "../../libraries/TimeLibrary.sol"; import "../../libraries/AuctionPriceFunctions.sol"; import "../shared/FETHNode.sol"; import "../shared/WorldsNftNode.sol"; import "./NFTDropMarketCore.sol"; /// @param startTime The time when the auction starts and buyers may mint. error NFTDropMarketDutchAuction_Auction_Has_Not_Started_Yet(uint256 startTime); error NFTDropMarketDutchAuction_Auction_Not_Found(); /// @param endTime The time when the price reaches the minPrice. /// @param numberStillAvailable The number of NFTs still available to be minted. error NFTDropMarketDutchAuction_Clearing_Price_Not_Reached(uint256 endTime, uint256 numberStillAvailable); error NFTDropMarketDutchAuction_Creator_Revenue_Has_Already_Been_Withdrawn(); /// @param maxTime The maximum endTime (`startTime + saleDuration`) for an auction created now. error NFTDropMarketDutchAuction_End_Time_Too_Far_In_The_Future(uint256 maxTime); error NFTDropMarketDutchAuction_Invalid_Nft_Recipient(); error NFTDropMarketDutchAuction_Limit_Per_Account_Must_Be_Set(); error NFTDropMarketDutchAuction_Min_Price_Must_Be_Less_Than_Max_Price(); error NFTDropMarketDutchAuction_Mint_Count_Must_Be_Greater_Than_Zero(); /// @param currentMintCount The number of NFTs that have already been minted. /// @param limitPerAccount The limit of NFTs that can be minted per account. error NFTDropMarketDutchAuction_Mint_Exceeds_Limit_Per_Account(uint256 currentMintCount, uint256 limitPerAccount); error NFTDropMarketDutchAuction_Must_Have_Available_Supply(); error NFTDropMarketDutchAuction_Nothing_To_Rebate_At_This_Time(); error NFTDropMarketDutchAuction_Sale_Duration_Must_Be_Greater_Than_Zero(); error NFTDropMarketDutchAuction_Start_Time_Must_Not_Be_In_The_Past(); /** * @title Allows creators to list a drop collection for sale via a dutch auction. * @notice The price per NFT declines overtime until the collection sells out or the minPrice is reached. * Collectors which buy in before this final clearing price point can request a rebate, such that all buyers end up * paying the same amount. * @author HardlyDifficult & reggieag. */ abstract contract NFTDropMarketDutchAuction is INFTDropMarketDutchAuction, ContextUpgradeable, WorldsNftNode, FETHNode, NFTDropMarketCore { using SafeCast for uint256; using TimeLibrary for uint256; using TimeLibrary for uint32; //////////////////////////////////////////////////////////////// // Data //////////////////////////////////////////////////////////////// /// @notice Tracks purchases of a given buyer from a collection in dutch auction. struct DutchAuctionBuyerMintInfo { // Slot 0 /// @notice The total amount paid by the buyer for NFTs minted, minus any rebates sent. uint96 totalPosted; /// @notice The total number of NFTs minted by the buyer. uint16 mintedCount; // (144-bits free space) } /// @notice Dutch auction configuration and purchase tracking for a given collection. struct DutchAuctionInfo { // Slot 0 /// @notice The maximum price per NFT, used at the start of the auction. uint96 maxPrice; /// @notice The minimum price per NFT, reached if the auction doesn't sell out before the endTime. uint96 minPrice; /// @notice The time when the auction starts and buyers may mint. uint32 startTime; /// @notice The time when the price reaches the minPrice if it hasn't already minted out. uint32 endTime; // (slot full) // Slot 1 /// @notice The maximum number of NFTs that can be minted per account in this sale. uint16 limitPerAccount; /// @notice The total number of NFTs that have been minted in this sale so far. uint32 totalMintedCount; /// @notice The total number of NFTs that were available to be minted when the auction was created. uint32 totalAvailableSupply; /// @notice The last successful sale price. uint96 lastSalePrice; /// @notice True if the creator revenue has already been withdrawn. bool creatorRevenueHasBeenWithdrawn; // (72-bits free space) // Slot 2 /// @notice The account which listed this collection for sale. address payable seller; // (96-bits free space) // Slot 3 /// @notice Tracks purchases for a given buyer. mapping(address buyer => DutchAuctionBuyerMintInfo mintInfo) buyerToMintInfo; // (slot full) } /// @notice Stores dutch auction details for a given collection. mapping(address collection => DutchAuctionInfo auctionInfo) private $collectionToDutchAuctionInfo; //////////////////////////////////////////////////////////////// // Events //////////////////////////////////////////////////////////////// /** * @notice Emitted when a collection is listed for sale via a linear dutch auction. * @param nftContract The address of the NFT collection. * @param seller The account which listed this collection for sale. * @param maxPrice The maximum price per NFT, used at the start of the auction. * @param minPrice The minimum price per NFT, reached if the auction doesn't sell out before the endTime. * @param limitPerAccount The maximum number of NFTs that can be minted per account in this sale. * @param startTime The time when the auction starts and buyers may mint, in seconds since Unix epoch. * @param endTime The time when the price reaches the minPrice if it hasn't already minted out, in seconds since Unix * epoch. */ event CreateLinearDutchAuction( address indexed nftContract, address indexed seller, uint256 maxPrice, uint256 minPrice, uint256 limitPerAccount, uint256 startTime, uint256 endTime ); /** * @notice Emitted when a buyer mints one or more NFTs from a dutch auction sale. * @param nftContract The address of the NFT collection. * @param buyer The account which minted the NFT(s). * @param pricePaidPerNft The price per NFT paid by the buyer at the time of minting. * @param count The number of NFTs minted. * @param firstTokenId The tokenId for the first NFT minted. * The other minted tokens are assigned sequentially, so `firstTokenId` - `firstTokenId + count - 1` were minted. * @param totalFees The amount of ETH that was sent to Foundation for this sale. * Always zero before the creator revenue has been withdrawn. * @param creatorRev The amount of ETH that was sent to the creator for this sale. Includes seller referral fees. * Always zero before the creator revenue has been withdrawn. */ event MintFromDutchAuctionV2( address indexed nftContract, address indexed buyer, uint256 pricePaidPerNft, uint256 count, uint256 firstTokenId, uint256 totalFees, uint256 creatorRev ); /** * @notice Emitted when a buyer receives a rebate for the difference between the current price per NFT and the price * they have already paid. * @param nftContract The address of the NFT collection. * @param buyer The account which received the rebate for earlier mint(s). * @param rebate The amount of ETH returned to the buyer. * @param currentPricePerNft The current price per NFT at the time of this rebate. * @dev If the price per NFT drops below currentPricePerNft then another rebate may be requested for this buyer. */ event RebateBuyerFromDutchAuction( address indexed nftContract, address indexed buyer, uint256 rebate, uint256 currentPricePerNft ); /** * @notice Emitted when the creator revenue is withdrawn after a dutch auction has reached the final clearing price. * @param nftContract The address of the NFT collection. * @param clearingPrice The final clearing price per NFT. * @param totalMintedCount The total number of NFTs minted. * @param totalFees The total fees collected. * @param creatorRev The amount of ETH withdrawn by the creator. */ event WithdrawCreatorRevenueFromDutchAuction( address indexed nftContract, uint256 clearingPrice, uint256 totalMintedCount, uint256 totalFees, uint256 creatorRev ); //////////////////////////////////////////////////////////////// // Creating auctions //////////////////////////////////////////////////////////////// /** * @notice Allows an admin of a collection to create a new dutch auction, where the price declines linearly over time * during the sale until it either sells out or the minPrice is reached. * @param nftContract The address of the NFT drop collection. * @param maxPrice The maximum price per NFT, used at the start of the auction. This value must be non-zero and * greater than the minPrice, but less than ~70 billion ETH. Set in wei. * @param minPrice The minimum price per NFT which is slowly reached overtime, and becomes a fixed price after the * endTime has been reached. Set in wei and this value may be 0. * @param limitPerAccount The max number of NFTs an account may mint in this sale. A value between 1 and 65,535 is * required. * @param startTime The time at which the auction should start, in seconds since Unix epoch. Pass 0 to have the * auction start immediately. * @param saleDuration The length of time after startTime until the auction reaches the minPrice and no longer * continues to decline, in seconds since Unix epoch. The auction's endTime (startTime + saleDuration) must be in * <= 2 years. * @dev Notes: * a) The sale is final and can not be updated or canceled. * b) Any collection that abides by `INFTLazyMintedCollectionMintCountTo`, `IAccessControl`, and `INFTSupplyLock` * is supported. */ function createLinearDutchAuctionV2( address nftContract, uint256 maxPrice, uint256 minPrice, uint256 limitPerAccount, uint256 startTime, uint256 saleDuration ) external onlySupportedCollectionType(nftContract) onlyCollectionAdmin(nftContract) notListed(nftContract) { /* CHECKS */ // Price must decline over time. if (maxPrice <= minPrice) { revert NFTDropMarketDutchAuction_Min_Price_Must_Be_Less_Than_Max_Price(); } // A non-zero limit is required. if (limitPerAccount == 0) { revert NFTDropMarketDutchAuction_Limit_Per_Account_Must_Be_Set(); } // The sale must start now or in the future. if (startTime == 0) { // When startTime is 0, the sale starts immediately. startTime = block.timestamp; } else if (startTime.hasExpired()) { revert NFTDropMarketDutchAuction_Start_Time_Must_Not_Be_In_The_Past(); } // The sale must run for > 0 seconds and end in <= 2 years. if (saleDuration == 0) { revert NFTDropMarketDutchAuction_Sale_Duration_Must_Be_Greater_Than_Zero(); } uint256 endTime = startTime + saleDuration; unchecked { // timestamp + 2 years can never realistically overflow 256 bits. if (endTime > block.timestamp + MAX_SCHEDULED_TIME_IN_THE_FUTURE) { // Prevent arbitrarily large values from accidentally being set. revert NFTDropMarketDutchAuction_End_Time_Too_Far_In_The_Future( block.timestamp + MAX_SCHEDULED_TIME_IN_THE_FUTURE ); } } // The collection must have NFTs available to mint. uint256 availableToMint = INFTLazyMintedCollectionMintCountTo(nftContract).numberOfTokensAvailableToMint(); if (availableToMint == 0) { revert NFTDropMarketDutchAuction_Must_Have_Available_Supply(); } address payable sender = payable(_msgSender()); DutchAuctionInfo storage auctionInfo = $collectionToDutchAuctionInfo[nftContract]; /* EFFECTS */ // Splitting storage write (by slot) to avoid stack too deep (auctionInfo.maxPrice, auctionInfo.minPrice, auctionInfo.startTime, auctionInfo.endTime) = ( maxPrice.toUint96(), // Safe cast is not required since minPrice is less than maxPrice which is also uint96. uint96(minPrice), // Safe cast is not required on the times since MAX_SCHEDULED_TIME_IN_THE_FUTURE confirms the max is in range // until 2106. Checking the endTime implicitly ensures that the startTime is also not too far in the future. uint32(startTime), uint32(endTime) ); (auctionInfo.limitPerAccount, auctionInfo.totalAvailableSupply, auctionInfo.seller) = ( limitPerAccount.toUint16(), // If a huge number of NFTs are available, this will revert & prevent it from being listed in a dutch auction. availableToMint.toUint32(), sender ); // totalMintedCount, lastSalePrice and creatorRevenueHasBeenWithdrawn default to 0/false /* INTERACTIONS */ // If a supply lock is not supported, this will revert blocking the ability to use dutch auctions. // This will also revert if the collection has already promised the lock to another market or user. INFTSupplyLock(nftContract).minterAcquireSupplyLock(endTime); emit CreateLinearDutchAuction(nftContract, sender, maxPrice, minPrice, limitPerAccount, startTime, endTime); } //////////////////////////////////////////////////////////////// // Minting //////////////////////////////////////////////////////////////// /** * @notice Mints NFTs from a dutch auction sale. * @param nftContract The address of the NFT collection. * @param count The number of NFTs to mint. * @param nftRecipient The address which will receive the NFT(s) and any future auction rebate for this purchase. * @return firstTokenId The ID of the first token minted. * The other minted tokens are assigned sequentially, so `firstTokenId` - `firstTokenId + count - 1` were minted. * @dev If more msg.value is provided then required, the surplus will be refunded to the nftRecipient. */ function mintFromDutchAuctionV2( address nftContract, uint256 count, address nftRecipient ) external payable returns (uint256 firstTokenId) { firstTokenId = _mintFromDutchAuction(nftContract, count, nftRecipient, true); } /// @notice [DEPRECATED] Use `mintFromDutchAuctionV2` instead. function mintFromDutchAuction(address nftContract, uint256 count) external payable returns (uint256 firstTokenId) { firstTokenId = _mintFromDutchAuction(nftContract, count, _msgSender(), false); } function _mintFromDutchAuction( address nftContract, uint256 count, address nftRecipient, bool includeMintFee ) private returns (uint256 firstTokenId) { /* CHECKS */ // A non-zero count is required. if (count == 0) { revert NFTDropMarketDutchAuction_Mint_Count_Must_Be_Greater_Than_Zero(); } if (nftRecipient == address(0)) { revert NFTDropMarketDutchAuction_Invalid_Nft_Recipient(); } DutchAuctionInfo storage auctionInfo = $collectionToDutchAuctionInfo[nftContract]; // The collection must be listed for sale in dutch auction. if (auctionInfo.endTime == 0) { // This check uses endTime as a proxy for auction exists since that slot is always read anyways during minting. revert NFTDropMarketDutchAuction_Auction_Not_Found(); } // The auction must have started. if (!auctionInfo.startTime.hasBeenReached()) { revert NFTDropMarketDutchAuction_Auction_Has_Not_Started_Yet(auctionInfo.startTime); } DutchAuctionBuyerMintInfo storage buyerMintInfo = auctionInfo.buyerToMintInfo[nftRecipient]; // Check if the buyer has exhausted their mint limit. uint256 buyerMintCount = count + buyerMintInfo.mintedCount; if (buyerMintCount > auctionInfo.limitPerAccount) { revert NFTDropMarketDutchAuction_Mint_Exceeds_Limit_Per_Account( buyerMintInfo.mintedCount, auctionInfo.limitPerAccount ); } // Calculate the price and cost. uint256 pricePerNft = getPriceAtTimeForDutchAuction(nftContract, block.timestamp); uint256 totalCostBeforeMintFee; unchecked { // Safe math is not required because price is uint96 and count is capped by the limitPerAccount which is uint16. totalCostBeforeMintFee = pricePerNft * count; } bool creatorRevenueHasBeenWithdrawn = auctionInfo.creatorRevenueHasBeenWithdrawn; uint256 totalFees; uint256 creatorRev; { // If too much value was provided, store the surplus for when the user requests a rebate. uint256 fixedProtocolFeeInWei = includeMintFee ? MINT_FEE_IN_WEI * count : 0; { uint256 totalCost = totalCostBeforeMintFee + fixedProtocolFeeInWei; /* EFFECTS */ (auctionInfo.totalMintedCount, auctionInfo.lastSalePrice) = ( // Safe cast not required for count / buyerMintCount, since they're capped by uint16 limitPerAccount. uint32(count + auctionInfo.totalMintedCount), // Safe cast is not required since the max and min prices are uint96. uint96(pricePerNft) ); (buyerMintInfo.totalPosted, buyerMintInfo.mintedCount) = ( (buyerMintInfo.totalPosted + totalCostBeforeMintFee).toUint96(), uint16(buyerMintCount) ); /* INTERACTIONS */ // If the msg.value was not enough to cover the cost, attempt to use the buyer's FETH balance. If insufficient // FETH is available this will revert the mint. This interaction is with a trusted contract. _tryUseFETHBalance({ totalAmount: totalCost, shouldRefundSurplus: true }); } // Mint NFT(s) for the buyer. firstTokenId = INFTLazyMintedCollectionMintCountTo(nftContract).mintCountTo(uint16(count), nftRecipient); if (creatorRevenueHasBeenWithdrawn) { // Once the revenue has been withdrawn, sales distribute funds immediately instead of storing the value in // escrow. The seller does not need to be cached before interactions since the field is immutable once an // auction has been created. (totalFees, creatorRev) = _distributeFundsFromSale({ nftContract: nftContract, saleCount: count, totalSale: totalCostBeforeMintFee, nftRecipientIfKnown: nftRecipient, seller: auctionInfo.seller, tokenId: firstTokenId, fixedProtocolFeeInWei: fixedProtocolFeeInWei }); } else if (includeMintFee) { // Pay the fixed fee and emit _distributeFixedProtocolFee(nftContract, firstTokenId, count, nftRecipient, fixedProtocolFeeInWei); } } emit MintFromDutchAuctionV2(nftContract, nftRecipient, pricePerNft, count, firstTokenId, totalFees, creatorRev); } //////////////////////////////////////////////////////////////// // Buyer post sale //////////////////////////////////////////////////////////////// /** * @notice Sends a buyer the difference between the amount they paid and the current price point for this dutch * auction. * @param nftContract The NFT collection address. * @param buyer The buyer to rebate. * @dev This may be called by anyone on behalf of the buyer, and may be called multiple times if the price continues * to decline after a previous call. */ function rebateBuyerFromDutchAuction(address nftContract, address payable buyer) external { /* CHECKS */ DutchAuctionBuyerMintInfo storage buyerMintInfo = $collectionToDutchAuctionInfo[nftContract].buyerToMintInfo[buyer]; (uint256 mintedCount, uint256 totalPosted) = (buyerMintInfo.mintedCount, buyerMintInfo.totalPosted); uint256 currentPricePerNft = getPriceAtTimeForDutchAuction(nftContract, block.timestamp); uint256 requiredAmount; unchecked { // Safe math is not required because the maxPrice is uint96 and mintedCount is uint16. requiredAmount = currentPricePerNft * mintedCount; } uint256 rebate = totalPosted - requiredAmount; if (rebate == 0) { revert NFTDropMarketDutchAuction_Nothing_To_Rebate_At_This_Time(); } /* EFFECTS */ // Safe cast is not required since requiredAmount is < totalPosted which is also uint96. buyerMintInfo.totalPosted = uint96(requiredAmount); /* INTERACTIONS */ _sendValueWithFallbackWithdraw(buyer, rebate, SEND_VALUE_GAS_LIMIT_MULTIPLE_RECIPIENTS); emit RebateBuyerFromDutchAuction(nftContract, buyer, rebate, currentPricePerNft); } /** * @notice Checks a buyer's pending rebate from previous purchase and the max number of NFTs they may still mint from * the dutch auction. * @param nftContract The address of the NFT collection. * @param buyer The address which has or will be minting. * @return outstandingRebateBalance The amount available to be rebated to this buyer. * @return numberThatCanBeMinted How many NFTs the buyer can still mint. */ function getBuyerInfoFromDutchAuction( address nftContract, address buyer ) external view returns (uint256 outstandingRebateBalance, uint256 numberThatCanBeMinted) { DutchAuctionInfo storage auctionInfo = $collectionToDutchAuctionInfo[nftContract]; DutchAuctionBuyerMintInfo memory buyerMintInfo = auctionInfo.buyerToMintInfo[buyer]; uint256 currentTotalCost; unchecked { // Safe math is not required because the maxPrice is uint96 and mintedCount is uint16. currentTotalCost = getPriceAtTimeForDutchAuction(nftContract, block.timestamp) * buyerMintInfo.mintedCount; } outstandingRebateBalance = buyerMintInfo.totalPosted - currentTotalCost; uint256 limitPerAccount = auctionInfo.limitPerAccount; // If the buyer has exhausted their limit then the number that can be minted is the default of 0. if (buyerMintInfo.mintedCount < limitPerAccount) { unchecked { // Safe math is not required due to the if statement directly above. numberThatCanBeMinted = limitPerAccount - buyerMintInfo.mintedCount; } uint256 availableSupply = auctionInfo.totalAvailableSupply; uint256 totalMintedCount = auctionInfo.totalMintedCount; if (availableSupply > totalMintedCount) { unchecked { // Safe math is not required due to the if statement directly above. availableSupply -= totalMintedCount; } if (numberThatCanBeMinted > availableSupply) { // The buyer's mint limit is limited by the available supply remaining. numberThatCanBeMinted = availableSupply; } } else { // The collection has sold out. numberThatCanBeMinted = 0; } } } //////////////////////////////////////////////////////////////// // Seller post sale //////////////////////////////////////////////////////////////// /** * @notice Sends the creator revenue from a dutch auction which has sold out or reached the endTime / minPrice. * @param nftContract The address of the NFT collection. * @dev Anyone may call this on behalf of the creator. This will also pay the treasury and split recipients if * applicable. Once called, any future sales at the final clearing price will send funds as purchases are made. This * is callable even if no funds to withdraw but it may only be called once per sale. */ function withdrawCreatorRevenueFromDutchAuction(address nftContract) external { /* CHECKS */ DutchAuctionInfo storage auctionInfo = $collectionToDutchAuctionInfo[nftContract]; address payable seller = auctionInfo.seller; // Auction must have been created. if (seller == address(0)) { revert NFTDropMarketDutchAuction_Auction_Not_Found(); } // Withdraw may only be called once. if (auctionInfo.creatorRevenueHasBeenWithdrawn) { revert NFTDropMarketDutchAuction_Creator_Revenue_Has_Already_Been_Withdrawn(); } // Auction must be sold out or has reached the endTime / minPrice. uint256 totalMintedCount = auctionInfo.totalMintedCount; if (!auctionInfo.endTime.hasExpired() && totalMintedCount < auctionInfo.totalAvailableSupply) { unchecked { revert NFTDropMarketDutchAuction_Clearing_Price_Not_Reached( auctionInfo.endTime, // Safe math is not required thanks to the above if check. auctionInfo.totalAvailableSupply - totalMintedCount ); } } // Calculate the total sale amount for distribution. uint256 clearingPrice = getPriceAtTimeForDutchAuction(nftContract, block.timestamp); uint256 totalSale; unchecked { // Safe math is not required since the max and min prices are uint96 and totalMintedCount is uint32. totalSale = clearingPrice * totalMintedCount; } /* EFFECTS */ auctionInfo.creatorRevenueHasBeenWithdrawn = true; /* INTERACTIONS */ (uint256 totalFees, uint256 creatorRev) = _distributeFundsFromSale({ nftContract: nftContract, saleCount: totalMintedCount, totalSale: totalSale, nftRecipientIfKnown: address(0), seller: seller, tokenId: 0, // Unknown since this may represent many sales. fixedProtocolFeeInWei: 0 }); emit WithdrawCreatorRevenueFromDutchAuction(nftContract, clearingPrice, totalMintedCount, totalFees, creatorRev); } /** * @notice Checks seller related information for a collection which has been scheduled in a dutch auction. * @param nftContract The address of the NFT collection. * @return seller The address of the user which listed the collection for sale. * @return creatorRevenueReadyForWithdrawal True if the auction has reached a final clearing price and revenue is * ready to be withdrawn. This will be false if the creator revenue has already been withdrawn. * @return creatorRevenueHasBeenWithdrawn True if the creator revenue has already been withdrawn. * @return totalFundsPendingDistribution The total amount of funds which are pending distribution. */ function getSellerInfoFromDutchAuction( address nftContract ) external view returns ( address seller, bool creatorRevenueReadyForWithdrawal, bool creatorRevenueHasBeenWithdrawn, uint256 totalFundsPendingDistribution ) { DutchAuctionInfo storage auctionInfo = $collectionToDutchAuctionInfo[nftContract]; // Return default values if an auction has not been created yet. if (auctionInfo.endTime != 0) { seller = auctionInfo.seller; creatorRevenueHasBeenWithdrawn = auctionInfo.creatorRevenueHasBeenWithdrawn; // creatorRevenueReadyForWithdrawal and totalFundsPendingDistribution are n/a if the creator revenue has already // been withdrawn. if (!creatorRevenueHasBeenWithdrawn) { creatorRevenueReadyForWithdrawal = // The auction has sold out. auctionInfo.totalMintedCount >= auctionInfo.totalAvailableSupply || // Or it's past the auction's endTime. auctionInfo.endTime.hasExpired(); unchecked { // Safe math is not required because the maxPrice is uint96 and totalMintedCount is uint32. totalFundsPendingDistribution = getPriceAtTimeForDutchAuction(nftContract, block.timestamp) * auctionInfo.totalMintedCount; } } } } /** * @notice A helper to distribute funds from a dutch auction sale. * @param nftContract The NFT collection address. * @param totalSale The total ETH sale amount. * @param seller The seller which listed the collection for sale. */ function _distributeFundsFromSale( address nftContract, uint256 saleCount, uint256 totalSale, address nftRecipientIfKnown, address payable seller, uint256 tokenId, uint256 fixedProtocolFeeInWei ) private returns (uint256 totalFees, uint256 creatorRev) { // These values do not need to be cached before interactions since the fields cannot be modified other than to // delete the World, resulting in 0 values being returned here which does not pose a security risk. (, address payable worldPaymentAddress, uint16 takeRateInBasisPoints) = IWorldsDropMarket(worlds) .soldInWorldByCollection(seller, nftContract, saleCount, totalSale); // sellerRev is always 0 and ignored here since mints are primary sales, revenue is attributed to the creator. (totalFees, creatorRev, ) = _distributeFunds( DistributeFundsParams({ nftContract: nftContract, firstTokenId: tokenId, nftCount: saleCount, nftRecipientIfKnown: nftRecipientIfKnown, seller: seller, price: totalSale, buyReferrer: payable(0), // Not supported sellerReferrerPaymentAddress: worldPaymentAddress, sellerReferrerTakeRateInBasisPoints: takeRateInBasisPoints, fixedProtocolFeeInWei: fixedProtocolFeeInWei }) ); } /** * @inheritdoc NFTDropMarketCore * @dev Returns the seller for a collection if listed in a dutch auction. */ function _getSellerOfCollection(address nftContract) internal view virtual override returns (address payable seller) { seller = $collectionToDutchAuctionInfo[nftContract].seller; if (seller == address(0)) { seller = super._getSellerOfCollection(nftContract); } } //////////////////////////////////////////////////////////////// // General Getters //////////////////////////////////////////////////////////////// /** * @notice Returns information about a given dutch auction. * @param nftContract The address of the NFT collection which was listed for sale in a dutch auction. * @return maxPrice The maximum price per NFT, used at the start of the auction. * @return minPrice The minimum price per NFT which is slowly reached overtime, and becomes a fixed price after the * endTime has been reached. This value may be 0. * @return limitPerAccount The max number of NFTs an account may mint in this sale. * @return startTime The time at which the auction should start, in seconds since Unix epoch. * @return endTime The time at which the auction reaches the minPrice and no longer continues to decline, in seconds * since Unix epoch. * @return totalAvailableSupply The collection's available supply when the auction was originally created. * @return totalMintedCount The number of NFTs minted via this dutch auction. * @return lastSalePrice The price per NFT of the last recorded sale, or 0 if no sales have been made. * @return currentPrice The current price per NFT. * @return mintFeePerNftInWei The fee in wei per NFT minted from this auction. * @dev To determine if price action has ended / the clearing price has been reached - check if the endTime has * expired or if totalMintedCount == totalAvailableSupply. */ function getDutchAuctionV2( address nftContract ) external view returns ( uint256 maxPrice, uint256 minPrice, uint256 limitPerAccount, uint256 startTime, uint256 endTime, uint256 totalAvailableSupply, uint256 totalMintedCount, uint256 lastSalePrice, uint256 currentPrice, uint256 mintFeePerNftInWei ) { DutchAuctionInfo storage auctionInfo = $collectionToDutchAuctionInfo[nftContract]; maxPrice = auctionInfo.maxPrice; minPrice = auctionInfo.minPrice; limitPerAccount = auctionInfo.limitPerAccount; startTime = auctionInfo.startTime; endTime = auctionInfo.endTime; totalAvailableSupply = auctionInfo.totalAvailableSupply; totalMintedCount = auctionInfo.totalMintedCount; lastSalePrice = auctionInfo.lastSalePrice; currentPrice = getPriceAtTimeForDutchAuction(nftContract, block.timestamp); mintFeePerNftInWei = MINT_FEE_IN_WEI; } /// @notice [DEPRECATED] Use `getDutchAuctionV2` instead. function getDutchAuction( address nftContract ) external view returns ( uint256 maxPrice, uint256 minPrice, uint256 limitPerAccount, uint256 startTime, uint256 endTime, uint256 totalAvailableSupply, uint256 totalMintedCount, uint256 lastSalePrice, uint256 currentPrice ) { // Unable to reuse the V2 implementation here due to stack too deep. DutchAuctionInfo storage auctionInfo = $collectionToDutchAuctionInfo[nftContract]; maxPrice = auctionInfo.maxPrice; minPrice = auctionInfo.minPrice; limitPerAccount = auctionInfo.limitPerAccount; startTime = auctionInfo.startTime; endTime = auctionInfo.endTime; totalAvailableSupply = auctionInfo.totalAvailableSupply; totalMintedCount = auctionInfo.totalMintedCount; lastSalePrice = auctionInfo.lastSalePrice; currentPrice = getPriceAtTimeForDutchAuction(nftContract, block.timestamp); } /** * @notice Get the price per NFT for sale in a dutch auction if purchased at the given time. * @param nftContract The NFT collection address. * @param time Time in seconds since the Unix epoch to calculate the price for. * @return price The price per NFT at the time provided. * @dev This should not be used for historical prices, once the collection sells out this always returns the final * clearing price and not the correct historical value. */ function getPriceAtTimeForDutchAuction(address nftContract, uint256 time) public view returns (uint256 price) { DutchAuctionInfo storage auctionInfo = $collectionToDutchAuctionInfo[nftContract]; if (auctionInfo.totalMintedCount >= auctionInfo.totalAvailableSupply) { // All tokens have been minted, so the final clearing price is the last successful sale price. price = auctionInfo.lastSalePrice; } else { // Not all tokens have been minted, so calculate current price based on auction config and the time provided. price = AuctionPriceFunctions.getLinearlyDecreasingPriceAtTime( auctionInfo.maxPrice, auctionInfo.minPrice, auctionInfo.startTime, auctionInfo.endTime, time ); } } /** * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps * @dev This mixin uses 1,000 slots in total. */ uint256[999] private __gap; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; /** * @title [DEPRECATED] This mixin has been deprecated in favor of the Worlds NFT contract. */ abstract contract NFTDropMarketExhibitionGap { /// @dev Was mapping(address nftContract => uint256 exhibitionId) private $nftContractToExhibitionId; uint256 private __gap_was_$nftContractToExhibitionId; /** * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps * @dev This mixin uses 1,000 slots in total. */ uint256[999] private __gap; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; import "@openzeppelin/contracts-v5/utils/math/SafeCast.sol"; import "../../interfaces/internal/INFTLazyMintedCollectionMintCountTo.sol"; import "../../interfaces/internal/routes/INFTDropMarketFixedPriceSale.sol"; import "../../interfaces/internal/IWorldsDropMarket.sol"; import "../../libraries/MerkleAddressLibrary.sol"; import "../../libraries/TimeLibrary.sol"; import "../shared/MarketFees.sol"; import "../shared/TxDeadline.sol"; import "../shared/WorldsNftNode.sol"; import "./NFTDropMarketCore.sol"; /// @param limitPerAccount The limit of tokens an account can purchase. error NFTDropMarketFixedPriceSale_Cannot_Buy_More_Than_Limit(uint256 limitPerAccount); /// @param earlyAccessStartTime The time when early access starts, in seconds since the Unix epoch. error NFTDropMarketFixedPriceSale_Early_Access_Not_Open(uint256 earlyAccessStartTime); error NFTDropMarketFixedPriceSale_Early_Access_Start_Time_Has_Expired(); error NFTDropMarketFixedPriceSale_General_Access_Is_Open(); /// @param generalAvailabilityStartTime The start time of the general availability period, in seconds since the Unix /// epoch. error NFTDropMarketFixedPriceSale_General_Access_Not_Open(uint256 generalAvailabilityStartTime); error NFTDropMarketFixedPriceSale_General_Availability_Start_Time_Has_Expired(); error NFTDropMarketFixedPriceSale_Invalid_Merkle_Proof(); error NFTDropMarketFixedPriceSale_Limit_Per_Account_Must_Be_Set(); error NFTDropMarketFixedPriceSale_Must_Be_Listed_For_Sale(); error NFTDropMarketFixedPriceSale_Must_Buy_At_Least_One_Token(); error NFTDropMarketFixedPriceSale_Must_Have_Non_Zero_Early_Access_Duration(); error NFTDropMarketFixedPriceSale_Invalid_Nft_Recipient(); /** * @title Allows creators to list a drop collection for sale at a fixed price point. * @dev Listing a collection for sale in this market requires the collection to implement * the functions in `INFTLazyMintedCollectionMintCountTo` and to register that interface with ERC165. * Additionally the collection must implement access control, or more specifically: * `hasRole(bytes32(0), msg.sender)` must return true when called from the creator or admin's account * and `hasRole(keccak256("MINTER_ROLE", address(this)))` must return true for this market's address. * @author batu-inal & HardlyDifficult & philbirt & reggieag */ abstract contract NFTDropMarketFixedPriceSale is INFTDropMarketFixedPriceSale, TxDeadline, ContextUpgradeable, WorldsNftNode, NFTDropMarketCore { using MerkleAddressLibrary for address; using SafeCast for uint256; using TimeLibrary for uint32; using TimeLibrary for uint256; /** * @notice Configuration for the terms of the sale. */ struct FixedPriceSaleConfig { /****** Slot 0 (of this struct) ******/ /// @notice The seller for the drop. address payable seller; /// @notice The fixed price per NFT in the collection. /// @dev The maximum price that can be set on an NFT is ~1.2M (2^80/10^18) ETH. uint80 price; /// @notice The max number of NFTs an account may mint in this sale. uint16 limitPerAccount; /****** Slot 1 ******/ /// @notice Tracks how many NFTs a given user has already minted. mapping(address => uint256) userToMintedCount; /****** Slot 2 ******/ /// @notice The start time of the general availability period, in seconds since the Unix epoch. /// @dev This must be >= `earlyAccessStartTime`. /// When set to 0, general availability was not scheduled and started as soon as the price was set. uint32 generalAvailabilityStartTime; /// @notice The time when early access purchasing may begin, in seconds since the Unix epoch. /// @dev This must be <= `generalAvailabilityStartTime`. /// When set to 0, early access was not scheduled and started as soon as the price was set. uint32 earlyAccessStartTime; // 192-bits available in this slot /****** Slot 3 ******/ /// @notice Merkle roots representing which users have access to purchase during the early access period. /// @dev There may be many roots supported per sale where each is considered additive as any root may be used to /// purchase. mapping(bytes32 => bool) earlyAccessMerkleRoots; } /// @notice Stores the current sale information for all drop contracts. mapping(address => FixedPriceSaleConfig) private nftContractToFixedPriceSaleConfig; /** * @notice Emitted when an early access merkle root is added to a fixed price sale early access period. * @param nftContract The address of the NFT drop collection. * @param merkleRoot The merkleRoot used to authorize early access purchases. * @param merkleTreeUri The URI for the merkle tree represented by the merkleRoot. */ event AddMerkleRootToFixedPriceSale(address indexed nftContract, bytes32 merkleRoot, string merkleTreeUri); /** * @notice Emitted when a collection is listed for sale. * @param nftContract The address of the NFT drop collection. * @param seller The address for the seller which listed this for sale. * @param price The price per NFT minted. * @param limitPerAccount The max number of NFTs an account may mint in this sale. * @param generalAvailabilityStartTime The time at which general purchases are available, in seconds since Unix epoch. * Can not be more than two years from the creation block timestamp. * @param earlyAccessStartTime The time at which early access purchases are available, in seconds since Unix epoch. * Can not be more than two years from the creation block timestamp. * @param merkleRoot The merkleRoot used to authorize early access purchases, or 0 if n/a. * @param merkleTreeUri The URI for the merkle tree represented by the merkleRoot, or empty if n/a. */ event CreateFixedPriceSale( address indexed nftContract, address indexed seller, uint256 price, uint256 limitPerAccount, uint256 generalAvailabilityStartTime, uint256 earlyAccessStartTime, bytes32 merkleRoot, string merkleTreeUri ); /** * @notice Emitted when NFTs are minted from the drop. * @dev The total price paid by the buyer is `totalFees + creatorRev`. * @param nftContract The address of the NFT drop collection. * @param buyer The address of the buyer. * @param firstTokenId The tokenId for the first NFT minted. * The other minted tokens are assigned sequentially, so `firstTokenId` - `firstTokenId + count - 1` were minted. * @param count The number of NFTs minted. * @param totalFees The amount of ETH that was sent to Foundation & referrals for this sale. * @param creatorRev The amount of ETH that was sent to the creator for this sale. */ event MintFromFixedPriceDrop( address indexed nftContract, address indexed buyer, uint256 indexed firstTokenId, uint256 count, uint256 totalFees, uint256 creatorRev ); //////////////////////////////////////////////////////////////// // Sale Management //////////////////////////////////////////////////////////////// /** * @notice Add a merkle root to an existing fixed price sale early access period. * @param nftContract The address of the NFT drop collection. * @param merkleRoot The merkleRoot used to authorize early access purchases. * @param merkleTreeUri The URI for the merkle tree represented by the merkleRoot. * @dev If you accidentally pass in the wrong merkleTreeUri for a merkleRoot, * you can call this function again to emit a new event with a new merkleTreeUri. */ function addMerkleRootToFixedPriceSale( address nftContract, bytes32 merkleRoot, string calldata merkleTreeUri ) external notSoldOut(nftContract) onlyCollectionAdmin(nftContract) onlyValidMerkle(merkleRoot, merkleTreeUri) { FixedPriceSaleConfig storage saleConfig = nftContractToFixedPriceSaleConfig[nftContract]; if (saleConfig.generalAvailabilityStartTime.hasBeenReached()) { // Start time may be 0, check if this collection has been listed to provide a better error message. if (saleConfig.seller == payable(0)) { revert NFTDropMarketFixedPriceSale_Must_Be_Listed_For_Sale(); } // Adding users to the allow list is unnecessary when general access is open. revert NFTDropMarketFixedPriceSale_General_Access_Is_Open(); } if (saleConfig.generalAvailabilityStartTime == saleConfig.earlyAccessStartTime) { // Must have non-zero early access duration, otherwise merkle roots are unnecessary. revert NFTDropMarketFixedPriceSale_Must_Have_Non_Zero_Early_Access_Duration(); } saleConfig.earlyAccessMerkleRoots[merkleRoot] = true; emit AddMerkleRootToFixedPriceSale(nftContract, merkleRoot, merkleTreeUri); } /** * @notice Create a fixed price sale drop without an early access period, optionally scheduling the sale to start * sometime in the future. * @param nftContract The address of the NFT drop collection. * @param price The price per NFT minted. * Set price to 0 for a first come first serve airdrop-like drop. * @param limitPerAccount The max number of NFTs an account may mint in this sale. * @param generalAvailabilityStartTime The time at which general purchases are available, in seconds since Unix epoch. * Set this to 0 in order to have general availability begin as soon as the transaction is mined. * Can not be more than two years from the creation block timestamp. * @param txDeadlineTime The deadline timestamp for the transaction to be mined, in seconds since Unix epoch. * Set this to 0 to send the transaction without a deadline. * @dev Notes: * a) The sale is final and can not be updated or canceled. * b) Any collection that abides by `INFTLazyMintedCollectionMintCountTo` and `IAccessControl` is supported. */ function createFixedPriceSale( address nftContract, uint256 price, uint256 limitPerAccount, uint256 generalAvailabilityStartTime, uint256 txDeadlineTime ) external txDeadlineNotExpired(txDeadlineTime) { // When generalAvailabilityStartTime is not specified, default to now. if (generalAvailabilityStartTime == 0) { generalAvailabilityStartTime = block.timestamp; } else if (generalAvailabilityStartTime.hasExpired()) { // The start time must be now or in the future. revert NFTDropMarketFixedPriceSale_General_Availability_Start_Time_Has_Expired(); } _createFixedPriceSale({ nftContract: nftContract, price: price, limitPerAccount: limitPerAccount, generalAvailabilityStartTime: generalAvailabilityStartTime, earlyAccessStartTime: generalAvailabilityStartTime, merkleRoot: bytes32(0), merkleTreeUri: "" }); } /** * @notice Create a fixed price sale drop with an early access period. * @param nftContract The address of the NFT drop collection. * @param price The price per NFT minted. * Set price to 0 for a first come first serve airdrop-like drop. * @param limitPerAccount The max number of NFTs an account may mint in this sale. * @param generalAvailabilityStartTime The time at which general purchases are available, in seconds since Unix epoch. * This value must be > `earlyAccessStartTime`. * @param earlyAccessStartTime The time at which early access purchases are available, in seconds since Unix epoch. * Set this to 0 in order to have early access begin as soon as the transaction is mined. * @param merkleRoot The merkleRoot used to authorize early access purchases. * @param merkleTreeUri The URI for the merkle tree represented by the merkleRoot. * @param txDeadlineTime The deadline timestamp for the transaction to be mined, in seconds since Unix epoch. * Set this to 0 to send the transaction without a deadline. * @dev Notes: * a) The sale is final and can not be updated or canceled. * b) Any collection that abides by `INFTLazyMintedCollectionMintCountTo` and `IAccessControl` is supported. */ function createFixedPriceSaleWithEarlyAccessAllowlist( address nftContract, uint256 price, uint256 limitPerAccount, uint256 generalAvailabilityStartTime, uint256 earlyAccessStartTime, bytes32 merkleRoot, string calldata merkleTreeUri, uint256 txDeadlineTime ) external txDeadlineNotExpired(txDeadlineTime) onlyValidMerkle(merkleRoot, merkleTreeUri) { // When earlyAccessStartTime is not specified, default to now. if (earlyAccessStartTime == 0) { earlyAccessStartTime = block.timestamp; } else if (earlyAccessStartTime.hasExpired()) { // The start time must be now or in the future. revert NFTDropMarketFixedPriceSale_Early_Access_Start_Time_Has_Expired(); } if (earlyAccessStartTime >= generalAvailabilityStartTime) { // Early access period must start before GA period. revert NFTDropMarketFixedPriceSale_Must_Have_Non_Zero_Early_Access_Duration(); } _createFixedPriceSale( nftContract, price, limitPerAccount, generalAvailabilityStartTime, earlyAccessStartTime, merkleRoot, merkleTreeUri ); } function _createFixedPriceSale( address nftContract, uint256 price, uint256 limitPerAccount, uint256 generalAvailabilityStartTime, uint256 earlyAccessStartTime, bytes32 merkleRoot, string memory merkleTreeUri ) private onlySupportedCollectionType(nftContract) notSoldOut(nftContract) onlyCollectionAdmin(nftContract) onlyValidScheduledTime(generalAvailabilityStartTime) notListed(nftContract) { // Validate input params. if (limitPerAccount == 0) { // A non-zero limit is required. revert NFTDropMarketFixedPriceSale_Limit_Per_Account_Must_Be_Set(); } // Confirm this collection has not already been listed. FixedPriceSaleConfig storage saleConfig = nftContractToFixedPriceSaleConfig[nftContract]; // Save the sale details. address payable sender = payable(_msgSender()); saleConfig.seller = sender; // Any price is supported, including 0. saleConfig.price = price.toUint80(); saleConfig.limitPerAccount = limitPerAccount.toUint16(); if (generalAvailabilityStartTime != block.timestamp) { // If starting now we don't need to write to storage // Safe cast is not required since onlyValidScheduledTime confirms the max is within range. saleConfig.generalAvailabilityStartTime = uint32(generalAvailabilityStartTime); } if (earlyAccessStartTime != block.timestamp) { // If starting now we don't need to write to storage // Safe cast is not required since callers require earlyAccessStartTime <= generalAvailabilityStartTime. saleConfig.earlyAccessStartTime = uint32(earlyAccessStartTime); } // Store the merkle root if there's an early access period if (merkleRoot != 0) { saleConfig.earlyAccessMerkleRoots[merkleRoot] = true; } emit CreateFixedPriceSale({ nftContract: nftContract, seller: sender, price: price, limitPerAccount: limitPerAccount, generalAvailabilityStartTime: generalAvailabilityStartTime, earlyAccessStartTime: earlyAccessStartTime, merkleRoot: merkleRoot, merkleTreeUri: merkleTreeUri }); } //////////////////////////////////////////////////////////////// // Mint from Sale //////////////////////////////////////////////////////////////// /** * @notice Used to mint `count` number of NFTs from the collection during general availability. * @param nftContract The address of the NFT drop collection. * @param count The number of NFTs to mint. * @param nftRecipient The address to transfer the NFT(s) to. * @param buyReferrer The address which referred this purchase, or address(0) if n/a. * @return firstTokenId The tokenId for the first NFT minted. * The other minted tokens are assigned sequentially, so `firstTokenId` - `firstTokenId + count - 1` were minted. * @dev This call may revert if the collection has sold out, has an insufficient number of tokens available, * or if the market's minter permissions were removed. * If insufficient msg.value is included, the sender's available FETH token balance will be used. */ function mintFromFixedPriceSaleV2( address nftContract, uint16 count, address nftRecipient, address payable buyReferrer ) external payable returns (uint256 firstTokenId) { firstTokenId = _mintFromFixedPriceSale({ nftContract: nftContract, count: count, nftRecipient: nftRecipient, buyReferrer: buyReferrer, includeMintFee: true }); } /// @notice [DEPRECATED] Use `mintFromFixedPriceSaleV2` instead. function mintFromFixedPriceSale( address nftContract, uint16 count, address payable buyReferrer ) external payable returns (uint256 firstTokenId) { firstTokenId = _mintFromFixedPriceSale({ nftContract: nftContract, count: count, nftRecipient: _msgSender(), buyReferrer: buyReferrer, includeMintFee: false }); } function _mintFromFixedPriceSale( address nftContract, uint16 count, address nftRecipient, address payable buyReferrer, bool includeMintFee ) private returns (uint256 firstTokenId) { FixedPriceSaleConfig storage saleConfig = nftContractToFixedPriceSaleConfig[nftContract]; // Must be in general access period. if (!saleConfig.generalAvailabilityStartTime.hasBeenReached()) { revert NFTDropMarketFixedPriceSale_General_Access_Not_Open(saleConfig.generalAvailabilityStartTime); } firstTokenId = _mintFromFixedPriceSale(saleConfig, nftContract, count, nftRecipient, buyReferrer, includeMintFee); } /** * @notice Used to mint `count` number of NFTs from the collection during early access. * @param nftContract The address of the NFT drop collection. * @param count The number of NFTs to mint. * @param nftRecipient The address to transfer the NFT(s) to. * @param buyReferrer The address which referred this purchase, or address(0) if n/a. * @param proof The merkle proof used to authorize this purchase. * @return firstTokenId The tokenId for the first NFT minted. * The other minted tokens are assigned sequentially, so `firstTokenId` - `firstTokenId + count - 1` were minted. * @dev This call may revert if the collection has sold out, has an insufficient number of tokens available, * or if the market's minter permissions were removed. * If insufficient msg.value is included, the sender's available FETH token balance will be used. */ function mintFromFixedPriceSaleWithEarlyAccessAllowlistV2( address nftContract, uint256 count, address nftRecipient, address payable buyReferrer, bytes32[] calldata proof ) external payable returns (uint256 firstTokenId) { firstTokenId = _mintFromFixedPriceSaleWithEarlyAccessAllowlist({ nftContract: nftContract, count: count, nftRecipient: nftRecipient, buyReferrer: buyReferrer, proof: proof, includeMintFee: true }); } /// @notice [DEPRECATED] Use `mintFromFixedPriceSaleWithEarlyAccessAllowlistV2` instead. function mintFromFixedPriceSaleWithEarlyAccessAllowlist( address nftContract, uint256 count, address payable buyReferrer, bytes32[] calldata proof ) external payable returns (uint256 firstTokenId) { firstTokenId = _mintFromFixedPriceSaleWithEarlyAccessAllowlist({ nftContract: nftContract, count: count, nftRecipient: _msgSender(), buyReferrer: buyReferrer, proof: proof, includeMintFee: false }); } function _mintFromFixedPriceSaleWithEarlyAccessAllowlist( address nftContract, uint256 count, address nftRecipient, address payable buyReferrer, bytes32[] calldata proof, bool includeMintFee ) private returns (uint256 firstTokenId) { FixedPriceSaleConfig storage saleConfig = nftContractToFixedPriceSaleConfig[nftContract]; // Skip proof check if in general access period. if (!saleConfig.generalAvailabilityStartTime.hasBeenReached()) { // Must be in early access period or beyond. if (!saleConfig.earlyAccessStartTime.hasBeenReached()) { if (saleConfig.earlyAccessStartTime == saleConfig.generalAvailabilityStartTime) { // This just provides a more targeted error message for the case where early access is not enabled. revert NFTDropMarketFixedPriceSale_Must_Have_Non_Zero_Early_Access_Duration(); } revert NFTDropMarketFixedPriceSale_Early_Access_Not_Open(saleConfig.earlyAccessStartTime); } bytes32 root = nftRecipient.getMerkleRootForAddress(proof); if (!saleConfig.earlyAccessMerkleRoots[root]) { // If the proof is invalid, this may be caused by an invalid nftRecipient address. // This check provides a more targeted error. if (nftRecipient == address(0)) { revert NFTDropMarketFixedPriceSale_Invalid_Nft_Recipient(); } revert NFTDropMarketFixedPriceSale_Invalid_Merkle_Proof(); } } firstTokenId = _mintFromFixedPriceSale(saleConfig, nftContract, count, nftRecipient, buyReferrer, includeMintFee); } function _mintFromFixedPriceSale( FixedPriceSaleConfig storage saleConfig, address nftContract, uint256 count, address nftRecipient, address payable buyReferrer, bool includeMintFee ) private returns (uint256 firstTokenId) { // Validate input params. if (count == 0) { revert NFTDropMarketFixedPriceSale_Must_Buy_At_Least_One_Token(); } if (nftRecipient == address(0)) { revert NFTDropMarketFixedPriceSale_Invalid_Nft_Recipient(); } // Confirm that the buyer will not exceed the limit specified after minting. { uint256 minted = saleConfig.userToMintedCount[nftRecipient] + count; if (minted > saleConfig.limitPerAccount) { if (saleConfig.limitPerAccount == 0) { // Provide a more targeted error if the collection has not been listed. revert NFTDropMarketFixedPriceSale_Must_Be_Listed_For_Sale(); } revert NFTDropMarketFixedPriceSale_Cannot_Buy_More_Than_Limit(saleConfig.limitPerAccount); } saleConfig.userToMintedCount[nftRecipient] = minted; } uint256 mintFee; address payable curator; uint16 takeRateInBasisPoints; // Calculate the total cost, considering the `count` requested. uint256 salePrice; { uint256 totalMintCost; unchecked { // Can not overflow as 2^80 * 2^16 == 2^96 max which fits in 256 bits. salePrice = uint256(saleConfig.price) * count; } if (includeMintFee) { unchecked { // Mint fee is a small fixed amount and the count is limited to uint16. mintFee = MINT_FEE_IN_WEI * count; } } unchecked { totalMintCost = salePrice + mintFee; } // Withdraw from the user's available FETH balance if insufficient msg.value was included. _tryUseFETHBalance({ totalAmount: totalMintCost, shouldRefundSurplus: false }); // Mint the NFTs. // Safe cast is not required, above confirms count <= limitPerAccount which is uint16. firstTokenId = INFTLazyMintedCollectionMintCountTo(nftContract).mintCountTo(uint16(count), nftRecipient); (, curator, takeRateInBasisPoints) = IWorldsDropMarket(worlds).soldInWorldByCollection( saleConfig.seller, nftContract, count, salePrice ); } // Distribute revenue from this sale. (uint256 totalFees, uint256 creatorRev, ) = _distributeFunds( DistributeFundsParams({ nftContract: nftContract, firstTokenId: firstTokenId, nftCount: count, nftRecipientIfKnown: nftRecipient, seller: saleConfig.seller, price: salePrice, buyReferrer: buyReferrer, sellerReferrerPaymentAddress: curator, sellerReferrerTakeRateInBasisPoints: takeRateInBasisPoints, fixedProtocolFeeInWei: mintFee }) ); emit MintFromFixedPriceDrop({ nftContract: nftContract, buyer: nftRecipient, firstTokenId: firstTokenId, count: count, totalFees: totalFees, creatorRev: creatorRev }); } //////////////////////////////////////////////////////////////// // Sale Info //////////////////////////////////////////////////////////////// /** * @notice Returns the max number of NFTs a given account may mint. * @param nftContract The address of the NFT drop collection. * @param user The address of the user which will be minting. * @return numberThatCanBeMinted How many NFTs the user can mint. */ function getAvailableCountFromFixedPriceSale( address nftContract, address user ) external view returns (uint256 numberThatCanBeMinted) { ( , , uint256 limitPerAccount, uint256 numberOfTokensAvailableToMint, bool marketCanMint, , , ) = getFixedPriceSaleV2(nftContract); if (!marketCanMint) { // No one can mint in the current state. return 0; } uint256 mintedCount = nftContractToFixedPriceSaleConfig[nftContract].userToMintedCount[user]; if (mintedCount >= limitPerAccount) { // User has exhausted their limit. return 0; } unchecked { // Safe math is not required due to the if statement directly above. numberThatCanBeMinted = limitPerAccount - mintedCount; } if (numberThatCanBeMinted > numberOfTokensAvailableToMint) { // User has more tokens available than the collection has available. numberThatCanBeMinted = numberOfTokensAvailableToMint; } } /** * @notice Returns details for a drop collection's fixed price sale. * @param nftContract The address of the NFT drop collection. * @return seller The address of the seller which listed this drop for sale. * This value will be address(0) if the collection is not listed or has sold out. * @return price The price per NFT minted. * @return limitPerAccount The max number of NFTs an account may mint in this sale. * @return numberOfTokensAvailableToMint The number of NFTs available to mint. * @return marketCanMint True if this contract has permissions to mint from the given collection. * @return generalAvailabilityStartTime The time at which general availability starts. * When set to 0, general availability was not scheduled and started as soon as the price was set. * @return earlyAccessStartTime The timestamp at which the allowlist period starts. * When set to 0, early access was not scheduled and started as soon as the price was set. */ function getFixedPriceSaleV2( address nftContract ) public view returns ( address payable seller, uint256 price, uint256 limitPerAccount, uint256 numberOfTokensAvailableToMint, bool marketCanMint, uint256 generalAvailabilityStartTime, uint256 earlyAccessStartTime, uint256 mintFeePerNftInWei ) { try INFTLazyMintedCollectionMintCountTo(nftContract).numberOfTokensAvailableToMint() returns (uint256 count) { if (count != 0) { try IAccessControl(nftContract).hasRole(MINTER_ROLE, address(this)) returns (bool hasRole) { FixedPriceSaleConfig storage saleConfig = nftContractToFixedPriceSaleConfig[nftContract]; seller = saleConfig.seller; price = saleConfig.price; limitPerAccount = saleConfig.limitPerAccount; numberOfTokensAvailableToMint = count; marketCanMint = hasRole; earlyAccessStartTime = saleConfig.earlyAccessStartTime; generalAvailabilityStartTime = saleConfig.generalAvailabilityStartTime; mintFeePerNftInWei = MINT_FEE_IN_WEI; } catch { // The contract is not supported - return default values. } } // Else minted completed -- return default values. } catch { // Contract not supported or self destructed - return default values } } /// @notice [DEPRECATED] Use `getFixedPriceSaleV2` instead. function getFixedPriceSale( address nftContract ) external view returns ( address payable seller, uint256 price, uint256 limitPerAccount, uint256 numberOfTokensAvailableToMint, bool marketCanMint, uint256 generalAvailabilityStartTime, uint256 earlyAccessStartTime ) { ( seller, price, limitPerAccount, numberOfTokensAvailableToMint, marketCanMint, generalAvailabilityStartTime, earlyAccessStartTime, ) = getFixedPriceSaleV2(nftContract); } /** * @notice Checks if a given merkle root has been authorized to purchase from a given drop collection. * @param nftContract The address of the NFT drop collection. * @param merkleRoot The merkle root to check. * @return supported True if the merkle root has been authorized. */ function getFixedPriceSaleEarlyAccessAllowlistSupported( address nftContract, bytes32 merkleRoot ) external view returns (bool supported) { supported = nftContractToFixedPriceSaleConfig[nftContract].earlyAccessMerkleRoots[merkleRoot]; } /** * @inheritdoc NFTDropMarketCore * @dev Returns the seller for a collection if listed and not already sold out. */ function _getSellerOfCollection(address nftContract) internal view virtual override returns (address payable seller) { seller = nftContractToFixedPriceSaleConfig[nftContract].seller; if (seller == address(0)) { seller = super._getSellerOfCollection(nftContract); } } /** * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[1_000] private __gap; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; /// Constant values shared across mixins. /** * @dev 100% in basis points. */ uint256 constant BASIS_POINTS = 10_000; /** * @dev The default admin role defined by OZ ACL modules. */ bytes32 constant DEFAULT_ADMIN_ROLE = 0x00; //////////////////////////////////////////////////////////////// // Royalties & Take Rates //////////////////////////////////////////////////////////////// /** * @dev The max take rate a World can have. */ uint256 constant MAX_WORLD_TAKE_RATE = 5_000; /** * @dev Cap the number of royalty recipients. * A cap is required to ensure gas costs are not too high when a sale is settled. */ uint256 constant MAX_ROYALTY_RECIPIENTS = 5; /** * @dev Default royalty cut paid out on secondary sales. * Set to 10% of the secondary sale. */ uint96 constant ROYALTY_IN_BASIS_POINTS = 1_000; /** * @dev Reward paid to referrers when a sale is made. * Set to 20% of the protocol fee. */ uint96 constant BUY_REFERRER_IN_BASIS_POINTS = 2000; /** * @dev 10%, expressed as a denominator for more efficient calculations. */ uint256 constant ROYALTY_RATIO = BASIS_POINTS / ROYALTY_IN_BASIS_POINTS; /** * @dev 20%, expressed as a denominator for more efficient calculations. */ uint256 constant BUY_REFERRER_RATIO = BASIS_POINTS / BUY_REFERRER_IN_BASIS_POINTS; //////////////////////////////////////////////////////////////// // Gas Limits //////////////////////////////////////////////////////////////// /** * @dev The gas limit used when making external read-only calls. * This helps to ensure that external calls does not prevent the market from executing. */ uint256 constant READ_ONLY_GAS_LIMIT = 40_000; /** * @dev The gas limit to send ETH to multiple recipients, enough for a 5-way split. */ uint256 constant SEND_VALUE_GAS_LIMIT_MULTIPLE_RECIPIENTS = 210_000; /** * @dev The gas limit to send ETH to a single recipient, enough for a contract with a simple receiver. */ uint256 constant SEND_VALUE_GAS_LIMIT_SINGLE_RECIPIENT = 20_000; //////////////////////////////////////////////////////////////// // Collection Type Names //////////////////////////////////////////////////////////////// /** * @dev The NFT collection type. */ string constant NFT_COLLECTION_TYPE = "NFT Collection"; /** * @dev The NFT drop collection type. */ string constant NFT_DROP_COLLECTION_TYPE = "NFT Drop Collection"; /** * @dev The NFT timed edition collection type. */ string constant NFT_TIMED_EDITION_COLLECTION_TYPE = "NFT Timed Edition Collection"; /** * @dev The NFT limited edition collection type. */ string constant NFT_LIMITED_EDITION_COLLECTION_TYPE = "NFT Limited Edition Collection"; //////////////////////////////////////////////////////////////// // Business Logic //////////////////////////////////////////////////////////////// /** * @dev Limits scheduled start/end times to be less than 2 years in the future. */ uint256 constant MAX_SCHEDULED_TIME_IN_THE_FUTURE = 365 days * 2; /** * @dev The minimum increase of 10% required when making an offer or placing a bid. */ uint256 constant MIN_PERCENT_INCREMENT_DENOMINATOR = BASIS_POINTS / 1_000; /// @dev The fixed fee charged for each NFT minted. uint256 constant MINT_FEE_IN_WEI = 0.0008 ether;
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import "../../interfaces/internal/IFethMarket.sol"; error FETHNode_FETH_Address_Is_Not_A_Contract(); error FETHNode_Only_FETH_Can_Transfer_ETH(); /** * @title A mixin for interacting with the FETH contract. * @author batu-inal & HardlyDifficult */ abstract contract FETHNode is ContextUpgradeable { using AddressUpgradeable for address; using AddressUpgradeable for address payable; /// @notice The FETH ERC-20 token for managing escrow and lockup. IFethMarket internal immutable feth; error FethNode_Too_Much_Value_Provided(uint256 expectedValueAmount); constructor(address _feth) { if (!_feth.isContract()) { revert FETHNode_FETH_Address_Is_Not_A_Contract(); } feth = IFethMarket(_feth); } /** * @notice Only used by FETH. Any direct transfer from users will revert. */ receive() external payable { if (msg.sender != address(feth)) { revert FETHNode_Only_FETH_Can_Transfer_ETH(); } } /** * @notice Withdraw the msg.sender's available FETH balance if they requested more than the msg.value provided. * @dev This may revert if the msg.sender is non-receivable. * This helper should not be used anywhere that may lead to locked assets. * @param totalAmount The total amount of ETH required (including the msg.value). * @param shouldRefundSurplus If true, refund msg.value - totalAmount to the msg.sender. Otherwise it will revert if * the msg.value is greater than totalAmount. */ function _tryUseFETHBalance(uint256 totalAmount, bool shouldRefundSurplus) internal { if (totalAmount > msg.value) { // Withdraw additional ETH required from the user's available FETH balance. unchecked { // The if above ensures delta will not underflow. // Withdraw ETH from the user's account in the FETH token contract, // making the funds available in this contract as ETH. feth.marketWithdrawFrom(_msgSender(), totalAmount - msg.value); } } else if (totalAmount < msg.value) { if (shouldRefundSurplus) { // Return any surplus ETH to the user. unchecked { // The if above ensures this will not underflow payable(_msgSender()).sendValue(msg.value - totalAmount); } } else { revert FethNode_Too_Much_Value_Provided(totalAmount); } } } /** * @notice Gets the FETH contract used to escrow offer funds. * @return fethAddress The FETH contract address. */ function getFethAddress() external view returns (address fethAddress) { fethAddress = address(feth); } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import "../../interfaces/internal/roles/IAdminRole.sol"; import "../../interfaces/internal/roles/IOperatorRole.sol"; error FoundationTreasuryNode_Address_Is_Not_A_Contract(); error FoundationTreasuryNode_Caller_Not_Admin(); error FoundationTreasuryNode_Caller_Not_Operator(); /** * @title Stores a reference to Foundation's treasury contract for other mixins to leverage. * @notice The treasury collects fees and defines admin/operator roles. * @author batu-inal & HardlyDifficult */ abstract contract FoundationTreasuryNodeV1 is Initializable { using AddressUpgradeable for address payable; /// @dev This value was replaced with an immutable version. address payable private __gap_was_treasury; /// @notice The address of the treasury contract. address payable private immutable treasury; /// @notice Requires the caller is a Foundation admin. modifier onlyFoundationAdmin() { if (!IAdminRole(treasury).isAdmin(msg.sender)) { revert FoundationTreasuryNode_Caller_Not_Admin(); } _; } /// @notice Requires the caller is a Foundation operator. modifier onlyFoundationOperator() { if (!IOperatorRole(treasury).isOperator(msg.sender)) { revert FoundationTreasuryNode_Caller_Not_Operator(); } _; } /** * @notice Set immutable variables for the implementation contract. * @dev Assigns the treasury contract address. */ constructor(address payable _treasury) { if (!_treasury.isContract()) { revert FoundationTreasuryNode_Address_Is_Not_A_Contract(); } treasury = _treasury; } /** * @notice Gets the Foundation treasury contract. * @dev This call is used in the royalty registry contract. * @return treasuryAddress The address of the Foundation treasury contract. */ function getFoundationTreasury() public view returns (address payable treasuryAddress) { treasuryAddress = treasury; } /** * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps * @dev This mixin uses a total of 2,001 slots. */ uint256[2_000] private __gap; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; /** * @title A placeholder contract leaving room for new mixins to be added to the future. * @author HardlyDifficult */ abstract contract Gap1000 { /** * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[1_000] private __gap; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; /** * @title A placeholder contract leaving room for new mixins to be added to the future. * @author HardlyDifficult */ abstract contract Gap8500 { /** * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[8_500] private __gap; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; import { ContextUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; import { AddressUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import { IMarketUtils } from "../../interfaces/internal/IMarketUtils.sol"; import "./Constants.sol"; import "./MarketStructs.sol"; import { FoundationTreasuryNodeV1 } from "./FoundationTreasuryNodeV1.sol"; import { MarketSharedCore } from "./MarketSharedCore.sol"; import { SendValueWithFallbackWithdraw } from "./SendValueWithFallbackWithdraw.sol"; error NFTMarketFees_Market_Utils_Is_Not_A_Contract(); error NFTMarketFees_Invalid_Protocol_Fee(); /** * @title A mixin to distribute funds when an NFT is sold. * @author batu-inal & HardlyDifficult */ abstract contract MarketFees is FoundationTreasuryNodeV1, ContextUpgradeable, MarketSharedCore, SendValueWithFallbackWithdraw { using AddressUpgradeable for address; using AddressUpgradeable for address payable; struct DistributeFundsParams { address nftContract; uint256 firstTokenId; uint256 nftCount; address nftRecipientIfKnown; address payable seller; uint256 price; address payable buyReferrer; address payable sellerReferrerPaymentAddress; uint16 sellerReferrerTakeRateInBasisPoints; uint256 fixedProtocolFeeInWei; } /** * @dev Removing old unused variables in an upgrade safe way. Was: * uint256 private _primaryFoundationFeeBasisPoints; * uint256 private _secondaryFoundationFeeBasisPoints; * uint256 private _secondaryCreatorFeeBasisPoints; * mapping(address => mapping(uint256 => bool)) private _nftContractToTokenIdToFirstSaleCompleted; */ uint256[4] private __gap_was_fees; /// @notice True for the Drop market which only performs primary sales. False if primary & secondary are supported. bool private immutable assumePrimarySale; /// @notice The fee collected by Foundation for sales facilitated by this market contract. uint256 private immutable defaultProtocolFeeInBasisPoints; /// @notice Reference to our MarketUtils contract. IMarketUtils private immutable marketUtils; /** * @notice Emitted when an NFT sold with a referrer. * @param nftContract The address of the NFT contract. * @param tokenId The id of the NFT. * @param buyReferrer The account which received the buy referral incentive. * @param buyReferrerFee The portion of the protocol fee collected by the buy referrer. * @param buyReferrerSellerFee The portion of the owner revenue collected by the buy referrer (not implemented). */ event BuyReferralPaid( address indexed nftContract, uint256 indexed tokenId, address buyReferrer, uint256 buyReferrerFee, uint256 buyReferrerSellerFee ); /** * @notice Emitted when an NFT is sold when associated with a sell referrer. * @param nftContract The address of the NFT contract. * @param tokenId The id of the NFT. * @param sellerReferrer The account which received the sell referral incentive. * @param sellerReferrerFee The portion of the seller revenue collected by the sell referrer. */ event SellerReferralPaid( address indexed nftContract, uint256 indexed tokenId, address sellerReferrer, uint256 sellerReferrerFee ); /** * @notice Emitted when a fixed protocol fee is paid as part of an NFT purchase. * @param nftContract The address of the NFT contract. * @param firstTokenId The id of the NFT, or the first/lowest id if it applies to multiple NFTs. * @param nftRecipient The account which acquired an NFT from this transaction (may not be the same as the msg.sender) * @param fixedProtocolFeeInWei The total fee collected by the protocol for this sale in wei. * @param nftCount The number of NFTs in this sale. * @dev Some of this amount may have been shared with a referrer, which would be emitted in via the BuyReferrerPaid * event. */ event FixedProtocolFeePaid( address indexed nftContract, uint256 indexed firstTokenId, address indexed nftRecipient, uint256 fixedProtocolFeeInWei, uint256 nftCount ); /** * @notice Sets the immutable variables for this contract. * @param _defaultProtocolFeeInBasisPoints The default protocol fee to use for this market. * @param marketUtilsAddress The address to use for our MarketUtils contract. * @param _assumePrimarySale True for the Drop market which only performs primary sales. * False if primary & secondary are supported. */ constructor(uint16 _defaultProtocolFeeInBasisPoints, address marketUtilsAddress, bool _assumePrimarySale) { if (_defaultProtocolFeeInBasisPoints + BASIS_POINTS / ROYALTY_RATIO >= BASIS_POINTS - MAX_WORLD_TAKE_RATE) { // The protocol fee must leave room for the creator royalties and the max World take rate. // If the protocol fee is invalid, revert. revert NFTMarketFees_Invalid_Protocol_Fee(); } if (!marketUtilsAddress.isContract()) { revert NFTMarketFees_Market_Utils_Is_Not_A_Contract(); } assumePrimarySale = _assumePrimarySale; defaultProtocolFeeInBasisPoints = _defaultProtocolFeeInBasisPoints; marketUtils = IMarketUtils(marketUtilsAddress); } /** * @notice Distributes funds to foundation, creator recipients, and NFT owner after a sale. * @return totalFees The total fees collected by the protocol and referrals, excluding any fixed fee charged. * @dev `virtual` allows other mixins to be notified anytime a sale occurs. */ function _distributeFunds( DistributeFundsParams memory params ) internal virtual returns (uint256 totalFees, uint256 creatorRev, uint256 sellerRev) { address payable[] memory creatorRecipients; uint256[] memory creatorShares; uint256 buyReferrerFee; uint256 sellerReferrerFee; (totalFees, creatorRecipients, creatorShares, sellerRev, buyReferrerFee, sellerReferrerFee) = getFees( params.nftContract, params.firstTokenId, params.seller, params.price, params.buyReferrer, params.sellerReferrerTakeRateInBasisPoints ); // The `getFees` breakdown doesn't yet account for the fixed protocol fee, so we add that in separately. if (params.fixedProtocolFeeInWei != 0) { totalFees += params.fixedProtocolFeeInWei; // The buy referrer is rewarded a portion of this fixed fee as well. if (params.buyReferrer != address(0)) { buyReferrerFee += params.fixedProtocolFeeInWei / BUY_REFERRER_RATIO; totalFees -= buyReferrerFee; } emit FixedProtocolFeePaid( params.nftContract, params.firstTokenId, params.nftRecipientIfKnown, params.fixedProtocolFeeInWei, params.nftCount ); } // Pay the creator(s) { // If just a single recipient was defined, use a larger gas limit in order to support in-contract split logic. uint256 creatorGasLimit = creatorRecipients.length == 1 ? SEND_VALUE_GAS_LIMIT_MULTIPLE_RECIPIENTS : SEND_VALUE_GAS_LIMIT_SINGLE_RECIPIENT; unchecked { for (uint256 i = 0; i < creatorRecipients.length; ++i) { _sendValueWithFallbackWithdraw(creatorRecipients[i], creatorShares[i], creatorGasLimit); // Sum the total creator rev from shares // creatorShares is in ETH so creatorRev will not overflow here. creatorRev += creatorShares[i]; } } } // Pay the seller _sendValueWithFallbackWithdraw(params.seller, sellerRev, SEND_VALUE_GAS_LIMIT_SINGLE_RECIPIENT); // Pay the protocol fee if (totalFees != 0) { getFoundationTreasury().sendValue(totalFees); } // Pay the buy referrer fee if (buyReferrerFee != 0) { _sendValueWithFallbackWithdraw(params.buyReferrer, buyReferrerFee, SEND_VALUE_GAS_LIMIT_SINGLE_RECIPIENT); emit BuyReferralPaid({ nftContract: params.nftContract, tokenId: params.firstTokenId, buyReferrer: params.buyReferrer, buyReferrerFee: buyReferrerFee, buyReferrerSellerFee: 0 }); unchecked { // Add the referrer fee back into the total fees so that all 3 return fields sum to the total sale price. totalFees += buyReferrerFee; } } // Remove the fixed fee from the `totalFees` being returned so that all 3 return fields sum to the total sale price. if (params.fixedProtocolFeeInWei != 0) { unchecked { totalFees -= params.fixedProtocolFeeInWei; } } if (params.sellerReferrerPaymentAddress != address(0)) { if (sellerReferrerFee != 0) { // Add the seller referrer fee back to revenue so that all 3 return fields sum to the total sale price. unchecked { if (sellerRev == 0) { // When sellerRev is 0, this is a primary sale and all revenue is attributed to the "creator". creatorRev += sellerReferrerFee; } else { sellerRev += sellerReferrerFee; } } _sendValueWithFallbackWithdraw( params.sellerReferrerPaymentAddress, sellerReferrerFee, SEND_VALUE_GAS_LIMIT_SINGLE_RECIPIENT ); } emit SellerReferralPaid( params.nftContract, params.firstTokenId, params.sellerReferrerPaymentAddress, sellerReferrerFee ); } } /// @dev Assumes the caller ensures that fixedProtocolFeeInWei > 0. function _distributeFixedProtocolFee( address nftContract, uint256 firstTokenId, uint256 nftCount, address buyer, uint256 fixedProtocolFeeInWei ) internal { getFoundationTreasury().sendValue(fixedProtocolFeeInWei); emit FixedProtocolFeePaid(nftContract, firstTokenId, buyer, fixedProtocolFeeInWei, nftCount); } /** * @notice Calculates how funds should be distributed for the given sale details. * @dev When the NFT is being sold by the `tokenCreator`, all the seller revenue will * be split with the royalty recipients defined for that NFT. */ function getFees( address nftContract, uint256 tokenId, address payable seller, uint256 price, address payable buyReferrer, uint16 sellerReferrerTakeRateInBasisPoints ) public view returns ( uint256 protocolFeeAmount, address payable[] memory creatorRecipients, uint256[] memory creatorShares, uint256 sellerRev, uint256 buyReferrerFee, uint256 sellerReferrerFee ) { MarketTransactionOptions memory options = MarketTransactionOptions({ // Market info marketTakeRateInBasisPoints: defaultProtocolFeeInBasisPoints, assumePrimarySale: assumePrimarySale, // Sale info nftContract: nftContract, tokenId: tokenId, price: price, seller: seller, // Referrals buyReferrer: buyReferrer, sellerReferrerTakeRateInBasisPoints: sellerReferrerTakeRateInBasisPoints, // Transaction info sender: _msgSender() }); (protocolFeeAmount, creatorRecipients, creatorShares, sellerRev, buyReferrerFee, sellerReferrerFee) = marketUtils .getTransactionBreakdown(options); } /** * @notice Returns how funds will be distributed for a sale at the given price point. * @param nftContract The address of the NFT contract. * @param tokenId The id of the NFT. * @param price The sale price to calculate the fees for. * @return totalFees How much will be sent to the Foundation treasury and/or referrals. * @return creatorRev How much will be sent across all the `creatorRecipients` defined. * @return creatorRecipients The addresses of the recipients to receive a portion of the creator fee. * @return creatorShares The percentage of the creator fee to be distributed to each `creatorRecipient`. * If there is only one `creatorRecipient`, this may be an empty array. * Otherwise `creatorShares.length` == `creatorRecipients.length`. * @return sellerRev How much will be sent to the owner/seller of the NFT. * If the NFT is being sold by the creator, this may be 0 and the full revenue will appear as `creatorRev`. * @return seller The address of the owner of the NFT. * If `sellerRev` is 0, this may be `address(0)`. * @dev Currently in use by the FNDMiddleware `getFees` call (now deprecated). */ function getFeesAndRecipients( address nftContract, uint256 tokenId, uint256 price ) external view returns ( uint256 totalFees, uint256 creatorRev, address payable[] memory creatorRecipients, uint256[] memory creatorShares, uint256 sellerRev, address payable seller ) { seller = _getSellerOrOwnerOf(nftContract, tokenId); (totalFees, creatorRecipients, creatorShares, sellerRev, , ) = getFees({ nftContract: nftContract, tokenId: tokenId, seller: seller, price: price, // Notice: Setting this value is a breaking change for the FNDMiddleware contract. // Will be wired in an upcoming release to communicate the buy referral information. buyReferrer: payable(0), sellerReferrerTakeRateInBasisPoints: 0 }); // Sum the total creator rev from shares unchecked { for (uint256 i = 0; i < creatorShares.length; ++i) { creatorRev += creatorShares[i]; } } } /** * @notice returns the address of the MarketUtils contract. */ function getMarketUtilsAddress() external view returns (address marketUtilsAddress) { marketUtilsAddress = address(marketUtils); } /** * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps * @dev This mixins uses 504 slots in total. */ uint256[500] private __gap; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; import "./FETHNode.sol"; /** * @title A place for common modifiers and functions used by various market mixins, if any. * @dev This also leaves a gap which can be used to add a new mixin to the top of the inheritance tree. * @author batu-inal & HardlyDifficult */ abstract contract MarketSharedCore is FETHNode { /** * @notice Checks who the seller for an NFT is if listed in this market. * @param nftContract The address of the NFT contract. * @param tokenId The id of the NFT. * @return seller The seller which listed this NFT for sale, or address(0) if not listed. */ function getSellerOf(address nftContract, uint256 tokenId) external view returns (address payable seller) { seller = _getSellerOf(nftContract, tokenId); } /** * @notice Checks who the seller for an NFT is if listed in this market. */ function _getSellerOf(address nftContract, uint256 tokenId) internal view virtual returns (address payable seller) { // Returns address(0) by default. } /** * @notice Checks who the seller for an NFT is if listed in this market or returns the current owner. */ function _getSellerOrOwnerOf( address nftContract, uint256 tokenId ) internal view virtual returns (address payable sellerOrOwner); /** * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[450] private __gap; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; /// @notice Details about a marketplace sale. struct MarketTransactionOptions { //////////////////////////////////////////////////////////////// // Market config //////////////////////////////////////////////////////////////// /// @notice Percentage of the transaction to go the the market, expressed in basis points. uint256 marketTakeRateInBasisPoints; /// @notice set to true when the token is being sold by it's creator bool assumePrimarySale; //////////////////////////////////////////////////////////////// // Sale info //////////////////////////////////////////////////////////////// /// @notice The contract address of the nft address nftContract; /// @notice The token id of the nft. uint256 tokenId; /// @notice price at which the token is being sold uint256 price; /// @notice address of the account that is selling the token address payable seller; //////////////////////////////////////////////////////////////// // Referrals //////////////////////////////////////////////////////////////// /// @notice Address of the account that referred the buyer. address payable buyReferrer; /// @notice Percentage of the transaction to go the the account which referred the seller, expressed in basis points. uint16 sellerReferrerTakeRateInBasisPoints; //////////////////////////////////////////////////////////////// // Transaction info //////////////////////////////////////////////////////////////// /// @notice The msg.sender which executed the purchase transaction. address sender; } /// @notice The auction configuration for a specific NFT. struct ReserveAuction { /// @notice The address of the NFT contract. address nftContract; /// @notice The id of the NFT. uint256 tokenId; /// @notice The owner of the NFT which listed it in auction. address payable seller; /// @notice The duration for this auction. uint256 duration; /// @notice The extension window for this auction. uint256 extensionDuration; /// @notice The time at which this auction will not accept any new bids. /// @dev This is `0` until the first bid is placed. uint256 endTime; /// @notice The current highest bidder in this auction. /// @dev This is `address(0)` until the first bid is placed. address payable bidder; /// @notice The latest price of the NFT in this auction. /// @dev This is set to the reserve price, and then to the highest bid once the auction has started. uint256 amount; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import "../../libraries/RouteCallLibrary.sol"; error RouterContextSingle_Address_Is_Not_A_Contract(); /** * @title Enables a trusted contract to override the usual msg.sender address. * @author HardlyDifficult */ abstract contract RouterContextSingle is ContextUpgradeable { using AddressUpgradeable for address; address private immutable approvedRouter; constructor(address router) { if (!router.isContract()) { revert RouterContextSingle_Address_Is_Not_A_Contract(); } approvedRouter = router; } /** * @notice Returns the contract which is able to override the msg.sender address. * @return router The address of the trusted router. */ function getApprovedRouterAddress() external view returns (address router) { router = approvedRouter; } /** * @notice Gets the sender of the transaction to use, overriding the usual msg.sender if the caller is a trusted * router. * @dev If the msg.sender is a trusted router contract, then the last 20 bytes of the calldata represents the * authorized sender to use. * If this is used for a call that was not routed with `routeCallTo`, the address returned will be incorrect (and * may be address(0)). */ function _msgSender() internal view virtual override returns (address sender) { sender = super._msgSender(); if (sender == approvedRouter) { sender = RouteCallLibrary.extractAppendedSenderAddress(); } } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import "./FETHNode.sol"; import "./FoundationTreasuryNodeV1.sol"; /** * @title A mixin for sending ETH with a fallback withdraw mechanism. * @notice Attempt to send ETH and if the transfer fails or runs out of gas, store the balance * in the FETH token contract for future withdrawal instead. * @dev This mixin was recently switched to escrow funds in FETH. * Once we have confirmed all pending balances have been withdrawn, we can remove the escrow tracking here. * @author batu-inal & HardlyDifficult */ abstract contract SendValueWithFallbackWithdraw is FoundationTreasuryNodeV1, FETHNode { using AddressUpgradeable for address payable; /// @dev Removing old unused variables in an upgrade safe way. uint256 private __gap_was_pendingWithdrawals; /** * @notice Emitted when escrowed funds are withdrawn to FETH. * @param user The account which has withdrawn ETH. * @param amount The amount of ETH which has been withdrawn. */ event WithdrawalToFETH(address indexed user, uint256 amount); /** * @notice Attempt to send a user or contract ETH. * If it fails store the amount owned for later withdrawal in FETH. * @dev This may fail when sending ETH to a contract that is non-receivable or exceeds the gas limit specified. */ function _sendValueWithFallbackWithdraw(address payable user, uint256 amount, uint256 gasLimit) internal { if (amount == 0) { return; } if (user == address(feth)) { // FETH may revert on ETH transfers and will reject `depositFor` calls to itself, so redirect funds to the // treasury contract instead. user = getFoundationTreasury(); } // Cap the gas to prevent consuming all available gas to block a tx from completing successfully // solhint-disable-next-line avoid-low-level-calls (bool success, ) = user.call{ value: amount, gas: gasLimit }(""); if (!success) { // Store the funds that failed to send for the user in the FETH token feth.depositFor{ value: amount }(user); emit WithdrawalToFETH(user, amount); } } /** * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[999] private __gap; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; import "../../libraries/TimeLibrary.sol"; error TxDeadline_Tx_Deadline_Expired(); /** * @title A mixin that provides a modifier to check that a transaction deadline has not expired. * @author HardlyDifficult */ abstract contract TxDeadline { using TimeLibrary for uint256; /// @notice Requires the deadline provided is 0, now, or in the future. modifier txDeadlineNotExpired(uint256 txDeadlineTime) { // No transaction deadline when set to 0. if (txDeadlineTime != 0 && txDeadlineTime.hasExpired()) { revert TxDeadline_Tx_Deadline_Expired(); } _; } // This mixin does not use any storage. }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.18; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; error WorldsNftNode_Worlds_NFT_Is_Not_A_Contract(); /** * @title Stores a reference to the Worlds NFT contract for contracts to leverage. * @author HardlyDifficult */ abstract contract WorldsNftNode { using AddressUpgradeable for address; address internal immutable worlds; constructor(address worldsNft) { if (!worldsNft.isContract()) { revert WorldsNftNode_Worlds_NFT_Is_Not_A_Contract(); } worlds = worldsNft; } /** * @notice Returns the address of the Worlds NFT contract. */ function getWorldsNftAddress() external view returns (address worldsNft) { worldsNft = worlds; } // This mixin uses 0 slots. }
{ "evmVersion": "shanghai", "optimizer": { "enabled": true, "runs": 1337000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address payable","name":"treasury","type":"address"},{"internalType":"address","name":"feth","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"marketUtils","type":"address"},{"internalType":"address","name":"worldsNft","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FETHNode_FETH_Address_Is_Not_A_Contract","type":"error"},{"inputs":[],"name":"FETHNode_Only_FETH_Can_Transfer_ETH","type":"error"},{"inputs":[{"internalType":"uint256","name":"expectedValueAmount","type":"uint256"}],"name":"FethNode_Too_Much_Value_Provided","type":"error"},{"inputs":[],"name":"FoundationTreasuryNode_Address_Is_Not_A_Contract","type":"error"},{"inputs":[],"name":"NFTDropMarketCore_Collection_Already_Listed_For_Sale","type":"error"},{"inputs":[],"name":"NFTDropMarketCore_Invalid_Merkle_Root","type":"error"},{"inputs":[],"name":"NFTDropMarketCore_Invalid_Merkle_Tree_URI","type":"error"},{"inputs":[],"name":"NFTDropMarketCore_Mint_Permission_Required","type":"error"},{"inputs":[],"name":"NFTDropMarketCore_Must_Have_Available_Supply","type":"error"},{"inputs":[],"name":"NFTDropMarketCore_Must_Support_Collection_Mint_Interface","type":"error"},{"inputs":[],"name":"NFTDropMarketCore_Must_Support_ERC721","type":"error"},{"inputs":[],"name":"NFTDropMarketCore_Only_Callable_By_Collection_Owner","type":"error"},{"inputs":[{"internalType":"uint256","name":"maxTime","type":"uint256"}],"name":"NFTDropMarketCore_Time_Too_Far_In_The_Future","type":"error"},{"inputs":[{"internalType":"uint256","name":"startTime","type":"uint256"}],"name":"NFTDropMarketDutchAuction_Auction_Has_Not_Started_Yet","type":"error"},{"inputs":[],"name":"NFTDropMarketDutchAuction_Auction_Not_Found","type":"error"},{"inputs":[{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"numberStillAvailable","type":"uint256"}],"name":"NFTDropMarketDutchAuction_Clearing_Price_Not_Reached","type":"error"},{"inputs":[],"name":"NFTDropMarketDutchAuction_Creator_Revenue_Has_Already_Been_Withdrawn","type":"error"},{"inputs":[{"internalType":"uint256","name":"maxTime","type":"uint256"}],"name":"NFTDropMarketDutchAuction_End_Time_Too_Far_In_The_Future","type":"error"},{"inputs":[],"name":"NFTDropMarketDutchAuction_Invalid_Nft_Recipient","type":"error"},{"inputs":[],"name":"NFTDropMarketDutchAuction_Limit_Per_Account_Must_Be_Set","type":"error"},{"inputs":[],"name":"NFTDropMarketDutchAuction_Min_Price_Must_Be_Less_Than_Max_Price","type":"error"},{"inputs":[],"name":"NFTDropMarketDutchAuction_Mint_Count_Must_Be_Greater_Than_Zero","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentMintCount","type":"uint256"},{"internalType":"uint256","name":"limitPerAccount","type":"uint256"}],"name":"NFTDropMarketDutchAuction_Mint_Exceeds_Limit_Per_Account","type":"error"},{"inputs":[],"name":"NFTDropMarketDutchAuction_Must_Have_Available_Supply","type":"error"},{"inputs":[],"name":"NFTDropMarketDutchAuction_Nothing_To_Rebate_At_This_Time","type":"error"},{"inputs":[],"name":"NFTDropMarketDutchAuction_Sale_Duration_Must_Be_Greater_Than_Zero","type":"error"},{"inputs":[],"name":"NFTDropMarketDutchAuction_Start_Time_Must_Not_Be_In_The_Past","type":"error"},{"inputs":[{"internalType":"uint256","name":"limitPerAccount","type":"uint256"}],"name":"NFTDropMarketFixedPriceSale_Cannot_Buy_More_Than_Limit","type":"error"},{"inputs":[{"internalType":"uint256","name":"earlyAccessStartTime","type":"uint256"}],"name":"NFTDropMarketFixedPriceSale_Early_Access_Not_Open","type":"error"},{"inputs":[],"name":"NFTDropMarketFixedPriceSale_Early_Access_Start_Time_Has_Expired","type":"error"},{"inputs":[],"name":"NFTDropMarketFixedPriceSale_General_Access_Is_Open","type":"error"},{"inputs":[{"internalType":"uint256","name":"generalAvailabilityStartTime","type":"uint256"}],"name":"NFTDropMarketFixedPriceSale_General_Access_Not_Open","type":"error"},{"inputs":[],"name":"NFTDropMarketFixedPriceSale_General_Availability_Start_Time_Has_Expired","type":"error"},{"inputs":[],"name":"NFTDropMarketFixedPriceSale_Invalid_Merkle_Proof","type":"error"},{"inputs":[],"name":"NFTDropMarketFixedPriceSale_Invalid_Nft_Recipient","type":"error"},{"inputs":[],"name":"NFTDropMarketFixedPriceSale_Limit_Per_Account_Must_Be_Set","type":"error"},{"inputs":[],"name":"NFTDropMarketFixedPriceSale_Must_Be_Listed_For_Sale","type":"error"},{"inputs":[],"name":"NFTDropMarketFixedPriceSale_Must_Buy_At_Least_One_Token","type":"error"},{"inputs":[],"name":"NFTDropMarketFixedPriceSale_Must_Have_Non_Zero_Early_Access_Duration","type":"error"},{"inputs":[],"name":"NFTDropMarket_NFT_Already_Minted","type":"error"},{"inputs":[],"name":"NFTMarketFees_Invalid_Protocol_Fee","type":"error"},{"inputs":[],"name":"NFTMarketFees_Market_Utils_Is_Not_A_Contract","type":"error"},{"inputs":[],"name":"RouterContextSingle_Address_Is_Not_A_Contract","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[],"name":"TxDeadline_Tx_Deadline_Expired","type":"error"},{"inputs":[],"name":"WorldsNftNode_Worlds_NFT_Is_Not_A_Contract","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nftContract","type":"address"},{"indexed":false,"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"indexed":false,"internalType":"string","name":"merkleTreeUri","type":"string"}],"name":"AddMerkleRootToFixedPriceSale","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nftContract","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"buyReferrer","type":"address"},{"indexed":false,"internalType":"uint256","name":"buyReferrerFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"buyReferrerSellerFee","type":"uint256"}],"name":"BuyReferralPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nftContract","type":"address"},{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"limitPerAccount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"generalAvailabilityStartTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"earlyAccessStartTime","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"indexed":false,"internalType":"string","name":"merkleTreeUri","type":"string"}],"name":"CreateFixedPriceSale","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nftContract","type":"address"},{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":false,"internalType":"uint256","name":"maxPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"limitPerAccount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"}],"name":"CreateLinearDutchAuction","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nftContract","type":"address"},{"indexed":true,"internalType":"uint256","name":"firstTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"nftRecipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"fixedProtocolFeeInWei","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nftCount","type":"uint256"}],"name":"FixedProtocolFeePaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nftContract","type":"address"},{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"pricePaidPerNft","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"count","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"firstTokenId","type":"uint256"}],"name":"MintFromDutchAuction","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nftContract","type":"address"},{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"pricePaidPerNft","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"count","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"firstTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalFees","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"creatorRev","type":"uint256"}],"name":"MintFromDutchAuctionV2","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nftContract","type":"address"},{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":true,"internalType":"uint256","name":"firstTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"count","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalFees","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"creatorRev","type":"uint256"}],"name":"MintFromFixedPriceDrop","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nftContract","type":"address"},{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"rebate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"currentPricePerNft","type":"uint256"}],"name":"RebateBuyerFromDutchAuction","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nftContract","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"sellerReferrer","type":"address"},{"indexed":false,"internalType":"uint256","name":"sellerReferrerFee","type":"uint256"}],"name":"SellerReferralPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nftContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"clearingPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalMintedCount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalFees","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"creatorRev","type":"uint256"}],"name":"WithdrawCreatorRevenueFromDutchAuction","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawalToFETH","type":"event"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"internalType":"string","name":"merkleTreeUri","type":"string"}],"name":"addMerkleRootToFixedPriceSale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"limitPerAccount","type":"uint256"},{"internalType":"uint256","name":"generalAvailabilityStartTime","type":"uint256"},{"internalType":"uint256","name":"txDeadlineTime","type":"uint256"}],"name":"createFixedPriceSale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"limitPerAccount","type":"uint256"},{"internalType":"uint256","name":"generalAvailabilityStartTime","type":"uint256"},{"internalType":"uint256","name":"earlyAccessStartTime","type":"uint256"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"internalType":"string","name":"merkleTreeUri","type":"string"},{"internalType":"uint256","name":"txDeadlineTime","type":"uint256"}],"name":"createFixedPriceSaleWithEarlyAccessAllowlist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"maxPrice","type":"uint256"},{"internalType":"uint256","name":"minPrice","type":"uint256"},{"internalType":"uint256","name":"limitPerAccount","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"saleDuration","type":"uint256"}],"name":"createLinearDutchAuctionV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getApprovedRouterAddress","outputs":[{"internalType":"address","name":"router","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"address","name":"user","type":"address"}],"name":"getAvailableCountFromFixedPriceSale","outputs":[{"internalType":"uint256","name":"numberThatCanBeMinted","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"address","name":"buyer","type":"address"}],"name":"getBuyerInfoFromDutchAuction","outputs":[{"internalType":"uint256","name":"outstandingRebateBalance","type":"uint256"},{"internalType":"uint256","name":"numberThatCanBeMinted","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"}],"name":"getDutchAuction","outputs":[{"internalType":"uint256","name":"maxPrice","type":"uint256"},{"internalType":"uint256","name":"minPrice","type":"uint256"},{"internalType":"uint256","name":"limitPerAccount","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"totalAvailableSupply","type":"uint256"},{"internalType":"uint256","name":"totalMintedCount","type":"uint256"},{"internalType":"uint256","name":"lastSalePrice","type":"uint256"},{"internalType":"uint256","name":"currentPrice","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"}],"name":"getDutchAuctionV2","outputs":[{"internalType":"uint256","name":"maxPrice","type":"uint256"},{"internalType":"uint256","name":"minPrice","type":"uint256"},{"internalType":"uint256","name":"limitPerAccount","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"totalAvailableSupply","type":"uint256"},{"internalType":"uint256","name":"totalMintedCount","type":"uint256"},{"internalType":"uint256","name":"lastSalePrice","type":"uint256"},{"internalType":"uint256","name":"currentPrice","type":"uint256"},{"internalType":"uint256","name":"mintFeePerNftInWei","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address payable","name":"seller","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"address payable","name":"buyReferrer","type":"address"},{"internalType":"uint16","name":"sellerReferrerTakeRateInBasisPoints","type":"uint16"}],"name":"getFees","outputs":[{"internalType":"uint256","name":"protocolFeeAmount","type":"uint256"},{"internalType":"address payable[]","name":"creatorRecipients","type":"address[]"},{"internalType":"uint256[]","name":"creatorShares","type":"uint256[]"},{"internalType":"uint256","name":"sellerRev","type":"uint256"},{"internalType":"uint256","name":"buyReferrerFee","type":"uint256"},{"internalType":"uint256","name":"sellerReferrerFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"name":"getFeesAndRecipients","outputs":[{"internalType":"uint256","name":"totalFees","type":"uint256"},{"internalType":"uint256","name":"creatorRev","type":"uint256"},{"internalType":"address payable[]","name":"creatorRecipients","type":"address[]"},{"internalType":"uint256[]","name":"creatorShares","type":"uint256[]"},{"internalType":"uint256","name":"sellerRev","type":"uint256"},{"internalType":"address payable","name":"seller","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFethAddress","outputs":[{"internalType":"address","name":"fethAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"}],"name":"getFixedPriceSale","outputs":[{"internalType":"address payable","name":"seller","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"limitPerAccount","type":"uint256"},{"internalType":"uint256","name":"numberOfTokensAvailableToMint","type":"uint256"},{"internalType":"bool","name":"marketCanMint","type":"bool"},{"internalType":"uint256","name":"generalAvailabilityStartTime","type":"uint256"},{"internalType":"uint256","name":"earlyAccessStartTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"name":"getFixedPriceSaleEarlyAccessAllowlistSupported","outputs":[{"internalType":"bool","name":"supported","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"}],"name":"getFixedPriceSaleV2","outputs":[{"internalType":"address payable","name":"seller","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"limitPerAccount","type":"uint256"},{"internalType":"uint256","name":"numberOfTokensAvailableToMint","type":"uint256"},{"internalType":"bool","name":"marketCanMint","type":"bool"},{"internalType":"uint256","name":"generalAvailabilityStartTime","type":"uint256"},{"internalType":"uint256","name":"earlyAccessStartTime","type":"uint256"},{"internalType":"uint256","name":"mintFeePerNftInWei","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFoundationTreasury","outputs":[{"internalType":"address payable","name":"treasuryAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMarketUtilsAddress","outputs":[{"internalType":"address","name":"marketUtilsAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"time","type":"uint256"}],"name":"getPriceAtTimeForDutchAuction","outputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"}],"name":"getSellerInfoFromDutchAuction","outputs":[{"internalType":"address","name":"seller","type":"address"},{"internalType":"bool","name":"creatorRevenueReadyForWithdrawal","type":"bool"},{"internalType":"bool","name":"creatorRevenueHasBeenWithdrawn","type":"bool"},{"internalType":"uint256","name":"totalFundsPendingDistribution","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getSellerOf","outputs":[{"internalType":"address payable","name":"seller","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWorldsNftAddress","outputs":[{"internalType":"address","name":"worldsNft","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"mintFromDutchAuction","outputs":[{"internalType":"uint256","name":"firstTokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"count","type":"uint256"},{"internalType":"address","name":"nftRecipient","type":"address"}],"name":"mintFromDutchAuctionV2","outputs":[{"internalType":"uint256","name":"firstTokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint16","name":"count","type":"uint16"},{"internalType":"address payable","name":"buyReferrer","type":"address"}],"name":"mintFromFixedPriceSale","outputs":[{"internalType":"uint256","name":"firstTokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint16","name":"count","type":"uint16"},{"internalType":"address","name":"nftRecipient","type":"address"},{"internalType":"address payable","name":"buyReferrer","type":"address"}],"name":"mintFromFixedPriceSaleV2","outputs":[{"internalType":"uint256","name":"firstTokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"count","type":"uint256"},{"internalType":"address payable","name":"buyReferrer","type":"address"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"mintFromFixedPriceSaleWithEarlyAccessAllowlist","outputs":[{"internalType":"uint256","name":"firstTokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"count","type":"uint256"},{"internalType":"address","name":"nftRecipient","type":"address"},{"internalType":"address payable","name":"buyReferrer","type":"address"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"mintFromFixedPriceSaleWithEarlyAccessAllowlistV2","outputs":[{"internalType":"uint256","name":"firstTokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"address payable","name":"buyer","type":"address"}],"name":"rebateBuyerFromDutchAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"}],"name":"withdrawCreatorRevenueFromDutchAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
61016060405234801562000011575f80fd5b5060405162005a3238038062005a3283398101604081905262000034916200028c565b5f8260018684878a6001600160a01b0381163b620000655760405163028bba2560e61b815260040160405180910390fd5b6001600160a01b0390811660805281163b62000094576040516376ee64e560e11b815260040160405180910390fd5b6001600160a01b0390811660a05281163b620000c357604051631341312360e01b815260040160405180910390fd5b6001600160a01b0390811660c05281163b620000f25760405163de58082760e01b815260040160405180910390fd5b6001600160a01b031660e0526200010e6113886127106200031c565b6200011e6103e861271062000338565b6200012c9061271062000338565b6200013c9061ffff861662000358565b106200015b57604051630567777b60e41b815260040160405180910390fd5b6001600160a01b0382163b620001845760405163140d37eb60e21b815260040160405180910390fd5b15156101005261ffff909116610120526001600160a01b031661014052620001ab620001b6565b50505050506200036e565b5f54610100900460ff1615620002225760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff9081161462000272575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6001600160a01b038116811462000289575f80fd5b50565b5f805f805f60a08688031215620002a1575f80fd5b8551620002ae8162000274565b6020870151909550620002c18162000274565b6040870151909450620002d48162000274565b6060870151909350620002e78162000274565b6080870151909250620002fa8162000274565b809150509295509295909350565b634e487b7160e01b5f52601160045260245ffd5b8181038181111562000332576200033262000308565b92915050565b5f826200035357634e487b7160e01b5f52601260045260245ffd5b500490565b8082018082111562000332576200033262000308565b60805160a05160c05160e0516101005161012051610140516156256200040d5f395f81816103430152611ab001525f6119d501525f6119fb01525f81816101f001528181610541015281816134130152818161353401526141cb01525f818161039601528181613ab50152613fd701525f8181610457015261442201525f818161080b0152818161346601528181614301015261473501526156255ff3fe6080604052600436106101d3575f3560e01c806387a4fdcb116100fd578063dccdafa511610092578063f59488d911610062578063f59488d9146107bf578063f5ec797e146107de578063f7a2da23146107fd578063fb70943f1461082f575f80fd5b8063dccdafa5146106c9578063e965a20214610736578063ecbc955414610749578063f169dda31461075c575f80fd5b8063af4f5ac2116100cd578063af4f5ac2146105ff578063bfb92b421461061e578063d539139314610683578063d782d491146106b6575f80fd5b806387a4fdcb14610502578063895633ba14610533578063aa09f69814610565578063af1e1de3146105ce575f80fd5b80632af2064f1161017357806362c465521161014357806362c465521461042a5780636a90a8271461044957806379ecb0b21461047b5780638129fc1c146104ee575f80fd5b80632af2064f146103ba578063334965c2146103d95780634dad54a1146103ec5780634fca06c61461040b575f80fd5b806316da9864116101ae57806316da9864146102ee5780631722c7e71461030157806321dbd9aa14610335578063228b131814610388575f80fd5b806306ca634b1461024d5780630853764a146102ae5780630cafb113146102cd575f80fd5b36610249573373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610247576040517faa39384e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b005b5f80fd5b348015610258575f80fd5b5061026c610267366004614ac6565b61084e565b6040805173ffffffffffffffffffffffffffffffffffffffff909516855292151560208501529015159183019190915260608201526080015b60405180910390f35b3480156102b9575f80fd5b506102476102c8366004614ae1565b61096a565b6102e06102db366004614b69565b610a2b565b6040519081526020016102a5565b6102e06102fc366004614be9565b610a47565b34801561030c575f80fd5b5061032061031b366004614c28565b610a5d565b604080519283526020830191909152016102a5565b348015610340575f80fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102a5565b348015610393575f80fd5b507f0000000000000000000000000000000000000000000000000000000000000000610363565b3480156103c5575f80fd5b506102476103d4366004614c28565b610b72565b6102e06103e7366004614c6e565b610ce5565b3480156103f7575f80fd5b506102e0610406366004614cc7565b610cfd565b348015610416575f80fd5b50610363610425366004614cc7565b610ded565b348015610435575f80fd5b50610247610444366004614cf1565b610dff565b348015610454575f80fd5b507f0000000000000000000000000000000000000000000000000000000000000000610363565b348015610486575f80fd5b5061049a610495366004614ac6565b611617565b6040805173ffffffffffffffffffffffffffffffffffffffff909916895260208901979097529587019490945260608601929092521515608085015260a084015260c083015260e0820152610100016102a5565b3480156104f9575f80fd5b50610247611833565b34801561050d575f80fd5b5061052161051c366004614d39565b6119bf565b6040516102a596959493929190614e24565b34801561053e575f80fd5b507f0000000000000000000000000000000000000000000000000000000000000000610363565b348015610570575f80fd5b5061058461057f366004614ac6565b611b8e565b604080519a8b5260208b0199909952978901969096526060880194909452608087019290925260a086015260c085015260e0840152610100830152610120820152610140016102a5565b3480156105d9575f80fd5b506105ed6105e8366004614e6d565b611c7a565b6040516102a596959493929190614e9f565b34801561060a575f80fd5b506102e0610619366004614c28565b611ce9565b348015610629575f80fd5b50610673610638366004614cc7565b73ffffffffffffffffffffffffffffffffffffffff9091165f908152613cc36020908152604080832093835260039093019052205460ff1690565b60405190151581526020016102a5565b34801561068e575f80fd5b506102e07f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b6102e06106c4366004614eff565b611d77565b3480156106d4575f80fd5b506106e86106e3366004614ac6565b611d98565b6040805173ffffffffffffffffffffffffffffffffffffffff909816885260208801969096529486019390935260608501919091521515608084015260a083015260c082015260e0016102a5565b6102e0610744366004614cc7565b611dc0565b6102e0610757366004614f6d565b611dd4565b348015610767575f80fd5b5061077b610776366004614ac6565b611de9565b60408051998a5260208a0198909852968801959095526060870193909352608086019190915260a085015260c084015260e0830152610100820152610120016102a5565b3480156107ca575f80fd5b506102476107d9366004614fe8565b611ec9565b3480156107e9575f80fd5b506102476107f8366004615070565b612063565b348015610808575f80fd5b507f0000000000000000000000000000000000000000000000000000000000000000610363565b34801561083a575f80fd5b50610247610849366004614ac6565b612405565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526140ac602052604081208054829182918291907c0100000000000000000000000000000000000000000000000000000000900463ffffffff1615610962576002810154600182015473ffffffffffffffffffffffffffffffffffffffff9091169550760100000000000000000000000000000000000000000000900460ff1692508261096257600181015463ffffffff6601000000000000820481166201000090920416101580610940575080547c0100000000000000000000000000000000000000000000000000000000900463ffffffff1642115b600182015490945062010000900463ffffffff1661095e8742610cfd565b0291505b509193509193565b80801580159061097e575061097e81421190565b156109b5576040517fbcb9700400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825f036109c457429250610a04565b6109cd83421190565b15610a04576040517fa619834a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a2386868686875f801b60405180602001604052805f81525061266c565b505050505050565b5f610a3c8787878787876001612d05565b979650505050505050565b5f610a558484846001612ec3565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff8281165f9081526140ac6020908152604080832093851683526003840182528083208151808301909252546bffffffffffffffffffffffff811682526c01000000000000000000000000900461ffff169181018290529192839290918390610ada8842610cfd565b835191029150610af99082906bffffffffffffffffffffffff166150f5565b6001840154602084015191965061ffff9081169116811115610b67576020830151600185015461ffff9091168203955063ffffffff660100000000000082048116916201000090041680821115610b6057808203915081871115610b5b578196505b610b64565b5f96505b50505b505050509250929050565b73ffffffffffffffffffffffffffffffffffffffff8083165f9081526140ac602090815260408083209385168352600390930190529081208054909161ffff6c01000000000000000000000000830416916bffffffffffffffffffffffff1690610bdc8642610cfd565b90508281025f610bec82856150f5565b9050805f03610c27576040517f433b2e9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b85547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff8316178655610c6b878262033450613405565b8673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167fd9f7a958c85633cf171f617fa7127c9f19bacb103e2bce41bb6728d0476515808386604051610cd3929190918252602082015260400190565b60405180910390a35050505050505050565b5f610cf48585858560016135e5565b95945050505050565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526140ac60205260408120600181015463ffffffff660100000000000082048116620100009092041610610d6d5760018101546a010000000000000000000090046bffffffffffffffffffffffff169150610de6565b8054610de3906bffffffffffffffffffffffff808216916c0100000000000000000000000081049091169063ffffffff780100000000000000000000000000000000000000000000000082048116917c01000000000000000000000000000000000000000000000000000000009004168761366e565b91505b5092915050565b5f610df883836136c4565b9392505050565b85610e4073ffffffffffffffffffffffffffffffffffffffff82167f5bf6f7b8000000000000000000000000000000000000000000000000000000006136cf565b610e76576040517f17fdef0700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610eb673ffffffffffffffffffffffffffffffffffffffff82167f80ac58cd000000000000000000000000000000000000000000000000000000006136e6565b610eec576040517f29d190d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f91d148540000000000000000000000000000000000000000000000000000000081527f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6600482015230602482015273ffffffffffffffffffffffffffffffffffffffff8216906391d1485490604401602060405180830381865afa158015610f7a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f9e9190615108565b610fd4576040517f436d641100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff81166391d148545f610ffa6137af565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925273ffffffffffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa158015611067573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061108b9190615108565b6110c1576040517f5fad784000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b875f6110cc826137bd565b73ffffffffffffffffffffffffffffffffffffffff1614611119576040517f2540293000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b868811611152576040517f5a42b07900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855f0361118b576040517f92865bfe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845f0361119a574294506111da565b6111a385421190565b156111da576040517f3a3baeca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835f03611213576040517f3335f9a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61121e8587615127565b90506303c26700420181111561126d576040517f82fae596000000000000000000000000000000000000000000000000000000008152426303c267000160048201526024015b60405180910390fd5b5f8a73ffffffffffffffffffffffffffffffffffffffff16638ae3e5f16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112b7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112db919061513a565b9050805f03611316576040517f61b9c86b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61131f6137af565b73ffffffffffffffffffffffffffffffffffffffff8d165f9081526140ac602052604090209091506113508c6137c7565b815477ffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff878116919091027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff16919091177801000000000000000000000000000000000000000000000000918c1691909102177fffffffffffffffff000000000000000000000000000000000000000000000000166c010000000000000000000000006bffffffffffffffffffffffff8e8116919091027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000169190911791161781556114568a61381c565b61145f84613863565b6002830180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff868116919091179091556001840180547fffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff000016660100000000000063ffffffff94909416939093027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169290921761ffff939093169290921790556040517f24ef95e700000000000000000000000000000000000000000000000000000000815260048101869052908e16906324ef95e7906024015f604051808303815f87803b158015611567575f80fd5b505af1158015611579573d5f803e3d5ffd5b505050508173ffffffffffffffffffffffffffffffffffffffff168d73ffffffffffffffffffffffffffffffffffffffff167f4be408b58dfcdd9eed5e094c36b581760de5ad0b07dc4fc948b61fba5001898e8e8e8e8e8a604051611600959493929190948552602085019390935260408401919091526060830152608082015260a00190565b60405180910390a350505050505050505050505050565b5f805f805f805f808873ffffffffffffffffffffffffffffffffffffffff16638ae3e5f16040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156116a4575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526116a19181019061513a565b60015b15611828578015611826576040517f91d148540000000000000000000000000000000000000000000000000000000081527f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6600482015230602482015273ffffffffffffffffffffffffffffffffffffffff8b16906391d1485490604401602060405180830381865afa925050508015611779575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261177691810190615108565b60015b156118265773ffffffffffffffffffffffffffffffffffffffff8b81165f908152613cc36020526040902080546002909101549181169b5074010000000000000000000000000000000000000000810469ffffffffffffffffffff169a507e01000000000000000000000000000000000000000000000000000000000000900461ffff169850919650945063ffffffff80821694506401000000009091041691506602d79883d200009050845b505b919395975091939597565b5f54610100900460ff161580801561185157505f54600160ff909116105b8061186a5750303b15801561186a57505f5460ff166001145b6118f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401611264565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015611952575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b61195a6138ac565b80156119bc575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b5f6060805f805f806040518061012001604052807f000000000000000000000000000000000000000000000000000000000000000081526020017f0000000000000000000000000000000000000000000000000000000000000000151581526020018e73ffffffffffffffffffffffffffffffffffffffff1681526020018d81526020018b81526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018961ffff168152602001611a936137af565b73ffffffffffffffffffffffffffffffffffffffff1681525090507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16630e13eac1826040518263ffffffff1660e01b8152600401611b079190615151565b5f60405180830381865afa158015611b21573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611b669190810190615333565b809750819850829950839a50849b50859c505050505050505096509650965096509650969050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526140ac60205260408120805460018201546bffffffffffffffffffffffff808316946c01000000000000000000000000840482169461ffff84169463ffffffff780100000000000000000000000000000000000000000000000082048116957c010000000000000000000000000000000000000000000000000000000090920481169466010000000000008304821694620100008404909216936a010000000000000000000090930416918190611c608c42610cfd565b92506602d79883d200009150509193959799509193959799565b5f806060805f80611c8b898961394c565b9050611c9b8989838a5f806119bf565b50939950919650945092505f90505b8351811015611cdc57838181518110611cc557611cc5615415565b602002602001015186019550806001019050611caa565b5093975093979195509350565b5f805f80611cf686611617565b505050945094509450505080611d11575f9350505050611d71565b73ffffffffffffffffffffffffffffffffffffffff8087165f908152613cc3602090815260408083209389168352600190930190522054838110611d5b575f945050505050611d71565b808403945082851115611d6c578294505b505050505b92915050565b5f611d8e8686611d856137af565b8787875f612d05565b9695505050505050565b5f805f805f805f611da888611617565b50959e949d50929b5090995097509550909350915050565b5f610df88383611dce6137af565b5f612ec3565b5f610a558484611de26137af565b855f6135e5565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526140ac60205260408120805460018201546bffffffffffffffffffffffff808316946c01000000000000000000000000840482169461ffff84169463ffffffff780100000000000000000000000000000000000000000000000082048116957c010000000000000000000000000000000000000000000000000000000090920481169466010000000000008304821694620100008404909216936a01000000000000000000009093041691611eb98b42610cfd565b9150509193959799909294969850565b808015801590611edd5750611edd81421190565b15611f14576040517fbcb9700400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84848482611f4e576040517f229955da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f819003611f88576040517fe85bdf0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b885f03611f9757429850611fd7565b611fa089421190565b15611fd7576040517fdddbb7cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b898910612010576040517f77b2af4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6120548d8d8d8d8d8d8d8d8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061266c92505050565b50505050505050505050505050565b838073ffffffffffffffffffffffffffffffffffffffff16638ae3e5f16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120ad573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120d1919061513a565b5f03612109576040517f3c263ade00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8473ffffffffffffffffffffffffffffffffffffffff81166391d148545f61212f6137af565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925273ffffffffffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa15801561219c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121c09190615108565b6121f6576040517f5fad784000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84848482612230576040517f229955da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81900361226a576040517fe85bdf0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff89165f908152613cc360205260409020600281015463ffffffff16421061232057805473ffffffffffffffffffffffffffffffffffffffff166122ee576040517f974bcaec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ff2279aef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600281015463ffffffff6401000000008204811691160361236d576040517f77b2af4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8981526003820160205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555173ffffffffffffffffffffffffffffffffffffffff8b16907f7f11be7894109a714225fbb6c33d88a14582407d653ac3fc5abf07d9b3ce8914906123f1908c908c908c90615442565b60405180910390a250505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8082165f9081526140ac6020526040902060028101549091168061246a576040517fcc4f974c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001820154760100000000000000000000000000000000000000000000900460ff16156124c3576040517fba5a58b200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600182015482546201000090910463ffffffff908116917c0100000000000000000000000000000000000000000000000000000000900416421115801561251d575060018301546601000000000000900463ffffffff1681105b1561259957825460018401546040517f1dd4212a0000000000000000000000000000000000000000000000000000000081527c010000000000000000000000000000000000000000000000000000000090920463ffffffff90811660048401526601000000000000909104168290036024820152604401611264565b5f6125a48542610cfd565b6001850180547fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff1676010000000000000000000000000000000000000000000017905590508181025f806125fd888685848a8180613a52565b604080518781526020810189905290810183905260608101829052919350915073ffffffffffffffffffffffffffffffffffffffff8916907f5e16e96b4ba4fe46f3be73d54d1fa0da481494ab74c2d6e33328366d6437693c9060800160405180910390a25050505050505050565b866126ad73ffffffffffffffffffffffffffffffffffffffff82167f5bf6f7b8000000000000000000000000000000000000000000000000000000006136cf565b6126e3576040517f17fdef0700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61272373ffffffffffffffffffffffffffffffffffffffff82167f80ac58cd000000000000000000000000000000000000000000000000000000006136e6565b612759576040517f29d190d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f91d148540000000000000000000000000000000000000000000000000000000081527f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6600482015230602482015273ffffffffffffffffffffffffffffffffffffffff8216906391d1485490604401602060405180830381865afa1580156127e7573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061280b9190615108565b612841576040517f436d641100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b878073ffffffffffffffffffffffffffffffffffffffff16638ae3e5f16040518163ffffffff1660e01b8152600401602060405180830381865afa15801561288b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128af919061513a565b5f036128e7576040517f3c263ade00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8873ffffffffffffffffffffffffffffffffffffffff81166391d148545f61290d6137af565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925273ffffffffffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa15801561297a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061299e9190615108565b6129d4576040517f5fad784000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b866303c267004201811115612a1d576040517fe43fc8b2000000000000000000000000000000000000000000000000000000008152426303c26700016004820152602401611264565b8a5f612a28826137bd565b73ffffffffffffffffffffffffffffffffffffffff1614612a75576040517f2540293000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b895f03612aae576040517f250099ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8c165f908152613cc36020526040812090612adc6137af565b82547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff82161783559050612b258d613bf7565b825469ffffffffffffffffffff9190911674010000000000000000000000000000000000000000027fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff909116178255612b7d8c61381c565b825461ffff919091167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909116178255428b14612c06576002820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff8d161790555b428a14612c47576002820180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff1664010000000063ffffffff8d16021790555b8815612c86575f898152600383016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b8073ffffffffffffffffffffffffffffffffffffffff168e73ffffffffffffffffffffffffffffffffffffffff167fa4e684574cd21d7eb4df36ec6d7f86d16aa900ceddae41e4e82f8f4170f293b98f8f8f8f8f8f604051612ced96959493929190615495565b60405180910390a35050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff87165f908152613cc360205260408120600281015463ffffffff16421015612ea8576002810154640100000000900463ffffffff16421015612deb57600281015463ffffffff8082166401000000009092041603612da4576040517f77b2af4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60028101546040517f8ba20e6800000000000000000000000000000000000000000000000000000000815264010000000090910463ffffffff166004820152602401611264565b5f612e0d73ffffffffffffffffffffffffffffffffffffffff89168787613c46565b5f81815260038401602052604090205490915060ff16612ea65773ffffffffffffffffffffffffffffffffffffffff8816612e74576040517f1126144d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ff88937c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b612eb6818a8a8a8a88613cbf565b9998505050505050505050565b5f835f03612efd576040517fb3896a5100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8316612f4a576040517fae36b52500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff85165f9081526140ac60205260408120805490917c010000000000000000000000000000000000000000000000000000000090910463ffffffff169003612fd2576040517fcc4f974c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80547801000000000000000000000000000000000000000000000000900463ffffffff164210156130555780546040517f70fdd722000000000000000000000000000000000000000000000000000000008152780100000000000000000000000000000000000000000000000090910463ffffffff166004820152602401611264565b73ffffffffffffffffffffffffffffffffffffffff84165f9081526003820160205260408120805490919061309e906c01000000000000000000000000900461ffff1688615127565b600184015490915061ffff1681111561310857815460018401546040517fb3c84a0b0000000000000000000000000000000000000000000000000000000081526c0100000000000000000000000090920461ffff9081166004840152166024820152604401611264565b5f6131138942610cfd565b600185015490915088820290760100000000000000000000000000000000000000000000900460ff165f80808a61314a575f61315b565b61315b8d6602d79883d20000615523565b90505f6131688287615127565b60018b01549091506131869062010000900463ffffffff168f615127565b60018b01805463ffffffff90921662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffff6bffffffffffffffffffffffff808c166a010000000000000000000002919091167fffffffffffffffffffff000000000000000000000000ffffffff00000000ffff90941693909317179055895461321d9161321891899116615127565b6137c7565b89547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166c0100000000000000000000000061ffff8b16027fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016176bffffffffffffffffffffffff919091161789556132978160016141c1565b506040517fd115124900000000000000000000000000000000000000000000000000000000815261ffff8e16600482015273ffffffffffffffffffffffffffffffffffffffff8d811660248301528f169063d1151249906044016020604051808303815f875af115801561330d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613331919061513a565b995083156133755761336b8e8e878f8d6002015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff168f87613a52565b9093509150613388565b8a15613388576133888e8b8f8f856142fb565b5060408051868152602081018e90529081018a9052606081018390526080810182905273ffffffffffffffffffffffffffffffffffffffff808d1691908f16907ffacca8c0845db767bcbcc63c5f7e7e93df5690aea049d11be2fffafd4185d8ec9060a00160405180910390a35050505050505050949350505050565b815f0361341157505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603613488577f000000000000000000000000000000000000000000000000000000000000000092505b5f8373ffffffffffffffffffffffffffffffffffffffff168383906040515f60405180830381858888f193505050503d805f81146134e1576040519150601f19603f3d011682016040523d82523d5f602084013e6134e6565b606091505b50509050806135df576040517faa67c91900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063aa67c9199085906024015f604051808303818588803b158015613577575f80fd5b505af1158015613589573d5f803e3d5ffd5b50505050508373ffffffffffffffffffffffffffffffffffffffff167fa2201512569adb2d513531dfd69b66df50bd5cffb8c1bbe65a4611f9e1eadbd1846040516135d691815260200190565b60405180910390a25b50505050565b73ffffffffffffffffffffffffffffffffffffffff85165f908152613cc360205260408120600281015463ffffffff1642101561365c5760028101546040517f26763e5a00000000000000000000000000000000000000000000000000000000815263ffffffff9091166004820152602401611264565b610a3c81888861ffff16888888613cbf565b5f83821161367d575084610cf4565b82821061368b575083610cf4565b61369585876150f5565b90508183036136a48183615523565b915084840382816136b7576136b761553a565b049150610a3c8683615127565b5f610df8838361439d565b5f6136d9836143a7565b8015610df85750610df883835b604080517fffffffff000000000000000000000000000000000000000000000000000000008316602480830191909152825180830390910181526044909101909152602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a70000000000000000000000000000000000000000000000000000000017815282515f9392849283928392918391908a617530fa92503d91505f51905082801561379c575060208210155b8015610a3c575015159695505050505050565b5f6137b861440a565b905090565b5f611d7182614476565b5f6bffffffffffffffffffffffff821115613818576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526060600482015260248101839052604401611264565b5090565b5f61ffff821115613818576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526010600482015260248101839052604401611264565b5f63ffffffff821115613818576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526020600482015260248101839052604401611264565b5f54610100900460ff16613942576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401611264565b61394a6144b4565b565b6040517f6352211e000000000000000000000000000000000000000000000000000000008152600481018290525f9073ffffffffffffffffffffffffffffffffffffffff841690636352211e90602401602060405180830381865afa9250505080156139f3575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526139f091810190615567565b60015b15613a485773ffffffffffffffffffffffffffffffffffffffff811615613a46576040517f5ca60e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b610df8838361439d565b6040517fcec32ca500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152888116602483015260448201889052606482018790525f918291829182917f0000000000000000000000000000000000000000000000000000000000000000169063cec32ca5906084016060604051808303815f875af1158015613afb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b1f9190615582565b9250925050613be46040518061014001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018881526020018c81526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018973ffffffffffffffffffffffffffffffffffffffff1681526020018b81526020015f73ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018361ffff16815260200187815250614552565b50909c909b509950505050505050505050565b5f69ffffffffffffffffffff821115613818576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526050600482015260248101839052604401611264565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606085901b1660208201525f908190603401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101209050610cf48484836148aa565b5f845f03613cf9576040517f2d69aaf400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8416613d46576040517f1126144d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff84165f908152600188016020526040812054613d78908790615127565b88549091507e01000000000000000000000000000000000000000000000000000000000000900461ffff16811115613e665787547e01000000000000000000000000000000000000000000000000000000000000900461ffff165f03613e0a576040517f974bcaec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b87546040517ffa7c028e0000000000000000000000000000000000000000000000000000000081527e0100000000000000000000000000000000000000000000000000000000000090910461ffff166004820152602401611264565b73ffffffffffffffffffffffffffffffffffffffff85165f90815260018901602052604081209190915587548190819074010000000000000000000000000000000000000000900469ffffffffffffffffffff168802818615613ed057896602d79883d200000294505b50808401613ede815f6141c1565b6040517fd115124900000000000000000000000000000000000000000000000000000000815261ffff8b16600482015273ffffffffffffffffffffffffffffffffffffffff8a811660248301528c169063d1151249906044016020604051808303815f875af1158015613f53573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613f77919061513a565b8c546040517fcec32ca500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201528d82166024820152604481018d9052606481018590529197507f0000000000000000000000000000000000000000000000000000000000000000169063cec32ca5906084016060604051808303815f875af115801561401d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906140419190615582565b9091508094508195505050505f806141316040518061014001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018d81526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018f5f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018581526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018661ffff16815260200188815250614552565b5091509150868a73ffffffffffffffffffffffffffffffffffffffff168d73ffffffffffffffffffffffffffffffffffffffff167f05ebbb6b0ce7d564230ba625dd7a0e5108786b0852d6060de6099e1778203e348e86866040516141a9939291909283526020830191909152604082015260600190565b60405180910390a45050505050509695505050505050565b3482111561428a577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663452f2b8f61420d6137af565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015234850360248201526044015f604051808303815f87803b158015614278575f80fd5b505af1158015610a23573d5f803e3d5ffd5b348210156142c25780156142c6576142c28234036142a66137af565b73ffffffffffffffffffffffffffffffffffffffff16906148eb565b5050565b6040517fabf2f33b00000000000000000000000000000000000000000000000000000000815260048101839052602401611264565b614325817f00000000000000000000000000000000000000000000000000000000000000006142a6565b8173ffffffffffffffffffffffffffffffffffffffff16848673ffffffffffffffffffffffffffffffffffffffff167f128e6430bdac5e0f43d2f25064b707cadc6dbb27cf69958b934944df4b23c423848760405161438e929190918252602082015260400190565b60405180910390a45050505050565b5f610df8836137bd565b5f6143d2827f01ffc9a7000000000000000000000000000000000000000000000000000000006136e6565b8015611d715750614403827fffffffff000000000000000000000000000000000000000000000000000000006136e6565b1592915050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016810361447357507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec36013560601c90565b90565b73ffffffffffffffffffffffffffffffffffffffff8082165f9081526140ac602052604090206002015416806144af57611d7182614a46565b919050565b5f54610100900460ff1661454a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401611264565b6001610dad55565b5f805f6060805f80614580885f015189602001518a608001518b60a001518c60c001518d61010001516119bf565b6101208e0151959c5091995092975090955090935091501561468c576101208801516145ac9088615127565b60c089015190975073ffffffffffffffffffffffffffffffffffffffff1615614606576145dd6107d06127106155b7565b8861012001516145ed91906155b7565b6145f79083615127565b915061460382886150f5565b96505b876060015173ffffffffffffffffffffffffffffffffffffffff168860200151895f015173ffffffffffffffffffffffffffffffffffffffff167f128e6430bdac5e0f43d2f25064b707cadc6dbb27cf69958b934944df4b23c4238b61012001518c60400151604051614683929190918252602082015260400190565b60405180910390a45b5f845160011461469e57614e206146a3565b620334505b90505f5b8551811015614716576146ed8682815181106146c5576146c5615415565b60200260200101518683815181106146df576146df615415565b602002602001015184613405565b8481815181106146ff576146ff615415565b6020026020010151880197508060010190506146a7565b5050614729886080015186614e20613405565b861561475957614759877f00000000000000000000000000000000000000000000000000000000000000006142a6565b81156147db576147708860c0015183614e20613405565b602088810151895160c08b01516040805173ffffffffffffffffffffffffffffffffffffffff92831681529485018790525f858201525192939116917f141b92fd9766c80ab120598ea2f6be9802470ec59b5446dd9bf46214ead8d08e9181900360600190a3958101955b610120880151156147f157876101200151870396505b60e088015173ffffffffffffffffffffffffffffffffffffffff161561489f57801561483d57845f03614827579485019461482c565b938401935b61483d8860e0015182614e20613405565b602080890151895160e08b01516040805173ffffffffffffffffffffffffffffffffffffffff928316815294850186905292939116917f27a4dd4ff659a9e6354fb079b2208365e5b83f55c22a4150eee2bca89501cb98910160405180910390a35b505050509193909250565b5f81815b848110156148e2576148d8828787848181106148cc576148cc615415565b90506020020135614a79565b91506001016148ae565b50949350505050565b80471015614955576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401611264565b5f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f81146149ab576040519150601f19603f3d011682016040523d82523d5f602084013e6149b0565b606091505b5050905080614a41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401611264565b505050565b73ffffffffffffffffffffffffffffffffffffffff8082165f908152613cc3602052604090205416806144af575f611d71565b5f818310614a93575f828152602084905260409020610df8565b5f838152602083905260409020610df8565b73ffffffffffffffffffffffffffffffffffffffff811681146119bc575f80fd5b5f60208284031215614ad6575f80fd5b8135610df881614aa5565b5f805f805f60a08688031215614af5575f80fd5b8535614b0081614aa5565b97602087013597506040870135966060810135965060800135945092505050565b5f8083601f840112614b31575f80fd5b50813567ffffffffffffffff811115614b48575f80fd5b6020830191508360208260051b8501011115614b62575f80fd5b9250929050565b5f805f805f8060a08789031215614b7e575f80fd5b8635614b8981614aa5565b9550602087013594506040870135614ba081614aa5565b93506060870135614bb081614aa5565b9250608087013567ffffffffffffffff811115614bcb575f80fd5b614bd789828a01614b21565b979a9699509497509295939492505050565b5f805f60608486031215614bfb575f80fd5b8335614c0681614aa5565b9250602084013591506040840135614c1d81614aa5565b809150509250925092565b5f8060408385031215614c39575f80fd5b8235614c4481614aa5565b91506020830135614c5481614aa5565b809150509250929050565b61ffff811681146119bc575f80fd5b5f805f8060808587031215614c81575f80fd5b8435614c8c81614aa5565b93506020850135614c9c81614c5f565b92506040850135614cac81614aa5565b91506060850135614cbc81614aa5565b939692955090935050565b5f8060408385031215614cd8575f80fd5b8235614ce381614aa5565b946020939093013593505050565b5f805f805f8060c08789031215614d06575f80fd5b8635614d1181614aa5565b9860208801359850604088013597606081013597506080810135965060a00135945092505050565b5f805f805f8060c08789031215614d4e575f80fd5b8635614d5981614aa5565b9550602087013594506040870135614d7081614aa5565b9350606087013592506080870135614d8781614aa5565b915060a0870135614d9781614c5f565b809150509295509295509295565b5f815180845260208085019450602084015f5b83811015614dea57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614db8565b509495945050505050565b5f815180845260208085019450602084015f5b83811015614dea57815187529582019590820190600101614e08565b86815260c060208201525f614e3c60c0830188614da5565b8281036040840152614e4e8188614df5565b60608401969096525050608081019290925260a0909101529392505050565b5f805f60608486031215614e7f575f80fd5b8335614e8a81614aa5565b95602085013595506040909401359392505050565b86815285602082015260c060408201525f614ebd60c0830187614da5565b8281036060840152614ecf8187614df5565b91505083608083015273ffffffffffffffffffffffffffffffffffffffff831660a0830152979650505050505050565b5f805f805f60808688031215614f13575f80fd5b8535614f1e81614aa5565b9450602086013593506040860135614f3581614aa5565b9250606086013567ffffffffffffffff811115614f50575f80fd5b614f5c88828901614b21565b969995985093965092949392505050565b5f805f60608486031215614f7f575f80fd5b8335614f8a81614aa5565b92506020840135614f9a81614c5f565b91506040840135614c1d81614aa5565b5f8083601f840112614fba575f80fd5b50813567ffffffffffffffff811115614fd1575f80fd5b602083019150836020828501011115614b62575f80fd5b5f805f805f805f805f6101008a8c031215615001575f80fd5b893561500c81614aa5565b985060208a0135975060408a0135965060608a0135955060808a0135945060a08a0135935060c08a013567ffffffffffffffff81111561504a575f80fd5b6150568c828d01614faa565b9a9d999c50979a9699959894979660e00135949350505050565b5f805f8060608587031215615083575f80fd5b843561508e81614aa5565b935060208501359250604085013567ffffffffffffffff8111156150b0575f80fd5b6150bc87828801614faa565b95989497509550505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115611d7157611d716150c8565b5f60208284031215615118575f80fd5b81518015158114610df8575f80fd5b80820180821115611d7157611d716150c8565b5f6020828403121561514a575f80fd5b5051919050565b5f610120820190508251825260208301511515602083015273ffffffffffffffffffffffffffffffffffffffff6040840151166040830152606083015160608301526080830151608083015260a08301516151c460a084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060c08301516151ec60c084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060e083015161520260e084018261ffff169052565b506101009283015173ffffffffffffffffffffffffffffffffffffffff16919092015290565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561529c5761529c615228565b604052919050565b5f67ffffffffffffffff8211156152bd576152bd615228565b5060051b60200190565b5f82601f8301126152d6575f80fd5b815160206152eb6152e6836152a4565b615255565b8083825260208201915060208460051b87010193508684111561530c575f80fd5b602086015b848110156153285780518352918301918301615311565b509695505050505050565b5f805f805f8060c08789031215615348575f80fd5b8651955060208088015167ffffffffffffffff80821115615367575f80fd5b818a0191508a601f83011261537a575f80fd5b81516153886152e6826152a4565b81815260059190911b8301840190848101908d8311156153a6575f80fd5b938501935b828510156153cd5784516153be81614aa5565b825293850193908501906153ab565b60408d0151909a5094505050808311156153e5575f80fd5b50506153f389828a016152c7565b945050606087015192506080870151915060a087015190509295509295509295565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b83815260406020820152816040820152818360608301375f818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b8681525f602087602084015286604084015285606084015284608084015260c060a084015283518060c08501525f5b818110156154e05785810183015185820160e0015282016154c4565b505f60e0828601015260e07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010192505050979650505050505050565b8082028115828204841417611d7157611d716150c8565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f60208284031215615577575f80fd5b8151610df881614aa5565b5f805f60608486031215615594575f80fd5b8351925060208401516155a681614aa5565b6040850151909250614c1d81614c5f565b5f826155ea577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b50049056fea26469706673582212205d584084516fff37c6ac9441ddd5d7d2b3021bbc7ab793089903f5b7ff81fdf764736f6c6343000818003300000000000000000000000067df244584b67e8c51b10ad610aaffa9a402fdb600000000000000000000000049128cf8abe9071ee24540a296b5ded3f9d50443000000000000000000000000762340b8a40cdd5bfc3edd94265899fda345d0e30000000000000000000000006f229b5cfc021dac5681fc1430e23965f6940d5f00000000000000000000000069525dac489e4718964b5615c3d794a25d62beb7
Deployed Bytecode
0x6080604052600436106101d3575f3560e01c806387a4fdcb116100fd578063dccdafa511610092578063f59488d911610062578063f59488d9146107bf578063f5ec797e146107de578063f7a2da23146107fd578063fb70943f1461082f575f80fd5b8063dccdafa5146106c9578063e965a20214610736578063ecbc955414610749578063f169dda31461075c575f80fd5b8063af4f5ac2116100cd578063af4f5ac2146105ff578063bfb92b421461061e578063d539139314610683578063d782d491146106b6575f80fd5b806387a4fdcb14610502578063895633ba14610533578063aa09f69814610565578063af1e1de3146105ce575f80fd5b80632af2064f1161017357806362c465521161014357806362c465521461042a5780636a90a8271461044957806379ecb0b21461047b5780638129fc1c146104ee575f80fd5b80632af2064f146103ba578063334965c2146103d95780634dad54a1146103ec5780634fca06c61461040b575f80fd5b806316da9864116101ae57806316da9864146102ee5780631722c7e71461030157806321dbd9aa14610335578063228b131814610388575f80fd5b806306ca634b1461024d5780630853764a146102ae5780630cafb113146102cd575f80fd5b36610249573373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000049128cf8abe9071ee24540a296b5ded3f9d504431614610247576040517faa39384e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b005b5f80fd5b348015610258575f80fd5b5061026c610267366004614ac6565b61084e565b6040805173ffffffffffffffffffffffffffffffffffffffff909516855292151560208501529015159183019190915260608201526080015b60405180910390f35b3480156102b9575f80fd5b506102476102c8366004614ae1565b61096a565b6102e06102db366004614b69565b610a2b565b6040519081526020016102a5565b6102e06102fc366004614be9565b610a47565b34801561030c575f80fd5b5061032061031b366004614c28565b610a5d565b604080519283526020830191909152016102a5565b348015610340575f80fd5b507f0000000000000000000000006f229b5cfc021dac5681fc1430e23965f6940d5f5b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102a5565b348015610393575f80fd5b507f00000000000000000000000069525dac489e4718964b5615c3d794a25d62beb7610363565b3480156103c5575f80fd5b506102476103d4366004614c28565b610b72565b6102e06103e7366004614c6e565b610ce5565b3480156103f7575f80fd5b506102e0610406366004614cc7565b610cfd565b348015610416575f80fd5b50610363610425366004614cc7565b610ded565b348015610435575f80fd5b50610247610444366004614cf1565b610dff565b348015610454575f80fd5b507f000000000000000000000000762340b8a40cdd5bfc3edd94265899fda345d0e3610363565b348015610486575f80fd5b5061049a610495366004614ac6565b611617565b6040805173ffffffffffffffffffffffffffffffffffffffff909916895260208901979097529587019490945260608601929092521515608085015260a084015260c083015260e0820152610100016102a5565b3480156104f9575f80fd5b50610247611833565b34801561050d575f80fd5b5061052161051c366004614d39565b6119bf565b6040516102a596959493929190614e24565b34801561053e575f80fd5b507f00000000000000000000000049128cf8abe9071ee24540a296b5ded3f9d50443610363565b348015610570575f80fd5b5061058461057f366004614ac6565b611b8e565b604080519a8b5260208b0199909952978901969096526060880194909452608087019290925260a086015260c085015260e0840152610100830152610120820152610140016102a5565b3480156105d9575f80fd5b506105ed6105e8366004614e6d565b611c7a565b6040516102a596959493929190614e9f565b34801561060a575f80fd5b506102e0610619366004614c28565b611ce9565b348015610629575f80fd5b50610673610638366004614cc7565b73ffffffffffffffffffffffffffffffffffffffff9091165f908152613cc36020908152604080832093835260039093019052205460ff1690565b60405190151581526020016102a5565b34801561068e575f80fd5b506102e07f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b6102e06106c4366004614eff565b611d77565b3480156106d4575f80fd5b506106e86106e3366004614ac6565b611d98565b6040805173ffffffffffffffffffffffffffffffffffffffff909816885260208801969096529486019390935260608501919091521515608084015260a083015260c082015260e0016102a5565b6102e0610744366004614cc7565b611dc0565b6102e0610757366004614f6d565b611dd4565b348015610767575f80fd5b5061077b610776366004614ac6565b611de9565b60408051998a5260208a0198909852968801959095526060870193909352608086019190915260a085015260c084015260e0830152610100820152610120016102a5565b3480156107ca575f80fd5b506102476107d9366004614fe8565b611ec9565b3480156107e9575f80fd5b506102476107f8366004615070565b612063565b348015610808575f80fd5b507f00000000000000000000000067df244584b67e8c51b10ad610aaffa9a402fdb6610363565b34801561083a575f80fd5b50610247610849366004614ac6565b612405565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526140ac602052604081208054829182918291907c0100000000000000000000000000000000000000000000000000000000900463ffffffff1615610962576002810154600182015473ffffffffffffffffffffffffffffffffffffffff9091169550760100000000000000000000000000000000000000000000900460ff1692508261096257600181015463ffffffff6601000000000000820481166201000090920416101580610940575080547c0100000000000000000000000000000000000000000000000000000000900463ffffffff1642115b600182015490945062010000900463ffffffff1661095e8742610cfd565b0291505b509193509193565b80801580159061097e575061097e81421190565b156109b5576040517fbcb9700400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825f036109c457429250610a04565b6109cd83421190565b15610a04576040517fa619834a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a2386868686875f801b60405180602001604052805f81525061266c565b505050505050565b5f610a3c8787878787876001612d05565b979650505050505050565b5f610a558484846001612ec3565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff8281165f9081526140ac6020908152604080832093851683526003840182528083208151808301909252546bffffffffffffffffffffffff811682526c01000000000000000000000000900461ffff169181018290529192839290918390610ada8842610cfd565b835191029150610af99082906bffffffffffffffffffffffff166150f5565b6001840154602084015191965061ffff9081169116811115610b67576020830151600185015461ffff9091168203955063ffffffff660100000000000082048116916201000090041680821115610b6057808203915081871115610b5b578196505b610b64565b5f96505b50505b505050509250929050565b73ffffffffffffffffffffffffffffffffffffffff8083165f9081526140ac602090815260408083209385168352600390930190529081208054909161ffff6c01000000000000000000000000830416916bffffffffffffffffffffffff1690610bdc8642610cfd565b90508281025f610bec82856150f5565b9050805f03610c27576040517f433b2e9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b85547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff8316178655610c6b878262033450613405565b8673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167fd9f7a958c85633cf171f617fa7127c9f19bacb103e2bce41bb6728d0476515808386604051610cd3929190918252602082015260400190565b60405180910390a35050505050505050565b5f610cf48585858560016135e5565b95945050505050565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526140ac60205260408120600181015463ffffffff660100000000000082048116620100009092041610610d6d5760018101546a010000000000000000000090046bffffffffffffffffffffffff169150610de6565b8054610de3906bffffffffffffffffffffffff808216916c0100000000000000000000000081049091169063ffffffff780100000000000000000000000000000000000000000000000082048116917c01000000000000000000000000000000000000000000000000000000009004168761366e565b91505b5092915050565b5f610df883836136c4565b9392505050565b85610e4073ffffffffffffffffffffffffffffffffffffffff82167f5bf6f7b8000000000000000000000000000000000000000000000000000000006136cf565b610e76576040517f17fdef0700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610eb673ffffffffffffffffffffffffffffffffffffffff82167f80ac58cd000000000000000000000000000000000000000000000000000000006136e6565b610eec576040517f29d190d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f91d148540000000000000000000000000000000000000000000000000000000081527f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6600482015230602482015273ffffffffffffffffffffffffffffffffffffffff8216906391d1485490604401602060405180830381865afa158015610f7a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f9e9190615108565b610fd4576040517f436d641100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff81166391d148545f610ffa6137af565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925273ffffffffffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa158015611067573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061108b9190615108565b6110c1576040517f5fad784000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b875f6110cc826137bd565b73ffffffffffffffffffffffffffffffffffffffff1614611119576040517f2540293000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b868811611152576040517f5a42b07900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855f0361118b576040517f92865bfe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845f0361119a574294506111da565b6111a385421190565b156111da576040517f3a3baeca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835f03611213576040517f3335f9a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61121e8587615127565b90506303c26700420181111561126d576040517f82fae596000000000000000000000000000000000000000000000000000000008152426303c267000160048201526024015b60405180910390fd5b5f8a73ffffffffffffffffffffffffffffffffffffffff16638ae3e5f16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112b7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112db919061513a565b9050805f03611316576040517f61b9c86b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61131f6137af565b73ffffffffffffffffffffffffffffffffffffffff8d165f9081526140ac602052604090209091506113508c6137c7565b815477ffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff878116919091027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff16919091177801000000000000000000000000000000000000000000000000918c1691909102177fffffffffffffffff000000000000000000000000000000000000000000000000166c010000000000000000000000006bffffffffffffffffffffffff8e8116919091027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000169190911791161781556114568a61381c565b61145f84613863565b6002830180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff868116919091179091556001840180547fffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff000016660100000000000063ffffffff94909416939093027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169290921761ffff939093169290921790556040517f24ef95e700000000000000000000000000000000000000000000000000000000815260048101869052908e16906324ef95e7906024015f604051808303815f87803b158015611567575f80fd5b505af1158015611579573d5f803e3d5ffd5b505050508173ffffffffffffffffffffffffffffffffffffffff168d73ffffffffffffffffffffffffffffffffffffffff167f4be408b58dfcdd9eed5e094c36b581760de5ad0b07dc4fc948b61fba5001898e8e8e8e8e8a604051611600959493929190948552602085019390935260408401919091526060830152608082015260a00190565b60405180910390a350505050505050505050505050565b5f805f805f805f808873ffffffffffffffffffffffffffffffffffffffff16638ae3e5f16040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156116a4575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526116a19181019061513a565b60015b15611828578015611826576040517f91d148540000000000000000000000000000000000000000000000000000000081527f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6600482015230602482015273ffffffffffffffffffffffffffffffffffffffff8b16906391d1485490604401602060405180830381865afa925050508015611779575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261177691810190615108565b60015b156118265773ffffffffffffffffffffffffffffffffffffffff8b81165f908152613cc36020526040902080546002909101549181169b5074010000000000000000000000000000000000000000810469ffffffffffffffffffff169a507e01000000000000000000000000000000000000000000000000000000000000900461ffff169850919650945063ffffffff80821694506401000000009091041691506602d79883d200009050845b505b919395975091939597565b5f54610100900460ff161580801561185157505f54600160ff909116105b8061186a5750303b15801561186a57505f5460ff166001145b6118f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401611264565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015611952575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b61195a6138ac565b80156119bc575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b5f6060805f805f806040518061012001604052807f000000000000000000000000000000000000000000000000000000000000000081526020017f0000000000000000000000000000000000000000000000000000000000000001151581526020018e73ffffffffffffffffffffffffffffffffffffffff1681526020018d81526020018b81526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018961ffff168152602001611a936137af565b73ffffffffffffffffffffffffffffffffffffffff1681525090507f0000000000000000000000006f229b5cfc021dac5681fc1430e23965f6940d5f73ffffffffffffffffffffffffffffffffffffffff16630e13eac1826040518263ffffffff1660e01b8152600401611b079190615151565b5f60405180830381865afa158015611b21573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611b669190810190615333565b809750819850829950839a50849b50859c505050505050505096509650965096509650969050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526140ac60205260408120805460018201546bffffffffffffffffffffffff808316946c01000000000000000000000000840482169461ffff84169463ffffffff780100000000000000000000000000000000000000000000000082048116957c010000000000000000000000000000000000000000000000000000000090920481169466010000000000008304821694620100008404909216936a010000000000000000000090930416918190611c608c42610cfd565b92506602d79883d200009150509193959799509193959799565b5f806060805f80611c8b898961394c565b9050611c9b8989838a5f806119bf565b50939950919650945092505f90505b8351811015611cdc57838181518110611cc557611cc5615415565b602002602001015186019550806001019050611caa565b5093975093979195509350565b5f805f80611cf686611617565b505050945094509450505080611d11575f9350505050611d71565b73ffffffffffffffffffffffffffffffffffffffff8087165f908152613cc3602090815260408083209389168352600190930190522054838110611d5b575f945050505050611d71565b808403945082851115611d6c578294505b505050505b92915050565b5f611d8e8686611d856137af565b8787875f612d05565b9695505050505050565b5f805f805f805f611da888611617565b50959e949d50929b5090995097509550909350915050565b5f610df88383611dce6137af565b5f612ec3565b5f610a558484611de26137af565b855f6135e5565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526140ac60205260408120805460018201546bffffffffffffffffffffffff808316946c01000000000000000000000000840482169461ffff84169463ffffffff780100000000000000000000000000000000000000000000000082048116957c010000000000000000000000000000000000000000000000000000000090920481169466010000000000008304821694620100008404909216936a01000000000000000000009093041691611eb98b42610cfd565b9150509193959799909294969850565b808015801590611edd5750611edd81421190565b15611f14576040517fbcb9700400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84848482611f4e576040517f229955da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f819003611f88576040517fe85bdf0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b885f03611f9757429850611fd7565b611fa089421190565b15611fd7576040517fdddbb7cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b898910612010576040517f77b2af4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6120548d8d8d8d8d8d8d8d8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061266c92505050565b50505050505050505050505050565b838073ffffffffffffffffffffffffffffffffffffffff16638ae3e5f16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120ad573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120d1919061513a565b5f03612109576040517f3c263ade00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8473ffffffffffffffffffffffffffffffffffffffff81166391d148545f61212f6137af565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925273ffffffffffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa15801561219c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121c09190615108565b6121f6576040517f5fad784000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84848482612230576040517f229955da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81900361226a576040517fe85bdf0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff89165f908152613cc360205260409020600281015463ffffffff16421061232057805473ffffffffffffffffffffffffffffffffffffffff166122ee576040517f974bcaec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ff2279aef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600281015463ffffffff6401000000008204811691160361236d576040517f77b2af4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8981526003820160205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555173ffffffffffffffffffffffffffffffffffffffff8b16907f7f11be7894109a714225fbb6c33d88a14582407d653ac3fc5abf07d9b3ce8914906123f1908c908c908c90615442565b60405180910390a250505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8082165f9081526140ac6020526040902060028101549091168061246a576040517fcc4f974c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001820154760100000000000000000000000000000000000000000000900460ff16156124c3576040517fba5a58b200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600182015482546201000090910463ffffffff908116917c0100000000000000000000000000000000000000000000000000000000900416421115801561251d575060018301546601000000000000900463ffffffff1681105b1561259957825460018401546040517f1dd4212a0000000000000000000000000000000000000000000000000000000081527c010000000000000000000000000000000000000000000000000000000090920463ffffffff90811660048401526601000000000000909104168290036024820152604401611264565b5f6125a48542610cfd565b6001850180547fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff1676010000000000000000000000000000000000000000000017905590508181025f806125fd888685848a8180613a52565b604080518781526020810189905290810183905260608101829052919350915073ffffffffffffffffffffffffffffffffffffffff8916907f5e16e96b4ba4fe46f3be73d54d1fa0da481494ab74c2d6e33328366d6437693c9060800160405180910390a25050505050505050565b866126ad73ffffffffffffffffffffffffffffffffffffffff82167f5bf6f7b8000000000000000000000000000000000000000000000000000000006136cf565b6126e3576040517f17fdef0700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61272373ffffffffffffffffffffffffffffffffffffffff82167f80ac58cd000000000000000000000000000000000000000000000000000000006136e6565b612759576040517f29d190d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f91d148540000000000000000000000000000000000000000000000000000000081527f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6600482015230602482015273ffffffffffffffffffffffffffffffffffffffff8216906391d1485490604401602060405180830381865afa1580156127e7573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061280b9190615108565b612841576040517f436d641100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b878073ffffffffffffffffffffffffffffffffffffffff16638ae3e5f16040518163ffffffff1660e01b8152600401602060405180830381865afa15801561288b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128af919061513a565b5f036128e7576040517f3c263ade00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8873ffffffffffffffffffffffffffffffffffffffff81166391d148545f61290d6137af565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925273ffffffffffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa15801561297a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061299e9190615108565b6129d4576040517f5fad784000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b866303c267004201811115612a1d576040517fe43fc8b2000000000000000000000000000000000000000000000000000000008152426303c26700016004820152602401611264565b8a5f612a28826137bd565b73ffffffffffffffffffffffffffffffffffffffff1614612a75576040517f2540293000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b895f03612aae576040517f250099ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8c165f908152613cc36020526040812090612adc6137af565b82547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff82161783559050612b258d613bf7565b825469ffffffffffffffffffff9190911674010000000000000000000000000000000000000000027fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff909116178255612b7d8c61381c565b825461ffff919091167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909116178255428b14612c06576002820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff8d161790555b428a14612c47576002820180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff1664010000000063ffffffff8d16021790555b8815612c86575f898152600383016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b8073ffffffffffffffffffffffffffffffffffffffff168e73ffffffffffffffffffffffffffffffffffffffff167fa4e684574cd21d7eb4df36ec6d7f86d16aa900ceddae41e4e82f8f4170f293b98f8f8f8f8f8f604051612ced96959493929190615495565b60405180910390a35050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff87165f908152613cc360205260408120600281015463ffffffff16421015612ea8576002810154640100000000900463ffffffff16421015612deb57600281015463ffffffff8082166401000000009092041603612da4576040517f77b2af4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60028101546040517f8ba20e6800000000000000000000000000000000000000000000000000000000815264010000000090910463ffffffff166004820152602401611264565b5f612e0d73ffffffffffffffffffffffffffffffffffffffff89168787613c46565b5f81815260038401602052604090205490915060ff16612ea65773ffffffffffffffffffffffffffffffffffffffff8816612e74576040517f1126144d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ff88937c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b612eb6818a8a8a8a88613cbf565b9998505050505050505050565b5f835f03612efd576040517fb3896a5100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8316612f4a576040517fae36b52500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff85165f9081526140ac60205260408120805490917c010000000000000000000000000000000000000000000000000000000090910463ffffffff169003612fd2576040517fcc4f974c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80547801000000000000000000000000000000000000000000000000900463ffffffff164210156130555780546040517f70fdd722000000000000000000000000000000000000000000000000000000008152780100000000000000000000000000000000000000000000000090910463ffffffff166004820152602401611264565b73ffffffffffffffffffffffffffffffffffffffff84165f9081526003820160205260408120805490919061309e906c01000000000000000000000000900461ffff1688615127565b600184015490915061ffff1681111561310857815460018401546040517fb3c84a0b0000000000000000000000000000000000000000000000000000000081526c0100000000000000000000000090920461ffff9081166004840152166024820152604401611264565b5f6131138942610cfd565b600185015490915088820290760100000000000000000000000000000000000000000000900460ff165f80808a61314a575f61315b565b61315b8d6602d79883d20000615523565b90505f6131688287615127565b60018b01549091506131869062010000900463ffffffff168f615127565b60018b01805463ffffffff90921662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffff6bffffffffffffffffffffffff808c166a010000000000000000000002919091167fffffffffffffffffffff000000000000000000000000ffffffff00000000ffff90941693909317179055895461321d9161321891899116615127565b6137c7565b89547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166c0100000000000000000000000061ffff8b16027fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016176bffffffffffffffffffffffff919091161789556132978160016141c1565b506040517fd115124900000000000000000000000000000000000000000000000000000000815261ffff8e16600482015273ffffffffffffffffffffffffffffffffffffffff8d811660248301528f169063d1151249906044016020604051808303815f875af115801561330d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613331919061513a565b995083156133755761336b8e8e878f8d6002015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff168f87613a52565b9093509150613388565b8a15613388576133888e8b8f8f856142fb565b5060408051868152602081018e90529081018a9052606081018390526080810182905273ffffffffffffffffffffffffffffffffffffffff808d1691908f16907ffacca8c0845db767bcbcc63c5f7e7e93df5690aea049d11be2fffafd4185d8ec9060a00160405180910390a35050505050505050949350505050565b815f0361341157505050565b7f00000000000000000000000049128cf8abe9071ee24540a296b5ded3f9d5044373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603613488577f00000000000000000000000067df244584b67e8c51b10ad610aaffa9a402fdb692505b5f8373ffffffffffffffffffffffffffffffffffffffff168383906040515f60405180830381858888f193505050503d805f81146134e1576040519150601f19603f3d011682016040523d82523d5f602084013e6134e6565b606091505b50509050806135df576040517faa67c91900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301527f00000000000000000000000049128cf8abe9071ee24540a296b5ded3f9d50443169063aa67c9199085906024015f604051808303818588803b158015613577575f80fd5b505af1158015613589573d5f803e3d5ffd5b50505050508373ffffffffffffffffffffffffffffffffffffffff167fa2201512569adb2d513531dfd69b66df50bd5cffb8c1bbe65a4611f9e1eadbd1846040516135d691815260200190565b60405180910390a25b50505050565b73ffffffffffffffffffffffffffffffffffffffff85165f908152613cc360205260408120600281015463ffffffff1642101561365c5760028101546040517f26763e5a00000000000000000000000000000000000000000000000000000000815263ffffffff9091166004820152602401611264565b610a3c81888861ffff16888888613cbf565b5f83821161367d575084610cf4565b82821061368b575083610cf4565b61369585876150f5565b90508183036136a48183615523565b915084840382816136b7576136b761553a565b049150610a3c8683615127565b5f610df8838361439d565b5f6136d9836143a7565b8015610df85750610df883835b604080517fffffffff000000000000000000000000000000000000000000000000000000008316602480830191909152825180830390910181526044909101909152602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a70000000000000000000000000000000000000000000000000000000017815282515f9392849283928392918391908a617530fa92503d91505f51905082801561379c575060208210155b8015610a3c575015159695505050505050565b5f6137b861440a565b905090565b5f611d7182614476565b5f6bffffffffffffffffffffffff821115613818576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526060600482015260248101839052604401611264565b5090565b5f61ffff821115613818576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526010600482015260248101839052604401611264565b5f63ffffffff821115613818576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526020600482015260248101839052604401611264565b5f54610100900460ff16613942576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401611264565b61394a6144b4565b565b6040517f6352211e000000000000000000000000000000000000000000000000000000008152600481018290525f9073ffffffffffffffffffffffffffffffffffffffff841690636352211e90602401602060405180830381865afa9250505080156139f3575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526139f091810190615567565b60015b15613a485773ffffffffffffffffffffffffffffffffffffffff811615613a46576040517f5ca60e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b610df8838361439d565b6040517fcec32ca500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152888116602483015260448201889052606482018790525f918291829182917f00000000000000000000000069525dac489e4718964b5615c3d794a25d62beb7169063cec32ca5906084016060604051808303815f875af1158015613afb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b1f9190615582565b9250925050613be46040518061014001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018881526020018c81526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018973ffffffffffffffffffffffffffffffffffffffff1681526020018b81526020015f73ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018361ffff16815260200187815250614552565b50909c909b509950505050505050505050565b5f69ffffffffffffffffffff821115613818576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526050600482015260248101839052604401611264565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606085901b1660208201525f908190603401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101209050610cf48484836148aa565b5f845f03613cf9576040517f2d69aaf400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8416613d46576040517f1126144d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff84165f908152600188016020526040812054613d78908790615127565b88549091507e01000000000000000000000000000000000000000000000000000000000000900461ffff16811115613e665787547e01000000000000000000000000000000000000000000000000000000000000900461ffff165f03613e0a576040517f974bcaec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b87546040517ffa7c028e0000000000000000000000000000000000000000000000000000000081527e0100000000000000000000000000000000000000000000000000000000000090910461ffff166004820152602401611264565b73ffffffffffffffffffffffffffffffffffffffff85165f90815260018901602052604081209190915587548190819074010000000000000000000000000000000000000000900469ffffffffffffffffffff168802818615613ed057896602d79883d200000294505b50808401613ede815f6141c1565b6040517fd115124900000000000000000000000000000000000000000000000000000000815261ffff8b16600482015273ffffffffffffffffffffffffffffffffffffffff8a811660248301528c169063d1151249906044016020604051808303815f875af1158015613f53573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613f77919061513a565b8c546040517fcec32ca500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201528d82166024820152604481018d9052606481018590529197507f00000000000000000000000069525dac489e4718964b5615c3d794a25d62beb7169063cec32ca5906084016060604051808303815f875af115801561401d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906140419190615582565b9091508094508195505050505f806141316040518061014001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018d81526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018f5f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018581526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018661ffff16815260200188815250614552565b5091509150868a73ffffffffffffffffffffffffffffffffffffffff168d73ffffffffffffffffffffffffffffffffffffffff167f05ebbb6b0ce7d564230ba625dd7a0e5108786b0852d6060de6099e1778203e348e86866040516141a9939291909283526020830191909152604082015260600190565b60405180910390a45050505050509695505050505050565b3482111561428a577f00000000000000000000000049128cf8abe9071ee24540a296b5ded3f9d5044373ffffffffffffffffffffffffffffffffffffffff1663452f2b8f61420d6137af565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015234850360248201526044015f604051808303815f87803b158015614278575f80fd5b505af1158015610a23573d5f803e3d5ffd5b348210156142c25780156142c6576142c28234036142a66137af565b73ffffffffffffffffffffffffffffffffffffffff16906148eb565b5050565b6040517fabf2f33b00000000000000000000000000000000000000000000000000000000815260048101839052602401611264565b614325817f00000000000000000000000067df244584b67e8c51b10ad610aaffa9a402fdb66142a6565b8173ffffffffffffffffffffffffffffffffffffffff16848673ffffffffffffffffffffffffffffffffffffffff167f128e6430bdac5e0f43d2f25064b707cadc6dbb27cf69958b934944df4b23c423848760405161438e929190918252602082015260400190565b60405180910390a45050505050565b5f610df8836137bd565b5f6143d2827f01ffc9a7000000000000000000000000000000000000000000000000000000006136e6565b8015611d715750614403827fffffffff000000000000000000000000000000000000000000000000000000006136e6565b1592915050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000762340b8a40cdd5bfc3edd94265899fda345d0e316810361447357507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec36013560601c90565b90565b73ffffffffffffffffffffffffffffffffffffffff8082165f9081526140ac602052604090206002015416806144af57611d7182614a46565b919050565b5f54610100900460ff1661454a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401611264565b6001610dad55565b5f805f6060805f80614580885f015189602001518a608001518b60a001518c60c001518d61010001516119bf565b6101208e0151959c5091995092975090955090935091501561468c576101208801516145ac9088615127565b60c089015190975073ffffffffffffffffffffffffffffffffffffffff1615614606576145dd6107d06127106155b7565b8861012001516145ed91906155b7565b6145f79083615127565b915061460382886150f5565b96505b876060015173ffffffffffffffffffffffffffffffffffffffff168860200151895f015173ffffffffffffffffffffffffffffffffffffffff167f128e6430bdac5e0f43d2f25064b707cadc6dbb27cf69958b934944df4b23c4238b61012001518c60400151604051614683929190918252602082015260400190565b60405180910390a45b5f845160011461469e57614e206146a3565b620334505b90505f5b8551811015614716576146ed8682815181106146c5576146c5615415565b60200260200101518683815181106146df576146df615415565b602002602001015184613405565b8481815181106146ff576146ff615415565b6020026020010151880197508060010190506146a7565b5050614729886080015186614e20613405565b861561475957614759877f00000000000000000000000067df244584b67e8c51b10ad610aaffa9a402fdb66142a6565b81156147db576147708860c0015183614e20613405565b602088810151895160c08b01516040805173ffffffffffffffffffffffffffffffffffffffff92831681529485018790525f858201525192939116917f141b92fd9766c80ab120598ea2f6be9802470ec59b5446dd9bf46214ead8d08e9181900360600190a3958101955b610120880151156147f157876101200151870396505b60e088015173ffffffffffffffffffffffffffffffffffffffff161561489f57801561483d57845f03614827579485019461482c565b938401935b61483d8860e0015182614e20613405565b602080890151895160e08b01516040805173ffffffffffffffffffffffffffffffffffffffff928316815294850186905292939116917f27a4dd4ff659a9e6354fb079b2208365e5b83f55c22a4150eee2bca89501cb98910160405180910390a35b505050509193909250565b5f81815b848110156148e2576148d8828787848181106148cc576148cc615415565b90506020020135614a79565b91506001016148ae565b50949350505050565b80471015614955576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401611264565b5f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f81146149ab576040519150601f19603f3d011682016040523d82523d5f602084013e6149b0565b606091505b5050905080614a41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401611264565b505050565b73ffffffffffffffffffffffffffffffffffffffff8082165f908152613cc3602052604090205416806144af575f611d71565b5f818310614a93575f828152602084905260409020610df8565b5f838152602083905260409020610df8565b73ffffffffffffffffffffffffffffffffffffffff811681146119bc575f80fd5b5f60208284031215614ad6575f80fd5b8135610df881614aa5565b5f805f805f60a08688031215614af5575f80fd5b8535614b0081614aa5565b97602087013597506040870135966060810135965060800135945092505050565b5f8083601f840112614b31575f80fd5b50813567ffffffffffffffff811115614b48575f80fd5b6020830191508360208260051b8501011115614b62575f80fd5b9250929050565b5f805f805f8060a08789031215614b7e575f80fd5b8635614b8981614aa5565b9550602087013594506040870135614ba081614aa5565b93506060870135614bb081614aa5565b9250608087013567ffffffffffffffff811115614bcb575f80fd5b614bd789828a01614b21565b979a9699509497509295939492505050565b5f805f60608486031215614bfb575f80fd5b8335614c0681614aa5565b9250602084013591506040840135614c1d81614aa5565b809150509250925092565b5f8060408385031215614c39575f80fd5b8235614c4481614aa5565b91506020830135614c5481614aa5565b809150509250929050565b61ffff811681146119bc575f80fd5b5f805f8060808587031215614c81575f80fd5b8435614c8c81614aa5565b93506020850135614c9c81614c5f565b92506040850135614cac81614aa5565b91506060850135614cbc81614aa5565b939692955090935050565b5f8060408385031215614cd8575f80fd5b8235614ce381614aa5565b946020939093013593505050565b5f805f805f8060c08789031215614d06575f80fd5b8635614d1181614aa5565b9860208801359850604088013597606081013597506080810135965060a00135945092505050565b5f805f805f8060c08789031215614d4e575f80fd5b8635614d5981614aa5565b9550602087013594506040870135614d7081614aa5565b9350606087013592506080870135614d8781614aa5565b915060a0870135614d9781614c5f565b809150509295509295509295565b5f815180845260208085019450602084015f5b83811015614dea57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614db8565b509495945050505050565b5f815180845260208085019450602084015f5b83811015614dea57815187529582019590820190600101614e08565b86815260c060208201525f614e3c60c0830188614da5565b8281036040840152614e4e8188614df5565b60608401969096525050608081019290925260a0909101529392505050565b5f805f60608486031215614e7f575f80fd5b8335614e8a81614aa5565b95602085013595506040909401359392505050565b86815285602082015260c060408201525f614ebd60c0830187614da5565b8281036060840152614ecf8187614df5565b91505083608083015273ffffffffffffffffffffffffffffffffffffffff831660a0830152979650505050505050565b5f805f805f60808688031215614f13575f80fd5b8535614f1e81614aa5565b9450602086013593506040860135614f3581614aa5565b9250606086013567ffffffffffffffff811115614f50575f80fd5b614f5c88828901614b21565b969995985093965092949392505050565b5f805f60608486031215614f7f575f80fd5b8335614f8a81614aa5565b92506020840135614f9a81614c5f565b91506040840135614c1d81614aa5565b5f8083601f840112614fba575f80fd5b50813567ffffffffffffffff811115614fd1575f80fd5b602083019150836020828501011115614b62575f80fd5b5f805f805f805f805f6101008a8c031215615001575f80fd5b893561500c81614aa5565b985060208a0135975060408a0135965060608a0135955060808a0135945060a08a0135935060c08a013567ffffffffffffffff81111561504a575f80fd5b6150568c828d01614faa565b9a9d999c50979a9699959894979660e00135949350505050565b5f805f8060608587031215615083575f80fd5b843561508e81614aa5565b935060208501359250604085013567ffffffffffffffff8111156150b0575f80fd5b6150bc87828801614faa565b95989497509550505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115611d7157611d716150c8565b5f60208284031215615118575f80fd5b81518015158114610df8575f80fd5b80820180821115611d7157611d716150c8565b5f6020828403121561514a575f80fd5b5051919050565b5f610120820190508251825260208301511515602083015273ffffffffffffffffffffffffffffffffffffffff6040840151166040830152606083015160608301526080830151608083015260a08301516151c460a084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060c08301516151ec60c084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060e083015161520260e084018261ffff169052565b506101009283015173ffffffffffffffffffffffffffffffffffffffff16919092015290565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561529c5761529c615228565b604052919050565b5f67ffffffffffffffff8211156152bd576152bd615228565b5060051b60200190565b5f82601f8301126152d6575f80fd5b815160206152eb6152e6836152a4565b615255565b8083825260208201915060208460051b87010193508684111561530c575f80fd5b602086015b848110156153285780518352918301918301615311565b509695505050505050565b5f805f805f8060c08789031215615348575f80fd5b8651955060208088015167ffffffffffffffff80821115615367575f80fd5b818a0191508a601f83011261537a575f80fd5b81516153886152e6826152a4565b81815260059190911b8301840190848101908d8311156153a6575f80fd5b938501935b828510156153cd5784516153be81614aa5565b825293850193908501906153ab565b60408d0151909a5094505050808311156153e5575f80fd5b50506153f389828a016152c7565b945050606087015192506080870151915060a087015190509295509295509295565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b83815260406020820152816040820152818360608301375f818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b8681525f602087602084015286604084015285606084015284608084015260c060a084015283518060c08501525f5b818110156154e05785810183015185820160e0015282016154c4565b505f60e0828601015260e07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010192505050979650505050505050565b8082028115828204841417611d7157611d716150c8565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f60208284031215615577575f80fd5b8151610df881614aa5565b5f805f60608486031215615594575f80fd5b8351925060208401516155a681614aa5565b6040850151909250614c1d81614c5f565b5f826155ea577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b50049056fea26469706673582212205d584084516fff37c6ac9441ddd5d7d2b3021bbc7ab793089903f5b7ff81fdf764736f6c63430008180033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000067df244584b67e8c51b10ad610aaffa9a402fdb600000000000000000000000049128cf8abe9071ee24540a296b5ded3f9d50443000000000000000000000000762340b8a40cdd5bfc3edd94265899fda345d0e30000000000000000000000006f229b5cfc021dac5681fc1430e23965f6940d5f00000000000000000000000069525dac489e4718964b5615c3d794a25d62beb7
-----Decoded View---------------
Arg [0] : treasury (address): 0x67Df244584b67E8C51B10aD610aAfFa9a402FdB6
Arg [1] : feth (address): 0x49128CF8ABE9071ee24540a296b5DED3F9D50443
Arg [2] : router (address): 0x762340B8a40Cdd5BFC3eDD94265899FDa345D0E3
Arg [3] : marketUtils (address): 0x6f229B5Cfc021dAC5681Fc1430E23965F6940D5F
Arg [4] : worldsNft (address): 0x69525Dac489e4718964B5615c3D794a25d62bEb7
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 00000000000000000000000067df244584b67e8c51b10ad610aaffa9a402fdb6
Arg [1] : 00000000000000000000000049128cf8abe9071ee24540a296b5ded3f9d50443
Arg [2] : 000000000000000000000000762340b8a40cdd5bfc3edd94265899fda345d0e3
Arg [3] : 0000000000000000000000006f229b5cfc021dac5681fc1430e23965f6940d5f
Arg [4] : 00000000000000000000000069525dac489e4718964b5615c3d794a25d62beb7
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ 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.