More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 515 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Set Approval For... | 69528406 | 27 days ago | IN | 0 POL | 0.00083648 | ||||
Set Approval For... | 69054852 | 39 days ago | IN | 0 POL | 0.00071437 | ||||
Set Approval For... | 69041767 | 39 days ago | IN | 0 POL | 0.00335015 | ||||
Set Approval For... | 67043772 | 89 days ago | IN | 0 POL | 0.00162115 | ||||
Set Approval For... | 66421456 | 105 days ago | IN | 0 POL | 0.00118391 | ||||
Set Approval For... | 66319960 | 108 days ago | IN | 0 POL | 0.00070358 | ||||
Set Approval For... | 66265633 | 109 days ago | IN | 0 POL | 0.00210304 | ||||
Set Approval For... | 65910944 | 118 days ago | IN | 0 POL | 0.00144692 | ||||
Set Approval For... | 65634710 | 125 days ago | IN | 0 POL | 0.00208819 | ||||
Set Approval For... | 65634704 | 125 days ago | IN | 0 POL | 0.00215479 | ||||
Safe Transfer Fr... | 65219285 | 136 days ago | IN | 0 POL | 0.05542 | ||||
Set Approval For... | 65156095 | 137 days ago | IN | 0 POL | 0.00173342 | ||||
Set Approval For... | 64900913 | 144 days ago | IN | 0 POL | 0.00081057 | ||||
Set Approval For... | 64704305 | 149 days ago | IN | 0 POL | 0.00179872 | ||||
Set Approval For... | 64563683 | 152 days ago | IN | 0 POL | 0.00094711 | ||||
Set Approval For... | 64507645 | 154 days ago | IN | 0 POL | 0.00235844 | ||||
Set Approval For... | 64250317 | 160 days ago | IN | 0 POL | 0.00103857 | ||||
Set Approval For... | 64250317 | 160 days ago | IN | 0 POL | 0.00163557 | ||||
Set Approval For... | 64250120 | 160 days ago | IN | 0 POL | 0.00255467 | ||||
Set Approval For... | 63989981 | 166 days ago | IN | 0 POL | 0.00179828 | ||||
Set Approval For... | 63952467 | 167 days ago | IN | 0 POL | 0.00386352 | ||||
Set Approval For... | 63445901 | 180 days ago | IN | 0 POL | 0.00077451 | ||||
Set Approval For... | 62636341 | 200 days ago | IN | 0 POL | 0.00327618 | ||||
Set Approval For... | 62170290 | 212 days ago | IN | 0 POL | 0.00073689 | ||||
Set Approval For... | 61771668 | 221 days ago | IN | 0 POL | 0.00174569 |
Loading...
Loading
Contract Name:
ERC721Full
Compiler Version
v0.8.22+commit.4fc1097e
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.22; import {IForwarderRegistry} from "./../../../metatx/interfaces/IForwarderRegistry.sol"; import {ITokenMetadataResolver} from "./../../metadata/interfaces/ITokenMetadataResolver.sol"; import {IOperatorFilterRegistry} from "./../../royalty/interfaces/IOperatorFilterRegistry.sol"; import {ERC721WithOperatorFilterer} from "./../ERC721WithOperatorFilterer.sol"; import {ERC721BatchTransferWithOperatorFilterer} from "./../ERC721BatchTransferWithOperatorFilterer.sol"; import {ERC721Metadata} from "./../ERC721Metadata.sol"; import {ERC721Mintable} from "./../ERC721Mintable.sol"; import {ERC721Deliverable} from "./../ERC721Deliverable.sol"; import {ERC2981} from "./../../royalty/ERC2981.sol"; import {ContractOwnership} from "./../../../access/ContractOwnership.sol"; import {TokenRecovery} from "./../../../security/TokenRecovery.sol"; import {Context} from "@openzeppelin/contracts/utils/Context.sol"; import {ForwarderRegistryContextBase} from "./../../../metatx/base/ForwarderRegistryContextBase.sol"; import {ForwarderRegistryContext} from "./../../../metatx/ForwarderRegistryContext.sol"; contract ERC721Full is ERC721WithOperatorFilterer, ERC721BatchTransferWithOperatorFilterer, ERC721Metadata, ERC721Mintable, ERC721Deliverable, ERC2981, TokenRecovery, ForwarderRegistryContext { constructor( string memory tokenName, string memory tokenSymbol, ITokenMetadataResolver metadataResolver, IOperatorFilterRegistry filterRegistry, IForwarderRegistry forwarderRegistry ) ContractOwnership(msg.sender) ERC721Metadata(tokenName, tokenSymbol, metadataResolver) ERC721WithOperatorFilterer(filterRegistry) ForwarderRegistryContext(forwarderRegistry) {} /// @inheritdoc ForwarderRegistryContextBase function _msgSender() internal view virtual override(Context, ForwarderRegistryContextBase) returns (address) { return ForwarderRegistryContextBase._msgSender(); } /// @inheritdoc ForwarderRegistryContextBase function _msgData() internal view virtual override(Context, ForwarderRegistryContextBase) returns (bytes calldata) { return ForwarderRegistryContextBase._msgData(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts 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.9.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ```solidity * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._ * _Available since v4.9 for `string`, `bytes`._ */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @notice Thrown when trying to transfer tokens without calldata to the contract. error EtherReceptionDisabled(); /// @notice Thrown when the multiple related arrays have different lengths. error InconsistentArrayLengths(); /// @notice Thrown when an ETH transfer has failed. error TransferFailed();
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {AccessControlBase} from "./base/AccessControlBase.sol"; import {ContractOwnership} from "./ContractOwnership.sol"; /// @title Access control via roles management (immutable version). /// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation. abstract contract AccessControl is AccessControlBase, ContractOwnership { }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {ContractOwnershipStorage} from "./libraries/ContractOwnershipStorage.sol"; import {ContractOwnershipBase} from "./base/ContractOwnershipBase.sol"; import {InterfaceDetection} from "./../introspection/InterfaceDetection.sol"; /// @title ERC173 Contract Ownership Standard (immutable version). /// @dev See https://eips.ethereum.org/EIPS/eip-173 /// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation. abstract contract ContractOwnership is ContractOwnershipBase, InterfaceDetection { using ContractOwnershipStorage for ContractOwnershipStorage.Layout; /// @notice Initializes the storage with an initial contract owner. /// @notice Marks the following ERC165 interface(s) as supported: ERC173. /// @dev Emits an {OwnershipTransferred} if `initialOwner` is not the zero address. /// @param initialOwner the initial contract owner. constructor(address initialOwner) { ContractOwnershipStorage.layout().constructorInit(initialOwner); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {IAccessControl} from "./../../access/interfaces/IAccessControl.sol"; import {AccessControlStorage} from "./../libraries/AccessControlStorage.sol"; import {ContractOwnershipStorage} from "./../libraries/ContractOwnershipStorage.sol"; import {Context} from "@openzeppelin/contracts/utils/Context.sol"; /// @title Access control via roles management (proxiable version). /// @dev This contract is to be used via inheritance in a proxied implementation. /// @dev Note: This contract requires ERC173 (Contract Ownership standard). abstract contract AccessControlBase is IAccessControl, Context { using AccessControlStorage for AccessControlStorage.Layout; using ContractOwnershipStorage for ContractOwnershipStorage.Layout; /// @notice Grants a role to an account. /// @dev Reverts with {NotContractOwner} if the sender is not the contract owner. /// @dev Emits a {RoleGranted} event if the account did not previously have the role. /// @param role The role to grant. /// @param account The account to grant the role to. function grantRole(bytes32 role, address account) external { address operator = _msgSender(); ContractOwnershipStorage.layout().enforceIsContractOwner(operator); AccessControlStorage.layout().grantRole(role, account, operator); } /// @notice Revokes a role from an account. /// @dev Reverts with {NotContractOwner} if the sender is not the contract owner. /// @dev Emits a {RoleRevoked} event if the account previously had the role. /// @param role The role to revoke. /// @param account The account to revoke the role from. function revokeRole(bytes32 role, address account) external { address operator = _msgSender(); ContractOwnershipStorage.layout().enforceIsContractOwner(operator); AccessControlStorage.layout().revokeRole(role, account, operator); } /// @inheritdoc IAccessControl function renounceRole(bytes32 role) external { AccessControlStorage.layout().renounceRole(_msgSender(), role); } /// @inheritdoc IAccessControl function hasRole(bytes32 role, address account) external view returns (bool hasRole_) { return AccessControlStorage.layout().hasRole(role, account); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {IERC173} from "./../interfaces/IERC173.sol"; import {ContractOwnershipStorage} from "./../libraries/ContractOwnershipStorage.sol"; import {Context} from "@openzeppelin/contracts/utils/Context.sol"; /// @title ERC173 Contract Ownership Standard (proxiable version). /// @dev See https://eips.ethereum.org/EIPS/eip-173 /// @dev This contract is to be used via inheritance in a proxied implementation. /// @dev Note: This contract requires ERC165 (Interface Detection Standard). abstract contract ContractOwnershipBase is IERC173, Context { using ContractOwnershipStorage for ContractOwnershipStorage.Layout; /// @inheritdoc IERC173 function owner() public view virtual returns (address) { return ContractOwnershipStorage.layout().owner(); } /// @inheritdoc IERC173 function transferOwnership(address newOwner) public virtual { ContractOwnershipStorage.layout().transferOwnership(_msgSender(), newOwner); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @notice Thrown when an account does not have the required role. /// @param role The role the caller is missing. /// @param account The account that was checked. error NotRoleHolder(bytes32 role, address account); /// @notice Thrown when an account does not have the required role on a target contract. /// @param targetContract The contract that was checked. /// @param role The role that was checked. /// @param account The account that was checked. error NotTargetContractRoleHolder(address targetContract, bytes32 role, address account);
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @notice Thrown when the target contract is actually not a contract. /// @param targetContract The contract that was checked error TargetIsNotAContract(address targetContract);
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @notice Thrown when an account is not the contract owner but is required to. /// @param account The account that was checked. error NotContractOwner(address account); /// @notice Thrown when an account is not the target contract owner but is required to. /// @param targetContract The contract that was checked. /// @param account The account that was checked. error NotTargetContractOwner(address targetContract, address account);
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @notice Emitted when `role` is granted to `account`. /// @param role The role that has been granted. /// @param account The account that has been granted the role. /// @param operator The account that granted the role. event RoleGranted(bytes32 role, address account, address operator); /// @notice Emitted when `role` is revoked from `account`. /// @param role The role that has been revoked. /// @param account The account that has been revoked the role. /// @param operator The account that revoked the role. event RoleRevoked(bytes32 role, address account, address operator);
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @notice Emitted when the contract ownership changes. /// @param previousOwner the previous contract owner. /// @param newOwner the new contract owner. event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @title Access control via roles management (functions) interface IAccessControl { /// @notice Renounces a role by the sender. /// @dev Reverts if `sender` does not have `role`. /// @dev Emits a {RoleRevoked} event. /// @param role The role to renounce. function renounceRole(bytes32 role) external; /// @notice Retrieves whether an account has a role. /// @param role The role. /// @param account The account. /// @return hasRole_ Whether `account` has `role`. function hasRole(bytes32 role, address account) external view returns (bool hasRole_); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @title ERC-173 Contract Ownership Standard (functions) /// @dev See https://eips.ethereum.org/EIPS/eip-173 /// @dev Note: the ERC-165 identifier for this interface is 0x7f5828d0 interface IERC173 { /// @notice Sets the address of the new contract owner. /// @dev Reverts if the sender is not the contract owner. /// @dev Emits an {OwnershipTransferred} event if `newOwner` is different from the current contract owner. /// @param newOwner The address of the new contract owner. Using the zero address means renouncing ownership. function transferOwnership(address newOwner) external; /// @notice Gets the address of the contract owner. /// @return contractOwner The address of the contract owner. function owner() external view returns (address contractOwner); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {NotRoleHolder, NotTargetContractRoleHolder} from "./../errors/AccessControlErrors.sol"; import {TargetIsNotAContract} from "./../errors/Common.sol"; import {RoleGranted, RoleRevoked} from "./../events/AccessControlEvents.sol"; import {IAccessControl} from "./../interfaces/IAccessControl.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; library AccessControlStorage { using Address for address; using AccessControlStorage for AccessControlStorage.Layout; struct Layout { mapping(bytes32 => mapping(address => bool)) roles; } bytes32 internal constant LAYOUT_STORAGE_SLOT = bytes32(uint256(keccak256("animoca.core.access.AccessControl.storage")) - 1); /// @notice Grants a role to an account. /// @dev Note: Call to this function should be properly access controlled. /// @dev Emits a {RoleGranted} event if the account did not previously have the role. /// @param role The role to grant. /// @param account The account to grant the role to. /// @param operator The account requesting the role change. function grantRole(Layout storage s, bytes32 role, address account, address operator) internal { if (!s.hasRole(role, account)) { s.roles[role][account] = true; emit RoleGranted(role, account, operator); } } /// @notice Revokes a role from an account. /// @dev Note: Call to this function should be properly access controlled. /// @dev Emits a {RoleRevoked} event if the account previously had the role. /// @param role The role to revoke. /// @param account The account to revoke the role from. /// @param operator The account requesting the role change. function revokeRole(Layout storage s, bytes32 role, address account, address operator) internal { if (s.hasRole(role, account)) { s.roles[role][account] = false; emit RoleRevoked(role, account, operator); } } /// @notice Renounces a role by the sender. /// @dev Reverts with {NotRoleHolder} if `sender` does not have `role`. /// @dev Emits a {RoleRevoked} event. /// @param sender The message sender. /// @param role The role to renounce. function renounceRole(Layout storage s, address sender, bytes32 role) internal { s.enforceHasRole(role, sender); s.roles[role][sender] = false; emit RoleRevoked(role, sender, sender); } /// @notice Retrieves whether an account has a role. /// @param role The role. /// @param account The account. /// @return hasRole_ Whether `account` has `role`. function hasRole(Layout storage s, bytes32 role, address account) internal view returns (bool hasRole_) { return s.roles[role][account]; } /// @notice Checks whether an account has a role in a target contract. /// @param targetContract The contract to check. /// @param role The role to check. /// @param account The account to check. /// @return hasTargetContractRole_ Whether `account` has `role` in `targetContract`. function hasTargetContractRole(address targetContract, bytes32 role, address account) internal view returns (bool hasTargetContractRole_) { if (!targetContract.isContract()) revert TargetIsNotAContract(targetContract); return IAccessControl(targetContract).hasRole(role, account); } /// @notice Ensures that an account has a role. /// @dev Reverts with {NotRoleHolder} if `account` does not have `role`. /// @param role The role. /// @param account The account. function enforceHasRole(Layout storage s, bytes32 role, address account) internal view { if (!s.hasRole(role, account)) revert NotRoleHolder(role, account); } /// @notice Enforces that an account has a role in a target contract. /// @dev Reverts with {NotTargetContractRoleHolder} if the account does not have the role. /// @param targetContract The contract to check. /// @param role The role to check. /// @param account The account to check. function enforceHasTargetContractRole(address targetContract, bytes32 role, address account) internal view { if (!hasTargetContractRole(targetContract, role, account)) revert NotTargetContractRoleHolder(targetContract, role, account); } function layout() internal pure returns (Layout storage s) { bytes32 position = LAYOUT_STORAGE_SLOT; assembly { s.slot := position } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {NotContractOwner, NotTargetContractOwner} from "./../errors/ContractOwnershipErrors.sol"; import {TargetIsNotAContract} from "./../errors/Common.sol"; import {OwnershipTransferred} from "./../events/ERC173Events.sol"; import {IERC173} from "./../interfaces/IERC173.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {ProxyInitialization} from "./../../proxy/libraries/ProxyInitialization.sol"; import {InterfaceDetectionStorage} from "./../../introspection/libraries/InterfaceDetectionStorage.sol"; library ContractOwnershipStorage { using Address for address; using ContractOwnershipStorage for ContractOwnershipStorage.Layout; using InterfaceDetectionStorage for InterfaceDetectionStorage.Layout; struct Layout { address contractOwner; } bytes32 internal constant LAYOUT_STORAGE_SLOT = bytes32(uint256(keccak256("animoca.core.access.ContractOwnership.storage")) - 1); bytes32 internal constant PROXY_INIT_PHASE_SLOT = bytes32(uint256(keccak256("animoca.core.access.ContractOwnership.phase")) - 1); /// @notice Initializes the storage with an initial contract owner (immutable version). /// @notice Marks the following ERC165 interface(s) as supported: ERC173. /// @dev Note: This function should be called ONLY in the constructor of an immutable (non-proxied) contract. /// @dev Emits an {OwnershipTransferred} if `initialOwner` is not the zero address. /// @param initialOwner The initial contract owner. function constructorInit(Layout storage s, address initialOwner) internal { if (initialOwner != address(0)) { s.contractOwner = initialOwner; emit OwnershipTransferred(address(0), initialOwner); } InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC173).interfaceId, true); } /// @notice Initializes the storage with an initial contract owner (proxied version). /// @notice Sets the proxy initialization phase to `1`. /// @notice Marks the following ERC165 interface(s) as supported: ERC173. /// @dev Note: This function should be called ONLY in the init function of a proxied contract. /// @dev Reverts with {InitializationPhaseAlreadyReached} if the proxy initialization phase is set to `1` or above. /// @dev Emits an {OwnershipTransferred} if `initialOwner` is not the zero address. /// @param initialOwner The initial contract owner. function proxyInit(Layout storage s, address initialOwner) internal { ProxyInitialization.setPhase(PROXY_INIT_PHASE_SLOT, 1); s.constructorInit(initialOwner); } /// @notice Sets the address of the new contract owner. /// @dev Reverts with {NotContractOwner} if `sender` is not the contract owner. /// @dev Emits an {OwnershipTransferred} event if `newOwner` is different from the current contract owner. /// @param newOwner The address of the new contract owner. Using the zero address means renouncing ownership. function transferOwnership(Layout storage s, address sender, address newOwner) internal { address previousOwner = s.contractOwner; if (sender != previousOwner) revert NotContractOwner(sender); if (previousOwner != newOwner) { s.contractOwner = newOwner; emit OwnershipTransferred(previousOwner, newOwner); } } /// @notice Gets the address of the contract owner. /// @return contractOwner The address of the contract owner. function owner(Layout storage s) internal view returns (address contractOwner) { return s.contractOwner; } /// @notice Checks whether an account is the owner of a target contract. /// @param targetContract The contract to check. /// @param account The account to check. /// @return isTargetContractOwner_ Whether `account` is the owner of `targetContract`. function isTargetContractOwner(address targetContract, address account) internal view returns (bool isTargetContractOwner_) { if (!targetContract.isContract()) revert TargetIsNotAContract(targetContract); return IERC173(targetContract).owner() == account; } /// @notice Ensures that an account is the contract owner. /// @dev Reverts with {NotContractOwner} if `account` is not the contract owner. /// @param account The account. function enforceIsContractOwner(Layout storage s, address account) internal view { if (account != s.contractOwner) revert NotContractOwner(account); } /// @notice Enforces that an account is the owner of a target contract. /// @dev Reverts with {NotTheTargetContractOwner} if the account is not the owner. /// @param targetContract The contract to check. /// @param account The account to check. function enforceIsTargetContractOwner(address targetContract, address account) internal view { if (!isTargetContractOwner(targetContract, account)) revert NotTargetContractOwner(targetContract, account); } function layout() internal pure returns (Layout storage s) { bytes32 position = LAYOUT_STORAGE_SLOT; assembly { s.slot := position } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {IERC165} from "./interfaces/IERC165.sol"; import {InterfaceDetectionStorage} from "./libraries/InterfaceDetectionStorage.sol"; /// @title ERC165 Interface Detection Standard (immutable or proxiable version). /// @dev This contract is to be used via inheritance in an immutable (non-proxied) or proxied implementation. abstract contract InterfaceDetection is IERC165 { using InterfaceDetectionStorage for InterfaceDetectionStorage.Layout; /// @inheritdoc IERC165 function supportsInterface(bytes4 interfaceId) external view returns (bool) { return InterfaceDetectionStorage.layout().supportsInterface(interfaceId); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @notice Thrown when setting the illegal interfaceId 0xffffffff. error IllegalInterfaceId();
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @title ERC165 Interface Detection Standard. /// @dev See https://eips.ethereum.org/EIPS/eip-165. /// @dev Note: The ERC-165 identifier for this interface is 0x01ffc9a7. interface IERC165 { /// @notice Returns whether this contract implements a given interface. /// @dev Note: This function call must use less than 30 000 gas. /// @param interfaceId the interface identifier to test. /// @return supported True if the interface is supported, false if `interfaceId` is `0xffffffff` or if the interface is not supported. function supportsInterface(bytes4 interfaceId) external view returns (bool supported); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {IllegalInterfaceId} from "./../errors/InterfaceDetectionErrors.sol"; import {IERC165} from "./../interfaces/IERC165.sol"; library InterfaceDetectionStorage { struct Layout { mapping(bytes4 => bool) supportedInterfaces; } bytes32 internal constant LAYOUT_STORAGE_SLOT = bytes32(uint256(keccak256("animoca.core.introspection.InterfaceDetection.storage")) - 1); bytes4 internal constant ILLEGAL_INTERFACE_ID = 0xffffffff; /// @notice Sets or unsets an ERC165 interface. /// @dev Revertswith {IllegalInterfaceId} if `interfaceId` is `0xffffffff`. /// @param interfaceId the interface identifier. /// @param supported True to set the interface, false to unset it. function setSupportedInterface(Layout storage s, bytes4 interfaceId, bool supported) internal { if (interfaceId == ILLEGAL_INTERFACE_ID) revert IllegalInterfaceId(); s.supportedInterfaces[interfaceId] = supported; } /// @notice Returns whether this contract implements a given interface. /// @dev Note: This function call must use less than 30 000 gas. /// @param interfaceId The interface identifier to test. /// @return supported True if the interface is supported, false if `interfaceId` is `0xffffffff` or if the interface is not supported. function supportsInterface(Layout storage s, bytes4 interfaceId) internal view returns (bool supported) { if (interfaceId == ILLEGAL_INTERFACE_ID) { return false; } if (interfaceId == type(IERC165).interfaceId) { return true; } return s.supportedInterfaces[interfaceId]; } function layout() internal pure returns (Layout storage s) { bytes32 position = LAYOUT_STORAGE_SLOT; assembly { s.slot := position } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {IForwarderRegistry} from "./interfaces/IForwarderRegistry.sol"; import {IERC2771} from "./interfaces/IERC2771.sol"; import {ForwarderRegistryContextBase} from "./base/ForwarderRegistryContextBase.sol"; /// @title Meta-Transactions Forwarder Registry Context (immutable version). /// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation. /// @dev Derived from https://github.com/wighawag/universal-forwarder (MIT licence) abstract contract ForwarderRegistryContext is ForwarderRegistryContextBase, IERC2771 { constructor(IForwarderRegistry forwarderRegistry_) ForwarderRegistryContextBase(forwarderRegistry_) {} function forwarderRegistry() external view returns (IForwarderRegistry) { return _FORWARDER_REGISTRY; } /// @inheritdoc IERC2771 function isTrustedForwarder(address forwarder) external view virtual returns (bool) { return forwarder == address(_FORWARDER_REGISTRY); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {IForwarderRegistry} from "./../interfaces/IForwarderRegistry.sol"; import {ERC2771Calldata} from "./../libraries/ERC2771Calldata.sol"; /// @title Meta-Transactions Forwarder Registry Context (proxiable version). /// @dev This contract is to be used via inheritance in a proxied implementation. /// @dev Derived from https://github.com/wighawag/universal-forwarder (MIT licence) abstract contract ForwarderRegistryContextBase { IForwarderRegistry internal immutable _FORWARDER_REGISTRY; constructor(IForwarderRegistry forwarderRegistry) { _FORWARDER_REGISTRY = forwarderRegistry; } /// @notice Returns the message sender depending on the ForwarderRegistry-based meta-transaction context. function _msgSender() internal view virtual returns (address) { // Optimised path in case of an EOA-initiated direct tx to the contract or a call from a contract not complying with EIP-2771 // solhint-disable-next-line avoid-tx-origin if (msg.sender == tx.origin || msg.data.length < 24) { return msg.sender; } address sender = ERC2771Calldata.msgSender(); // Return the EIP-2771 calldata-appended sender address if the message was forwarded by the ForwarderRegistry or an approved forwarder if (msg.sender == address(_FORWARDER_REGISTRY) || _FORWARDER_REGISTRY.isApprovedForwarder(sender, msg.sender)) { return sender; } return msg.sender; } /// @notice Returns the message data depending on the ForwarderRegistry-based meta-transaction context. function _msgData() internal view virtual returns (bytes calldata) { // Optimised path in case of an EOA-initiated direct tx to the contract or a call from a contract not complying with EIP-2771 // solhint-disable-next-line avoid-tx-origin if (msg.sender == tx.origin || msg.data.length < 24) { return msg.data; } // Return the EIP-2771 calldata (minus the appended sender) if the message was forwarded by the ForwarderRegistry or an approved forwarder if (msg.sender == address(_FORWARDER_REGISTRY) || _FORWARDER_REGISTRY.isApprovedForwarder(ERC2771Calldata.msgSender(), msg.sender)) { return ERC2771Calldata.msgData(); } return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @title Secure Protocol for Native Meta Transactions. /// @dev See https://eips.ethereum.org/EIPS/eip-2771 interface IERC2771 { /// @notice Checks whether a forwarder is trusted. /// @param forwarder The forwarder to check. /// @return isTrusted True if `forwarder` is trusted, false if not. function isTrustedForwarder(address forwarder) external view returns (bool isTrusted); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @title Universal Meta-Transactions Forwarder Registry. /// @dev Derived from https://github.com/wighawag/universal-forwarder (MIT licence) interface IForwarderRegistry { /// @notice Checks whether an account is as an approved meta-transaction forwarder for a sender account. /// @param sender The sender account. /// @param forwarder The forwarder account. /// @return isApproved True if `forwarder` is an approved meta-transaction forwarder for `sender`, false otherwise. function isApprovedForwarder(address sender, address forwarder) external view returns (bool isApproved); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @dev Derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT licence) /// @dev See https://eips.ethereum.org/EIPS/eip-2771 library ERC2771Calldata { /// @notice Returns the sender address appended at the end of the calldata, as specified in EIP-2771. function msgSender() internal pure returns (address sender) { assembly { sender := shr(96, calldataload(sub(calldatasize(), 20))) } } /// @notice Returns the calldata while omitting the appended sender address, as specified in EIP-2771. function msgData() internal pure returns (bytes calldata data) { unchecked { return msg.data[:msg.data.length - 20]; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @notice Emitted when trying to set a phase value that has already been reached. /// @param currentPhase The current phase. /// @param newPhase The new phase trying to be set. error InitializationPhaseAlreadyReached(uint256 currentPhase, uint256 newPhase);
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {InitializationPhaseAlreadyReached} from "./../errors/ProxyInitializationErrors.sol"; import {StorageSlot} from "@openzeppelin/contracts/utils/StorageSlot.sol"; /// @notice Multiple calls protection for storage-modifying proxy initialization functions. library ProxyInitialization { /// @notice Sets the initialization phase during a storage-modifying proxy initialization function. /// @dev Reverts with {InitializationPhaseAlreadyReached} if `phase` has been reached already. /// @param storageSlot the storage slot where `phase` is stored. /// @param phase the initialization phase. function setPhase(bytes32 storageSlot, uint256 phase) internal { StorageSlot.Uint256Slot storage currentVersion = StorageSlot.getUint256Slot(storageSlot); uint256 currentPhase = currentVersion.value; if (currentPhase >= phase) revert InitializationPhaseAlreadyReached(currentPhase, phase); currentVersion.value = phase; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {TokenRecoveryBase} from "./base/TokenRecoveryBase.sol"; import {ContractOwnership} from "./../access/ContractOwnership.sol"; /// @title Recovery mechanism for ETH/ERC20/ERC721 tokens accidentally sent to this contract (immutable version). /// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation. abstract contract TokenRecovery is TokenRecoveryBase, ContractOwnership { }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {InconsistentArrayLengths} from "./../../CommonErrors.sol"; import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; import {IERC721} from "./../../token/ERC721/interfaces/IERC721.sol"; import {ContractOwnershipStorage} from "./../../access/libraries/ContractOwnershipStorage.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {Context} from "@openzeppelin/contracts/utils/Context.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; /// @title Recovery mechanism for ETH/ERC20/ERC721 tokens accidentally sent to this contract (proxiable version). /// @dev This contract is to be used via inheritance in a proxied implementation. /// @dev Note: This contract requires ERC173 (Contract Ownership standard). abstract contract TokenRecoveryBase is Context { using ContractOwnershipStorage for ContractOwnershipStorage.Layout; using SafeERC20 for IERC20; using Address for address payable; /// @notice Extract ETH tokens which were accidentally sent to the contract to a list of accounts. /// @dev Note: While contracts can generally prevent accidental ETH transfer by implementating a reverting /// `receive()` function, this can still be bypassed in a `selfdestruct(address)` scenario. /// @dev Warning: this function should be overriden for contracts which are supposed to hold ETH tokens /// so that the extraction is limited to only amounts sent accidentally. /// @dev Reverts with {NotContractOwner} if the sender is not the contract owner. /// @dev Reverts with {InconsistentArrayLengths} `accounts` and `amounts` do not have the same length. /// @dev Reverts if one of the ETH transfers fails for any reason. /// @param accounts the list of accounts to transfer the tokens to. /// @param amounts the list of token amounts to transfer. function recoverETH(address payable[] calldata accounts, uint256[] calldata amounts) public virtual { ContractOwnershipStorage.layout().enforceIsContractOwner(_msgSender()); uint256 length = accounts.length; if (length != amounts.length) revert InconsistentArrayLengths(); for (uint256 i; i < length; ++i) { accounts[i].sendValue(amounts[i]); } } /// @notice Extract ERC20 tokens which were accidentally sent to the contract to a list of accounts. /// @dev Warning: this function should be overriden for contracts which are supposed to hold ERC20 tokens /// so that the extraction is limited to only amounts sent accidentally. /// @dev Reverts with {NotContractOwner} if the sender is not the contract owner. /// @dev Reverts with {InconsistentArrayLengths} if `accounts`, `tokens` and `amounts` do not have the same length. /// @dev Reverts if one of the ERC20 transfers fails for any reason. /// @param accounts the list of accounts to transfer the tokens to. /// @param tokens the list of ERC20 token addresses. /// @param amounts the list of token amounts to transfer. function recoverERC20s(address[] calldata accounts, IERC20[] calldata tokens, uint256[] calldata amounts) public virtual { ContractOwnershipStorage.layout().enforceIsContractOwner(_msgSender()); uint256 length = accounts.length; if (length != tokens.length || length != amounts.length) revert InconsistentArrayLengths(); for (uint256 i; i < length; ++i) { tokens[i].safeTransfer(accounts[i], amounts[i]); } } /// @notice Extract ERC721 tokens which were accidentally sent to the contract to a list of accounts. /// @dev Warning: this function should be overriden for contracts which are supposed to hold ERC721 tokens /// so that the extraction is limited to only tokens sent accidentally. /// @dev Reverts with {NotContractOwner} if the sender is not the contract owner. /// @dev Reverts with {InconsistentArrayLengths} if `accounts`, `contracts` and `amounts` do not have the same length. /// @dev Reverts if one of the ERC721 transfers fails for any reason. /// @param accounts the list of accounts to transfer the tokens to. /// @param contracts the list of ERC721 contract addresses. /// @param tokenIds the list of token ids to transfer. function recoverERC721s(address[] calldata accounts, IERC721[] calldata contracts, uint256[] calldata tokenIds) public virtual { ContractOwnershipStorage.layout().enforceIsContractOwner(_msgSender()); uint256 length = accounts.length; if (length != contracts.length || length != tokenIds.length) revert InconsistentArrayLengths(); for (uint256 i; i < length; ++i) { contracts[i].transferFrom(address(this), accounts[i], tokenIds[i]); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {ERC721Storage} from "./libraries/ERC721Storage.sol"; import {ERC721BatchTransferWithOperatorFiltererBase} from "./base/ERC721BatchTransferWithOperatorFiltererBase.sol"; /// @title ERC721 Non-Fungible Token Standard: optional extension: Batch Transfer with Operator Filterer (immutable version). /// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation. abstract contract ERC721BatchTransferWithOperatorFilterer is ERC721BatchTransferWithOperatorFiltererBase { /// @notice Marks the following ERC165 interfaces(s) as supported: ERC721BatchTransfer constructor() { ERC721Storage.initERC721BatchTransfer(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {ERC721Storage} from "./libraries/ERC721Storage.sol"; import {ERC721DeliverableBase} from "./base/ERC721DeliverableBase.sol"; import {AccessControl} from "./../../access/AccessControl.sol"; /// @title ERC721 Non-Fungible Token Standard, optional extension: Deliverable (immutable version). /// @notice ERC721Deliverable implementation where burnt tokens can be minted again. /// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation. abstract contract ERC721Deliverable is ERC721DeliverableBase, AccessControl { /// @notice Marks the following ERC165 interface(s) as supported: ERC721Deliverable. constructor() { ERC721Storage.initERC721Deliverable(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {ITokenMetadataResolver} from "./../metadata/interfaces/ITokenMetadataResolver.sol"; import {TokenMetadataStorage} from "./../metadata/libraries/TokenMetadataStorage.sol"; import {ERC721Storage} from "./libraries/ERC721Storage.sol"; import {ERC721MetadataBase} from "./base/ERC721MetadataBase.sol"; /// @title ERC721 Non-Fungible Token Standard, optional extension: Metadata (immutable version). /// @notice This contracts uses an external resolver for managing individual tokens metadata. /// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation. abstract contract ERC721Metadata is ERC721MetadataBase { using TokenMetadataStorage for TokenMetadataStorage.Layout; /// @notice Marks the following ERC165 interfaces as supported: ERC721Metadata. /// @param name The name of the token. /// @param symbol The symbol of the token. /// @param metadataResolver The address of the metadata resolver contract. constructor(string memory name, string memory symbol, ITokenMetadataResolver metadataResolver) { TokenMetadataStorage.layout().constructorInit(name, symbol, metadataResolver); ERC721Storage.initERC721Metadata(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {ERC721Storage} from "./libraries/ERC721Storage.sol"; import {ERC721MintableBase} from "./base/ERC721MintableBase.sol"; import {AccessControl} from "./../../access/AccessControl.sol"; /// @title ERC721 Non-Fungible Token Standard, optional extension: Mintable (immutable version). /// @notice ERC721Mintable implementation where burnt tokens can be minted again. /// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation. abstract contract ERC721Mintable is ERC721MintableBase, AccessControl { /// @notice Marks the following ERC165 interface(s) as supported: ERC721Mintable. constructor() { ERC721Storage.initERC721Mintable(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {IOperatorFilterRegistry} from "./../royalty/interfaces/IOperatorFilterRegistry.sol"; import {ERC721Storage} from "./libraries/ERC721Storage.sol"; import {OperatorFiltererStorage} from "./../royalty/libraries/OperatorFiltererStorage.sol"; import {ERC721WithOperatorFiltererBase} from "./base/ERC721WithOperatorFiltererBase.sol"; import {OperatorFiltererBase} from "./../royalty/base/OperatorFiltererBase.sol"; import {ContractOwnership} from "./../../access/ContractOwnership.sol"; /// @title ERC721 Non-Fungible Token Standard with Operator Filterer (immutable version). /// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation. abstract contract ERC721WithOperatorFilterer is ERC721WithOperatorFiltererBase, OperatorFiltererBase, ContractOwnership { using OperatorFiltererStorage for OperatorFiltererStorage.Layout; /// @notice Marks the following ERC165 interfaces as supported: ERC721. /// @notice Sets the address that the contract will make OperatorFilter checks against. /// @param operatorFilterRegistry The operator filter registry address. When set to the zero address, checks will be bypassed. constructor(IOperatorFilterRegistry operatorFilterRegistry) { ERC721Storage.init(); OperatorFiltererStorage.layout().constructorInit(operatorFilterRegistry); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {IERC721BatchTransfer} from "./../interfaces/IERC721BatchTransfer.sol"; import {ERC721Storage} from "./../libraries/ERC721Storage.sol"; import {OperatorFiltererStorage} from "./../../royalty/libraries/OperatorFiltererStorage.sol"; import {Context} from "@openzeppelin/contracts/utils/Context.sol"; /// @title ERC721 Non-Fungible Token Standard, optional extension: Batch Transfer with Operator Filterer (proxiable version). /// @dev This contract is to be used via inheritance in a proxied implementation. /// @dev Note: This contract requires ERC721 (Non-Fungible Token Standard). abstract contract ERC721BatchTransferWithOperatorFiltererBase is IERC721BatchTransfer, Context { using ERC721Storage for ERC721Storage.Layout; using OperatorFiltererStorage for OperatorFiltererStorage.Layout; /// @inheritdoc IERC721BatchTransfer /// @dev Reverts with OperatorNotAllowed if the sender is not `from` and is not allowed by the operator registry. function batchTransferFrom(address from, address to, uint256[] calldata tokenIds) external virtual { address sender = _msgSender(); OperatorFiltererStorage.layout().requireAllowedOperatorForTransfer(sender, from); ERC721Storage.layout().batchTransferFrom(sender, from, to, tokenIds); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {IERC721Deliverable} from "./../interfaces/IERC721Deliverable.sol"; import {ERC721Storage} from "./../libraries/ERC721Storage.sol"; import {AccessControlStorage} from "./../../../access/libraries/AccessControlStorage.sol"; import {Context} from "@openzeppelin/contracts/utils/Context.sol"; /// @title ERC721 Non-Fungible Token Standard, optional extension: Deliverable (proxiable version). /// @notice ERC721Deliverable implementation where burnt tokens can be minted again. /// @dev This contract is to be used via inheritance in a proxied implementation. /// @dev Note: This contract requires ERC721 (Non-Fungible Token Standard). /// @dev Note: This contract requires AccessControl. abstract contract ERC721DeliverableBase is IERC721Deliverable, Context { using ERC721Storage for ERC721Storage.Layout; using AccessControlStorage for AccessControlStorage.Layout; // prevent variable name clash with public ERC721MintableBase.MINTER_ROLE bytes32 private constant _MINTER_ROLE = "minter"; /// @inheritdoc IERC721Deliverable /// @dev Reverts with {NotRoleHolder} if the sender does not have the 'minter' role. function deliver(address[] calldata recipients, uint256[] calldata tokenIds) external virtual { AccessControlStorage.layout().enforceHasRole(_MINTER_ROLE, _msgSender()); ERC721Storage.layout().deliver(recipients, tokenIds); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {IERC721Metadata} from "./../interfaces/IERC721Metadata.sol"; import {ERC721Storage} from "./../libraries/ERC721Storage.sol"; import {TokenMetadataStorage} from "./../../metadata/libraries/TokenMetadataStorage.sol"; import {TokenMetadataBase} from "./../../metadata/base/TokenMetadataBase.sol"; /// @title ERC721 Non-Fungible Token Standard, optional extension: Metadata (proxiable version). /// @notice This contracts uses an external resolver for managing individual tokens metadata. /// @dev This contract is to be used via inheritance in a proxied implementation. /// @dev Note: This contract requires ERC721 (Non-Fungible Token Standard). abstract contract ERC721MetadataBase is TokenMetadataBase, IERC721Metadata { using ERC721Storage for ERC721Storage.Layout; using TokenMetadataStorage for TokenMetadataStorage.Layout; /// @inheritdoc IERC721Metadata function name() public view virtual override(IERC721Metadata, TokenMetadataBase) returns (string memory tokenName) { return TokenMetadataBase.name(); } /// @inheritdoc IERC721Metadata function symbol() public view virtual override(IERC721Metadata, TokenMetadataBase) returns (string memory tokenSymbol) { return TokenMetadataBase.symbol(); } /// @inheritdoc IERC721Metadata function tokenURI(uint256 tokenId) external view virtual returns (string memory uri) { ERC721Storage.layout().ownerOf(tokenId); // reverts if the token does not exist return TokenMetadataStorage.layout().tokenMetadataURI(address(this), tokenId); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {IERC721Mintable} from "./../interfaces/IERC721Mintable.sol"; import {ERC721Storage} from "./../libraries/ERC721Storage.sol"; import {AccessControlStorage} from "./../../../access/libraries/AccessControlStorage.sol"; import {Context} from "@openzeppelin/contracts/utils/Context.sol"; /// @title ERC721 Non-Fungible Token Standard, optional extension: Mintable (proxiable version). /// @notice ERC721Mintable implementation where burnt tokens can be minted again. /// @dev This contract is to be used via inheritance in a proxied implementation. /// @dev Note: This contract requires ERC721 (Non-Fungible Token Standard). /// @dev Note: This contract requires AccessControl. abstract contract ERC721MintableBase is IERC721Mintable, Context { using ERC721Storage for ERC721Storage.Layout; using AccessControlStorage for AccessControlStorage.Layout; bytes32 public constant MINTER_ROLE = "minter"; /// @inheritdoc IERC721Mintable /// @dev Reverts with {NotRoleHolder} if the sender does not have the 'minter' role. function mint(address to, uint256 tokenId) external virtual { AccessControlStorage.layout().enforceHasRole(MINTER_ROLE, _msgSender()); ERC721Storage.layout().mint(to, tokenId); } /// @inheritdoc IERC721Mintable /// @dev Reverts with {NotRoleHolder} if the sender does not have the 'minter' role. function safeMint(address to, uint256 tokenId, bytes calldata data) external virtual { AccessControlStorage.layout().enforceHasRole(MINTER_ROLE, _msgSender()); ERC721Storage.layout().safeMint(_msgSender(), to, tokenId, data); } /// @inheritdoc IERC721Mintable /// @dev Reverts with {NotRoleHolder} if the sender does not have the 'minter' role. function batchMint(address to, uint256[] calldata tokenIds) external virtual { AccessControlStorage.layout().enforceHasRole(MINTER_ROLE, _msgSender()); ERC721Storage.layout().batchMint(to, tokenIds); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {IERC721} from "./../interfaces/IERC721.sol"; import {ERC721Storage} from "./../libraries/ERC721Storage.sol"; import {OperatorFiltererStorage} from "./../../royalty/libraries/OperatorFiltererStorage.sol"; import {Context} from "@openzeppelin/contracts/utils/Context.sol"; /// @title ERC721 Non-Fungible Token Standard with Operator Filterer (proxiable version). /// @dev This contract is to be used via inheritance in a proxied implementation. /// @dev Note: This contract requires ERC165 (Interface Detection Standard). /// @dev Note: This contract requires OperatorFilterer. abstract contract ERC721WithOperatorFiltererBase is IERC721, Context { using ERC721Storage for ERC721Storage.Layout; using OperatorFiltererStorage for OperatorFiltererStorage.Layout; /// @inheritdoc IERC721 /// @dev Reverts with {OperatorNotAllowed} if `to` is not the zero address and is not allowed by the operator registry. function approve(address to, uint256 tokenId) external virtual { if (to != address(0)) { OperatorFiltererStorage.layout().requireAllowedOperatorForApproval(to); } ERC721Storage.layout().approve(_msgSender(), to, tokenId); } /// @inheritdoc IERC721 /// @dev Reverts with {OperatorNotAllowed} if `approved` is true and `operator` is not allowed by the operator registry. function setApprovalForAll(address operator, bool approved) external virtual { if (approved) { OperatorFiltererStorage.layout().requireAllowedOperatorForApproval(operator); } ERC721Storage.layout().setApprovalForAll(_msgSender(), operator, approved); } /// @inheritdoc IERC721 /// @dev Reverts with {OperatorNotAllowed} if the sender is not `from` and is not allowed by the operator registry. function transferFrom(address from, address to, uint256 tokenId) external { address sender = _msgSender(); OperatorFiltererStorage.layout().requireAllowedOperatorForTransfer(sender, from); ERC721Storage.layout().transferFrom(sender, from, to, tokenId); } /// @inheritdoc IERC721 /// @dev Reverts with {OperatorNotAllowed} if the sender is not `from` and is not allowed by the operator registry. function safeTransferFrom(address from, address to, uint256 tokenId) external virtual { address sender = _msgSender(); OperatorFiltererStorage.layout().requireAllowedOperatorForTransfer(sender, from); ERC721Storage.layout().safeTransferFrom(sender, from, to, tokenId); } /// @inheritdoc IERC721 /// @dev Reverts with {OperatorNotAllowed} if the sender is not `from` and is not allowed by the operator registry. function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external virtual { address sender = _msgSender(); OperatorFiltererStorage.layout().requireAllowedOperatorForTransfer(sender, from); ERC721Storage.layout().safeTransferFrom(sender, from, to, tokenId, data); } /// @inheritdoc IERC721 function balanceOf(address owner) external view returns (uint256 balance) { return ERC721Storage.layout().balanceOf(owner); } /// @inheritdoc IERC721 function ownerOf(uint256 tokenId) external view returns (address tokenOwner) { return ERC721Storage.layout().ownerOf(tokenId); } /// @inheritdoc IERC721 function getApproved(uint256 tokenId) external view returns (address approved) { return ERC721Storage.layout().getApproved(tokenId); } /// @inheritdoc IERC721 function isApprovedForAll(address owner, address operator) external view returns (bool approvedForAll) { return ERC721Storage.layout().isApprovedForAll(owner, operator); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @notice Thrown when trying to approve oneself. /// @param account The account trying to approve itself. error ERC721SelfApproval(address account); /// @notice Thrown when trying to approveForAll oneself. /// @param account The account trying to approveForAll itself. error ERC721SelfApprovalForAll(address account); /// @notice Thrown when a sender tries to set a token approval but is neither the owner nor approvedForAll by the owner. /// @param sender The message sender. /// @param tokenId The identifier of the token. error ERC721NonApprovedForApproval(address sender, address owner, uint256 tokenId); /// @notice Thrown when transferring a token to the zero address. error ERC721TransferToAddressZero(); /// @notice Thrown when a token does not exist but is required to. /// @param tokenId The identifier of the token that was checked. error ERC721NonExistingToken(uint256 tokenId); /// @notice Thrown when a sender tries to transfer a token but is neither the owner nor approved by the owner. /// @param sender The message sender. /// @param tokenId The identifier of the token. error ERC721NonApprovedForTransfer(address sender, address owner, uint256 tokenId); /// @notice Thrown when a token is not owned by the expected account. /// @param account The account that was expected to own the token. /// @param tokenId The identifier of the token. error ERC721NonOwnedToken(address account, uint256 tokenId); /// @notice Thrown when a safe transfer is rejected by the recipient contract. /// @param recipient The recipient contract. /// @param tokenId The identifier of the token. error ERC721SafeTransferRejected(address recipient, uint256 tokenId); /// @notice Thrown when querying the balance of the zero address. error ERC721BalanceOfAddressZero();
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @notice Thrown when minting a token to the zero address. error ERC721MintToAddressZero(); /// @notice Thrown when minting a token that already exists. /// @param tokenId The identifier of the token that already exists. error ERC721ExistingToken(uint256 tokenId);
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @notice Thrown when minting a token which has been burnt before (MintableOnce implementation). /// @param tokenId The identifier of the token that has been burnt before. error ERC721BurntToken(uint256 tokenId);
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @notice Emitted when a token is transferred. /// @param from The previous token owner. /// @param to The new token owner. /// @param tokenId The transferred token identifier. event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /// @notice Emitted when a single token approval is set. /// @param owner The token owner. /// @param approved The approved address. /// @param tokenId The approved token identifier. event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /// @notice Emitted when an approval for all tokens is set or unset. /// @param owner The tokens owner. /// @param operator The approved address. /// @param approved True when then approval is set, false when it is unset. event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @title ERC721 Non-Fungible Token Standard, basic interface (functions). /// @dev See https://eips.ethereum.org/EIPS/eip-721 /// @dev This interface only contains the standard functions. See IERC721Events for the events. /// @dev Note: The ERC-165 identifier for this interface is 0x80ac58cd. interface IERC721 { /// @notice Sets or unsets an approval to transfer a single token on behalf of its owner. /// @dev Note: There can only be one approved address per token at a given time. /// @dev Note: A token approval gets reset when this token is transferred, including a self-transfer. /// @dev Reverts if `tokenId` does not exist. /// @dev Reverts if `to` is the token owner. /// @dev Reverts if the sender is not the token owner and has not been approved by the token owner. /// @dev Emits an {Approval} event. /// @param to The address to approve, or the zero address to remove any existing approval. /// @param tokenId The token identifier to give approval for. function approve(address to, uint256 tokenId) external; /// @notice Sets or unsets an approval to transfer all tokens on behalf of their owner. /// @dev Reverts if the sender is the same as `operator`. /// @dev Emits an {ApprovalForAll} event. /// @param operator The address to approve for all tokens. /// @param approved True to set an approval for all tokens, false to unset it. function setApprovalForAll(address operator, bool approved) external; /// @notice Unsafely transfers the ownership of a token to a recipient. /// @dev Note: Usage of this method is discouraged, use `safeTransferFrom` whenever possible. /// @dev Resets the token approval for `tokenId`. /// @dev Reverts if `to` is the zero address. /// @dev Reverts if `from` is not the owner of `tokenId`. /// @dev Reverts if the sender is not `from` and has not been approved by `from` for `tokenId`. /// @dev Emits a {Transfer} event. /// @param from The current token owner. /// @param to The recipient of the token transfer. Self-transfers are possible. /// @param tokenId The identifier of the token to transfer. function transferFrom(address from, address to, uint256 tokenId) external; /// @notice Safely transfers the ownership of a token to a recipient. /// @dev Resets the token approval for `tokenId`. /// @dev Reverts if `to` is the zero address. /// @dev Reverts if `from` is not the owner of `tokenId`. /// @dev Reverts if the sender is not `from` and has not been approved by `from` for `tokenId`. /// @dev Reverts if `to` is a contract and the call to {IERC721Receiver-onERC721Received} fails, reverts or is rejected. /// @dev Emits a {Transfer} event. /// @param from The current token owner. /// @param to The recipient of the token transfer. /// @param tokenId The identifier of the token to transfer. function safeTransferFrom(address from, address to, uint256 tokenId) external; /// @notice Safely transfers the ownership of a token to a recipient. /// @dev Resets the token approval for `tokenId`. /// @dev Reverts if `to` is the zero address. /// @dev Reverts if `from` is not the owner of `tokenId`. /// @dev Reverts if the sender is not `from` and has not been approved by `from` for `tokenId`. /// @dev Reverts if `to` is a contract and the call to {IERC721Receiver-onERC721Received} fails, reverts or is rejected. /// @dev Emits a {Transfer} event. /// @param from The current token owner. /// @param to The recipient of the token transfer. /// @param tokenId The identifier of the token to transfer. /// @param data Optional data to send along to a receiver contract. function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /// @notice Gets the balance of an address. /// @dev Reverts if `owner` is the zero address. /// @param owner The address to query the balance of. /// @return balance The amount owned by the owner. function balanceOf(address owner) external view returns (uint256 balance); /// @notice Gets the owner of a token. /// @dev Reverts if `tokenId` does not exist. /// @param tokenId The token identifier to query the owner of. /// @return tokenOwner The owner of the token identifier. function ownerOf(uint256 tokenId) external view returns (address tokenOwner); /// @notice Gets the approved address for a token. /// @dev Reverts if `tokenId` does not exist. /// @param tokenId The token identifier to query the approval of. /// @return approved The approved address for the token identifier, or the zero address if no approval is set. function getApproved(uint256 tokenId) external view returns (address approved); /// @notice Gets whether an operator is approved for all tokens by an owner. /// @param owner The address which gives the approval for all tokens. /// @param operator The address which receives the approval for all tokens. /// @return approvedForAll Whether the operator is approved for all tokens by the owner. function isApprovedForAll(address owner, address operator) external view returns (bool approvedForAll); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @title ERC721 Non-Fungible Token Standard, optional extension: Batch Transfer. /// @dev See https://eips.ethereum.org/EIPS/eip-721 /// @dev Note: The ERC-165 identifier for this interface is 0xf3993d11. interface IERC721BatchTransfer { /// @notice Unsafely transfers a batch of tokens to a recipient. /// @dev Resets the token approval for each of `tokenIds`. /// @dev Reverts if `to` is the zero address. /// @dev Reverts if one of `tokenIds` is not owned by `from`. /// @dev Reverts if the sender is not `from` and has not been approved by `from` for each of `tokenIds`. /// @dev Emits an {IERC721-Transfer} event for each of `tokenIds`. /// @param from Current tokens owner. /// @param to Address of the new token owner. /// @param tokenIds Identifiers of the tokens to transfer. function batchTransferFrom(address from, address to, uint256[] calldata tokenIds) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @title ERC721 Non-Fungible Token Standard, optional extension: Burnable. /// @dev See https://eips.ethereum.org/EIPS/eip-721 /// @dev Note: The ERC-165 identifier for this interface is 0x8b8b4ef5. interface IERC721Burnable { /// @notice Burns a token. /// @dev Reverts if `tokenId` is not owned by `from`. /// @dev Reverts if the sender is not `from` and has not been approved by `from` for `tokenId`. /// @dev Emits an {IERC721-Transfer} event with `to` set to the zero address. /// @param from The current token owner. /// @param tokenId The identifier of the token to burn. function burnFrom(address from, uint256 tokenId) external; /// @notice Burns a batch of tokens. /// @dev Reverts if one of `tokenIds` is not owned by `from`. /// @dev Reverts if the sender is not `from` and has not been approved by `from` for each of `tokenIds`. /// @dev Emits an {IERC721-Transfer} event with `to` set to the zero address for each of `tokenIds`. /// @param from The current tokens owner. /// @param tokenIds The identifiers of the tokens to burn. function batchBurnFrom(address from, uint256[] calldata tokenIds) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @title ERC721 Non-Fungible Token Standard, optional extension: Deliverable. /// @dev See https://eips.ethereum.org/EIPS/eip-721 /// @dev Note: The ERC-165 identifier for this interface is 0x9da5e832. interface IERC721Deliverable { /// @notice Unsafely mints tokens to multiple recipients. /// @dev Reverts if `recipients` and `tokenIds` have different lengths. /// @dev Reverts if one of `recipients` is the zero address. /// @dev Reverts if one of `tokenIds` already exists. /// @dev Emits an {IERC721-Transfer} event from the zero address for each of `recipients` and `tokenIds`. /// @param recipients Addresses of the new tokens owners. /// @param tokenIds Identifiers of the tokens to mint. function deliver(address[] calldata recipients, uint256[] calldata tokenIds) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @title ERC721 Non-Fungible Token Standard, optional extension: Metadata. /// @dev See https://eips.ethereum.org/EIPS/eip-721 /// @dev Note: The ERC-165 identifier for this interface is 0x5b5e139f. interface IERC721Metadata { /// @notice Gets the name of the token. E.g. "My Token". /// @return tokenName The name of the token. function name() external view returns (string memory tokenName); /// @notice Gets the symbol of the token. E.g. "TOK". /// @return tokenSymbol The symbol of the token. function symbol() external view returns (string memory tokenSymbol); /// @notice Gets the metadata URI for a token identifier. /// @dev Reverts if `tokenId` does not exist. /// @param tokenId The token identifier. /// @return uri The metadata URI for the token identifier. function tokenURI(uint256 tokenId) external view returns (string memory uri); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @title ERC721 Non-Fungible Token Standard, optional extension: Mintable. /// @dev See https://eips.ethereum.org/EIPS/eip-721 /// @dev Note: The ERC-165 identifier for this interface is 0x8e773e13. interface IERC721Mintable { /// @notice Unsafely mints a token. /// @dev Reverts if `to` is the zero address. /// @dev Reverts if `tokenId` already exists. /// @dev Emits an {IERC721-Transfer} event from the zero address. /// @param to Address of the new token owner. /// @param tokenId Identifier of the token to mint. function mint(address to, uint256 tokenId) external; /// @notice Safely mints a token. /// @dev Reverts if `to` is the zero address. /// @dev Reverts if `tokenId` already exists. /// @dev Reverts if `to` is a contract and the call to {IERC721Receiver-onERC721Received} fails, reverts or is rejected. /// @dev Emits an {IERC721-Transfer} event from the zero address. /// @param to Address of the new token owner. /// @param tokenId Identifier of the token to mint. /// @param data Optional data to pass along to the receiver call. function safeMint(address to, uint256 tokenId, bytes calldata data) external; /// @notice Unsafely mints a batch of tokens. /// @dev Reverts if `to` is the zero address. /// @dev Reverts if one of `tokenIds` already exists. /// @dev Emits an {IERC721-Transfer} event from the zero address for each of `tokenIds`. /// @param to Address of the new tokens owner. /// @param tokenIds Identifiers of the tokens to mint. function batchMint(address to, uint256[] calldata tokenIds) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @title ERC721 Non-Fungible Token Standard, Tokens Receiver. /// @notice Interface for supporting safe transfers from ERC721 contracts. /// @dev See https://eips.ethereum.org/EIPS/eip-721 /// @dev Note: The ERC-165 identifier for this interface is 0x150b7a02. interface IERC721Receiver { /// @notice Handles the receipt of an ERC721 token. /// @dev Note: This function is called by an ERC721 contract after a safe transfer. /// @dev Note: The ERC721 contract address is always the message sender. /// @param operator The initiator of the safe transfer. /// @param from The previous token owner. /// @param tokenId The token identifier. /// @param data Optional additional data with no specified format. /// @return magicValue `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` (`0x150b7a02`) to accept, any other value to refuse. function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4 magicValue); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; // solhint-disable-next-line max-line-length import {ERC721SelfApproval, ERC721SelfApprovalForAll, ERC721NonApprovedForApproval, ERC721TransferToAddressZero, ERC721NonExistingToken, ERC721NonApprovedForTransfer, ERC721NonOwnedToken, ERC721SafeTransferRejected, ERC721BalanceOfAddressZero} from "./../errors/ERC721Errors.sol"; import {ERC721MintToAddressZero, ERC721ExistingToken} from "./../errors/ERC721MintableErrors.sol"; import {ERC721BurntToken} from "./../errors/ERC721MintableOnceErrors.sol"; import {InconsistentArrayLengths} from "./../../../CommonErrors.sol"; import {Transfer, Approval, ApprovalForAll} from "./../events/ERC721Events.sol"; import {IERC721} from "./../interfaces/IERC721.sol"; import {IERC721BatchTransfer} from "./../interfaces/IERC721BatchTransfer.sol"; import {IERC721Metadata} from "./../interfaces/IERC721Metadata.sol"; import {IERC721Mintable} from "./../interfaces/IERC721Mintable.sol"; import {IERC721Deliverable} from "./../interfaces/IERC721Deliverable.sol"; import {IERC721Burnable} from "./../interfaces/IERC721Burnable.sol"; import {IERC721Receiver} from "./../interfaces/IERC721Receiver.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {InterfaceDetectionStorage} from "./../../../introspection/libraries/InterfaceDetectionStorage.sol"; library ERC721Storage { using Address for address; using ERC721Storage for ERC721Storage.Layout; using InterfaceDetectionStorage for InterfaceDetectionStorage.Layout; struct Layout { mapping(uint256 => uint256) owners; mapping(address => uint256) balances; mapping(uint256 => address) approvals; mapping(address => mapping(address => bool)) operators; } bytes32 internal constant LAYOUT_STORAGE_SLOT = bytes32(uint256(keccak256("animoca.token.ERC721.ERC721.storage")) - 1); bytes4 internal constant ERC721_RECEIVED = IERC721Receiver.onERC721Received.selector; // Single token approval flag // This bit is set in the owner's value to indicate that there is an approval set for this token uint256 internal constant TOKEN_APPROVAL_OWNER_FLAG = 1 << 160; // Burnt token magic value // This magic number is used as the owner's value to indicate that the token has been burnt uint256 internal constant BURNT_TOKEN_OWNER_VALUE = 0xdead000000000000000000000000000000000000000000000000000000000000; /// @notice Marks the following ERC165 interface(s) as supported: ERC721. function init() internal { InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC721).interfaceId, true); } /// @notice Marks the following ERC165 interface(s) as supported: ERC721BatchTransfer. function initERC721BatchTransfer() internal { InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC721BatchTransfer).interfaceId, true); } /// @notice Marks the following ERC165 interface(s) as supported: ERC721Metadata. function initERC721Metadata() internal { InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC721Metadata).interfaceId, true); } /// @notice Marks the following ERC165 interface(s) as supported: ERC721Mintable. function initERC721Mintable() internal { InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC721Mintable).interfaceId, true); } /// @notice Marks the following ERC165 interface(s) as supported: ERC721Deliverable. function initERC721Deliverable() internal { InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC721Deliverable).interfaceId, true); } /// @notice Marks the following ERC165 interface(s) as supported: ERC721Burnable. function initERC721Burnable() internal { InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC721Burnable).interfaceId, true); } /// @notice Sets or unsets an approval to transfer a single token on behalf of its owner. /// @dev Note: This function implements {ERC721-approve(address,uint256)}. /// @dev Reverts with {ERC721NonExistingToken} if `tokenId` does not exist. /// @dev Reverts with {ERC721SelfApproval} if `to` is the token owner. /// @dev Reverts with {ERC721NonApprovedForApproval} if `sender` is not the token owner and has not been approved by the token owner. /// @dev Emits an {Approval} event. /// @param sender The message sender. /// @param to The address to approve, or the zero address to remove any existing approval. /// @param tokenId The token identifier to give approval for. function approve(Layout storage s, address sender, address to, uint256 tokenId) internal { uint256 owner = s.owners[tokenId]; if (!_tokenExists(owner)) revert ERC721NonExistingToken(tokenId); address ownerAddress = _tokenOwner(owner); if (to == ownerAddress) revert ERC721SelfApproval(ownerAddress); if (!_isOperatable(s, ownerAddress, sender)) revert ERC721NonApprovedForApproval(sender, ownerAddress, tokenId); if (to == address(0)) { if (_tokenHasApproval(owner)) { // remove the approval bit if it is present s.owners[tokenId] = uint256(uint160(ownerAddress)); } } else { uint256 ownerWithApprovalBit = owner | TOKEN_APPROVAL_OWNER_FLAG; if (owner != ownerWithApprovalBit) { // add the approval bit if it is not present s.owners[tokenId] = ownerWithApprovalBit; } s.approvals[tokenId] = to; } emit Approval(ownerAddress, to, tokenId); } /// @notice Sets or unsets an approval to transfer all tokens on behalf of their owner. /// @dev Note: This function implements {ERC721-setApprovalForAll(address,bool)}. /// @dev Reverts with {ERC721SelfApprovalForAll} if `sender` is the same as `operator`. /// @dev Emits an {ApprovalForAll} event. /// @param sender The message sender. /// @param operator The address to approve for all tokens. /// @param approved True to set an approval for all tokens, false to unset it. function setApprovalForAll(Layout storage s, address sender, address operator, bool approved) internal { if (operator == sender) revert ERC721SelfApprovalForAll(sender); s.operators[sender][operator] = approved; emit ApprovalForAll(sender, operator, approved); } /// @notice Unsafely transfers the ownership of a token to a recipient by a sender. /// @dev Note: This function implements {ERC721-transferFrom(address,address,uint256)}. /// @dev Resets the token approval for `tokenId`. /// @dev Reverts with {ERC721TransferToAddressZero} if `to` is the zero address. /// @dev Reverts with {ERC721NonExistingToken} if `tokenId` does not exist. /// @dev Reverts with {ERC721NonOwnedToken} if `from` is not the owner of `tokenId`. /// @dev Reverts with {ERC721NonApprovedForTransfer} if `sender` is not `from` and has not been approved by `from` for `tokenId`. /// @dev Emits a {Transfer} event. /// @param sender The message sender. /// @param from The current token owner. /// @param to The recipient of the token transfer. /// @param tokenId The identifier of the token to transfer. function transferFrom(Layout storage s, address sender, address from, address to, uint256 tokenId) internal { if (to == address(0)) revert ERC721TransferToAddressZero(); uint256 owner = s.owners[tokenId]; if (!_tokenExists(owner)) revert ERC721NonExistingToken(tokenId); if (_tokenOwner(owner) != from) revert ERC721NonOwnedToken(from, tokenId); if (!_isOperatable(s, from, sender)) { if (!_tokenHasApproval(owner) || sender != s.approvals[tokenId]) revert ERC721NonApprovedForTransfer(sender, from, tokenId); } s.owners[tokenId] = uint256(uint160(to)); if (from != to) { unchecked { // cannot underflow as balance is verified through ownership --s.balances[from]; // cannot overflow as supply cannot overflow ++s.balances[to]; } } emit Transfer(from, to, tokenId); } /// @notice Safely transfers the ownership of a token to a recipient by a sender. /// @dev Note: This function implements {ERC721-safeTransferFrom(address,address,uint256)}. /// @dev Warning: Since a `to` contract can run arbitrary code, developers should be aware of potential re-entrancy attacks. /// @dev Resets the token approval for `tokenId`. /// @dev Reverts with {ERC721TransferToAddressZero} if `to` is the zero address. /// @dev Reverts with {ERC721NonExistingToken} if `tokenId` does not exist. /// @dev Reverts with {ERC721NonOwnedToken} if `from` is not the owner of `tokenId`. /// @dev Reverts with {ERC721NonApprovedForTransfer} if `sender` is not `from` and has not been approved by `from` for `tokenId`. /// @dev Reverts with {ERC721SafeTransferRejected} if `to` is a contract and the call to /// {IERC721Receiver-onERC721Received} fails, reverts or is rejected. /// @dev Emits a {Transfer} event. /// @param sender The message sender. /// @param from The current token owner. /// @param to The recipient of the token transfer. /// @param tokenId The identifier of the token to transfer. function safeTransferFrom(Layout storage s, address sender, address from, address to, uint256 tokenId) internal { s.transferFrom(sender, from, to, tokenId); if (to.isContract()) { _callOnERC721Received(sender, from, to, tokenId, ""); } } /// @notice Safely transfers the ownership of a token to a recipient by a sender. /// @dev Note: This function implements {ERC721-safeTransferFrom(address,address,uint256,bytes)}. /// @dev Warning: Since a `to` contract can run arbitrary code, developers should be aware of potential re-entrancy attacks. /// @dev Resets the token approval for `tokenId`. /// @dev Reverts with {ERC721TransferToAddressZero} if `to` is the zero address. /// @dev Reverts with {ERC721NonExistingToken} if `tokenId` does not exist. /// @dev Reverts with {ERC721NonOwnedToken} if `from` is not the owner of `tokenId`. /// @dev Reverts with {ERC721NonApprovedForTransfer} if `sender` is not `from` and has not been approved by `from` for `tokenId`. /// @dev Reverts with {ERC721SafeTransferRejected} if `to` is a contract and the call to /// {IERC721Receiver-onERC721Received} fails, reverts or is rejected. /// @dev Emits a {Transfer} event. /// @param sender The message sender. /// @param from The current token owner. /// @param to The recipient of the token transfer. /// @param tokenId The identifier of the token to transfer. /// @param data Optional data to send along to a receiver contract. function safeTransferFrom(Layout storage s, address sender, address from, address to, uint256 tokenId, bytes calldata data) internal { s.transferFrom(sender, from, to, tokenId); if (to.isContract()) { _callOnERC721Received(sender, from, to, tokenId, data); } } /// @notice Unsafely transfers a batch of tokens to a recipient by a sender. /// @dev Note: This function implements {ERC721BatchTransfer-batchTransferFrom(address,address,uint256[])}. /// @dev Resets the token approval for each of `tokenIds`. /// @dev Reverts with {ERC721TransferToAddressZero} if `to` is the zero address. /// @dev Reverts with {ERC721NonExistingToken} if one of `tokenIds` does not exist. /// @dev Reverts with {ERC721NonOwnedToken} if one of `tokenIds` is not owned by `from`. /// @dev Reverts with {ERC721NonApprovedForTransfer} if the sender is not `from` and has not been approved by `from` for each of `tokenIds`. /// @dev Emits a {Transfer} event for each of `tokenIds`. /// @param sender The message sender. /// @param from Current tokens owner. /// @param to Address of the new token owner. /// @param tokenIds Identifiers of the tokens to transfer. function batchTransferFrom(Layout storage s, address sender, address from, address to, uint256[] calldata tokenIds) internal { if (to == address(0)) revert ERC721TransferToAddressZero(); bool operatable = _isOperatable(s, from, sender); uint256 length = tokenIds.length; for (uint256 i; i < length; ++i) { uint256 tokenId = tokenIds[i]; uint256 owner = s.owners[tokenId]; if (!_tokenExists(owner)) revert ERC721NonExistingToken(tokenId); if (_tokenOwner(owner) != from) revert ERC721NonOwnedToken(from, tokenId); if (!operatable) { if (!_tokenHasApproval(owner) || sender != s.approvals[tokenId]) revert ERC721NonApprovedForTransfer(sender, from, tokenId); } s.owners[tokenId] = uint256(uint160(to)); emit Transfer(from, to, tokenId); } if (from != to && length != 0) { unchecked { // cannot underflow as balance is verified through ownership s.balances[from] -= length; // cannot overflow as supply cannot overflow s.balances[to] += length; } } } /// @notice Unsafely mints a token. /// @dev Note: This function implements {ERC721Mintable-mint(address,uint256)}. /// @dev Note: Either `mint` or `mintOnce` should be used in a given contract, but not both. /// @dev Reverts with {ERC721MintToAddressZero} if `to` is the zero address. /// @dev Reverts with {ERC721ExistingToken} if `tokenId` already exists. /// @dev Emits a {Transfer} event from the zero address. /// @param to Address of the new token owner. /// @param tokenId Identifier of the token to mint. function mint(Layout storage s, address to, uint256 tokenId) internal { if (to == address(0)) revert ERC721MintToAddressZero(); if (_tokenExists(s.owners[tokenId])) revert ERC721ExistingToken(tokenId); s.owners[tokenId] = uint256(uint160(to)); unchecked { // cannot overflow due to the cost of minting individual tokens ++s.balances[to]; } emit Transfer(address(0), to, tokenId); } /// @notice Safely mints a token. /// @dev Note: This function implements {ERC721Mintable-safeMint(address,uint256,bytes)}. /// @dev Note: Either `safeMint` or `safeMintOnce` should be used in a given contract, but not both. /// @dev Warning: Since a `to` contract can run arbitrary code, developers should be aware of potential re-entrancy attacks. /// @dev Reverts with {ERC721MintToAddressZero} if `to` is the zero address. /// @dev Reverts with {ERC721ExistingToken} if `tokenId` already exists. /// @dev Reverts with {ERC721SafeTransferRejected} if `to` is a contract and the call to /// {IERC721Receiver-onERC721Received} fails, reverts or is rejected. /// @dev Emits a {Transfer} event from the zero address. /// @param to Address of the new token owner. /// @param tokenId Identifier of the token to mint. /// @param data Optional data to pass along to the receiver call. function safeMint(Layout storage s, address sender, address to, uint256 tokenId, bytes memory data) internal { s.mint(to, tokenId); if (to.isContract()) { _callOnERC721Received(sender, address(0), to, tokenId, data); } } /// @notice Unsafely mints a batch of tokens. /// @dev Note: This function implements {ERC721Mintable-batchMint(address,uint256[])}. /// @dev Note: Either `batchMint` or `batchMintOnce` should be used in a given contract, but not both. /// @dev Reverts with {ERC721MintToAddressZero} if `to` is the zero address. /// @dev Reverts with {ERC721ExistingToken} if one of `tokenIds` already exists. /// @dev Emits a {Transfer} event from the zero address for each of `tokenIds`. /// @param to Address of the new tokens owner. /// @param tokenIds Identifiers of the tokens to mint. function batchMint(Layout storage s, address to, uint256[] memory tokenIds) internal { if (to == address(0)) revert ERC721MintToAddressZero(); uint256 length = tokenIds.length; for (uint256 i; i < length; ++i) { uint256 tokenId = tokenIds[i]; if (_tokenExists(s.owners[tokenId])) revert ERC721ExistingToken(tokenId); s.owners[tokenId] = uint256(uint160(to)); emit Transfer(address(0), to, tokenId); } unchecked { s.balances[to] += length; } } /// @notice Unsafely mints tokens to multiple recipients. /// @dev Note: This function implements {ERC721Deliverable-deliver(address[],uint256[])}. /// @dev Note: Either `deliver` or `deliverOnce` should be used in a given contract, but not both. /// @dev Reverts with {InconsistentArrayLengths} if `recipients` and `tokenIds` have different lengths. /// @dev Reverts with {ERC721MintToAddressZero} if one of `recipients` is the zero address. /// @dev Reverts with {ERC721ExistingToken} if one of `tokenIds` already exists. /// @dev Emits a {Transfer} event from the zero address for each of `recipients` and `tokenIds`. /// @param recipients Addresses of the new tokens owners. /// @param tokenIds Identifiers of the tokens to mint. function deliver(Layout storage s, address[] memory recipients, uint256[] memory tokenIds) internal { uint256 length = recipients.length; if (length != tokenIds.length) revert InconsistentArrayLengths(); for (uint256 i; i < length; ++i) { s.mint(recipients[i], tokenIds[i]); } } /// @notice Unsafely mints a token once. /// @dev Note: This function implements {ERC721Mintable-mint(address,uint256)}. /// @dev Note: Either `mint` or `mintOnce` should be used in a given contract, but not both. /// @dev Reverts with {ERC721MintToAddressZero} if `to` is the zero address. /// @dev Reverts with {ERC721ExistingToken} if `tokenId` already exists. /// @dev Reverts with {ERC721BurntToken} if `tokenId` has been previously burnt. /// @dev Emits a {Transfer} event from the zero address. /// @param to Address of the new token owner. /// @param tokenId Identifier of the token to mint. function mintOnce(Layout storage s, address to, uint256 tokenId) internal { if (to == address(0)) revert ERC721MintToAddressZero(); uint256 owner = s.owners[tokenId]; if (_tokenExists(owner)) revert ERC721ExistingToken(tokenId); if (_tokenWasBurnt(owner)) revert ERC721BurntToken(tokenId); s.owners[tokenId] = uint256(uint160(to)); unchecked { // cannot overflow due to the cost of minting individual tokens ++s.balances[to]; } emit Transfer(address(0), to, tokenId); } /// @notice Safely mints a token once. /// @dev Note: This function implements {ERC721Mintable-safeMint(address,uint256,bytes)}. /// @dev Note: Either `safeMint` or `safeMintOnce` should be used in a given contract, but not both. /// @dev Reverts with {ERC721MintToAddressZero} if `to` is the zero address. /// @dev Reverts with {ERC721ExistingToken} if `tokenId` already exists. /// @dev Reverts with {ERC721BurntToken} if `tokenId` has been previously burnt. /// @dev Reverts with {ERC721SafeTransferRejected} if `to` is a contract and the call to /// {IERC721Receiver-onERC721Received} fails, reverts or is rejected. /// @dev Emits a {Transfer} event from the zero address. /// @param to Address of the new token owner. /// @param tokenId Identifier of the token to mint. /// @param data Optional data to pass along to the receiver call. function safeMintOnce(Layout storage s, address sender, address to, uint256 tokenId, bytes memory data) internal { s.mintOnce(to, tokenId); if (to.isContract()) { _callOnERC721Received(sender, address(0), to, tokenId, data); } } /// @notice Unsafely mints a batch of tokens once. /// @dev Note: This function implements {ERC721Mintable-batchMint(address,uint256[])}. /// @dev Note: Either `batchMint` or `batchMintOnce` should be used in a given contract, but not both. /// @dev Reverts with {ERC721MintToAddressZero} if `to` is the zero address. /// @dev Reverts with {ERC721ExistingToken} if one of `tokenIds` already exists. /// @dev Reverts with {ERC721BurntToken} if one of `tokenIds` has been previously burnt. /// @dev Emits a {Transfer} event from the zero address for each of `tokenIds`. /// @param to Address of the new tokens owner. /// @param tokenIds Identifiers of the tokens to mint. function batchMintOnce(Layout storage s, address to, uint256[] memory tokenIds) internal { if (to == address(0)) revert ERC721MintToAddressZero(); uint256 length = tokenIds.length; for (uint256 i; i < length; ++i) { uint256 tokenId = tokenIds[i]; uint256 owner = s.owners[tokenId]; if (_tokenExists(owner)) revert ERC721ExistingToken(tokenId); if (_tokenWasBurnt(owner)) revert ERC721BurntToken(tokenId); s.owners[tokenId] = uint256(uint160(to)); emit Transfer(address(0), to, tokenId); } unchecked { s.balances[to] += length; } } /// @notice Unsafely mints tokens to multiple recipients once. /// @dev Note: This function implements {ERC721Deliverable-deliver(address[],uint256[])}. /// @dev Note: Either `deliver` or `deliverOnce` should be used in a given contract, but not both. /// @dev Reverts with {InconsistentArrayLengths} if `recipients` and `tokenIds` have different lengths. /// @dev Reverts with {ERC721MintToAddressZero} if one of `recipients` is the zero address. /// @dev Reverts with {ERC721ExistingToken} if one of `tokenIds` already exists. /// @dev Reverts with {ERC721BurntToken} if one of `tokenIds` has been previously burnt. /// @dev Emits a {Transfer} event from the zero address for each of `recipients` and `tokenIds`. /// @param recipients Addresses of the new tokens owners. /// @param tokenIds Identifiers of the tokens to mint. function deliverOnce(Layout storage s, address[] memory recipients, uint256[] memory tokenIds) internal { uint256 length = recipients.length; if (length != tokenIds.length) revert InconsistentArrayLengths(); for (uint256 i; i < length; ++i) { address to = recipients[i]; if (to == address(0)) revert ERC721MintToAddressZero(); uint256 tokenId = tokenIds[i]; uint256 owner = s.owners[tokenId]; if (_tokenExists(owner)) revert ERC721ExistingToken(tokenId); if (_tokenWasBurnt(owner)) revert ERC721BurntToken(tokenId); s.owners[tokenId] = uint256(uint160(to)); unchecked { ++s.balances[to]; } emit Transfer(address(0), to, tokenId); } } /// @notice Burns a token by a sender. /// @dev Note: This function implements {ERC721Burnable-burnFrom(address,uint256)}. /// @dev Reverts with {ERC721NonOwnedToken} if `tokenId` is not owned by `from`. /// @dev Reverts with {ERC721NonApprovedForTransfer} if `sender` is not `from` and has not been approved by `from` for `tokenId`. /// @dev Emits a {Transfer} event with `to` set to the zero address. /// @param sender The message sender. /// @param from The current token owner. /// @param tokenId The identifier of the token to burn. function burnFrom(Layout storage s, address sender, address from, uint256 tokenId) internal { uint256 owner = s.owners[tokenId]; if (!_tokenExists(owner)) revert ERC721NonExistingToken(tokenId); if (_tokenOwner(owner) != from) revert ERC721NonOwnedToken(from, tokenId); if (!_isOperatable(s, from, sender)) { if (!_tokenHasApproval(owner) || sender != s.approvals[tokenId]) revert ERC721NonApprovedForTransfer(sender, from, tokenId); } s.owners[tokenId] = BURNT_TOKEN_OWNER_VALUE; unchecked { // cannot underflow as balance is verified through TOKEN ownership --s.balances[from]; } emit Transfer(from, address(0), tokenId); } /// @notice Burns a batch of tokens by a sender. /// @dev Note: This function implements {ERC721Burnable-batchBurnFrom(address,uint256[])}. /// @dev Reverts with {ERC721NonOwnedToken} if one of `tokenIds` is not owned by `from`. /// @dev Reverts with {ERC721NonApprovedForTransfer} if `sender` is not `from` and has not been approved by `from` for each of `tokenIds`. /// @dev Emits a {Transfer} event with `to` set to the zero address for each of `tokenIds`. /// @param sender The message sender. /// @param from The current tokens owner. /// @param tokenIds The identifiers of the tokens to burn. function batchBurnFrom(Layout storage s, address sender, address from, uint256[] calldata tokenIds) internal { bool operatable = _isOperatable(s, from, sender); uint256 length = tokenIds.length; for (uint256 i; i < length; ++i) { uint256 tokenId = tokenIds[i]; uint256 owner = s.owners[tokenId]; if (!_tokenExists(owner)) revert ERC721NonExistingToken(tokenId); if (_tokenOwner(owner) != from) revert ERC721NonOwnedToken(from, tokenId); if (!operatable) { if (!_tokenHasApproval(owner) || sender != s.approvals[tokenId]) revert ERC721NonApprovedForTransfer(sender, from, tokenId); } s.owners[tokenId] = BURNT_TOKEN_OWNER_VALUE; emit Transfer(from, address(0), tokenId); } if (length != 0) { unchecked { s.balances[from] -= length; } } } /// @notice Gets the balance of an address. /// @dev Note: This function implements {ERC721-balanceOf(address)}. /// @dev Reverts with {ERC721BalanceOfAddressZero} if `owner` is the zero address. /// @param owner The address to query the balance of. /// @return balance The amount owned by the owner. function balanceOf(Layout storage s, address owner) internal view returns (uint256 balance) { if (owner == address(0)) revert ERC721BalanceOfAddressZero(); return s.balances[owner]; } /// @notice Gets the owner of a token. /// @dev Note: This function implements {ERC721-ownerOf(uint256)}. /// @dev Reverts with {ERC721NonExistingToken} if `tokenId` does not exist. /// @param tokenId The token identifier to query the owner of. /// @return tokenOwner The owner of the token. function ownerOf(Layout storage s, uint256 tokenId) internal view returns (address tokenOwner) { uint256 owner = s.owners[tokenId]; if (!_tokenExists(owner)) revert ERC721NonExistingToken(tokenId); return _tokenOwner(owner); } /// @notice Gets the approved address for a token. /// @dev Note: This function implements {ERC721-getApproved(uint256)}. /// @dev Reverts with {ERC721NonExistingToken} if `tokenId` does not exist. /// @param tokenId The token identifier to query the approval of. /// @return approved The approved address for the token identifier, or the zero address if no approval is set. function getApproved(Layout storage s, uint256 tokenId) internal view returns (address approved) { uint256 owner = s.owners[tokenId]; if (!_tokenExists(owner)) revert ERC721NonExistingToken(tokenId); if (_tokenHasApproval(owner)) { return s.approvals[tokenId]; } else { return address(0); } } /// @notice Gets whether an operator is approved for all tokens by an owner. /// @dev Note: This function implements {ERC721-isApprovedForAll(address,address)}. /// @param owner The address which gives the approval for all tokens. /// @param operator The address which receives the approval for all tokens. /// @return approvedForAll Whether the operator is approved for all tokens by the owner. function isApprovedForAll(Layout storage s, address owner, address operator) internal view returns (bool approvedForAll) { return s.operators[owner][operator]; } /// @notice Gets whether a token was burnt. /// @param tokenId The token identifier. /// @return tokenWasBurnt Whether the token was burnt. function wasBurnt(Layout storage s, uint256 tokenId) internal view returns (bool tokenWasBurnt) { return _tokenWasBurnt(s.owners[tokenId]); } function layout() internal pure returns (Layout storage s) { bytes32 position = LAYOUT_STORAGE_SLOT; assembly { s.slot := position } } /// @notice Calls {IERC721Receiver-onERC721Received} on a target contract. /// @dev Reverts with {ERC721SafeTransferRejected} if the call to the target fails, reverts or is rejected. /// @param sender The message sender. /// @param from Previous token owner. /// @param to New token owner. /// @param tokenId Identifier of the token transferred. /// @param data Optional data to send along with the receiver contract call. function _callOnERC721Received(address sender, address from, address to, uint256 tokenId, bytes memory data) private { if (IERC721Receiver(to).onERC721Received(sender, from, tokenId, data) != ERC721_RECEIVED) revert ERC721SafeTransferRejected(to, tokenId); } /// @notice Returns whether an account is authorised to make a transfer on behalf of an owner. /// @param owner The token owner. /// @param account The account to check the operatability of. /// @return operatable True if `account` is `owner` or is an operator for `owner`, false otherwise. function _isOperatable(Layout storage s, address owner, address account) private view returns (bool operatable) { return (owner == account) || s.operators[owner][account]; } function _tokenOwner(uint256 owner) private pure returns (address tokenOwner) { return address(uint160(owner)); } function _tokenExists(uint256 owner) private pure returns (bool tokenExists) { return uint160(owner) != 0; } function _tokenWasBurnt(uint256 owner) private pure returns (bool tokenWasBurnt) { return owner == BURNT_TOKEN_OWNER_VALUE; } function _tokenHasApproval(uint256 owner) private pure returns (bool tokenHasApproval) { return owner & TOKEN_APPROVAL_OWNER_FLAG != 0; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {ITokenMetadataResolver} from "./../interfaces/ITokenMetadataResolver.sol"; import {TokenMetadataStorage} from "./../libraries/TokenMetadataStorage.sol"; /// @title TokenMetadataBase (proxiable version). /// @notice Provides metadata management for token contracts (ERC721/ERC1155) which uses an external resolver for managing individual tokens metadata. /// @dev This contract is to be used via inheritance in a proxied implementation. abstract contract TokenMetadataBase { using TokenMetadataStorage for TokenMetadataStorage.Layout; /// @notice Gets the token name. E.g. "My Token". /// @return tokenName The token name. function name() public view virtual returns (string memory tokenName) { return TokenMetadataStorage.layout().name(); } /// @notice Gets the token symbol. E.g. "TOK". /// @return tokenSymbol The token symbol. function symbol() public view virtual returns (string memory tokenSymbol) { return TokenMetadataStorage.layout().symbol(); } /// @notice Gets the token metadata resolver address. /// @return tokenMetadataResolver The token metadata resolver address. function metadataResolver() external view virtual returns (ITokenMetadataResolver tokenMetadataResolver) { return TokenMetadataStorage.layout().metadataResolver(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @title ITokenMetadataResolver /// @notice Interface for Token Metadata Resolvers. interface ITokenMetadataResolver { /// @notice Gets the token metadata URI for a token. /// @param tokenContract The token contract for which to retrieve the token URI. /// @param tokenId The token identifier. /// @return tokenURI The token metadata URI. function tokenMetadataURI(address tokenContract, uint256 tokenId) external view returns (string memory tokenURI); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {ITokenMetadataResolver} from "./../interfaces/ITokenMetadataResolver.sol"; import {ProxyInitialization} from "./../../../proxy/libraries/ProxyInitialization.sol"; library TokenMetadataStorage { struct Layout { string tokenName; string tokenSymbol; ITokenMetadataResolver tokenMetadataResolver; } bytes32 internal constant LAYOUT_STORAGE_SLOT = bytes32(uint256(keccak256("animoca.token.metadata.TokenMetadata.storage")) - 1); bytes32 internal constant PROXY_INIT_PHASE_SLOT = bytes32(uint256(keccak256("animoca.token.metadata.TokenMetadata.phase")) - 1); /// @notice Initializes the metadata storage (immutable version). /// @dev Note: This function should be called ONLY in the constructor of an immutable (non-proxied) contract. /// @param tokenName The token name. /// @param tokenSymbol The token symbol. /// @param tokenMetadataResolver The address of the metadata resolver contract. function constructorInit( Layout storage s, string memory tokenName, string memory tokenSymbol, ITokenMetadataResolver tokenMetadataResolver ) internal { s.tokenName = tokenName; s.tokenSymbol = tokenSymbol; s.tokenMetadataResolver = tokenMetadataResolver; } /// @notice Initializes the metadata storage (proxied version). /// @notice Sets the proxy initialization phase to `1`. /// @dev Note: This function should be called ONLY in the init function of a proxied contract. /// @dev Reverts with {InitializationPhaseAlreadyReached} if the proxy initialization phase is set to `1` or above. /// @param tokenName The token name. /// @param tokenSymbol The token symbol. /// @param tokenMetadataResolver The address of the metadata resolver contract. function proxyInit( Layout storage s, string calldata tokenName, string calldata tokenSymbol, ITokenMetadataResolver tokenMetadataResolver ) internal { ProxyInitialization.setPhase(PROXY_INIT_PHASE_SLOT, 1); s.tokenName = tokenName; s.tokenSymbol = tokenSymbol; s.tokenMetadataResolver = tokenMetadataResolver; } /// @notice Gets the name of the token. /// @return tokenName The name of the token contract. function name(Layout storage s) internal view returns (string memory tokenName) { return s.tokenName; } /// @notice Gets the symbol of the token. /// @return tokenSymbol The symbol of the token contract. function symbol(Layout storage s) internal view returns (string memory tokenSymbol) { return s.tokenSymbol; } /// @notice Gets the address of the token metadata resolver. /// @return tokenMetadataResolver The address of the token metadata resolver. function metadataResolver(Layout storage s) internal view returns (ITokenMetadataResolver tokenMetadataResolver) { return s.tokenMetadataResolver; } /// @notice Gets the token metadata URI retieved from the metadata resolver contract. /// @param tokenContract The address of the token contract. /// @param tokenId The ID of the token. function tokenMetadataURI(Layout storage s, address tokenContract, uint256 tokenId) internal view returns (string memory) { return s.tokenMetadataResolver.tokenMetadataURI(tokenContract, tokenId); } function layout() internal pure returns (Layout storage s) { bytes32 position = LAYOUT_STORAGE_SLOT; assembly { s.slot := position } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {ERC2981Storage} from "./libraries/ERC2981Storage.sol"; import {ERC2981Base} from "./base/ERC2981Base.sol"; import {ContractOwnership} from "./../../access/ContractOwnership.sol"; /// @title ERC2981 NFT Royalty Standard (immutable version). /// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation. abstract contract ERC2981 is ERC2981Base, ContractOwnership { /// @notice Marks the following ERC165 interface(s) as supported: ERC2981. constructor() { ERC2981Storage.init(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {IERC2981} from "./../interfaces/IERC2981.sol"; import {ERC2981Storage} from "./../libraries/ERC2981Storage.sol"; import {ContractOwnershipStorage} from "./../../../access/libraries/ContractOwnershipStorage.sol"; import {Context} from "@openzeppelin/contracts/utils/Context.sol"; /// @title ERC2981 NFT Royalty Standard (proxiable version). /// @dev This contract is to be used via inheritance in a proxied implementation. /// @dev Note: This contract requires ERC165 (Interface Detection Standard). /// @dev Note: This contract requires ERC173 (Contract Ownership standard). abstract contract ERC2981Base is Context, IERC2981 { using ERC2981Storage for ERC2981Storage.Layout; using ContractOwnershipStorage for ContractOwnershipStorage.Layout; uint256 public constant ROYALTY_FEE_DENOMINATOR = ERC2981Storage.ROYALTY_FEE_DENOMINATOR; /// @notice Sets the royalty percentage. /// @dev Reverts with {NotContractOwner} if the sender is not the contract owner. /// @dev Reverts with {IncorrectRoyaltyPercentage} if `percentage` is above 100% (> FEE_DENOMINATOR). /// @param percentage The new percentage to set. For example 50000 sets 50% royalty. function setRoyaltyPercentage(uint256 percentage) external { ContractOwnershipStorage.layout().enforceIsContractOwner(_msgSender()); ERC2981Storage.layout().setRoyaltyPercentage(percentage); } /// @notice Sets the royalty receiver. /// @dev Reverts with {NotContractOwner} if the sender is not the contract owner. /// @dev Reverts with {IncorrectRoyaltyReceiver} if `receiver` is the zero address. /// @param receiver The new receiver to set. function setRoyaltyReceiver(address receiver) external { ContractOwnershipStorage.layout().enforceIsContractOwner(_msgSender()); ERC2981Storage.layout().setRoyaltyReceiver(receiver); } /// @inheritdoc IERC2981 function royaltyInfo(uint256 tokenId, uint256 salePrice) external view returns (address receiver, uint256 royaltyAmount) { return ERC2981Storage.layout().royaltyInfo(tokenId, salePrice); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {IOperatorFilterRegistry} from "./../interfaces/IOperatorFilterRegistry.sol"; import {OperatorFiltererStorage} from "./../libraries/OperatorFiltererStorage.sol"; import {ContractOwnershipStorage} from "./../../../access/libraries/ContractOwnershipStorage.sol"; import {Context} from "@openzeppelin/contracts/utils/Context.sol"; /// @title Operator Filterer for token contracts (proxiable version). /// @dev This contract is to be used via inheritance in a proxied implementation. /// @dev Note: This contract requires ERC173 (Contract Ownership standard). abstract contract OperatorFiltererBase is Context { using OperatorFiltererStorage for OperatorFiltererStorage.Layout; using ContractOwnershipStorage for ContractOwnershipStorage.Layout; /// @notice Updates the address that the contract will make OperatorFilter checks against. /// @dev Reverts with {NotContractOwner} if the sender is not the contract owner. /// @param registry The new operator filter registry address. When set to the zero address, checks will be bypassed. function updateOperatorFilterRegistry(IOperatorFilterRegistry registry) external { ContractOwnershipStorage.layout().enforceIsContractOwner(_msgSender()); OperatorFiltererStorage.layout().updateOperatorFilterRegistry(registry); } /// @notice Gets the operator filter registry address. function operatorFilterRegistry() external view returns (IOperatorFilterRegistry) { return OperatorFiltererStorage.layout().operatorFilterRegistry(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @notice Thrown when setting a royalty percentage that is above 100% (> FEE_DENOMINATOR). /// @param percentage The royalty percentage that was attempted to be set. error ERC2981IncorrectRoyaltyPercentage(uint256 percentage); /// @notice Thrown when setting a royalty receiver that is the zero address. error ERC2981IncorrectRoyaltyReceiver();
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @notice Thrown when transferring to or giving approval to a non-authorized operator. /// @param operator The address that is not authorized. error OperatorNotAllowed(address operator);
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @title ERC2981 NFT Royalty Standard. /// @dev See https://eips.ethereum.org/EIPS/eip-2981 /// @dev Note: The ERC-165 identifier for this interface is 0x2a55205a. interface IERC2981 { /// @notice Called with the sale price to determine how much royalty is owed and to whom. /// @param tokenId The NFT asset queried for royalty information /// @param salePrice The sale price of the NFT asset specified by `tokenId` /// @return receiver Address of who should be sent the royalty payment /// @return royaltyAmount The royalty payment amount for `salePrice` function royaltyInfo(uint256 tokenId, uint256 salePrice) external view returns (address receiver, uint256 royaltyAmount); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; interface IOperatorFilterRegistry { function isOperatorAllowed(address registrant, address operator) external view returns (bool); function register(address registrant) external; function registerAndSubscribe(address registrant, address subscription) external; function registerAndCopyEntries(address registrant, address registrantToCopy) external; function unregister(address addr) external; function updateOperator(address registrant, address operator, bool filtered) external; function updateOperators(address registrant, address[] calldata operators, bool filtered) external; function updateCodeHash(address registrant, bytes32 codehash, bool filtered) external; function updateCodeHashes(address registrant, bytes32[] calldata codeHashes, bool filtered) external; function subscribe(address registrant, address registrantToSubscribe) external; function unsubscribe(address registrant, bool copyExistingEntries) external; function subscriptionOf(address addr) external returns (address registrant); function subscribers(address registrant) external returns (address[] memory); function subscriberAt(address registrant, uint256 index) external returns (address); function copyEntriesOf(address registrant, address registrantToCopy) external; function isOperatorFiltered(address registrant, address operator) external returns (bool); function isCodeHashOfFiltered(address registrant, address operatorWithCode) external returns (bool); function isCodeHashFiltered(address registrant, bytes32 codeHash) external returns (bool); function filteredOperators(address addr) external returns (address[] memory); function filteredCodeHashes(address addr) external returns (bytes32[] memory); function filteredOperatorAt(address registrant, uint256 index) external returns (address); function filteredCodeHashAt(address registrant, uint256 index) external returns (bytes32); function isRegistered(address addr) external returns (bool); function codeHashOf(address addr) external returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {ERC2981IncorrectRoyaltyReceiver, ERC2981IncorrectRoyaltyPercentage} from "./../errors/ERC2981Errors.sol"; import {IERC2981} from "./../interfaces/IERC2981.sol"; import {InterfaceDetectionStorage} from "./../../../introspection/libraries/InterfaceDetectionStorage.sol"; library ERC2981Storage { using InterfaceDetectionStorage for InterfaceDetectionStorage.Layout; struct Layout { address royaltyReceiver; uint96 royaltyPercentage; } bytes32 internal constant LAYOUT_STORAGE_SLOT = bytes32(uint256(keccak256("animoca.token.royalty.ERC2981.storage")) - 1); uint256 internal constant ROYALTY_FEE_DENOMINATOR = 100000; /// @notice Marks the following ERC165 interface(s) as supported: ERC2981. function init() internal { InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC2981).interfaceId, true); } /// @notice Sets the royalty percentage. /// @dev Reverts with {ERC2981IncorrectRoyaltyPercentage} if `percentage` is above 100% (> FEE_DENOMINATOR). /// @param percentage The new percentage to set. For example 50000 sets 50% royalty. function setRoyaltyPercentage(Layout storage s, uint256 percentage) internal { if (percentage > ROYALTY_FEE_DENOMINATOR) { revert ERC2981IncorrectRoyaltyPercentage(percentage); } s.royaltyPercentage = uint96(percentage); } /// @notice Sets the royalty receiver. /// @dev Reverts with {ERC2981IncorrectRoyaltyReceiver} if `receiver` is the zero address. /// @param receiver The new receiver to set. function setRoyaltyReceiver(Layout storage s, address receiver) internal { if (receiver == address(0)) { revert ERC2981IncorrectRoyaltyReceiver(); } s.royaltyReceiver = receiver; } /// @notice Called with the sale price to determine how much royalty is owed and to whom. // / @param tokenId The NFT asset queried for royalty information /// @param salePrice The sale price of the NFT asset specified by `tokenId` /// @return receiver Address of who should be sent the royalty payment /// @return royaltyAmount The royalty payment amount for `salePrice` function royaltyInfo(Layout storage s, uint256, uint256 salePrice) internal view returns (address receiver, uint256 royaltyAmount) { receiver = s.royaltyReceiver; uint256 royaltyPercentage = s.royaltyPercentage; if (salePrice == 0 || royaltyPercentage == 0) { royaltyAmount = 0; } else { if (salePrice < ROYALTY_FEE_DENOMINATOR) { royaltyAmount = (salePrice * royaltyPercentage) / ROYALTY_FEE_DENOMINATOR; } else { royaltyAmount = (salePrice / ROYALTY_FEE_DENOMINATOR) * royaltyPercentage; } } } function layout() internal pure returns (Layout storage s) { bytes32 position = LAYOUT_STORAGE_SLOT; assembly { s.slot := position } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {OperatorNotAllowed} from "./../errors/OperatorFiltererErrors.sol"; import {IOperatorFilterRegistry} from "./../interfaces/IOperatorFilterRegistry.sol"; import {ProxyInitialization} from "./../../../proxy/libraries/ProxyInitialization.sol"; library OperatorFiltererStorage { using OperatorFiltererStorage for OperatorFiltererStorage.Layout; struct Layout { IOperatorFilterRegistry registry; } bytes32 internal constant PROXY_INIT_PHASE_SLOT = bytes32(uint256(keccak256("animoca.token.royalty.OperatorFilterer.phase")) - 1); bytes32 internal constant LAYOUT_STORAGE_SLOT = bytes32(uint256(keccak256("animoca.token.royalty.OperatorFilterer.storage")) - 1); /// @notice Sets the address that the contract will make OperatorFilter checks against. /// @dev Note: This function should be called ONLY in the constructor of an immutable (non-proxied) contract. /// @param registry The operator filter registry address. When set to the zero address, checks will be bypassed. function constructorInit(Layout storage s, IOperatorFilterRegistry registry) internal { s.registry = registry; } /// @notice Sets the address that the contract will make OperatorFilter checks against. /// @dev Note: This function should be called ONLY in the init function of a proxied contract. /// @dev Reverts with {InitializationPhaseAlreadyReached} if the proxy initialization phase is set to `1` or above. /// @param registry The operator filter registry address. When set to the zero address, checks will be bypassed. function proxyInit(Layout storage s, IOperatorFilterRegistry registry) internal { ProxyInitialization.setPhase(PROXY_INIT_PHASE_SLOT, 1); s.constructorInit(registry); } /// @notice Updates the address that the contract will make OperatorFilter checks against. /// @param registry The new operator filter registry address. When set to the zero address, checks will be bypassed. function updateOperatorFilterRegistry(Layout storage s, IOperatorFilterRegistry registry) internal { s.registry = registry; } /// @dev Reverts with {OperatorNotAllowed} if `sender` is not `from` and is not allowed by a valid operator registry. function requireAllowedOperatorForTransfer(Layout storage s, address sender, address from) internal view { // Allow spending tokens from addresses with balance // Note that this still allows listings and marketplaces with escrow to transfer tokens if transferred from an EOA. if (sender != from) { _checkFilterOperator(s, sender); } } /// @dev Reverts with {OperatorNotAllowed} if `sender` is not allowed by a valid operator registry. function requireAllowedOperatorForApproval(Layout storage s, address operator) internal view { _checkFilterOperator(s, operator); } function operatorFilterRegistry(Layout storage s) internal view returns (IOperatorFilterRegistry) { return s.registry; } function layout() internal pure returns (Layout storage s) { bytes32 position = LAYOUT_STORAGE_SLOT; assembly { s.slot := position } } function _checkFilterOperator(Layout storage s, address operator) private view { IOperatorFilterRegistry registry = s.registry; // Check registry code length to facilitate testing in environments without a deployed registry. if (address(registry) != address(0) && address(registry).code.length > 0) { if (!registry.isOperatorAllowed(address(this), operator)) { revert OperatorNotAllowed(operator); } } } }
{ "evmVersion": "paris", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 99999 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"string","name":"tokenName","type":"string"},{"internalType":"string","name":"tokenSymbol","type":"string"},{"internalType":"contract ITokenMetadataResolver","name":"metadataResolver","type":"address"},{"internalType":"contract IOperatorFilterRegistry","name":"filterRegistry","type":"address"},{"internalType":"contract IForwarderRegistry","name":"forwarderRegistry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"percentage","type":"uint256"}],"name":"ERC2981IncorrectRoyaltyPercentage","type":"error"},{"inputs":[],"name":"ERC2981IncorrectRoyaltyReceiver","type":"error"},{"inputs":[],"name":"ERC721BalanceOfAddressZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721ExistingToken","type":"error"},{"inputs":[],"name":"ERC721MintToAddressZero","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonApprovedForApproval","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonApprovedForTransfer","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonExistingToken","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonOwnedToken","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721SafeTransferRejected","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"ERC721SelfApproval","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"ERC721SelfApprovalForAll","type":"error"},{"inputs":[],"name":"ERC721TransferToAddressZero","type":"error"},{"inputs":[],"name":"IllegalInterfaceId","type":"error"},{"inputs":[],"name":"InconsistentArrayLengths","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NotContractOwner","type":"error"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"NotRoleHolder","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"OperatorNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROYALTY_FEE_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"batchMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"batchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"deliver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"forwarderRegistry","outputs":[{"internalType":"contract IForwarderRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"approved","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"hasRole_","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"approvedForAll","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataResolver","outputs":[{"internalType":"contract ITokenMetadataResolver","name":"tokenMetadataResolver","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"tokenName","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operatorFilterRegistry","outputs":[{"internalType":"contract IOperatorFilterRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"tokenOwner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"recoverERC20s","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"contract IERC721[]","name":"contracts","type":"address[]"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"recoverERC721s","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"recoverETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"percentage","type":"uint256"}],"name":"setRoyaltyPercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"setRoyaltyReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"tokenSymbol","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"uri","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IOperatorFilterRegistry","name":"registry","type":"address"}],"name":"updateOperatorFilterRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60a06040523480156200001157600080fd5b5060405162003f8d38038062003f8d833981016040819052620000349162000446565b8080868686863362000051816200004a620000f3565b9062000129565b506200005c620001a4565b62000089816200006b620001be565b9081546001600160a01b0319166001600160a01b0391909116179055565b5062000094620001ee565b620000ae838383620000a562000206565b92919062000236565b620000b86200027d565b50620000c691505062000295565b620000d0620002ad565b620000da620002c5565b6001600160a01b03166080525062000671945050505050565b6000806200012360017fc9ed16f33ab3a66c84bfd83099ccb2a8845871e2e1c1928f63797152f0fd54cd620004f2565b92915050565b6001600160a01b03811615620001805781546001600160a01b0319166001600160a01b03821690811783556040516000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a35b620001a06307f5828d60e41b600162000198620002d8565b919062000308565b5050565b620001bc6380ac58cd60e01b600162000198620002d8565b565b6000806200012360017f609b85bcafa81ecfaf3ff62cdde2c6c9082a68dbe4922f07399c706bdeb7cd31620004f2565b620001bc63f3993d1160e01b600162000198620002d8565b6000806200012360017f7ea68fd2dcf1c056b94db6a0a537aa80d26fa9ab1eacd85da1ba0b61b7e7a8a5620004f2565b83620002438482620005a5565b5060018401620002548382620005a5565b5060029390930180546001600160a01b0319166001600160a01b03909416939093179092555050565b620001bc635b5e139f60e01b600162000198620002d8565b620001bc638e773e1360e01b600162000198620002d8565b620001bc634ed2f41960e11b600162000198620002d8565b620001bc63152a902d60e11b6001620001985b6000806200012360017fca9d3e17f264b0f3984e2634e94adb37fa3e6a8103f06aeae6fa59e21c769f5e620004f2565b600160e01b6001600160e01b031983160162000337576040516372c683bb60e01b815260040160405180910390fd5b6001600160e01b03199190911660009081526020929092526040909120805460ff1916911515919091179055565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200038d57600080fd5b81516001600160401b0380821115620003aa57620003aa62000365565b604051601f8301601f19908116603f01168101908282118183101715620003d557620003d562000365565b8160405283815260209250866020858801011115620003f357600080fd5b600091505b83821015620004175785820183015181830184015290820190620003f8565b6000602085830101528094505050505092915050565b6001600160a01b03811681146200044357600080fd5b50565b600080600080600060a086880312156200045f57600080fd5b85516001600160401b03808211156200047757600080fd5b6200048589838a016200037b565b965060208801519150808211156200049c57600080fd5b50620004ab888289016200037b565b9450506040860151620004be816200042d565b6060870151909350620004d1816200042d565b6080870151909250620004e4816200042d565b809150509295509295909350565b818103818111156200012357634e487b7160e01b600052601160045260246000fd5b600181811c908216806200052957607f821691505b6020821081036200054a57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620005a0576000816000526020600020601f850160051c810160208610156200057b5750805b601f850160051c820191505b818110156200059c5782815560010162000587565b5050505b505050565b81516001600160401b03811115620005c157620005c162000365565b620005d981620005d2845462000514565b8462000550565b602080601f831160018114620006115760008415620005f85750858301515b600019600386901b1c1916600185901b1785556200059c565b600085815260208120601f198616915b82811015620006425788860151825594840194600190910190840162000621565b5085821015620006615787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6080516138eb620006a26000396000818161036d015281816103ed01528181612ba70152612c2f01526138eb6000f3fe608060405234801561001057600080fd5b50600436106102775760003560e01c80638bb9c5bf11610160578063b88d4fde116100d8578063e1a8bf2c1161008c578063f2fde38b11610071578063f2fde38b146105a6578063f3993d11146105b9578063f7ba94bd146105cc57600080fd5b8063e1a8bf2c14610589578063e985e9c51461059357600080fd5b8063c87b56dd116100bd578063c87b56dd1461053c578063d53913931461054f578063d547741f1461057657600080fd5b8063b88d4fde14610516578063c3666c361461052957600080fd5b806395d89b411161012f578063a0c76f6211610114578063a0c76f62146104f3578063a22cb465146104fb578063b0ccc31e1461050e57600080fd5b806395d89b41146104d85780639da5e832146104e057600080fd5b80638bb9c5bf146104975780638da5cb5b146104aa5780638dc251e3146104b257806391d14854146104c557600080fd5b806340c10f19116101f357806361ba27da116101c257806370a08231116101a757806370a082311461045057806373c8a958146104715780638832e6e31461048457600080fd5b806361ba27da1461042a5780636352211e1461043d57600080fd5b806340c10f19146103a457806342842e0e146103b75780634684d7e9146103ca578063572b6c05146103dd57600080fd5b8063114ba8ee1161024a5780632a55205a1161022f5780632a55205a1461032c5780632b4c9f161461036b5780632f2ff15d1461039157600080fd5b8063114ba8ee1461030657806323b872dd1461031957600080fd5b806301ffc9a71461027c57806306fdde03146102a4578063081812fc146102b9578063095ea7b3146102f1575b600080fd5b61028f61028a3660046130f4565b6105df565b60405190151581526020015b60405180910390f35b6102ac6105f9565b60405161029b919061317f565b6102cc6102c7366004613192565b610608565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161029b565b6103046102ff3660046131cd565b61061c565b005b6103046103143660046131f9565b61066b565b610304610327366004613216565b6106d6565b61033f61033a366004613257565b610714565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091520161029b565b7f00000000000000000000000000000000000000000000000000000000000000006102cc565b61030461039f366004613279565b610737565b6103046103b23660046131cd565b61076a565b6103046103c5366004613216565b6107b9565b6103046103d83660046132ee565b6107ea565b61028f6103eb3660046131f9565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff90811691161490565b610304610438366004613192565b61085e565b6102cc61044b366004613192565b61087b565b61046361045e3660046131f9565b61088f565b60405190815260200161029b565b61030461047f366004613343565b6108a3565b61030461049236600461341f565b610999565b6103046104a5366004613192565b610a1b565b6102cc610a36565b6103046104c03660046131f9565b610a5d565b61028f6104d3366004613279565b610a7a565b6102ac610ac5565b6103046104ee36600461347b565b610acf565b6102cc610b73565b6103046105093660046134e9565b610b9d565b6102cc610bcc565b610304610524366004613517565b610bd9565b610304610537366004613343565b610c16565b6102ac61054a366004613192565b610d8e565b6104637f6d696e746572000000000000000000000000000000000000000000000000000081565b610304610584366004613279565b610db1565b610463620186a081565b61028f6105a136600461358a565b610ddf565b6103046105b43660046131f9565b610e2d565b6103046105c73660046135b8565b610e48565b6103046105da36600461347b565b610e82565b60006105f3826105ed610f39565b90610f67565b92915050565b6060610603611041565b905090565b60006105f382610616611053565b90611081565b73ffffffffffffffffffffffffffffffffffffffff82161561064a5761064a8261064461113a565b90611168565b610667610655611172565b838361065f611053565b92919061117c565b5050565b610684610676611172565b61067e6113f7565b90611425565b6106d38161069061113a565b9081547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b50565b60006106e0611172565b90506106f681856106ef61113a565b91906114d2565b61070e81858585610705611053565b9392919061150f565b50505050565b60008061072b84846107246117ed565b919061181b565b915091505b9250929050565b6000610741611172565b905061074f8161067e6113f7565b61076583838361075d6118c5565b9291906118f3565b505050565b6107a57f6d696e7465720000000000000000000000000000000000000000000000000000610796611172565b61079e6118c5565b91906119c9565b61066782826107b2611053565b9190611a4f565b60006107c3611172565b90506107d281856106ef61113a565b61070e818585856107e1611053565b93929190611b69565b6108167f6d696e7465720000000000000000000000000000000000000000000000000000610796611172565b610765838383808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506108579250611053915050565b9190611baf565b610869610676611172565b6106d3816108756117ed565b90611d27565b60006105f382610889611053565b90611dad565b60006105f38261089d611053565b90611e16565b6108ae610676611172565b8483811415806108be5750808214155b156108f5576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8181101561098f5761098788888381811061091557610915613611565b905060200201602081019061092a91906131f9565b85858481811061093c5761093c613611565b9050602002013588888581811061095557610955613611565b905060200201602081019061096a91906131f9565b73ffffffffffffffffffffffffffffffffffffffff169190611e92565b6001016108f8565b5050505050505050565b6109c57f6d696e7465720000000000000000000000000000000000000000000000000000610796611172565b61070e6109d0611172565b858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610a129250611053915050565b93929190611f1f565b6106d3610a26611172565b82610a2f6118c5565b9190611f55565b6000610603610a436113f7565b5473ffffffffffffffffffffffffffffffffffffffff1690565b610a68610676611172565b6106d381610a746117ed565b90611ff9565b6000610abe8383610a896118c5565b60009283526020908152604080842073ffffffffffffffffffffffffffffffffffffffff909316845291905290205460ff1690565b9392505050565b6060610603612046565b610afb7f6d696e7465720000000000000000000000000000000000000000000000000000610796611172565b61070e84848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808802828101820190935287825290935087925086918291850190849080828437600092019190915250610b6c9250611053915050565b9190612058565b6000610603610b806120ee565b6002015473ffffffffffffffffffffffffffffffffffffffff1690565b8015610baf57610baf8261064461113a565b610667610bba611172565b8383610bc4611053565b92919061211c565b6000610603610a4361113a565b6000610be3611172565b9050610bf281876106ef61113a565b610c0e818787878787610c03611053565b959493929190612234565b505050505050565b610c21610676611172565b848381141580610c315750808214155b15610c68576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8181101561098f57858582818110610c8557610c85613611565b9050602002016020810190610c9a91906131f9565b73ffffffffffffffffffffffffffffffffffffffff166323b872dd308a8a85818110610cc857610cc8613611565b9050602002016020810190610cdd91906131f9565b878786818110610cef57610cef613611565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b16815273ffffffffffffffffffffffffffffffffffffffff958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b158015610d6b57600080fd5b505af1158015610d7f573d6000803e3d6000fd5b50505050806001019050610c6b565b6060610d9c82610889611053565b506105f33083610daa6120ee565b91906122aa565b6000610dbb611172565b9050610dc98161067e6113f7565b610765838383610dd76118c5565b92919061236a565b6000610abe8383610dee611053565b919073ffffffffffffffffffffffffffffffffffffffff9182166000908152600393909301602090815260408085209290931684525290205460ff1690565b6106d3610e38611172565b82610e416113f7565b9190612434565b6000610e52611172565b9050610e6181866106ef61113a565b610e7b8186868686610e71611053565b9493929190612548565b5050505050565b610e8d610676611172565b82818114610ec7576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610c0e57610f31848483818110610ee757610ee7613611565b90506020020135878784818110610f0057610f00613611565b9050602002016020810190610f1591906131f9565b73ffffffffffffffffffffffffffffffffffffffff169061284d565b600101610eca565b6000806105f360017fca9d3e17f264b0f3984e2634e94adb37fa3e6a8103f06aeae6fa59e21c769f5e61366f565b60007c01000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831601610fb7575060006105f3565b7ffe003659000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831601611008575060016105f3565b507fffffffff00000000000000000000000000000000000000000000000000000000166000908152602091909152604090205460ff1690565b606061060361104e6120ee565b6129a7565b6000806105f360017fddf3ee18ae6d688373c219468f8be446e7ae82215f4779d821c7ea5e8c13c0c161366f565b60008181526020839052604081205473ffffffffffffffffffffffffffffffffffffffff81166110e5576040517fdd560475000000000000000000000000000000000000000000000000000000008152600481018490526024015b60405180910390fd5b74010000000000000000000000000000000000000000811615611130575050600081815260028301602052604090205473ffffffffffffffffffffffffffffffffffffffff166105f3565b60009150506105f3565b6000806105f360017f609b85bcafa81ecfaf3ff62cdde2c6c9082a68dbe4922f07399c706bdeb7cd3161366f565b6106678282612a3d565b6000610603612b64565b60008181526020859052604090205473ffffffffffffffffffffffffffffffffffffffff81166111db576040517fdd560475000000000000000000000000000000000000000000000000000000008152600481018390526024016110dc565b8073ffffffffffffffffffffffffffffffffffffffff80821690851603611246576040517fb7fdc01000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016110dc565b611251868287612cab565b6112ae576040517fc7563a1800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808716600483015282166024820152604481018490526064016110dc565b73ffffffffffffffffffffffffffffffffffffffff8416611313577401000000000000000000000000000000000000000082161561130e57600083815260208790526040902073ffffffffffffffffffffffffffffffffffffffff821690555b611394565b7401000000000000000000000000000000000000000082178083146113445760008481526020889052604090208190555b506000838152600287016020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff86161790555b828473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050505050565b6000806105f360017fc9ed16f33ab3a66c84bfd83099ccb2a8845871e2e1c1928f63797152f0fd54cd61366f565b815473ffffffffffffffffffffffffffffffffffffffff828116911614610667576040517f2ef4875e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016110dc565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614610765576107658383612a3d565b73ffffffffffffffffffffffffffffffffffffffff821661155c576040517f86c8706700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526020869052604090205473ffffffffffffffffffffffffffffffffffffffff81166115bb576040517fdd560475000000000000000000000000000000000000000000000000000000008152600481018390526024016110dc565b73ffffffffffffffffffffffffffffffffffffffff84168173ffffffffffffffffffffffffffffffffffffffff161461163f576040517f14dbb53600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602481018390526044016110dc565b61164a868587612cab565b6116f957740100000000000000000000000000000000000000008116158061169b5750600082815260028701602052604090205473ffffffffffffffffffffffffffffffffffffffff868116911614155b156116f9576040517fa4a3018b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808716600483015285166024820152604481018390526064016110dc565b600082815260208790526040902073ffffffffffffffffffffffffffffffffffffffff8085169182905585161461178a5773ffffffffffffffffffffffffffffffffffffffff80851660009081526001808901602052604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190559286168252919020805490910190555b818373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050505050565b6000806105f360017f2c0cf10337caabbd02dcf226f05f5fd19a0919a41a8df8958c39b8000782685861366f565b825473ffffffffffffffffffffffffffffffffffffffff8116906000907401000000000000000000000000000000000000000090046bffffffffffffffffffffffff16831580611869575080155b1561187757600091506118bc565b620186a08410156118a157620186a06118908286613682565b61189a9190613699565b91506118bc565b806118af620186a086613699565b6118b99190613682565b91505b50935093915050565b6000806105f360017fc8827d3282af6f37b64c3e9e6f3ac9df286ab0bb0fccd6f8661bf19adb368b2361366f565b60008381526020858152604080832073ffffffffffffffffffffffffffffffffffffffff8616845290915290205460ff1661070e5760008381526020858152604080832073ffffffffffffffffffffffffffffffffffffffff8681168086529184529382902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055815187815292830152918316918101919091527f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d906060015b60405180910390a150505050565b60008281526020848152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610765576040517f7aa728820000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff821660248201526044016110dc565b73ffffffffffffffffffffffffffffffffffffffff8216611a9c576040517f7851b9cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526020849052604090205473ffffffffffffffffffffffffffffffffffffffff1615611afb576040517f753eceac000000000000000000000000000000000000000000000000000000008152600481018290526024016110dc565b60008181526020848152604080832073ffffffffffffffffffffffffffffffffffffffff86169081905580845260018088019093528184208054909301909255518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4505050565b611b76858585858561150f565b73ffffffffffffffffffffffffffffffffffffffff82163b15610e7b57610e7b8484848460405180602001604052806000815250612d20565b73ffffffffffffffffffffffffffffffffffffffff8216611bfc576040517f7851b9cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160005b81811015611cf2576000838281518110611c1d57611c1d613611565b60200260200101519050611c5b8660000160008381526020019081526020016000205473ffffffffffffffffffffffffffffffffffffffff16151590565b15611c95576040517f753eceac000000000000000000000000000000000000000000000000000000008152600481018290526024016110dc565b60008181526020879052604080822073ffffffffffffffffffffffffffffffffffffffff88169081905590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a450600101611c01565b5073ffffffffffffffffffffffffffffffffffffffff9092166000908152600190930160205250604090912080549091019055565b620186a0811115611d67576040517fac040408000000000000000000000000000000000000000000000000000000008152600481018290526024016110dc565b81546bffffffffffffffffffffffff909116740100000000000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff909116179055565b60008181526020839052604081205473ffffffffffffffffffffffffffffffffffffffff8116611e0c576040517fdd560475000000000000000000000000000000000000000000000000000000008152600481018490526024016110dc565b805b949350505050565b600073ffffffffffffffffffffffffffffffffffffffff8216611e65576040517faefbce4e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5073ffffffffffffffffffffffffffffffffffffffff166000908152600191909101602052604090205490565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610765908490612e35565b611f2a858484611a4f565b73ffffffffffffffffffffffffffffffffffffffff83163b15610e7b57610e7b846000858585612d20565b611f608382846119c9565b60008181526020848152604080832073ffffffffffffffffffffffffffffffffffffffff86168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905580518481529182018390528101919091527ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9060600160405180910390a1505050565b73ffffffffffffffffffffffffffffffffffffffff8116611490576040517f16de0c8000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60606106036120536120ee565b612f44565b815181518114612094576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610e7b576120e68482815181106120b4576120b4613611565b60200260200101518483815181106120ce576120ce613611565b602002602001015187611a4f9092919063ffffffff16565b600101612097565b6000806105f360017f7ea68fd2dcf1c056b94db6a0a537aa80d26fa9ab1eacd85da1ba0b61b7e7a8a561366f565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612199576040517fe4215c6a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024016110dc565b73ffffffffffffffffffffffffffffffffffffffff838116600081815260038701602090815260408083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a350505050565b612241878787878761150f565b73ffffffffffffffffffffffffffffffffffffffff84163b156122a1576122a18686868686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612d2092505050565b50505050505050565b60028301546040517ff724dad700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015260248201849052606092169063f724dad790604401600060405180830381865afa158015612324573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611e0e9190810190613703565b60008381526020858152604080832073ffffffffffffffffffffffffffffffffffffffff8616845290915290205460ff161561070e5760008381526020858152604080832073ffffffffffffffffffffffffffffffffffffffff8681168086529184529382902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055815187815292830152918316918101919091527ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b906060016119bb565b825473ffffffffffffffffffffffffffffffffffffffff90811690831681146124a1576040517f2ef4875e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024016110dc565b8173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461070e5783547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182178655604051908316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350505050565b73ffffffffffffffffffffffffffffffffffffffff8316612595576040517f86c8706700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006125a2878688612cab565b90508160005b818110156127c65760008585838181106125c4576125c4613611565b602090810292909201356000818152928d90526040909220549192505073ffffffffffffffffffffffffffffffffffffffff8116612631576040517fdd560475000000000000000000000000000000000000000000000000000000008152600481018390526024016110dc565b73ffffffffffffffffffffffffffffffffffffffff89168173ffffffffffffffffffffffffffffffffffffffff16146126b5576040517f14dbb53600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a166004820152602481018390526044016110dc565b846127655774010000000000000000000000000000000000000000811615806127075750600082815260028c01602052604090205473ffffffffffffffffffffffffffffffffffffffff8b8116911614155b15612765576040517fa4a3018b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808c1660048301528a166024820152604481018390526064016110dc565b600082815260208c9052604080822073ffffffffffffffffffffffffffffffffffffffff808c16918290559151859391928d16917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a450506001016125a8565b508473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161415801561280257508015155b1561098f5773ffffffffffffffffffffffffffffffffffffffff808716600090815260018a016020526040808220805485900390559187168152208054820190555050505050505050565b804710156128b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016110dc565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114612911576040519150601f19603f3d011682016040523d82523d6000602084013e612916565b606091505b5050905080610765576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016110dc565b60608160000180546129b8906137c3565b80601f01602080910402602001604051908101604052809291908181526020018280546129e4906137c3565b8015612a315780601f10612a0657610100808354040283529160200191612a31565b820191906000526020600020905b815481529060010190602001808311612a1457829003601f168201915b50505050509050919050565b815473ffffffffffffffffffffffffffffffffffffffff168015801590612a7b575060008173ffffffffffffffffffffffffffffffffffffffff163b115b15610765576040517fc617113400000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015282169063c617113490604401602060405180830381865afa158015612af2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b169190613816565b610765576040517fede71dcc00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526024016110dc565b600033321480612b745750601836105b15612b7e57503390565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec36013560601c7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16331480612c9a57506040517f8929a8ca00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301523360248301527f00000000000000000000000000000000000000000000000000000000000000001690638929a8ca90604401602060405180830381865afa158015612c76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c9a9190613816565b15612ca457919050565b3391505090565b60008173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161480611e0e57505073ffffffffffffffffffffffffffffffffffffffff9182166000908152600393909301602090815260408085209290931684525290205460ff1690565b6040517f150b7a02000000000000000000000000000000000000000000000000000000008082529073ffffffffffffffffffffffffffffffffffffffff85169063150b7a0290612d7a908990899088908890600401613833565b6020604051808303816000875af1158015612d99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dbd919061387c565b7fffffffff000000000000000000000000000000000000000000000000000000001614610e7b576040517fc215a7a100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602481018390526044016110dc565b6000612e97826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612f559092919063ffffffff16565b9050805160001480612eb8575080806020019051810190612eb89190613816565b610765576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016110dc565b60608160010180546129b8906137c3565b6060611e0e8484600085856000808673ffffffffffffffffffffffffffffffffffffffff168587604051612f899190613899565b60006040518083038185875af1925050503d8060008114612fc6576040519150601f19603f3d011682016040523d82523d6000602084013e612fcb565b606091505b5091509150612fdc87838387612fe7565b979650505050505050565b6060831561307d5782516000036130765773ffffffffffffffffffffffffffffffffffffffff85163b613076576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016110dc565b5081611e0e565b611e0e83838151156130925781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110dc919061317f565b7fffffffff00000000000000000000000000000000000000000000000000000000811681146106d357600080fd5b60006020828403121561310657600080fd5b8135610abe816130c6565b60005b8381101561312c578181015183820152602001613114565b50506000910152565b6000815180845261314d816020860160208601613111565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610abe6020830184613135565b6000602082840312156131a457600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff811681146106d357600080fd5b600080604083850312156131e057600080fd5b82356131eb816131ab565b946020939093013593505050565b60006020828403121561320b57600080fd5b8135610abe816131ab565b60008060006060848603121561322b57600080fd5b8335613236816131ab565b92506020840135613246816131ab565b929592945050506040919091013590565b6000806040838503121561326a57600080fd5b50508035926020909101359150565b6000806040838503121561328c57600080fd5b82359150602083013561329e816131ab565b809150509250929050565b60008083601f8401126132bb57600080fd5b50813567ffffffffffffffff8111156132d357600080fd5b6020830191508360208260051b850101111561073057600080fd5b60008060006040848603121561330357600080fd5b833561330e816131ab565b9250602084013567ffffffffffffffff81111561332a57600080fd5b613336868287016132a9565b9497909650939450505050565b6000806000806000806060878903121561335c57600080fd5b863567ffffffffffffffff8082111561337457600080fd5b6133808a838b016132a9565b9098509650602089013591508082111561339957600080fd5b6133a58a838b016132a9565b909650945060408901359150808211156133be57600080fd5b506133cb89828a016132a9565b979a9699509497509295939492505050565b60008083601f8401126133ef57600080fd5b50813567ffffffffffffffff81111561340757600080fd5b60208301915083602082850101111561073057600080fd5b6000806000806060858703121561343557600080fd5b8435613440816131ab565b935060208501359250604085013567ffffffffffffffff81111561346357600080fd5b61346f878288016133dd565b95989497509550505050565b6000806000806040858703121561349157600080fd5b843567ffffffffffffffff808211156134a957600080fd5b6134b5888389016132a9565b909650945060208701359150808211156134ce57600080fd5b5061346f878288016132a9565b80151581146106d357600080fd5b600080604083850312156134fc57600080fd5b8235613507816131ab565b9150602083013561329e816134db565b60008060008060006080868803121561352f57600080fd5b853561353a816131ab565b9450602086013561354a816131ab565b935060408601359250606086013567ffffffffffffffff81111561356d57600080fd5b613579888289016133dd565b969995985093965092949392505050565b6000806040838503121561359d57600080fd5b82356135a8816131ab565b9150602083013561329e816131ab565b600080600080606085870312156135ce57600080fd5b84356135d9816131ab565b935060208501356135e9816131ab565b9250604085013567ffffffffffffffff81111561360557600080fd5b61346f878288016132a9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156105f3576105f3613640565b80820281158282048414176105f3576105f3613640565b6000826136cf577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561371557600080fd5b815167ffffffffffffffff8082111561372d57600080fd5b818401915084601f83011261374157600080fd5b815181811115613753576137536136d4565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715613799576137996136d4565b816040528281528760208487010111156137b257600080fd5b612fdc836020830160208801613111565b600181811c908216806137d757607f821691505b602082108103613810577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60006020828403121561382857600080fd5b8151610abe816134db565b600073ffffffffffffffffffffffffffffffffffffffff8087168352808616602084015250836040830152608060608301526138726080830184613135565b9695505050505050565b60006020828403121561388e57600080fd5b8151610abe816130c6565b600082516138ab818460208701613111565b919091019291505056fea26469706673582212208f76727b2352cb155e35798ed65ac892a63b76f9ab032c13b7c182c0bed7b71864736f6c6343000816003300000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000224b212198b212e0be24c7d7ead0b8ca5f443e55000000000000000000000000000000000000aaeb6d7670e522a718067333cd4e0000000000000000000000003f547f87251710f70109ae0409d461b27070969300000000000000000000000000000000000000000000000000000000000000224f70656e2043616d707573205075626c6973686572204e465420536561736f6e2032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4f435f504e46545f533200000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102775760003560e01c80638bb9c5bf11610160578063b88d4fde116100d8578063e1a8bf2c1161008c578063f2fde38b11610071578063f2fde38b146105a6578063f3993d11146105b9578063f7ba94bd146105cc57600080fd5b8063e1a8bf2c14610589578063e985e9c51461059357600080fd5b8063c87b56dd116100bd578063c87b56dd1461053c578063d53913931461054f578063d547741f1461057657600080fd5b8063b88d4fde14610516578063c3666c361461052957600080fd5b806395d89b411161012f578063a0c76f6211610114578063a0c76f62146104f3578063a22cb465146104fb578063b0ccc31e1461050e57600080fd5b806395d89b41146104d85780639da5e832146104e057600080fd5b80638bb9c5bf146104975780638da5cb5b146104aa5780638dc251e3146104b257806391d14854146104c557600080fd5b806340c10f19116101f357806361ba27da116101c257806370a08231116101a757806370a082311461045057806373c8a958146104715780638832e6e31461048457600080fd5b806361ba27da1461042a5780636352211e1461043d57600080fd5b806340c10f19146103a457806342842e0e146103b75780634684d7e9146103ca578063572b6c05146103dd57600080fd5b8063114ba8ee1161024a5780632a55205a1161022f5780632a55205a1461032c5780632b4c9f161461036b5780632f2ff15d1461039157600080fd5b8063114ba8ee1461030657806323b872dd1461031957600080fd5b806301ffc9a71461027c57806306fdde03146102a4578063081812fc146102b9578063095ea7b3146102f1575b600080fd5b61028f61028a3660046130f4565b6105df565b60405190151581526020015b60405180910390f35b6102ac6105f9565b60405161029b919061317f565b6102cc6102c7366004613192565b610608565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161029b565b6103046102ff3660046131cd565b61061c565b005b6103046103143660046131f9565b61066b565b610304610327366004613216565b6106d6565b61033f61033a366004613257565b610714565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091520161029b565b7f0000000000000000000000003f547f87251710f70109ae0409d461b2707096936102cc565b61030461039f366004613279565b610737565b6103046103b23660046131cd565b61076a565b6103046103c5366004613216565b6107b9565b6103046103d83660046132ee565b6107ea565b61028f6103eb3660046131f9565b7f0000000000000000000000003f547f87251710f70109ae0409d461b27070969373ffffffffffffffffffffffffffffffffffffffff90811691161490565b610304610438366004613192565b61085e565b6102cc61044b366004613192565b61087b565b61046361045e3660046131f9565b61088f565b60405190815260200161029b565b61030461047f366004613343565b6108a3565b61030461049236600461341f565b610999565b6103046104a5366004613192565b610a1b565b6102cc610a36565b6103046104c03660046131f9565b610a5d565b61028f6104d3366004613279565b610a7a565b6102ac610ac5565b6103046104ee36600461347b565b610acf565b6102cc610b73565b6103046105093660046134e9565b610b9d565b6102cc610bcc565b610304610524366004613517565b610bd9565b610304610537366004613343565b610c16565b6102ac61054a366004613192565b610d8e565b6104637f6d696e746572000000000000000000000000000000000000000000000000000081565b610304610584366004613279565b610db1565b610463620186a081565b61028f6105a136600461358a565b610ddf565b6103046105b43660046131f9565b610e2d565b6103046105c73660046135b8565b610e48565b6103046105da36600461347b565b610e82565b60006105f3826105ed610f39565b90610f67565b92915050565b6060610603611041565b905090565b60006105f382610616611053565b90611081565b73ffffffffffffffffffffffffffffffffffffffff82161561064a5761064a8261064461113a565b90611168565b610667610655611172565b838361065f611053565b92919061117c565b5050565b610684610676611172565b61067e6113f7565b90611425565b6106d38161069061113a565b9081547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b50565b60006106e0611172565b90506106f681856106ef61113a565b91906114d2565b61070e81858585610705611053565b9392919061150f565b50505050565b60008061072b84846107246117ed565b919061181b565b915091505b9250929050565b6000610741611172565b905061074f8161067e6113f7565b61076583838361075d6118c5565b9291906118f3565b505050565b6107a57f6d696e7465720000000000000000000000000000000000000000000000000000610796611172565b61079e6118c5565b91906119c9565b61066782826107b2611053565b9190611a4f565b60006107c3611172565b90506107d281856106ef61113a565b61070e818585856107e1611053565b93929190611b69565b6108167f6d696e7465720000000000000000000000000000000000000000000000000000610796611172565b610765838383808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506108579250611053915050565b9190611baf565b610869610676611172565b6106d3816108756117ed565b90611d27565b60006105f382610889611053565b90611dad565b60006105f38261089d611053565b90611e16565b6108ae610676611172565b8483811415806108be5750808214155b156108f5576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8181101561098f5761098788888381811061091557610915613611565b905060200201602081019061092a91906131f9565b85858481811061093c5761093c613611565b9050602002013588888581811061095557610955613611565b905060200201602081019061096a91906131f9565b73ffffffffffffffffffffffffffffffffffffffff169190611e92565b6001016108f8565b5050505050505050565b6109c57f6d696e7465720000000000000000000000000000000000000000000000000000610796611172565b61070e6109d0611172565b858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610a129250611053915050565b93929190611f1f565b6106d3610a26611172565b82610a2f6118c5565b9190611f55565b6000610603610a436113f7565b5473ffffffffffffffffffffffffffffffffffffffff1690565b610a68610676611172565b6106d381610a746117ed565b90611ff9565b6000610abe8383610a896118c5565b60009283526020908152604080842073ffffffffffffffffffffffffffffffffffffffff909316845291905290205460ff1690565b9392505050565b6060610603612046565b610afb7f6d696e7465720000000000000000000000000000000000000000000000000000610796611172565b61070e84848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808802828101820190935287825290935087925086918291850190849080828437600092019190915250610b6c9250611053915050565b9190612058565b6000610603610b806120ee565b6002015473ffffffffffffffffffffffffffffffffffffffff1690565b8015610baf57610baf8261064461113a565b610667610bba611172565b8383610bc4611053565b92919061211c565b6000610603610a4361113a565b6000610be3611172565b9050610bf281876106ef61113a565b610c0e818787878787610c03611053565b959493929190612234565b505050505050565b610c21610676611172565b848381141580610c315750808214155b15610c68576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8181101561098f57858582818110610c8557610c85613611565b9050602002016020810190610c9a91906131f9565b73ffffffffffffffffffffffffffffffffffffffff166323b872dd308a8a85818110610cc857610cc8613611565b9050602002016020810190610cdd91906131f9565b878786818110610cef57610cef613611565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b16815273ffffffffffffffffffffffffffffffffffffffff958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b158015610d6b57600080fd5b505af1158015610d7f573d6000803e3d6000fd5b50505050806001019050610c6b565b6060610d9c82610889611053565b506105f33083610daa6120ee565b91906122aa565b6000610dbb611172565b9050610dc98161067e6113f7565b610765838383610dd76118c5565b92919061236a565b6000610abe8383610dee611053565b919073ffffffffffffffffffffffffffffffffffffffff9182166000908152600393909301602090815260408085209290931684525290205460ff1690565b6106d3610e38611172565b82610e416113f7565b9190612434565b6000610e52611172565b9050610e6181866106ef61113a565b610e7b8186868686610e71611053565b9493929190612548565b5050505050565b610e8d610676611172565b82818114610ec7576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610c0e57610f31848483818110610ee757610ee7613611565b90506020020135878784818110610f0057610f00613611565b9050602002016020810190610f1591906131f9565b73ffffffffffffffffffffffffffffffffffffffff169061284d565b600101610eca565b6000806105f360017fca9d3e17f264b0f3984e2634e94adb37fa3e6a8103f06aeae6fa59e21c769f5e61366f565b60007c01000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831601610fb7575060006105f3565b7ffe003659000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831601611008575060016105f3565b507fffffffff00000000000000000000000000000000000000000000000000000000166000908152602091909152604090205460ff1690565b606061060361104e6120ee565b6129a7565b6000806105f360017fddf3ee18ae6d688373c219468f8be446e7ae82215f4779d821c7ea5e8c13c0c161366f565b60008181526020839052604081205473ffffffffffffffffffffffffffffffffffffffff81166110e5576040517fdd560475000000000000000000000000000000000000000000000000000000008152600481018490526024015b60405180910390fd5b74010000000000000000000000000000000000000000811615611130575050600081815260028301602052604090205473ffffffffffffffffffffffffffffffffffffffff166105f3565b60009150506105f3565b6000806105f360017f609b85bcafa81ecfaf3ff62cdde2c6c9082a68dbe4922f07399c706bdeb7cd3161366f565b6106678282612a3d565b6000610603612b64565b60008181526020859052604090205473ffffffffffffffffffffffffffffffffffffffff81166111db576040517fdd560475000000000000000000000000000000000000000000000000000000008152600481018390526024016110dc565b8073ffffffffffffffffffffffffffffffffffffffff80821690851603611246576040517fb7fdc01000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016110dc565b611251868287612cab565b6112ae576040517fc7563a1800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808716600483015282166024820152604481018490526064016110dc565b73ffffffffffffffffffffffffffffffffffffffff8416611313577401000000000000000000000000000000000000000082161561130e57600083815260208790526040902073ffffffffffffffffffffffffffffffffffffffff821690555b611394565b7401000000000000000000000000000000000000000082178083146113445760008481526020889052604090208190555b506000838152600287016020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff86161790555b828473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050505050565b6000806105f360017fc9ed16f33ab3a66c84bfd83099ccb2a8845871e2e1c1928f63797152f0fd54cd61366f565b815473ffffffffffffffffffffffffffffffffffffffff828116911614610667576040517f2ef4875e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016110dc565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614610765576107658383612a3d565b73ffffffffffffffffffffffffffffffffffffffff821661155c576040517f86c8706700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526020869052604090205473ffffffffffffffffffffffffffffffffffffffff81166115bb576040517fdd560475000000000000000000000000000000000000000000000000000000008152600481018390526024016110dc565b73ffffffffffffffffffffffffffffffffffffffff84168173ffffffffffffffffffffffffffffffffffffffff161461163f576040517f14dbb53600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602481018390526044016110dc565b61164a868587612cab565b6116f957740100000000000000000000000000000000000000008116158061169b5750600082815260028701602052604090205473ffffffffffffffffffffffffffffffffffffffff868116911614155b156116f9576040517fa4a3018b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808716600483015285166024820152604481018390526064016110dc565b600082815260208790526040902073ffffffffffffffffffffffffffffffffffffffff8085169182905585161461178a5773ffffffffffffffffffffffffffffffffffffffff80851660009081526001808901602052604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190559286168252919020805490910190555b818373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050505050565b6000806105f360017f2c0cf10337caabbd02dcf226f05f5fd19a0919a41a8df8958c39b8000782685861366f565b825473ffffffffffffffffffffffffffffffffffffffff8116906000907401000000000000000000000000000000000000000090046bffffffffffffffffffffffff16831580611869575080155b1561187757600091506118bc565b620186a08410156118a157620186a06118908286613682565b61189a9190613699565b91506118bc565b806118af620186a086613699565b6118b99190613682565b91505b50935093915050565b6000806105f360017fc8827d3282af6f37b64c3e9e6f3ac9df286ab0bb0fccd6f8661bf19adb368b2361366f565b60008381526020858152604080832073ffffffffffffffffffffffffffffffffffffffff8616845290915290205460ff1661070e5760008381526020858152604080832073ffffffffffffffffffffffffffffffffffffffff8681168086529184529382902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055815187815292830152918316918101919091527f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d906060015b60405180910390a150505050565b60008281526020848152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610765576040517f7aa728820000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff821660248201526044016110dc565b73ffffffffffffffffffffffffffffffffffffffff8216611a9c576040517f7851b9cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526020849052604090205473ffffffffffffffffffffffffffffffffffffffff1615611afb576040517f753eceac000000000000000000000000000000000000000000000000000000008152600481018290526024016110dc565b60008181526020848152604080832073ffffffffffffffffffffffffffffffffffffffff86169081905580845260018088019093528184208054909301909255518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4505050565b611b76858585858561150f565b73ffffffffffffffffffffffffffffffffffffffff82163b15610e7b57610e7b8484848460405180602001604052806000815250612d20565b73ffffffffffffffffffffffffffffffffffffffff8216611bfc576040517f7851b9cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160005b81811015611cf2576000838281518110611c1d57611c1d613611565b60200260200101519050611c5b8660000160008381526020019081526020016000205473ffffffffffffffffffffffffffffffffffffffff16151590565b15611c95576040517f753eceac000000000000000000000000000000000000000000000000000000008152600481018290526024016110dc565b60008181526020879052604080822073ffffffffffffffffffffffffffffffffffffffff88169081905590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a450600101611c01565b5073ffffffffffffffffffffffffffffffffffffffff9092166000908152600190930160205250604090912080549091019055565b620186a0811115611d67576040517fac040408000000000000000000000000000000000000000000000000000000008152600481018290526024016110dc565b81546bffffffffffffffffffffffff909116740100000000000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff909116179055565b60008181526020839052604081205473ffffffffffffffffffffffffffffffffffffffff8116611e0c576040517fdd560475000000000000000000000000000000000000000000000000000000008152600481018490526024016110dc565b805b949350505050565b600073ffffffffffffffffffffffffffffffffffffffff8216611e65576040517faefbce4e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5073ffffffffffffffffffffffffffffffffffffffff166000908152600191909101602052604090205490565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610765908490612e35565b611f2a858484611a4f565b73ffffffffffffffffffffffffffffffffffffffff83163b15610e7b57610e7b846000858585612d20565b611f608382846119c9565b60008181526020848152604080832073ffffffffffffffffffffffffffffffffffffffff86168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905580518481529182018390528101919091527ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9060600160405180910390a1505050565b73ffffffffffffffffffffffffffffffffffffffff8116611490576040517f16de0c8000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60606106036120536120ee565b612f44565b815181518114612094576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610e7b576120e68482815181106120b4576120b4613611565b60200260200101518483815181106120ce576120ce613611565b602002602001015187611a4f9092919063ffffffff16565b600101612097565b6000806105f360017f7ea68fd2dcf1c056b94db6a0a537aa80d26fa9ab1eacd85da1ba0b61b7e7a8a561366f565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612199576040517fe4215c6a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024016110dc565b73ffffffffffffffffffffffffffffffffffffffff838116600081815260038701602090815260408083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a350505050565b612241878787878761150f565b73ffffffffffffffffffffffffffffffffffffffff84163b156122a1576122a18686868686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612d2092505050565b50505050505050565b60028301546040517ff724dad700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015260248201849052606092169063f724dad790604401600060405180830381865afa158015612324573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611e0e9190810190613703565b60008381526020858152604080832073ffffffffffffffffffffffffffffffffffffffff8616845290915290205460ff161561070e5760008381526020858152604080832073ffffffffffffffffffffffffffffffffffffffff8681168086529184529382902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055815187815292830152918316918101919091527ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b906060016119bb565b825473ffffffffffffffffffffffffffffffffffffffff90811690831681146124a1576040517f2ef4875e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024016110dc565b8173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461070e5783547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182178655604051908316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350505050565b73ffffffffffffffffffffffffffffffffffffffff8316612595576040517f86c8706700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006125a2878688612cab565b90508160005b818110156127c65760008585838181106125c4576125c4613611565b602090810292909201356000818152928d90526040909220549192505073ffffffffffffffffffffffffffffffffffffffff8116612631576040517fdd560475000000000000000000000000000000000000000000000000000000008152600481018390526024016110dc565b73ffffffffffffffffffffffffffffffffffffffff89168173ffffffffffffffffffffffffffffffffffffffff16146126b5576040517f14dbb53600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a166004820152602481018390526044016110dc565b846127655774010000000000000000000000000000000000000000811615806127075750600082815260028c01602052604090205473ffffffffffffffffffffffffffffffffffffffff8b8116911614155b15612765576040517fa4a3018b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808c1660048301528a166024820152604481018390526064016110dc565b600082815260208c9052604080822073ffffffffffffffffffffffffffffffffffffffff808c16918290559151859391928d16917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a450506001016125a8565b508473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161415801561280257508015155b1561098f5773ffffffffffffffffffffffffffffffffffffffff808716600090815260018a016020526040808220805485900390559187168152208054820190555050505050505050565b804710156128b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016110dc565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114612911576040519150601f19603f3d011682016040523d82523d6000602084013e612916565b606091505b5050905080610765576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016110dc565b60608160000180546129b8906137c3565b80601f01602080910402602001604051908101604052809291908181526020018280546129e4906137c3565b8015612a315780601f10612a0657610100808354040283529160200191612a31565b820191906000526020600020905b815481529060010190602001808311612a1457829003601f168201915b50505050509050919050565b815473ffffffffffffffffffffffffffffffffffffffff168015801590612a7b575060008173ffffffffffffffffffffffffffffffffffffffff163b115b15610765576040517fc617113400000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015282169063c617113490604401602060405180830381865afa158015612af2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b169190613816565b610765576040517fede71dcc00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526024016110dc565b600033321480612b745750601836105b15612b7e57503390565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec36013560601c7f0000000000000000000000003f547f87251710f70109ae0409d461b27070969373ffffffffffffffffffffffffffffffffffffffff16331480612c9a57506040517f8929a8ca00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301523360248301527f0000000000000000000000003f547f87251710f70109ae0409d461b2707096931690638929a8ca90604401602060405180830381865afa158015612c76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c9a9190613816565b15612ca457919050565b3391505090565b60008173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161480611e0e57505073ffffffffffffffffffffffffffffffffffffffff9182166000908152600393909301602090815260408085209290931684525290205460ff1690565b6040517f150b7a02000000000000000000000000000000000000000000000000000000008082529073ffffffffffffffffffffffffffffffffffffffff85169063150b7a0290612d7a908990899088908890600401613833565b6020604051808303816000875af1158015612d99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dbd919061387c565b7fffffffff000000000000000000000000000000000000000000000000000000001614610e7b576040517fc215a7a100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602481018390526044016110dc565b6000612e97826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612f559092919063ffffffff16565b9050805160001480612eb8575080806020019051810190612eb89190613816565b610765576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016110dc565b60608160010180546129b8906137c3565b6060611e0e8484600085856000808673ffffffffffffffffffffffffffffffffffffffff168587604051612f899190613899565b60006040518083038185875af1925050503d8060008114612fc6576040519150601f19603f3d011682016040523d82523d6000602084013e612fcb565b606091505b5091509150612fdc87838387612fe7565b979650505050505050565b6060831561307d5782516000036130765773ffffffffffffffffffffffffffffffffffffffff85163b613076576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016110dc565b5081611e0e565b611e0e83838151156130925781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110dc919061317f565b7fffffffff00000000000000000000000000000000000000000000000000000000811681146106d357600080fd5b60006020828403121561310657600080fd5b8135610abe816130c6565b60005b8381101561312c578181015183820152602001613114565b50506000910152565b6000815180845261314d816020860160208601613111565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610abe6020830184613135565b6000602082840312156131a457600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff811681146106d357600080fd5b600080604083850312156131e057600080fd5b82356131eb816131ab565b946020939093013593505050565b60006020828403121561320b57600080fd5b8135610abe816131ab565b60008060006060848603121561322b57600080fd5b8335613236816131ab565b92506020840135613246816131ab565b929592945050506040919091013590565b6000806040838503121561326a57600080fd5b50508035926020909101359150565b6000806040838503121561328c57600080fd5b82359150602083013561329e816131ab565b809150509250929050565b60008083601f8401126132bb57600080fd5b50813567ffffffffffffffff8111156132d357600080fd5b6020830191508360208260051b850101111561073057600080fd5b60008060006040848603121561330357600080fd5b833561330e816131ab565b9250602084013567ffffffffffffffff81111561332a57600080fd5b613336868287016132a9565b9497909650939450505050565b6000806000806000806060878903121561335c57600080fd5b863567ffffffffffffffff8082111561337457600080fd5b6133808a838b016132a9565b9098509650602089013591508082111561339957600080fd5b6133a58a838b016132a9565b909650945060408901359150808211156133be57600080fd5b506133cb89828a016132a9565b979a9699509497509295939492505050565b60008083601f8401126133ef57600080fd5b50813567ffffffffffffffff81111561340757600080fd5b60208301915083602082850101111561073057600080fd5b6000806000806060858703121561343557600080fd5b8435613440816131ab565b935060208501359250604085013567ffffffffffffffff81111561346357600080fd5b61346f878288016133dd565b95989497509550505050565b6000806000806040858703121561349157600080fd5b843567ffffffffffffffff808211156134a957600080fd5b6134b5888389016132a9565b909650945060208701359150808211156134ce57600080fd5b5061346f878288016132a9565b80151581146106d357600080fd5b600080604083850312156134fc57600080fd5b8235613507816131ab565b9150602083013561329e816134db565b60008060008060006080868803121561352f57600080fd5b853561353a816131ab565b9450602086013561354a816131ab565b935060408601359250606086013567ffffffffffffffff81111561356d57600080fd5b613579888289016133dd565b969995985093965092949392505050565b6000806040838503121561359d57600080fd5b82356135a8816131ab565b9150602083013561329e816131ab565b600080600080606085870312156135ce57600080fd5b84356135d9816131ab565b935060208501356135e9816131ab565b9250604085013567ffffffffffffffff81111561360557600080fd5b61346f878288016132a9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156105f3576105f3613640565b80820281158282048414176105f3576105f3613640565b6000826136cf577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561371557600080fd5b815167ffffffffffffffff8082111561372d57600080fd5b818401915084601f83011261374157600080fd5b815181811115613753576137536136d4565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715613799576137996136d4565b816040528281528760208487010111156137b257600080fd5b612fdc836020830160208801613111565b600181811c908216806137d757607f821691505b602082108103613810577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60006020828403121561382857600080fd5b8151610abe816134db565b600073ffffffffffffffffffffffffffffffffffffffff8087168352808616602084015250836040830152608060608301526138726080830184613135565b9695505050505050565b60006020828403121561388e57600080fd5b8151610abe816130c6565b600082516138ab818460208701613111565b919091019291505056fea26469706673582212208f76727b2352cb155e35798ed65ac892a63b76f9ab032c13b7c182c0bed7b71864736f6c63430008160033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000224b212198b212e0be24c7d7ead0b8ca5f443e55000000000000000000000000000000000000aaeb6d7670e522a718067333cd4e0000000000000000000000003f547f87251710f70109ae0409d461b27070969300000000000000000000000000000000000000000000000000000000000000224f70656e2043616d707573205075626c6973686572204e465420536561736f6e2032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4f435f504e46545f533200000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : tokenName (string): Open Campus Publisher NFT Season 2
Arg [1] : tokenSymbol (string): OC_PNFT_S2
Arg [2] : metadataResolver (address): 0x224b212198B212E0bE24c7D7EaD0B8cA5F443E55
Arg [3] : filterRegistry (address): 0x000000000000AAeB6D7670E522A718067333cd4E
Arg [4] : forwarderRegistry (address): 0x3f547F87251710F70109Ae0409d461b270709693
-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [2] : 000000000000000000000000224b212198b212e0be24c7d7ead0b8ca5f443e55
Arg [3] : 000000000000000000000000000000000000aaeb6d7670e522a718067333cd4e
Arg [4] : 0000000000000000000000003f547f87251710f70109ae0409d461b270709693
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000022
Arg [6] : 4f70656e2043616d707573205075626c6973686572204e465420536561736f6e
Arg [7] : 2032000000000000000000000000000000000000000000000000000000000000
Arg [8] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [9] : 4f435f504e46545f533200000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
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.