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
|
|||
---|---|---|---|---|---|---|
16749704 | 673 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
NFTDropMarket
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 1337000 runs
Other Settings:
default 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.12; import "@openzeppelin/contracts/utils/Context.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import "./mixins/shared/FETHNode.sol"; import "./mixins/shared/FoundationTreasuryNode.sol"; import "./mixins/shared/Gap9000.sol"; import "./mixins/shared/Gap500.sol"; import "./mixins/shared/MarketFees.sol"; import "./mixins/shared/MarketSharedCore.sol"; import "./mixins/shared/RouterContext.sol"; import "./mixins/shared/SendValueWithFallbackWithdraw.sol"; import "./mixins/shared/TxDeadline.sol"; import "./mixins/nftDropMarket/NFTDropMarketCore.sol"; import "./mixins/nftDropMarket/NFTDropMarketFixedPriceSale.sol"; import "./mixins/nftDropMarket/NFTDropMarketExhibition.sol"; error NFTDropMarket_NFT_Already_Minted(); /** * @title A market for minting NFTs with Foundation. * @author batu-inal & HardlyDifficult & philbirt & reggieag */ contract NFTDropMarket is TxDeadline, Initializable, FoundationTreasuryNode, Context, RouterContext, FETHNode, MarketSharedCore, NFTDropMarketCore, ReentrancyGuardUpgradeable, SendValueWithFallbackWithdraw, MarketFees, Gap500, Gap9000, NFTDropMarketExhibition, NFTDropMarketFixedPriceSale { /** * @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 royaltyRegistry The Royalty Registry contract address. * @param nftMarket The NFT Market contract address, containing exhibition definitions. * @param router The trusted router contract address. */ constructor( address payable treasury, address feth, address royaltyRegistry, address nftMarket, address router ) FoundationTreasuryNode(treasury) FETHNode(feth) MarketFees( /* protocolFeeInBasisPoints: */ 1500, royaltyRegistry, /* assumePrimarySale: */ true ) NFTDropMarketExhibition(nftMarket) RouterContext(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(); } /** * @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, NFTDropMarketFixedPriceSale) returns (address payable seller) { // Check the current owner first in case it has been sold. try IERC721(nftContract).ownerOf(tokenId) returns (address owner) { if (owner != address(0)) { // If sold, return address(0) since that owner cannot sell via this market. return payable(address(0)); } } catch { // Fall through } return super._getSellerOf(nftContract, tokenId); } /** * @inheritdoc NFTDropMarketFixedPriceSale */ function _getProtocolFee( address nftContract ) internal view override(MarketFees, NFTDropMarketFixedPriceSale) returns (uint256 protocolFeeInBasisPoints) { protocolFeeInBasisPoints = super._getProtocolFee(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); } /** * @inheritdoc RouterContext */ function _msgSender() internal view override(Context, RouterContext) returns (address sender) { sender = super._msgSender(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @author: manifold.xyz import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /** * @dev Royalty registry interface */ interface IRoyaltyRegistry is IERC165 { event RoyaltyOverride(address owner, address tokenAddress, address royaltyAddress); /** * Override the location of where to look up royalty information for a given token contract. * Allows for backwards compatibility and implementation of royalty logic for contracts that did not previously support them. * * @param tokenAddress - The token address you wish to override * @param royaltyAddress - The royalty override address */ function setRoyaltyLookupAddress(address tokenAddress, address royaltyAddress) external returns (bool); /** * Returns royalty address location. Returns the tokenAddress by default, or the override if it exists * * @param tokenAddress - The token address you are looking up the royalty for */ function getRoyaltyLookupAddress(address tokenAddress) external view returns (address); /** * Returns the token address that an overrideAddress is set for. * Note: will not be accurate if the override was created before this function was added. * * @param overrideAddress - The override address you are looking up the token for */ function getOverrideLookupTokenAddress(address overrideAddress) external view returns (address); /** * Whether or not the message sender can override the royalty address for the given token address * * @param tokenAddress - The token address you are looking up the royalty for */ function overrideAllowed(address tokenAddress) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.1) (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] * ``` * 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.8.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; import "../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 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.8.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 * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return 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 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 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.8.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 v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (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 rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the merkle tree. uint256 leavesLen = leaves.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof"); // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { return hashes[totalHashes - 1]; } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } /** * @dev Calldata version of {processMultiProof}. * * 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 rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the merkle tree. uint256 leavesLen = leaves.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof"); // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { return hashes[totalHashes - 1]; } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) { return a < b ? _efficientHash(a, b) : _efficientHash(b, a); } function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { /// @solidity memory-safe-assembly assembly { mstore(0x00, a) mstore(0x20, b) value := keccak256(0x00, 0x40) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.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}. * 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 // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.0; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing * all math on `uint256` and `int256` and then downcasting. */ library SafeCast { /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toUint248(uint256 value) internal pure returns (uint248) { require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits"); return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toUint240(uint256 value) internal pure returns (uint240) { require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits"); return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toUint232(uint256 value) internal pure returns (uint232) { require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits"); return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.2._ */ function toUint224(uint256 value) internal pure returns (uint224) { require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits"); return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toUint216(uint256 value) internal pure returns (uint216) { require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits"); return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toUint208(uint256 value) internal pure returns (uint208) { require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits"); return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toUint200(uint256 value) internal pure returns (uint200) { require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits"); return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toUint192(uint256 value) internal pure returns (uint192) { require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits"); return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toUint184(uint256 value) internal pure returns (uint184) { require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits"); return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toUint176(uint256 value) internal pure returns (uint176) { require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits"); return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toUint168(uint256 value) internal pure returns (uint168) { require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits"); return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toUint160(uint256 value) internal pure returns (uint160) { require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits"); return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toUint152(uint256 value) internal pure returns (uint152) { require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits"); return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toUint144(uint256 value) internal pure returns (uint144) { require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits"); return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toUint136(uint256 value) internal pure returns (uint136) { require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits"); return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v2.5._ */ function toUint128(uint256 value) internal pure returns (uint128) { require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toUint120(uint256 value) internal pure returns (uint120) { require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits"); return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toUint112(uint256 value) internal pure returns (uint112) { require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits"); return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toUint104(uint256 value) internal pure returns (uint104) { require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits"); return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.2._ */ function toUint96(uint256 value) internal pure returns (uint96) { require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits"); return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toUint88(uint256 value) internal pure returns (uint88) { require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits"); return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toUint80(uint256 value) internal pure returns (uint80) { require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits"); return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toUint72(uint256 value) internal pure returns (uint72) { require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits"); return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v2.5._ */ function toUint64(uint256 value) internal pure returns (uint64) { require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toUint56(uint256 value) internal pure returns (uint56) { require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits"); return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toUint48(uint256 value) internal pure returns (uint48) { require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits"); return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toUint40(uint256 value) internal pure returns (uint40) { require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits"); return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v2.5._ */ function toUint32(uint256 value) internal pure returns (uint32) { require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toUint24(uint256 value) internal pure returns (uint24) { require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits"); return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v2.5._ */ function toUint16(uint256 value) internal pure returns (uint16) { require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits"); return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v2.5._ */ function toUint8(uint256 value) internal pure returns (uint8) { require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits"); return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. * * _Available since v3.0._ */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); require(downcasted == value, "SafeCast: value doesn't fit in 248 bits"); } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); require(downcasted == value, "SafeCast: value doesn't fit in 240 bits"); } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); require(downcasted == value, "SafeCast: value doesn't fit in 232 bits"); } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.7._ */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); require(downcasted == value, "SafeCast: value doesn't fit in 224 bits"); } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); require(downcasted == value, "SafeCast: value doesn't fit in 216 bits"); } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); require(downcasted == value, "SafeCast: value doesn't fit in 208 bits"); } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); require(downcasted == value, "SafeCast: value doesn't fit in 200 bits"); } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); require(downcasted == value, "SafeCast: value doesn't fit in 192 bits"); } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); require(downcasted == value, "SafeCast: value doesn't fit in 184 bits"); } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); require(downcasted == value, "SafeCast: value doesn't fit in 176 bits"); } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); require(downcasted == value, "SafeCast: value doesn't fit in 168 bits"); } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); require(downcasted == value, "SafeCast: value doesn't fit in 160 bits"); } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); require(downcasted == value, "SafeCast: value doesn't fit in 152 bits"); } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); require(downcasted == value, "SafeCast: value doesn't fit in 144 bits"); } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); require(downcasted == value, "SafeCast: value doesn't fit in 136 bits"); } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v3.1._ */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); require(downcasted == value, "SafeCast: value doesn't fit in 128 bits"); } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); require(downcasted == value, "SafeCast: value doesn't fit in 120 bits"); } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); require(downcasted == value, "SafeCast: value doesn't fit in 112 bits"); } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); require(downcasted == value, "SafeCast: value doesn't fit in 104 bits"); } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.7._ */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); require(downcasted == value, "SafeCast: value doesn't fit in 96 bits"); } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); require(downcasted == value, "SafeCast: value doesn't fit in 88 bits"); } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); require(downcasted == value, "SafeCast: value doesn't fit in 80 bits"); } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); require(downcasted == value, "SafeCast: value doesn't fit in 72 bits"); } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v3.1._ */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); require(downcasted == value, "SafeCast: value doesn't fit in 64 bits"); } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); require(downcasted == value, "SafeCast: value doesn't fit in 56 bits"); } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); require(downcasted == value, "SafeCast: value doesn't fit in 48 bits"); } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); require(downcasted == value, "SafeCast: value doesn't fit in 40 bits"); } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v3.1._ */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); require(downcasted == value, "SafeCast: value doesn't fit in 32 bits"); } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); require(downcasted == value, "SafeCast: value doesn't fit in 24 bits"); } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v3.1._ */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); require(downcasted == value, "SafeCast: value doesn't fit in 16 bits"); } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v3.1._ */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); require(downcasted == value, "SafeCast: value doesn't fit in 8 bits"); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. * * _Available since v3.0._ */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256"); return int256(value); } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.12; /** * @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.12; /** * @title Declares the type of the collection contract. * @dev This interface is declared as an ERC-165 interface. * @author reggieag */ interface INFTCollectionType { function getNFTCollectionType() external view returns (string memory collectionType); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.12; /** * @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.12; /** * @notice The required interface for collections in the NFTDropMarket to support exhibitions. * @author philbirt */ interface INFTMarketExhibition { function isAllowedSellerForExhibition( uint256 exhibitionId, address seller ) external view returns (bool allowedSeller); function getExhibitionPaymentDetails( uint256 exhibitionId ) external view returns (address payable curator, uint16 takeRateInBasisPoints); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.12; /** * @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.12; /** * @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.12; /** * @title Interface for routing calls to the NFT Drop Market to create fixed price sales. * @author HardlyDifficult & reggieag */ interface INFTDropMarketFixedPriceSale { function createFixedPriceSaleV3( address nftContract, uint256 exhibitionId, uint256 price, uint256 limitPerAccount, uint256 generalAvailabilityStartTime, uint256 txDeadlineTime ) external; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.12; /** * @notice An interface for communicating fees to 3rd party marketplaces. * @dev Originally implemented in mainnet contract 0x44d6e8933f8271abcf253c72f9ed7e0e4c0323b3 */ interface IGetFees { /** * @notice Get the recipient addresses to which creator royalties should be sent. * @dev The expected royalty amounts are communicated with `getFeeBps`. * @param tokenId The ID of the NFT to get royalties for. * @return recipients An array of addresses to which royalties should be sent. */ function getFeeRecipients(uint256 tokenId) external view returns (address payable[] memory recipients); /** * @notice Get the creator royalty amounts to be sent to each recipient, in basis points. * @dev The expected recipients are communicated with `getFeeRecipients`. * @param tokenId The ID of the NFT to get royalties for. * @return royaltiesInBasisPoints The array of fees to be sent to each recipient, in basis points. */ function getFeeBps(uint256 tokenId) external view returns (uint256[] memory royaltiesInBasisPoints); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.12; interface IGetRoyalties { /** * @notice Get the creator royalties to be sent. * @dev The data is the same as when calling `getFeeRecipients` and `getFeeBps` separately. * @param tokenId The ID of the NFT to get royalties for. * @return recipients An array of addresses to which royalties should be sent. * @return royaltiesInBasisPoints The array of fees to be sent to each recipient, in basis points. */ function getRoyalties( uint256 tokenId ) external view returns (address payable[] memory recipients, uint256[] memory royaltiesInBasisPoints); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.12; interface IOwnable { /** * @dev Returns the address of the current owner. */ function owner() external view returns (address); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.12; /** * @notice Interface for EIP-2981: NFT Royalty Standard. * For more see: https://eips.ethereum.org/EIPS/eip-2981. */ interface IRoyaltyInfo { /** * @notice Get the creator royalties to be sent. * @param tokenId The ID of the NFT to get royalties for. * @param salePrice The total price of the sale. * @return receiver The address to which royalties should be sent. * @return royaltyAmount The total amount that should be sent to the `receiver`. */ function royaltyInfo( uint256 tokenId, uint256 salePrice ) external view returns (address receiver, uint256 royaltyAmount); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.12; interface ITokenCreator { /** * @notice Returns the creator of this NFT collection. * @param tokenId The ID of the NFT to get the creator payment address for. * @return creator The creator of this collection. */ function tokenCreator(uint256 tokenId) external view returns (address payable creator); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.12; /** * @title Helper functions for arrays. * @author batu-inal & HardlyDifficult */ library ArrayLibrary { /** * @notice Reduces the size of an array if it's greater than the specified max size, * using the first maxSize elements. */ function capLength(address payable[] memory data, uint256 maxLength) internal pure { if (data.length > maxLength) { assembly { mstore(data, maxLength) } } } /** * @notice Reduces the size of an array if it's greater than the specified max size, * using the first maxSize elements. */ function capLength(uint256[] memory data, uint256 maxLength) internal pure { if (data.length > maxLength) { assembly { mstore(data, maxLength) } } } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.12; 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.12; /** * @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.12; /** * @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 { /** * @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.12; import "@openzeppelin/contracts/utils/Context.sol"; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import "../../interfaces/internal/INFTMarketExhibition.sol"; error NFTDropMarketExhibition_Exhibition_Does_Not_Exist(); error NFTDropMarketExhibition_NFT_Market_Is_Not_A_Contract(); error NFTDropMarketExhibition_Seller_Not_Allowed_In_Exhibition(); /** * @title Enables a curation surface for sellers to exhibit their NFTs in the drop market. * @author HardlyDifficult & philbirt */ abstract contract NFTDropMarketExhibition is Context { using AddressUpgradeable for address; /// @notice Maps a collection to the exhibition it was listed with. mapping(address => uint256) private nftContractToExhibitionId; /// @notice The NFT Market contract address, containing exhibition definitions. address private immutable _nftMarket; /** * @notice Emitted when a collection is added to an exhibition. * @param nftContract The contract address of the collection. * @param exhibitionId The ID of the exhibition the collection was added to. */ event CollectionAddedToExhibition(address indexed nftContract, uint256 indexed exhibitionId); /** * @notice Set immutable variables for the implementation contract. * @dev Using immutable instead of constants allows us to use different values on testnet. * @param nftMarket The NFT Market contract address, containing exhibition definitions. */ constructor(address nftMarket) { if (!nftMarket.isContract()) { revert NFTDropMarketExhibition_NFT_Market_Is_Not_A_Contract(); } _nftMarket = nftMarket; } /** * @notice Adds a collection to an exhibition, if the ID provided is not 0. */ function _addCollectionToExhibition(address nftContract, uint256 exhibitionId) internal { if (exhibitionId != 0) { // If there is an exhibition, make sure the seller is allowed to list in it if ( !INFTMarketExhibition(_nftMarket).isAllowedSellerForExhibition({ exhibitionId: exhibitionId, seller: _msgSender() }) ) { (address curator, ) = INFTMarketExhibition(_nftMarket).getExhibitionPaymentDetails(exhibitionId); if (curator == address(0)) { // Provides a more useful error when an exhibition never existed or has since been deleted. revert NFTDropMarketExhibition_Exhibition_Does_Not_Exist(); } revert NFTDropMarketExhibition_Seller_Not_Allowed_In_Exhibition(); } nftContractToExhibitionId[nftContract] = exhibitionId; emit CollectionAddedToExhibition(nftContract, exhibitionId); } } /** * @notice Returns the exhibition ID for a given Collection. * @param nftContract The contract address of the Collection. * @return exhibitionId The ID of the exhibition this Collection is assigned to, or 0 if it's * not assigned to an exhibition. */ function getExhibitionIdForCollection(address nftContract) external view returns (uint256 exhibitionId) { exhibitionId = nftContractToExhibitionId[nftContract]; } /** * @notice Returns the contract which contains the exhibition definitions. * @return nftMarket The NFT Market contract address. */ function getNftMarket() external view returns (address nftMarket) { nftMarket = _nftMarket; } /** * @notice Returns the exhibition payment details for a given Collection. * @dev The payment address and take rate will be 0 if the collection is not assigned to an exhibition or if the * exhibition has seen been deleted. */ function _getExhibitionByCollection( address nftContract ) internal view returns (address payable curator, uint16 takeRateInBasisPoints) { uint256 exhibitionId = nftContractToExhibitionId[nftContract]; if (exhibitionId != 0) { (curator, takeRateInBasisPoints) = INFTMarketExhibition(_nftMarket).getExhibitionPaymentDetails(exhibitionId); } } /** * @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.12; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import "@openzeppelin/contracts/access/IAccessControl.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts/utils/Context.sol"; import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; import "@openzeppelin/contracts/utils/math/SafeCast.sol"; import "../../interfaces/internal/INFTLazyMintedCollectionMintCountTo.sol"; import "../../interfaces/internal/routes/INFTDropMarketFixedPriceSale.sol"; import "../../libraries/MerkleAddressLibrary.sol"; import "../../libraries/TimeLibrary.sol"; import "../shared/Constants.sol"; import "../shared/MarketFees.sol"; import "../shared/TxDeadline.sol"; import "./NFTDropMarketExhibition.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_Invalid_Merkle_Root(); error NFTDropMarketFixedPriceSale_Invalid_Merkle_Tree_URI(); error NFTDropMarketFixedPriceSale_Limit_Per_Account_Must_Be_Set(); error NFTDropMarketFixedPriceSale_Mint_Permission_Required(); 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_Must_Not_Be_Sold_Out(); error NFTDropMarketFixedPriceSale_Must_Not_Have_Pending_Sale(); error NFTDropMarketFixedPriceSale_Must_Support_Collection_Mint_Interface(); error NFTDropMarketFixedPriceSale_Must_Support_ERC721(); error NFTDropMarketFixedPriceSale_Only_Callable_By_Collection_Owner(); error NFTDropMarketFixedPriceSale_Start_Time_Too_Far_In_The_Future(); /// @param mintCost The total cost for this purchase. error NFTDropMarketFixedPriceSale_Too_Much_Value_Provided(uint256 mintCost); /** * @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, MarketFees, NFTDropMarketExhibition { using AddressUpgradeable for address; using AddressUpgradeable for address payable; using ERC165Checker for address; 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; /** * @dev Protocol fee for edition mints in basis points. */ uint256 private constant EDITION_PROTOCOL_FEE_IN_BASIS_POINTS = 500; /** * @notice Hash of the edition type name. * @dev This is precalculated in order to save gas on use. * `keccak256(abi.encodePacked(NFT_TIMED_EDITION_COLLECTION_TYPE))` */ bytes32 private constant editionTypeHash = 0xee2afa3f960e108aca17013728aafa363a0f4485661d9b6f41c6b4ddb55008ee; /** * @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"); /** * @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 ); /// @notice Requires the given NFT contract can mint at least 1 more NFT. modifier notSoldOut(address nftContract) { if (INFTLazyMintedCollectionMintCountTo(nftContract).numberOfTokensAvailableToMint() == 0) { revert NFTDropMarketFixedPriceSale_Must_Not_Be_Sold_Out(); } _; } /// @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 NFTDropMarketFixedPriceSale_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 NFTDropMarketFixedPriceSale_Must_Support_Collection_Mint_Interface(); } if (!nftContract.supportsERC165InterfaceUnchecked(type(IERC721).interfaceId)) { // Must be an ERC-721 NFT collection. revert NFTDropMarketFixedPriceSale_Must_Support_ERC721(); } if (!IAccessControl(nftContract).hasRole(MINTER_ROLE, address(this))) { revert NFTDropMarketFixedPriceSale_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 NFTDropMarketFixedPriceSale_Invalid_Merkle_Root(); } if (bytes(merkleTreeUri).length == 0) { revert NFTDropMarketFixedPriceSale_Invalid_Merkle_Tree_URI(); } _; } /// @notice Requires that the time provided is not more than 2 years in the future. modifier onlyValidStartTime(uint256 startTime) { if (startTime > block.timestamp + MAX_SCHEDULED_TIME_IN_THE_FUTURE) { // Prevent arbitrarily large values from accidentally being set. revert NFTDropMarketFixedPriceSale_Start_Time_Too_Far_In_The_Future(); } _; } /** * @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 [DEPRECATED] use `createFixedPriceSaleV3` instead. * Create a fixed price sale drop without 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. * @dev Notes: * a) The sale is final and can not be updated or canceled. * b) The sale is immediately kicked off. * c) Any collection that abides by `INFTLazyMintedCollectionMintCountTo` and `IAccessControl` is supported. */ function createFixedPriceSale(address nftContract, uint80 price, uint16 limitPerAccount) external { _createFixedPriceSale({ nftContract: nftContract, exhibitionId: 0, price: price, limitPerAccount: limitPerAccount, generalAvailabilityStartTime: block.timestamp, earlyAccessStartTime: block.timestamp, merkleRoot: bytes32(0), merkleTreeUri: "" }); } /** * @notice [DEPRECATED] use `createFixedPriceSaleV3` instead. * 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 createFixedPriceSaleV2( address nftContract, uint256 price, uint256 limitPerAccount, uint256 generalAvailabilityStartTime, uint256 txDeadlineTime ) external { createFixedPriceSaleV3({ nftContract: nftContract, exhibitionId: 0, price: price, limitPerAccount: limitPerAccount, generalAvailabilityStartTime: generalAvailabilityStartTime, txDeadlineTime: txDeadlineTime }); } /** * @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 exhibitionId The exhibition to associate this fix priced sale to. * Set this to 0 to exist outside of an exhibition. * @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 createFixedPriceSaleV3( address nftContract, uint256 exhibitionId, uint256 price, uint256 limitPerAccount, uint256 generalAvailabilityStartTime, uint256 txDeadlineTime ) public 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, exhibitionId: exhibitionId, price: price, limitPerAccount: limitPerAccount, generalAvailabilityStartTime: generalAvailabilityStartTime, earlyAccessStartTime: generalAvailabilityStartTime, merkleRoot: bytes32(0), merkleTreeUri: "" }); } /** * @notice [DEPRECATED] use `createFixedPriceSaleWithEarlyAccessAllowlistV2` instead. * 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 { createFixedPriceSaleWithEarlyAccessAllowlistV2({ nftContract: nftContract, exhibitionId: 0, price: price, limitPerAccount: limitPerAccount, generalAvailabilityStartTime: generalAvailabilityStartTime, earlyAccessStartTime: earlyAccessStartTime, merkleRoot: merkleRoot, merkleTreeUri: merkleTreeUri, txDeadlineTime: txDeadlineTime }); } /** * @notice Create a fixed price sale drop with an early access period. * @param nftContract The address of the NFT drop collection. * @param exhibitionId The exhibition to associate this fix priced sale to. * Set this to 0 to exist outside of an exhibition. * @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 createFixedPriceSaleWithEarlyAccessAllowlistV2( address nftContract, uint256 exhibitionId, uint256 price, uint256 limitPerAccount, uint256 generalAvailabilityStartTime, uint256 earlyAccessStartTime, bytes32 merkleRoot, string calldata merkleTreeUri, uint256 txDeadlineTime ) public 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, exhibitionId, price, limitPerAccount, generalAvailabilityStartTime, earlyAccessStartTime, merkleRoot, merkleTreeUri ); } /** * @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 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 msg.sender's available FETH token balance will be used. */ function mintFromFixedPriceSale( address nftContract, uint16 count, address payable buyReferrer ) external payable 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, buyReferrer); } /** * @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 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 msg.sender's available FETH token balance will be used. */ function mintFromFixedPriceSaleWithEarlyAccessAllowlist( address nftContract, uint256 count, address payable buyReferrer, bytes32[] calldata proof ) external payable 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 = _msgSender().getMerkleRootForAddress(proof); if (!saleConfig.earlyAccessMerkleRoots[root]) { revert NFTDropMarketFixedPriceSale_Invalid_Merkle_Proof(); } } firstTokenId = _mintFromFixedPriceSale(saleConfig, nftContract, count, buyReferrer); } function _createFixedPriceSale( address nftContract, uint256 exhibitionId, uint256 price, uint256 limitPerAccount, uint256 generalAvailabilityStartTime, uint256 earlyAccessStartTime, bytes32 merkleRoot, string memory merkleTreeUri ) private onlySupportedCollectionType(nftContract) notSoldOut(nftContract) onlyCollectionAdmin(nftContract) onlyValidStartTime(generalAvailabilityStartTime) { // 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]; if (saleConfig.seller != payable(0)) { revert NFTDropMarketFixedPriceSale_Must_Not_Have_Pending_Sale(); } // 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 onlyValidStartTime 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; } _addCollectionToExhibition(nftContract, exhibitionId); emit CreateFixedPriceSale({ nftContract: nftContract, seller: sender, price: price, limitPerAccount: limitPerAccount, generalAvailabilityStartTime: generalAvailabilityStartTime, earlyAccessStartTime: earlyAccessStartTime, merkleRoot: merkleRoot, merkleTreeUri: merkleTreeUri }); } function _mintFromFixedPriceSale( FixedPriceSaleConfig storage saleConfig, address nftContract, uint256 count, address payable buyReferrer ) private returns (uint256 firstTokenId) { // Validate input params. if (count == 0) { revert NFTDropMarketFixedPriceSale_Must_Buy_At_Least_One_Token(); } // Confirm that the buyer will not exceed the limit specified after minting. address sender = _msgSender(); uint256 minted = saleConfig.userToMintedCount[sender] + 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[sender] = minted; // Calculate the total cost, considering the `count` requested. uint256 mintCost; unchecked { // Can not overflow as 2^80 * 2^16 == 2^96 max which fits in 256 bits. mintCost = uint256(saleConfig.price) * count; } // The sale price is immutable so the buyer is aware of how much they will be paying when their tx is broadcasted. if (msg.value > mintCost) { // Since price is known ahead of time, if too much ETH is sent then something went wrong. revert NFTDropMarketFixedPriceSale_Too_Much_Value_Provided(mintCost); } // Withdraw from the user's available FETH balance if insufficient msg.value was included. _tryUseFETHBalance({ totalAmount: mintCost, shouldRefundSurplus: false }); // Mint the NFTs. // Safe cast is not required, above confirms count <= limitPerAccount which is uint16. firstTokenId = INFTLazyMintedCollectionMintCountTo(nftContract).mintCountTo(uint16(count), sender); (address payable curator, uint16 takeRateInBasisPoints) = _getExhibitionByCollection(nftContract); // Distribute revenue from this sale. (uint256 totalFees, uint256 creatorRev, ) = _distributeFunds({ nftContract: nftContract, tokenId: firstTokenId, seller: saleConfig.seller, price: mintCost, buyReferrer: buyReferrer, sellerReferrerPaymentAddress: curator, sellerReferrerTakeRateInBasisPoints: takeRateInBasisPoints }); emit MintFromFixedPriceDrop({ nftContract: nftContract, buyer: sender, firstTokenId: firstTokenId, count: count, totalFees: totalFees, creatorRev: creatorRev }); } /** * @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, , ) = getFixedPriceSale( 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 getFixedPriceSale( address nftContract ) public view returns ( address payable seller, uint256 price, uint256 limitPerAccount, uint256 numberOfTokensAvailableToMint, bool marketCanMint, uint256 generalAvailabilityStartTime, uint256 earlyAccessStartTime ) { 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; } 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 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 MarketFees * @dev Offers a reduced protocol fee for NFT edition collection sales. */ function _getProtocolFee( address nftContract ) internal view virtual override returns (uint256 protocolFeeInBasisPoints) { try INFTCollectionType(nftContract).getNFTCollectionType() returns (string memory nftCollectionType) { if (keccak256(abi.encodePacked(nftCollectionType)) == editionTypeHash) { return EDITION_PROTOCOL_FEE_IN_BASIS_POINTS; } } catch { // Fall through to use the default fee of 15% instead. // If the collection implements a fallback function, decoding will revert and cause the sale to fail. } return super._getProtocolFee(nftContract); } /** * @inheritdoc MarketSharedCore * @dev Returns the seller for a collection if listed and not already sold out. */ function _getSellerOf( address nftContract, uint256 /* tokenId */ ) internal view virtual override returns (address payable seller) { (seller, , , , , , ) = getFixedPriceSale(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.12; /// 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 an exhibition can have. */ uint256 constant MAX_EXHIBITION_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 10%, expressed as a denominator for more efficient calculations. */ uint256 constant ROYALTY_RATIO = BASIS_POINTS / ROYALTY_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 edition collection type. */ string constant NFT_TIMED_EDITION_COLLECTION_TYPE = "NFT Timed 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;
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.12; import "@openzeppelin/contracts/utils/Context.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 Context { using AddressUpgradeable for address; using AddressUpgradeable for address payable; /// @notice The FETH ERC-20 token for managing escrow and lockup. IFethMarket internal immutable feth; 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. */ 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 (shouldRefundSurplus && totalAmount < msg.value) { // Return any surplus ETH to the user. unchecked { // The if above ensures this will not underflow payable(_msgSender()).sendValue(msg.value - 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.12; 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 A mixin that stores a reference to the Foundation treasury contract. * @notice The treasury collects fees and defines admin/operator roles. * @author batu-inal & HardlyDifficult */ abstract contract FoundationTreasuryNode { 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 */ uint256[2_000] private __gap; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.12; /** * @title A placeholder contract leaving room for new mixins to be added to the future. * @author HardlyDifficult */ abstract contract Gap500 { /** * @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[500] private __gap; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.12; /** * @title A placeholder contract leaving room for new mixins to be added to the future. * @author HardlyDifficult */ abstract contract Gap9000 { /** * @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[9_000] private __gap; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.12; import "@openzeppelin/contracts/utils/Context.sol"; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; import "@manifoldxyz/royalty-registry-solidity/contracts/IRoyaltyRegistry.sol"; import "../../interfaces/internal/INFTCollectionType.sol"; import "../../interfaces/standards/royalties/IGetFees.sol"; import "../../interfaces/standards/royalties/IGetRoyalties.sol"; import "../../interfaces/standards/royalties/IOwnable.sol"; import "../../interfaces/standards/royalties/IRoyaltyInfo.sol"; import "../../interfaces/standards/royalties/ITokenCreator.sol"; import "../../libraries/ArrayLibrary.sol"; import "./Constants.sol"; import "./FoundationTreasuryNode.sol"; import "./SendValueWithFallbackWithdraw.sol"; import "./MarketSharedCore.sol"; error NFTMarketFees_Royalty_Registry_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 FoundationTreasuryNode, Context, MarketSharedCore, SendValueWithFallbackWithdraw { using AddressUpgradeable for address; using ArrayLibrary for address payable[]; using ArrayLibrary for uint256[]; using ERC165Checker for address; /** * @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 The royalties sent to creator recipients on secondary sales. uint256 private constant CREATOR_ROYALTY_DENOMINATOR = BASIS_POINTS / 1_000; // 10% /// @notice The fee collected by Foundation for sales facilitated by this market contract. uint256 private immutable DEFAULT_PROTOCOL_FEE_IN_BASIS_POINTS; /// @notice The fee collected by the buy referrer for sales facilitated by this market contract. /// This fee is calculated from the total protocol fee. uint256 private constant BUY_REFERRER_FEE_DENOMINATOR = BASIS_POINTS / 100; // 1% /// @notice The address of the royalty registry which may be used to define royalty overrides for some collections. IRoyaltyRegistry private immutable royaltyRegistry; /// @notice The address of this contract's implementation. /// @dev This is used when making stateless external calls to this contract, /// saving gas over hopping through the proxy which is only necessary when accessing state. MarketFees private immutable implementationAddress; /// @notice True for the Drop market which only performs primary sales. False if primary & secondary are supported. bool private immutable assumePrimarySale; /** * @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 Configures the registry allowing for royalty overrides to be defined. * @param _royaltyRegistry The registry to use for royalty overrides. * @param _assumePrimarySale True for the Drop market which only performs primary sales. * False if primary & secondary are supported. */ constructor(uint16 protocolFeeInBasisPoints, address _royaltyRegistry, bool _assumePrimarySale) { if ( protocolFeeInBasisPoints < BASIS_POINTS / BUY_REFERRER_FEE_DENOMINATOR || protocolFeeInBasisPoints + BASIS_POINTS / CREATOR_ROYALTY_DENOMINATOR >= BASIS_POINTS - MAX_EXHIBITION_TAKE_RATE ) { /* If the protocol fee is invalid, revert: * Protocol fee must be greater than the buy referrer fee since referrer fees are deducted from the protocol fee. * The protocol fee must leave room for the creator royalties and the max exhibition take rate. */ revert NFTMarketFees_Invalid_Protocol_Fee(); } DEFAULT_PROTOCOL_FEE_IN_BASIS_POINTS = protocolFeeInBasisPoints; if (!_royaltyRegistry.isContract()) { // Not using a 165 check since mainnet and goerli are not using the same versions of the registry. revert NFTMarketFees_Royalty_Registry_Is_Not_A_Contract(); } royaltyRegistry = IRoyaltyRegistry(_royaltyRegistry); assumePrimarySale = _assumePrimarySale; // In the constructor, `this` refers to the implementation address. Everywhere else it'll be the proxy. implementationAddress = this; } /** * @notice Distributes funds to foundation, creator recipients, and NFT owner after a sale. */ function _distributeFunds( address nftContract, uint256 tokenId, address payable seller, uint256 price, address payable buyReferrer, address payable sellerReferrerPaymentAddress, uint16 sellerReferrerTakeRateInBasisPoints ) internal returns (uint256 totalFees, uint256 creatorRev, uint256 sellerRev) { if (price == 0) { // When the sale price is 0, there are no revenue to distribute. return (0, 0, 0); } address payable[] memory creatorRecipients; uint256[] memory creatorShares; uint256 buyReferrerFee; uint256 sellerReferrerFee; (totalFees, creatorRecipients, creatorShares, sellerRev, buyReferrerFee, sellerReferrerFee) = _getFees( nftContract, tokenId, seller, price, buyReferrer, sellerReferrerTakeRateInBasisPoints ); // 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(seller, sellerRev, SEND_VALUE_GAS_LIMIT_SINGLE_RECIPIENT); // Pay the protocol fee _sendValueWithFallbackWithdraw(getFoundationTreasury(), totalFees, SEND_VALUE_GAS_LIMIT_SINGLE_RECIPIENT); // Pay the buy referrer fee if (buyReferrerFee != 0) { _sendValueWithFallbackWithdraw(buyReferrer, buyReferrerFee, SEND_VALUE_GAS_LIMIT_SINGLE_RECIPIENT); emit BuyReferralPaid({ nftContract: nftContract, tokenId: tokenId, buyReferrer: 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 price for events totalFees += buyReferrerFee; } } if (sellerReferrerPaymentAddress != address(0)) { if (sellerReferrerFee != 0) { // Add the seller referrer fee back to revenue so that all 3 return fields sum to the total price for events. 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( sellerReferrerPaymentAddress, sellerReferrerFee, SEND_VALUE_GAS_LIMIT_SINGLE_RECIPIENT ); } emit SellerReferralPaid(nftContract, tokenId, sellerReferrerPaymentAddress, sellerReferrerFee); } } /** * @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)`. */ 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 registry allowing for royalty configuration overrides. * @dev See https://royaltyregistry.xyz/ * @return registry The address of the royalty registry contract. */ function getRoyaltyRegistry() external view returns (address registry) { registry = address(royaltyRegistry); } /** * @notice **For internal use only.** * @dev This function is external to allow using try/catch but is not intended for external use. * This checks the token creator. */ function internalGetTokenCreator( address nftContract, uint256 tokenId ) external view returns (address payable creator) { creator = ITokenCreator(nftContract).tokenCreator{ gas: READ_ONLY_GAS_LIMIT }(tokenId); } /** * @notice **For internal use only.** * @dev This function is external to allow using try/catch but is not intended for external use. * If ERC2981 royalties (or getRoyalties) are defined by the NFT contract, allow this standard to define immutable * royalties that cannot be later changed via the royalty registry. */ function internalGetImmutableRoyalties( address nftContract, uint256 tokenId ) external view returns (address payable[] memory recipients, uint256[] memory splitPerRecipientInBasisPoints) { // 1st priority: ERC-2981 if (nftContract.supportsERC165InterfaceUnchecked(type(IRoyaltyInfo).interfaceId)) { try IRoyaltyInfo(nftContract).royaltyInfo{ gas: READ_ONLY_GAS_LIMIT }(tokenId, BASIS_POINTS) returns ( address receiver, uint256 royaltyAmount ) { // Manifold contracts return (address(this), 0) when royalties are not defined // - so ignore results when the amount is 0 if (royaltyAmount > 0) { recipients = new address payable[](1); recipients[0] = payable(receiver); splitPerRecipientInBasisPoints = new uint256[](1); // The split amount is assumed to be 100% when only 1 recipient is returned return (recipients, splitPerRecipientInBasisPoints); } } catch { // Fall through } } // 2nd priority: getRoyalties if (nftContract.supportsERC165InterfaceUnchecked(type(IGetRoyalties).interfaceId)) { try IGetRoyalties(nftContract).getRoyalties{ gas: READ_ONLY_GAS_LIMIT }(tokenId) returns ( address payable[] memory _recipients, uint256[] memory recipientBasisPoints ) { if (_recipients.length != 0 && _recipients.length == recipientBasisPoints.length) { return (_recipients, recipientBasisPoints); } } catch { // Fall through } } } /** * @notice **For internal use only.** * @dev This function is external to allow using try/catch but is not intended for external use. * This checks for royalties defined in the royalty registry or via a non-standard royalty API. */ function internalGetMutableRoyalties( address nftContract, uint256 tokenId, address payable creator ) external view returns (address payable[] memory recipients, uint256[] memory splitPerRecipientInBasisPoints) { /* Overrides must support ERC-165 when registered, except for overrides defined by the registry owner. If that results in an override w/o 165 we may need to upgrade the market to support or ignore that override. */ // The registry requires overrides are not 0 and contracts when set. // If no override is set, the nftContract address is returned. try royaltyRegistry.getRoyaltyLookupAddress{ gas: READ_ONLY_GAS_LIMIT }(nftContract) returns ( address overrideContract ) { if (overrideContract != nftContract) { nftContract = overrideContract; // The functions above are repeated here if an override is set. // 3rd priority: ERC-2981 override if (nftContract.supportsERC165InterfaceUnchecked(type(IRoyaltyInfo).interfaceId)) { try IRoyaltyInfo(nftContract).royaltyInfo{ gas: READ_ONLY_GAS_LIMIT }(tokenId, BASIS_POINTS) returns ( address receiver, uint256 royaltyAmount ) { // Manifold contracts return (address(this), 0) when royalties are not defined // - so ignore results when the amount is 0 if (royaltyAmount != 0) { recipients = new address payable[](1); recipients[0] = payable(receiver); splitPerRecipientInBasisPoints = new uint256[](1); // The split amount is assumed to be 100% when only 1 recipient is returned return (recipients, splitPerRecipientInBasisPoints); } } catch { // Fall through } } // 4th priority: getRoyalties override if (recipients.length == 0 && nftContract.supportsERC165InterfaceUnchecked(type(IGetRoyalties).interfaceId)) { try IGetRoyalties(nftContract).getRoyalties{ gas: READ_ONLY_GAS_LIMIT }(tokenId) returns ( address payable[] memory _recipients, uint256[] memory recipientBasisPoints ) { if (_recipients.length != 0 && _recipients.length == recipientBasisPoints.length) { return (_recipients, recipientBasisPoints); } } catch { // Fall through } } } } catch { // Ignore out of gas errors and continue using the nftContract address } // 5th priority: getFee* from contract or override if (nftContract.supportsERC165InterfaceUnchecked(type(IGetFees).interfaceId)) { try IGetFees(nftContract).getFeeRecipients{ gas: READ_ONLY_GAS_LIMIT }(tokenId) returns ( address payable[] memory _recipients ) { if (_recipients.length != 0) { try IGetFees(nftContract).getFeeBps{ gas: READ_ONLY_GAS_LIMIT }(tokenId) returns ( uint256[] memory recipientBasisPoints ) { if (_recipients.length == recipientBasisPoints.length) { return (_recipients, recipientBasisPoints); } } catch { // Fall through } } } catch { // Fall through } } // 6th priority: tokenCreator w/ or w/o requiring 165 from contract or override if (creator != address(0)) { // Only pay the tokenCreator if there wasn't another royalty defined recipients = new address payable[](1); recipients[0] = creator; splitPerRecipientInBasisPoints = new uint256[](1); // The split amount is assumed to be 100% when only 1 recipient is returned return (recipients, splitPerRecipientInBasisPoints); } // 7th priority: owner from contract or override try IOwnable(nftContract).owner{ gas: READ_ONLY_GAS_LIMIT }() returns (address owner) { if (owner != address(0)) { // Only pay the owner if there wasn't another royalty defined recipients = new address payable[](1); recipients[0] = payable(owner); splitPerRecipientInBasisPoints = new uint256[](1); // The split amount is assumed to be 100% when only 1 recipient is returned return (recipients, splitPerRecipientInBasisPoints); } } catch { // Fall through } // If no valid payment address or creator is found, return 0 recipients } /** * @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 ) private view returns ( uint256 totalFees, address payable[] memory creatorRecipients, uint256[] memory creatorShares, uint256 sellerRev, uint256 buyReferrerFee, uint256 sellerReferrerFee ) { // Calculate the protocol fee totalFees = (price * _getProtocolFee(nftContract)) / BASIS_POINTS; address payable creator; try implementationAddress.internalGetTokenCreator(nftContract, tokenId) returns (address payable _creator) { creator = _creator; } catch { // Fall through } try implementationAddress.internalGetImmutableRoyalties(nftContract, tokenId) returns ( address payable[] memory _recipients, uint256[] memory _splitPerRecipientInBasisPoints ) { (creatorRecipients, creatorShares) = (_recipients, _splitPerRecipientInBasisPoints); } catch { // Fall through } if (creatorRecipients.length == 0) { // Check mutable royalties only if we didn't find results from the immutable API try implementationAddress.internalGetMutableRoyalties(nftContract, tokenId, creator) returns ( address payable[] memory _recipients, uint256[] memory _splitPerRecipientInBasisPoints ) { (creatorRecipients, creatorShares) = (_recipients, _splitPerRecipientInBasisPoints); } catch { // Fall through } } if (creatorRecipients.length != 0 || assumePrimarySale) { uint256 creatorRev; if (assumePrimarySale) { // All revenue should go to the creator recipients unchecked { // totalFees is always < price. creatorRev = price - totalFees; } if (creatorRecipients.length == 0) { // If no creators were found via the royalty APIs, then set that recipient to the seller's address creatorRecipients = new address payable[](1); creatorRecipients[0] = seller; creatorShares = new uint256[](1); // The split amount is assumed to be 100% when only 1 recipient is returned } } else if (seller == creator || (creatorRecipients.length != 0 && seller == creatorRecipients[0])) { // When sold by the creator, all revenue is split if applicable. unchecked { // totalFees is always < price. creatorRev = price - totalFees; } } else { // Rounding favors the owner first, then creator, and foundation last. unchecked { // Safe math is not required when dividing by a non-zero constant. creatorRev = price / CREATOR_ROYALTY_DENOMINATOR; } sellerRev = price - totalFees - creatorRev; } // Cap the max number of recipients supported creatorRecipients.capLength(MAX_ROYALTY_RECIPIENTS); creatorShares.capLength(MAX_ROYALTY_RECIPIENTS); // Calculate the seller referrer fee when some revenue is awarded to the creator if (sellerReferrerTakeRateInBasisPoints != 0) { sellerReferrerFee = (price * sellerReferrerTakeRateInBasisPoints) / BASIS_POINTS; // Subtract the seller referrer fee from the seller revenue so we do not double pay. if (sellerRev == 0) { // If the seller revenue is 0, this is a primary sale where all seller revenue is attributed to the "creator". creatorRev -= sellerReferrerFee; } else { sellerRev -= sellerReferrerFee; } } // Sum the total shares defined uint256 totalShares; if (creatorRecipients.length > 1) { unchecked { for (uint256 i = 0; i < creatorRecipients.length; ++i) { if (creatorRecipients[i] == seller) { // If the seller is any of the recipients defined, assume a primary sale creatorRev += sellerRev; sellerRev = 0; } if (totalShares != type(uint256).max) { if (creatorShares[i] > BASIS_POINTS) { // If the numbers are >100% we ignore the fee recipients and pay just the first instead totalShares = type(uint256).max; // Continue the loop in order to detect a potential primary sale condition } else { totalShares += creatorShares[i]; } } } } if (totalShares == 0 || totalShares == type(uint256).max) { // If no shares were defined or shares were out of bounds, pay only the first recipient creatorRecipients.capLength(1); creatorShares.capLength(1); } } // Send payouts to each additional recipient if more than 1 was defined uint256 totalRoyaltiesDistributed; for (uint256 i = 1; i < creatorRecipients.length; ) { uint256 royalty = (creatorRev * creatorShares[i]) / totalShares; totalRoyaltiesDistributed += royalty; creatorShares[i] = royalty; unchecked { ++i; } } // Send the remainder to the 1st creator, rounding in their favor creatorShares[0] = creatorRev - totalRoyaltiesDistributed; } else { // No royalty recipients found. unchecked { // totalFees is always < price. sellerRev = price - totalFees; } // Calculate the seller referrer fee when there is no creator royalty if (sellerReferrerTakeRateInBasisPoints != 0) { sellerReferrerFee = (price * sellerReferrerTakeRateInBasisPoints) / BASIS_POINTS; sellerRev -= sellerReferrerFee; } } if (buyReferrer != address(0) && buyReferrer != _msgSender() && buyReferrer != seller && buyReferrer != creator) { unchecked { buyReferrerFee = price / BUY_REFERRER_FEE_DENOMINATOR; // buyReferrerFee is always <= totalFees totalFees -= buyReferrerFee; } } } /** * @notice Calculates the protocol fee for the given NFT contract. * @dev This returns the contract's default fee but may be overridden to change fees based on the collection type. */ function _getProtocolFee(address /* nftContract */) internal view virtual returns (uint256 protocolFeeInBasisPoints) { protocolFeeInBasisPoints = DEFAULT_PROTOCOL_FEE_IN_BASIS_POINTS; } /** * @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[500] private __gap; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.12; 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); /** * @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[500] private __gap; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.12; import "@openzeppelin/contracts/utils/Context.sol"; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; error RouterContext_Not_A_Contract(); /** * @title Enables a trusted router contract to override the usual msg.sender address. * @author HardlyDifficult */ abstract contract RouterContext is Context { using AddressUpgradeable for address; address private immutable approvedRouter; constructor(address router) { if (!router.isContract()) { revert RouterContext_Not_A_Contract(); } approvedRouter = router; } /** * @notice Returns the router 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 Returns the sender of the transaction. * @dev If the msg.sender is the trusted router contract, then the last 20 bytes of the calldata is the authorized * sender. */ function _msgSender() internal view virtual override returns (address sender) { sender = super._msgSender(); if (sender == approvedRouter) { 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.12; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import "./FETHNode.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 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; } // 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.12; 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. }
{ "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":"royaltyRegistry","type":"address"},{"internalType":"address","name":"nftMarket","type":"address"},{"internalType":"address","name":"router","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":[],"name":"FoundationTreasuryNode_Address_Is_Not_A_Contract","type":"error"},{"inputs":[],"name":"NFTDropMarketExhibition_Exhibition_Does_Not_Exist","type":"error"},{"inputs":[],"name":"NFTDropMarketExhibition_NFT_Market_Is_Not_A_Contract","type":"error"},{"inputs":[],"name":"NFTDropMarketExhibition_Seller_Not_Allowed_In_Exhibition","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_Merkle_Root","type":"error"},{"inputs":[],"name":"NFTDropMarketFixedPriceSale_Invalid_Merkle_Tree_URI","type":"error"},{"inputs":[],"name":"NFTDropMarketFixedPriceSale_Limit_Per_Account_Must_Be_Set","type":"error"},{"inputs":[],"name":"NFTDropMarketFixedPriceSale_Mint_Permission_Required","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":"NFTDropMarketFixedPriceSale_Must_Not_Be_Sold_Out","type":"error"},{"inputs":[],"name":"NFTDropMarketFixedPriceSale_Must_Not_Have_Pending_Sale","type":"error"},{"inputs":[],"name":"NFTDropMarketFixedPriceSale_Must_Support_Collection_Mint_Interface","type":"error"},{"inputs":[],"name":"NFTDropMarketFixedPriceSale_Must_Support_ERC721","type":"error"},{"inputs":[],"name":"NFTDropMarketFixedPriceSale_Only_Callable_By_Collection_Owner","type":"error"},{"inputs":[],"name":"NFTDropMarketFixedPriceSale_Start_Time_Too_Far_In_The_Future","type":"error"},{"inputs":[{"internalType":"uint256","name":"mintCost","type":"uint256"}],"name":"NFTDropMarketFixedPriceSale_Too_Much_Value_Provided","type":"error"},{"inputs":[],"name":"NFTDropMarket_NFT_Already_Minted","type":"error"},{"inputs":[],"name":"NFTMarketFees_Invalid_Protocol_Fee","type":"error"},{"inputs":[],"name":"NFTMarketFees_Royalty_Registry_Is_Not_A_Contract","type":"error"},{"inputs":[],"name":"RouterContext_Not_A_Contract","type":"error"},{"inputs":[],"name":"TxDeadline_Tx_Deadline_Expired","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":"uint256","name":"exhibitionId","type":"uint256"}],"name":"CollectionAddedToExhibition","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":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":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":"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":"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":"uint80","name":"price","type":"uint80"},{"internalType":"uint16","name":"limitPerAccount","type":"uint16"}],"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":"txDeadlineTime","type":"uint256"}],"name":"createFixedPriceSaleV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"exhibitionId","type":"uint256"},{"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":"createFixedPriceSaleV3","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":"exhibitionId","type":"uint256"},{"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":"createFixedPriceSaleWithEarlyAccessAllowlistV2","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"}],"name":"getExhibitionIdForCollection","outputs":[{"internalType":"uint256","name":"exhibitionId","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":[],"name":"getFoundationTreasury","outputs":[{"internalType":"address payable","name":"treasuryAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNftMarket","outputs":[{"internalType":"address","name":"nftMarket","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRoyaltyRegistry","outputs":[{"internalType":"address","name":"registry","type":"address"}],"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":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"internalGetImmutableRoyalties","outputs":[{"internalType":"address payable[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"splitPerRecipientInBasisPoints","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address payable","name":"creator","type":"address"}],"name":"internalGetMutableRoyalties","outputs":[{"internalType":"address payable[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"splitPerRecipientInBasisPoints","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"internalGetTokenCreator","outputs":[{"internalType":"address payable","name":"creator","type":"address"}],"stateMutability":"view","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":"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"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
6101806040523480156200001257600080fd5b506040516200522a3803806200522a8339810160408190526200003591620002c9565b816105dc84600187858a6001600160a01b0381163b620000685760405163028bba2560e61b815260040160405180910390fd5b6001600160a01b0390811660805281163b6200009757604051633d7a0d8f60e11b815260040160405180910390fd5b6001600160a01b0390811660a05281163b620000c65760405163de58082760e01b815260040160405180910390fd5b6001600160a01b031660c052620000e160646127106200035f565b620000ef906127106200035f565b8361ffff1610806200013d57506200010c61138861271062000382565b6200011c6103e86127106200035f565b6200012a906127106200035f565b6200013a9061ffff86166200039e565b10155b156200015c57604051630567777b60e41b815260040160405180910390fd5b61ffff831660e0526001600160a01b0382163b6200018d5760405163dd78160760e01b815260040160405180910390fd5b6001600160a01b0391821661010052151561014052306101205282163b15159050620001cc57604051630e4e467360e21b815260040160405180910390fd5b6001600160a01b031661016052620001e3620001ee565b5050505050620003b4565b600054610100900460ff16156200025b5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161015620002ae576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6001600160a01b0381168114620002c657600080fd5b50565b600080600080600060a08688031215620002e257600080fd5b8551620002ef81620002b0565b60208701519095506200030281620002b0565b60408701519094506200031581620002b0565b60608701519093506200032881620002b0565b60808701519092506200033b81620002b0565b809150509295509295909350565b634e487b7160e01b600052601160045260246000fd5b6000826200037d57634e487b7160e01b600052601260045260246000fd5b500490565b8181038181111562000398576200039862000349565b92915050565b8082018082111562000398576200039862000349565b60805160a05160c05160e05161010051610120516101405161016051614dbc6200046e600039600081816104bb015281816135520152818161365e0152613aaa015260008181612af80152612b210152600081816128980152818161296d0152612a5b015260008181610535015261137801526000613eee0152600081816101ac0152818161038f015281816139450152614158015260008181610347015261389d0152600081816106490152613c150152614dbc6000f3fe60806040526004361061018f5760003560e01c8063af4f5ac2116100d6578063dccdafa51161007f578063f59488d911610059578063f59488d9146105fa578063f5ec797e1461061a578063f7a2da231461063a57600080fd5b8063dccdafa514610559578063ecbc9554146105c7578063efef76f8146105da57600080fd5b8063d5391393116100b0578063d5391393146104df578063d782d49114610513578063daa351d41461052657600080fd5b8063af4f5ac214610425578063bfb92b4214610445578063cafc21b3146104ac57600080fd5b80636a90a827116101385780639901261c116101125780639901261c146103b35780639d460fc6146103d3578063af1e1de3146103f357600080fd5b80636a90a827146103385780638129fc1c1461036b578063895633ba1461038057600080fd5b8063420176341161016957806342017634146102b35780634c542f77146102d35780634fca06c61461031857600080fd5b80630d7daf3e1461020a5780632657c55814610241578063387fd4af1461026157600080fd5b36610205573373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610203576040517faa39384e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b005b600080fd5b34801561021657600080fd5b5061022a61022536600461422f565b61066d565b6040516102389291906142dc565b60405180910390f35b34801561024d57600080fd5b5061020361025c366004614311565b610915565b34801561026d57600080fd5b506102a561027c36600461436b565b73ffffffffffffffffffffffffffffffffffffffff1660009081526138db602052604090205490565b604051908152602001610238565b3480156102bf57600080fd5b506102036102ce366004614388565b61094d565b3480156102df57600080fd5b506102f36102ee36600461422f565b610a13565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610238565b34801561032457600080fd5b506102f361033336600461422f565b610ab1565b34801561034457600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006102f3565b34801561037757600080fd5b50610203610abd565b34801561038c57600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006102f3565b3480156103bf57600080fd5b506102036103ce366004614416565b610c54565b3480156103df57600080fd5b506102036103ee3660046144b4565b610df3565b3480156103ff57600080fd5b5061041361040e3660046144f8565b610e09565b6040516102389695949392919061452d565b34801561043157600080fd5b506102a561044036600461458e565b610e7c565b34801561045157600080fd5b5061049c61046036600461422f565b73ffffffffffffffffffffffffffffffffffffffff9091166000908152613cc36020908152604080832093835260039093019052205460ff1690565b6040519015158152602001610238565b3480156104b857600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006102f3565b3480156104eb57600080fd5b506102a57f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b6102a56105213660046145c7565b610f0e565b34801561053257600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006102f3565b34801561056557600080fd5b5061057961057436600461436b565b611087565b6040805173ffffffffffffffffffffffffffffffffffffffff909816885260208801969096529486019390935260608501919091521515608084015260a083015260c082015260e001610238565b6102a56105d5366004614669565b61129d565b3480156105e657600080fd5b5061022a6105f53660046146a9565b61132e565b34801561060657600080fd5b506102036106153660046146e0565b611a7a565b34801561062657600080fd5b5061020361063536600461476f565b611a98565b34801561064657600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006102f3565b6060806106b073ffffffffffffffffffffffffffffffffffffffff85167f2a55205a00000000000000000000000000000000000000000000000000000000611e43565b156107f2576040517f2a55205a00000000000000000000000000000000000000000000000000000000815260048101849052612710602482015273ffffffffffffffffffffffffffffffffffffffff851690632a55205a90619c409060440160408051808303818786fa93505050508015610766575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252610763918101906147cb565b60015b156107f25780156107ef57604080516001808252818301909252906020808301908036833701905050935081846000815181106107a5576107a5614828565b73ffffffffffffffffffffffffffffffffffffffff92909216602092830291909101820152604080516001808252818301909252918281019080368337019050509250505061090e565b50505b61083273ffffffffffffffffffffffffffffffffffffffff85167fbb3bafd600000000000000000000000000000000000000000000000000000000611e43565b1561090e576040517fbb3bafd60000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff85169063bb3bafd690619c40906024016000604051808303818786fa935050505080156108e657506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526108e39190810190614999565b60015b1561090e578151158015906108fc575080518251145b1561090b57909250905061090e565b50505b9250929050565b6109488360008469ffffffffffffffffffff168461ffff1642426000801b60405180602001604052806000815250611f0e565b505050565b808015801590610961575061096181421190565b15610998576040517fbcb9700400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826000036109a8574292506109e8565b6109b183421190565b156109e8576040517fa619834a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a0a8787878787886000801b60405180602001604052806000815250611f0e565b50505050505050565b6040517f40c1a0640000000000000000000000000000000000000000000000000000000081526004810182905260009073ffffffffffffffffffffffffffffffffffffffff8416906340c1a06490619c40906024016020604051808303818786fa158015610a85573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610aaa91906149fd565b9392505050565b6000610aaa83836125a1565b600054610100900460ff1615808015610add5750600054600160ff909116105b80610af75750303b158015610af7575060005460ff166001145b610b88576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015610be657600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b610bee612680565b8015610c5157600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b808015801590610c685750610c6881421190565b15610c9f576040517fbcb9700400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84848482610cd9576040517ff6ee573100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000819003610d14576040517feea86ac000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b88600003610d2457429850610d64565b610d2d89421190565b15610d64576040517fdddbb7cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b898910610d9d576040517f77b2af4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610de38e8e8e8e8e8e8e8e8e8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611f0e92505050565b5050505050505050505050505050565b610e028560008686868661094d565b5050505050565b600080606080600080610e1c8989612721565b9050610e2d8989838a60008061281c565b5093995091965094509250600090505b8351811015610e6f57838181518110610e5857610e58614828565b602002602001015186019550806001019050610e3d565b5093975093979195509350565b600080600080610e8b86611087565b5050945094509450505080610ea65760009350505050610f08565b73ffffffffffffffffffffffffffffffffffffffff8087166000908152613cc3602090815260408083209389168352600190930190522054838110610ef2576000945050505050610f08565b808403945082851115610f03578294505b505050505b92915050565b73ffffffffffffffffffffffffffffffffffffffff85166000908152613cc360205260408120600281015463ffffffff16421015611070576002810154640100000000900463ffffffff16421015610ff557600281015463ffffffff8082166401000000009092041603610fae576040517f77b2af4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60028101546040517f8ba20e6800000000000000000000000000000000000000000000000000000000815264010000000090910463ffffffff166004820152602401610b7f565b60006110218585611004612fff565b73ffffffffffffffffffffffffffffffffffffffff16919061300e565b600081815260038401602052604090205490915060ff1661106e576040517ff88937c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b61107c81888888613088565b979650505050505050565b60008060008060008060008773ffffffffffffffffffffffffffffffffffffffff16638ae3e5f16040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611117575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261111491810190614a1a565b60015b15611292578015611290576040517f91d148540000000000000000000000000000000000000000000000000000000081527f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6600482015230602482015273ffffffffffffffffffffffffffffffffffffffff8a16906391d1485490604401602060405180830381865afa9250505080156111ec575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526111e991810190614a33565b60015b156112905773ffffffffffffffffffffffffffffffffffffffff8a81166000908152613cc36020526040902080546002909101549181169a5074010000000000000000000000000000000000000000810469ffffffffffffffffffff1699507e01000000000000000000000000000000000000000000000000000000000000900461ffff169750919550935063ffffffff8082169350640100000000909104169050835b505b919395979092949650565b73ffffffffffffffffffffffffffffffffffffffff83166000908152613cc360205260408120600281015463ffffffff164210156113155760028101546040517f26763e5a00000000000000000000000000000000000000000000000000000000815263ffffffff9091166004820152602401610b7f565b61132581868661ffff1686613088565b95945050505050565b6040517fde5488af00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015260609182917f0000000000000000000000000000000000000000000000000000000000000000169063de5488af90619c40906024016020604051808303818786fa935050505080156113fe575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526113fb918101906149fd565b60015b156116e6578573ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146116e45794508461147973ffffffffffffffffffffffffffffffffffffffff82167f2a55205a00000000000000000000000000000000000000000000000000000000611e43565b156115bc576040517f2a55205a00000000000000000000000000000000000000000000000000000000815260048101869052612710602482015273ffffffffffffffffffffffffffffffffffffffff871690632a55205a90619c409060440160408051808303818786fa9350505050801561152f575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261152c918101906147cb565b60015b156115bc5780156115b9576040805160018082528183019092529060208083019080368337019050509450818560008151811061156e5761156e614828565b73ffffffffffffffffffffffffffffffffffffffff92909216602092830291909101820152604080516001808252818301909252918281019080368337019050509350505050611a72565b50505b8251158015611606575061160673ffffffffffffffffffffffffffffffffffffffff87167fbb3bafd600000000000000000000000000000000000000000000000000000000611e43565b156116e4576040517fbb3bafd60000000000000000000000000000000000000000000000000000000081526004810186905273ffffffffffffffffffffffffffffffffffffffff87169063bb3bafd690619c40906024016000604051808303818786fa935050505080156116ba57506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526116b79190810190614999565b60015b156116e4578151158015906116d0575080518251145b156116e1579093509150611a729050565b50505b505b61172673ffffffffffffffffffffffffffffffffffffffff86167fb779958400000000000000000000000000000000000000000000000000000000611e43565b156118b1576040517fb9c4d9fb0000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff86169063b9c4d9fb90619c40906024016000604051808303818786fa935050505080156117da57506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526117d79190810190614a55565b60015b156118b1578051156118af576040517f0ebd4c7f0000000000000000000000000000000000000000000000000000000081526004810186905273ffffffffffffffffffffffffffffffffffffffff871690630ebd4c7f90619c40906024016000604051808303818786fa9350505050801561189557506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526118929190810190614a92565b60015b156118af5780518251036118ad579092509050611a72565b505b505b73ffffffffffffffffffffffffffffffffffffffff831615611949576040805160018082528183019092529060208083019080368337019050509150828260008151811061190157611901614828565b73ffffffffffffffffffffffffffffffffffffffff92909216602092830291909101820152604080516001808252818301909252918281019080368337019050509050611a72565b8473ffffffffffffffffffffffffffffffffffffffff16638da5cb5b619c406040518263ffffffff1660e01b81526004016020604051808303818786fa935050505080156119d2575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526119cf918101906149fd565b60015b15611a725773ffffffffffffffffffffffffffffffffffffffff811615611a705760408051600180825281830190925290602080830190803683370190505092508083600081518110611a2757611a27614828565b73ffffffffffffffffffffffffffffffffffffffff9290921660209283029190910182015260408051600180825281830190925291828101908036833701905050915050611a72565b505b935093915050565b611a8d8960008a8a8a8a8a8a8a8a610c54565b505050505050505050565b838073ffffffffffffffffffffffffffffffffffffffff16638ae3e5f16040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ae4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b089190614a1a565b600003611b41576040517f31bf2c0f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8473ffffffffffffffffffffffffffffffffffffffff81166391d148546000611b68612fff565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925273ffffffffffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa158015611bd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bfb9190614a33565b611c31576040517ff4678ab600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84848482611c6b576040517ff6ee573100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000819003611ca6576040517feea86ac000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff89166000908152613cc360205260409020600281015463ffffffff164210611d5d57805473ffffffffffffffffffffffffffffffffffffffff16611d2b576040517f974bcaec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ff2279aef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600281015463ffffffff64010000000082048116911603611daa576040517f77b2af4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008981526003820160205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555173ffffffffffffffffffffffffffffffffffffffff8b16907f7f11be7894109a714225fbb6c33d88a14582407d653ac3fc5abf07d9b3ce891490611e2f908c908c908c90614ac7565b60405180910390a250505050505050505050565b604080517fffffffff000000000000000000000000000000000000000000000000000000008316602480830191909152825180830390910181526044909101909152602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825160009392849283928392918391908a617530fa92503d91506000519050828015611efb575060208210155b801561107c575015159695505050505050565b87611f4f73ffffffffffffffffffffffffffffffffffffffff82167f5bf6f7b8000000000000000000000000000000000000000000000000000000006133fa565b611f85576040517f27deb56b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611fc573ffffffffffffffffffffffffffffffffffffffff82167f80ac58cd00000000000000000000000000000000000000000000000000000000611e43565b611ffb576040517f88f65abf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f91d148540000000000000000000000000000000000000000000000000000000081527f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6600482015230602482015273ffffffffffffffffffffffffffffffffffffffff8216906391d1485490604401602060405180830381865afa15801561208b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120af9190614a33565b6120e5576040517f8ae605c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b888073ffffffffffffffffffffffffffffffffffffffff16638ae3e5f16040518163ffffffff1660e01b8152600401602060405180830381865afa158015612131573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121559190614a1a565b60000361218e576040517f31bf2c0f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8973ffffffffffffffffffffffffffffffffffffffff81166391d1485460006121b5612fff565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925273ffffffffffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa158015612224573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122489190614a33565b61227e576040517ff4678ab600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8661228d6303c2670042614b4a565b8111156122c6576040517f8dea773d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b88600003612300576040517f250099ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff808d166000908152613cc360205260409020805490911615612363576040517fdf55741b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061236d612fff565b82547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff821617835590506123b68c613416565b825469ffffffffffffffffffff9190911674010000000000000000000000000000000000000000027fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff90911617825561240e8b6134b6565b825461ffff919091167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909116178255428a14612497576002820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff8c161790555b4289146124d8576002820180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff1664010000000063ffffffff8c16021790555b8715612518576000888152600383016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b6125228e8e61354a565b8073ffffffffffffffffffffffffffffffffffffffff168e73ffffffffffffffffffffffffffffffffffffffff167fa4e684574cd21d7eb4df36ec6d7f86d16aa900ceddae41e4e82f8f4170f293b98e8e8e8e8e8e60405161258996959493929190614b81565b60405180910390a35050505050505050505050505050565b6040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810182905260009073ffffffffffffffffffffffffffffffffffffffff841690636352211e90602401602060405180830381865afa925050508015612649575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252612646918101906149fd565b60015b156126765773ffffffffffffffffffffffffffffffffffffffff811615612674576000915050610f08565b505b610aaa83836137b5565b600054610100900460ff16612717576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b7f565b61271f6137ce565b565b6040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810182905260009073ffffffffffffffffffffffffffffffffffffffff841690636352211e90602401602060405180830381865afa9250505080156127c9575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526127c6918101906149fd565b60015b156126765773ffffffffffffffffffffffffffffffffffffffff811615612674576040517f5ca60e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060608060008060006127106128328d61386d565b61283c908b614bf5565b6128469190614c0c565b6040517f4c542f7700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8e81166004830152602482018e90529197506000917f00000000000000000000000000000000000000000000000000000000000000001690634c542f7790604401602060405180830381865afa925050508015612919575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252612916918101906149fd565b60015b156129215790505b6040517f0d7daf3e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8e81166004830152602482018e90527f00000000000000000000000000000000000000000000000000000000000000001690630d7daf3e90604401600060405180830381865afa9250505080156129f357506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526129f09190810190614999565b60015b156129fe5790965094505b8551600003612aec576040517fefef76f800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8e81166004830152602482018e905282811660448301527f0000000000000000000000000000000000000000000000000000000000000000169063efef76f890606401600060405180830381865afa925050508015612ae157506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612ade9190810190614999565b60015b15612aec5790965094505b8551151580612b1857507f00000000000000000000000000000000000000000000000000000000000000005b15612edd5760007f000000000000000000000000000000000000000000000000000000000000000015612bd057878b0390508651600003612bcb5760408051600180825281830190925290602080830190803683370190505096508b87600081518110612b8757612b87614828565b73ffffffffffffffffffffffffffffffffffffffff929092166020928302919091018201526040805160018082528183019092529182810190803683370190505095505b612c85565b8173ffffffffffffffffffffffffffffffffffffffff168c73ffffffffffffffffffffffffffffffffffffffff161480612c5a5750865115801590612c5a575086600081518110612c2357612c23614828565b602002602001015173ffffffffffffffffffffffffffffffffffffffff168c73ffffffffffffffffffffffffffffffffffffffff16145b15612c685750868a03612c85565b50600a8a0480612c78898d614c47565b612c829190614c47565b94505b612c90876005613878565b612c9b866005613878565b61ffff891615612ce857612710612cb661ffff8b168d614bf5565b612cc09190614c0c565b925084600003612cdb57612cd48382614c47565b9050612ce8565b612ce58386614c47565b94505b6000600188511115612e365760005b8851811015612dee578d73ffffffffffffffffffffffffffffffffffffffff16898281518110612d2957612d29614828565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603612d555760009692909201915b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214612de657612710888281518110612d9157612d91614828565b60200260200101511115612dc7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9150612de6565b878181518110612dd957612dd9614828565b6020026020010151820191505b600101612cf7565b50801580612e1b57507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81145b15612e3657612e2b886001613878565b612e36876001613878565b600060015b8951811015612eab576000838a8381518110612e5957612e59614828565b602002602001015186612e6c9190614bf5565b612e769190614c0c565b9050612e828184614b4a565b9250808a8381518110612e9757612e97614828565b602090810291909101015250600101612e3b565b50612eb68184614c47565b88600081518110612ec957612ec9614828565b602002602001018181525050505050612f16565b868a03935061ffff881615612f1657612710612efd61ffff8a168c614bf5565b612f079190614c0c565b9150612f138285614c47565b93505b73ffffffffffffffffffffffffffffffffffffffff891615801590612f6e5750612f3e612fff565b73ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff1614155b8015612fa657508a73ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff1614155b8015612fde57508073ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff1614155b15612fef5760648a04925082870396505b5096509650965096509650969050565b6000613009613885565b905090565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606085901b1660208201526000908190603401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012090506113258484836138ef565b6000826000036130c4576040517f2d69aaf400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006130ce612fff565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018801602052604081205491925090613105908690614b4a565b87549091507e01000000000000000000000000000000000000000000000000000000000000900461ffff168111156131f45786547e01000000000000000000000000000000000000000000000000000000000000900461ffff16600003613198576040517f974bcaec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b86546040517ffa7c028e0000000000000000000000000000000000000000000000000000000081527e0100000000000000000000000000000000000000000000000000000000000090910461ffff166004820152602401610b7f565b73ffffffffffffffffffffffffffffffffffffffff821660009081526001880160205260409020819055865474010000000000000000000000000000000000000000900469ffffffffffffffffffff16850234811015613283576040517f9239ca9d00000000000000000000000000000000000000000000000000000000815260048101829052602401610b7f565b61328e81600061393b565b6040517fd115124900000000000000000000000000000000000000000000000000000000815261ffff8716600482015273ffffffffffffffffffffffffffffffffffffffff848116602483015288169063d1151249906044016020604051808303816000875af1158015613306573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332a9190614a1a565b935060008061333889613a4c565b8b549193509150600090819061336b908c908a9073ffffffffffffffffffffffffffffffffffffffff16888d8989613b35565b5091509150878773ffffffffffffffffffffffffffffffffffffffff168c73ffffffffffffffffffffffffffffffffffffffff167f05ebbb6b0ce7d564230ba625dd7a0e5108786b0852d6060de6099e1778203e348d86866040516133e3939291909283526020830191909152604082015260600190565b60405180910390a450505050505050949350505050565b600061340583613d9d565b8015610aaa5750610aaa8383611e43565b600069ffffffffffffffffffff8211156134b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203860448201527f30206269747300000000000000000000000000000000000000000000000000006064820152608401610b7f565b5090565b600061ffff8211156134b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203160448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610b7f565b80156137b1577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e06db9682613595612fff565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925273ffffffffffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa158015613604573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136289190614a33565b61375f576040517f55daed3e000000000000000000000000000000000000000000000000000000008152600481018290526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906355daed3e906024016040805180830381865afa1580156136b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136dd9190614c5a565b50905073ffffffffffffffffffffffffffffffffffffffff811661372d576040517f167ce11a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fa0cfce1100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660008181526138db6020526040808220849055518392917fa69ac11ca23c60fc41e8e7b0217b2da8c6290a60e39202b1a24b126f47480b4791a35b5050565b60006137c083611087565b509498975050505050505050565b600054610100900460ff16613865576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b7f565b6001610dad55565b6000610f0882613e01565b80825111156137b1579052565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001681036138ec57507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec36013560601c5b90565b600081815b848110156139325761391e8287878481811061391257613912614828565b90506020020135613f12565b91508061392a81614c89565b9150506138f4565b50949350505050565b34821115613a11577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663452f2b8f613987612fff565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff90911660048201523485036024820152604401600060405180830381600087803b1580156139f557600080fd5b505af1158015613a09573d6000803e3d6000fd5b505050505050565b808015613a1d57503482105b156137b1576137b1823403613a30612fff565b73ffffffffffffffffffffffffffffffffffffffff1690613f41565b73ffffffffffffffffffffffffffffffffffffffff811660009081526138db602052604081205481908015613b2f576040517f55daed3e000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906355daed3e906024016040805180830381865afa158015613b05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b299190614c5a565b90935091505b50915091565b600080600086600003613b5057506000915081905080613d90565b606080600080613b648e8e8e8e8e8d61281c565b8451959c509199509297509095509093509150600090600114613b8957614e20613b8e565b620334505b905060005b8551811015613c0257613bd9868281518110613bb157613bb1614828565b6020026020010151868381518110613bcb57613bcb614828565b60200260200101518461409b565b848181518110613beb57613beb614828565b602002602001015188019750806001019050613b93565b50613c108d87614e2061409b565b613c3d7f000000000000000000000000000000000000000000000000000000000000000089614e2061409b565b8215613cd257613c508b84614e2061409b565b8d8f73ffffffffffffffffffffffffffffffffffffffff167f141b92fd9766c80ab120598ea2f6be9802470ec59b5446dd9bf46214ead8d08e8d866000604051613cc59392919073ffffffffffffffffffffffffffffffffffffffff9390931683526020830191909152604082015260600190565b60405180910390a3968201965b73ffffffffffffffffffffffffffffffffffffffff8a1615613d8a578115613d175785600003613d055795810195613d0a565b948101945b613d178a83614e2061409b565b8d8f73ffffffffffffffffffffffffffffffffffffffff167f27a4dd4ff659a9e6354fb079b2208365e5b83f55c22a4150eee2bca89501cb988c85604051613d8192919073ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b60405180910390a35b50505050505b9750975097945050505050565b6000613dc9827f01ffc9a700000000000000000000000000000000000000000000000000000000611e43565b8015610f085750613dfa827fffffffff00000000000000000000000000000000000000000000000000000000611e43565b1592915050565b60008173ffffffffffffffffffffffffffffffffffffffff1663dfea951d6040518163ffffffff1660e01b8152600401600060405180830381865afa925050508015613e8d57506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052613e8a9190810190614cc1565b60015b15613eec576040517fee2afa3f960e108aca17013728aafa363a0f4485661d9b6f41c6b4ddb55008ee90613ec5908390602001614d6a565b6040516020818303038152906040528051906020012003613eea57506101f492915050565b505b7f0000000000000000000000000000000000000000000000000000000000000000610f08565b6000818310613f2e576000828152602084905260409020610aaa565b6000838152602083905260409020610aaa565b80471015613fab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610b7f565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114614005576040519150601f19603f3d011682016040523d82523d6000602084013e61400a565b606091505b5050905080610948576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610b7f565b816000036140a857505050565b60008373ffffffffffffffffffffffffffffffffffffffff16838390604051600060405180830381858888f193505050503d8060008114614105576040519150601f19603f3d011682016040523d82523d6000602084013e61410a565b606091505b5050905080614207576040517faa67c91900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063aa67c9199085906024016000604051808303818588803b15801561419d57600080fd5b505af11580156141b1573d6000803e3d6000fd5b50505050508373ffffffffffffffffffffffffffffffffffffffff167fa2201512569adb2d513531dfd69b66df50bd5cffb8c1bbe65a4611f9e1eadbd1846040516141fe91815260200190565b60405180910390a25b50505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610c5157600080fd5b6000806040838503121561424257600080fd5b823561424d8161420d565b946020939093013593505050565b600081518084526020808501945080840160005b838110156142a157815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161426f565b509495945050505050565b600081518084526020808501945080840160005b838110156142a1578151875295820195908201906001016142c0565b6040815260006142ef604083018561425b565b828103602084015261132581856142ac565b61ffff81168114610c5157600080fd5b60008060006060848603121561432657600080fd5b83356143318161420d565b9250602084013569ffffffffffffffffffff8116811461435057600080fd5b9150604084013561436081614301565b809150509250925092565b60006020828403121561437d57600080fd5b8135610aaa8161420d565b60008060008060008060c087890312156143a157600080fd5b86356143ac8161420d565b9860208801359850604088013597606081013597506080810135965060a00135945092505050565b60008083601f8401126143e657600080fd5b50813567ffffffffffffffff8111156143fe57600080fd5b60208301915083602082850101111561090e57600080fd5b6000806000806000806000806000806101208b8d03121561443657600080fd5b8a356144418161420d565b995060208b0135985060408b0135975060608b0135965060808b0135955060a08b0135945060c08b0135935060e08b013567ffffffffffffffff81111561448757600080fd5b6144938d828e016143d4565b915080945050809250506101008b013590509295989b9194979a5092959850565b600080600080600060a086880312156144cc57600080fd5b85356144d78161420d565b97602087013597506040870135966060810135965060800135945092505050565b60008060006060848603121561450d57600080fd5b83356145188161420d565b95602085013595506040909401359392505050565b86815285602082015260c06040820152600061454c60c083018761425b565b828103606084015261455e81876142ac565b91505083608083015273ffffffffffffffffffffffffffffffffffffffff831660a0830152979650505050505050565b600080604083850312156145a157600080fd5b82356145ac8161420d565b915060208301356145bc8161420d565b809150509250929050565b6000806000806000608086880312156145df57600080fd5b85356145ea8161420d565b94506020860135935060408601356146018161420d565b9250606086013567ffffffffffffffff8082111561461e57600080fd5b818801915088601f83011261463257600080fd5b81358181111561464157600080fd5b8960208260051b850101111561465657600080fd5b9699959850939650602001949392505050565b60008060006060848603121561467e57600080fd5b83356146898161420d565b9250602084013561469981614301565b915060408401356143608161420d565b6000806000606084860312156146be57600080fd5b83356146c98161420d565b92506020840135915060408401356143608161420d565b60008060008060008060008060006101008a8c0312156146ff57600080fd5b893561470a8161420d565b985060208a0135975060408a0135965060608a0135955060808a0135945060a08a0135935060c08a013567ffffffffffffffff81111561474957600080fd5b6147558c828d016143d4565b9a9d999c50979a9699959894979660e00135949350505050565b6000806000806060858703121561478557600080fd5b84356147908161420d565b935060208501359250604085013567ffffffffffffffff8111156147b357600080fd5b6147bf878288016143d4565b95989497509550505050565b600080604083850312156147de57600080fd5b82516147e98161420d565b6020939093015192949293505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561489e5761489e6147f9565b604052919050565b600067ffffffffffffffff8211156148c0576148c06147f9565b5060051b60200190565b600082601f8301126148db57600080fd5b815160206148f06148eb836148a6565b614857565b82815260059290921b8401810191818101908684111561490f57600080fd5b8286015b848110156149335780516149268161420d565b8352918301918301614913565b509695505050505050565b600082601f83011261494f57600080fd5b8151602061495f6148eb836148a6565b82815260059290921b8401810191818101908684111561497e57600080fd5b8286015b848110156149335780518352918301918301614982565b600080604083850312156149ac57600080fd5b825167ffffffffffffffff808211156149c457600080fd5b6149d0868387016148ca565b935060208501519150808211156149e657600080fd5b506149f38582860161493e565b9150509250929050565b600060208284031215614a0f57600080fd5b8151610aaa8161420d565b600060208284031215614a2c57600080fd5b5051919050565b600060208284031215614a4557600080fd5b81518015158114610aaa57600080fd5b600060208284031215614a6757600080fd5b815167ffffffffffffffff811115614a7e57600080fd5b614a8a848285016148ca565b949350505050565b600060208284031215614aa457600080fd5b815167ffffffffffffffff811115614abb57600080fd5b614a8a8482850161493e565b83815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610f0857610f08614b1b565b60005b83811015614b78578181015183820152602001614b60565b50506000910152565b86815285602082015284604082015283606082015282608082015260c060a0820152600082518060c0840152614bbe8160e0850160208701614b5d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160e001979650505050505050565b8082028115828204841417610f0857610f08614b1b565b600082614c42577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610f0857610f08614b1b565b60008060408385031215614c6d57600080fd5b8251614c788161420d565b60208401519092506145bc81614301565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614cba57614cba614b1b565b5060010190565b600060208284031215614cd357600080fd5b815167ffffffffffffffff80821115614ceb57600080fd5b818401915084601f830112614cff57600080fd5b815181811115614d1157614d116147f9565b614d4260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614857565b9150808252856020828501011115614d5957600080fd5b613932816020840160208601614b5d565b60008251614d7c818460208701614b5d565b919091019291505056fea2646970667358221220170c552b54ba2816b33c06b93307a6db77190c478c202848d08f1d0f08b119e864736f6c6343000813003300000000000000000000000067df244584b67e8c51b10ad610aaffa9a402fdb600000000000000000000000049128cf8abe9071ee24540a296b5ded3f9d50443000000000000000000000000ad2184fb5dbcfc05d8f056542fb25b04fa32a95d000000000000000000000000cda72070e455bb31c7690a170224ce43623d0b6f000000000000000000000000762340b8a40cdd5bfc3edd94265899fda345d0e3
Deployed Bytecode
0x60806040526004361061018f5760003560e01c8063af4f5ac2116100d6578063dccdafa51161007f578063f59488d911610059578063f59488d9146105fa578063f5ec797e1461061a578063f7a2da231461063a57600080fd5b8063dccdafa514610559578063ecbc9554146105c7578063efef76f8146105da57600080fd5b8063d5391393116100b0578063d5391393146104df578063d782d49114610513578063daa351d41461052657600080fd5b8063af4f5ac214610425578063bfb92b4214610445578063cafc21b3146104ac57600080fd5b80636a90a827116101385780639901261c116101125780639901261c146103b35780639d460fc6146103d3578063af1e1de3146103f357600080fd5b80636a90a827146103385780638129fc1c1461036b578063895633ba1461038057600080fd5b8063420176341161016957806342017634146102b35780634c542f77146102d35780634fca06c61461031857600080fd5b80630d7daf3e1461020a5780632657c55814610241578063387fd4af1461026157600080fd5b36610205573373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000049128cf8abe9071ee24540a296b5ded3f9d504431614610203576040517faa39384e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b005b600080fd5b34801561021657600080fd5b5061022a61022536600461422f565b61066d565b6040516102389291906142dc565b60405180910390f35b34801561024d57600080fd5b5061020361025c366004614311565b610915565b34801561026d57600080fd5b506102a561027c36600461436b565b73ffffffffffffffffffffffffffffffffffffffff1660009081526138db602052604090205490565b604051908152602001610238565b3480156102bf57600080fd5b506102036102ce366004614388565b61094d565b3480156102df57600080fd5b506102f36102ee36600461422f565b610a13565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610238565b34801561032457600080fd5b506102f361033336600461422f565b610ab1565b34801561034457600080fd5b507f000000000000000000000000762340b8a40cdd5bfc3edd94265899fda345d0e36102f3565b34801561037757600080fd5b50610203610abd565b34801561038c57600080fd5b507f00000000000000000000000049128cf8abe9071ee24540a296b5ded3f9d504436102f3565b3480156103bf57600080fd5b506102036103ce366004614416565b610c54565b3480156103df57600080fd5b506102036103ee3660046144b4565b610df3565b3480156103ff57600080fd5b5061041361040e3660046144f8565b610e09565b6040516102389695949392919061452d565b34801561043157600080fd5b506102a561044036600461458e565b610e7c565b34801561045157600080fd5b5061049c61046036600461422f565b73ffffffffffffffffffffffffffffffffffffffff9091166000908152613cc36020908152604080832093835260039093019052205460ff1690565b6040519015158152602001610238565b3480156104b857600080fd5b507f000000000000000000000000cda72070e455bb31c7690a170224ce43623d0b6f6102f3565b3480156104eb57600080fd5b506102a57f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b6102a56105213660046145c7565b610f0e565b34801561053257600080fd5b507f000000000000000000000000ad2184fb5dbcfc05d8f056542fb25b04fa32a95d6102f3565b34801561056557600080fd5b5061057961057436600461436b565b611087565b6040805173ffffffffffffffffffffffffffffffffffffffff909816885260208801969096529486019390935260608501919091521515608084015260a083015260c082015260e001610238565b6102a56105d5366004614669565b61129d565b3480156105e657600080fd5b5061022a6105f53660046146a9565b61132e565b34801561060657600080fd5b506102036106153660046146e0565b611a7a565b34801561062657600080fd5b5061020361063536600461476f565b611a98565b34801561064657600080fd5b507f00000000000000000000000067df244584b67e8c51b10ad610aaffa9a402fdb66102f3565b6060806106b073ffffffffffffffffffffffffffffffffffffffff85167f2a55205a00000000000000000000000000000000000000000000000000000000611e43565b156107f2576040517f2a55205a00000000000000000000000000000000000000000000000000000000815260048101849052612710602482015273ffffffffffffffffffffffffffffffffffffffff851690632a55205a90619c409060440160408051808303818786fa93505050508015610766575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252610763918101906147cb565b60015b156107f25780156107ef57604080516001808252818301909252906020808301908036833701905050935081846000815181106107a5576107a5614828565b73ffffffffffffffffffffffffffffffffffffffff92909216602092830291909101820152604080516001808252818301909252918281019080368337019050509250505061090e565b50505b61083273ffffffffffffffffffffffffffffffffffffffff85167fbb3bafd600000000000000000000000000000000000000000000000000000000611e43565b1561090e576040517fbb3bafd60000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff85169063bb3bafd690619c40906024016000604051808303818786fa935050505080156108e657506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526108e39190810190614999565b60015b1561090e578151158015906108fc575080518251145b1561090b57909250905061090e565b50505b9250929050565b6109488360008469ffffffffffffffffffff168461ffff1642426000801b60405180602001604052806000815250611f0e565b505050565b808015801590610961575061096181421190565b15610998576040517fbcb9700400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826000036109a8574292506109e8565b6109b183421190565b156109e8576040517fa619834a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a0a8787878787886000801b60405180602001604052806000815250611f0e565b50505050505050565b6040517f40c1a0640000000000000000000000000000000000000000000000000000000081526004810182905260009073ffffffffffffffffffffffffffffffffffffffff8416906340c1a06490619c40906024016020604051808303818786fa158015610a85573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610aaa91906149fd565b9392505050565b6000610aaa83836125a1565b600054610100900460ff1615808015610add5750600054600160ff909116105b80610af75750303b158015610af7575060005460ff166001145b610b88576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015610be657600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b610bee612680565b8015610c5157600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b808015801590610c685750610c6881421190565b15610c9f576040517fbcb9700400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84848482610cd9576040517ff6ee573100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000819003610d14576040517feea86ac000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b88600003610d2457429850610d64565b610d2d89421190565b15610d64576040517fdddbb7cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b898910610d9d576040517f77b2af4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610de38e8e8e8e8e8e8e8e8e8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611f0e92505050565b5050505050505050505050505050565b610e028560008686868661094d565b5050505050565b600080606080600080610e1c8989612721565b9050610e2d8989838a60008061281c565b5093995091965094509250600090505b8351811015610e6f57838181518110610e5857610e58614828565b602002602001015186019550806001019050610e3d565b5093975093979195509350565b600080600080610e8b86611087565b5050945094509450505080610ea65760009350505050610f08565b73ffffffffffffffffffffffffffffffffffffffff8087166000908152613cc3602090815260408083209389168352600190930190522054838110610ef2576000945050505050610f08565b808403945082851115610f03578294505b505050505b92915050565b73ffffffffffffffffffffffffffffffffffffffff85166000908152613cc360205260408120600281015463ffffffff16421015611070576002810154640100000000900463ffffffff16421015610ff557600281015463ffffffff8082166401000000009092041603610fae576040517f77b2af4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60028101546040517f8ba20e6800000000000000000000000000000000000000000000000000000000815264010000000090910463ffffffff166004820152602401610b7f565b60006110218585611004612fff565b73ffffffffffffffffffffffffffffffffffffffff16919061300e565b600081815260038401602052604090205490915060ff1661106e576040517ff88937c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b61107c81888888613088565b979650505050505050565b60008060008060008060008773ffffffffffffffffffffffffffffffffffffffff16638ae3e5f16040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611117575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261111491810190614a1a565b60015b15611292578015611290576040517f91d148540000000000000000000000000000000000000000000000000000000081527f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6600482015230602482015273ffffffffffffffffffffffffffffffffffffffff8a16906391d1485490604401602060405180830381865afa9250505080156111ec575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526111e991810190614a33565b60015b156112905773ffffffffffffffffffffffffffffffffffffffff8a81166000908152613cc36020526040902080546002909101549181169a5074010000000000000000000000000000000000000000810469ffffffffffffffffffff1699507e01000000000000000000000000000000000000000000000000000000000000900461ffff169750919550935063ffffffff8082169350640100000000909104169050835b505b919395979092949650565b73ffffffffffffffffffffffffffffffffffffffff83166000908152613cc360205260408120600281015463ffffffff164210156113155760028101546040517f26763e5a00000000000000000000000000000000000000000000000000000000815263ffffffff9091166004820152602401610b7f565b61132581868661ffff1686613088565b95945050505050565b6040517fde5488af00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015260609182917f000000000000000000000000ad2184fb5dbcfc05d8f056542fb25b04fa32a95d169063de5488af90619c40906024016020604051808303818786fa935050505080156113fe575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526113fb918101906149fd565b60015b156116e6578573ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146116e45794508461147973ffffffffffffffffffffffffffffffffffffffff82167f2a55205a00000000000000000000000000000000000000000000000000000000611e43565b156115bc576040517f2a55205a00000000000000000000000000000000000000000000000000000000815260048101869052612710602482015273ffffffffffffffffffffffffffffffffffffffff871690632a55205a90619c409060440160408051808303818786fa9350505050801561152f575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261152c918101906147cb565b60015b156115bc5780156115b9576040805160018082528183019092529060208083019080368337019050509450818560008151811061156e5761156e614828565b73ffffffffffffffffffffffffffffffffffffffff92909216602092830291909101820152604080516001808252818301909252918281019080368337019050509350505050611a72565b50505b8251158015611606575061160673ffffffffffffffffffffffffffffffffffffffff87167fbb3bafd600000000000000000000000000000000000000000000000000000000611e43565b156116e4576040517fbb3bafd60000000000000000000000000000000000000000000000000000000081526004810186905273ffffffffffffffffffffffffffffffffffffffff87169063bb3bafd690619c40906024016000604051808303818786fa935050505080156116ba57506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526116b79190810190614999565b60015b156116e4578151158015906116d0575080518251145b156116e1579093509150611a729050565b50505b505b61172673ffffffffffffffffffffffffffffffffffffffff86167fb779958400000000000000000000000000000000000000000000000000000000611e43565b156118b1576040517fb9c4d9fb0000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff86169063b9c4d9fb90619c40906024016000604051808303818786fa935050505080156117da57506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526117d79190810190614a55565b60015b156118b1578051156118af576040517f0ebd4c7f0000000000000000000000000000000000000000000000000000000081526004810186905273ffffffffffffffffffffffffffffffffffffffff871690630ebd4c7f90619c40906024016000604051808303818786fa9350505050801561189557506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526118929190810190614a92565b60015b156118af5780518251036118ad579092509050611a72565b505b505b73ffffffffffffffffffffffffffffffffffffffff831615611949576040805160018082528183019092529060208083019080368337019050509150828260008151811061190157611901614828565b73ffffffffffffffffffffffffffffffffffffffff92909216602092830291909101820152604080516001808252818301909252918281019080368337019050509050611a72565b8473ffffffffffffffffffffffffffffffffffffffff16638da5cb5b619c406040518263ffffffff1660e01b81526004016020604051808303818786fa935050505080156119d2575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526119cf918101906149fd565b60015b15611a725773ffffffffffffffffffffffffffffffffffffffff811615611a705760408051600180825281830190925290602080830190803683370190505092508083600081518110611a2757611a27614828565b73ffffffffffffffffffffffffffffffffffffffff9290921660209283029190910182015260408051600180825281830190925291828101908036833701905050915050611a72565b505b935093915050565b611a8d8960008a8a8a8a8a8a8a8a610c54565b505050505050505050565b838073ffffffffffffffffffffffffffffffffffffffff16638ae3e5f16040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ae4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b089190614a1a565b600003611b41576040517f31bf2c0f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8473ffffffffffffffffffffffffffffffffffffffff81166391d148546000611b68612fff565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925273ffffffffffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa158015611bd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bfb9190614a33565b611c31576040517ff4678ab600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84848482611c6b576040517ff6ee573100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000819003611ca6576040517feea86ac000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff89166000908152613cc360205260409020600281015463ffffffff164210611d5d57805473ffffffffffffffffffffffffffffffffffffffff16611d2b576040517f974bcaec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ff2279aef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600281015463ffffffff64010000000082048116911603611daa576040517f77b2af4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008981526003820160205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555173ffffffffffffffffffffffffffffffffffffffff8b16907f7f11be7894109a714225fbb6c33d88a14582407d653ac3fc5abf07d9b3ce891490611e2f908c908c908c90614ac7565b60405180910390a250505050505050505050565b604080517fffffffff000000000000000000000000000000000000000000000000000000008316602480830191909152825180830390910181526044909101909152602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825160009392849283928392918391908a617530fa92503d91506000519050828015611efb575060208210155b801561107c575015159695505050505050565b87611f4f73ffffffffffffffffffffffffffffffffffffffff82167f5bf6f7b8000000000000000000000000000000000000000000000000000000006133fa565b611f85576040517f27deb56b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611fc573ffffffffffffffffffffffffffffffffffffffff82167f80ac58cd00000000000000000000000000000000000000000000000000000000611e43565b611ffb576040517f88f65abf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f91d148540000000000000000000000000000000000000000000000000000000081527f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6600482015230602482015273ffffffffffffffffffffffffffffffffffffffff8216906391d1485490604401602060405180830381865afa15801561208b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120af9190614a33565b6120e5576040517f8ae605c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b888073ffffffffffffffffffffffffffffffffffffffff16638ae3e5f16040518163ffffffff1660e01b8152600401602060405180830381865afa158015612131573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121559190614a1a565b60000361218e576040517f31bf2c0f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8973ffffffffffffffffffffffffffffffffffffffff81166391d1485460006121b5612fff565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925273ffffffffffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa158015612224573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122489190614a33565b61227e576040517ff4678ab600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8661228d6303c2670042614b4a565b8111156122c6576040517f8dea773d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b88600003612300576040517f250099ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff808d166000908152613cc360205260409020805490911615612363576040517fdf55741b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061236d612fff565b82547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff821617835590506123b68c613416565b825469ffffffffffffffffffff9190911674010000000000000000000000000000000000000000027fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff90911617825561240e8b6134b6565b825461ffff919091167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909116178255428a14612497576002820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff8c161790555b4289146124d8576002820180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff1664010000000063ffffffff8c16021790555b8715612518576000888152600383016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b6125228e8e61354a565b8073ffffffffffffffffffffffffffffffffffffffff168e73ffffffffffffffffffffffffffffffffffffffff167fa4e684574cd21d7eb4df36ec6d7f86d16aa900ceddae41e4e82f8f4170f293b98e8e8e8e8e8e60405161258996959493929190614b81565b60405180910390a35050505050505050505050505050565b6040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810182905260009073ffffffffffffffffffffffffffffffffffffffff841690636352211e90602401602060405180830381865afa925050508015612649575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252612646918101906149fd565b60015b156126765773ffffffffffffffffffffffffffffffffffffffff811615612674576000915050610f08565b505b610aaa83836137b5565b600054610100900460ff16612717576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b7f565b61271f6137ce565b565b6040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810182905260009073ffffffffffffffffffffffffffffffffffffffff841690636352211e90602401602060405180830381865afa9250505080156127c9575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526127c6918101906149fd565b60015b156126765773ffffffffffffffffffffffffffffffffffffffff811615612674576040517f5ca60e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060608060008060006127106128328d61386d565b61283c908b614bf5565b6128469190614c0c565b6040517f4c542f7700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8e81166004830152602482018e90529197506000917f0000000000000000000000000faa0d8c91d16e2f2fc2fc8435ffe67a03c7c0191690634c542f7790604401602060405180830381865afa925050508015612919575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252612916918101906149fd565b60015b156129215790505b6040517f0d7daf3e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8e81166004830152602482018e90527f0000000000000000000000000faa0d8c91d16e2f2fc2fc8435ffe67a03c7c0191690630d7daf3e90604401600060405180830381865afa9250505080156129f357506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526129f09190810190614999565b60015b156129fe5790965094505b8551600003612aec576040517fefef76f800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8e81166004830152602482018e905282811660448301527f0000000000000000000000000faa0d8c91d16e2f2fc2fc8435ffe67a03c7c019169063efef76f890606401600060405180830381865afa925050508015612ae157506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612ade9190810190614999565b60015b15612aec5790965094505b8551151580612b1857507f00000000000000000000000000000000000000000000000000000000000000015b15612edd5760007f000000000000000000000000000000000000000000000000000000000000000115612bd057878b0390508651600003612bcb5760408051600180825281830190925290602080830190803683370190505096508b87600081518110612b8757612b87614828565b73ffffffffffffffffffffffffffffffffffffffff929092166020928302919091018201526040805160018082528183019092529182810190803683370190505095505b612c85565b8173ffffffffffffffffffffffffffffffffffffffff168c73ffffffffffffffffffffffffffffffffffffffff161480612c5a5750865115801590612c5a575086600081518110612c2357612c23614828565b602002602001015173ffffffffffffffffffffffffffffffffffffffff168c73ffffffffffffffffffffffffffffffffffffffff16145b15612c685750868a03612c85565b50600a8a0480612c78898d614c47565b612c829190614c47565b94505b612c90876005613878565b612c9b866005613878565b61ffff891615612ce857612710612cb661ffff8b168d614bf5565b612cc09190614c0c565b925084600003612cdb57612cd48382614c47565b9050612ce8565b612ce58386614c47565b94505b6000600188511115612e365760005b8851811015612dee578d73ffffffffffffffffffffffffffffffffffffffff16898281518110612d2957612d29614828565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603612d555760009692909201915b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214612de657612710888281518110612d9157612d91614828565b60200260200101511115612dc7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9150612de6565b878181518110612dd957612dd9614828565b6020026020010151820191505b600101612cf7565b50801580612e1b57507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81145b15612e3657612e2b886001613878565b612e36876001613878565b600060015b8951811015612eab576000838a8381518110612e5957612e59614828565b602002602001015186612e6c9190614bf5565b612e769190614c0c565b9050612e828184614b4a565b9250808a8381518110612e9757612e97614828565b602090810291909101015250600101612e3b565b50612eb68184614c47565b88600081518110612ec957612ec9614828565b602002602001018181525050505050612f16565b868a03935061ffff881615612f1657612710612efd61ffff8a168c614bf5565b612f079190614c0c565b9150612f138285614c47565b93505b73ffffffffffffffffffffffffffffffffffffffff891615801590612f6e5750612f3e612fff565b73ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff1614155b8015612fa657508a73ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff1614155b8015612fde57508073ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff1614155b15612fef5760648a04925082870396505b5096509650965096509650969050565b6000613009613885565b905090565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606085901b1660208201526000908190603401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012090506113258484836138ef565b6000826000036130c4576040517f2d69aaf400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006130ce612fff565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018801602052604081205491925090613105908690614b4a565b87549091507e01000000000000000000000000000000000000000000000000000000000000900461ffff168111156131f45786547e01000000000000000000000000000000000000000000000000000000000000900461ffff16600003613198576040517f974bcaec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b86546040517ffa7c028e0000000000000000000000000000000000000000000000000000000081527e0100000000000000000000000000000000000000000000000000000000000090910461ffff166004820152602401610b7f565b73ffffffffffffffffffffffffffffffffffffffff821660009081526001880160205260409020819055865474010000000000000000000000000000000000000000900469ffffffffffffffffffff16850234811015613283576040517f9239ca9d00000000000000000000000000000000000000000000000000000000815260048101829052602401610b7f565b61328e81600061393b565b6040517fd115124900000000000000000000000000000000000000000000000000000000815261ffff8716600482015273ffffffffffffffffffffffffffffffffffffffff848116602483015288169063d1151249906044016020604051808303816000875af1158015613306573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332a9190614a1a565b935060008061333889613a4c565b8b549193509150600090819061336b908c908a9073ffffffffffffffffffffffffffffffffffffffff16888d8989613b35565b5091509150878773ffffffffffffffffffffffffffffffffffffffff168c73ffffffffffffffffffffffffffffffffffffffff167f05ebbb6b0ce7d564230ba625dd7a0e5108786b0852d6060de6099e1778203e348d86866040516133e3939291909283526020830191909152604082015260600190565b60405180910390a450505050505050949350505050565b600061340583613d9d565b8015610aaa5750610aaa8383611e43565b600069ffffffffffffffffffff8211156134b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203860448201527f30206269747300000000000000000000000000000000000000000000000000006064820152608401610b7f565b5090565b600061ffff8211156134b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203160448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610b7f565b80156137b1577f000000000000000000000000cda72070e455bb31c7690a170224ce43623d0b6f73ffffffffffffffffffffffffffffffffffffffff16632e06db9682613595612fff565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925273ffffffffffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa158015613604573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136289190614a33565b61375f576040517f55daed3e000000000000000000000000000000000000000000000000000000008152600481018290526000907f000000000000000000000000cda72070e455bb31c7690a170224ce43623d0b6f73ffffffffffffffffffffffffffffffffffffffff16906355daed3e906024016040805180830381865afa1580156136b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136dd9190614c5a565b50905073ffffffffffffffffffffffffffffffffffffffff811661372d576040517f167ce11a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fa0cfce1100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660008181526138db6020526040808220849055518392917fa69ac11ca23c60fc41e8e7b0217b2da8c6290a60e39202b1a24b126f47480b4791a35b5050565b60006137c083611087565b509498975050505050505050565b600054610100900460ff16613865576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b7f565b6001610dad55565b6000610f0882613e01565b80825111156137b1579052565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000762340b8a40cdd5bfc3edd94265899fda345d0e31681036138ec57507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec36013560601c5b90565b600081815b848110156139325761391e8287878481811061391257613912614828565b90506020020135613f12565b91508061392a81614c89565b9150506138f4565b50949350505050565b34821115613a11577f00000000000000000000000049128cf8abe9071ee24540a296b5ded3f9d5044373ffffffffffffffffffffffffffffffffffffffff1663452f2b8f613987612fff565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff90911660048201523485036024820152604401600060405180830381600087803b1580156139f557600080fd5b505af1158015613a09573d6000803e3d6000fd5b505050505050565b808015613a1d57503482105b156137b1576137b1823403613a30612fff565b73ffffffffffffffffffffffffffffffffffffffff1690613f41565b73ffffffffffffffffffffffffffffffffffffffff811660009081526138db602052604081205481908015613b2f576040517f55daed3e000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000cda72070e455bb31c7690a170224ce43623d0b6f73ffffffffffffffffffffffffffffffffffffffff16906355daed3e906024016040805180830381865afa158015613b05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b299190614c5a565b90935091505b50915091565b600080600086600003613b5057506000915081905080613d90565b606080600080613b648e8e8e8e8e8d61281c565b8451959c509199509297509095509093509150600090600114613b8957614e20613b8e565b620334505b905060005b8551811015613c0257613bd9868281518110613bb157613bb1614828565b6020026020010151868381518110613bcb57613bcb614828565b60200260200101518461409b565b848181518110613beb57613beb614828565b602002602001015188019750806001019050613b93565b50613c108d87614e2061409b565b613c3d7f00000000000000000000000067df244584b67e8c51b10ad610aaffa9a402fdb689614e2061409b565b8215613cd257613c508b84614e2061409b565b8d8f73ffffffffffffffffffffffffffffffffffffffff167f141b92fd9766c80ab120598ea2f6be9802470ec59b5446dd9bf46214ead8d08e8d866000604051613cc59392919073ffffffffffffffffffffffffffffffffffffffff9390931683526020830191909152604082015260600190565b60405180910390a3968201965b73ffffffffffffffffffffffffffffffffffffffff8a1615613d8a578115613d175785600003613d055795810195613d0a565b948101945b613d178a83614e2061409b565b8d8f73ffffffffffffffffffffffffffffffffffffffff167f27a4dd4ff659a9e6354fb079b2208365e5b83f55c22a4150eee2bca89501cb988c85604051613d8192919073ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b60405180910390a35b50505050505b9750975097945050505050565b6000613dc9827f01ffc9a700000000000000000000000000000000000000000000000000000000611e43565b8015610f085750613dfa827fffffffff00000000000000000000000000000000000000000000000000000000611e43565b1592915050565b60008173ffffffffffffffffffffffffffffffffffffffff1663dfea951d6040518163ffffffff1660e01b8152600401600060405180830381865afa925050508015613e8d57506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052613e8a9190810190614cc1565b60015b15613eec576040517fee2afa3f960e108aca17013728aafa363a0f4485661d9b6f41c6b4ddb55008ee90613ec5908390602001614d6a565b6040516020818303038152906040528051906020012003613eea57506101f492915050565b505b7f00000000000000000000000000000000000000000000000000000000000005dc610f08565b6000818310613f2e576000828152602084905260409020610aaa565b6000838152602083905260409020610aaa565b80471015613fab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610b7f565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114614005576040519150601f19603f3d011682016040523d82523d6000602084013e61400a565b606091505b5050905080610948576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610b7f565b816000036140a857505050565b60008373ffffffffffffffffffffffffffffffffffffffff16838390604051600060405180830381858888f193505050503d8060008114614105576040519150601f19603f3d011682016040523d82523d6000602084013e61410a565b606091505b5050905080614207576040517faa67c91900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301527f00000000000000000000000049128cf8abe9071ee24540a296b5ded3f9d50443169063aa67c9199085906024016000604051808303818588803b15801561419d57600080fd5b505af11580156141b1573d6000803e3d6000fd5b50505050508373ffffffffffffffffffffffffffffffffffffffff167fa2201512569adb2d513531dfd69b66df50bd5cffb8c1bbe65a4611f9e1eadbd1846040516141fe91815260200190565b60405180910390a25b50505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610c5157600080fd5b6000806040838503121561424257600080fd5b823561424d8161420d565b946020939093013593505050565b600081518084526020808501945080840160005b838110156142a157815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161426f565b509495945050505050565b600081518084526020808501945080840160005b838110156142a1578151875295820195908201906001016142c0565b6040815260006142ef604083018561425b565b828103602084015261132581856142ac565b61ffff81168114610c5157600080fd5b60008060006060848603121561432657600080fd5b83356143318161420d565b9250602084013569ffffffffffffffffffff8116811461435057600080fd5b9150604084013561436081614301565b809150509250925092565b60006020828403121561437d57600080fd5b8135610aaa8161420d565b60008060008060008060c087890312156143a157600080fd5b86356143ac8161420d565b9860208801359850604088013597606081013597506080810135965060a00135945092505050565b60008083601f8401126143e657600080fd5b50813567ffffffffffffffff8111156143fe57600080fd5b60208301915083602082850101111561090e57600080fd5b6000806000806000806000806000806101208b8d03121561443657600080fd5b8a356144418161420d565b995060208b0135985060408b0135975060608b0135965060808b0135955060a08b0135945060c08b0135935060e08b013567ffffffffffffffff81111561448757600080fd5b6144938d828e016143d4565b915080945050809250506101008b013590509295989b9194979a5092959850565b600080600080600060a086880312156144cc57600080fd5b85356144d78161420d565b97602087013597506040870135966060810135965060800135945092505050565b60008060006060848603121561450d57600080fd5b83356145188161420d565b95602085013595506040909401359392505050565b86815285602082015260c06040820152600061454c60c083018761425b565b828103606084015261455e81876142ac565b91505083608083015273ffffffffffffffffffffffffffffffffffffffff831660a0830152979650505050505050565b600080604083850312156145a157600080fd5b82356145ac8161420d565b915060208301356145bc8161420d565b809150509250929050565b6000806000806000608086880312156145df57600080fd5b85356145ea8161420d565b94506020860135935060408601356146018161420d565b9250606086013567ffffffffffffffff8082111561461e57600080fd5b818801915088601f83011261463257600080fd5b81358181111561464157600080fd5b8960208260051b850101111561465657600080fd5b9699959850939650602001949392505050565b60008060006060848603121561467e57600080fd5b83356146898161420d565b9250602084013561469981614301565b915060408401356143608161420d565b6000806000606084860312156146be57600080fd5b83356146c98161420d565b92506020840135915060408401356143608161420d565b60008060008060008060008060006101008a8c0312156146ff57600080fd5b893561470a8161420d565b985060208a0135975060408a0135965060608a0135955060808a0135945060a08a0135935060c08a013567ffffffffffffffff81111561474957600080fd5b6147558c828d016143d4565b9a9d999c50979a9699959894979660e00135949350505050565b6000806000806060858703121561478557600080fd5b84356147908161420d565b935060208501359250604085013567ffffffffffffffff8111156147b357600080fd5b6147bf878288016143d4565b95989497509550505050565b600080604083850312156147de57600080fd5b82516147e98161420d565b6020939093015192949293505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561489e5761489e6147f9565b604052919050565b600067ffffffffffffffff8211156148c0576148c06147f9565b5060051b60200190565b600082601f8301126148db57600080fd5b815160206148f06148eb836148a6565b614857565b82815260059290921b8401810191818101908684111561490f57600080fd5b8286015b848110156149335780516149268161420d565b8352918301918301614913565b509695505050505050565b600082601f83011261494f57600080fd5b8151602061495f6148eb836148a6565b82815260059290921b8401810191818101908684111561497e57600080fd5b8286015b848110156149335780518352918301918301614982565b600080604083850312156149ac57600080fd5b825167ffffffffffffffff808211156149c457600080fd5b6149d0868387016148ca565b935060208501519150808211156149e657600080fd5b506149f38582860161493e565b9150509250929050565b600060208284031215614a0f57600080fd5b8151610aaa8161420d565b600060208284031215614a2c57600080fd5b5051919050565b600060208284031215614a4557600080fd5b81518015158114610aaa57600080fd5b600060208284031215614a6757600080fd5b815167ffffffffffffffff811115614a7e57600080fd5b614a8a848285016148ca565b949350505050565b600060208284031215614aa457600080fd5b815167ffffffffffffffff811115614abb57600080fd5b614a8a8482850161493e565b83815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610f0857610f08614b1b565b60005b83811015614b78578181015183820152602001614b60565b50506000910152565b86815285602082015284604082015283606082015282608082015260c060a0820152600082518060c0840152614bbe8160e0850160208701614b5d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160e001979650505050505050565b8082028115828204841417610f0857610f08614b1b565b600082614c42577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610f0857610f08614b1b565b60008060408385031215614c6d57600080fd5b8251614c788161420d565b60208401519092506145bc81614301565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614cba57614cba614b1b565b5060010190565b600060208284031215614cd357600080fd5b815167ffffffffffffffff80821115614ceb57600080fd5b818401915084601f830112614cff57600080fd5b815181811115614d1157614d116147f9565b614d4260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614857565b9150808252856020828501011115614d5957600080fd5b613932816020840160208601614b5d565b60008251614d7c818460208701614b5d565b919091019291505056fea2646970667358221220170c552b54ba2816b33c06b93307a6db77190c478c202848d08f1d0f08b119e864736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000067df244584b67e8c51b10ad610aaffa9a402fdb600000000000000000000000049128cf8abe9071ee24540a296b5ded3f9d50443000000000000000000000000ad2184fb5dbcfc05d8f056542fb25b04fa32a95d000000000000000000000000cda72070e455bb31c7690a170224ce43623d0b6f000000000000000000000000762340b8a40cdd5bfc3edd94265899fda345d0e3
-----Decoded View---------------
Arg [0] : treasury (address): 0x67Df244584b67E8C51B10aD610aAfFa9a402FdB6
Arg [1] : feth (address): 0x49128CF8ABE9071ee24540a296b5DED3F9D50443
Arg [2] : royaltyRegistry (address): 0xaD2184FB5DBcfC05d8f056542fB25b04fa32A95D
Arg [3] : nftMarket (address): 0xcDA72070E455bb31C7690a170224Ce43623d0B6f
Arg [4] : router (address): 0x762340B8a40Cdd5BFC3eDD94265899FDa345D0E3
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 00000000000000000000000067df244584b67e8c51b10ad610aaffa9a402fdb6
Arg [1] : 00000000000000000000000049128cf8abe9071ee24540a296b5ded3f9d50443
Arg [2] : 000000000000000000000000ad2184fb5dbcfc05d8f056542fb25b04fa32a95d
Arg [3] : 000000000000000000000000cda72070e455bb31c7690a170224ce43623d0b6f
Arg [4] : 000000000000000000000000762340b8a40cdd5bfc3edd94265899fda345d0e3
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.