Overview
APE Balance
APE Value
$0.00Multichain Info
Latest 25 from a total of 1,098 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Freeze Accounts ... | 32788262 | 34 hrs ago | IN | 0 APE | 0.01036747 | ||||
| Unfreeze Account... | 32788240 | 34 hrs ago | IN | 0 APE | 0.00499211 | ||||
| Freeze Accounts ... | 32786696 | 35 hrs ago | IN | 0 APE | 0.01036747 | ||||
| Unfreeze Account... | 32786535 | 35 hrs ago | IN | 0 APE | 0.00499201 | ||||
| Freeze Accounts ... | 32734986 | 2 days ago | IN | 0 APE | 0.01036625 | ||||
| Freeze Accounts ... | 32734958 | 2 days ago | IN | 0 APE | 0.01036747 | ||||
| Freeze Accounts ... | 32701772 | 3 days ago | IN | 0 APE | 0.01036747 | ||||
| Unfreeze Account... | 32701758 | 3 days ago | IN | 0 APE | 0.00499211 | ||||
| Set Transfer Sec... | 32119126 | 18 days ago | IN | 0 APE | 0.00412567 | ||||
| Apply List To Co... | 32119125 | 18 days ago | IN | 0 APE | 0.00569342 | ||||
| Set Transfer Sec... | 31107703 | 39 days ago | IN | 0 APE | 0.00412567 | ||||
| Apply List To Co... | 31107702 | 39 days ago | IN | 0 APE | 0.00569342 | ||||
| Set Transfer Sec... | 29565594 | 55 days ago | IN | 0 APE | 0.00103195 | ||||
| Apply List To Co... | 29565592 | 55 days ago | IN | 0 APE | 0.00142373 | ||||
| Set Transfer Sec... | 28559684 | 66 days ago | IN | 0 APE | 0.00103192 | ||||
| Apply List To Co... | 28559683 | 66 days ago | IN | 0 APE | 0.00142373 | ||||
| Set Transfer Sec... | 28290366 | 68 days ago | IN | 0 APE | 0.00096077 | ||||
| Apply List To Co... | 28290365 | 68 days ago | IN | 0 APE | 0.00091786 | ||||
| Set Transfer Sec... | 28174433 | 69 days ago | IN | 0 APE | 0.00103195 | ||||
| Apply List To Co... | 28174431 | 69 days ago | IN | 0 APE | 0.00142373 | ||||
| Apply List To Co... | 26370028 | 80 days ago | IN | 0 APE | 0.00094023 | ||||
| Set Transfer Sec... | 26370012 | 80 days ago | IN | 0 APE | 0.00141783 | ||||
| Set Token Type O... | 26369996 | 80 days ago | IN | 0 APE | 0.00075962 | ||||
| Apply List To Co... | 26366827 | 80 days ago | IN | 0 APE | 0.00094023 | ||||
| Set Transfer Sec... | 26366784 | 80 days ago | IN | 0 APE | 0.00141783 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | ||||
|---|---|---|---|---|---|---|---|
| 32844060 | 15 mins ago | 0 APE | |||||
| 32844060 | 15 mins ago | 0 APE | |||||
| 32844060 | 15 mins ago | 0 APE | |||||
| 32844018 | 17 mins ago | 0 APE | |||||
| 32844018 | 17 mins ago | 0 APE | |||||
| 32844018 | 17 mins ago | 0 APE | |||||
| 32843875 | 20 mins ago | 0 APE | |||||
| 32843875 | 20 mins ago | 0 APE | |||||
| 32843875 | 20 mins ago | 0 APE | |||||
| 32843757 | 24 mins ago | 0 APE | |||||
| 32843757 | 24 mins ago | 0 APE | |||||
| 32843757 | 24 mins ago | 0 APE | |||||
| 32843661 | 26 mins ago | 0 APE | |||||
| 32843661 | 26 mins ago | 0 APE | |||||
| 32843661 | 26 mins ago | 0 APE | |||||
| 32843374 | 34 mins ago | 0 APE | |||||
| 32843374 | 34 mins ago | 0 APE | |||||
| 32843374 | 34 mins ago | 0 APE | |||||
| 32843266 | 37 mins ago | 0 APE | |||||
| 32843266 | 37 mins ago | 0 APE | |||||
| 32843266 | 37 mins ago | 0 APE | |||||
| 32843266 | 37 mins ago | 0 APE | |||||
| 32843266 | 37 mins ago | 0 APE | |||||
| 32843266 | 37 mins ago | 0 APE | |||||
| 32843266 | 37 mins ago | 0 APE |
Cross-Chain Transactions
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "../Constants.sol";
import "../interfaces/IEOARegistry.sol";
import "../interfaces/ITransferValidator.sol";
import "./TransferPolicy.sol";
import {CreatorTokenTransferValidatorConfiguration} from "./CreatorTokenTransferValidatorConfiguration.sol";
import "@limitbreak/permit-c/PermitC.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "@opensea/tstorish/Tstorish.sol";
/**
* @title CreatorTokenTransferValidator
* @author Limit Break, Inc.
* @notice The CreatorTokenTransferValidator contract is designed to provide a customizable and secure transfer
* validation mechanism for NFT collections. This contract allows the owner of an NFT collection to configure
* the transfer security level, blacklisted accounts and codehashes, whitelisted accounts and codehashes, and
* authorized accounts and codehashes for each collection.
*
* @dev <h4>Features</h4>
* - Transfer security levels: Provides different levels of transfer security,
* from open transfers to completely restricted transfers.
* - Blacklist: Allows the owner of a collection to blacklist specific operator addresses or codehashes
* from executing transfers on behalf of others.
* - Whitelist: Allows the owner of a collection to whitelist specific operator addresses or codehashes
* permitted to execute transfers on behalf of others or send/receive tokens when otherwise disabled by
* security policy.
* - Authorizers: Allows the owner of a collection to enable authorizer contracts, that can perform
* authorization-based filtering of transfers.
*
* @dev <h4>Benefits</h4>
* - Enhanced security: Allows creators to have more control over their NFT collections, ensuring the safety
* and integrity of their assets.
* - Flexibility: Provides collection owners the ability to customize transfer rules as per their requirements.
* - Compliance: Facilitates compliance with regulations by enabling creators to restrict transfers based on
* specific criteria.
*
* @dev <h4>Intended Usage</h4>
* - The CreatorTokenTransferValidatorV3 contract is intended to be used by NFT collection owners to manage and
* enforce transfer policies. This contract is integrated with the following varations of creator token
* NFT contracts to validate transfers according to the defined security policies.
*
* - ERC721-C: Creator token implenting OpenZeppelin's ERC-721 standard.
* - ERC721-AC: Creator token implenting Azuki's ERC-721A standard.
* - ERC721-CW: Creator token implementing OpenZeppelin's ERC-721 standard with opt-in staking to
* wrap/upgrade a pre-existing ERC-721 collection.
* - ERC721-ACW: Creator token implementing Azuki's ERC721-A standard with opt-in staking to
* wrap/upgrade a pre-existing ERC-721 collection.
* - ERC1155-C: Creator token implenting OpenZeppelin's ERC-1155 standard.
* - ERC1155-CW: Creator token implementing OpenZeppelin's ERC-1155 standard with opt-in staking to
* wrap/upgrade a pre-existing ERC-1155 collection.
*
* <h4>Transfer Security Levels</h4>
* - Recommended: Recommended defaults are same as Level 3 (Whitelisting with OTC Enabled).
* - Caller Constraints: OperatorWhitelistEnableOTC
* - Receiver Constraints: None
* - Level 1: No transfer restrictions.
* - Caller Constraints: None
* - Receiver Constraints: None
* - Level 2: Only non-blacklisted operators can initiate transfers, over-the-counter (OTC) trading enabled.
* - Caller Constraints: OperatorBlacklistEnableOTC
* - Receiver Constraints: None
* - Level 3: Only whitelisted accounts can initiate transfers, over-the-counter (OTC) trading enabled.
* - Caller Constraints: OperatorWhitelistEnableOTC
* - Receiver Constraints: None
* - Level 4: Only whitelisted accounts can initiate transfers, over-the-counter (OTC) trading disabled.
* - Caller Constraints: OperatorWhitelistDisableOTC
* - Receiver Constraints: None
* - Level 5: Only whitelisted accounts can initiate transfers, over-the-counter (OTC) trading enabled.
* Transfers to contracts with code are not allowed, unless present on the whitelist.
* - Caller Constraints: OperatorWhitelistEnableOTC
* - Receiver Constraints: NoCode
* - Level 6: Only whitelisted accounts can initiate transfers, over-the-counter (OTC) trading enabled.
* Transfers are allowed only to Externally Owned Accounts (EOAs), unless present on the whitelist.
* - Caller Constraints: OperatorWhitelistEnableOTC
* - Receiver Constraints: EOA
* - Level 7: Only whitelisted accounts can initiate transfers, over-the-counter (OTC) trading disabled.
* Transfers to contracts with code are not allowed, unless present on the whitelist.
* - Caller Constraints: OperatorWhitelistDisableOTC
* - Receiver Constraints: NoCode
* - Level 8: Only whitelisted accounts can initiate transfers, over-the-counter (OTC) trading disabled.
* Transfers are allowed only to Externally Owned Accounts (EOAs), unless present on the whitelist.
* - Caller Constraints: OperatorWhitelistDisableOTC
* - Receiver Constraints: EOA
*/
contract CreatorTokenTransferValidator is IEOARegistry, ITransferValidator, ERC165, Tstorish, PermitC {
using EnumerableSet for EnumerableSet.AddressSet;
using EnumerableSet for EnumerableSet.Bytes32Set;
/*************************************************************************/
/* CUSTOM ERRORS */
/*************************************************************************/
/// @dev Thrown when attempting to set a list id that does not exist.
error CreatorTokenTransferValidator__ListDoesNotExist();
/// @dev Thrown when attempting to transfer the ownership of a list to the zero address.
error CreatorTokenTransferValidator__ListOwnershipCannotBeTransferredToZeroAddress();
/// @dev Thrown when attempting to call a function that requires the caller to be the list owner.
error CreatorTokenTransferValidator__CallerDoesNotOwnList();
/// @dev Thrown when validating a transfer for a collection using whitelists and the operator is not on the whitelist.
error CreatorTokenTransferValidator__CallerMustBeWhitelisted();
/// @dev Thrown when authorizing a transfer for a collection using authorizers and the msg.sender is not in the authorizer list.
error CreatorTokenTransferValidator__CallerMustBeAnAuthorizer();
/// @dev Thrown when attempting to call a function that requires owner or default admin role for a collection that the caller does not have.
error CreatorTokenTransferValidator__CallerMustHaveElevatedPermissionsForSpecifiedNFT();
/// @dev Thrown when constructor args are not valid
error CreatorTokenTransferValidator__InvalidConstructorArgs();
/// @dev Thrown when setting the transfer security level to an invalid value.
error CreatorTokenTransferValidator__InvalidTransferSecurityLevel();
/// @dev Thrown when validating a transfer for a collection using blacklists and the operator is on the blacklist.
error CreatorTokenTransferValidator__OperatorIsBlacklisted();
/// @dev Thrown when validating a transfer for a collection that does not allow receiver to have code and the receiver has code.
error CreatorTokenTransferValidator__ReceiverMustNotHaveDeployedCode();
/// @dev Thrown when validating a transfer for a collection that requires receivers be verified EOAs and the receiver is not verified.
error CreatorTokenTransferValidator__ReceiverProofOfEOASignatureUnverified();
/// @dev Thrown when a frozen account is the receiver of a transfer
error CreatorTokenTransferValidator__ReceiverAccountIsFrozen();
/// @dev Thrown when a frozen account is the sender of a transfer
error CreatorTokenTransferValidator__SenderAccountIsFrozen();
/// @dev Thrown when validating a transfer for a collection that is in soulbound token mode.
error CreatorTokenTransferValidator__TokenIsSoulbound();
/// @dev Thrown when an authorizer attempts to set a wildcard authorized operator on collections that don't allow wildcards
error CreatorTokenTransferValidator__WildcardOperatorsCannotBeAuthorizedForCollection();
/// @dev Thrown when attempting to set a authorized operator when authorization mode is disabled.
error CreatorTokenTransferValidator__AuthorizationDisabledForCollection();
/// @dev Thrown when attempting to validate a permitted transfer where the permit type does not match the collection-defined token type.
error CreatorTokenTransferValidator__TokenTypesDoNotMatch();
/*************************************************************************/
/* EVENTS */
/*************************************************************************/
/// @dev Emitted when a new list is created.
event CreatedList(uint256 indexed id, string name);
/// @dev Emitted when a list is applied to a collection.
event AppliedListToCollection(address indexed collection, uint120 indexed id);
/// @dev Emitted when the ownership of a list is transferred to a new owner.
event ReassignedListOwnership(uint256 indexed id, address indexed newOwner);
/// @dev Emitted when an account is added to the list of frozen accounts for a collection.
event AccountFrozenForCollection(address indexed collection, address indexed account);
/// @dev Emitted when an account is removed from the list of frozen accounts for a collection.
event AccountUnfrozenForCollection(address indexed collection, address indexed account);
/// @dev Emitted when an address is added to a list.
event AddedAccountToList(uint8 indexed kind, uint256 indexed id, address indexed account);
/// @dev Emitted when a codehash is added to a list.
event AddedCodeHashToList(uint8 indexed kind, uint256 indexed id, bytes32 indexed codehash);
/// @dev Emitted when an address is removed from a list.
event RemovedAccountFromList(uint8 indexed kind, uint256 indexed id, address indexed account);
/// @dev Emitted when a codehash is removed from a list.
event RemovedCodeHashFromList(uint8 indexed kind, uint256 indexed id, bytes32 indexed codehash);
/// @dev Emitted when the security level for a collection is updated.
event SetTransferSecurityLevel(address indexed collection, uint8 level);
/// @dev Emitted when a collection updates its authorization mode.
event SetAuthorizationModeEnabled(address indexed collection, bool disabled, bool authorizersCannotSetWildcardOperators);
/// @dev Emitted when a collection turns account freezing on or off.
event SetAccountFreezingModeEnabled(address indexed collection, bool enabled);
/// @dev Emitted when a collection's token type is updated.
event SetTokenType(address indexed collection, uint16 tokenType);
/*************************************************************************/
/* STRUCTS */
/*************************************************************************/
/**
* @dev This struct is internally for the storage of account and codehash lists.
*/
struct List {
EnumerableSet.AddressSet enumerableAccounts;
EnumerableSet.Bytes32Set enumerableCodehashes;
mapping (address => bool) nonEnumerableAccounts;
mapping (bytes32 => bool) nonEnumerableCodehashes;
}
/**
* @dev This struct is internally for the storage of account lists.
*/
struct AccountList {
EnumerableSet.AddressSet enumerableAccounts;
mapping (address => bool) nonEnumerableAccounts;
}
/*************************************************************************/
/* CONSTANTS */
/*************************************************************************/
/// @dev Immutable lookup table for constant gas determination of caller constraints by security level.
/// @dev Created during contract construction using defined constants.
uint256 private immutable _callerConstraintsLookup;
/// @dev Immutable lookup table for constant gas determination of receiver constraints by security level.
/// @dev Created during contract construction using defined constants.
uint256 private immutable _receiverConstraintsLookup;
/// @dev The address of the EOA Registry to use to validate an account is a verified EOA.
address private immutable _eoaRegistry;
/// @dev The legacy Creator Token Transfer Validator Interface
bytes4 private constant LEGACY_TRANSFER_VALIDATOR_INTERFACE_ID = 0x00000000;
/// @dev The default admin role value for contracts that implement access control.
bytes32 private constant DEFAULT_ACCESS_CONTROL_ADMIN_ROLE = 0x00;
/// @dev Value representing a zero value code hash.
bytes32 private constant BYTES32_ZERO = 0x0000000000000000000000000000000000000000000000000000000000000000;
address private constant WILDCARD_OPERATOR_ADDRESS = address(0x01);
uint16 private constant DEFAULT_TOKEN_TYPE = 0;
/*************************************************************************/
/* STORAGE */
/*************************************************************************/
/// @notice Keeps track of the most recently created list id.
uint120 public lastListId;
/// @notice Mapping of list ids to list owners
mapping (uint120 => address) public listOwners;
/// @dev Mapping of collection addresses to their security policy settings
mapping (address => CollectionSecurityPolicyV3) internal collectionSecurityPolicies;
/// @dev Mapping of list ids to blacklist settings
mapping (uint120 => List) internal blacklists;
/// @dev Mapping of list ids to whitelist settings
mapping (uint120 => List) internal whitelists;
/// @dev Mapping of list ids to authorizers
mapping (uint120 => List) internal authorizers;
/// @dev Mapping of collections to accounts that are frozen for those collections
mapping (address => AccountList) internal frozenAccounts;
constructor(
address defaultOwner,
address eoaRegistry_,
string memory name,
string memory version,
address validatorConfiguration
)
Tstorish()
PermitC(
name,
version,
defaultOwner,
CreatorTokenTransferValidatorConfiguration(validatorConfiguration).getNativeValueToCheckPauseState()
) {
if (defaultOwner == address(0) || eoaRegistry_ == address(0)) {
revert CreatorTokenTransferValidator__InvalidConstructorArgs();
}
_createDefaultList(defaultOwner);
_eoaRegistry = eoaRegistry_;
_callerConstraintsLookup = _constructCallerConstraintsTable();
_receiverConstraintsLookup = _constructReceiverConstraintsTable();
}
/**
* @dev This function is only called during contract construction to create the default list.
*/
function _createDefaultList(address defaultOwner) internal {
uint120 id = 0;
listOwners[id] = defaultOwner;
emit CreatedList(id, "DEFAULT LIST");
emit ReassignedListOwnership(id, defaultOwner);
}
/**
* @dev This function is only called during contract construction to create the caller constraints
* @dev lookup table.
*/
function _constructCallerConstraintsTable() internal pure returns (uint256) {
return
(CALLER_CONSTRAINTS_OPERATOR_WHITELIST_ENABLE_OTC << (TRANSFER_SECURITY_LEVEL_RECOMMENDED << 3))
| (CALLER_CONSTRAINTS_NONE << (TRANSFER_SECURITY_LEVEL_ONE << 3))
| (CALLER_CONSTRAINTS_OPERATOR_BLACKLIST_ENABLE_OTC << (TRANSFER_SECURITY_LEVEL_TWO << 3))
| (CALLER_CONSTRAINTS_OPERATOR_WHITELIST_ENABLE_OTC << (TRANSFER_SECURITY_LEVEL_THREE << 3))
| (CALLER_CONSTRAINTS_OPERATOR_WHITELIST_DISABLE_OTC << (TRANSFER_SECURITY_LEVEL_FOUR << 3))
| (CALLER_CONSTRAINTS_OPERATOR_WHITELIST_ENABLE_OTC << (TRANSFER_SECURITY_LEVEL_FIVE << 3))
| (CALLER_CONSTRAINTS_OPERATOR_WHITELIST_ENABLE_OTC << (TRANSFER_SECURITY_LEVEL_SIX << 3))
| (CALLER_CONSTRAINTS_OPERATOR_WHITELIST_DISABLE_OTC << (TRANSFER_SECURITY_LEVEL_SEVEN << 3))
| (CALLER_CONSTRAINTS_OPERATOR_WHITELIST_DISABLE_OTC << (TRANSFER_SECURITY_LEVEL_EIGHT << 3))
| (CALLER_CONSTRAINTS_SBT << (TRANSFER_SECURITY_LEVEL_NINE << 3));
}
/**
* @dev This function is only called during contract construction to create the receiver constraints
* @dev lookup table.
*/
function _constructReceiverConstraintsTable() internal pure returns (uint256) {
return
(RECEIVER_CONSTRAINTS_NONE << (TRANSFER_SECURITY_LEVEL_RECOMMENDED << 3))
| (RECEIVER_CONSTRAINTS_NONE << (TRANSFER_SECURITY_LEVEL_ONE << 3))
| (RECEIVER_CONSTRAINTS_NONE << (TRANSFER_SECURITY_LEVEL_TWO << 3))
| (RECEIVER_CONSTRAINTS_NONE << (TRANSFER_SECURITY_LEVEL_THREE << 3))
| (RECEIVER_CONSTRAINTS_NONE << (TRANSFER_SECURITY_LEVEL_FOUR << 3))
| (RECEIVER_CONSTRAINTS_NO_CODE << (TRANSFER_SECURITY_LEVEL_FIVE << 3))
| (RECEIVER_CONSTRAINTS_EOA << (TRANSFER_SECURITY_LEVEL_SIX << 3))
| (RECEIVER_CONSTRAINTS_NO_CODE << (TRANSFER_SECURITY_LEVEL_SEVEN << 3))
| (RECEIVER_CONSTRAINTS_EOA << (TRANSFER_SECURITY_LEVEL_EIGHT << 3))
| (RECEIVER_CONSTRAINTS_SBT << (TRANSFER_SECURITY_LEVEL_NINE << 3));
}
/*************************************************************************/
/* MODIFIERS */
/*************************************************************************/
/**
* @dev This modifier restricts a function call to the owner of the list `id`.
* @dev Throws when the caller is not the list owner.
*/
modifier onlyListOwner(uint120 id) {
_requireCallerOwnsList(id);
_;
}
/*************************************************************************/
/* APPLY TRANSFER POLICIES */
/*************************************************************************/
/**
* @notice Apply the collection transfer policy to a transfer operation of a creator token.
*
* @dev If the caller is self (Permit-C Processor) it means we have already applied operator validation in the
* _beforeTransferFrom callback. In this case, the security policy was already applied and the operator
* that used the Permit-C processor passed the security policy check and transfer can be safely allowed.
*
* @dev The order of checking whitelisted accounts, authorized operator check and whitelisted codehashes
* is very deliberate. The order of operations is determined by the most frequently used settings that are
* expected in the wild.
*
* @dev Throws when the collection has enabled account freezing mode and either the `from` or `to` addresses
* are on the list of frozen accounts for the collection.
* @dev Throws when the collection is set to Level 9 - Soulbound Token.
* @dev Throws when the receiver has deployed code and isn't whitelisted, if ReceiverConstraints.NoCode is set
* and the transfer is not approved by an authorizer for the collection.
* @dev Throws when the receiver has never verified a signature to prove they are an EOA and the receiver
* isn't whitelisted, if the ReceiverConstraints.EOA is set and the transfer is not approved by an
* authorizer for the collection..
* @dev Throws when `msg.sender` is blacklisted, if CallerConstraints.OperatorBlacklistEnableOTC is set, unless
* `msg.sender` is also the `from` address or the transfer is approved by an authorizer for the collection.
* @dev Throws when `msg.sender` isn't whitelisted, if CallerConstraints.OperatorWhitelistEnableOTC is set, unless
* `msg.sender` is also the `from` address or the transfer is approved by an authorizer for the collection.
* @dev Throws when neither `msg.sender` nor `from` are whitelisted, if
* CallerConstraints.OperatorWhitelistDisableOTC is set and the transfer
* is not approved by an authorizer for the collection.
*
* @dev <h4>Postconditions:</h4>
* 1. Transfer is allowed or denied based on the applied transfer policy.
*
* @param caller The address initiating the transfer.
* @param from The address of the token owner.
* @param to The address of the token receiver.
*/
function validateTransfer(address caller, address from, address to) public view {
(bytes4 errorSelector,) = _validateTransfer(_callerAuthorizedCheckCollection, msg.sender, caller, from, to, 0);
if (errorSelector != SELECTOR_NO_ERROR) {
_revertCustomErrorSelectorAsm(errorSelector);
}
}
/**
* @notice Apply the collection transfer policy to a transfer operation of a creator token.
*
* @dev If the caller is self (Permit-C Processor) it means we have already applied operator validation in the
* _beforeTransferFrom callback. In this case, the security policy was already applied and the operator
* that used the Permit-C processor passed the security policy check and transfer can be safely allowed.
*
* @dev The order of checking whitelisted accounts, authorized operator check and whitelisted codehashes
* is very deliberate. The order of operations is determined by the most frequently used settings that are
* expected in the wild.
*
* @dev Throws when the collection has enabled account freezing mode and either the `from` or `to` addresses
* are on the list of frozen accounts for the collection.
* @dev Throws when the collection is set to Level 9 - Soulbound Token.
* @dev Throws when the receiver has deployed code and isn't whitelisted, if ReceiverConstraints.NoCode is set
* and the transfer is not approved by an authorizer for the collection.
* @dev Throws when the receiver has never verified a signature to prove they are an EOA and the receiver
* isn't whitelisted, if the ReceiverConstraints.EOA is set and the transfer is not approved by an
* authorizer for the collection..
* @dev Throws when `msg.sender` is blacklisted, if CallerConstraints.OperatorBlacklistEnableOTC is set, unless
* `msg.sender` is also the `from` address or the transfer is approved by an authorizer for the collection.
* @dev Throws when `msg.sender` isn't whitelisted, if CallerConstraints.OperatorWhitelistEnableOTC is set, unless
* `msg.sender` is also the `from` address or the transfer is approved by an authorizer for the collection.
* @dev Throws when neither `msg.sender` nor `from` are whitelisted, if
* CallerConstraints.OperatorWhitelistDisableOTC is set and the transfer
* is not approved by an authorizer for the collection.
*
* @dev <h4>Postconditions:</h4>
* 1. Transfer is allowed or denied based on the applied transfer policy.
*
* @param caller The address initiating the transfer.
* @param from The address of the token owner.
* @param to The address of the token receiver.
* @param tokenId The token id being transferred.
*/
function validateTransfer(address caller, address from, address to, uint256 tokenId) public view {
(bytes4 errorSelector,) = _validateTransfer(_callerAuthorizedCheckToken, msg.sender, caller, from, to, tokenId);
if (errorSelector != SELECTOR_NO_ERROR) {
_revertCustomErrorSelectorAsm(errorSelector);
}
}
/**
* @notice Apply the collection transfer policy to a transfer operation of a creator token.
*
* @dev If the caller is self (Permit-C Processor) it means we have already applied operator validation in the
* _beforeTransferFrom callback. In this case, the security policy was already applied and the operator
* that used the Permit-C processor passed the security policy check and transfer can be safely allowed.
*
* @dev The order of checking whitelisted accounts, authorized operator check and whitelisted codehashes
* is very deliberate. The order of operations is determined by the most frequently used settings that are
* expected in the wild.
*
* @dev Throws when the collection has enabled account freezing mode and either the `from` or `to` addresses
* are on the list of frozen accounts for the collection.
* @dev Throws when the collection is set to Level 9 - Soulbound Token.
* @dev Throws when the receiver has deployed code and isn't whitelisted, if ReceiverConstraints.NoCode is set
* and the transfer is not approved by an authorizer for the collection.
* @dev Throws when the receiver has never verified a signature to prove they are an EOA and the receiver
* isn't whitelisted, if the ReceiverConstraints.EOA is set and the transfer is not approved by an
* authorizer for the collection..
* @dev Throws when `msg.sender` is blacklisted, if CallerConstraints.OperatorBlacklistEnableOTC is set, unless
* `msg.sender` is also the `from` address or the transfer is approved by an authorizer for the collection.
* @dev Throws when `msg.sender` isn't whitelisted, if CallerConstraints.OperatorWhitelistEnableOTC is set, unless
* `msg.sender` is also the `from` address or the transfer is approved by an authorizer for the collection.
* @dev Throws when neither `msg.sender` nor `from` are whitelisted, if
* CallerConstraints.OperatorWhitelistDisableOTC is set and the transfer
* is not approved by an authorizer for the collection.
*
* @dev <h4>Postconditions:</h4>
* 1. Transfer is allowed or denied based on the applied transfer policy.
*
* @param caller The address initiating the transfer.
* @param from The address of the token owner.
* @param to The address of the token receiver.
* @param tokenId The token id being transferred.
*/
function validateTransfer(address caller, address from, address to, uint256 tokenId, uint256 /*amount*/) external {
validateTransfer(caller, from, to, tokenId);
}
/**
* @notice Apply the collection transfer policy to a transfer operation of a creator token.
*
* @dev If the caller is self (Permit-C Processor) it means we have already applied operator validation in the
* _beforeTransferFrom callback. In this case, the security policy was already applied and the operator
* that used the Permit-C processor passed the security policy check and transfer can be safely allowed.
*
* @dev The order of checking whitelisted accounts, authorized operator check and whitelisted codehashes
* is very deliberate. The order of operations is determined by the most frequently used settings that are
* expected in the wild.
*
* @dev Throws when the collection has enabled account freezing mode and either the `from` or `to` addresses
* are on the list of frozen accounts for the collection.
* @dev Throws when the collection is set to Level 9 - Soulbound Token.
* @dev Throws when the receiver has deployed code and isn't whitelisted, if ReceiverConstraints.NoCode is set
* and the transfer is not approved by an authorizer for the collection.
* @dev Throws when the receiver has never verified a signature to prove they are an EOA and the receiver
* isn't whitelisted, if the ReceiverConstraints.EOA is set and the transfer is not approved by an
* authorizer for the collection..
* @dev Throws when `msg.sender` is blacklisted, if CallerConstraints.OperatorBlacklistEnableOTC is set, unless
* `msg.sender` is also the `from` address or the transfer is approved by an authorizer for the collection.
* @dev Throws when `msg.sender` isn't whitelisted, if CallerConstraints.OperatorWhitelistEnableOTC is set, unless
* `msg.sender` is also the `from` address or the transfer is approved by an authorizer for the collection.
* @dev Throws when neither `msg.sender` nor `from` are whitelisted, if
* CallerConstraints.OperatorWhitelistDisableOTC is set and the transfer
* is not approved by an authorizer for the collection.
*
* @dev <h4>Postconditions:</h4>
* 1. Transfer is allowed or denied based on the applied transfer policy.
*
* @param caller The address initiating the transfer.
* @param from The address of the token owner.
* @param to The address of the token receiver.
*/
function applyCollectionTransferPolicy(address caller, address from, address to) external view {
validateTransfer(caller, from, to);
}
/**
* @notice Returns the caller and receiver constraints for the specified transfer security level.
*
* @param level The transfer security level to return the caller and receiver constraints for.
*
* @return callerConstraints The `CallerConstraints` value for the level.
* @return receiverConstraints The `ReceiverConstraints` value for the level.
*/
function transferSecurityPolicies(
uint256 level
) public view returns (uint256 callerConstraints, uint256 receiverConstraints) {
callerConstraints = uint8((_callerConstraintsLookup >> (level << 3)));
receiverConstraints = uint8((_receiverConstraintsLookup >> (level << 3)));
}
/**
* @notice Sets an operator for an authorized transfer that skips transfer security level
* validation for caller and receiver constraints.
*
* @dev An authorizer *MUST* clear the authorization with a call to `afterAuthorizedTransfer`
* to prevent unauthorized transfers of the token.
*
* @dev Throws when authorization mode is disabled for the collection.
* @dev Throws when using the wildcard operator address and the collection does not allow
* for wildcard authorized operators.
* @dev Throws when the caller is not an allowed authorizer for the collection.
*
* @dev <h4>Postconditions:</h4>
* 1. The `operator` is stored as an authorized operator for transfers.
*
* @param operator The address of the operator to set as authorized for transfers.
* @param token The address of the token to authorize.
* @param tokenId The token id to set the authorized operator for.
*/
function beforeAuthorizedTransfer(address operator, address token, uint256 tokenId) external {
_setOperatorInTransientStorage(operator, token, tokenId, false);
}
/**
* @notice Clears the authorized operator for a token to prevent additional transfers that
* do not conform to the transfer security level for the token.
*
* @dev Throws when authorization mode is disabled for the collection.
* @dev Throws when using the wildcard operator address and the collection does not allow
* for wildcard authorized operators.
* @dev Throws when the caller is not an allowed authorizer for the collection.
*
* @dev <h4>Postconditions:</h4>
* 1. The authorized operator for the token is cleared from storage.
*
* @param token The address of the token to authorize.
* @param tokenId The token id to set the authorized operator for.
*/
function afterAuthorizedTransfer(address token, uint256 tokenId) public {
_setOperatorInTransientStorage(address(uint160(uint256(BYTES32_ZERO))), token, tokenId, false);
}
/**
* @notice Sets an operator for an authorized transfer that skips transfer security level
* validation for caller and receiver constraints.
* @notice This overload of `beforeAuthorizedTransfer` defaults to a tokenId of 0.
*
* @dev An authorizer *MUST* clear the authorization with a call to `afterAuthorizedTransfer`
* to prevent unauthorized transfers of the token.
*
* @dev Throws when authorization mode is disabled for the collection.
* @dev Throws when using the wildcard operator address and the collection does not allow
* for wildcard authorized operators.
* @dev Throws when the caller is not an allowed authorizer for the collection.
*
* @dev <h4>Postconditions:</h4>
* 1. The `operator` is stored as an authorized operator for transfers.
*
* @param operator The address of the operator to set as authorized for transfers.
* @param token The address of the token to authorize.
*/
function beforeAuthorizedTransfer(address operator, address token) external {
_setOperatorInTransientStorage(operator, token, 0, true);
}
/**
* @notice Clears the authorized operator for a token to prevent additional transfers that
* do not conform to the transfer security level for the token.
* @notice This overload of `afterAuthorizedTransfer` defaults to a tokenId of 0.
*
* @dev Throws when authorization mode is disabled for the collection.
* @dev Throws when using the wildcard operator address and the collection does not allow
* for wildcard authorized operators.
* @dev Throws when the caller is not an allowed authorizer for the collection.
*
* @dev <h4>Postconditions:</h4>
* 1. The authorized operator for the token is cleared from storage.
*
* @param token The address of the token to authorize.
*/
function afterAuthorizedTransfer(address token) external {
afterAuthorizedTransfer(token, 0);
}
/**
* @notice Sets the wildcard operator to authorize any operator to transfer a token while
* skipping transfer security level validation for caller and receiver constraints.
*
* @dev An authorizer *MUST* clear the authorization with a call to `afterAuthorizedTransfer`
* to prevent unauthorized transfers of the token.
*
* @dev Throws when authorization mode is disabled for the collection.
* @dev Throws when the collection does not allow for wildcard authorized operators.
* @dev Throws when the caller is not an allowed authorizer for the collection.
*
* @dev <h4>Postconditions:</h4>
* 1. The wildcard operator is stored as an authorized operator for transfers.
*
* @param token The address of the token to authorize.
* @param tokenId The token id to set the authorized operator for.
*/
function beforeAuthorizedTransfer(address token, uint256 tokenId) external {
_setOperatorInTransientStorage(WILDCARD_OPERATOR_ADDRESS, token, tokenId, false);
}
/**
* @notice Sets the wildcard operator to authorize any operator to transfer a token while
* skipping transfer security level validation for caller and receiver constraints.
*
* @dev An authorizer *MUST* clear the authorization with a call to `afterAuthorizedTransfer`
* to prevent unauthorized transfers of the token.
*
* @dev Throws when authorization mode is disabled for the collection.
* @dev Throws when the collection does not allow for wildcard authorized operators.
* @dev Throws when the caller is not an allowed authorizer for the collection.
*
* @dev <h4>Postconditions:</h4>
* 1. The wildcard operator is stored as an authorized operator for transfers.
*
* @param token The address of the token to authorize.
* @param tokenId The token id to set the authorized operator for.
*/
function beforeAuthorizedTransferWithAmount(address token, uint256 tokenId, uint256 /*amount*/) external {
_setOperatorInTransientStorage(WILDCARD_OPERATOR_ADDRESS, token, tokenId, false);
}
/**
* @notice Clears the authorized operator for a token to prevent additional transfers that
* do not conform to the transfer security level for the token.
*
* @dev Throws when authorization mode is disabled for the collection.
* @dev Throws when using the wildcard operator address and the collection does not allow
* for wildcard authorized operators.
* @dev Throws when the caller is not an allowed authorizer for the collection.
*
* @dev <h4>Postconditions:</h4>
* 1. The authorized operator for the token is cleared from storage.
*
* @param token The address of the token to authorize.
* @param tokenId The token id to set the authorized operator for.
*/
function afterAuthorizedTransferWithAmount(address token, uint256 tokenId) external {
afterAuthorizedTransfer(token, tokenId);
}
/*************************************************************************/
/* LIST MANAGEMENT */
/*************************************************************************/
/**
* @notice Creates a new list id. The list id is a handle to allow editing of blacklisted and whitelisted accounts
* and codehashes.
*
* @dev <h4>Postconditions:</h4>
* 1. A new list with the specified name is created.
* 2. The caller is set as the owner of the new list.
* 3. A `CreatedList` event is emitted.
* 4. A `ReassignedListOwnership` event is emitted.
*
* @param name The name of the new list.
* @return id The id of the new list.
*/
function createList(string calldata name) public returns (uint120 id) {
unchecked {
id = ++lastListId;
}
listOwners[id] = msg.sender;
emit CreatedList(id, name);
emit ReassignedListOwnership(id, msg.sender);
}
/**
* @notice Creates a new list id, and copies all blacklisted and whitelisted accounts and codehashes from the
* specified source list.
*
* @dev <h4>Postconditions:</h4>
* 1. A new list with the specified name is created.
* 2. The caller is set as the owner of the new list.
* 3. A `CreatedList` event is emitted.
* 4. A `ReassignedListOwnership` event is emitted.
* 5. All blacklisted and whitelisted accounts and codehashes from the specified source list are copied
* to the new list.
* 6. An `AddedAccountToList` event is emitted for each blacklisted and whitelisted account copied.
* 7. An `AddedCodeHashToList` event is emitted for each blacklisted and whitelisted codehash copied.
*
* @param name The name of the new list.
* @param sourceListId The id of the source list to copy from.
* @return id The id of the new list.
*/
function createListCopy(string calldata name, uint120 sourceListId) external returns (uint120 id) {
unchecked {
id = ++lastListId;
}
unchecked {
if (sourceListId > id - 1) {
revert CreatorTokenTransferValidator__ListDoesNotExist();
}
}
listOwners[id] = msg.sender;
emit CreatedList(id, name);
emit ReassignedListOwnership(id, msg.sender);
List storage sourceBlacklist = blacklists[sourceListId];
List storage sourceWhitelist = whitelists[sourceListId];
List storage sourceAuthorizers = authorizers[sourceListId];
List storage targetBlacklist = blacklists[id];
List storage targetWhitelist = whitelists[id];
List storage targetAuthorizers = authorizers[id];
_copyAddressSet(LIST_TYPE_BLACKLIST, id, sourceBlacklist, targetBlacklist);
_copyBytes32Set(LIST_TYPE_BLACKLIST, id, sourceBlacklist, targetBlacklist);
_copyAddressSet(LIST_TYPE_WHITELIST, id, sourceWhitelist, targetWhitelist);
_copyBytes32Set(LIST_TYPE_WHITELIST, id, sourceWhitelist, targetWhitelist);
_copyAddressSet(LIST_TYPE_AUTHORIZERS, id, sourceAuthorizers, targetAuthorizers);
_copyBytes32Set(LIST_TYPE_AUTHORIZERS, id, sourceAuthorizers, targetAuthorizers);
}
/**
* @notice Transfer ownership of a list to a new owner.
*
* @dev Throws when the new owner is the zero address.
* @dev Throws when the caller does not own the specified list.
*
* @dev <h4>Postconditions:</h4>
* 1. The list ownership is transferred to the new owner.
* 2. A `ReassignedListOwnership` event is emitted.
*
* @param id The id of the list.
* @param newOwner The address of the new owner.
*/
function reassignOwnershipOfList(uint120 id, address newOwner) public {
if(newOwner == address(0)) {
revert CreatorTokenTransferValidator__ListOwnershipCannotBeTransferredToZeroAddress();
}
_reassignOwnershipOfList(id, newOwner);
}
/**
* @notice Renounce the ownership of a list, rendering the list immutable.
*
* @dev Throws when the caller does not own the specified list.
*
* @dev <h4>Postconditions:</h4>
* 1. The ownership of the specified list is renounced.
* 2. A `ReassignedListOwnership` event is emitted.
*
* @param id The id of the list.
*/
function renounceOwnershipOfList(uint120 id) public {
_reassignOwnershipOfList(id, address(0));
}
/**
* @notice Set the transfer security level, authorization mode and account freezing mode settings of a collection.
*
* @dev Throws when the caller is neither collection contract, nor the owner or admin of the specified collection.
*
* @dev <h4>Postconditions:</h4>
* 1. The transfer security level of the specified collection is set to the new value.
* 2. The authorization mode setting of the specified collection is set to the new value.
* 3. The authorization wildcard operator mode setting of the specified collection is set to the new value.
* 4. The account freezing mode setting of the specified collection is set to the new value.
* 5. A `SetTransferSecurityLevel` event is emitted.
* 6. A `SetAuthorizationModeEnabled` event is emitted.
* 7. A `SetAccountFreezingModeEnabled` event is emitted.
*
* @param collection The address of the collection.
* @param level The new transfer security level to apply.
* @param disableAuthorizationMode Flag if the collection allows for authorizer mode.
* @param disableWildcardOperators Flag if the authorizer can set wildcard operators.
* @param enableAccountFreezingMode Flag if the collection is using account freezing.
*/
function setTransferSecurityLevelOfCollection(
address collection,
uint8 level,
bool disableAuthorizationMode,
bool disableWildcardOperators,
bool enableAccountFreezingMode) external {
if (level > TRANSFER_SECURITY_LEVEL_NINE) {
revert CreatorTokenTransferValidator__InvalidTransferSecurityLevel();
}
_requireCallerIsNFTOrContractOwnerOrAdmin(collection);
collectionSecurityPolicies[collection].transferSecurityLevel = level;
collectionSecurityPolicies[collection].disableAuthorizationMode = disableAuthorizationMode;
collectionSecurityPolicies[collection].authorizersCannotSetWildcardOperators = disableWildcardOperators;
collectionSecurityPolicies[collection].enableAccountFreezingMode = enableAccountFreezingMode;
emit SetTransferSecurityLevel(collection, level);
emit SetAuthorizationModeEnabled(collection, disableAuthorizationMode, disableWildcardOperators);
emit SetAccountFreezingModeEnabled(collection, enableAccountFreezingMode);
}
/**
* @notice Set the token type setting of a collection.
*
* @dev Throws when the caller is neither collection contract, nor the owner or admin of the specified collection.
*
* @dev <h4>Postconditions:</h4>
* 1. The token type of the specified collection is set to the new value.
* 2. A `SetTokenType` event is emitted.
*
* @param collection The address of the collection.
* @param tokenType The new transfer security level to apply.
*/
function setTokenTypeOfCollection(
address collection,
uint16 tokenType
) external {
_requireCallerIsNFTOrContractOwnerOrAdmin(collection);
collectionSecurityPolicies[collection].tokenType = tokenType;
emit SetTokenType(collection, tokenType);
}
/**
* @notice Applies the specified list to a collection.
*
* @dev Throws when the caller is neither collection contract, nor the owner or admin of the specified collection.
* @dev Throws when the specified list id does not exist.
*
* @dev <h4>Postconditions:</h4>
* 1. The list of the specified collection is set to the new value.
* 2. An `AppliedListToCollection` event is emitted.
*
* @param collection The address of the collection.
* @param id The id of the operator whitelist.
*/
function applyListToCollection(address collection, uint120 id) public {
_requireCallerIsNFTOrContractOwnerOrAdmin(collection);
if (id > lastListId) {
revert CreatorTokenTransferValidator__ListDoesNotExist();
}
collectionSecurityPolicies[collection].listId = id;
emit AppliedListToCollection(collection, id);
}
/**
* @notice Adds accounts to the frozen accounts list of a collection.
*
* @dev Throws when the caller is neither collection contract, nor the owner or admin of the specified collection.
*
* @dev <h4>Postconditions:</h4>
* 1. The accounts are added to the list of frozen accounts for a collection.
* 2. A `AccountFrozenForCollection` event is emitted for each account added to the list.
*
* @param collection The address of the collection.
* @param accountsToFreeze The list of accounts to added to frozen accounts.
*/
function freezeAccountsForCollection(address collection, address[] calldata accountsToFreeze) external {
_requireCallerIsNFTOrContractOwnerOrAdmin(collection);
AccountList storage accounts = frozenAccounts[collection];
for (uint256 i = 0; i < accountsToFreeze.length;) {
address accountToFreeze = accountsToFreeze[i];
if (accounts.enumerableAccounts.add(accountToFreeze)) {
emit AccountFrozenForCollection(collection, accountToFreeze);
accounts.nonEnumerableAccounts[accountToFreeze] = true;
}
unchecked {
++i;
}
}
}
/**
* @notice Removes accounts to the frozen accounts list of a collection.
*
* @dev Throws when the caller is neither collection contract, nor the owner or admin of the specified collection.
*
* @dev <h4>Postconditions:</h4>
* 1. The accounts are removed from the list of frozen accounts for a collection.
* 2. A `AccountUnfrozenForCollection` event is emitted for each account removed from the list.
*
* @param collection The address of the collection.
* @param accountsToUnfreeze The list of accounts to remove from frozen accounts.
*/
function unfreezeAccountsForCollection(address collection, address[] calldata accountsToUnfreeze) external {
_requireCallerIsNFTOrContractOwnerOrAdmin(collection);
AccountList storage accounts = frozenAccounts[collection];
for (uint256 i = 0; i < accountsToUnfreeze.length;) {
address accountToUnfreeze = accountsToUnfreeze[i];
if (accounts.enumerableAccounts.remove(accountToUnfreeze)) {
emit AccountUnfrozenForCollection(collection, accountToUnfreeze);
accounts.nonEnumerableAccounts[accountToUnfreeze] = false;
}
unchecked {
++i;
}
}
}
/**
* @notice Get the security policy of the specified collection.
* @param collection The address of the collection.
* @return The security policy of the specified collection, which includes:
* Transfer security level, operator whitelist id, permitted contract receiver allowlist id,
* authorizer mode, if authorizer can set a wildcard operator, and if account freezing is
* enabled.
*/
function getCollectionSecurityPolicy(
address collection
) external view returns (CollectionSecurityPolicyV3 memory) {
return collectionSecurityPolicies[collection];
}
/**
* @notice Adds one or more accounts to a blacklist.
*
* @dev Throws when the caller does not own the specified list.
* @dev Throws when the accounts array is empty.
*
* @dev <h4>Postconditions:</h4>
* 1. Accounts not previously in the list are added.
* 2. An `AddedAccountToList` event is emitted for each account that is newly added to the list.
*
* @param id The id of the list.
* @param accounts The addresses of the accounts to add.
*/
function addAccountsToBlacklist(
uint120 id,
address[] calldata accounts
) external {
_addAccountsToList(blacklists[id], LIST_TYPE_BLACKLIST, id, accounts);
}
/**
* @notice Adds one or more accounts to a whitelist.
*
* @dev Throws when the caller does not own the specified list.
* @dev Throws when the accounts array is empty.
*
* @dev <h4>Postconditions:</h4>
* 1. Accounts not previously in the list are added.
* 2. An `AddedAccountToList` event is emitted for each account that is newly added to the list.
*
* @param id The id of the list.
* @param accounts The addresses of the accounts to add.
*/
function addAccountsToWhitelist(
uint120 id,
address[] calldata accounts
) external {
_addAccountsToList(whitelists[id], LIST_TYPE_WHITELIST, id, accounts);
}
/**
* @notice Adds one or more accounts to authorizers.
*
* @dev Throws when the caller does not own the specified list.
* @dev Throws when the accounts array is empty.
*
* @dev <h4>Postconditions:</h4>
* 1. Accounts not previously in the list are added.
* 2. An `AddedAccountToList` event is emitted for each account that is newly added to the list.
*
* @param id The id of the list.
* @param accounts The addresses of the accounts to add.
*/
function addAccountsToAuthorizers(
uint120 id,
address[] calldata accounts
) external {
_addAccountsToList(authorizers[id], LIST_TYPE_AUTHORIZERS, id, accounts);
}
/**
* @notice Adds one or more codehashes to a blacklist.
*
* @dev Throws when the caller does not own the specified list.
* @dev Throws when the codehashes array is empty.
* @dev Throws when a codehash is zero.
*
* @dev <h4>Postconditions:</h4>
* 1. Codehashes not previously in the list are added.
* 2. An `AddedCodeHashToList` event is emitted for each codehash that is newly added to the list.
*
* @param id The id of the list.
* @param codehashes The codehashes to add.
*/
function addCodeHashesToBlacklist(
uint120 id,
bytes32[] calldata codehashes
) external {
_addCodeHashesToList(blacklists[id], LIST_TYPE_BLACKLIST, id, codehashes);
}
/**
* @notice Adds one or more codehashes to a whitelist.
*
* @dev Throws when the caller does not own the specified list.
* @dev Throws when the codehashes array is empty.
* @dev Throws when a codehash is zero.
*
* @dev <h4>Postconditions:</h4>
* 1. Codehashes not previously in the list are added.
* 2. An `AddedCodeHashToList` event is emitted for each codehash that is newly added to the list.
*
* @param id The id of the list.
* @param codehashes The codehashes to add.
*/
function addCodeHashesToWhitelist(
uint120 id,
bytes32[] calldata codehashes
) external {
_addCodeHashesToList(whitelists[id], LIST_TYPE_WHITELIST, id, codehashes);
}
/**
* @notice Removes one or more accounts from a blacklist.
*
* @dev Throws when the caller does not own the specified list.
* @dev Throws when the accounts array is empty.
*
* @dev <h4>Postconditions:</h4>
* 1. Accounts previously in the list are removed.
* 2. A `RemovedAccountFromList` event is emitted for each account that is removed from the list.
*
* @param id The id of the list.
* @param accounts The addresses of the accounts to remove.
*/
function removeAccountsFromBlacklist(
uint120 id,
address[] calldata accounts
) external {
_removeAccountsFromList(blacklists[id], LIST_TYPE_BLACKLIST, id, accounts);
}
/**
* @notice Removes one or more accounts from a whitelist.
*
* @dev Throws when the caller does not own the specified list.
* @dev Throws when the accounts array is empty.
*
* @dev <h4>Postconditions:</h4>
* 1. Accounts previously in the list are removed.
* 2. A `RemovedAccountFromList` event is emitted for each account that is removed from the list.
*
* @param id The id of the list.
* @param accounts The addresses of the accounts to remove.
*/
function removeAccountsFromWhitelist(
uint120 id,
address[] calldata accounts
) external {
_removeAccountsFromList(whitelists[id], LIST_TYPE_WHITELIST, id, accounts);
}
/**
* @notice Removes one or more accounts from authorizers.
*
* @dev Throws when the caller does not own the specified list.
* @dev Throws when the accounts array is empty.
*
* @dev <h4>Postconditions:</h4>
* 1. Accounts previously in the list are removed.
* 2. A `RemovedAccountFromList` event is emitted for each account that is removed from the list.
*
* @param id The id of the list.
* @param accounts The addresses of the accounts to remove.
*/
function removeAccountsFromAuthorizers(
uint120 id,
address[] calldata accounts
) external {
_removeAccountsFromList(authorizers[id], LIST_TYPE_AUTHORIZERS, id, accounts);
}
/**
* @notice Removes one or more codehashes from a blacklist.
*
* @dev Throws when the caller does not own the specified list.
* @dev Throws when the codehashes array is empty.
*
* @dev <h4>Postconditions:</h4>
* 1. Codehashes previously in the list are removed.
* 2. A `RemovedCodeHashFromList` event is emitted for each codehash that is removed from the list.
*
* @param id The id of the list.
* @param codehashes The codehashes to remove.
*/
function removeCodeHashesFromBlacklist(
uint120 id,
bytes32[] calldata codehashes
) external {
_removeCodeHashesFromList(blacklists[id], LIST_TYPE_BLACKLIST, id, codehashes);
}
/**
* @notice Removes one or more codehashes from a whitelist.
*
* @dev Throws when the caller does not own the specified list.
* @dev Throws when the codehashes array is empty.
*
* @dev <h4>Postconditions:</h4>
* 1. Codehashes previously in the list are removed.
* 2. A `RemovedCodeHashFromList` event is emitted for each codehash that is removed from the list.
*
* @param id The id of the list.
* @param codehashes The codehashes to remove.
*/
function removeCodeHashesFromWhitelist(
uint120 id,
bytes32[] calldata codehashes
) external {
_removeCodeHashesFromList(whitelists[id], LIST_TYPE_WHITELIST, id, codehashes);
}
/**
* @notice Get blacklisted accounts by list id.
* @param id The id of the list.
* @return An array of blacklisted accounts.
*/
function getBlacklistedAccounts(uint120 id) public view returns (address[] memory) {
return blacklists[id].enumerableAccounts.values();
}
/**
* @notice Get whitelisted accounts by list id.
* @param id The id of the list.
* @return An array of whitelisted accounts.
*/
function getWhitelistedAccounts(uint120 id) public view returns (address[] memory) {
return whitelists[id].enumerableAccounts.values();
}
/**
* @notice Get authorizor accounts by list id.
* @param id The id of the list.
* @return An array of authorizer accounts.
*/
function getAuthorizerAccounts(uint120 id) public view returns (address[] memory) {
return authorizers[id].enumerableAccounts.values();
}
/**
* @notice Get blacklisted codehashes by list id.
* @param id The id of the list.
* @return An array of blacklisted codehashes.
*/
function getBlacklistedCodeHashes(uint120 id) public view returns (bytes32[] memory) {
return blacklists[id].enumerableCodehashes.values();
}
/**
* @notice Get whitelisted codehashes by list id.
* @param id The id of the list.
* @return An array of whitelisted codehashes.
*/
function getWhitelistedCodeHashes(uint120 id) public view returns (bytes32[] memory) {
return whitelists[id].enumerableCodehashes.values();
}
/**
* @notice Check if an account is blacklisted in a specified list.
* @param id The id of the list.
* @param account The address of the account to check.
* @return True if the account is blacklisted in the specified list, false otherwise.
*/
function isAccountBlacklisted(uint120 id, address account) public view returns (bool) {
return blacklists[id].nonEnumerableAccounts[account];
}
/**
* @notice Check if an account is whitelisted in a specified list.
* @param id The id of the list.
* @param account The address of the account to check.
* @return True if the account is whitelisted in the specified list, false otherwise.
*/
function isAccountWhitelisted(uint120 id, address account) public view returns (bool) {
return whitelists[id].nonEnumerableAccounts[account];
}
/**
* @notice Check if an account is an authorizer in a specified list.
* @param id The id of the list.
* @param account The address of the account to check.
* @return True if the account is an authorizer in the specified list, false otherwise.
*/
function isAccountAuthorizer(uint120 id, address account) public view returns (bool) {
return authorizers[id].nonEnumerableAccounts[account];
}
/**
* @notice Check if a codehash is blacklisted in a specified list.
* @param id The id of the list.
* @param codehash The codehash to check.
* @return True if the codehash is blacklisted in the specified list, false otherwise.
*/
function isCodeHashBlacklisted(uint120 id, bytes32 codehash) public view returns (bool) {
return blacklists[id].nonEnumerableCodehashes[codehash];
}
/**
* @notice Check if a codehash is whitelisted in a specified list.
* @param id The id of the list.
* @param codehash The codehash to check.
* @return True if the codehash is whitelisted in the specified list, false otherwise.
*/
function isCodeHashWhitelisted(uint120 id, bytes32 codehash) public view returns (bool) {
return whitelists[id].nonEnumerableCodehashes[codehash];
}
/**
* @notice Get blacklisted accounts by collection.
* @param collection The address of the collection.
* @return An array of blacklisted accounts.
*/
function getBlacklistedAccountsByCollection(address collection) external view returns (address[] memory) {
return getBlacklistedAccounts(collectionSecurityPolicies[collection].listId);
}
/**
* @notice Get whitelisted accounts by collection.
* @param collection The address of the collection.
* @return An array of whitelisted accounts.
*/
function getWhitelistedAccountsByCollection(address collection) external view returns (address[] memory) {
return getWhitelistedAccounts(collectionSecurityPolicies[collection].listId);
}
/**
* @notice Get authorizer accounts by collection.
* @param collection The address of the collection.
* @return An array of authorizer accounts.
*/
function getAuthorizerAccountsByCollection(address collection) external view returns (address[] memory) {
return getAuthorizerAccounts(collectionSecurityPolicies[collection].listId);
}
/**
* @notice Get frozen accounts by collection.
* @param collection The address of the collection.
* @return An array of frozen accounts.
*/
function getFrozenAccountsByCollection(address collection) external view returns (address[] memory) {
return frozenAccounts[collection].enumerableAccounts.values();
}
/**
* @notice Get blacklisted codehashes by collection.
* @param collection The address of the collection.
* @return An array of blacklisted codehashes.
*/
function getBlacklistedCodeHashesByCollection(address collection) external view returns (bytes32[] memory) {
return getBlacklistedCodeHashes(collectionSecurityPolicies[collection].listId);
}
/**
* @notice Get whitelisted codehashes by collection.
* @param collection The address of the collection.
* @return An array of whitelisted codehashes.
*/
function getWhitelistedCodeHashesByCollection(address collection) external view returns (bytes32[] memory) {
return getWhitelistedCodeHashes(collectionSecurityPolicies[collection].listId);
}
/**
* @notice Check if an account is blacklisted by a specified collection.
* @param collection The address of the collection.
* @param account The address of the account to check.
* @return True if the account is blacklisted by the specified collection, false otherwise.
*/
function isAccountBlacklistedByCollection(address collection, address account) external view returns (bool) {
return isAccountBlacklisted(collectionSecurityPolicies[collection].listId, account);
}
/**
* @notice Check if an account is whitelisted by a specified collection.
* @param collection The address of the collection.
* @param account The address of the account to check.
* @return True if the account is whitelisted by the specified collection, false otherwise.
*/
function isAccountWhitelistedByCollection(address collection, address account) external view returns (bool) {
return isAccountWhitelisted(collectionSecurityPolicies[collection].listId, account);
}
/**
* @notice Check if an account is an authorizer of a specified collection.
* @param collection The address of the collection.
* @param account The address of the account to check.
* @return True if the account is an authorizer by the specified collection, false otherwise.
*/
function isAccountAuthorizerOfCollection(address collection, address account) external view returns (bool) {
return isAccountAuthorizer(collectionSecurityPolicies[collection].listId, account);
}
/**
* @notice Check if an account is frozen for a specified collection.
* @param collection The address of the collection.
* @param account The address of the account to check.
* @return True if the account is frozen by the specified collection, false otherwise.
*/
function isAccountFrozenForCollection(address collection, address account) external view returns (bool) {
return frozenAccounts[collection].nonEnumerableAccounts[account];
}
/**
* @notice Check if a codehash is blacklisted by a specified collection.
* @param collection The address of the collection.
* @param codehash The codehash to check.
* @return True if the codehash is blacklisted by the specified collection, false otherwise.
*/
function isCodeHashBlacklistedByCollection(address collection, bytes32 codehash) external view returns (bool) {
return isCodeHashBlacklisted(collectionSecurityPolicies[collection].listId, codehash);
}
/**
* @notice Check if a codehash is whitelisted by a specified collection.
* @param collection The address of the collection.
* @param codehash The codehash to check.
* @return True if the codehash is whitelisted by the specified collection, false otherwise.
*/
function isCodeHashWhitelistedByCollection(address collection, bytes32 codehash) external view returns (bool) {
return isCodeHashWhitelisted(collectionSecurityPolicies[collection].listId, codehash);
}
/// @notice Returns true if the specified account has verified a signature on the registry, false otherwise.
function isVerifiedEOA(address account) public view returns (bool) {
return IEOARegistry(_eoaRegistry).isVerifiedEOA(account);
}
/// @notice ERC-165 Interface Support
/// @dev Do not remove LEGACY from this contract or future contracts.
/// Doing so will break backwards compatibility with V1 and V2 creator tokens.
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == LEGACY_TRANSFER_VALIDATOR_INTERFACE_ID ||
interfaceId == type(ITransferValidator).interfaceId ||
interfaceId == type(IPermitC).interfaceId ||
interfaceId == type(IEOARegistry).interfaceId ||
super.supportsInterface(interfaceId);
}
/*************************************************************************/
/* HELPERS */
/*************************************************************************/
/**
* @notice Reverts the transaction if the caller is not the owner or assigned the default
* @notice admin role of the contract at `tokenAddress`.
*
* @dev Throws when the caller is neither owner nor assigned the default admin role.
*
* @param tokenAddress The contract address of the token to check permissions for.
*/
function _requireCallerIsNFTOrContractOwnerOrAdmin(address tokenAddress) internal view {
address caller = msg.sender;
if(caller == tokenAddress) {
return;
}
(address contractOwner,) = _safeOwner(tokenAddress);
if(caller == contractOwner) {
return;
}
(bool callerIsContractAdmin,) = _safeHasRole(tokenAddress, DEFAULT_ACCESS_CONTROL_ADMIN_ROLE, caller);
if(callerIsContractAdmin) {
return;
}
revert CreatorTokenTransferValidator__CallerMustHaveElevatedPermissionsForSpecifiedNFT();
}
/**
* @notice Copies all addresses in `ptrFromList` to `ptrToList`.
*
* @dev This function will copy all addresses from one list to another list.
* @dev Note: If used to copy adddresses to an existing list the current list contents will not be
* @dev deleted before copying. New addresses will be appeneded to the end of the list and the
* @dev non-enumerable mapping key value will be set to true.
*
* @dev <h4>Postconditions:</h4>
* 1. Addresses in from list that are not already present in to list are added to the to list.
* 2. Emits an `AddedAccountToList` event for each address copied to the list.
*
* @param listType The type of list addresses are being copied from and to.
* @param destinationListId The id of the list being copied to.
* @param ptrFromList The storage pointer for the list being copied from.
* @param ptrToList The storage pointer for the list being copied to.
*/
function _copyAddressSet(
uint8 listType,
uint120 destinationListId,
List storage ptrFromList,
List storage ptrToList
) private {
EnumerableSet.AddressSet storage ptrFromSet = ptrFromList.enumerableAccounts;
EnumerableSet.AddressSet storage ptrToSet = ptrToList.enumerableAccounts;
mapping (address => bool) storage ptrToNonEnumerableSet = ptrToList.nonEnumerableAccounts;
uint256 sourceLength = ptrFromSet.length();
address account;
for (uint256 i = 0; i < sourceLength;) {
account = ptrFromSet.at(i);
if (ptrToSet.add(account)) {
emit AddedAccountToList(listType, destinationListId, account);
ptrToNonEnumerableSet[account] = true;
}
unchecked {
++i;
}
}
}
/**
* @notice Copies all codehashes in `ptrFromList` to `ptrToList`.
*
* @dev This function will copy all codehashes from one list to another list.
* @dev Note: If used to copy codehashes to an existing list the current list contents will not be
* @dev deleted before copying. New codehashes will be appeneded to the end of the list and the
* @dev non-enumerable mapping key value will be set to true.
*
* @dev <h4>Postconditions:</h4>
* 1. Codehashes in from list that are not already present in to list are added to the to list.
* 2. Emits an `AddedCodeHashToList` event for each codehash copied to the list.
*
* @param listType The type of list codehashes are being copied from and to.
* @param destinationListId The id of the list being copied to.
* @param ptrFromList The storage pointer for the list being copied from.
* @param ptrToList The storage pointer for the list being copied to.
*/
function _copyBytes32Set(
uint8 listType,
uint120 destinationListId,
List storage ptrFromList,
List storage ptrToList
) private {
EnumerableSet.Bytes32Set storage ptrFromSet = ptrFromList.enumerableCodehashes;
EnumerableSet.Bytes32Set storage ptrToSet = ptrToList.enumerableCodehashes;
mapping (bytes32 => bool) storage ptrToNonEnumerableSet = ptrToList.nonEnumerableCodehashes;
uint256 sourceLength = ptrFromSet.length();
bytes32 codehash;
for (uint256 i = 0; i < sourceLength;) {
codehash = ptrFromSet.at(i);
if (ptrToSet.add(codehash)) {
emit AddedCodeHashToList(listType, destinationListId, codehash);
ptrToNonEnumerableSet[codehash] = true;
}
unchecked {
++i;
}
}
}
/**
* @notice Adds one or more accounts to a list.
*
* @dev <h4>Postconditions:</h4>
* 1. Accounts that were not previously in the list are added to the list.
* 2. An `AddedAccountToList` event is emitted for each account that was not
* previously on the list.
*
* @param list The storage pointer for the list to add accounts to.
* @param listType The type of list the accounts are being added to.
* @param id The id of the list the accounts are being added to.
* @param accounts An array of accounts to add to the list.
*/
function _addAccountsToList(
List storage list,
uint8 listType,
uint120 id,
address[] calldata accounts
) internal onlyListOwner(id) {
address account;
for (uint256 i = 0; i < accounts.length;) {
account = accounts[i];
if (list.enumerableAccounts.add(account)) {
emit AddedAccountToList(listType, id, account);
list.nonEnumerableAccounts[account] = true;
}
unchecked {
++i;
}
}
}
/**
* @notice Adds one or more codehashes to a list.
*
* @dev <h4>Postconditions:</h4>
* 1. Codehashes that were not previously in the list are added to the list.
* 2. An `AddedCodeHashToList` event is emitted for each codehash that was not
* previously on the list.
*
* @param list The storage pointer for the list to add codehashes to.
* @param listType The type of list the codehashes are being added to.
* @param id The id of the list the codehashes are being added to.
* @param codehashes An array of codehashes to add to the list.
*/
function _addCodeHashesToList(
List storage list,
uint8 listType,
uint120 id,
bytes32[] calldata codehashes
) internal onlyListOwner(id) {
bytes32 codehash;
for (uint256 i = 0; i < codehashes.length;) {
codehash = codehashes[i];
if (list.enumerableCodehashes.add(codehash)) {
emit AddedCodeHashToList(listType, id, codehash);
list.nonEnumerableCodehashes[codehash] = true;
}
unchecked {
++i;
}
}
}
/**
* @notice Removes one or more accounts from a list.
*
* @dev <h4>Postconditions:</h4>
* 1. Accounts that were previously in the list are removed from the list.
* 2. An `RemovedAccountFromList` event is emitted for each account that was
* previously on the list.
*
* @param list The storage pointer for the list to remove accounts from.
* @param listType The type of list the accounts are being removed from.
* @param id The id of the list the accounts are being removed from.
* @param accounts An array of accounts to remove from the list.
*/
function _removeAccountsFromList(
List storage list,
uint8 listType,
uint120 id,
address[] memory accounts
) internal onlyListOwner(id) {
address account;
for (uint256 i = 0; i < accounts.length;) {
account = accounts[i];
if (list.enumerableAccounts.remove(account)) {
emit RemovedAccountFromList(listType, id, account);
delete list.nonEnumerableAccounts[account];
}
unchecked {
++i;
}
}
}
/**
* @notice Removes one or more codehashes from a list.
*
* @dev <h4>Postconditions:</h4>
* 1. Codehashes that were previously in the list are removed from the list.
* 2. An `RemovedCodeHashFromList` event is emitted for each codehash that was
* previously on the list.
*
* @param list The storage pointer for the list to remove codehashes from.
* @param listType The type of list the codehashes are being removed from.
* @param id The id of the list the codehashes are being removed from.
* @param codehashes An array of codehashes to remove from the list.
*/
function _removeCodeHashesFromList(
List storage list,
uint8 listType,
uint120 id,
bytes32[] calldata codehashes
) internal onlyListOwner(id) {
bytes32 codehash;
for (uint256 i = 0; i < codehashes.length;) {
codehash = codehashes[i];
if (list.enumerableCodehashes.remove(codehash)) {
emit RemovedCodeHashFromList(listType, id, codehash);
delete list.nonEnumerableCodehashes[codehash];
}
unchecked {
++i;
}
}
}
/**
* @notice Sets the owner of list `id` to `newOwner`.
*
* @dev Throws when the caller is not the owner of the list.
*
* @dev <h4>Postconditions:</h4>
* 1. The owner of list `id` is set to `newOwner`.
* 2. Emits a `ReassignedListOwnership` event.
*
* @param id The id of the list to reassign ownership of.
* @param newOwner The account to assign ownership of the list to.
*/
function _reassignOwnershipOfList(uint120 id, address newOwner) private {
_requireCallerOwnsList(id);
listOwners[id] = newOwner;
emit ReassignedListOwnership(id, newOwner);
}
/**
* @notice Requires the caller to be the owner of list `id`.
*
* @dev Throws when the caller is not the owner of the list.
*
* @param id The id of the list to check ownership of.
*/
function _requireCallerOwnsList(uint120 id) private view {
if (msg.sender != listOwners[id]) {
revert CreatorTokenTransferValidator__CallerDoesNotOwnList();
}
}
/**
* @dev Internal function used to efficiently retrieve the code length of `account`.
*
* @param account The address to get the deployed code length for.
*
* @return length The length of deployed code at the address.
*/
function _getCodeLengthAsm(address account) internal view returns (uint256 length) {
assembly { length := extcodesize(account) }
}
/**
* @dev Internal function used to efficiently retrieve the codehash of `account`.
*
* @param account The address to get the deployed codehash for.
*
* @return codehash The codehash of the deployed code at the address.
*/
function _getCodeHashAsm(address account) internal view returns (bytes32 codehash) {
assembly { codehash := extcodehash(account) }
}
/**
* @dev Hook that is called before any permitted token transfer that goes through Permit-C.
* Applies the collection transfer policy, using the operator that called Permit-C as the caller.
* This allows creator token standard protections to extend to permitted transfers.
*
* @param token The collection address of the token being transferred.
* @param from The address of the token owner.
* @param to The address of the token receiver.
* @param id The token id being transferred.
*/
function _beforeTransferFrom(
uint256 tokenType,
address token,
address from,
address to,
uint256 id,
uint256 /*amount*/
) internal override returns (bool isError) {
(bytes4 selector, uint16 collectionTokenType) = _validateTransfer(_callerAuthorizedCheckToken, token, msg.sender, from, to, id);
if (collectionTokenType == DEFAULT_TOKEN_TYPE || collectionTokenType == tokenType) {
isError = SELECTOR_NO_ERROR != selector;
} else {
revert CreatorTokenTransferValidator__TokenTypesDoNotMatch();
}
}
/**
* @notice Apply the collection transfer policy to a transfer operation of a creator token.
*
* @dev If the caller is self (Permit-C Processor) it means we have already applied operator validation in the
* _beforeTransferFrom callback. In this case, the security policy was already applied and the operator
* that used the Permit-C processor passed the security policy check and transfer can be safely allowed.
*
* @dev The order of checking whitelisted accounts, authorized operator check and whitelisted codehashes
* is very deliberate. The order of operations is determined by the most frequently used settings that are
* expected in the wild.
*
* @dev Throws when the collection has enabled account freezing mode and either the `from` or `to` addresses
* are on the list of frozen accounts for the collection.
* @dev Throws when the collection is set to Level 9 - Soulbound Token.
* @dev Throws when the receiver has deployed code and isn't whitelisted, if ReceiverConstraints.NoCode is set
* and the transfer is not approved by an authorizer for the collection.
* @dev Throws when the receiver has never verified a signature to prove they are an EOA and the receiver
* isn't whitelisted, if the ReceiverConstraints.EOA is set and the transfer is not approved by an
* authorizer for the collection..
* @dev Throws when `msg.sender` is blacklisted, if CallerConstraints.OperatorBlacklistEnableOTC is set, unless
* `msg.sender` is also the `from` address or the transfer is approved by an authorizer for the collection.
* @dev Throws when `msg.sender` isn't whitelisted, if CallerConstraints.OperatorWhitelistEnableOTC is set, unless
* `msg.sender` is also the `from` address or the transfer is approved by an authorizer for the collection.
* @dev Throws when neither `msg.sender` nor `from` are whitelisted, if
* CallerConstraints.OperatorWhitelistDisableOTC is set and the transfer
* is not approved by an authorizer for the collection.
*
* @dev <h4>Postconditions:</h4>
* 1. Transfer is allowed or denied based on the applied transfer policy.
*
* @param collection The collection address of the token being transferred.
* @param caller The address initiating the transfer.
* @param from The address of the token owner.
* @param to The address of the token receiver.
* @param tokenId The token id being transferred.
*
* @return The selector value for an error if the transfer is not allowed, `SELECTOR_NO_ERROR` if the transfer is allowed.
*/
function _validateTransfer(
function(address,address,uint256) internal view returns(bool) _callerAuthorizedParam,
address collection,
address caller,
address from,
address to,
uint256 tokenId
) internal view returns (bytes4,uint16) {
if (caller == address(this)) {
// If the caller is self (Permit-C Processor) it means we have already applied operator validation in the
// _beforeTransferFrom callback. In this case, the security policy was already applied and the operator
// that used the Permit-C processor passed the security policy check and transfer can be safely allowed.
return (SELECTOR_NO_ERROR, DEFAULT_TOKEN_TYPE);
}
CollectionSecurityPolicyV3 storage collectionSecurityPolicy = collectionSecurityPolicies[collection];
uint120 listId = collectionSecurityPolicy.listId;
(uint256 callerConstraints, uint256 receiverConstraints) =
transferSecurityPolicies(collectionSecurityPolicy.transferSecurityLevel);
if (collectionSecurityPolicy.enableAccountFreezingMode) {
AccountList storage frozenAccountList = frozenAccounts[collection];
if (frozenAccountList.nonEnumerableAccounts[from]) {
return (CreatorTokenTransferValidator__SenderAccountIsFrozen.selector, DEFAULT_TOKEN_TYPE);
}
if (frozenAccountList.nonEnumerableAccounts[to]) {
return (CreatorTokenTransferValidator__ReceiverAccountIsFrozen.selector, DEFAULT_TOKEN_TYPE);
}
}
if (callerConstraints == CALLER_CONSTRAINTS_SBT) {
return (CreatorTokenTransferValidator__TokenIsSoulbound.selector, DEFAULT_TOKEN_TYPE);
}
List storage whitelist = whitelists[listId];
if (receiverConstraints == RECEIVER_CONSTRAINTS_NO_CODE) {
if (_getCodeLengthAsm(to) > 0) {
if (!whitelist.nonEnumerableAccounts[to]) {
// Cache _callerAuthorizedParam on stack to avoid stack too deep
function(address,address,uint256) internal view returns(bool) _callerAuthorized = _callerAuthorizedParam;
if(!_callerAuthorized(collection, caller, tokenId)) {
if (!whitelist.nonEnumerableCodehashes[_getCodeHashAsm(to)]) {
return (CreatorTokenTransferValidator__ReceiverMustNotHaveDeployedCode.selector, DEFAULT_TOKEN_TYPE);
}
}
}
}
} else if (receiverConstraints == RECEIVER_CONSTRAINTS_EOA) {
if (!isVerifiedEOA(to)) {
if (!whitelist.nonEnumerableAccounts[to]) {
// Cache _callerAuthorizedParam on stack to avoid stack too deep
function(address,address,uint256) internal view returns(bool) _callerAuthorized = _callerAuthorizedParam;
if(!_callerAuthorized(collection, caller, tokenId)) {
if (!whitelist.nonEnumerableCodehashes[_getCodeHashAsm(to)]) {
return (CreatorTokenTransferValidator__ReceiverProofOfEOASignatureUnverified.selector, DEFAULT_TOKEN_TYPE);
}
}
}
}
}
if (caller == from) {
if (callerConstraints != CALLER_CONSTRAINTS_OPERATOR_WHITELIST_DISABLE_OTC) {
return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType);
}
}
if (callerConstraints == CALLER_CONSTRAINTS_OPERATOR_BLACKLIST_ENABLE_OTC) {
// Cache _callerAuthorizedParam on stack to avoid stack too deep
function(address,address,uint256) internal view returns(bool) _callerAuthorized = _callerAuthorizedParam;
if(_callerAuthorized(collection, caller, tokenId)) {
return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType);
}
List storage blacklist = blacklists[listId];
if (blacklist.nonEnumerableAccounts[caller]) {
return (CreatorTokenTransferValidator__OperatorIsBlacklisted.selector, DEFAULT_TOKEN_TYPE);
}
if (blacklist.nonEnumerableCodehashes[_getCodeHashAsm(caller)]) {
return (CreatorTokenTransferValidator__OperatorIsBlacklisted.selector, DEFAULT_TOKEN_TYPE);
}
} else if (callerConstraints == CALLER_CONSTRAINTS_OPERATOR_WHITELIST_ENABLE_OTC) {
if (whitelist.nonEnumerableAccounts[caller]) {
return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType);
}
// Cache _callerAuthorizedParam on stack to avoid stack too deep
function(address,address,uint256) internal view returns(bool) _callerAuthorized = _callerAuthorizedParam;
if( _callerAuthorized(collection, caller, tokenId)) {
return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType);
}
if (whitelist.nonEnumerableCodehashes[_getCodeHashAsm(caller)]) {
return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType);
}
return (CreatorTokenTransferValidator__CallerMustBeWhitelisted.selector, DEFAULT_TOKEN_TYPE);
} else if (callerConstraints == CALLER_CONSTRAINTS_OPERATOR_WHITELIST_DISABLE_OTC) {
mapping(address => bool) storage accountWhitelist = whitelist.nonEnumerableAccounts;
if (accountWhitelist[caller]) {
return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType);
}
if (accountWhitelist[from]) {
return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType);
}
// Cache _callerAuthorizedParam on stack to avoid stack too deep
function(address,address,uint256) internal view returns(bool) _callerAuthorized = _callerAuthorizedParam;
if(_callerAuthorized(collection, caller, tokenId)) {
return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType);
}
mapping(bytes32 => bool) storage codehashWhitelist = whitelist.nonEnumerableCodehashes;
// Cache caller on stack to avoid stack too deep
address tmpAddress = caller;
if (codehashWhitelist[_getCodeHashAsm(tmpAddress)]) {
return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType);
}
// Cache from on stack to avoid stack too deep
tmpAddress = from;
if (codehashWhitelist[_getCodeHashAsm(tmpAddress)]) {
return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType);
}
return (CreatorTokenTransferValidator__CallerMustBeWhitelisted.selector, DEFAULT_TOKEN_TYPE);
}
return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType);
}
/**
* @dev Internal function used to efficiently revert with a custom error selector.
*
* @param errorSelector The error selector to revert with.
*/
function _revertCustomErrorSelectorAsm(bytes4 errorSelector) internal pure {
assembly {
mstore(0x00, errorSelector)
revert(0x00, 0x04)
}
}
/**
* @dev Internal function used to check if authorization mode can be activated for a transfer.
*
* @dev Throws when the collection has not enabled authorization mode.
* @dev Throws when the wildcard operator is being set for a collection that does not
* allow wildcard operators.
* @dev Throws when the authorizer is not in the list of approved authorizers for
* the collection.
*
* @param collection The collection address to activate authorization mode for a transfer.
* @param operator The operator specified by the authorizer to allow transfers.
* @param authorizer The address of the authorizer making the call.
*/
function _checkCollectionAllowsAuthorizerAndOperator(
address collection,
address operator,
address authorizer
) internal view {
CollectionSecurityPolicyV3 storage collectionSecurityPolicy = collectionSecurityPolicies[collection];
if (collectionSecurityPolicy.disableAuthorizationMode) {
revert CreatorTokenTransferValidator__AuthorizationDisabledForCollection();
}
if (collectionSecurityPolicy.authorizersCannotSetWildcardOperators) {
if (operator == WILDCARD_OPERATOR_ADDRESS) {
revert CreatorTokenTransferValidator__WildcardOperatorsCannotBeAuthorizedForCollection();
}
}
if (!authorizers[collectionSecurityPolicy.listId].nonEnumerableAccounts[authorizer]) {
revert CreatorTokenTransferValidator__CallerMustBeAnAuthorizer();
}
}
/**
* @dev Modifier to apply the allowed authorizer and operator for collection checks.
*
* @dev Throws when the collection has not enabled authorization mode.
* @dev Throws when the wildcard operator is being set for a collection that does not
* allow wildcard operators.
* @dev Throws when the authorizer is not in the list of approved authorizers for
* the collection.
*
* @param collection The collection address to activate authorization mode for a transfer.
* @param operator The operator specified by the authorizer to allow transfers.
* @param authorizer The address of the authorizer making the call.
*/
modifier whenAuthorizerAndOperatorEnabledForCollection(
address collection,
address operator,
address authorizer
) {
_checkCollectionAllowsAuthorizerAndOperator(collection, operator, authorizer);
_;
}
/**
* @dev Internal function for setting the authorized operator in storage for a token and collection.
*
* @param operator The allowed operator for an authorized transfer.
* @param collection The address of the collection that the operator is authorized for.
* @param tokenId The id of the token that is authorized.
* @param allowAnyTokenId Flag if the authorizer is enabling transfers for any token id
*/
function _setOperatorInTransientStorage(
address operator,
address collection,
uint256 tokenId,
bool allowAnyTokenId
) internal whenAuthorizerAndOperatorEnabledForCollection(collection, operator, msg.sender) {
_setTstorish(_getTransientOperatorSlot(collection), (allowAnyTokenId ? 1 << 255 : 0) | uint256(uint160(operator)));
_setTstorish(_getTransientOperatorSlot(collection, tokenId), uint256(uint160(operator)));
}
/**
* @dev Internal function to check if a caller is an authorized operator for the token being transferred.
*
* @param caller The caller of the token transfer.
* @param collection The collection address of the token being transferred.
* @param tokenId The id of the token being transferred.
*
* @return isAuthorized True if the caller is authorized to transfer the token, false otherwise.
*/
function _callerAuthorizedCheckToken(
address collection,
address caller,
uint256 tokenId
) internal view returns (bool isAuthorized) {
uint256 slotValue;
(isAuthorized, ) = _callerAuthorized(caller, _getTransientOperatorSlot(collection, tokenId));
if (isAuthorized) return true;
(isAuthorized, slotValue) = _callerAuthorized(caller, _getTransientOperatorSlot(collection));
isAuthorized = isAuthorized && slotValue >> 255 == 1;
}
/**
* @dev Internal function to check if a caller is an authorized operator for the collection being transferred.
*
* @param caller The caller of the token transfer.
* @param collection The collection address of the token being transferred.
*
* @return isAuthorized True if the caller is authorized to transfer the collection, false otherwise.
*/
function _callerAuthorizedCheckCollection(
address collection,
address caller,
uint256 /*tokenId*/
) internal view returns (bool isAuthorized) {
(isAuthorized, ) = _callerAuthorized(caller, _getTransientOperatorSlot(collection));
}
/**
* @dev Internal function to check if a caller is an authorized operator.
* @dev This overload of `_callerAuthorized` checks a specific storage slot for the caller address.
*
* @param caller The caller of the token transfer.
* @param slot The storage slot to check for the caller address.
*
* @return isAuthorized True if the caller is authorized to transfer the token, false otherwise.
* @return slotValue The transient storage value in `slot`, used to check for allow any token id flag if necessary.
*/
function _callerAuthorized(address caller, uint256 slot) internal view returns (bool isAuthorized, uint256 slotValue) {
slotValue = _getTstorish(slot);
address authorizedOperator = address(uint160(slotValue));
isAuthorized = authorizedOperator == WILDCARD_OPERATOR_ADDRESS || authorizedOperator == caller;
}
/**
* @dev Internal function used to compute the transient storage slot for the authorized
* operator of a token in a collection.
*
* @param collection The collection address of the token being transferred.
* @param tokenId The id of the token being transferred.
*
* @return operatorSlot The storage slot location for the authorized operator value.
*/
function _getTransientOperatorSlot(
address collection,
uint256 tokenId
) internal pure returns (uint256 operatorSlot) {
assembly {
mstore(0x00, collection)
mstore(0x20, tokenId)
operatorSlot := shr(4, keccak256(0x00, 0x40))
}
}
/**
* @dev Internal function used to compute the transient storage slot for the authorized operator of a collection.
*
* @param collection The collection address of the token being transferred.
*
* @return operatorSlot The storage slot location for the authorized operator value.
*/
function _getTransientOperatorSlot(address collection) internal pure returns (uint256 operatorSlot) {
return uint256(uint160(collection));
}
/**
* @dev A gas efficient, and fallback-safe way to call the owner function on a token contract.
* This will get the owner if it exists - and when the function is unimplemented, the
* presence of a fallback function will not result in halted execution.
*
* @param tokenAddress The address of the token collection to get the owner of.
*
* @return owner The owner of the token collection contract.
* @return isError True if there was an error in retrieving the owner, false if the call was successful.
*/
function _safeOwner(
address tokenAddress
) internal view returns(address owner, bool isError) {
assembly {
function _callOwner(_tokenAddress) -> _owner, _isError {
mstore(0x00, 0x8da5cb5b)
if and(iszero(lt(returndatasize(), 0x20)), staticcall(gas(), _tokenAddress, 0x1C, 0x04, 0x00, 0x20)) {
_owner := mload(0x00)
leave
}
_isError := true
}
owner, isError := _callOwner(tokenAddress)
}
}
/**
* @dev A gas efficient, and fallback-safe way to call the hasRole function on a token contract.
* This will check if the account `hasRole` if `hasRole` exists - and when the function is unimplemented, the
* presence of a fallback function will not result in halted execution.
*
* @param tokenAddress The address of the token collection to call hasRole on.
* @param role The role to check if the account has on the collection.
* @param account The address of the account to check if they have a specified role.
*
* @return hasRole The owner of the token collection contract.
* @return isError True if there was an error in retrieving the owner, false if the call was successful.
*/
function _safeHasRole(
address tokenAddress,
bytes32 role,
address account
) internal view returns(bool hasRole, bool isError) {
assembly {
function _callHasRole(_tokenAddress, _role, _account) -> _hasRole, _isError {
let ptr := mload(0x40)
mstore(0x40, add(ptr, 0x60))
mstore(ptr, 0x91d14854)
mstore(add(0x20, ptr), _role)
mstore(add(0x40, ptr), _account)
if and(iszero(lt(returndatasize(), 0x20)), staticcall(gas(), _tokenAddress, add(ptr, 0x1C), 0x44, 0x00, 0x20)) {
_hasRole := mload(0x00)
leave
}
_isError := true
}
hasRole, isError := _callHasRole(tokenAddress, role, account)
}
}
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /** * @dev Constant definitions for receiver constraints used by the transfer validator. */ /// @dev No constraints on the receiver of a token. uint256 constant RECEIVER_CONSTRAINTS_NONE = 0; /// @dev Token receiver cannot have deployed code. uint256 constant RECEIVER_CONSTRAINTS_NO_CODE = 1; /// @dev Token receiver must be a verified EOA with the EOA Registry. uint256 constant RECEIVER_CONSTRAINTS_EOA = 2; /// @dev Token is a soulbound token and cannot be transferred. uint256 constant RECEIVER_CONSTRAINTS_SBT = 3; /** * @dev Constant definitions for caller constraints used by the transfer validator. */ /// @dev No constraints on the caller of a token transfer. uint256 constant CALLER_CONSTRAINTS_NONE = 0; /// @dev Caller of a token transfer must not be on the blacklist unless it is an OTC transfer. uint256 constant CALLER_CONSTRAINTS_OPERATOR_BLACKLIST_ENABLE_OTC = 1; /// @dev Caller of a token transfer must be on the whitelist unless it is an OTC transfer. uint256 constant CALLER_CONSTRAINTS_OPERATOR_WHITELIST_ENABLE_OTC = 2; /// @dev Caller of a token transfer must be on the whitelist. uint256 constant CALLER_CONSTRAINTS_OPERATOR_WHITELIST_DISABLE_OTC = 3; /// @dev Token is a soulbound token and cannot be transferred. uint256 constant CALLER_CONSTRAINTS_SBT = 4; /** * @dev Constant definitions for transfer security levels used by the transfer validator * to define what receiver and caller constraints are applied to a transfer. */ /// @dev Recommend Security Level - /// Caller Constraints: Operator Whitelist /// Receiver Constraints: None /// OTC: Allowed uint8 constant TRANSFER_SECURITY_LEVEL_RECOMMENDED = 0; /// @dev Security Level One - /// Caller Constraints: None /// Receiver Constraints: None /// OTC: Allowed uint8 constant TRANSFER_SECURITY_LEVEL_ONE = 1; /// @dev Security Level Two - /// Caller Constraints: Operator Blacklist /// Receiver Constraints: None /// OTC: Allowed uint8 constant TRANSFER_SECURITY_LEVEL_TWO = 2; /// @dev Security Level Three - /// Caller Constraints: Operator Whitelist /// Receiver Constraints: None /// OTC: Allowed uint8 constant TRANSFER_SECURITY_LEVEL_THREE = 3; /// @dev Security Level Four - /// Caller Constraints: Operator Whitelist /// Receiver Constraints: None /// OTC: Not Allowed uint8 constant TRANSFER_SECURITY_LEVEL_FOUR = 4; /// @dev Security Level Five - /// Caller Constraints: Operator Whitelist /// Receiver Constraints: No Code /// OTC: Allowed uint8 constant TRANSFER_SECURITY_LEVEL_FIVE = 5; /// @dev Security Level Six - /// Caller Constraints: Operator Whitelist /// Receiver Constraints: Verified EOA /// OTC: Allowed uint8 constant TRANSFER_SECURITY_LEVEL_SIX = 6; /// @dev Security Level Seven - /// Caller Constraints: Operator Whitelist /// Receiver Constraints: No Code /// OTC: Not Allowed uint8 constant TRANSFER_SECURITY_LEVEL_SEVEN = 7; /// @dev Security Level Eight - /// Caller Constraints: Operator Whitelist /// Receiver Constraints: Verified EOA /// OTC: Not Allowed uint8 constant TRANSFER_SECURITY_LEVEL_EIGHT = 8; /// @dev Security Level Nine - /// Soulbound Token, No Transfers Allowed uint8 constant TRANSFER_SECURITY_LEVEL_NINE = 9; /// @dev List type is a blacklist. uint8 constant LIST_TYPE_BLACKLIST = 0; /// @dev List type is a whitelist. uint8 constant LIST_TYPE_WHITELIST = 1; /// @dev List type is authorizers. uint8 constant LIST_TYPE_AUTHORIZERS = 2; /// @dev Constant value for the no error selector. bytes4 constant SELECTOR_NO_ERROR = bytes4(0x00000000);
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
interface IEOARegistry is IERC165 {
function isVerifiedEOA(address account) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
interface ITransferValidator {
function applyCollectionTransferPolicy(address caller, address from, address to) external view;
function validateTransfer(address caller, address from, address to) external view;
function validateTransfer(address caller, address from, address to, uint256 tokenId) external view;
function validateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount) external;
function beforeAuthorizedTransfer(address operator, address token, uint256 tokenId) external;
function afterAuthorizedTransfer(address token, uint256 tokenId) external;
function beforeAuthorizedTransfer(address operator, address token) external;
function afterAuthorizedTransfer(address token) external;
function beforeAuthorizedTransfer(address token, uint256 tokenId) external;
function beforeAuthorizedTransferWithAmount(address token, uint256 tokenId, uint256 amount) external;
function afterAuthorizedTransferWithAmount(address token, uint256 tokenId) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/**
* @dev Defines constraints for staking tokens in token wrapper contracts.
*/
enum StakerConstraints {
// 0: No constraints applied to staker.
None,
// 1: Transaction originator must be the address that will receive the wrapped tokens.
CallerIsTxOrigin,
// 2: Address that will receive the wrapped tokens must be a verified EOA.
EOA
}
/**
* @dev Defines the security policy for a token collection in Creator Token Standards V2.
*
* @dev **transferSecurityLevel**: The transfer security level set for the collection.
* @dev **listId**: The list id that contains the blacklist and whitelist to apply to the collection.
* @dev **enableGraylisting**: If true, graylisting will be enabled for the collection.
*/
struct CollectionSecurityPolicyV3 {
bool disableAuthorizationMode;
bool authorizersCannotSetWildcardOperators;
uint8 transferSecurityLevel;
uint120 listId;
bool enableAccountFreezingMode;
uint16 tokenType;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/access/Ownable.sol";
contract CreatorTokenTransferValidatorConfiguration is Ownable {
error CreatorTokenTransferValidatorConfiguration__ConfigurationNotInitialized();
bool configurationInitialized;
uint256 private nativeValueToCheckPauseState;
constructor(address defaultOwner) {
_transferOwnership(defaultOwner);
}
function setNativeValueToCheckPauseState(uint256 _nativeValueToCheckPauseState) external onlyOwner {
nativeValueToCheckPauseState = _nativeValueToCheckPauseState;
configurationInitialized = true;
}
function getNativeValueToCheckPauseState() external view returns(uint256 _nativeValueToCheckPauseState) {
if (!configurationInitialized) {
revert CreatorTokenTransferValidatorConfiguration__ConfigurationNotInitialized();
}
_nativeValueToCheckPauseState = nativeValueToCheckPauseState;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "./Errors.sol";
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
import {IERC721} from "@openzeppelin/contracts/interfaces/IERC721.sol";
import {IERC1155} from "@openzeppelin/contracts/interfaces/IERC1155.sol";
import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol";
import {Ownable} from "./openzeppelin-optimized/Ownable.sol";
import {EIP712} from "./openzeppelin-optimized/EIP712.sol";
import {
ZERO_BYTES32,
ZERO,
ONE,
ORDER_STATE_OPEN,
ORDER_STATE_FILLED,
ORDER_STATE_CANCELLED,
SINGLE_USE_PERMIT_TRANSFER_ADVANCED_TYPEHASH_STUB,
PERMIT_ORDER_ADVANCED_TYPEHASH_STUB,
UPPER_BIT_MASK,
TOKEN_TYPE_ERC1155,
TOKEN_TYPE_ERC20,
TOKEN_TYPE_ERC721,
PAUSABLE_APPROVAL_TRANSFER_FROM_ERC721,
PAUSABLE_APPROVAL_TRANSFER_FROM_ERC1155,
PAUSABLE_APPROVAL_TRANSFER_FROM_ERC20,
PAUSABLE_PERMITTED_TRANSFER_FROM_ERC721,
PAUSABLE_PERMITTED_TRANSFER_FROM_ERC1155,
PAUSABLE_PERMITTED_TRANSFER_FROM_ERC20,
PAUSABLE_ORDER_TRANSFER_FROM_ERC1155,
PAUSABLE_ORDER_TRANSFER_FROM_ERC20
} from "./Constants.sol";
import {PackedApproval, OrderFillAmounts} from "./DataTypes.sol";
import {PermitHash} from './libraries/PermitHash.sol';
import {IPermitC} from './interfaces/IPermitC.sol';
import {CollateralizedPausableFlags} from './CollateralizedPausableFlags.sol';
/*
@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@(
@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@
#@@@@@@@@@@@@@@
@@@@@@@@@@@@
@@@@@@@@@@@@@@* @@@@@@@@@@@@
@@@@@@@@@@@@@@@ @ @@@@@@@@@@@@
@@@@@@@@@@@@@@@ @ @@@@@@@@@@@
@@@@@@@@@@@@@@@ @@ @@@@@@@@@@@@
@@@@@@@@@@@@@@@ #@@ @@@@@@@@@@@@/
@@@@@@@@@@@@@@. @@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@&%%%%%%%%&&@@@@@@@@@@@@@@
@@@@@@@@@@@@@@ @@@@@ @@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@ @@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@ @@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@@ @@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@@ @@@@@@@@@@@&
@@@@@@@@@@@@@@ *@@@@@@@ (@@@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@@@ @@@@@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
.@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@% @@@@@@@@@@@@@@@@@@@@@@@@(
@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
* @title PermitC
* @custom:version 1.0.0
* @author Limit Break, Inc.
* @description Advanced approval management for ERC20, ERC721 and ERC1155 tokens
* allowing for single use permit transfers, time-bound approvals
* and order ID based transfers.
*/
contract PermitC is Ownable, CollateralizedPausableFlags, EIP712, IPermitC {
/**
* @notice Map of approval details for the provided bytes32 hash to allow for multiple accessors
*
* @dev keccak256(abi.encode(owner, tokenType, token, id, orderId, masterNonce)) =>
* @dev operator => (state, amount, expiration)
* @dev Utilized for stored approvals by an owner's direct call to `approve` and
* @dev approvals by signature in `updateApprovalBySignature`. Both methods use a
* @dev bytes32(0) value for the `orderId`.
*/
mapping(bytes32 => mapping(address => PackedApproval)) private _transferApprovals;
/**
* @notice Map of approval details for the provided bytes32 hash to allow for multiple accessors
*
* @dev keccak256(abi.encode(owner, tokenType, token, id, orderId, masterNonce)) =>
* @dev operator => (state, amount, expiration)
* @dev Utilized for order approvals by `fillPermittedOrderERC20` and `fillPermittedOrderERC1155`
* @dev with the `orderId` provided by the sender.
*/
mapping(bytes32 => mapping(address => PackedApproval)) private _orderApprovals;
/**
* @notice Map of registered additional data hashes for transfer permits.
*
* @dev This is used to prevent someone from providing an invalid EIP712 envelope label
* @dev and tricking a user into signing a different message than they expect.
*/
mapping(bytes32 => bool) private _registeredTransferHashes;
/**
* @notice Map of registered additional data hashes for order permits.
*
* @dev This is used to prevent someone from providing an invalid EIP712 envelope label
* @dev and tricking a user into signing a different message than they expect.
*/
mapping(bytes32 => bool) private _registeredOrderHashes;
/// @dev Map of an address to a bitmap (slot => status)
mapping(address => mapping(uint256 => uint256)) private _unorderedNonces;
/**
* @notice Master nonce used to invalidate all outstanding approvals for an owner
*
* @dev owner => masterNonce
* @dev This is incremented when the owner calls lockdown()
*/
mapping(address => uint256) private _masterNonces;
constructor(
string memory name,
string memory version,
address _defaultContractOwner,
uint256 _nativeValueToCheckPauseState
) CollateralizedPausableFlags(_nativeValueToCheckPauseState) EIP712(name, version) {
_transferOwnership(_defaultContractOwner);
}
/**
* =================================================
* ================= Modifiers =====================
* =================================================
*/
modifier onlyRegisteredTransferAdvancedTypeHash(bytes32 advancedPermitHash) {
_requireTransferAdvancedPermitHashIsRegistered(advancedPermitHash);
_;
}
modifier onlyRegisteredOrderAdvancedTypeHash(bytes32 advancedPermitHash) {
_requireOrderAdvancedPermitHashIsRegistered(advancedPermitHash);
_;
}
/**
* =================================================
* ============== Approval Transfers ===============
* =================================================
*/
/**
* @notice Approve an operator to spend a specific token / ID combination
* @notice This function is compatible with ERC20, ERC721 and ERC1155
* @notice To give unlimited approval for ERC20 and ERC1155, set amount to type(uint200).max
* @notice When approving an ERC721, you MUST set amount to `1`
* @notice When approving an ERC20, you MUST set id to `0`
*
* @dev <h4>Postconditions:</h4>
* @dev 1. Updates the approval for an operator to use an amount of a specific token / ID combination
* @dev 2. If the expiration is 0, the approval is valid only in the context of the current block
* @dev 3. If the expiration is not 0, the approval is valid until the expiration timestamp
* @dev 4. If the provided amount is type(uint200).max, the approval is unlimited
*
* @param tokenType The type of token being approved - must be 20, 721 or 1155.
* @param token The address of the token contract
* @param id The token ID
* @param operator The address of the operator
* @param amount The amount of tokens to approve
* @param expiration The expiration timestamp of the approval
*/
function approve(
uint256 tokenType,
address token,
uint256 id,
address operator,
uint200 amount,
uint48 expiration
) external {
_requireValidTokenType(tokenType);
_storeApproval(tokenType, token, id, amount, expiration, msg.sender, operator);
}
/**
* @notice Use a signed permit to increase the allowance for a provided operator
* @notice This function is compatible with ERC20, ERC721 and ERC1155
* @notice To give unlimited approval for ERC20 and ERC1155, set amount to type(uint200).max
* @notice When approving an ERC721, you MUST set amount to `1`
* @notice When approving an ERC20, you MUST set id to `0`
* @notice An `approvalExpiration` of zero is considered an atomic permit which will use the
* @notice current block time as the expiration time when storing the permit data.
*
* @dev - Throws if the permit has expired
* @dev - Throws if the permit's nonce has already been used
* @dev - Throws if the permit signature is does not recover to the provided owner
*
* @dev <h4>Postconditions:</h4>
* @dev 1. Updates the approval for an operator to use an amount of a specific token / ID combination
* @dev 3. Sets the expiration of the approval to the expiration timestamp of the permit
* @dev 4. If the provided amount is type(uint200).max, the approval is unlimited
*
* @param tokenType The type of token being approved - must be 20, 721 or 1155.
* @param token Address of the token to approve
* @param id The token ID
* @param nonce The nonce of the permit
* @param amount The amount of tokens to approve
* @param operator The address of the operator
* @param approvalExpiration The expiration timestamp of the approval
* @param sigDeadline The deadline timestamp for the permit signature
* @param owner The owner of the tokens
* @param signedPermit The permit signature, signed by the owner
*/
function updateApprovalBySignature(
uint256 tokenType,
address token,
uint256 id,
uint256 nonce,
uint200 amount,
address operator,
uint48 approvalExpiration,
uint48 sigDeadline,
address owner,
bytes calldata signedPermit
) external {
if (block.timestamp > sigDeadline) {
revert PermitC__ApprovalTransferPermitExpiredOrUnset();
}
_requireValidTokenType(tokenType);
_checkAndInvalidateNonce(owner, nonce);
_verifyPermitSignature(
_hashTypedDataV4(
PermitHash.hashOnChainApproval(
tokenType,
token,
id,
amount,
nonce,
operator,
approvalExpiration,
sigDeadline,
_masterNonces[owner]
)
),
signedPermit,
owner
);
// Expiration of zero is considered an atomic permit which is only valid in the
// current block.
approvalExpiration = approvalExpiration == 0 ? uint48(block.timestamp) : approvalExpiration;
_storeApproval(tokenType, token, id, amount, approvalExpiration, owner, operator);
}
/**
* @notice Returns the amount of allowance an operator has and it's expiration for a specific token and id
* @notice If the expiration on the allowance has expired, returns 0
* @notice To retrieve allowance for ERC20, set id to `0`
*
* @param owner The owner of the token
* @param operator The operator of the token
* @param tokenType The type of token the allowance is for
* @param token The address of the token contract
* @param id The token ID
*
* @return allowedAmount The amount of allowance the operator has
* @return expiration The expiration timestamp of the allowance
*/
function allowance(
address owner,
address operator,
uint256 tokenType,
address token,
uint256 id
) external view returns (uint256 allowedAmount, uint256 expiration) {
return _allowance(_transferApprovals, owner, operator, tokenType, token, id, ZERO_BYTES32);
}
/**
* =================================================
* ================ Signed Transfers ===============
* =================================================
*/
/**
* @notice Registers the combination of a provided string with the `SINGLE_USE_PERMIT_TRANSFER_ADVANCED_TYPEHASH_STUB`
* @notice and `PERMIT_ORDER_ADVANCED_TYPEHASH_STUB` to create valid additional data hashes
*
* @dev This function prevents malicious actors from changing the label of the EIP712 hash
* @dev to a value that would fool an external user into signing a different message.
*
* @dev <h4>Postconditions:</h4>
* @dev 1. The provided string is combined with the `SINGLE_USE_PERMIT_TRANSFER_ADVANCED_TYPEHASH_STUB` string
* @dev 2. The combined string is hashed using keccak256
* @dev 3. The resulting hash is added to the `_registeredTransferHashes` mapping
* @dev 4. The provided string is combined with the `PERMIT_ORDER_ADVANCED_TYPEHASH_STUB` string
* @dev 5. The combined string is hashed using keccak256
* @dev 6. The resulting hash is added to the `_registeredOrderHashes` mapping
*
* @param additionalDataTypeString The string to register as a valid additional data hash
*/
function registerAdditionalDataHash(string calldata additionalDataTypeString) external {
_registeredTransferHashes[
keccak256(
bytes(
string.concat(
SINGLE_USE_PERMIT_TRANSFER_ADVANCED_TYPEHASH_STUB,
additionalDataTypeString
)
)
)
] = true;
_registeredOrderHashes[
keccak256(
bytes(
string.concat(
PERMIT_ORDER_ADVANCED_TYPEHASH_STUB,
additionalDataTypeString
)
)
)
] = true;
}
/**
* @notice Transfer an ERC721 token from the owner to the recipient using a permit signature.
*
* @dev Be advised that the permitted amount for ERC721 is always inferred to be 1, so signed permitted amount
* @dev MUST always be set to 1.
*
* @dev - Throws if the permit is expired
* @dev - Throws if the nonce has already been used
* @dev - Throws if the permit is not signed by the owner
* @dev - Throws if the requested amount exceeds the permitted amount
* @dev - Throws if the provided token address does not implement ERC721 transferFrom function
* @dev - Returns `false` if the transfer fails
*
* @dev <h4>Postconditions:</h4>
* @dev 1. Transfers the token from the owner to the recipient
* @dev 2. The nonce of the permit is marked as used
* @dev 3. Performs any additional checks in the before and after hooks
*
* @param token The address of the token
* @param id The ID of the token
* @param nonce The nonce of the permit
* @param expiration The expiration timestamp of the permit
* @param owner The owner of the token
* @param to The address to transfer the tokens to
* @param signedPermit The permit signature, signed by the owner
*
* @return isError True if the transfer failed, false otherwise
*/
function permitTransferFromERC721(
address token,
uint256 id,
uint256 nonce,
uint256 expiration,
address owner,
address to,
bytes calldata signedPermit
) external returns (bool isError) {
_requireNotPaused(PAUSABLE_PERMITTED_TRANSFER_FROM_ERC721);
_checkPermitApproval(TOKEN_TYPE_ERC721, token, id, ONE, nonce, expiration, owner, ONE, signedPermit);
isError = _transferFromERC721(owner, to, token, id);
if (isError) {
_restoreNonce(owner, nonce);
}
}
/**
* @notice Transfers an ERC721 token from the owner to the recipient using a permit signature
* @notice This function includes additional data to verify on the signature, allowing
* @notice protocols to extend the validation in one function call. NOTE: before calling this
* @notice function you MUST register the stub end of the additional data typestring using
* @notice the `registerAdditionalDataHash` function.
*
* @dev Be advised that the permitted amount for ERC721 is always inferred to be 1, so signed permitted amount
* @dev MUST always be set to 1.
*
* @dev - Throws for any reason permitTransferFromERC721 would.
* @dev - Throws if the additional data does not match the signature
* @dev - Throws if the provided hash has not been registered as a valid additional data hash
* @dev - Throws if the provided hash does not match the provided additional data
*
* @dev <h4>Postconditions:</h4>
* @dev 1. Transfers the token from the owner to the recipient
* @dev 2. Performs any additional checks in the before and after hooks
* @dev 3. The nonce of the permit is marked as used
*
* @param token The address of the token
* @param id The ID of the token
* @param nonce The nonce of the permit
* @param expiration The expiration timestamp of the permit
* @param owner The owner of the token
* @param to The address to transfer the tokens to
* @param additionalData The additional data to verify on the signature
* @param advancedPermitHash The hash of the additional data
* @param signedPermit The permit signature, signed by the owner
*
* @return isError True if the transfer failed, false otherwise
*/
function permitTransferFromWithAdditionalDataERC721(
address token,
uint256 id,
uint256 nonce,
uint256 expiration,
address owner,
address to,
bytes32 additionalData,
bytes32 advancedPermitHash,
bytes calldata signedPermit
) external onlyRegisteredTransferAdvancedTypeHash(advancedPermitHash) returns (bool isError) {
_requireNotPaused(PAUSABLE_PERMITTED_TRANSFER_FROM_ERC721);
_checkPermitApprovalWithAdditionalDataERC721(
token,
id,
ONE,
nonce,
expiration,
owner,
ONE,
signedPermit,
additionalData,
advancedPermitHash
);
isError = _transferFromERC721(owner, to, token, id);
if (isError) {
_restoreNonce(owner, nonce);
}
}
/**
* @notice Transfer an ERC1155 token from the owner to the recipient using a permit signature
*
* @dev - Throws if the permit is expired
* @dev - Throws if the nonce has already been used
* @dev - Throws if the permit is not signed by the owner
* @dev - Throws if the requested amount exceeds the permitted amount
* @dev - Throws if the provided token address does not implement ERC1155 safeTransferFrom function
* @dev - Returns `false` if the transfer fails
*
* @dev <h4>Postconditions:</h4>
* @dev 1. Transfers the token (in the requested amount) from the owner to the recipient
* @dev 2. The nonce of the permit is marked as used
* @dev 3. Performs any additional checks in the before and after hooks
*
* @param token The address of the token
* @param id The ID of the token
* @param nonce The nonce of the permit
* @param permitAmount The amount of tokens permitted by the owner
* @param expiration The expiration timestamp of the permit
* @param owner The owner of the token
* @param to The address to transfer the tokens to
* @param transferAmount The amount of tokens to transfer
* @param signedPermit The permit signature, signed by the owner
*
* @return isError True if the transfer failed, false otherwise
*/
function permitTransferFromERC1155(
address token,
uint256 id,
uint256 nonce,
uint256 permitAmount,
uint256 expiration,
address owner,
address to,
uint256 transferAmount,
bytes calldata signedPermit
) external returns (bool isError) {
_requireNotPaused(PAUSABLE_PERMITTED_TRANSFER_FROM_ERC1155);
_checkPermitApproval(TOKEN_TYPE_ERC1155, token, id, permitAmount, nonce, expiration, owner, transferAmount, signedPermit);
isError = _transferFromERC1155(token, owner, to, id, transferAmount);
if (isError) {
_restoreNonce(owner, nonce);
}
}
/**
* @notice Transfers a token from the owner to the recipient using a permit signature
* @notice This function includes additional data to verify on the signature, allowing
* @notice protocols to extend the validation in one function call. NOTE: before calling this
* @notice function you MUST register the stub end of the additional data typestring using
* @notice the `registerAdditionalDataHash` function.
*
* @dev - Throws for any reason permitTransferFrom would.
* @dev - Throws if the additional data does not match the signature
* @dev - Throws if the provided hash has not been registered as a valid additional data hash
* @dev - Throws if the provided hash does not match the provided additional data
* @dev - Throws if the provided hash has not been registered as a valid additional data hash
* @dev - Returns `false` if the transfer fails
*
* @dev <h4>Postconditions:</h4>
* @dev 1. Transfers the token (in the requested amount) from the owner to the recipient
* @dev 2. Performs any additional checks in the before and after hooks
* @dev 3. The nonce of the permit is marked as used
*
* @param token The address of the token
* @param id The ID of the token
* @param nonce The nonce of the permit
* @param permitAmount The amount of tokens permitted by the owner
* @param expiration The expiration timestamp of the permit
* @param owner The owner of the token
* @param to The address to transfer the tokens to
* @param transferAmount The amount of tokens to transfer
* @param additionalData The additional data to verify on the signature
* @param advancedPermitHash The hash of the additional data
* @param signedPermit The permit signature, signed by the owner
*
* @return isError True if the transfer failed, false otherwise
*/
function permitTransferFromWithAdditionalDataERC1155(
address token,
uint256 id,
uint256 nonce,
uint256 permitAmount,
uint256 expiration,
address owner,
address to,
uint256 transferAmount,
bytes32 additionalData,
bytes32 advancedPermitHash,
bytes calldata signedPermit
) external onlyRegisteredTransferAdvancedTypeHash(advancedPermitHash) returns (bool isError) {
_requireNotPaused(PAUSABLE_PERMITTED_TRANSFER_FROM_ERC1155);
_checkPermitApprovalWithAdditionalDataERC1155(
token,
id,
permitAmount,
nonce,
expiration,
owner,
transferAmount,
signedPermit,
additionalData,
advancedPermitHash
);
// copy id to top of stack to avoid stack too deep
uint256 tmpId = id;
isError = _transferFromERC1155(token, owner, to, tmpId, transferAmount);
if (isError) {
_restoreNonce(owner, nonce);
}
}
/**
* @notice Transfer an ERC20 token from the owner to the recipient using a permit signature.
*
* @dev Be advised that the token ID for ERC20 is always inferred to be 0, so signed token ID
* @dev MUST always be set to 0.
*
* @dev - Throws if the permit is expired
* @dev - Throws if the nonce has already been used
* @dev - Throws if the permit is not signed by the owner
* @dev - Throws if the requested amount exceeds the permitted amount
* @dev - Throws if the provided token address does not implement ERC20 transferFrom function
* @dev - Returns `false` if the transfer fails
*
* @dev <h4>Postconditions:</h4>
* @dev 1. Transfers the token in the requested amount from the owner to the recipient
* @dev 2. The nonce of the permit is marked as used
* @dev 3. Performs any additional checks in the before and after hooks
*
* @param token The address of the token
* @param nonce The nonce of the permit
* @param permitAmount The amount of tokens permitted by the owner
* @param expiration The expiration timestamp of the permit
* @param owner The owner of the token
* @param to The address to transfer the tokens to
* @param signedPermit The permit signature, signed by the owner
*
* @return isError True if the transfer failed, false otherwise
*/
function permitTransferFromERC20(
address token,
uint256 nonce,
uint256 permitAmount,
uint256 expiration,
address owner,
address to,
uint256 transferAmount,
bytes calldata signedPermit
) external returns (bool isError) {
_requireNotPaused(PAUSABLE_PERMITTED_TRANSFER_FROM_ERC20);
_checkPermitApproval(TOKEN_TYPE_ERC20, token, ZERO, permitAmount, nonce, expiration, owner, transferAmount, signedPermit);
isError = _transferFromERC20(token, owner, to, ZERO, transferAmount);
if (isError) {
_restoreNonce(owner, nonce);
}
}
/**
* @notice Transfers an ERC20 token from the owner to the recipient using a permit signature
* @notice This function includes additional data to verify on the signature, allowing
* @notice protocols to extend the validation in one function call. NOTE: before calling this
* @notice function you MUST register the stub end of the additional data typestring using
* @notice the `registerAdditionalDataHash` function.
*
* @dev Be advised that the token ID for ERC20 is always inferred to be 0, so signed token ID
* @dev MUST always be set to 0.
*
* @dev - Throws for any reason permitTransferFromERC20 would.
* @dev - Throws if the additional data does not match the signature
* @dev - Throws if the provided hash has not been registered as a valid additional data hash
* @dev - Throws if the provided hash does not match the provided additional data
* @dev - Returns `false` if the transfer fails
*
* @dev <h4>Postconditions:</h4>
* @dev 1. Transfers the token (in the requested amount) from the owner to the recipient
* @dev 2. Performs any additional checks in the before and after hooks
* @dev 3. The nonce of the permit is marked as used
*
* @param token The address of the token
* @param nonce The nonce of the permit
* @param permitAmount The amount of tokens permitted by the owner
* @param expiration The expiration timestamp of the permit
* @param owner The owner of the token
* @param to The address to transfer the tokens to
* @param transferAmount The amount of tokens to transfer
* @param additionalData The additional data to verify on the signature
* @param advancedPermitHash The hash of the additional data
* @param signedPermit The permit signature, signed by the owner
*
* @return isError True if the transfer failed, false otherwise
*/
function permitTransferFromWithAdditionalDataERC20(
address token,
uint256 nonce,
uint256 permitAmount,
uint256 expiration,
address owner,
address to,
uint256 transferAmount,
bytes32 additionalData,
bytes32 advancedPermitHash,
bytes calldata signedPermit
) external onlyRegisteredTransferAdvancedTypeHash(advancedPermitHash) returns (bool isError) {
_requireNotPaused(PAUSABLE_PERMITTED_TRANSFER_FROM_ERC20);
_checkPermitApprovalWithAdditionalDataERC20(
token,
ZERO,
permitAmount,
nonce,
expiration,
owner,
transferAmount,
signedPermit,
additionalData,
advancedPermitHash
);
isError = _transferFromERC20(token, owner, to, ZERO, transferAmount);
if (isError) {
_restoreNonce(owner, nonce);
}
}
/**
* @notice Returns true if the provided hash has been registered as a valid additional data hash for transfers.
*
* @param hash The hash to check
*
* @return isRegistered true if the hash is valid, false otherwise
*/
function isRegisteredTransferAdditionalDataHash(bytes32 hash) external view returns (bool isRegistered) {
isRegistered = _registeredTransferHashes[hash];
}
/**
* @notice Returns true if the provided hash has been registered as a valid additional data hash for orders.
*
* @param hash The hash to check
*
* @return isRegistered true if the hash is valid, false otherwise
*/
function isRegisteredOrderAdditionalDataHash(bytes32 hash) external view returns (bool isRegistered) {
isRegistered = _registeredOrderHashes[hash];
}
/**
* =================================================
* =============== Order Transfers =================
* =================================================
*/
/**
* @notice Transfers an ERC1155 token from the owner to the recipient using a permit signature
* @notice Order transfers are used to transfer a specific amount of a token from a specific order
* @notice and allow for multiple uses of the same permit up to the allocated amount. NOTE: before calling this
* @notice function you MUST register the stub end of the additional data typestring using
* @notice the `registerAdditionalDataHash` function.
*
* @dev - Throws if the permit is expired
* @dev - Throws if the permit is not signed by the owner
* @dev - Throws if the requested amount + amount already filled exceeds the permitted amount
* @dev - Throws if the requested amount is less than the minimum fill amount
* @dev - Throws if the provided token address does not implement ERC1155 safeTransferFrom function
* @dev - Throws if the provided advanced permit hash has not been registered
* @dev - Returns `false` if the transfer fails
*
* @dev <h4>Postconditions:</h4>
* @dev 1. Transfers the token (in the requested amount) from the owner to the recipient
* @dev 2. Updates the amount filled for the order ID
* @dev 3. If completely filled, marks the order as filled
*
* @param signedPermit The permit signature, signed by the owner
* @param orderFillAmounts The amount of tokens to transfer
* @param token The address of the token
* @param id The ID of the token
* @param owner The owner of the token
* @param to The address to transfer the tokens to
* @param salt The salt of the permit
* @param expiration The expiration timestamp of the permit
* @param orderId The order ID
* @param advancedPermitHash The hash of the additional data
*
* @return quantityFilled The amount of tokens filled
* @return isError True if the transfer failed, false otherwise
*/
function fillPermittedOrderERC1155(
bytes calldata signedPermit,
OrderFillAmounts calldata orderFillAmounts,
address token,
uint256 id,
address owner,
address to,
uint256 salt,
uint48 expiration,
bytes32 orderId,
bytes32 advancedPermitHash
) external onlyRegisteredOrderAdvancedTypeHash(advancedPermitHash) returns (uint256 quantityFilled, bool isError) {
_requireNotPaused(PAUSABLE_ORDER_TRANSFER_FROM_ERC1155);
PackedApproval storage orderStatus = _checkOrderTransferERC1155(
signedPermit,
orderFillAmounts,
token,
id,
owner,
salt,
expiration,
orderId,
advancedPermitHash
);
(
quantityFilled,
isError
) = _orderTransfer(
orderStatus,
orderFillAmounts,
token,
id,
owner,
to,
orderId,
_transferFromERC1155
);
if (isError) {
_restoreFillableItems(orderStatus, owner, orderId, quantityFilled, true);
}
}
/**
* @notice Transfers an ERC20 token from the owner to the recipient using a permit signature
* @notice Order transfers are used to transfer a specific amount of a token from a specific order
* @notice and allow for multiple uses of the same permit up to the allocated amount. NOTE: before calling this
* @notice function you MUST register the stub end of the additional data typestring using
* @notice the `registerAdditionalDataHash` function.
*
* @dev - Throws if the permit is expired
* @dev - Throws if the permit is not signed by the owner
* @dev - Throws if the requested amount + amount already filled exceeds the permitted amount
* @dev - Throws if the requested amount is less than the minimum fill amount
* @dev - Throws if the provided token address does not implement ERC20 transferFrom function
* @dev - Throws if the provided advanced permit hash has not been registered
* @dev - Returns `false` if the transfer fails
*
* @dev <h4>Postconditions:</h4>
* @dev 1. Transfers the token (in the requested amount) from the owner to the recipient
* @dev 2. Updates the amount filled for the order ID
* @dev 3. If completely filled, marks the order as filled
*
* @param signedPermit The permit signature, signed by the owner
* @param orderFillAmounts The amount of tokens to transfer
* @param token The address of the token
* @param owner The owner of the token
* @param to The address to transfer the tokens to
* @param salt The salt of the permit
* @param expiration The expiration timestamp of the permit
* @param orderId The order ID
* @param advancedPermitHash The hash of the additional data
*
* @return quantityFilled The amount of tokens filled
* @return isError True if the transfer failed, false otherwise
*/
function fillPermittedOrderERC20(
bytes calldata signedPermit,
OrderFillAmounts calldata orderFillAmounts,
address token,
address owner,
address to,
uint256 salt,
uint48 expiration,
bytes32 orderId,
bytes32 advancedPermitHash
) external onlyRegisteredOrderAdvancedTypeHash(advancedPermitHash) returns (uint256 quantityFilled, bool isError) {
_requireNotPaused(PAUSABLE_ORDER_TRANSFER_FROM_ERC20);
PackedApproval storage orderStatus = _checkOrderTransferERC20(
signedPermit,
orderFillAmounts,
token,
ZERO,
owner,
salt,
expiration,
orderId,
advancedPermitHash
);
(
quantityFilled,
isError
) = _orderTransfer(
orderStatus,
orderFillAmounts,
token,
ZERO,
owner,
to,
orderId,
_transferFromERC20
);
if (isError) {
_restoreFillableItems(orderStatus, owner, orderId, quantityFilled, true);
}
}
/**
* @notice Closes an outstanding order to prevent further execution of transfers.
*
* @dev - Throws if the order is not in the open state
*
* @dev <h4>Postconditions:</h4>
* @dev 1. Marks the order as cancelled
* @dev 2. Sets the order amount to 0
* @dev 3. Sets the order expiration to 0
* @dev 4. Emits a OrderClosed event
*
* @param owner The owner of the token
* @param operator The operator allowed to transfer the token
* @param tokenType The type of token the order is for - must be 20, 721 or 1155.
* @param token The address of the token contract
* @param id The token ID
* @param orderId The order ID
*/
function closePermittedOrder(
address owner,
address operator,
uint256 tokenType,
address token,
uint256 id,
bytes32 orderId
) external {
if(!(msg.sender == owner || msg.sender == operator)) {
revert PermitC__CallerMustBeOwnerOrOperator();
}
_requireValidTokenType(tokenType);
PackedApproval storage orderStatus = _getPackedApprovalPtr(_orderApprovals, owner, tokenType, token, id, orderId, operator);
if (orderStatus.state == ORDER_STATE_OPEN) {
orderStatus.state = ORDER_STATE_CANCELLED;
orderStatus.amount = 0;
orderStatus.expiration = 0;
emit OrderClosed(orderId, owner, operator, true);
} else {
revert PermitC__OrderIsEitherCancelledOrFilled();
}
}
/**
* @notice Returns the amount of allowance an operator has for a specific token and id
* @notice If the expiration on the allowance has expired, returns 0
*
* @dev Overload of the on chain allowance function for approvals with a specified order ID
*
* @param owner The owner of the token
* @param operator The operator of the token
* @param token The address of the token contract
* @param id The token ID
*
* @return allowedAmount The amount of allowance the operator has
*/
function allowance(
address owner,
address operator,
uint256 tokenType,
address token,
uint256 id,
bytes32 orderId
) external view returns (uint256 allowedAmount, uint256 expiration) {
return _allowance(_orderApprovals, owner, operator, tokenType, token, id, orderId);
}
/**
* =================================================
* ================ Nonce Management ===============
* =================================================
*/
/**
* @notice Invalidates the provided nonce
*
* @dev - Throws if the provided nonce has already been used
*
* @dev <h4>Postconditions:</h4>
* @dev 1. Sets the provided nonce as used for the sender
*
* @param nonce Nonce to invalidate
*/
function invalidateUnorderedNonce(uint256 nonce) external {
_checkAndInvalidateNonce(msg.sender, nonce);
}
/**
* @notice Returns if the provided nonce has been used
*
* @param owner The owner of the token
* @param nonce The nonce to check
*
* @return isValid true if the nonce is valid, false otherwise
*/
function isValidUnorderedNonce(address owner, uint256 nonce) external view returns (bool isValid) {
isValid = ((_unorderedNonces[owner][uint248(nonce >> 8)] >> uint8(nonce)) & ONE) == ZERO;
}
/**
* @notice Revokes all outstanding approvals for the sender
*
* @dev <h4>Postconditions:</h4>
* @dev 1. Increments the master nonce for the sender
* @dev 2. All outstanding approvals for the sender are invalidated
*/
function lockdown() external {
unchecked {
_masterNonces[msg.sender]++;
}
emit Lockdown(msg.sender);
}
/**
* @notice Returns the master nonce for the provided owner address
*
* @param owner The owner address
*
* @return The master nonce
*/
function masterNonce(address owner) external view returns (uint256) {
return _masterNonces[owner];
}
/**
* =================================================
* ============== Transfer Functions ===============
* =================================================
*/
/**
* @notice Transfer an ERC721 token from the owner to the recipient using on chain approvals
*
* @dev Public transfer function overload for approval transfers
* @dev - Throws if the provided token address does not implement ERC721 transferFrom function
* @dev - Throws if the requested amount exceeds the approved amount
* @dev - Throws if the approval is expired
* @dev - Returns `false` if the transfer fails
*
* @dev <h4>Postconditions:</h4>
* @dev 1. Transfers the token (in the requested amount) from the owner to the recipient
* @dev 2. Decrements the approval amount by the requested amount
* @dev 3. Performs any additional checks in the before and after hooks
*
* @param owner The owner of the token
* @param to The recipient of the token
* @param token The address of the token
* @param id The id of the token
*
* @return isError True if the transfer failed, false otherwise
*/
function transferFromERC721(
address owner,
address to,
address token,
uint256 id
) external returns (bool isError) {
_requireNotPaused(PAUSABLE_APPROVAL_TRANSFER_FROM_ERC721);
PackedApproval storage approval = _checkAndUpdateApproval(owner, TOKEN_TYPE_ERC721, token, id, ONE, true);
isError = _transferFromERC721(owner, to, token, id);
if (isError) {
_restoreFillableItems(approval, owner, ZERO_BYTES32, ONE, false);
}
}
/**
* @notice Transfer an ERC1155 token from the owner to the recipient using on chain approvals
*
* @dev Public transfer function overload for approval transfers
* @dev - Throws if the provided token address does not implement ERC1155 safeTransferFrom function
* @dev - Throws if the requested amount exceeds the approved amount
* @dev - Throws if the approval is expired
* @dev - Returns `false` if the transfer fails
*
* @dev <h4>Postconditions:</h4>
* @dev 1. Transfers the token (in the requested amount) from the owner to the recipient
* @dev 2. Decrements the approval amount by the requested amount
* @dev 3. Performs any additional checks in the before and after hooks
*
* @param owner The owner of the token
* @param to The recipient of the token
* @param amount The amount of the token to transfer
* @param token The address of the token
* @param id The id of the token
*
* @return isError True if the transfer failed, false otherwise
*/
function transferFromERC1155(
address owner,
address to,
address token,
uint256 id,
uint256 amount
) external returns (bool isError) {
_requireNotPaused(PAUSABLE_APPROVAL_TRANSFER_FROM_ERC1155);
PackedApproval storage approval = _checkAndUpdateApproval(owner, TOKEN_TYPE_ERC1155, token, id, amount, false);
isError = _transferFromERC1155(token, owner, to, id, amount);
if (isError) {
_restoreFillableItems(approval, owner, ZERO_BYTES32, amount, false);
}
}
/**
* @notice Transfer an ERC20 token from the owner to the recipient using on chain approvals
*
* @dev Public transfer function overload for approval transfers
* @dev - Throws if the provided token address does not implement ERC20 transferFrom function
* @dev - Throws if the requested amount exceeds the approved amount
* @dev - Throws if the approval is expired
* @dev - Returns `false` if the transfer fails
*
* @dev <h4>Postconditions:</h4>
* @dev 1. Transfers the token (in the requested amount) from the owner to the recipient
* @dev 2. Decrements the approval amount by the requested amount
* @dev 3. Performs any additional checks in the before and after hooks
*
* @param owner The owner of the token
* @param to The recipient of the token
* @param amount The amount of the token to transfer
* @param token The address of the token
*
* @return isError True if the transfer failed, false otherwise
*/
function transferFromERC20(
address owner,
address to,
address token,
uint256 amount
) external returns (bool isError) {
_requireNotPaused(PAUSABLE_APPROVAL_TRANSFER_FROM_ERC20);
PackedApproval storage approval = _checkAndUpdateApproval(owner, TOKEN_TYPE_ERC20, token, ZERO, amount, false);
isError = _transferFromERC20(token, owner, to, ZERO, amount);
if (isError) {
_restoreFillableItems(approval, owner, ZERO_BYTES32, amount, false);
}
}
/**
* @notice Performs a transfer of an ERC721 token.
*
* @dev Will **NOT** attempt transfer if `_beforeTransferFrom` hook returns false.
* @dev Will **NOT** revert if the transfer is unsucessful.
* @dev Invokers **MUST** check `isError` return value to determine success.
*
* @param owner The owner of the token being transferred
* @param to The address to transfer the token to
* @param token The token address of the token being transferred
* @param id The token id being transferred
*
* @return isError True if the token was not transferred, false if token was transferred
*/
function _transferFromERC721(
address owner,
address to,
address token,
uint256 id
) private returns (bool isError) {
isError = _beforeTransferFrom(TOKEN_TYPE_ERC721, token, owner, to, id, ONE);
if (!isError) {
try IERC721(token).transferFrom(owner, to, id) { }
catch {
isError = true;
}
}
}
/**
* @notice Performs a transfer of an ERC1155 token.
*
* @dev Will **NOT** attempt transfer if `_beforeTransferFrom` hook returns false.
* @dev Will **NOT** revert if the transfer is unsucessful.
* @dev Invokers **MUST** check `isError` return value to determine success.
*
* @param token The token address of the token being transferred
* @param owner The owner of the token being transferred
* @param to The address to transfer the token to
* @param id The token id being transferred
* @param amount The quantity of token id to transfer
*
* @return isError True if the token was not transferred, false if token was transferred
*/
function _transferFromERC1155(
address token,
address owner,
address to,
uint256 id,
uint256 amount
) private returns (bool isError) {
isError = _beforeTransferFrom(TOKEN_TYPE_ERC1155, token, owner, to, id, amount);
if (!isError) {
try IERC1155(token).safeTransferFrom(owner, to, id, amount, "") { } catch {
isError = true;
}
}
}
/**
* @notice Performs a transfer of an ERC20 token.
*
* @dev Will **NOT** attempt transfer if `_beforeTransferFrom` hook returns false.
* @dev Will **NOT** revert if the transfer is unsucessful.
* @dev Invokers **MUST** check `isError` return value to determine success.
*
* @param token The token address of the token being transferred
* @param owner The owner of the token being transferred
* @param to The address to transfer the token to
* @param amount The quantity of token id to transfer
*
* @return isError True if the token was not transferred, false if token was transferred
*/
function _transferFromERC20(
address token,
address owner,
address to,
uint256 /*id*/,
uint256 amount
) private returns (bool isError) {
isError = _beforeTransferFrom(TOKEN_TYPE_ERC20, token, owner, to, ZERO, amount);
if (!isError) {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, owner, to, amount));
if (!success) {
isError = true;
} else if (data.length > 0) {
isError = !abi.decode(data, (bool));
}
}
}
/**
* =================================================
* ============ Signature Verification =============
* =================================================
*/
/**
* @notice Returns the domain separator used in the permit signature
*
* @return domainSeparator The domain separator
*/
function domainSeparatorV4() external view returns (bytes32 domainSeparator) {
domainSeparator = _domainSeparatorV4();
}
/**
* @notice Verifies a permit signature based on the bytes length of the signature provided.
*
* @dev Throws when -
* @dev The bytes signature length is 64 or 65 bytes AND
* @dev The ECDSA recovered signer is not the owner AND
* @dev The owner's code length is zero OR the owner does not return a valid EIP-1271 response
* @dev
* @dev OR
* @dev
* @dev The bytes signature length is not 64 or 65 bytes AND
* @dev The owner's code length is zero OR the owner does not return a valid EIP-1271 response
*/
function _verifyPermitSignature(bytes32 digest, bytes calldata signature, address owner) private view {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// Divide the signature in r, s and v variables
/// @solidity memory-safe-assembly
assembly {
r := calldataload(signature.offset)
s := calldataload(add(signature.offset, 32))
v := byte(0, calldataload(add(signature.offset, 64)))
}
(bool isError, address signer) = _ecdsaRecover(digest, v, r, s);
if (owner != signer || isError) {
_verifyEIP1271Signature(owner, digest, signature);
}
} else if (signature.length == 64) {
bytes32 r;
bytes32 vs;
// Divide the signature in r and vs variables
/// @solidity memory-safe-assembly
assembly {
r := calldataload(signature.offset)
vs := calldataload(add(signature.offset, 32))
}
(bool isError, address signer) = _ecdsaRecover(digest, r, vs);
if (owner != signer || isError) {
_verifyEIP1271Signature(owner, digest, signature);
}
} else {
_verifyEIP1271Signature(owner, digest, signature);
}
}
/**
* @notice Verifies an EIP-1271 signature.
*
* @dev Throws when `signer` code length is zero OR the EIP-1271 call does not
* @dev return the correct magic value.
*
* @param signer The signer address to verify a signature with
* @param hash The hash digest to verify with the signer
* @param signature The signature to verify
*/
function _verifyEIP1271Signature(address signer, bytes32 hash, bytes calldata signature) private view {
if(signer.code.length == 0) {
revert PermitC__SignatureTransferInvalidSignature();
}
if (!_safeIsValidSignature(signer, hash, signature)) {
revert PermitC__SignatureTransferInvalidSignature();
}
}
/**
* @notice Overload of the `_ecdsaRecover` function to unpack the `v` and `s` values
*
* @param digest The hash digest that was signed
* @param r The `r` value of the signature
* @param vs The packed `v` and `s` values of the signature
*
* @return isError True if the ECDSA function is provided invalid inputs
* @return signer The recovered address from ECDSA
*/
function _ecdsaRecover(bytes32 digest, bytes32 r, bytes32 vs) private pure returns (bool isError, address signer) {
unchecked {
bytes32 s = vs & UPPER_BIT_MASK;
uint8 v = uint8(uint256(vs >> 255)) + 27;
(isError, signer) = _ecdsaRecover(digest, v, r, s);
}
}
/**
* @notice Recovers the signer address using ECDSA
*
* @dev Does **NOT** revert if invalid input values are provided or `signer` is recovered as address(0)
* @dev Returns an `isError` value in those conditions that is handled upstream
*
* @param digest The hash digest that was signed
* @param v The `v` value of the signature
* @param r The `r` value of the signature
* @param s The `s` value of the signature
*
* @return isError True if the ECDSA function is provided invalid inputs
* @return signer The recovered address from ECDSA
*/
function _ecdsaRecover(bytes32 digest, uint8 v, bytes32 r, bytes32 s) private pure returns (bool isError, address signer) {
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
// Invalid signature `s` value - return isError = true and signer = address(0) to check EIP-1271
return (true, address(0));
}
signer = ecrecover(digest, v, r, s);
isError = (signer == address(0));
}
/**
* @notice A gas efficient, and fallback-safe way to call the isValidSignature function for EIP-1271.
*
* @param signer The EIP-1271 signer to call to check for a valid signature.
* @param hash The hash digest to verify with the EIP-1271 signer.
* @param signature The supplied signature to verify.
*
* @return isValid True if the EIP-1271 signer returns the EIP-1271 magic value.
*/
function _safeIsValidSignature(
address signer,
bytes32 hash,
bytes calldata signature
) private view returns(bool isValid) {
assembly {
function _callIsValidSignature(_signer, _hash, _signatureOffset, _signatureLength) -> _isValid {
let ptr := mload(0x40)
// store isValidSignature(bytes32,bytes) selector
mstore(ptr, hex"1626ba7e")
// store bytes32 hash value in abi encoded location
mstore(add(ptr, 0x04), _hash)
// store abi encoded location of the bytes signature data
mstore(add(ptr, 0x24), 0x40)
// store bytes signature length
mstore(add(ptr, 0x44), _signatureLength)
// copy calldata bytes signature to memory
calldatacopy(add(ptr, 0x64), _signatureOffset, _signatureLength)
// calculate data length based on abi encoded data with rounded up signature length
let dataLength := add(0x64, and(add(_signatureLength, 0x1F), not(0x1F)))
// update free memory pointer
mstore(0x40, add(ptr, dataLength))
// static call _signer with abi encoded data
// skip return data check if call failed or return data size is not at least 32 bytes
if and(iszero(lt(returndatasize(), 0x20)), staticcall(gas(), _signer, ptr, dataLength, 0x00, 0x20)) {
// check if return data is equal to isValidSignature magic value
_isValid := eq(mload(0x00), hex"1626ba7e")
leave
}
}
isValid := _callIsValidSignature(signer, hash, signature.offset, signature.length)
}
}
/**
* =================================================
* ===================== Hooks =====================
* =================================================
*/
/**
* @dev This function is empty by default. Override it to add additional logic after the approval transfer.
* @dev The function returns a boolean value instead of reverting to indicate if there is an error for more granular control in inheriting protocols.
*/
function _beforeTransferFrom(uint256 tokenType, address token, address owner, address to, uint256 id, uint256 amount) internal virtual returns (bool isError) {}
/**
* =================================================
* ==================== Internal ===================
* =================================================
*/
/**
* @notice Checks if an advanced permit typehash has been registered with PermitC
*
* @dev Throws when the typehash has not been registered
*
* @param advancedPermitHash The permit typehash to check
*/
function _requireTransferAdvancedPermitHashIsRegistered(bytes32 advancedPermitHash) private view {
if (!_registeredTransferHashes[advancedPermitHash]) {
revert PermitC__SignatureTransferPermitHashNotRegistered();
}
}
/**
* @notice Checks if an advanced permit typehash has been registered with PermitC
*
* @dev Throws when the typehash has not been registered
*
* @param advancedPermitHash The permit typehash to check
*/
function _requireOrderAdvancedPermitHashIsRegistered(bytes32 advancedPermitHash) private view {
if (!_registeredOrderHashes[advancedPermitHash]) {
revert PermitC__SignatureTransferPermitHashNotRegistered();
}
}
/**
* @notice Invalidates an account nonce if it has not been previously used
*
* @dev Throws when the nonce was previously used
*
* @param account The account to invalidate the nonce of
* @param nonce The nonce to invalidate
*/
function _checkAndInvalidateNonce(address account, uint256 nonce) private {
unchecked {
if (uint256(_unorderedNonces[account][uint248(nonce >> 8)] ^= (ONE << uint8(nonce))) &
(ONE << uint8(nonce)) == ZERO) {
revert PermitC__NonceAlreadyUsedOrRevoked();
}
}
}
/**
* @notice Checks an approval to ensure it is sufficient for the `amount` to send
*
* @dev Throws when the approval is expired
* @dev Throws when the approved amount is insufficient
*
* @param owner The owner of the token
* @param tokenType The type of token
* @param token The address of the token
* @param id The id of the token
* @param amount The amount to deduct from the approval
* @param zeroOutApproval True if the approval should be set to zero
*
* @return approval Storage pointer for the approval data
*/
function _checkAndUpdateApproval(
address owner,
uint256 tokenType,
address token,
uint256 id,
uint256 amount,
bool zeroOutApproval
) private returns (PackedApproval storage approval) {
approval = _getPackedApprovalPtr(_transferApprovals, owner, tokenType, token, id, ZERO_BYTES32, msg.sender);
if (approval.expiration < block.timestamp) {
revert PermitC__ApprovalTransferPermitExpiredOrUnset();
}
if (approval.amount < amount) {
revert PermitC__ApprovalTransferExceededPermittedAmount();
}
if(zeroOutApproval) {
approval.amount = 0;
} else if (approval.amount < type(uint200).max) {
unchecked {
approval.amount -= uint200(amount);
}
}
}
/**
* @notice Gets the storage pointer for an approval
*
* @param _approvals The mapping to retrieve the approval from
* @param account The account the approval is from
* @param tokenType The type of token the approval is for
* @param token The address of the token
* @param id The id of the token
* @param orderId The order id for the approval
* @param operator The operator for the approval
*
* @return approval Storage pointer for the approval data
*/
function _getPackedApprovalPtr(
mapping(bytes32 => mapping(address => PackedApproval)) storage _approvals,
address account,
uint256 tokenType,
address token,
uint256 id,
bytes32 orderId,
address operator
) private view returns (PackedApproval storage approval) {
approval = _approvals[_getPackedApprovalKey(account, tokenType, token, id, orderId)][operator];
}
/**
* @notice Gets the storage key for the mapping for a specific approval
*
* @param owner The owner of the token
* @param tokenType The type of token
* @param token The address of the token
* @param id The id of the token
* @param orderId The order id of the approval
*
* @return key The key value to use to access the approval in the mapping
*/
function _getPackedApprovalKey(address owner, uint256 tokenType, address token, uint256 id, bytes32 orderId) private view returns (bytes32 key) {
key = keccak256(abi.encode(owner, tokenType, token, id, orderId, _masterNonces[owner]));
}
/**
* @notice Checks the permit approval for a single use permit without additional data
*
* @dev Throws when the `nonce` has already been consumed
* @dev Throws when the permit amount is less than the transfer amount
* @dev Throws when the permit is expired
* @dev Throws when the signature is invalid
*
* @param tokenType The type of token
* @param token The address of the token
* @param id The id of the token
* @param permitAmount The amount authorized by the owner signature
* @param nonce The nonce of the permit
* @param expiration The time the permit expires
* @param owner The owner of the token
* @param transferAmount The amount of tokens requested to transfer
* @param signedPermit The signature for the permit
*/
function _checkPermitApproval(
uint256 tokenType,
address token,
uint256 id,
uint256 permitAmount,
uint256 nonce,
uint256 expiration,
address owner,
uint256 transferAmount,
bytes calldata signedPermit
) private {
bytes32 digest = _hashTypedDataV4(
PermitHash.hashSingleUsePermit(
tokenType,
token,
id,
permitAmount,
nonce,
expiration,
_masterNonces[owner]
)
);
_checkPermitData(
nonce,
expiration,
transferAmount,
permitAmount,
owner,
digest,
signedPermit
);
}
/**
* @notice Overload of `_checkPermitApprovalWithAdditionalData` to supply TOKEN_TYPE_ERC1155
*
* @dev Prevents stack too deep in `permitTransferFromWithAdditionalDataERC1155`
* @dev Throws when the `nonce` has already been consumed
* @dev Throws when the permit amount is less than the transfer amount
* @dev Throws when the permit is expired
* @dev Throws when the signature is invalid
*
* @param token The address of the token
* @param id The id of the token
* @param permitAmount The amount authorized by the owner signature
* @param nonce The nonce of the permit
* @param expiration The time the permit expires
* @param owner The owner of the token
* @param transferAmount The amount of tokens requested to transfer
* @param signedPermit The signature for the permit
* @param additionalData The additional data to validate with the permit signature
* @param advancedPermitHash The typehash of the permit to use for validating the signature
*/
function _checkPermitApprovalWithAdditionalDataERC1155(
address token,
uint256 id,
uint256 permitAmount,
uint256 nonce,
uint256 expiration,
address owner,
uint256 transferAmount,
bytes calldata signedPermit,
bytes32 additionalData,
bytes32 advancedPermitHash
) private {
_checkPermitApprovalWithAdditionalData(
TOKEN_TYPE_ERC1155,
token,
id,
permitAmount,
nonce,
expiration,
owner,
transferAmount,
signedPermit,
additionalData,
advancedPermitHash
);
}
/**
* @notice Overload of `_checkPermitApprovalWithAdditionalData` to supply TOKEN_TYPE_ERC20
*
* @dev Prevents stack too deep in `permitTransferFromWithAdditionalDataERC220`
* @dev Throws when the `nonce` has already been consumed
* @dev Throws when the permit amount is less than the transfer amount
* @dev Throws when the permit is expired
* @dev Throws when the signature is invalid
*
* @param token The address of the token
* @param id The id of the token
* @param permitAmount The amount authorized by the owner signature
* @param nonce The nonce of the permit
* @param expiration The time the permit expires
* @param owner The owner of the token
* @param transferAmount The amount of tokens requested to transfer
* @param signedPermit The signature for the permit
* @param additionalData The additional data to validate with the permit signature
* @param advancedPermitHash The typehash of the permit to use for validating the signature
*/
function _checkPermitApprovalWithAdditionalDataERC20(
address token,
uint256 id,
uint256 permitAmount,
uint256 nonce,
uint256 expiration,
address owner,
uint256 transferAmount,
bytes calldata signedPermit,
bytes32 additionalData,
bytes32 advancedPermitHash
) private {
_checkPermitApprovalWithAdditionalData(
TOKEN_TYPE_ERC20,
token,
id,
permitAmount,
nonce,
expiration,
owner,
transferAmount,
signedPermit,
additionalData,
advancedPermitHash
);
}
/**
* @notice Overload of `_checkPermitApprovalWithAdditionalData` to supply TOKEN_TYPE_ERC721
*
* @dev Prevents stack too deep in `permitTransferFromWithAdditionalDataERC721`
* @dev Throws when the `nonce` has already been consumed
* @dev Throws when the permit amount is less than the transfer amount
* @dev Throws when the permit is expired
* @dev Throws when the signature is invalid
*
* @param token The address of the token
* @param id The id of the token
* @param permitAmount The amount authorized by the owner signature
* @param nonce The nonce of the permit
* @param expiration The time the permit expires
* @param owner The owner of the token
* @param transferAmount The amount of tokens requested to transfer
* @param signedPermit The signature for the permit
* @param additionalData The additional data to validate with the permit signature
* @param advancedPermitHash The typehash of the permit to use for validating the signature
*/
function _checkPermitApprovalWithAdditionalDataERC721(
address token,
uint256 id,
uint256 permitAmount,
uint256 nonce,
uint256 expiration,
address owner,
uint256 transferAmount,
bytes calldata signedPermit,
bytes32 additionalData,
bytes32 advancedPermitHash
) private {
_checkPermitApprovalWithAdditionalData(
TOKEN_TYPE_ERC721,
token,
id,
permitAmount,
nonce,
expiration,
owner,
transferAmount,
signedPermit,
additionalData,
advancedPermitHash
);
}
/**
* @notice Checks the permit approval for a single use permit with additional data
*
* @dev Throws when the `nonce` has already been consumed
* @dev Throws when the permit amount is less than the transfer amount
* @dev Throws when the permit is expired
* @dev Throws when the signature is invalid
*
* @param tokenType The type of token
* @param token The address of the token
* @param id The id of the token
* @param permitAmount The amount authorized by the owner signature
* @param nonce The nonce of the permit
* @param expiration The time the permit expires
* @param owner The owner of the token
* @param transferAmount The amount of tokens requested to transfer
* @param signedPermit The signature for the permit
* @param additionalData The additional data to validate with the permit signature
* @param advancedPermitHash The typehash of the permit to use for validating the signature
*/
function _checkPermitApprovalWithAdditionalData(
uint256 tokenType,
address token,
uint256 id,
uint256 permitAmount,
uint256 nonce,
uint256 expiration,
address owner,
uint256 transferAmount,
bytes calldata signedPermit,
bytes32 additionalData,
bytes32 advancedPermitHash
) private {
bytes32 digest = _getAdvancedTypedDataV4PermitHash(
tokenType,
token,
id,
permitAmount,
owner,
nonce,
expiration,
additionalData,
advancedPermitHash
);
_checkPermitData(
nonce,
expiration,
transferAmount,
permitAmount,
owner,
digest,
signedPermit
);
}
/**
* @notice Checks that a single use permit has not expired, was authorized for the amount
* @notice being transferred, has a valid nonce and has a valid signature.
*
* @dev Throws when the `nonce` has already been consumed
* @dev Throws when the permit amount is less than the transfer amount
* @dev Throws when the permit is expired
* @dev Throws when the signature is invalid
*
* @param nonce The nonce of the permit
* @param expiration The time the permit expires
* @param transferAmount The amount of tokens requested to transfer
* @param permitAmount The amount authorized by the owner signature
* @param owner The owner of the token
* @param digest The digest that was signed by the owner
* @param signedPermit The signature for the permit
*/
function _checkPermitData(
uint256 nonce,
uint256 expiration,
uint256 transferAmount,
uint256 permitAmount,
address owner,
bytes32 digest,
bytes calldata signedPermit
) private {
if (block.timestamp > expiration) {
revert PermitC__SignatureTransferExceededPermitExpired();
}
if (transferAmount > permitAmount) {
revert PermitC__SignatureTransferExceededPermittedAmount();
}
_checkAndInvalidateNonce(owner, nonce);
_verifyPermitSignature(digest, signedPermit, owner);
}
/**
* @notice Stores an approval for future use by `operator` to move tokens on behalf of `owner`
*
* @param tokenType The type of token
* @param token The address of the token
* @param id The id of the token
* @param amount The amount authorized by the owner
* @param expiration The time the permit expires
* @param owner The owner of the token
* @param operator The account allowed to transfer the tokens
*/
function _storeApproval(
uint256 tokenType,
address token,
uint256 id,
uint200 amount,
uint48 expiration,
address owner,
address operator
) private {
PackedApproval storage approval = _getPackedApprovalPtr(_transferApprovals, owner, tokenType, token, id, ZERO_BYTES32, operator);
approval.expiration = expiration;
approval.amount = amount;
emit Approval(owner, token, operator, id, amount, expiration);
}
/**
* @notice Overload of `_checkOrderTransfer` to supply TOKEN_TYPE_ERC1155
*
* @dev Prevents stack too deep in `fillPermittedOrderERC1155`
* @dev Throws when the order start amount is greater than type(uint200).max
* @dev Throws when the order status is not open
* @dev Throws when the signature is invalid
* @dev Throws when the permit is expired
*
* @param signedPermit The signature for the permit
* @param orderFillAmounts A struct containing the order start, requested fill and minimum fill amounts
* @param token The address of the token
* @param id The id of the token
* @param owner The owner of the token
* @param salt The salt value for the permit
* @param expiration The time the permit expires
* @param orderId The order id for the permit
* @param advancedPermitHash The typehash of the permit to use for validating the signature
*
* @return orderStatus Storage pointer for the approval data
*/
function _checkOrderTransferERC1155(
bytes calldata signedPermit,
OrderFillAmounts calldata orderFillAmounts,
address token,
uint256 id,
address owner,
uint256 salt,
uint48 expiration,
bytes32 orderId,
bytes32 advancedPermitHash
) private returns (PackedApproval storage orderStatus) {
orderStatus = _checkOrderTransfer(
signedPermit,
orderFillAmounts,
TOKEN_TYPE_ERC1155,
token,
id,
owner,
salt,
expiration,
orderId,
advancedPermitHash
);
}
/**
* @notice Overload of `_checkOrderTransfer` to supply TOKEN_TYPE_ERC20
*
* @dev Prevents stack too deep in `fillPermittedOrderERC20`
* @dev Throws when the order start amount is greater than type(uint200).max
* @dev Throws when the order status is not open
* @dev Throws when the signature is invalid
* @dev Throws when the permit is expired
*
* @param signedPermit The signature for the permit
* @param orderFillAmounts A struct containing the order start, requested fill and minimum fill amounts
* @param token The address of the token
* @param id The id of the token
* @param owner The owner of the token
* @param salt The salt value for the permit
* @param expiration The time the permit expires
* @param orderId The order id for the permit
* @param advancedPermitHash The typehash of the permit to use for validating the signature
*
* @return orderStatus Storage pointer for the approval data
*/
function _checkOrderTransferERC20(
bytes calldata signedPermit,
OrderFillAmounts calldata orderFillAmounts,
address token,
uint256 id,
address owner,
uint256 salt,
uint48 expiration,
bytes32 orderId,
bytes32 advancedPermitHash
) private returns (PackedApproval storage orderStatus) {
orderStatus = _checkOrderTransfer(
signedPermit,
orderFillAmounts,
TOKEN_TYPE_ERC20,
token,
id,
owner,
salt,
expiration,
orderId,
advancedPermitHash
);
}
/**
* @notice Validates an order transfer to check order start amount, status, signature if not previously
* @notice opened, and expiration.
*
* @dev Throws when the order start amount is greater than type(uint200).max
* @dev Throws when the order status is not open
* @dev Throws when the signature is invalid
* @dev Throws when the permit is expired
*
* @param signedPermit The signature for the permit
* @param orderFillAmounts A struct containing the order start, requested fill and minimum fill amounts
* @param tokenType The type of token
* @param token The address of the token
* @param id The id of the token
* @param owner The owner of the token
* @param salt The salt value for the permit
* @param expiration The time the permit expires
* @param orderId The order id for the permit
* @param advancedPermitHash The typehash of the permit to use for validating the signature
*
* @return orderStatus Storage pointer for the approval data
*/
function _checkOrderTransfer(
bytes calldata signedPermit,
OrderFillAmounts calldata orderFillAmounts,
uint256 tokenType,
address token,
uint256 id,
address owner,
uint256 salt,
uint48 expiration,
bytes32 orderId,
bytes32 advancedPermitHash
) private returns (PackedApproval storage orderStatus) {
if (orderFillAmounts.orderStartAmount > type(uint200).max) {
revert PermitC__AmountExceedsStorageMaximum();
}
orderStatus = _getPackedApprovalPtr(_orderApprovals, owner, tokenType, token, id, orderId, msg.sender);
if (orderStatus.state == ORDER_STATE_OPEN) {
if (orderStatus.amount == 0) {
_verifyPermitSignature(
_getAdvancedTypedDataV4PermitHash(
tokenType,
token,
id,
orderFillAmounts.orderStartAmount,
owner,
salt,
expiration,
orderId,
advancedPermitHash
),
signedPermit,
owner
);
orderStatus.amount = uint200(orderFillAmounts.orderStartAmount);
orderStatus.expiration = expiration;
emit OrderOpened(orderId, owner, msg.sender, orderFillAmounts.orderStartAmount);
}
if (block.timestamp > orderStatus.expiration) {
revert PermitC__SignatureTransferExceededPermitExpired();
}
} else {
revert PermitC__OrderIsEitherCancelledOrFilled();
}
}
/**
* @notice Checks the order fill amounts against approval data and transfers tokens, updates
* @notice approval if the fill results in the order being closed.
*
* @dev Throws when the amount to fill is less than the minimum fill amount
*
* @param orderStatus Storage pointer for the approval data
* @param orderFillAmounts A struct containing the order start, requested fill and minimum fill amounts
* @param token The address of the token
* @param id The id of the token
* @param owner The owner of the token
* @param to The address to send the tokens to
* @param orderId The order id for the permit
* @param _transferFrom Function pointer of the transfer function to send tokens with
*
* @return quantityFilled The number of tokens filled in the order
* @return isError True if there was an error transferring tokens, false otherwise
*/
function _orderTransfer(
PackedApproval storage orderStatus,
OrderFillAmounts calldata orderFillAmounts,
address token,
uint256 id,
address owner,
address to,
bytes32 orderId,
function (address, address, address, uint256, uint256) internal returns (bool) _transferFrom
) private returns (uint256 quantityFilled, bool isError) {
quantityFilled = orderFillAmounts.requestedFillAmount;
if (quantityFilled > orderStatus.amount) {
quantityFilled = orderStatus.amount;
}
if (quantityFilled < orderFillAmounts.minimumFillAmount) {
revert PermitC__UnableToFillMinimumRequestedQuantity();
}
unchecked {
orderStatus.amount -= uint200(quantityFilled);
emit OrderFilled(orderId, owner, msg.sender, quantityFilled);
}
if (orderStatus.amount == 0) {
orderStatus.state = ORDER_STATE_FILLED;
emit OrderClosed(orderId, owner, msg.sender, false);
}
isError = _transferFrom(token, owner, to, id, quantityFilled);
}
/**
* @notice Restores an account's nonce when a transfer was not successful
*
* @dev Throws when the nonce was not already consumed
*
* @param account The account to restore the nonce of
* @param nonce The nonce to restore
*/
function _restoreNonce(address account, uint256 nonce) private {
unchecked {
if (uint256(_unorderedNonces[account][uint248(nonce >> 8)] ^= (ONE << uint8(nonce))) &
(ONE << uint8(nonce)) != ZERO) {
revert PermitC__NonceNotUsedOrRevoked();
}
}
}
/**
* @notice Restores an approval amount when a transfer was not successful
*
* @param approval Storage pointer for the approval data
* @param owner The owner of the tokens
* @param orderId The order id to restore approval amount on
* @param unfilledAmount The amount that was not filled on the order
* @param isOrderPermit True if the fill restoration is for an permit order
*/
function _restoreFillableItems(
PackedApproval storage approval,
address owner,
bytes32 orderId,
uint256 unfilledAmount,
bool isOrderPermit
) private {
if (unfilledAmount > 0) {
if (isOrderPermit) {
// Order permits always deduct amount and must be restored
unchecked {
approval.amount += uint200(unfilledAmount);
}
approval.state = ORDER_STATE_OPEN;
emit OrderRestored(orderId, owner, unfilledAmount);
} else if (approval.amount < type(uint200).max) {
// Stored approvals only deduct amount
unchecked {
approval.amount += uint200(unfilledAmount);
}
}
}
}
function _requireValidTokenType(uint256 tokenType) private pure {
if(!(
tokenType == TOKEN_TYPE_ERC721 ||
tokenType == TOKEN_TYPE_ERC1155 ||
tokenType == TOKEN_TYPE_ERC20
)
) {
revert PermitC__InvalidTokenType();
}
}
/**
* @notice Generates an EIP-712 digest for a permit
*
* @param tokenType The type of token
* @param token The address of the token
* @param id The id of the token
* @param amount The amount authorized by the owner signature
* @param owner The owner of the token
* @param nonce The nonce for the permit
* @param expiration The time the permit expires
* @param additionalData The additional data to validate with the permit signature
* @param advancedPermitHash The typehash of the permit to use for validating the signature
*
* @return digest The EIP-712 digest of the permit data
*/
function _getAdvancedTypedDataV4PermitHash(
uint256 tokenType,
address token,
uint256 id,
uint256 amount,
address owner,
uint256 nonce,
uint256 expiration,
bytes32 additionalData,
bytes32 advancedPermitHash
) private view returns (bytes32 digest) {
// cache masterNonce on stack to avoid stack too deep
uint256 masterNonce_ = _masterNonces[owner];
digest =
_hashTypedDataV4(
PermitHash.hashSingleUsePermitWithAdditionalData(
tokenType,
token,
id,
amount,
nonce,
expiration,
additionalData,
advancedPermitHash,
masterNonce_
)
);
}
/**
* @notice Returns the current allowed amount and expiration for a stored permit
*
* @dev Returns zero allowed if the permit has expired
*
* @param _approvals The mapping to retrieve the approval from
* @param owner The account the approval is from
* @param operator The operator for the approval
* @param tokenType The type of token the approval is for
* @param token The address of the token
* @param id The id of the token
* @param orderId The order id for the approval
*
* @return allowedAmount The amount authorized by the approval, zero if the permit has expired
* @return expiration The expiration of the approval
*/
function _allowance(
mapping(bytes32 => mapping(address => PackedApproval)) storage _approvals,
address owner,
address operator,
uint256 tokenType,
address token,
uint256 id,
bytes32 orderId
) private view returns (uint256 allowedAmount, uint256 expiration) {
PackedApproval storage allowed = _getPackedApprovalPtr(_approvals, owner, tokenType, token, id, orderId, operator);
allowedAmount = allowed.expiration < block.timestamp ? 0 : allowed.amount;
expiration = allowed.expiration;
}
/**
* @notice Allows the owner of the PermitC contract to access pausable admin functions
*
* @dev May be overriden by an inheriting contract to provide alternative permission structure
*/
function _requireCallerHasPausePermissions() internal view virtual override {
_checkOwner();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
contract Tstorish {
// Declare a storage variable indicating if TSTORE support has been
// activated post-deployment.
bool private _tstoreSupport;
/*
* ------------------------------------------------------------------------+
* Opcode | Mnemonic | Stack | Memory |
* ------------------------------------------------------------------------|
* 60 0x02 | PUSH1 0x02 | 0x02 | |
* 60 0x1e | PUSH1 0x1e | 0x1e 0x02 | |
* 61 0x3d5c | PUSH2 0x3d5c | 0x3d5c 0x1e 0x02 | |
* 3d | RETURNDATASIZE | 0 0x3d5c 0x1e 0x02 | |
* |
* :: store deployed bytecode in memory: (3d) RETURNDATASIZE (5c) TLOAD :: |
* 52 | MSTORE | 0x1e 0x02 | [0..0x20): 0x3d5c |
* f3 | RETURN | | [0..0x20): 0x3d5c |
* ------------------------------------------------------------------------+
*/
uint256 constant _TLOAD_TEST_PAYLOAD = 0x6002_601e_613d5c_3d_52_f3;
uint256 constant _TLOAD_TEST_PAYLOAD_LENGTH = 0x0a;
uint256 constant _TLOAD_TEST_PAYLOAD_OFFSET = 0x16;
// Declare an immutable variable to store the initial TSTORE support status.
bool private immutable _tstoreInitialSupport;
// Declare an immutable variable to store the tstore test contract address.
address private immutable _tloadTestContract;
// Declare a few custom revert error types.
error TStoreAlreadyActivated();
error TStoreNotSupported();
error TloadTestContractDeploymentFailed();
error OnlyDirectCalls();
/**
* @dev Determine TSTORE availability during deployment. This involves
* attempting to deploy a contract that utilizes TLOAD as part of the
* contract construction bytecode, and configuring initial support for
* using TSTORE in place of SSTORE based on the result.
*/
constructor() {
// Deploy the contract testing TLOAD support and store the address.
address tloadTestContract = _prepareTloadTest();
// Ensure the deployment was successful.
if (tloadTestContract == address(0)) {
revert TloadTestContractDeploymentFailed();
}
// Determine if TSTORE is supported.
bool tstoreInitialSupport = _testTload(tloadTestContract);
// Store the result as an immutable.
_tstoreInitialSupport = tstoreInitialSupport;
// Set the address of the deployed TLOAD test contract as an immutable.
_tloadTestContract = tloadTestContract;
}
/**
* @dev External function to activate TSTORE usage. Does not need to be
* called if TSTORE is supported from deployment, and only needs to be
* called once. Reverts if TSTORE has already been activated or if the
* opcode is not available. Note that this must be called directly from
* an externally-owned account to avoid potential reentrancy issues.
*/
function __activateTstore() external {
// Ensure this function is triggered from an externally-owned account.
if (msg.sender != tx.origin) {
revert OnlyDirectCalls();
}
// Determine if TSTORE can potentially be activated.
if (_tstoreInitialSupport || _tstoreSupport) {
revert TStoreAlreadyActivated();
}
// Determine if TSTORE can be activated and revert if not.
if (!_testTload(_tloadTestContract)) {
revert TStoreNotSupported();
}
// Mark TSTORE as activated.
_tstoreSupport = true;
}
/**
* @dev Internal function to set a TSTORISH value.
*
* @param storageSlot The slot to write the TSTORISH value to.
* @param value The value to write to the given storage slot.
*/
function _setTstorish(uint256 storageSlot, uint256 value) internal {
if (_tstoreInitialSupport) {
assembly {
tstore(storageSlot, value)
}
} else if (_tstoreSupport) {
assembly {
tstore(storageSlot, value)
}
} else {
assembly {
sstore(storageSlot, value)
}
}
}
/**
* @dev Internal function to read a TSTORISH value.
*
* @param storageSlot The slot to read the TSTORISH value from.
*
* @return value The TSTORISH value at the given storage slot.
*/
function _getTstorish(
uint256 storageSlot
) internal view returns (uint256 value) {
if (_tstoreInitialSupport) {
assembly {
value := tload(storageSlot)
}
} else if (_tstoreSupport) {
assembly {
value := tload(storageSlot)
}
} else {
assembly {
value := sload(storageSlot)
}
}
}
/**
* @dev Internal function to clear a TSTORISH value.
*
* @param storageSlot The slot to clear the TSTORISH value for.
*/
function _clearTstorish(uint256 storageSlot) internal {
if (_tstoreInitialSupport) {
assembly {
tstore(storageSlot, 0)
}
} else if (_tstoreSupport) {
assembly {
tstore(storageSlot, 0)
}
} else {
assembly {
sstore(storageSlot, 0)
}
}
}
/**
* @dev Private function to deploy a test contract that utilizes TLOAD as
* part of its fallback logic.
*/
function _prepareTloadTest() private returns (address contractAddress) {
// Utilize assembly to deploy a contract testing TLOAD support.
assembly {
// Write the contract deployment code payload to scratch space.
mstore(0, _TLOAD_TEST_PAYLOAD)
// Deploy the contract.
contractAddress := create(
0,
_TLOAD_TEST_PAYLOAD_OFFSET,
_TLOAD_TEST_PAYLOAD_LENGTH
)
}
}
/**
* @dev Private view function to determine if TSTORE/TLOAD are supported by
* the current EVM implementation by attempting to call the test
* contract, which utilizes TLOAD as part of its fallback logic.
*/
function _testTload(
address tloadTestContract
) private view returns (bool ok) {
// Call the test contract, which will perform a TLOAD test. If the call
// does not revert, then TLOAD/TSTORE is supported. Do not forward all
// available gas, as all forwarded gas will be consumed on revert.
(ok, ) = tloadTestContract.staticcall{ gas: gasleft() / 10 }("");
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @dev Thrown when a stored approval exceeds type(uint200).max error PermitC__AmountExceedsStorageMaximum(); /// @dev Thrown when a transfer amount requested exceeds the permitted amount error PermitC__ApprovalTransferExceededPermittedAmount(); /// @dev Thrown when a transfer is requested after the permit has expired error PermitC__ApprovalTransferPermitExpiredOrUnset(); /// @dev Thrown when attempting to close an order by an account that is not the owner or operator error PermitC__CallerMustBeOwnerOrOperator(); /// @dev Thrown when attempting to approve a token type that is not valid for PermitC error PermitC__InvalidTokenType(); /// @dev Thrown when attempting to invalidate a nonce that has already been used error PermitC__NonceAlreadyUsedOrRevoked(); /// @dev Thrown when attempting to restore a nonce that has not been used error PermitC__NonceNotUsedOrRevoked(); /// @dev Thrown when attempting to fill an order that has already been filled or cancelled error PermitC__OrderIsEitherCancelledOrFilled(); /// @dev Thrown when a transfer amount requested exceeds the permitted amount error PermitC__SignatureTransferExceededPermittedAmount(); /// @dev Thrown when a transfer is requested after the permit has expired error PermitC__SignatureTransferExceededPermitExpired(); /// @dev Thrown when attempting to use an advanced permit typehash that is not registered error PermitC__SignatureTransferPermitHashNotRegistered(); /// @dev Thrown when a permit signature is invalid error PermitC__SignatureTransferInvalidSignature(); /// @dev Thrown when the remaining fill amount is less than the requested minimum fill error PermitC__UnableToFillMinimumRequestedQuantity();
// 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 v4.4.1 (interfaces/IERC721.sol) pragma solidity ^0.8.0; import "../token/ERC721/IERC721.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC1155.sol) pragma solidity ^0.8.0; import "../token/ERC1155/IERC1155.sol";
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC1271 standard signature validation method for
* contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
*
* _Available since v4.1._
*/
interface IERC1271 {
/**
* @dev Should return whether the signature provided is valid for the provided data
* @param hash Hash of the data to be signed
* @param signature Signature byte array associated with _data
*/
function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
error Ownable__CallerIsNotOwner();
error Ownable__NewOwnerIsZeroAddress();
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if(owner() != _msgSender()) revert Ownable__CallerIsNotOwner();
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if(newOwner == address(0)) revert Ownable__NewOwnerIsZeroAddress();
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol)
pragma solidity ^0.8.8;
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
* thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
* they need in their contracts using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*
* NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
* separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the
* separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
*
* _Available since v3.4._
*
* @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
*/
abstract contract EIP712 {
bytes32 private constant _TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
// Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
// invalidate the cached domain separator if the chain id changes.
bytes32 private immutable _cachedDomainSeparator;
uint256 private immutable _cachedChainId;
bytes32 private immutable _hashedName;
bytes32 private immutable _hashedVersion;
/**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/
constructor(string memory name, string memory version) {
_hashedName = keccak256(bytes(name));
_hashedVersion = keccak256(bytes(version));
_cachedChainId = block.chainid;
_cachedDomainSeparator = _buildDomainSeparator();
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
if (block.chainid == _cachedChainId) {
return _cachedDomainSeparator;
} else {
return _buildDomainSeparator();
}
}
function _buildDomainSeparator() private view returns (bytes32) {
return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @dev Constant bytes32 value of 0x000...000
bytes32 constant ZERO_BYTES32 = bytes32(0);
/// @dev Constant value of 0
uint256 constant ZERO = 0;
/// @dev Constant value of 1
uint256 constant ONE = 1;
/// @dev Constant value representing an open order in storage
uint8 constant ORDER_STATE_OPEN = 0;
/// @dev Constant value representing a filled order in storage
uint8 constant ORDER_STATE_FILLED = 1;
/// @dev Constant value representing a cancelled order in storage
uint8 constant ORDER_STATE_CANCELLED = 2;
/// @dev Constant value representing the ERC721 token type for signatures and transfer hooks
uint256 constant TOKEN_TYPE_ERC721 = 721;
/// @dev Constant value representing the ERC1155 token type for signatures and transfer hooks
uint256 constant TOKEN_TYPE_ERC1155 = 1155;
/// @dev Constant value representing the ERC20 token type for signatures and transfer hooks
uint256 constant TOKEN_TYPE_ERC20 = 20;
/// @dev Constant value to mask the upper bits of a signature that uses a packed `vs` value to extract `s`
bytes32 constant UPPER_BIT_MASK = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
/// @dev EIP-712 typehash used for validating signature based stored approvals
bytes32 constant UPDATE_APPROVAL_TYPEHASH =
keccak256("UpdateApprovalBySignature(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 approvalExpiration,uint256 sigDeadline,uint256 masterNonce)");
/// @dev EIP-712 typehash used for validating a single use permit without additional data
bytes32 constant SINGLE_USE_PERMIT_TYPEHASH =
keccak256("PermitTransferFrom(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 expiration,uint256 masterNonce)");
/// @dev EIP-712 typehash used for validating a single use permit with additional data
string constant SINGLE_USE_PERMIT_TRANSFER_ADVANCED_TYPEHASH_STUB =
"PermitTransferFromWithAdditionalData(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 expiration,uint256 masterNonce,";
/// @dev EIP-712 typehash used for validating an order permit that updates storage as it fills
string constant PERMIT_ORDER_ADVANCED_TYPEHASH_STUB =
"PermitOrderWithAdditionalData(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 salt,address operator,uint256 expiration,uint256 masterNonce,";
/// @dev Pausable flag for stored approval transfers of ERC721 assets
uint256 constant PAUSABLE_APPROVAL_TRANSFER_FROM_ERC721 = 1 << 0;
/// @dev Pausable flag for stored approval transfers of ERC1155 assets
uint256 constant PAUSABLE_APPROVAL_TRANSFER_FROM_ERC1155 = 1 << 1;
/// @dev Pausable flag for stored approval transfers of ERC20 assets
uint256 constant PAUSABLE_APPROVAL_TRANSFER_FROM_ERC20 = 1 << 2;
/// @dev Pausable flag for single use permit transfers of ERC721 assets
uint256 constant PAUSABLE_PERMITTED_TRANSFER_FROM_ERC721 = 1 << 3;
/// @dev Pausable flag for single use permit transfers of ERC1155 assets
uint256 constant PAUSABLE_PERMITTED_TRANSFER_FROM_ERC1155 = 1 << 4;
/// @dev Pausable flag for single use permit transfers of ERC20 assets
uint256 constant PAUSABLE_PERMITTED_TRANSFER_FROM_ERC20 = 1 << 5;
/// @dev Pausable flag for order fill transfers of ERC1155 assets
uint256 constant PAUSABLE_ORDER_TRANSFER_FROM_ERC1155 = 1 << 6;
/// @dev Pausable flag for order fill transfers of ERC20 assets
uint256 constant PAUSABLE_ORDER_TRANSFER_FROM_ERC20 = 1 << 7;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @dev Storage data struct for stored approvals and order approvals
struct PackedApproval {
// Only used for partial fill position 1155 transfers
uint8 state;
// Amount allowed
uint200 amount;
// Permission expiry
uint48 expiration;
}
/// @dev Calldata data struct for order fill amounts
struct OrderFillAmounts {
uint256 orderStartAmount;
uint256 requestedFillAmount;
uint256 minimumFillAmount;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {SINGLE_USE_PERMIT_TYPEHASH, UPDATE_APPROVAL_TYPEHASH} from "../Constants.sol";
library PermitHash {
/**
* @notice Hashes the permit data for a stored approval
*
* @param tokenType The type of token
* @param token The address of the token
* @param id The id of the token
* @param amount The amount authorized by the owner signature
* @param nonce The nonce for the permit
* @param operator The account that is allowed to use the permit
* @param approvalExpiration The time the permit approval expires
* @param sigDeadline The deadline for submitting the permit onchain
* @param masterNonce The signers master nonce
*
* @return hash The hash of the permit data
*/
function hashOnChainApproval(
uint256 tokenType,
address token,
uint256 id,
uint256 amount,
uint256 nonce,
address operator,
uint256 approvalExpiration,
uint256 sigDeadline,
uint256 masterNonce
) internal pure returns (bytes32 hash) {
hash = keccak256(
abi.encode(
UPDATE_APPROVAL_TYPEHASH,
tokenType,
token,
id,
amount,
nonce,
operator,
approvalExpiration,
sigDeadline,
masterNonce
)
);
}
/**
* @notice Hashes the permit data with the single user permit without additional data typehash
*
* @param tokenType The type of token
* @param token The address of the token
* @param id The id of the token
* @param amount The amount authorized by the owner signature
* @param nonce The nonce for the permit
* @param expiration The time the permit expires
* @param masterNonce The signers master nonce
*
* @return hash The hash of the permit data
*/
function hashSingleUsePermit(
uint256 tokenType,
address token,
uint256 id,
uint256 amount,
uint256 nonce,
uint256 expiration,
uint256 masterNonce
) internal view returns (bytes32 hash) {
hash = keccak256(
abi.encode(
SINGLE_USE_PERMIT_TYPEHASH,
tokenType,
token,
id,
amount,
nonce,
msg.sender,
expiration,
masterNonce
)
);
}
/**
* @notice Hashes the permit data with the supplied typehash
*
* @param tokenType The type of token
* @param token The address of the token
* @param id The id of the token
* @param amount The amount authorized by the owner signature
* @param nonce The nonce for the permit
* @param expiration The time the permit expires
* @param additionalData The additional data to validate with the permit signature
* @param additionalDataTypeHash The typehash of the permit to use for validating the signature
* @param masterNonce The signers master nonce
*
* @return hash The hash of the permit data with the supplied typehash
*/
function hashSingleUsePermitWithAdditionalData(
uint256 tokenType,
address token,
uint256 id,
uint256 amount,
uint256 nonce,
uint256 expiration,
bytes32 additionalData,
bytes32 additionalDataTypeHash,
uint256 masterNonce
) internal view returns (bytes32 hash) {
hash = keccak256(
abi.encode(
additionalDataTypeHash,
tokenType,
token,
id,
amount,
nonce,
msg.sender,
expiration,
masterNonce,
additionalData
)
);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {OrderFillAmounts} from "../DataTypes.sol";
interface IPermitC {
/**
* =================================================
* ==================== Events =====================
* =================================================
*/
/// @dev Emitted when an approval is stored
event Approval(
address indexed owner,
address indexed token,
address indexed operator,
uint256 id,
uint200 amount,
uint48 expiration
);
/// @dev Emitted when a user increases their master nonce
event Lockdown(address indexed owner);
/// @dev Emitted when an order is opened
event OrderOpened(
bytes32 indexed orderId,
address indexed owner,
address indexed operator,
uint256 fillableQuantity
);
/// @dev Emitted when an order has a fill
event OrderFilled(
bytes32 indexed orderId,
address indexed owner,
address indexed operator,
uint256 amount
);
/// @dev Emitted when an order has been fully filled or cancelled
event OrderClosed(
bytes32 indexed orderId,
address indexed owner,
address indexed operator,
bool wasCancellation);
/// @dev Emitted when an order has an amount restored due to a failed transfer
event OrderRestored(
bytes32 indexed orderId,
address indexed owner,
uint256 amountRestoredToOrder
);
/**
* =================================================
* ============== Approval Transfers ===============
* =================================================
*/
function approve(uint256 tokenType, address token, uint256 id, address operator, uint200 amount, uint48 expiration) external;
function updateApprovalBySignature(
uint256 tokenType,
address token,
uint256 id,
uint256 nonce,
uint200 amount,
address operator,
uint48 approvalExpiration,
uint48 sigDeadline,
address owner,
bytes calldata signedPermit
) external;
function allowance(
address owner,
address operator,
uint256 tokenType,
address token,
uint256 id
) external view returns (uint256 amount, uint256 expiration);
/**
* =================================================
* ================ Signed Transfers ===============
* =================================================
*/
function registerAdditionalDataHash(string memory additionalDataTypeString) external;
function permitTransferFromERC721(
address token,
uint256 id,
uint256 nonce,
uint256 expiration,
address owner,
address to,
bytes calldata signedPermit
) external returns (bool isError);
function permitTransferFromWithAdditionalDataERC721(
address token,
uint256 id,
uint256 nonce,
uint256 expiration,
address owner,
address to,
bytes32 additionalData,
bytes32 advancedPermitHash,
bytes calldata signedPermit
) external returns (bool isError);
function permitTransferFromERC1155(
address token,
uint256 id,
uint256 nonce,
uint256 permitAmount,
uint256 expiration,
address owner,
address to,
uint256 transferAmount,
bytes calldata signedPermit
) external returns (bool isError);
function permitTransferFromWithAdditionalDataERC1155(
address token,
uint256 id,
uint256 nonce,
uint256 permitAmount,
uint256 expiration,
address owner,
address to,
uint256 transferAmount,
bytes32 additionalData,
bytes32 advancedPermitHash,
bytes calldata signedPermit
) external returns (bool isError);
function permitTransferFromERC20(
address token,
uint256 nonce,
uint256 permitAmount,
uint256 expiration,
address owner,
address to,
uint256 transferAmount,
bytes calldata signedPermit
) external returns (bool isError);
function permitTransferFromWithAdditionalDataERC20(
address token,
uint256 nonce,
uint256 permitAmount,
uint256 expiration,
address owner,
address to,
uint256 transferAmount,
bytes32 additionalData,
bytes32 advancedPermitHash,
bytes calldata signedPermit
) external returns (bool isError);
function isRegisteredTransferAdditionalDataHash(bytes32 hash) external view returns (bool isRegistered);
function isRegisteredOrderAdditionalDataHash(bytes32 hash) external view returns (bool isRegistered);
/**
* =================================================
* =============== Order Transfers =================
* =================================================
*/
function fillPermittedOrderERC1155(
bytes calldata signedPermit,
OrderFillAmounts calldata orderFillAmounts,
address token,
uint256 id,
address owner,
address to,
uint256 nonce,
uint48 expiration,
bytes32 orderId,
bytes32 advancedPermitHash
) external returns (uint256 quantityFilled, bool isError);
function fillPermittedOrderERC20(
bytes calldata signedPermit,
OrderFillAmounts calldata orderFillAmounts,
address token,
address owner,
address to,
uint256 nonce,
uint48 expiration,
bytes32 orderId,
bytes32 advancedPermitHash
) external returns (uint256 quantityFilled, bool isError);
function closePermittedOrder(
address owner,
address operator,
uint256 tokenType,
address token,
uint256 id,
bytes32 orderId
) external;
function allowance(
address owner,
address operator,
uint256 tokenType,
address token,
uint256 id,
bytes32 orderId
) external view returns (uint256 amount, uint256 expiration);
/**
* =================================================
* ================ Nonce Management ===============
* =================================================
*/
function invalidateUnorderedNonce(uint256 nonce) external;
function isValidUnorderedNonce(address owner, uint256 nonce) external view returns (bool isValid);
function lockdown() external;
function masterNonce(address owner) external view returns (uint256);
/**
* =================================================
* ============== Transfer Functions ===============
* =================================================
*/
function transferFromERC721(
address from,
address to,
address token,
uint256 id
) external returns (bool isError);
function transferFromERC1155(
address from,
address to,
address token,
uint256 id,
uint256 amount
) external returns (bool isError);
function transferFromERC20(
address from,
address to,
address token,
uint256 amount
) external returns (bool isError);
/**
* =================================================
* ============ Signature Verification =============
* =================================================
*/
function domainSeparatorV4() external view returns (bytes32);
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/*
@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@(
@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@
#@@@@@@@@@@@@@@
@@@@@@@@@@@@
@@@@@@@@@@@@@@* @@@@@@@@@@@@
@@@@@@@@@@@@@@@ @ @@@@@@@@@@@@
@@@@@@@@@@@@@@@ @ @@@@@@@@@@@
@@@@@@@@@@@@@@@ @@ @@@@@@@@@@@@
@@@@@@@@@@@@@@@ #@@ @@@@@@@@@@@@/
@@@@@@@@@@@@@@. @@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@&%%%%%%%%&&@@@@@@@@@@@@@@
@@@@@@@@@@@@@@ @@@@@ @@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@ @@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@ @@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@@ @@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@@ @@@@@@@@@@@&
@@@@@@@@@@@@@@ *@@@@@@@ (@@@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@@@ @@@@@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
.@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@% @@@@@@@@@@@@@@@@@@@@@@@@(
@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
* @title CollateralizedPausableFlags
* @custom:version 1.0.0
* @author Limit Break, Inc.
* @description Collateralized Pausable Flags is an extension for contracts
* that require features to be pausable in the event of potential
* or actual threats without incurring a storage read overhead cost
* during normal operations by using contract starting balance as
* a signal for checking the paused state.
*
* Using contract balance to enable checking paused state creates an
* economic penalty for developers that deploy code that can be
* exploited as well as an economic incentive (recovery of collateral)
* for them to mitigate the threat.
*
* Developers implementing Collateralized Pausable Flags should consider
* their risk mitigation strategy and ensure funds are readily available
* for pausing if ever necessary by setting an appropriate threshold
* value and considering use of an escrow contract that can initiate the
* pause with funds.
*
* There is no restriction on the depositor as this can be easily
* circumvented through a `SELFDESTRUCT` opcode.
*
* Developers must be aware of potential outflows from the contract that
* could reduce collateral below the pausable check threshold and protect
* against those methods when pausing is required.
*/
abstract contract CollateralizedPausableFlags {
/// @dev Emitted when the pausable flags are updated
event PausableFlagsUpdated(uint256 previousFlags, uint256 newFlags);
/// @dev Thrown when an execution path requires a flag to not be paused but it is paused
error CollateralizedPausableFlags__Paused();
/// @dev Thrown when an executin path requires a flag to be paused but it is not paused
error CollateralizedPausableFlags__NotPaused();
/// @dev Thrown when a call to withdraw funds fails
error CollateralizedPausableFlags__WithdrawFailed();
/// @dev Immutable variable that defines the native funds threshold before flags are checked
uint256 private immutable nativeValueToCheckPauseState;
/// @dev Flags for current pausable state, each bit is considered a separate flag
uint256 private pausableFlags;
/// @dev Immutable pointer for the _requireNotPaused function to use based on value threshold
function(uint256) internal view immutable _requireNotPaused;
/// @dev Immutable pointer for the _requirePaused function to use based on value threshold
function(uint256) internal view immutable _requirePaused;
/// @dev Immutable pointer for the _getPausableFlags function to use based on value threshold
function() internal view returns (uint256) immutable _getPausableFlags;
constructor(uint256 _nativeValueToCheckPauseState) {
// Optimizes value check at runtime by reducing the stored immutable
// value by 1 so that greater than can be used instead of greater
// than or equal while allowing the deployment parameter to reflect
// the value at which the deployer wants to trigger pause checking.
// Example:
// Constructed with a value of 1000
// Immutable value stored is 999
// State checking enabled at 1000 units deposited because
// 1000 > 999 evaluates true
if (_nativeValueToCheckPauseState > 0) {
unchecked {
_nativeValueToCheckPauseState -= 1;
}
_requireNotPaused = _requireNotPausedWithCollateralCheck;
_requirePaused = _requirePausedWithCollateralCheck;
_getPausableFlags = _getPausableFlagsWithCollateralCheck;
} else {
_requireNotPaused = _requireNotPausedWithoutCollateralCheck;
_requirePaused = _requirePausedWithoutCollateralCheck;
_getPausableFlags = _getPausableFlagsWithoutCollateralCheck;
}
nativeValueToCheckPauseState = _nativeValueToCheckPauseState;
}
/**
* @dev Modifier to make a function callable only when the specified flags are not paused
* @dev Throws when any of the flags specified are paused
*
* @param _flags The flags to check for pause state
*/
modifier whenNotPaused(uint256 _flags) {
_requireNotPaused(_flags);
_;
}
/**
* @dev Modifier to make a function callable only when the specified flags are paused
* @dev Throws when any of the flags specified are not paused
*
* @param _flags The flags to check for pause state
*/
modifier whenPaused(uint256 _flags) {
_requirePaused(_flags);
_;
}
/**
* @dev Modifier to make a function callable only by a permissioned account
* @dev Throws when the caller does not have permission
*/
modifier onlyPausePermissionedCaller() {
_requireCallerHasPausePermissions();
_;
}
/**
* @notice Updates the pausable flags settings
*
* @dev Throws when the caller does not have permission
* @dev **NOTE:** Pausable flag settings will only take effect if contract balance exceeds
* @dev `nativeValueToPause`
*
* @dev <h4>Postconditions:</h4>
* @dev 1. address(this).balance increases by msg.value
* @dev 2. `pausableFlags` is set to the new value
* @dev 3. Emits a PausableFlagsUpdated event
*
* @param _pausableFlags The new pausable flags to set
*/
function pause(uint256 _pausableFlags) external payable onlyPausePermissionedCaller {
_setPausableFlags(_pausableFlags);
}
/**
* @notice Allows any account to supply funds for enabling the pausable checks
*
* @dev **NOTE:** The threshold check for pausable collateral does not pause
* @dev any functions unless the associated pausable flag is set.
*/
function pausableDepositCollateral() external payable {
// thank you for your contribution to safety
}
/**
* @notice Resets all pausable flags to unpaused and withdraws funds
*
* @dev Throws when the caller does not have permission
*
* @dev <h4>Postconditions:</h4>
* @dev 1. `pausableFlags` is set to zero
* @dev 2. Emits a PausableFlagsUpdated event
* @dev 3. Transfers `withdrawAmount` of native funds to `withdrawTo` if non-zero
*
* @param withdrawTo The address to withdraw the collateral to
* @param withdrawAmount The amount of collateral to withdraw
*/
function unpause(address withdrawTo, uint256 withdrawAmount) external onlyPausePermissionedCaller {
_setPausableFlags(0);
if (withdrawAmount > 0) {
(bool success, ) = withdrawTo.call{value: withdrawAmount}("");
if(!success) revert CollateralizedPausableFlags__WithdrawFailed();
}
}
/**
* @notice Returns collateralized pausable configuration information
*
* @return _nativeValueToCheckPauseState The collateral required to enable pause state checking
* @return _pausableFlags The current pausable flags set, only checked when collateral met
*/
function pausableConfigurationSettings() external view returns(
uint256 _nativeValueToCheckPauseState,
uint256 _pausableFlags
) {
unchecked {
_nativeValueToCheckPauseState = nativeValueToCheckPauseState + 1;
_pausableFlags = pausableFlags;
}
}
/**
* @notice Updates the `pausableFlags` variable and emits a PausableFlagsUpdated event
*
* @param _pausableFlags The new pausable flags to set
*/
function _setPausableFlags(uint256 _pausableFlags) internal {
uint256 previousFlags = pausableFlags;
pausableFlags = _pausableFlags;
emit PausableFlagsUpdated(previousFlags, _pausableFlags);
}
/**
* @notice Checks the current pause state of the supplied flags and reverts if any are paused
*
* @dev *Should* be called prior to any transfers of native funds out of the contract for efficiency
* @dev Throws when the native funds balance is greater than the value to enable pausing AND
* @dev one or more of the supplied `_flags` is paused.
*
* @param _flags The flags to check for pause state
*/
function _requireNotPausedWithCollateralCheck(uint256 _flags) private view {
if (_nativeBalanceSubMsgValue() > nativeValueToCheckPauseState) {
if (pausableFlags & _flags > 0) {
revert CollateralizedPausableFlags__Paused();
}
}
}
/**
* @notice Checks the current pause state of the supplied flags and reverts if any are paused
*
* @dev Throws when one or more of the supplied `_flags` is paused.
*
* @param _flags The flags to check for pause state
*/
function _requireNotPausedWithoutCollateralCheck(uint256 _flags) private view {
if (pausableFlags & _flags > 0) {
revert CollateralizedPausableFlags__Paused();
}
}
/**
* @notice Checks the current pause state of the supplied flags and reverts if none are paused
*
* @dev *Should* be called prior to any transfers of native funds out of the contract for efficiency
* @dev Throws when the native funds balance is not greater than the value to enable pausing OR
* @dev none of the supplied `_flags` are paused.
*
* @param _flags The flags to check for pause state
*/
function _requirePausedWithCollateralCheck(uint256 _flags) private view {
if (_nativeBalanceSubMsgValue() <= nativeValueToCheckPauseState) {
revert CollateralizedPausableFlags__NotPaused();
} else if (pausableFlags & _flags == 0) {
revert CollateralizedPausableFlags__NotPaused();
}
}
/**
* @notice Checks the current pause state of the supplied flags and reverts if none are paused
*
* @dev Throws when none of the supplied `_flags` are paused.
*
* @param _flags The flags to check for pause state
*/
function _requirePausedWithoutCollateralCheck(uint256 _flags) private view {
if (pausableFlags & _flags == 0) {
revert CollateralizedPausableFlags__NotPaused();
}
}
/**
* @notice Returns the current state of the pausable flags
*
* @dev Will return zero if the native funds balance is not greater than the value to enable pausing
*
* @return _pausableFlags The current state of the pausable flags
*/
function _getPausableFlagsWithCollateralCheck() private view returns(uint256 _pausableFlags) {
if (_nativeBalanceSubMsgValue() > nativeValueToCheckPauseState) {
_pausableFlags = pausableFlags;
}
}
/**
* @notice Returns the current state of the pausable flags
*
* @return _pausableFlags The current state of the pausable flags
*/
function _getPausableFlagsWithoutCollateralCheck() private view returns(uint256 _pausableFlags) {
_pausableFlags = pausableFlags;
}
/**
* @notice Returns the current contract balance minus the value sent with the call
*
* @dev This is expected to be the contract balance at the beginning of a function call
* @dev to efficiently determine whether a contract has the necessary collateral to enable
* @dev the pausable flags checking for contracts that hold native token funds.
* @dev This should **NOT** be used in any way to determine current balance for contract logic
* @dev other than its intended purpose for pause state checking activation.
*/
function _nativeBalanceSubMsgValue() private view returns (uint256 _value) {
unchecked {
_value = address(this).balance - msg.value;
}
}
/**
* @dev To be implemented by an inheriting contract for authorization to `pause` and `unpause`
* @dev functions as well as any functions in the inheriting contract that utilize the
* @dev `onlyPausePermissionedCaller` modifier.
*
* @dev Implementing contract function **MUST** throw when the caller is not permissioned
*/
function _requireCallerHasPausePermissions() internal view virtual;
}// 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.6.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.8.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*
* _Available since v3.1._
*/
interface IERC1155 is IERC165 {
/**
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
*/
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/
event URI(string value, uint256 indexed id);
/**
* @dev Returns the amount of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) external view returns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
external
view
returns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address account, address operator) external view returns (bool);
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes calldata data
) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../Strings.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV // Deprecated in v4.8
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10**64) {
value /= 10**64;
result += 64;
}
if (value >= 10**32) {
value /= 10**32;
result += 32;
}
if (value >= 10**16) {
value /= 10**16;
result += 16;
}
if (value >= 10**8) {
value /= 10**8;
result += 8;
}
if (value >= 10**4) {
value /= 10**4;
result += 4;
}
if (value >= 10**2) {
value /= 10**2;
result += 2;
}
if (value >= 10**1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}{
"remappings": [
"@openzeppelin/=lib/openzeppelin-contracts/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"murky/=lib/murky/src/",
"erc721a/=lib/ERC721A/",
"@limitbreak/permit-c/=lib/PermitC/src/",
"@opensea/tstorish/=lib/tstorish/src/",
"@rari-capital/solmate/=lib/PermitC/lib/solmate/",
"ERC721A/=lib/ERC721A/contracts/",
"PermitC/=lib/PermitC/",
"erc4626-tests/=lib/PermitC/lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-gas-metering/=lib/PermitC/lib/forge-gas-metering/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin/=lib/PermitC/lib/openzeppelin-contracts/contracts/",
"solady/=lib/PermitC/lib/forge-gas-metering/lib/solady/",
"solmate/=lib/PermitC/lib/solmate/src/",
"tstorish/=lib/tstorish/src/"
],
"optimizer": {
"enabled": true,
"runs": 777
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"defaultOwner","type":"address"},{"internalType":"address","name":"eoaRegistry_","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"address","name":"validatorConfiguration","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CollateralizedPausableFlags__NotPaused","type":"error"},{"inputs":[],"name":"CollateralizedPausableFlags__Paused","type":"error"},{"inputs":[],"name":"CollateralizedPausableFlags__WithdrawFailed","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__AuthorizationDisabledForCollection","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__CallerDoesNotOwnList","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__CallerMustBeAnAuthorizer","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__CallerMustBeWhitelisted","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__CallerMustHaveElevatedPermissionsForSpecifiedNFT","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__InvalidConstructorArgs","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__InvalidTransferSecurityLevel","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__ListDoesNotExist","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__ListOwnershipCannotBeTransferredToZeroAddress","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__OperatorIsBlacklisted","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__ReceiverAccountIsFrozen","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__ReceiverMustNotHaveDeployedCode","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__ReceiverProofOfEOASignatureUnverified","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__SenderAccountIsFrozen","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__TokenIsSoulbound","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__TokenTypesDoNotMatch","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__WildcardOperatorsCannotBeAuthorizedForCollection","type":"error"},{"inputs":[],"name":"OnlyDirectCalls","type":"error"},{"inputs":[],"name":"Ownable__CallerIsNotOwner","type":"error"},{"inputs":[],"name":"Ownable__NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"PermitC__AmountExceedsStorageMaximum","type":"error"},{"inputs":[],"name":"PermitC__ApprovalTransferExceededPermittedAmount","type":"error"},{"inputs":[],"name":"PermitC__ApprovalTransferPermitExpiredOrUnset","type":"error"},{"inputs":[],"name":"PermitC__CallerMustBeOwnerOrOperator","type":"error"},{"inputs":[],"name":"PermitC__InvalidTokenType","type":"error"},{"inputs":[],"name":"PermitC__NonceAlreadyUsedOrRevoked","type":"error"},{"inputs":[],"name":"PermitC__NonceNotUsedOrRevoked","type":"error"},{"inputs":[],"name":"PermitC__OrderIsEitherCancelledOrFilled","type":"error"},{"inputs":[],"name":"PermitC__SignatureTransferExceededPermitExpired","type":"error"},{"inputs":[],"name":"PermitC__SignatureTransferExceededPermittedAmount","type":"error"},{"inputs":[],"name":"PermitC__SignatureTransferInvalidSignature","type":"error"},{"inputs":[],"name":"PermitC__SignatureTransferPermitHashNotRegistered","type":"error"},{"inputs":[],"name":"PermitC__UnableToFillMinimumRequestedQuantity","type":"error"},{"inputs":[],"name":"TStoreAlreadyActivated","type":"error"},{"inputs":[],"name":"TStoreNotSupported","type":"error"},{"inputs":[],"name":"TloadTestContractDeploymentFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"AccountFrozenForCollection","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"AccountUnfrozenForCollection","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"kind","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"AddedAccountToList","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"kind","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"codehash","type":"bytes32"}],"name":"AddedCodeHashToList","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":true,"internalType":"uint120","name":"id","type":"uint120"}],"name":"AppliedListToCollection","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint200","name":"amount","type":"uint200"},{"indexed":false,"internalType":"uint48","name":"expiration","type":"uint48"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"string","name":"name","type":"string"}],"name":"CreatedList","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"Lockdown","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"orderId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"wasCancellation","type":"bool"}],"name":"OrderClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"orderId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"OrderFilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"orderId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"uint256","name":"fillableQuantity","type":"uint256"}],"name":"OrderOpened","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"orderId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountRestoredToOrder","type":"uint256"}],"name":"OrderRestored","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":"uint256","name":"previousFlags","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFlags","type":"uint256"}],"name":"PausableFlagsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"ReassignedListOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"kind","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"RemovedAccountFromList","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"kind","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"codehash","type":"bytes32"}],"name":"RemovedCodeHashFromList","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"SetAccountFreezingModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":false,"internalType":"bool","name":"disabled","type":"bool"},{"indexed":false,"internalType":"bool","name":"authorizersCannotSetWildcardOperators","type":"bool"}],"name":"SetAuthorizationModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":false,"internalType":"uint16","name":"tokenType","type":"uint16"}],"name":"SetTokenType","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":false,"internalType":"uint8","name":"level","type":"uint8"}],"name":"SetTransferSecurityLevel","type":"event"},{"inputs":[],"name":"__activateTstore","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"addAccountsToAuthorizers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"addAccountsToBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"addAccountsToWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"bytes32[]","name":"codehashes","type":"bytes32[]"}],"name":"addCodeHashesToBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"bytes32[]","name":"codehashes","type":"bytes32[]"}],"name":"addCodeHashesToWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"afterAuthorizedTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"afterAuthorizedTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"afterAuthorizedTransferWithAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenType","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"allowedAmount","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenType","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes32","name":"orderId","type":"bytes32"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"allowedAmount","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"applyCollectionTransferPolicy","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint120","name":"id","type":"uint120"}],"name":"applyListToCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenType","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint200","name":"amount","type":"uint200"},{"internalType":"uint48","name":"expiration","type":"uint48"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"beforeAuthorizedTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"beforeAuthorizedTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"beforeAuthorizedTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"beforeAuthorizedTransferWithAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenType","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes32","name":"orderId","type":"bytes32"}],"name":"closePermittedOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"}],"name":"createList","outputs":[{"internalType":"uint120","name":"id","type":"uint120"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint120","name":"sourceListId","type":"uint120"}],"name":"createListCopy","outputs":[{"internalType":"uint120","name":"id","type":"uint120"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"domainSeparatorV4","outputs":[{"internalType":"bytes32","name":"domainSeparator","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"signedPermit","type":"bytes"},{"components":[{"internalType":"uint256","name":"orderStartAmount","type":"uint256"},{"internalType":"uint256","name":"requestedFillAmount","type":"uint256"},{"internalType":"uint256","name":"minimumFillAmount","type":"uint256"}],"internalType":"struct OrderFillAmounts","name":"orderFillAmounts","type":"tuple"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"bytes32","name":"orderId","type":"bytes32"},{"internalType":"bytes32","name":"advancedPermitHash","type":"bytes32"}],"name":"fillPermittedOrderERC1155","outputs":[{"internalType":"uint256","name":"quantityFilled","type":"uint256"},{"internalType":"bool","name":"isError","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"signedPermit","type":"bytes"},{"components":[{"internalType":"uint256","name":"orderStartAmount","type":"uint256"},{"internalType":"uint256","name":"requestedFillAmount","type":"uint256"},{"internalType":"uint256","name":"minimumFillAmount","type":"uint256"}],"internalType":"struct OrderFillAmounts","name":"orderFillAmounts","type":"tuple"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"bytes32","name":"orderId","type":"bytes32"},{"internalType":"bytes32","name":"advancedPermitHash","type":"bytes32"}],"name":"fillPermittedOrderERC20","outputs":[{"internalType":"uint256","name":"quantityFilled","type":"uint256"},{"internalType":"bool","name":"isError","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"address[]","name":"accountsToFreeze","type":"address[]"}],"name":"freezeAccountsForCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"}],"name":"getAuthorizerAccounts","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"}],"name":"getAuthorizerAccountsByCollection","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"}],"name":"getBlacklistedAccounts","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"}],"name":"getBlacklistedAccountsByCollection","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"}],"name":"getBlacklistedCodeHashes","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"}],"name":"getBlacklistedCodeHashesByCollection","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"}],"name":"getCollectionSecurityPolicy","outputs":[{"components":[{"internalType":"bool","name":"disableAuthorizationMode","type":"bool"},{"internalType":"bool","name":"authorizersCannotSetWildcardOperators","type":"bool"},{"internalType":"uint8","name":"transferSecurityLevel","type":"uint8"},{"internalType":"uint120","name":"listId","type":"uint120"},{"internalType":"bool","name":"enableAccountFreezingMode","type":"bool"},{"internalType":"uint16","name":"tokenType","type":"uint16"}],"internalType":"struct CollectionSecurityPolicyV3","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"}],"name":"getFrozenAccountsByCollection","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"}],"name":"getWhitelistedAccounts","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"}],"name":"getWhitelistedAccountsByCollection","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"}],"name":"getWhitelistedCodeHashes","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"}],"name":"getWhitelistedCodeHashesByCollection","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"invalidateUnorderedNonce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address","name":"account","type":"address"}],"name":"isAccountAuthorizer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"isAccountAuthorizerOfCollection","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address","name":"account","type":"address"}],"name":"isAccountBlacklisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"isAccountBlacklistedByCollection","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"isAccountFrozenForCollection","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address","name":"account","type":"address"}],"name":"isAccountWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"isAccountWhitelistedByCollection","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"bytes32","name":"codehash","type":"bytes32"}],"name":"isCodeHashBlacklisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"bytes32","name":"codehash","type":"bytes32"}],"name":"isCodeHashBlacklistedByCollection","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"bytes32","name":"codehash","type":"bytes32"}],"name":"isCodeHashWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"bytes32","name":"codehash","type":"bytes32"}],"name":"isCodeHashWhitelistedByCollection","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"isRegisteredOrderAdditionalDataHash","outputs":[{"internalType":"bool","name":"isRegistered","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"isRegisteredTransferAdditionalDataHash","outputs":[{"internalType":"bool","name":"isRegistered","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"isValidUnorderedNonce","outputs":[{"internalType":"bool","name":"isValid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isVerifiedEOA","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastListId","outputs":[{"internalType":"uint120","name":"","type":"uint120"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"","type":"uint120"}],"name":"listOwners","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockdown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"masterNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pausableConfigurationSettings","outputs":[{"internalType":"uint256","name":"_nativeValueToCheckPauseState","type":"uint256"},{"internalType":"uint256","name":"_pausableFlags","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pausableDepositCollateral","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pausableFlags","type":"uint256"}],"name":"pause","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"permitAmount","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"transferAmount","type":"uint256"},{"internalType":"bytes","name":"signedPermit","type":"bytes"}],"name":"permitTransferFromERC1155","outputs":[{"internalType":"bool","name":"isError","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"permitAmount","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"transferAmount","type":"uint256"},{"internalType":"bytes","name":"signedPermit","type":"bytes"}],"name":"permitTransferFromERC20","outputs":[{"internalType":"bool","name":"isError","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"signedPermit","type":"bytes"}],"name":"permitTransferFromERC721","outputs":[{"internalType":"bool","name":"isError","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"permitAmount","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"transferAmount","type":"uint256"},{"internalType":"bytes32","name":"additionalData","type":"bytes32"},{"internalType":"bytes32","name":"advancedPermitHash","type":"bytes32"},{"internalType":"bytes","name":"signedPermit","type":"bytes"}],"name":"permitTransferFromWithAdditionalDataERC1155","outputs":[{"internalType":"bool","name":"isError","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"permitAmount","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"transferAmount","type":"uint256"},{"internalType":"bytes32","name":"additionalData","type":"bytes32"},{"internalType":"bytes32","name":"advancedPermitHash","type":"bytes32"},{"internalType":"bytes","name":"signedPermit","type":"bytes"}],"name":"permitTransferFromWithAdditionalDataERC20","outputs":[{"internalType":"bool","name":"isError","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes32","name":"additionalData","type":"bytes32"},{"internalType":"bytes32","name":"advancedPermitHash","type":"bytes32"},{"internalType":"bytes","name":"signedPermit","type":"bytes"}],"name":"permitTransferFromWithAdditionalDataERC721","outputs":[{"internalType":"bool","name":"isError","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address","name":"newOwner","type":"address"}],"name":"reassignOwnershipOfList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"additionalDataTypeString","type":"string"}],"name":"registerAdditionalDataHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"removeAccountsFromAuthorizers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"removeAccountsFromBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"removeAccountsFromWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"bytes32[]","name":"codehashes","type":"bytes32[]"}],"name":"removeCodeHashesFromBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"bytes32[]","name":"codehashes","type":"bytes32[]"}],"name":"removeCodeHashesFromWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"}],"name":"renounceOwnershipOfList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint16","name":"tokenType","type":"uint16"}],"name":"setTokenTypeOfCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint8","name":"level","type":"uint8"},{"internalType":"bool","name":"disableAuthorizationMode","type":"bool"},{"internalType":"bool","name":"disableWildcardOperators","type":"bool"},{"internalType":"bool","name":"enableAccountFreezingMode","type":"bool"}],"name":"setTransferSecurityLevelOfCollection","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":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFromERC1155","outputs":[{"internalType":"bool","name":"isError","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFromERC20","outputs":[{"internalType":"bool","name":"isError","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"transferFromERC721","outputs":[{"internalType":"bool","name":"isError","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"level","type":"uint256"}],"name":"transferSecurityPolicies","outputs":[{"internalType":"uint256","name":"callerConstraints","type":"uint256"},{"internalType":"uint256","name":"receiverConstraints","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"address[]","name":"accountsToUnfreeze","type":"address[]"}],"name":"unfreezeAccountsForCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"withdrawTo","type":"address"},{"internalType":"uint256","name":"withdrawAmount","type":"uint256"}],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenType","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint200","name":"amount","type":"uint200"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint48","name":"approvalExpiration","type":"uint48"},{"internalType":"uint48","name":"sigDeadline","type":"uint48"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"bytes","name":"signedPermit","type":"bytes"}],"name":"updateApprovalBySignature","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"validateTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"validateTransfer","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"validateTransfer","outputs":[],"stateMutability":"view","type":"function"}]Contract Creation Code
61022060405234801562000011575f80fd5b50604051620065fe380380620065fe8339810160408190526200003491620005fa565b828286836001600160a01b031663c8dc9bc46040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000074573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200009a919062000697565b8383825f620000a8620002aa565b90506001600160a01b038116620000d257604051632aea588760e01b815260040160405180910390fd5b5f620000de82620002c3565b1515608052506001600160a01b031660a052620000fb3362000325565b801562000149576200037d602090811b62002c26176001600160401b0390811660e052620003b1821b62002c7317811661010052620003fb90911b62002cd91716610120525f190162000188565b62000412602090811b62002d0c176001600160401b0390811660e052620003d6821b62002cb5178116610100526200043690911b62002d2f1716610120525b60c0528151602080840191909120610180528151908201206101a052466101605262000217610180516101a051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b61014052506200022990508262000325565b505050506001600160a01b03851615806200024b57506001600160a01b038416155b156200026a5760405163c56e5d7360e01b815260040160405180910390fd5b62000275856200043c565b5050506001600160a01b0316610200525069040303020203020100026101c05269030201020100000000006101e052620006cf565b5f696002601e613d5c3d52f35f52600a60165ff0905090565b5f816001600160a01b0316600a5a620002dd9190620006af565b6040515f8181818686fa925050503d805f811462000317576040519150601f19603f3d011682016040523d82523d5f602084013e6200031c565b606091505b50909392505050565b5f80546001600160a01b03838116610100818102610100600160a81b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b60c0513447031115620003ae57600154811615620003ae57604051636623b92d60e11b815260040160405180910390fd5b50565b60c05134470311620003d65760405163fd2c901360e01b815260040160405180910390fd5b80600154165f03620003ae5760405163fd2c901360e01b815260040160405180910390fd5b60c0515f9034470311156200040f57506001545b90565b600154811615620003ae57604051636623b92d60e11b815260040160405180910390fd5b60015490565b5f80805260096020527fec8156718a8372b1db44bb411437d0870f3e3790d4a08526d024ce1b0b668f6b80546001600160a01b0384166001600160a01b031990911617905560405181907f5cc365f89543268cb9f25c255f7f610e9147e733c589bc2732279575f125be1490620004d3906020808252600c908201526b1111519055531508131254d560a21b604082015260600190565b60405180910390a26040516001600160a01b038316906001600160781b038316907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e27367905f90a35050565b80516001600160a01b038116811462000534575f80fd5b919050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f8301126200055d575f80fd5b81516001600160401b03808211156200057a576200057a62000539565b604051601f8301601f19908116603f01168101908282118183101715620005a557620005a562000539565b8160405283815260209250866020858801011115620005c2575f80fd5b5f91505b83821015620005e55785820183015181830184015290820190620005c6565b5f602085830101528094505050505092915050565b5f805f805f60a086880312156200060f575f80fd5b6200061a866200051d565b94506200062a602087016200051d565b60408701519094506001600160401b038082111562000647575f80fd5b6200065589838a016200054d565b945060608801519150808211156200066b575f80fd5b506200067a888289016200054d565b9250506200068b608087016200051d565b90509295509295909350565b5f60208284031215620006a8575f80fd5b5051919050565b5f82620006ca57634e487b7160e01b5f52601260045260245ffd5b500490565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e05161020051615e30620007ce5f395f6120ce01525f8181610dc70152613e9f01525f8181610d9a0152613e6801525f613db701525f613d8f01525f613d1601525f613d3e01525f50505f50505f81816114b701528181611531015281816115c8015281816118c901528181611a6801528181611c0101528181611f9d01528181612325015281816125cc0152818161264c015261279a01525f818161138601528181612c2801528181612c750152612cdc01525f611eb801525f8181611e6a015281816148e10152614e9c0152615e305ff3fe6080604052600436106105c1575f3560e01c80638254fcb7116102f0578063b97f6f8b11610191578063ddae38f2116100e7578063e34fda8511610092578063f7a2000a1161006d578063f7a2000a14611374578063fb2de5d7146113ae578063ffbcb4aa146113cd575f80fd5b8063e34fda85146105e4578063e991dc3014611336578063f2fde38b14611355575f80fd5b8063df21dc1d116100c2578063df21dc1d146112c4578063df5fd29a146112f8578063e07cb24014611317575f80fd5b8063ddae38f214611267578063de02cbb114611286578063def0125b146112a5575f80fd5b8063d415f62f11610147578063db5f30a811610122578063db5f30a81461120a578063dd71105d14611229578063dda964e314611248575f80fd5b8063d415f62f14611184578063d5dc239a146111cc578063db188e63146111eb575f80fd5b8063c435f43511610177578063c435f43514611127578063caee23ea14611146578063cfea7ecf14611165575f80fd5b8063b97f6f8b146110e9578063bf7bfd7e14611108575f80fd5b8063a5d56b4611610246578063b67d8f99116101fc578063b89c4b0d116101d7578063b89c4b0d14610f78578063b8dcc68f14610f97578063b955455214610fb6575f80fd5b8063b67d8f9914610ee8578063b6e39ba114610f07578063b70510f514610f26575f80fd5b8063ad1ff6851161022c578063ad1ff68514610e76578063ae602f4414610e95578063b3992ab114610ec9575f80fd5b8063a5d56b4614610e0c578063a87b03b614610e2b575f80fd5b80638da5cb5b116102a6578063982d03c011610281578063982d03c014610d5d5780639c2a9c6f14610d7c578063a1cc5cc114610ded575f80fd5b80638da5cb5b14610cea5780638e28800f14610d1f5780639340a7cc14610d3e575f80fd5b806389631626116102d65780638963162614610c8d57806389a9c85514610cac5780638b6ee86514610ccb575f80fd5b80638254fcb714610c4057806386e1177414610c6e575f80fd5b80633e5c139d116104655780636498c045116103bb578063725d07c5116103665780637bac97de116103415780637bac97de14610be35780637c1e14b414610c025780637df81b9014610c21575f80fd5b8063725d07c514610b8e5780637423eb3c14610bad57806378e890ba14610bc1575f80fd5b8063715018a611610396578063715018a614610b3c5780637161ac8d14610b5057806371be859d14610b6f575f80fd5b80636498c04514610adf5780636971082814610afe5780636bfab91d14610b1d575f80fd5b80634c9d0b451161041b578063539d2602116103f6578063539d260214610a595780635e17263d14610a785780635ed5917f14610ac0575f80fd5b80634c9d0b45146109fc5780635079331514610a1b578063515f7b2814610a3a575f80fd5b80633f6560ee1161044b5780633f6560ee1461098a578063409dc573146109be5780634be52a89146109dd575f80fd5b80633e5c139d146109575780633e8a0bc914610976575f80fd5b80631854b2411161051a5780632c7fe70a116104d05780633779e6fd116104ab5780633779e6fd146108e55780633a0e3160146109195780633cda743a14610938575f80fd5b80632c7fe70a146108885780632eb0b98a146108a7578063317e3e8d146108c6575f80fd5b806323c992621161050057806323c9926214610813578063285fb8c81461084a57806328cc113114610869575f80fd5b80631854b241146107a55780631f2fdc79146107c4575f80fd5b80630f59197d1161057a578063136439dd11610555578063136439dd1461071457806316a17ce01461072757806316f18d7414610779575f80fd5b80630f59197d146106aa57806310b5c6a0146106c957806312d3848a146106f5575f80fd5b8063057497cb116105aa578063057497cb1461061a5780630ad388991461066c5780630e14021a1461068b575f80fd5b806301549930146105c557806301ffc9a7146105e6575b5f80fd5b3480156105d0575f80fd5b506105e46105df366004614fbf565b6113fb565b005b3480156105f1575f80fd5b5061060561060036600461500e565b611423565b60405190151581526020015b60405180910390f35b348015610625575f80fd5b5061060561063436600461504b565b6001600160781b0382165f908152600c602090815260408083206001600160a01b038516845260040190915290205460ff1692915050565b348015610677575f80fd5b506105e461068636600461507c565b6114a2565b348015610696575f80fd5b506106056106a53660046150d3565b6114af565b3480156106b5575f80fd5b506106056106c4366004615176565b61151f565b3480156106d4575f80fd5b506106e86106e336600461522e565b61159d565b6040516106119190615247565b348015610700575f80fd5b5061060561070f366004615293565b6115c0565b6105e46107223660046152e4565b61162e565b348015610732575f80fd5b5061060561074136600461504b565b6001600160781b0382165f908152600b602090815260408083206001600160a01b038516845260040190915290205460ff1692915050565b348015610784575f80fd5b5061079861079336600461507c565b61163f565b60405161061191906152fb565b3480156107b0575f80fd5b506105e46107bf366004615293565b611673565b3480156107cf575f80fd5b506106056107de366004615332565b6001600160a01b039091165f908152600660209081526040808320600885901c845290915290205460ff9091161c6001161590565b34801561081e575f80fd5b50600854610832906001600160781b031681565b6040516001600160781b039091168152602001610611565b348015610855575f80fd5b506105e461086436600461535a565b611686565b348015610874575f80fd5b506105e461088336600461539a565b611691565b348015610893575f80fd5b506106056108a2366004615332565b61169e565b3480156108b2575f80fd5b506105e46108c1366004614fbf565b6116e9565b3480156108d1575f80fd5b506105e46108e03660046153d7565b61174a565b3480156108f0575f80fd5b506109046108ff366004615472565b6118b6565b60408051928352901515602083015201610611565b348015610924575f80fd5b506105e4610933366004615332565b611942565b348015610943575f80fd5b5061060561095236600461552d565b611953565b348015610962575f80fd5b506106e861097136600461507c565b6119a0565b348015610981575f80fd5b506105e46119d4565b348015610995575f80fd5b506109a96109a4366004615547565b611a11565b60408051928352602083019190915201610611565b3480156109c9575f80fd5b506105e46109d8366004614fbf565b611a31565b3480156109e8575f80fd5b506106056109f7366004615598565b611a56565b348015610a07575f80fd5b50610798610a1636600461522e565b611ad1565b348015610a26575f80fd5b506105e4610a3536600461552d565b611af7565b348015610a45575f80fd5b506105e4610a54366004614fbf565b611b04565b348015610a64575f80fd5b506105e4610a7336600461565b565b611b29565b348015610a83575f80fd5b50610605610a923660046156f7565b6001600160781b03919091165f908152600c6020908152604080832093835260059093019052205460ff1690565b348015610acb575f80fd5b50610605610ada366004615711565b611bf9565b348015610aea575f80fd5b506109a9610af936600461579d565b611c68565b348015610b09575f80fd5b506105e4610b18366004614fbf565b611c8a565b348015610b28575f80fd5b506105e4610b3736600461504b565b611cea565b348015610b47575f80fd5b506105e4611d1b565b348015610b5b575f80fd5b50610798610b6a36600461522e565b611d2e565b348015610b7a575f80fd5b506105e4610b893660046157f8565b611d54565b348015610b99575f80fd5b506106e8610ba836600461507c565b611e25565b348015610bb8575f80fd5b506105e4611e48565b348015610bcc575f80fd5b50610bd5611f07565b604051908152602001610611565b348015610bee575f80fd5b50610605610bfd36600461552d565b611f15565b348015610c0d575f80fd5b506105e4610c1c36600461535a565b611f62565b348015610c2c575f80fd5b50610605610c3b366004615813565b611f95565b348015610c4b575f80fd5b50610605610c5a3660046152e4565b5f9081526004602052604090205460ff1690565b348015610c79575f80fd5b506105e4610c88366004615332565b612003565b348015610c98575f80fd5b506106e8610ca736600461522e565b61208a565b348015610cb7575f80fd5b50610605610cc636600461507c565b6120ad565b348015610cd6575f80fd5b506105e4610ce536600461522e565b612139565b348015610cf5575f80fd5b505f5461010090046001600160a01b03165b6040516001600160a01b039091168152602001610611565b348015610d2a575f80fd5b50610605610d3936600461552d565b612143565b348015610d49575f80fd5b50610798610d5836600461507c565b612190565b348015610d68575f80fd5b506106e8610d7736600461507c565b6121c4565b348015610d87575f80fd5b506109a9610d963660046152e4565b60ff7f000000000000000000000000000000000000000000000000000000000000000060039290921b91821c8116927f000000000000000000000000000000000000000000000000000000000000000090921c1690565b348015610df8575f80fd5b506105e4610e07366004614fbf565b6121f8565b348015610e17575f80fd5b506105e4610e26366004614fbf565b61221d565b348015610e36575f80fd5b50610605610e4536600461552d565b6001600160a01b039182165f908152600e602090815260408083209390941682526002909201909152205460ff1690565b348015610e81575f80fd5b506105e4610e9036600461579d565b612240565b348015610ea0575f80fd5b50610d07610eaf36600461522e565b60096020525f90815260409020546001600160a01b031681565b348015610ed4575f80fd5b50610605610ee336600461585b565b612313565b348015610ef3575f80fd5b50610605610f02366004615332565b61238e565b348015610f12575f80fd5b506105e4610f21366004615332565b6123d6565b348015610f31575f80fd5b50610605610f4036600461504b565b6001600160781b0382165f908152600d602090815260408083206001600160a01b038516845260040190915290205460ff1692915050565b348015610f83575f80fd5b506105e4610f92366004615332565b6123dc565b348015610fa2575f80fd5b50610832610fb13660046158d9565b6123e8565b348015610fc1575f80fd5b50611088610fd036600461507c565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a0810191909152506001600160a01b03165f908152600a6020908152604091829020825160c081018452905460ff8082161515835261010082048116151593830193909352620100008104831693820193909352630100000083046001600160781b03166060820152600160901b830490911615156080820152600160981b90910461ffff1660a082015290565b60405161061191905f60c08201905082511515825260208301511515602083015260ff60408401511660408301526001600160781b03606084015116606083015260808301511515608083015261ffff60a08401511660a083015292915050565b3480156110f4575f80fd5b506105e4611103366004615918565b6124b5565b348015611113575f80fd5b506105e461112236600461597a565b6124d5565b348015611132575f80fd5b506105e46111413660046152e4565b612582565b348015611151575f80fd5b506105e4611160366004615813565b61258c565b348015611170575f80fd5b5061090461117f3660046159a2565b6125b9565b34801561118f575f80fd5b5061060561119e3660046156f7565b6001600160781b03919091165f908152600b6020908152604080832093835260059093019052205460ff1690565b3480156111d7575f80fd5b506106056111e6366004615a53565b612644565b3480156111f6575f80fd5b506105e46112053660046158d9565b6126b2565b348015611215575f80fd5b506105e4611224366004615aeb565b612786565b348015611234575f80fd5b50610605611243366004615813565b612792565b348015611253575f80fd5b506106e861126236600461522e565b6127f5565b348015611272575f80fd5b506105e4611281366004614fbf565b612818565b348015611291575f80fd5b506108326112a0366004615b24565b61283d565b3480156112b0575f80fd5b506105e46112bf366004614fbf565b6129d8565b3480156112cf575f80fd5b50610bd56112de36600461507c565b6001600160a01b03165f9081526007602052604090205490565b348015611303575f80fd5b506105e4611312366004614fbf565b6129fb565b348015611322575f80fd5b506105e46113313660046157f8565b612a5c565b348015611341575f80fd5b506106e861135036600461507c565b612b2a565b348015611360575f80fd5b506105e461136f36600461507c565b612b5e565b34801561137f575f80fd5b50600180547f0000000000000000000000000000000000000000000000000000000000000000909101906109a9565b3480156113b9575f80fd5b506105e46113c8366004615b6b565b612b96565b3480156113d8575f80fd5b506106056113e73660046152e4565b5f9081526005602052604090205460ff1690565b6001600160781b0383165f908152600b6020526040812061141e91858585612d35565b505050565b5f6001600160e01b03198216158061144b57506001600160e01b03198216630dd9a30760e11b145b8061146657506001600160e01b03198216633016020d60e21b145b8061148157506001600160e01b031982166389a9c85560e01b145b8061149c57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6114ac815f6123dc565b50565b5f6114de60107f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b6114f26104838c8c8b8d8c8c8b8b8b612dfd565b6114ff8b87878d88612ece565b9050801561151157611511868a612f6b565b9a9950505050505050505050565b5f8361152a81612fc0565b61155860107f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b61156b8e8e8d8f8e8e8d8b8b8f8f612fee565b8c6115798f8b8b848c612ece565b9250821561158b5761158b8a8e612f6b565b50509c9b505050505050505050505050565b6001600160781b0381165f908152600b6020526040902060609061149c90613004565b5f6115ef60027f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b5f611600876104838787875f613010565b905061160f8588888787612ece565b915081156116245761162481885f86816130ec565b5095945050505050565b6116366131c7565b6114ac816131cf565b6001600160a01b0381165f908152600a602052604090205460609061149c90630100000090046001600160781b0316611d2e565b61167f8585858561258c565b5050505050565b61141e838383611f62565b61141e600184845f613214565b6001600160a01b0382165f908152600a6020908152604080832054630100000090046001600160781b03168352600b825280832084845260050190915281205460ff165b9392505050565b61141e600c5f856001600160781b03166001600160781b031681526020019081526020015f206001858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061327892505050565b600960ff8516111561176f576040516317c5702360e01b815260040160405180910390fd5b6117788561332a565b6001600160a01b0385165f818152600a6020908152604091829020805462ff00ff19166201000060ff8a1690810260ff1916919091178815151772ff00000000000000000000000000000000ff0019166101008815150272ff000000000000000000000000000000000000191617600160901b871515021790915591519182527fb39d8f1e6f05413a407e46fc950eb92e9f5b3d65a47c3f0bdc7a2741a6ec0f7d910160405180910390a260408051841515815283151560208201526001600160a01b038716917f9c615afab54584e53810beb24cced6ca36919dfc62bff2d4a0d244906c41c2ac910160405180910390a2846001600160a01b03167f9c6e8620d0004b9dd8b49560e2de8ced6f409f529cc23d0bb9e5a106d5c43242826040516118a7911515815260200190565b60405180910390a25050505050565b5f80826118c28161339e565b6118f060407f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b5f6119038f8f8f8f8f8f8e8e8e8e6133cc565b9050611917818e8e8e8e8e8c612ece6133f1565b9094509250821561193057611930818b888760016130ec565b50509b509b9950505050505050505050565b61194f600183835f613214565b5050565b6001600160a01b038281165f908152600a6020908152604080832054630100000090046001600160781b03168352600d82528083209385168352600490930190529081205460ff166116e2565b6001600160a01b0381165f908152600a602052604090205460609061149c90630100000090046001600160781b03166127f5565b335f8181526007602052604080822080546001019055517f8e8cebe67607ce50a14a2e3261437f641a7b33ecc053e3d9c90b25ae5e66c6569190a2565b5f80611a236002888888888887613537565b915091509550959350505050565b6001600160781b0383165f908152600c6020526040902061141e9060018585856135a6565b5f83611a6181612fc0565b611a8f60207f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b611aa28d5f8d8f8e8e8d8b8b8f8f61364f565b611aaf8d8a8a5f8b613664565b91508115611ac157611ac1898d612f6b565b509b9a5050505050505050505050565b6001600160781b0381165f908152600c6020526040902060609061149c90600201613004565b61194f82825f6001613214565b6001600160781b0383165f908152600c6020526040902061141e90600185858561376e565b8365ffffffffffff16421115611b5257604051630104f5db60e71b815260040160405180910390fd5b611b5b8b613814565b611b65838961384d565b611bc5611bbd611bb88d8d8d8c6001600160c81b03168e8d8d65ffffffffffff168d65ffffffffffff1660075f8f6001600160a01b03166001600160a01b031681526020019081526020015f20546138a1565b613941565b83838661398d565b65ffffffffffff851615611bd95784611bdb565b425b9450611bec8b8b8b8a89888c613a56565b5050505050505050505050565b5f611c2860087f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b611c3e6102d18a8a60018b8b8b60018b8b612dfd565b611c4a85858b8b613b04565b90508015611c5c57611c5c8588612f6b565b98975050505050505050565b5f80611c7a6003898989898989613537565b915091505b965096945050505050565b61141e600b5f856001600160781b03166001600160781b031681526020019081526020015f205f858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061327892505050565b6001600160a01b038116611d11576040516303e9dcb360e31b815260040160405180910390fd5b61194f8282613b8d565b611d23613c03565b611d2c5f613c32565b565b6001600160781b0381165f908152600b6020526040902060609061149c90600201613004565b611d5d8361332a565b6001600160a01b0383165f908152600e60205260408120905b8281101561167f575f848483818110611d9157611d91615ba6565b9050602002016020810190611da6919061507c565b9050611db28382613ca1565b15611e1c57806001600160a01b0316866001600160a01b03167f1138edbff75f319641eb242dbcacee294ebc2a473eb6aa1454a7706da5bf96b060405160405180910390a36001600160a01b0381165f9081526002840160205260409020805460ff191660011790555b50600101611d76565b6001600160a01b0381165f908152600e6020526040902060609061149c90613004565b333214611e685760405163096650c560e21b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000080611e9557505f5460ff165b15611eb357604051630f45b98b60e41b815260040160405180910390fd5b611edc7f0000000000000000000000000000000000000000000000000000000000000000613cb5565b611ef9576040516370a4078f60e01b815260040160405180910390fd5b5f805460ff19166001179055565b5f611f10613d13565b905090565b6001600160a01b038281165f908152600a6020908152604080832054630100000090046001600160781b03168352600b82528083209385168352600490930190529081205460ff166116e2565b5f611f73613e07338686865f613e20565b5090506001600160e01b0319811615611f8f57611f8f816143e9565b50505050565b5f611fc460017f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b5f611fd6866102d18686600180613010565b9050611fe486868686613b04565b91508115611ffa57611ffa81875f6001816130ec565b50949350505050565b61200b6131c7565b6120145f6131cf565b801561194f575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114612063576040519150601f19603f3d011682016040523d82523d5f602084013e612068565b606091505b505090508061141e57604051630fc77c5160e21b815260040160405180910390fd5b6001600160781b0381165f908152600c6020526040902060609061149c90613004565b6040516389a9c85560e01b81526001600160a01b0382811660048301525f917f0000000000000000000000000000000000000000000000000000000000000000909116906389a9c85590602401602060405180830381865afa158015612115573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061149c9190615bba565b6114ac815f613b8d565b6001600160a01b038281165f908152600a6020908152604080832054630100000090046001600160781b03168352600c82528083209385168352600490930190529081205460ff166116e2565b6001600160a01b0381165f908152600a602052604090205460609061149c90630100000090046001600160781b0316611ad1565b6001600160a01b0381165f908152600a602052604090205460609061149c90630100000090046001600160781b031661159d565b6001600160781b0383165f908152600c6020526040902061141e906001858585612d35565b6001600160781b0383165f908152600b6020526040812061141e918585856135a6565b336001600160a01b038716148061225f5750336001600160a01b038616145b61227c5760405163eda7110360e01b815260040160405180910390fd5b61228584613814565b5f612296600388878787878c6143f1565b805490915060ff166122f15760028155604051600181526001600160a01b03878116919089169084907f705db7ac401a8091bb37a7838ad73d1fa8e1c663cb345f347fefe71280e3f03b9060200160405180910390a461230a565b60405163465fc3a960e11b815260040160405180910390fd5b50505050505050565b5f8361231e81612fc0565b61234c60087f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b6123618c8c60018d8d8d60018b8b8f8f61449b565b61236d88888e8e613b04565b9150811561237f5761237f888b612f6b565b509a9950505050505050505050565b6001600160a01b0382165f908152600a6020908152604080832054630100000090046001600160781b03168352600c825280832084845260050190915281205460ff166116e2565b61194f82825b61194f5f838382613214565b600880546001600160781b038082166001019081166effffffffffffffffffffffffffffff1990921682179092555f8181526009602052604090819020805473ffffffffffffffffffffffffffffffffffffffff191633179055517f5cc365f89543268cb9f25c255f7f610e9147e733c589bc2732279575f125be14906124729086908690615bd5565b60405180910390a260405133906001600160781b038316907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e27367905f90a392915050565b6124be86613814565b6124cd86868685853389613a56565b505050505050565b6124de8261332a565b6008546001600160781b03908116908216111561250e57604051637b8b439360e11b815260040160405180910390fd5b6001600160a01b0382165f818152600a6020526040808220805471ffffffffffffffffffffffffffffff000000191663010000006001600160781b0387169081029190911790915590519092917fa66ff5557b7dc1562bb5e83306e15b513a25aa7537369bce38fc29c20847a79191a35050565b6114ac338261384d565b5f61259d6144b13387878787613e20565b5090506001600160e01b031981161561167f5761167f816143e9565b5f80826125c58161339e565b6125f360807f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b5f6126068e8e8e8e5f8f8e8e8e8e614511565b905061261a818d8d5f8e8e8c6136646133f1565b9094509250821561263357612633818b888760016130ec565b50509a509a98505050505050505050565b5f61267360207f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b61268660148b5f8b8d8c8c8b8b8b612dfd565b6126938a87875f88613664565b905080156126a5576126a5868a612f6b565b9998505050505050505050565b600160045f6040518060e0016040528060a58152602001615d5660a5913985856040516020016126e493929190615c25565b6040516020818303038152906040528051906020012081526020019081526020015f205f6101000a81548160ff021916908315150217905550600160055f6040518060c00160405280609d8152602001615cb9609d9139858560405160200161274f93929190615c25565b60408051808303601f190181529181528151602092830120835290820192909252015f20805460ff19169115159190911790555050565b61141e8383835f613214565b5f6127c160047f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b5f6127d1866014865f875f613010565b90506127e08487875f87613664565b91508115611ffa57611ffa81875f86816130ec565b6001600160781b0381165f908152600d6020526040902060609061149c90613004565b6001600160781b0383165f908152600d6020526040902061141e906002858585612d35565b600880546effffffffffffffffffffffffffffff19811660016001600160781b039283169081018084169290921790935591908316111561289157604051637b8b439360e11b815260040160405180910390fd5b6001600160781b0381165f8181526009602052604090819020805473ffffffffffffffffffffffffffffffffffffffff191633179055517f5cc365f89543268cb9f25c255f7f610e9147e733c589bc2732279575f125be14906128f79087908790615bd5565b60405180910390a260405133906001600160781b038316907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e27367905f90a36001600160781b038083165f908152600b60208181526040808420600c808452828620600d808652848820988a16885295855283872091855283872095909452918520909592949293919261298b90888886614526565b6129975f8888866145d9565b6129a46001888785614526565b6129b160018887856145d9565b6129be6002888684614526565b6129cb60028886846145d9565b5050505050509392505050565b6001600160781b0383165f908152600b6020526040812061141e9185858561376e565b61141e600d5f856001600160781b03166001600160781b031681526020019081526020015f206002858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061327892505050565b612a658361332a565b6001600160a01b0383165f908152600e60205260408120905b8281101561167f575f848483818110612a9957612a99615ba6565b9050602002016020810190612aae919061507c565b9050612aba8382614673565b15612b2157806001600160a01b0316866001600160a01b03167f208795fcac393398e42038456348398d8cac9067232f671ab240444cb51b1d2060405160405180910390a36001600160a01b0381165f9081526002840160205260409020805460ff191690555b50600101612a7e565b6001600160a01b0381165f908152600a602052604090205460609061149c90630100000090046001600160781b031661208a565b612b66613c03565b6001600160a01b038116612b8d57604051633e58254b60e01b815260040160405180910390fd5b6114ac81613c32565b612b9f8261332a565b6001600160a01b0382165f818152600a602090815260409182902080547fffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffff16600160981b61ffff87169081029190911790915591519182527fa5c37ab91519073edd58e608f19f7ce383fd171f4f22c3612a1d0a7c1047794a910160405180910390a25050565b7f000000000000000000000000000000000000000000000000000000000000000034470311156114ac576001548116156114ac57604051636623b92d60e11b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000034470311612cb55760405163fd2c901360e01b815260040160405180910390fd5b80600154165f036114ac5760405163fd2c901360e01b815260040160405180910390fd5b5f7f00000000000000000000000000000000000000000000000000000000000000003447031115612d0957506001545b90565b6001548116156114ac57604051636623b92d60e11b815260040160405180910390fd5b60015490565b82612d3f81614687565b5f805b83811015612df357848482818110612d5c57612d5c615ba6565b9050602002016020810190612d71919061507c565b9150612d7d8883613ca1565b15612deb57816001600160a01b0316866001600160781b03168860ff167fda8f3bd170446760f0f965a9b52bf271cb9679b5e0a70059eff2d49425229d1760405160405180910390a46001600160a01b0382165f9081526004890160205260409020805460ff191660011790555b600101612d42565b5050505050505050565b5f612ebc611bb88c8c8c8c8c8c60075f8e6001600160a01b03166001600160a01b031681526020019081526020015f2054604080517f932b8553b8e35bbee682d275cbe1cf115e14a777e2ca3266b4797369fb6317d3602080830191909152818301999099526001600160a01b03979097166060880152608087019590955260a086019390935260c08501919091523360e085015261010084015261012080840191909152815180840390910181526101409092019052805191012090565b9050611bec8787868b898689896146c7565b5f612edf610483878787878761471f565b905080612f6257604051637921219560e11b81526001600160a01b0386811660048301528581166024830152604482018590526064820184905260a060848301525f60a483015287169063f242432a9060c4015f604051808303815f87803b158015612f49575f80fd5b505af1925050508015612f5a575060015b612f62575060015b95945050505050565b6001600160a01b0382165f908152600660209081526040808320600885901c845290915290208054600160ff84161b90811891829055161561194f5760405163e4adc0bf60e01b815260040160405180910390fd5b5f8181526004602052604090205460ff166114ac57604051632391283760e11b815260040160405180910390fd5b611bec6104838c8c8c8c8c8c8c8c8c8c8c614789565b60605f6116e2836147bc565b5f61302160028888888886336143f1565b805490915042600160d01b90910465ffffffffffff16101561305657604051630104f5db60e71b815260040160405180910390fd5b805461010090046001600160c81b03168311156130865760405163fee142c560e01b815260040160405180910390fd5b81156130a0578054610100600160d01b03191681556130e2565b80546001600160c81b03610100909104811610156130e25780546001600160c81b03610100808304821686900390911602610100600160d01b03199091161781555b9695505050505050565b811561167f57801561318057845460ff196001600160c81b036101008084048216860190911602167fffffffffffff00000000000000000000000000000000000000000000000000009091161785556040518281526001600160a01b0385169084907f83e0ca2c1392f14286fa1e41c797789d48c5827572e8bcc352d8943c1961eaf09060200160405180910390a361167f565b84546001600160c81b036101009091048116101561167f5784546001600160c81b036101008083048216850190911602610100600160d01b03199091161785555050505050565b611d2c613c03565b600180549082905560408051828152602081018490527fe0d8d9ad73c586e8cf60ffd390b6f3654200a2d8857eb6abba4f6842a1210aae910160405180910390a15050565b828433613222838383614815565b6132506001600160a01b038716886001600160a01b031686613244575f61324a565b600160ff1b5b176148df565b61230a61326987875f9182526020526040902060041c90565b886001600160a01b03166148df565b8161328281614687565b5f805b835181101561230a578381815181106132a0576132a0615ba6565b602090810291909101015191506132b78783614673565b1561332257816001600160a01b0316856001600160781b03168760ff167f503012490a650739416858609e898957b874d17415a062945179c5735797884060405160405180910390a46001600160a01b0382165f9081526004880160205260409020805460ff191690555b600101613285565b336001600160a01b038216810361333f575050565b5f61334983614921565b509050806001600160a01b0316826001600160a01b03160361336a57505050565b5f613376848285614969565b50905080156133855750505050565b604051637f954ba160e01b815260040160405180910390fd5b5f8181526005602052604090205460ff166114ac57604051632391283760e11b815260040160405180910390fd5b5f6133e28b8b8b6104838c8c8c8c8c8c8c6149d5565b9b9a5050505050505050505050565b87546020880135905f9061010090046001600160c81b031682111561342357895461010090046001600160c81b031691505b88604001358210156134485760405163b9ff981560e01b815260040160405180910390fd5b89546001600160c81b03610100808304821685900390911602610100600160d01b0319909116178a5560405182815233906001600160a01b0388169086907f2203cb053e6b01ec07e87d67d288d360ae164171185684936663b7d8fa9c534c9060200160405180910390a4895461010090046001600160c81b03165f0361351757895460ff19166001178a556040515f815233906001600160a01b0388169086907f705db7ac401a8091bb37a7838ad73d1fa8e1c663cb345f347fefe71280e3f03b9060200160405180910390a45b6135288887878a868863ffffffff16565b90509850989650505050505050565b5f805f6135498a8a898989898e6143f1565b805490915042600160d01b90910465ffffffffffff161061357957805461010090046001600160c81b031661357b565b5f5b90546001600160c81b039091169a600160d01b90910465ffffffffffff169950975050505050505050565b826135b081614687565b5f805b83811015612df3578484828181106135cd576135cd615ba6565b9050602002013591506135ec8289600201614b1490919063ffffffff16565b156136475781866001600160781b03168860ff167fc8615322788d404dfe307db9eef031bc148d1cec5e270a1fd6528a02b445d44560405160405180910390a45f8281526005890160205260409020805460ff191660011790555b6001016135b3565b611bec60148c8c8c8c8c8c8c8c8c8c8c614789565b5f61367460148787875f8761471f565b905080612f6257604080516001600160a01b0387811660248301528681166044830152606480830186905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166323b872dd60e01b17905291515f928392908a16916136f39190615c4b565b5f604051808303815f865af19150503d805f811461372c576040519150601f19603f3d011682016040523d82523d5f602084013e613731565b606091505b5091509150816137445760019250613763565b805115613763578080602001905181019061375f9190615bba565b1592505b505095945050505050565b8261377881614687565b5f805b83811015612df35784848281811061379557613795615ba6565b9050602002013591506137b48289600201614b1f90919063ffffffff16565b1561380c5781866001600160781b03168860ff167f061d78094976b1d9ae7bb858f141c915b46152756409caadb07482983c2ca30160405160405180910390a45f8281526005890160205260409020805460ff191690555b60010161377b565b6102d1811480613825575061048381145b806138305750601481145b6114ac57604051639d36a97960e01b815260040160405180910390fd5b6001600160a01b0382165f908152600660209081526040808320600885901c845290915290208054600160ff84161b908118918290551661194f5760405163d979627360e01b815260040160405180910390fd5b604080517ff9c04f8b028fcfa3315ea5accaee4589194a685f07cda0392e6ba9550706111960208201529081018a90526001600160a01b03808a1660608301526080820189905260a0820188905260c08201879052851660e08201526101008101849052610120810183905261014081018290525f90610160015b6040516020818303038152906040528051906020012090509998505050505050505050565b5f61149c61394d613d13565b8360405161190160f01b602082015260228101839052604281018290525f9060620160405160208183030381529060405280519060200120905092915050565b60418290036139f1578235602084013560408501355f90811a90806139b489848787614b2a565b91509150806001600160a01b0316866001600160a01b03161415806139d65750815b156139e7576139e7868a8a8a614bd3565b5050505050611f8f565b6040829003613a4a57823560208401355f80613a0e888585614c26565b91509150806001600160a01b0316856001600160a01b0316141580613a305750815b15613a4157613a4185898989614bd3565b50505050611f8f565b611f8f81858585614bd3565b5f613a676002848a8a8a86886143f1565b805460ff16600160d01b65ffffffffffff8716908102610100600160d01b031916919091176101006001600160c81b038916908102919091178355604080518a815260208101929092528101919091529091506001600160a01b0383811691898216918616907f0ec867d4f1b037422566cd0248bae620e6c142dcf5631948271916e8ca8dd2639060600160405180910390a45050505050505050565b5f613b166102d184878786600161471f565b905080613b85576040516323b872dd60e01b81526001600160a01b0386811660048301528581166024830152604482018490528416906323b872dd906064015f604051808303815f87803b158015613b6c575f80fd5b505af1925050508015613b7d575060015b613b85575060015b949350505050565b613b9682614687565b6001600160781b0382165f81815260096020526040808220805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03861690811790915590519092917f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e2736791a35050565b5f546001600160a01b03610100909104163314611d2c576040516208650f60e61b815260040160405180910390fd5b5f80546001600160a01b038381166101008181027fffffffffffffffffffffff0000000000000000000000000000000000000000ff851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b5f6116e2836001600160a01b038416614c6d565b5f816001600160a01b0316600a5a613ccd9190615c66565b6040515f8181818686fa925050503d805f8114613d05576040519150601f19603f3d011682016040523d82523d5f602084013e613d0a565b606091505b50909392505050565b5f7f00000000000000000000000000000000000000000000000000000000000000004603613d6057507f000000000000000000000000000000000000000000000000000000000000000090565b611f10604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b5f611ffa836001600160a01b038616614cb9565b614cb9565b5f80306001600160a01b03871603613e3c57505f905080611c7f565b6001600160a01b0387165f908152600a602052604090208054630100000081046001600160781b0316907f00000000000000000000000000000000000000000000000000000000000000006107f862010000830460031b1690811c60ff908116927f000000000000000000000000000000000000000000000000000000000000000090921c811691600160901b90041615613f57576001600160a01b03808c165f908152600e60209081526040808320938d1683526002840190915290205460ff1615613f1b575063056c6b9160e31b95505f9450611c7f9350505050565b6001600160a01b0389165f90815260028201602052604090205460ff1615613f555750632a5cb1c360e01b95505f9450611c7f9350505050565b505b60048203613f76575063d73e63af60e01b94505f9350611c7f92505050565b6001600160781b0383165f908152600c602052604090205f19820161400a57883b15614005576001600160a01b0389165f90815260048201602052604090205460ff16614005578c613fcd8d8d8b63ffffffff8516565b61400357893f5f90815260058301602052604090205460ff1661400357506305652c5560e51b96505f9550611c7f945050505050565b505b614088565b600282036140885761401b896120ad565b614088576001600160a01b0389165f90815260048201602052604090205460ff16614088578c6140508d8d8b63ffffffff8516565b61408657893f5f90815260058301602052604090205460ff166140865750636719795560e11b96505f9550611c7f945050505050565b505b896001600160a01b03168b6001600160a01b0316036140c557600383146140c557505091545f9450600160981b900461ffff169250611c7f915050565b600183036141b1578c6140dd8d8d8b63ffffffff8516565b156140ff57505092545f9550600160981b900461ffff169350611c7f92505050565b5f600b5f876001600160781b03166001600160781b031681526020019081526020015f209050806004015f8e6001600160a01b03166001600160a01b031681526020019081526020015f205f9054906101000a900460ff1615614176575063204f370f60e11b97505f9650611c7f95505050505050565b8c3f5f90815260058201602052604090205460ff16156141aa575063204f370f60e11b97505f9650611c7f95505050505050565b50506143c9565b60028303614279576001600160a01b038b165f90815260048201602052604090205460ff16156141f757505091545f9450600160981b900461ffff169250611c7f915050565b8c6142078d8d8b63ffffffff8516565b1561422957505092545f9550600160981b900461ffff169350611c7f92505050565b8b3f5f90815260058301602052604090205460ff161561426057505092545f9550600160981b900461ffff169350611c7f92505050565b5063ef28f90160e01b96505f9550611c7f945050505050565b600383036143c9576001600160a01b038b165f90815260048201602081905260409091205460ff16156142c357505092545f9550600160981b900461ffff169350611c7f92505050565b6001600160a01b038b165f9081526020829052604090205460ff161561430057505092545f9550600160981b900461ffff169350611c7f92505050565b8d6143108e8e8c63ffffffff8516565b1561433357505093545f9650600160981b900461ffff169450611c7f9350505050565b8c3f5f9081526005840160208190526040909120548e9060ff161561437257505095545f9850600160981b900461ffff169650611c7f95505050505050565b508c3f5f908152602082905260409020548d9060ff16156143ad57505095545f9850600160981b900461ffff169650611c7f95505050505050565b5063ef28f90160e01b99505f9850611c7f975050505050505050565b505091545f9b600160981b90910461ffff169a5098505050505050505050565b805f5260045ffd5b5f875f61446089898989896001600160a01b039485165f818152600760209081526040918290205482518083019490945283830197909752949096166060820152608081019290925260a082015260c0808201939093528351808203909301835260e001909252805191012090565b81526020019081526020015f205f836001600160a01b03166001600160a01b031681526020019081526020015f209050979650505050505050565b611bec6102d18c8c8c8c8c8c8c8c8c8c8c614789565b5f806144cd84613e1b87865f9182526020526040902060041c90565b50915081156144e05760019150506116e2565b6144f3846001600160a01b038716614cb9565b9092509050818015612f62575060ff81901c60011495945050505050565b5f6133e28b8b8b60148c8c8c8c8c8c8c6149d5565b8181600481015f61453684614cfa565b90505f805b828110156145cd5761454d8682614d03565b91506145598583613ca1565b156145c557816001600160a01b0316896001600160781b03168b60ff167fda8f3bd170446760f0f965a9b52bf271cb9679b5e0a70059eff2d49425229d1760405160405180910390a46001600160a01b0382165f908152602085905260409020805460ff191660011790555b60010161453b565b50505050505050505050565b6002808301908201600583015f6145ef84614cfa565b90505f805b828110156145cd576146068682614d03565b91506146128583614b14565b1561466b5781896001600160781b03168b60ff167fc8615322788d404dfe307db9eef031bc148d1cec5e270a1fd6528a02b445d44560405160405180910390a45f828152602085905260409020805460ff191660011790555b6001016145f4565b5f6116e2836001600160a01b038416614d0e565b6001600160781b0381165f908152600960205260409020546001600160a01b031633146114ac576040516304e680cb60e41b815260040160405180910390fd5b864211156146e85760405163e3fd7ac360e01b815260040160405180910390fd5b848611156147095760405163de7fafeb60e01b815260040160405180910390fd5b614713848961384d565b612df38383838761398d565b5f805f6147326144b189338a8a8a613e20565b909250905061ffff8116158061474b5750888161ffff16145b15614764576001600160e01b031982161515925061477d565b604051633d29aed360e11b815260040160405180910390fd5b50509695505050505050565b5f61479b8d8d8d8d8b8e8e8a8a614df1565b90506147ad8989888d8b868b8b6146c7565b50505050505050505050505050565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561480957602002820191905f5260205f20905b8154815260200190600101908083116147f5575b50505050509050919050565b6001600160a01b0383165f908152600a60205260409020805460ff161561484f5760405163b1ae736760e01b815260040160405180910390fd5b8054610100900460ff1615614888575f196001600160a01b038416016148885760405163bf729bb160e01b815260040160405180910390fd5b8054630100000090046001600160781b03165f908152600d602090815260408083206001600160a01b038616845260040190915290205460ff16611f8f57604051635e47503160e11b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000001561490c5780825d5050565b5f5460ff161561491d5780825d5050565b9055565b5f80614957565b638da5cb5b5f525f8060205f6004601c865afa60203d1015161561494f575f519150915091565b509160019150565b61496083614928565b91509150915091565b5f806149be565b5f80604051606081016040526391d14854815284816020015285816040015260205f6044601c8401875afa60203d101516156149b0575f519250506149b6565b50600190505b935093915050565b6149c9838587614970565b91509150935093915050565b5f6001600160c81b038a3511156149ff57604051633b0a334360e01b815260040160405180910390fd5b614a0f6003878b8b8b88336143f1565b805490915060ff166122f157805461010090046001600160c81b03165f03614ae357614a56614a4e8a8a8a8e358b8b65ffffffffffff8c168b8b614df1565b8d8d8961398d565b805460ff166101008b356001600160c81b0381169190910279ffffffffffffffffffffffffffffffffffffffffffffffffffff1691909117600160d01b65ffffffffffff87160217825560405190815233906001600160a01b0388169085907f257001e1f7fbfc5bbde5da225c876ab67293f37bda3afb8b35d9a55dfad6f65d9060200160405180910390a45b8054600160d01b900465ffffffffffff164211156133e25760405163e3fd7ac360e01b815260040160405180910390fd5b5f6116e28383614c6d565b5f6116e28383614d0e565b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614b5f5750600190505f614bca565b604080515f81526020810180835288905260ff871691810191909152606081018590526080810184905260019060a0016020604051602081039080840390855afa158015614baf573d5f803e3d5ffd5b5050604051601f1901516001600160a01b0381161593509150505b94509492505050565b836001600160a01b03163b5f03614bfd576040516373c919b560e01b815260040160405180910390fd5b614c0984848484614e1d565b611f8f576040516373c919b560e01b815260040160405180910390fd5b5f807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316601b60ff85901c01614c5f87828885614b2a565b909890975095505050505050565b5f818152600183016020526040812054614cb257508154600181810184555f84815260208082209093018490558454848252828601909352604090209190915561149c565b505f61149c565b5f80614cc483614e99565b9050806001600160a01b03811660011480614cf05750846001600160a01b0316816001600160a01b0316145b9250509250929050565b5f61149c825490565b5f6116e28383614edd565b5f8181526001830160205260408120548015614de8575f614d30600183615c85565b85549091505f90614d4390600190615c85565b9050818114614da2575f865f018281548110614d6157614d61615ba6565b905f5260205f200154905080875f018481548110614d8157614d81615ba6565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080614db357614db3615ca4565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f90556001935050505061149c565b5f91505061149c565b6001600160a01b0385165f908152600760205260408120546133e2611bb88c8c8c8c8b8b8b8b8a614f03565b5f614e8d565b5f604051630b135d3f60e11b81528360048201526040602482015285604482015285856064830137601f19601f87011660640180820160405260205f8284875afa60203d10151615614e8357630b135d3f60e11b5f511492505050613b85565b5050949350505050565b612f6282848688614e23565b5f7f000000000000000000000000000000000000000000000000000000000000000015614ec557505c90565b5f5460ff1615614ed457505c90565b5080545b919050565b5f825f018281548110614ef257614ef2615ba6565b905f5260205f200154905092915050565b60408051602081018490529081018a90526001600160a01b03891660608201526080810188905260a0810187905260c081018690523360e08201526101008101859052610120810182905261014081018490525f906101600161391c565b80356001600160781b0381168114614ed8575f80fd5b5f8083601f840112614f87575f80fd5b50813567ffffffffffffffff811115614f9e575f80fd5b6020830191508360208260051b8501011115614fb8575f80fd5b9250929050565b5f805f60408486031215614fd1575f80fd5b614fda84614f61565b9250602084013567ffffffffffffffff811115614ff5575f80fd5b61500186828701614f77565b9497909650939450505050565b5f6020828403121561501e575f80fd5b81356001600160e01b0319811681146116e2575f80fd5b80356001600160a01b0381168114614ed8575f80fd5b5f806040838503121561505c575f80fd5b61506583614f61565b915061507360208401615035565b90509250929050565b5f6020828403121561508c575f80fd5b6116e282615035565b5f8083601f8401126150a5575f80fd5b50813567ffffffffffffffff8111156150bc575f80fd5b602083019150836020828501011115614fb8575f80fd5b5f805f805f805f805f806101208b8d0312156150ed575f80fd5b6150f68b615035565b995060208b0135985060408b0135975060608b0135965060808b0135955061512060a08c01615035565b945061512e60c08c01615035565b935060e08b013592506101008b013567ffffffffffffffff811115615151575f80fd5b61515d8d828e01615095565b915080935050809150509295989b9194979a5092959850565b5f805f805f805f805f805f806101608d8f031215615192575f80fd5b61519b8d615035565b9b5060208d01359a5060408d0135995060608d0135985060808d013597506151c560a08e01615035565b96506151d360c08e01615035565b955060e08d013594506101008d013593506101208d0135925067ffffffffffffffff6101408e01351115615205575f80fd5b6152168e6101408f01358f01615095565b81935080925050509295989b509295989b509295989b565b5f6020828403121561523e575f80fd5b6116e282614f61565b602080825282518282018190525f9190848201906040850190845b818110156152875783516001600160a01b031683529284019291840191600101615262565b50909695505050505050565b5f805f805f60a086880312156152a7575f80fd5b6152b086615035565b94506152be60208701615035565b93506152cc60408701615035565b94979396509394606081013594506080013592915050565b5f602082840312156152f4575f80fd5b5035919050565b602080825282518282018190525f9190848201906040850190845b8181101561528757835183529284019291840191600101615316565b5f8060408385031215615343575f80fd5b61534c83615035565b946020939093013593505050565b5f805f6060848603121561536c575f80fd5b61537584615035565b925061538360208501615035565b915061539160408501615035565b90509250925092565b5f805f606084860312156153ac575f80fd5b6153b584615035565b95602085013595506040909401359392505050565b80151581146114ac575f80fd5b5f805f805f60a086880312156153eb575f80fd5b6153f486615035565b9450602086013560ff81168114615409575f80fd5b93506040860135615419816153ca565b92506060860135615429816153ca565b91506080860135615439816153ca565b809150509295509295909350565b5f60608284031215615457575f80fd5b50919050565b803565ffffffffffff81168114614ed8575f80fd5b5f805f805f805f805f805f6101808c8e03121561548d575f80fd5b8b3567ffffffffffffffff8111156154a3575f80fd5b6154af8e828f01615095565b909c509a506154c390508d60208e01615447565b98506154d160808d01615035565b975060a08c013596506154e660c08d01615035565b95506154f460e08d01615035565b94506101008c0135935061550b6101208d0161545d565b92506101408c013591506101608c013590509295989b509295989b9093969950565b5f806040838503121561553e575f80fd5b61506583615035565b5f805f805f60a0868803121561555b575f80fd5b61556486615035565b945061557260208701615035565b93506040860135925061558760608701615035565b949793965091946080013592915050565b5f805f805f805f805f805f6101408c8e0312156155b3575f80fd5b6155bc8c615035565b9a5060208c0135995060408c0135985060608c013597506155df60808d01615035565b96506155ed60a08d01615035565b955060c08c0135945060e08c013593506101008c013592506101208c013567ffffffffffffffff81111561561f575f80fd5b61562b8e828f01615095565b915080935050809150509295989b509295989b9093969950565b80356001600160c81b0381168114614ed8575f80fd5b5f805f805f805f805f805f6101408c8e031215615676575f80fd5b8b359a5061568660208d01615035565b995060408c0135985060608c013597506156a260808d01615645565b96506156b060a08d01615035565b95506156be60c08d0161545d565b94506156cc60e08d0161545d565b93506156db6101008d01615035565b92506101208c013567ffffffffffffffff81111561561f575f80fd5b5f8060408385031215615708575f80fd5b61534c83614f61565b5f805f805f805f8060e0898b031215615728575f80fd5b61573189615035565b975060208901359650604089013595506060890135945061575460808a01615035565b935061576260a08a01615035565b925060c089013567ffffffffffffffff81111561577d575f80fd5b6157898b828c01615095565b999c989b5096995094979396929594505050565b5f805f805f8060c087890312156157b2575f80fd5b6157bb87615035565b95506157c960208801615035565b9450604087013593506157de60608801615035565b92506080870135915060a087013590509295509295509295565b5f805f6040848603121561580a575f80fd5b614fda84615035565b5f805f8060808587031215615826575f80fd5b61582f85615035565b935061583d60208601615035565b925061584b60408601615035565b9396929550929360600135925050565b5f805f805f805f805f806101208b8d031215615875575f80fd5b61587e8b615035565b995060208b0135985060408b0135975060608b013596506158a160808c01615035565b95506158af60a08c01615035565b945060c08b0135935060e08b013592506101008b013567ffffffffffffffff811115615151575f80fd5b5f80602083850312156158ea575f80fd5b823567ffffffffffffffff811115615900575f80fd5b61590c85828601615095565b90969095509350505050565b5f805f805f8060c0878903121561592d575f80fd5b8635955061593d60208801615035565b94506040870135935061595260608801615035565b925061596060808801615645565b915061596e60a0880161545d565b90509295509295509295565b5f806040838503121561598b575f80fd5b61599483615035565b915061507360208401614f61565b5f805f805f805f805f806101608b8d0312156159bc575f80fd5b8a3567ffffffffffffffff8111156159d2575f80fd5b6159de8d828e01615095565b909b5099506159f290508c60208d01615447565b9750615a0060808c01615035565b9650615a0e60a08c01615035565b9550615a1c60c08c01615035565b945060e08b01359350615a326101008c0161545d565b92506101208b013591506101408b013590509295989b9194979a5092959850565b5f805f805f805f805f6101008a8c031215615a6c575f80fd5b615a758a615035565b985060208a0135975060408a0135965060608a01359550615a9860808b01615035565b9450615aa660a08b01615035565b935060c08a0135925060e08a013567ffffffffffffffff811115615ac8575f80fd5b615ad48c828d01615095565b915080935050809150509295985092959850929598565b5f805f60608486031215615afd575f80fd5b615b0684615035565b9250615b1460208501615035565b9150604084013590509250925092565b5f805f60408486031215615b36575f80fd5b833567ffffffffffffffff811115615b4c575f80fd5b615b5886828701615095565b9094509250615391905060208501614f61565b5f8060408385031215615b7c575f80fd5b615b8583615035565b9150602083013561ffff81168114615b9b575f80fd5b809150509250929050565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215615bca575f80fd5b81516116e2816153ca565b60208152816020820152818360408301375f818301604090810191909152601f909201601f19160101919050565b5f5b83811015615c1d578181015183820152602001615c05565b50505f910152565b5f8451615c36818460208901615c03565b8201838582375f930192835250909392505050565b5f8251615c5c818460208701615c03565b9190910192915050565b5f82615c8057634e487b7160e01b5f52601260045260245ffd5b500490565b8181038181111561149c57634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603160045260245ffdfe5065726d69744f72646572576974684164646974696f6e616c446174612875696e7432353620746f6b656e547970652c6164647265737320746f6b656e2c75696e743235362069642c75696e7432353620616d6f756e742c75696e743235362073616c742c61646472657373206f70657261746f722c75696e743235362065787069726174696f6e2c75696e74323536206d61737465724e6f6e63652c5065726d69745472616e7366657246726f6d576974684164646974696f6e616c446174612875696e7432353620746f6b656e547970652c6164647265737320746f6b656e2c75696e743235362069642c75696e7432353620616d6f756e742c75696e74323536206e6f6e63652c61646472657373206f70657261746f722c75696e743235362065787069726174696f6e2c75696e74323536206d61737465724e6f6e63652ca26469706673582212204aed5a9438fa1f93a19402978e99446b15ffab9a7272f92ed814de426e3dc30964736f6c63430008180033000000000000000000000000c327b16c33fdd558c1ad7daaff1a4081e91049f3000000000000000000000000e0a0004cb92d89cd9b056927df0fe008c16cf86f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000721c006d06dc5c03b6106fa9fe32c10efb1ddb62000000000000000000000000000000000000000000000000000000000000001d43726561746f72546f6b656e5472616e7366657256616c696461746f7200000000000000000000000000000000000000000000000000000000000000000000013300000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106105c1575f3560e01c80638254fcb7116102f0578063b97f6f8b11610191578063ddae38f2116100e7578063e34fda8511610092578063f7a2000a1161006d578063f7a2000a14611374578063fb2de5d7146113ae578063ffbcb4aa146113cd575f80fd5b8063e34fda85146105e4578063e991dc3014611336578063f2fde38b14611355575f80fd5b8063df21dc1d116100c2578063df21dc1d146112c4578063df5fd29a146112f8578063e07cb24014611317575f80fd5b8063ddae38f214611267578063de02cbb114611286578063def0125b146112a5575f80fd5b8063d415f62f11610147578063db5f30a811610122578063db5f30a81461120a578063dd71105d14611229578063dda964e314611248575f80fd5b8063d415f62f14611184578063d5dc239a146111cc578063db188e63146111eb575f80fd5b8063c435f43511610177578063c435f43514611127578063caee23ea14611146578063cfea7ecf14611165575f80fd5b8063b97f6f8b146110e9578063bf7bfd7e14611108575f80fd5b8063a5d56b4611610246578063b67d8f99116101fc578063b89c4b0d116101d7578063b89c4b0d14610f78578063b8dcc68f14610f97578063b955455214610fb6575f80fd5b8063b67d8f9914610ee8578063b6e39ba114610f07578063b70510f514610f26575f80fd5b8063ad1ff6851161022c578063ad1ff68514610e76578063ae602f4414610e95578063b3992ab114610ec9575f80fd5b8063a5d56b4614610e0c578063a87b03b614610e2b575f80fd5b80638da5cb5b116102a6578063982d03c011610281578063982d03c014610d5d5780639c2a9c6f14610d7c578063a1cc5cc114610ded575f80fd5b80638da5cb5b14610cea5780638e28800f14610d1f5780639340a7cc14610d3e575f80fd5b806389631626116102d65780638963162614610c8d57806389a9c85514610cac5780638b6ee86514610ccb575f80fd5b80638254fcb714610c4057806386e1177414610c6e575f80fd5b80633e5c139d116104655780636498c045116103bb578063725d07c5116103665780637bac97de116103415780637bac97de14610be35780637c1e14b414610c025780637df81b9014610c21575f80fd5b8063725d07c514610b8e5780637423eb3c14610bad57806378e890ba14610bc1575f80fd5b8063715018a611610396578063715018a614610b3c5780637161ac8d14610b5057806371be859d14610b6f575f80fd5b80636498c04514610adf5780636971082814610afe5780636bfab91d14610b1d575f80fd5b80634c9d0b451161041b578063539d2602116103f6578063539d260214610a595780635e17263d14610a785780635ed5917f14610ac0575f80fd5b80634c9d0b45146109fc5780635079331514610a1b578063515f7b2814610a3a575f80fd5b80633f6560ee1161044b5780633f6560ee1461098a578063409dc573146109be5780634be52a89146109dd575f80fd5b80633e5c139d146109575780633e8a0bc914610976575f80fd5b80631854b2411161051a5780632c7fe70a116104d05780633779e6fd116104ab5780633779e6fd146108e55780633a0e3160146109195780633cda743a14610938575f80fd5b80632c7fe70a146108885780632eb0b98a146108a7578063317e3e8d146108c6575f80fd5b806323c992621161050057806323c9926214610813578063285fb8c81461084a57806328cc113114610869575f80fd5b80631854b241146107a55780631f2fdc79146107c4575f80fd5b80630f59197d1161057a578063136439dd11610555578063136439dd1461071457806316a17ce01461072757806316f18d7414610779575f80fd5b80630f59197d146106aa57806310b5c6a0146106c957806312d3848a146106f5575f80fd5b8063057497cb116105aa578063057497cb1461061a5780630ad388991461066c5780630e14021a1461068b575f80fd5b806301549930146105c557806301ffc9a7146105e6575b5f80fd5b3480156105d0575f80fd5b506105e46105df366004614fbf565b6113fb565b005b3480156105f1575f80fd5b5061060561060036600461500e565b611423565b60405190151581526020015b60405180910390f35b348015610625575f80fd5b5061060561063436600461504b565b6001600160781b0382165f908152600c602090815260408083206001600160a01b038516845260040190915290205460ff1692915050565b348015610677575f80fd5b506105e461068636600461507c565b6114a2565b348015610696575f80fd5b506106056106a53660046150d3565b6114af565b3480156106b5575f80fd5b506106056106c4366004615176565b61151f565b3480156106d4575f80fd5b506106e86106e336600461522e565b61159d565b6040516106119190615247565b348015610700575f80fd5b5061060561070f366004615293565b6115c0565b6105e46107223660046152e4565b61162e565b348015610732575f80fd5b5061060561074136600461504b565b6001600160781b0382165f908152600b602090815260408083206001600160a01b038516845260040190915290205460ff1692915050565b348015610784575f80fd5b5061079861079336600461507c565b61163f565b60405161061191906152fb565b3480156107b0575f80fd5b506105e46107bf366004615293565b611673565b3480156107cf575f80fd5b506106056107de366004615332565b6001600160a01b039091165f908152600660209081526040808320600885901c845290915290205460ff9091161c6001161590565b34801561081e575f80fd5b50600854610832906001600160781b031681565b6040516001600160781b039091168152602001610611565b348015610855575f80fd5b506105e461086436600461535a565b611686565b348015610874575f80fd5b506105e461088336600461539a565b611691565b348015610893575f80fd5b506106056108a2366004615332565b61169e565b3480156108b2575f80fd5b506105e46108c1366004614fbf565b6116e9565b3480156108d1575f80fd5b506105e46108e03660046153d7565b61174a565b3480156108f0575f80fd5b506109046108ff366004615472565b6118b6565b60408051928352901515602083015201610611565b348015610924575f80fd5b506105e4610933366004615332565b611942565b348015610943575f80fd5b5061060561095236600461552d565b611953565b348015610962575f80fd5b506106e861097136600461507c565b6119a0565b348015610981575f80fd5b506105e46119d4565b348015610995575f80fd5b506109a96109a4366004615547565b611a11565b60408051928352602083019190915201610611565b3480156109c9575f80fd5b506105e46109d8366004614fbf565b611a31565b3480156109e8575f80fd5b506106056109f7366004615598565b611a56565b348015610a07575f80fd5b50610798610a1636600461522e565b611ad1565b348015610a26575f80fd5b506105e4610a3536600461552d565b611af7565b348015610a45575f80fd5b506105e4610a54366004614fbf565b611b04565b348015610a64575f80fd5b506105e4610a7336600461565b565b611b29565b348015610a83575f80fd5b50610605610a923660046156f7565b6001600160781b03919091165f908152600c6020908152604080832093835260059093019052205460ff1690565b348015610acb575f80fd5b50610605610ada366004615711565b611bf9565b348015610aea575f80fd5b506109a9610af936600461579d565b611c68565b348015610b09575f80fd5b506105e4610b18366004614fbf565b611c8a565b348015610b28575f80fd5b506105e4610b3736600461504b565b611cea565b348015610b47575f80fd5b506105e4611d1b565b348015610b5b575f80fd5b50610798610b6a36600461522e565b611d2e565b348015610b7a575f80fd5b506105e4610b893660046157f8565b611d54565b348015610b99575f80fd5b506106e8610ba836600461507c565b611e25565b348015610bb8575f80fd5b506105e4611e48565b348015610bcc575f80fd5b50610bd5611f07565b604051908152602001610611565b348015610bee575f80fd5b50610605610bfd36600461552d565b611f15565b348015610c0d575f80fd5b506105e4610c1c36600461535a565b611f62565b348015610c2c575f80fd5b50610605610c3b366004615813565b611f95565b348015610c4b575f80fd5b50610605610c5a3660046152e4565b5f9081526004602052604090205460ff1690565b348015610c79575f80fd5b506105e4610c88366004615332565b612003565b348015610c98575f80fd5b506106e8610ca736600461522e565b61208a565b348015610cb7575f80fd5b50610605610cc636600461507c565b6120ad565b348015610cd6575f80fd5b506105e4610ce536600461522e565b612139565b348015610cf5575f80fd5b505f5461010090046001600160a01b03165b6040516001600160a01b039091168152602001610611565b348015610d2a575f80fd5b50610605610d3936600461552d565b612143565b348015610d49575f80fd5b50610798610d5836600461507c565b612190565b348015610d68575f80fd5b506106e8610d7736600461507c565b6121c4565b348015610d87575f80fd5b506109a9610d963660046152e4565b60ff7f000000000000000000000000000000000000000000000403030202030201000260039290921b91821c8116927f000000000000000000000000000000000000000000000302010201000000000090921c1690565b348015610df8575f80fd5b506105e4610e07366004614fbf565b6121f8565b348015610e17575f80fd5b506105e4610e26366004614fbf565b61221d565b348015610e36575f80fd5b50610605610e4536600461552d565b6001600160a01b039182165f908152600e602090815260408083209390941682526002909201909152205460ff1690565b348015610e81575f80fd5b506105e4610e9036600461579d565b612240565b348015610ea0575f80fd5b50610d07610eaf36600461522e565b60096020525f90815260409020546001600160a01b031681565b348015610ed4575f80fd5b50610605610ee336600461585b565b612313565b348015610ef3575f80fd5b50610605610f02366004615332565b61238e565b348015610f12575f80fd5b506105e4610f21366004615332565b6123d6565b348015610f31575f80fd5b50610605610f4036600461504b565b6001600160781b0382165f908152600d602090815260408083206001600160a01b038516845260040190915290205460ff1692915050565b348015610f83575f80fd5b506105e4610f92366004615332565b6123dc565b348015610fa2575f80fd5b50610832610fb13660046158d9565b6123e8565b348015610fc1575f80fd5b50611088610fd036600461507c565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a0810191909152506001600160a01b03165f908152600a6020908152604091829020825160c081018452905460ff8082161515835261010082048116151593830193909352620100008104831693820193909352630100000083046001600160781b03166060820152600160901b830490911615156080820152600160981b90910461ffff1660a082015290565b60405161061191905f60c08201905082511515825260208301511515602083015260ff60408401511660408301526001600160781b03606084015116606083015260808301511515608083015261ffff60a08401511660a083015292915050565b3480156110f4575f80fd5b506105e4611103366004615918565b6124b5565b348015611113575f80fd5b506105e461112236600461597a565b6124d5565b348015611132575f80fd5b506105e46111413660046152e4565b612582565b348015611151575f80fd5b506105e4611160366004615813565b61258c565b348015611170575f80fd5b5061090461117f3660046159a2565b6125b9565b34801561118f575f80fd5b5061060561119e3660046156f7565b6001600160781b03919091165f908152600b6020908152604080832093835260059093019052205460ff1690565b3480156111d7575f80fd5b506106056111e6366004615a53565b612644565b3480156111f6575f80fd5b506105e46112053660046158d9565b6126b2565b348015611215575f80fd5b506105e4611224366004615aeb565b612786565b348015611234575f80fd5b50610605611243366004615813565b612792565b348015611253575f80fd5b506106e861126236600461522e565b6127f5565b348015611272575f80fd5b506105e4611281366004614fbf565b612818565b348015611291575f80fd5b506108326112a0366004615b24565b61283d565b3480156112b0575f80fd5b506105e46112bf366004614fbf565b6129d8565b3480156112cf575f80fd5b50610bd56112de36600461507c565b6001600160a01b03165f9081526007602052604090205490565b348015611303575f80fd5b506105e4611312366004614fbf565b6129fb565b348015611322575f80fd5b506105e46113313660046157f8565b612a5c565b348015611341575f80fd5b506106e861135036600461507c565b612b2a565b348015611360575f80fd5b506105e461136f36600461507c565b612b5e565b34801561137f575f80fd5b50600180547f00000000000000000000000000000000000000000000000000753d533d967fff909101906109a9565b3480156113b9575f80fd5b506105e46113c8366004615b6b565b612b96565b3480156113d8575f80fd5b506106056113e73660046152e4565b5f9081526005602052604090205460ff1690565b6001600160781b0383165f908152600b6020526040812061141e91858585612d35565b505050565b5f6001600160e01b03198216158061144b57506001600160e01b03198216630dd9a30760e11b145b8061146657506001600160e01b03198216633016020d60e21b145b8061148157506001600160e01b031982166389a9c85560e01b145b8061149c57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6114ac815f6123dc565b50565b5f6114de60107f0000000000000000000000000000000000000000000000000000037d00002c2663ffffffff16565b6114f26104838c8c8b8d8c8c8b8b8b612dfd565b6114ff8b87878d88612ece565b9050801561151157611511868a612f6b565b9a9950505050505050505050565b5f8361152a81612fc0565b61155860107f0000000000000000000000000000000000000000000000000000037d00002c2663ffffffff16565b61156b8e8e8d8f8e8e8d8b8b8f8f612fee565b8c6115798f8b8b848c612ece565b9250821561158b5761158b8a8e612f6b565b50509c9b505050505050505050505050565b6001600160781b0381165f908152600b6020526040902060609061149c90613004565b5f6115ef60027f0000000000000000000000000000000000000000000000000000037d00002c2663ffffffff16565b5f611600876104838787875f613010565b905061160f8588888787612ece565b915081156116245761162481885f86816130ec565b5095945050505050565b6116366131c7565b6114ac816131cf565b6001600160a01b0381165f908152600a602052604090205460609061149c90630100000090046001600160781b0316611d2e565b61167f8585858561258c565b5050505050565b61141e838383611f62565b61141e600184845f613214565b6001600160a01b0382165f908152600a6020908152604080832054630100000090046001600160781b03168352600b825280832084845260050190915281205460ff165b9392505050565b61141e600c5f856001600160781b03166001600160781b031681526020019081526020015f206001858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061327892505050565b600960ff8516111561176f576040516317c5702360e01b815260040160405180910390fd5b6117788561332a565b6001600160a01b0385165f818152600a6020908152604091829020805462ff00ff19166201000060ff8a1690810260ff1916919091178815151772ff00000000000000000000000000000000ff0019166101008815150272ff000000000000000000000000000000000000191617600160901b871515021790915591519182527fb39d8f1e6f05413a407e46fc950eb92e9f5b3d65a47c3f0bdc7a2741a6ec0f7d910160405180910390a260408051841515815283151560208201526001600160a01b038716917f9c615afab54584e53810beb24cced6ca36919dfc62bff2d4a0d244906c41c2ac910160405180910390a2846001600160a01b03167f9c6e8620d0004b9dd8b49560e2de8ced6f409f529cc23d0bb9e5a106d5c43242826040516118a7911515815260200190565b60405180910390a25050505050565b5f80826118c28161339e565b6118f060407f0000000000000000000000000000000000000000000000000000037d00002c2663ffffffff16565b5f6119038f8f8f8f8f8f8e8e8e8e6133cc565b9050611917818e8e8e8e8e8c612ece6133f1565b9094509250821561193057611930818b888760016130ec565b50509b509b9950505050505050505050565b61194f600183835f613214565b5050565b6001600160a01b038281165f908152600a6020908152604080832054630100000090046001600160781b03168352600d82528083209385168352600490930190529081205460ff166116e2565b6001600160a01b0381165f908152600a602052604090205460609061149c90630100000090046001600160781b03166127f5565b335f8181526007602052604080822080546001019055517f8e8cebe67607ce50a14a2e3261437f641a7b33ecc053e3d9c90b25ae5e66c6569190a2565b5f80611a236002888888888887613537565b915091509550959350505050565b6001600160781b0383165f908152600c6020526040902061141e9060018585856135a6565b5f83611a6181612fc0565b611a8f60207f0000000000000000000000000000000000000000000000000000037d00002c2663ffffffff16565b611aa28d5f8d8f8e8e8d8b8b8f8f61364f565b611aaf8d8a8a5f8b613664565b91508115611ac157611ac1898d612f6b565b509b9a5050505050505050505050565b6001600160781b0381165f908152600c6020526040902060609061149c90600201613004565b61194f82825f6001613214565b6001600160781b0383165f908152600c6020526040902061141e90600185858561376e565b8365ffffffffffff16421115611b5257604051630104f5db60e71b815260040160405180910390fd5b611b5b8b613814565b611b65838961384d565b611bc5611bbd611bb88d8d8d8c6001600160c81b03168e8d8d65ffffffffffff168d65ffffffffffff1660075f8f6001600160a01b03166001600160a01b031681526020019081526020015f20546138a1565b613941565b83838661398d565b65ffffffffffff851615611bd95784611bdb565b425b9450611bec8b8b8b8a89888c613a56565b5050505050505050505050565b5f611c2860087f0000000000000000000000000000000000000000000000000000037d00002c2663ffffffff16565b611c3e6102d18a8a60018b8b8b60018b8b612dfd565b611c4a85858b8b613b04565b90508015611c5c57611c5c8588612f6b565b98975050505050505050565b5f80611c7a6003898989898989613537565b915091505b965096945050505050565b61141e600b5f856001600160781b03166001600160781b031681526020019081526020015f205f858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061327892505050565b6001600160a01b038116611d11576040516303e9dcb360e31b815260040160405180910390fd5b61194f8282613b8d565b611d23613c03565b611d2c5f613c32565b565b6001600160781b0381165f908152600b6020526040902060609061149c90600201613004565b611d5d8361332a565b6001600160a01b0383165f908152600e60205260408120905b8281101561167f575f848483818110611d9157611d91615ba6565b9050602002016020810190611da6919061507c565b9050611db28382613ca1565b15611e1c57806001600160a01b0316866001600160a01b03167f1138edbff75f319641eb242dbcacee294ebc2a473eb6aa1454a7706da5bf96b060405160405180910390a36001600160a01b0381165f9081526002840160205260409020805460ff191660011790555b50600101611d76565b6001600160a01b0381165f908152600e6020526040902060609061149c90613004565b333214611e685760405163096650c560e21b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000180611e9557505f5460ff165b15611eb357604051630f45b98b60e41b815260040160405180910390fd5b611edc7f000000000000000000000000b924c643f478fbfe3423c9188bdf4f095b9f3828613cb5565b611ef9576040516370a4078f60e01b815260040160405180910390fd5b5f805460ff19166001179055565b5f611f10613d13565b905090565b6001600160a01b038281165f908152600a6020908152604080832054630100000090046001600160781b03168352600b82528083209385168352600490930190529081205460ff166116e2565b5f611f73613e07338686865f613e20565b5090506001600160e01b0319811615611f8f57611f8f816143e9565b50505050565b5f611fc460017f0000000000000000000000000000000000000000000000000000037d00002c2663ffffffff16565b5f611fd6866102d18686600180613010565b9050611fe486868686613b04565b91508115611ffa57611ffa81875f6001816130ec565b50949350505050565b61200b6131c7565b6120145f6131cf565b801561194f575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114612063576040519150601f19603f3d011682016040523d82523d5f602084013e612068565b606091505b505090508061141e57604051630fc77c5160e21b815260040160405180910390fd5b6001600160781b0381165f908152600c6020526040902060609061149c90613004565b6040516389a9c85560e01b81526001600160a01b0382811660048301525f917f000000000000000000000000e0a0004cb92d89cd9b056927df0fe008c16cf86f909116906389a9c85590602401602060405180830381865afa158015612115573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061149c9190615bba565b6114ac815f613b8d565b6001600160a01b038281165f908152600a6020908152604080832054630100000090046001600160781b03168352600c82528083209385168352600490930190529081205460ff166116e2565b6001600160a01b0381165f908152600a602052604090205460609061149c90630100000090046001600160781b0316611ad1565b6001600160a01b0381165f908152600a602052604090205460609061149c90630100000090046001600160781b031661159d565b6001600160781b0383165f908152600c6020526040902061141e906001858585612d35565b6001600160781b0383165f908152600b6020526040812061141e918585856135a6565b336001600160a01b038716148061225f5750336001600160a01b038616145b61227c5760405163eda7110360e01b815260040160405180910390fd5b61228584613814565b5f612296600388878787878c6143f1565b805490915060ff166122f15760028155604051600181526001600160a01b03878116919089169084907f705db7ac401a8091bb37a7838ad73d1fa8e1c663cb345f347fefe71280e3f03b9060200160405180910390a461230a565b60405163465fc3a960e11b815260040160405180910390fd5b50505050505050565b5f8361231e81612fc0565b61234c60087f0000000000000000000000000000000000000000000000000000037d00002c2663ffffffff16565b6123618c8c60018d8d8d60018b8b8f8f61449b565b61236d88888e8e613b04565b9150811561237f5761237f888b612f6b565b509a9950505050505050505050565b6001600160a01b0382165f908152600a6020908152604080832054630100000090046001600160781b03168352600c825280832084845260050190915281205460ff166116e2565b61194f82825b61194f5f838382613214565b600880546001600160781b038082166001019081166effffffffffffffffffffffffffffff1990921682179092555f8181526009602052604090819020805473ffffffffffffffffffffffffffffffffffffffff191633179055517f5cc365f89543268cb9f25c255f7f610e9147e733c589bc2732279575f125be14906124729086908690615bd5565b60405180910390a260405133906001600160781b038316907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e27367905f90a392915050565b6124be86613814565b6124cd86868685853389613a56565b505050505050565b6124de8261332a565b6008546001600160781b03908116908216111561250e57604051637b8b439360e11b815260040160405180910390fd5b6001600160a01b0382165f818152600a6020526040808220805471ffffffffffffffffffffffffffffff000000191663010000006001600160781b0387169081029190911790915590519092917fa66ff5557b7dc1562bb5e83306e15b513a25aa7537369bce38fc29c20847a79191a35050565b6114ac338261384d565b5f61259d6144b13387878787613e20565b5090506001600160e01b031981161561167f5761167f816143e9565b5f80826125c58161339e565b6125f360807f0000000000000000000000000000000000000000000000000000037d00002c2663ffffffff16565b5f6126068e8e8e8e5f8f8e8e8e8e614511565b905061261a818d8d5f8e8e8c6136646133f1565b9094509250821561263357612633818b888760016130ec565b50509a509a98505050505050505050565b5f61267360207f0000000000000000000000000000000000000000000000000000037d00002c2663ffffffff16565b61268660148b5f8b8d8c8c8b8b8b612dfd565b6126938a87875f88613664565b905080156126a5576126a5868a612f6b565b9998505050505050505050565b600160045f6040518060e0016040528060a58152602001615d5660a5913985856040516020016126e493929190615c25565b6040516020818303038152906040528051906020012081526020019081526020015f205f6101000a81548160ff021916908315150217905550600160055f6040518060c00160405280609d8152602001615cb9609d9139858560405160200161274f93929190615c25565b60408051808303601f190181529181528151602092830120835290820192909252015f20805460ff19169115159190911790555050565b61141e8383835f613214565b5f6127c160047f0000000000000000000000000000000000000000000000000000037d00002c2663ffffffff16565b5f6127d1866014865f875f613010565b90506127e08487875f87613664565b91508115611ffa57611ffa81875f86816130ec565b6001600160781b0381165f908152600d6020526040902060609061149c90613004565b6001600160781b0383165f908152600d6020526040902061141e906002858585612d35565b600880546effffffffffffffffffffffffffffff19811660016001600160781b039283169081018084169290921790935591908316111561289157604051637b8b439360e11b815260040160405180910390fd5b6001600160781b0381165f8181526009602052604090819020805473ffffffffffffffffffffffffffffffffffffffff191633179055517f5cc365f89543268cb9f25c255f7f610e9147e733c589bc2732279575f125be14906128f79087908790615bd5565b60405180910390a260405133906001600160781b038316907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e27367905f90a36001600160781b038083165f908152600b60208181526040808420600c808452828620600d808652848820988a16885295855283872091855283872095909452918520909592949293919261298b90888886614526565b6129975f8888866145d9565b6129a46001888785614526565b6129b160018887856145d9565b6129be6002888684614526565b6129cb60028886846145d9565b5050505050509392505050565b6001600160781b0383165f908152600b6020526040812061141e9185858561376e565b61141e600d5f856001600160781b03166001600160781b031681526020019081526020015f206002858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061327892505050565b612a658361332a565b6001600160a01b0383165f908152600e60205260408120905b8281101561167f575f848483818110612a9957612a99615ba6565b9050602002016020810190612aae919061507c565b9050612aba8382614673565b15612b2157806001600160a01b0316866001600160a01b03167f208795fcac393398e42038456348398d8cac9067232f671ab240444cb51b1d2060405160405180910390a36001600160a01b0381165f9081526002840160205260409020805460ff191690555b50600101612a7e565b6001600160a01b0381165f908152600a602052604090205460609061149c90630100000090046001600160781b031661208a565b612b66613c03565b6001600160a01b038116612b8d57604051633e58254b60e01b815260040160405180910390fd5b6114ac81613c32565b612b9f8261332a565b6001600160a01b0382165f818152600a602090815260409182902080547fffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffff16600160981b61ffff87169081029190911790915591519182527fa5c37ab91519073edd58e608f19f7ce383fd171f4f22c3612a1d0a7c1047794a910160405180910390a25050565b7f00000000000000000000000000000000000000000000000000753d533d967fff34470311156114ac576001548116156114ac57604051636623b92d60e11b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000753d533d967fff34470311612cb55760405163fd2c901360e01b815260040160405180910390fd5b80600154165f036114ac5760405163fd2c901360e01b815260040160405180910390fd5b5f7f00000000000000000000000000000000000000000000000000753d533d967fff3447031115612d0957506001545b90565b6001548116156114ac57604051636623b92d60e11b815260040160405180910390fd5b60015490565b82612d3f81614687565b5f805b83811015612df357848482818110612d5c57612d5c615ba6565b9050602002016020810190612d71919061507c565b9150612d7d8883613ca1565b15612deb57816001600160a01b0316866001600160781b03168860ff167fda8f3bd170446760f0f965a9b52bf271cb9679b5e0a70059eff2d49425229d1760405160405180910390a46001600160a01b0382165f9081526004890160205260409020805460ff191660011790555b600101612d42565b5050505050505050565b5f612ebc611bb88c8c8c8c8c8c60075f8e6001600160a01b03166001600160a01b031681526020019081526020015f2054604080517f932b8553b8e35bbee682d275cbe1cf115e14a777e2ca3266b4797369fb6317d3602080830191909152818301999099526001600160a01b03979097166060880152608087019590955260a086019390935260c08501919091523360e085015261010084015261012080840191909152815180840390910181526101409092019052805191012090565b9050611bec8787868b898689896146c7565b5f612edf610483878787878761471f565b905080612f6257604051637921219560e11b81526001600160a01b0386811660048301528581166024830152604482018590526064820184905260a060848301525f60a483015287169063f242432a9060c4015f604051808303815f87803b158015612f49575f80fd5b505af1925050508015612f5a575060015b612f62575060015b95945050505050565b6001600160a01b0382165f908152600660209081526040808320600885901c845290915290208054600160ff84161b90811891829055161561194f5760405163e4adc0bf60e01b815260040160405180910390fd5b5f8181526004602052604090205460ff166114ac57604051632391283760e11b815260040160405180910390fd5b611bec6104838c8c8c8c8c8c8c8c8c8c8c614789565b60605f6116e2836147bc565b5f61302160028888888886336143f1565b805490915042600160d01b90910465ffffffffffff16101561305657604051630104f5db60e71b815260040160405180910390fd5b805461010090046001600160c81b03168311156130865760405163fee142c560e01b815260040160405180910390fd5b81156130a0578054610100600160d01b03191681556130e2565b80546001600160c81b03610100909104811610156130e25780546001600160c81b03610100808304821686900390911602610100600160d01b03199091161781555b9695505050505050565b811561167f57801561318057845460ff196001600160c81b036101008084048216860190911602167fffffffffffff00000000000000000000000000000000000000000000000000009091161785556040518281526001600160a01b0385169084907f83e0ca2c1392f14286fa1e41c797789d48c5827572e8bcc352d8943c1961eaf09060200160405180910390a361167f565b84546001600160c81b036101009091048116101561167f5784546001600160c81b036101008083048216850190911602610100600160d01b03199091161785555050505050565b611d2c613c03565b600180549082905560408051828152602081018490527fe0d8d9ad73c586e8cf60ffd390b6f3654200a2d8857eb6abba4f6842a1210aae910160405180910390a15050565b828433613222838383614815565b6132506001600160a01b038716886001600160a01b031686613244575f61324a565b600160ff1b5b176148df565b61230a61326987875f9182526020526040902060041c90565b886001600160a01b03166148df565b8161328281614687565b5f805b835181101561230a578381815181106132a0576132a0615ba6565b602090810291909101015191506132b78783614673565b1561332257816001600160a01b0316856001600160781b03168760ff167f503012490a650739416858609e898957b874d17415a062945179c5735797884060405160405180910390a46001600160a01b0382165f9081526004880160205260409020805460ff191690555b600101613285565b336001600160a01b038216810361333f575050565b5f61334983614921565b509050806001600160a01b0316826001600160a01b03160361336a57505050565b5f613376848285614969565b50905080156133855750505050565b604051637f954ba160e01b815260040160405180910390fd5b5f8181526005602052604090205460ff166114ac57604051632391283760e11b815260040160405180910390fd5b5f6133e28b8b8b6104838c8c8c8c8c8c8c6149d5565b9b9a5050505050505050505050565b87546020880135905f9061010090046001600160c81b031682111561342357895461010090046001600160c81b031691505b88604001358210156134485760405163b9ff981560e01b815260040160405180910390fd5b89546001600160c81b03610100808304821685900390911602610100600160d01b0319909116178a5560405182815233906001600160a01b0388169086907f2203cb053e6b01ec07e87d67d288d360ae164171185684936663b7d8fa9c534c9060200160405180910390a4895461010090046001600160c81b03165f0361351757895460ff19166001178a556040515f815233906001600160a01b0388169086907f705db7ac401a8091bb37a7838ad73d1fa8e1c663cb345f347fefe71280e3f03b9060200160405180910390a45b6135288887878a868863ffffffff16565b90509850989650505050505050565b5f805f6135498a8a898989898e6143f1565b805490915042600160d01b90910465ffffffffffff161061357957805461010090046001600160c81b031661357b565b5f5b90546001600160c81b039091169a600160d01b90910465ffffffffffff169950975050505050505050565b826135b081614687565b5f805b83811015612df3578484828181106135cd576135cd615ba6565b9050602002013591506135ec8289600201614b1490919063ffffffff16565b156136475781866001600160781b03168860ff167fc8615322788d404dfe307db9eef031bc148d1cec5e270a1fd6528a02b445d44560405160405180910390a45f8281526005890160205260409020805460ff191660011790555b6001016135b3565b611bec60148c8c8c8c8c8c8c8c8c8c8c614789565b5f61367460148787875f8761471f565b905080612f6257604080516001600160a01b0387811660248301528681166044830152606480830186905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166323b872dd60e01b17905291515f928392908a16916136f39190615c4b565b5f604051808303815f865af19150503d805f811461372c576040519150601f19603f3d011682016040523d82523d5f602084013e613731565b606091505b5091509150816137445760019250613763565b805115613763578080602001905181019061375f9190615bba565b1592505b505095945050505050565b8261377881614687565b5f805b83811015612df35784848281811061379557613795615ba6565b9050602002013591506137b48289600201614b1f90919063ffffffff16565b1561380c5781866001600160781b03168860ff167f061d78094976b1d9ae7bb858f141c915b46152756409caadb07482983c2ca30160405160405180910390a45f8281526005890160205260409020805460ff191690555b60010161377b565b6102d1811480613825575061048381145b806138305750601481145b6114ac57604051639d36a97960e01b815260040160405180910390fd5b6001600160a01b0382165f908152600660209081526040808320600885901c845290915290208054600160ff84161b908118918290551661194f5760405163d979627360e01b815260040160405180910390fd5b604080517ff9c04f8b028fcfa3315ea5accaee4589194a685f07cda0392e6ba9550706111960208201529081018a90526001600160a01b03808a1660608301526080820189905260a0820188905260c08201879052851660e08201526101008101849052610120810183905261014081018290525f90610160015b6040516020818303038152906040528051906020012090509998505050505050505050565b5f61149c61394d613d13565b8360405161190160f01b602082015260228101839052604281018290525f9060620160405160208183030381529060405280519060200120905092915050565b60418290036139f1578235602084013560408501355f90811a90806139b489848787614b2a565b91509150806001600160a01b0316866001600160a01b03161415806139d65750815b156139e7576139e7868a8a8a614bd3565b5050505050611f8f565b6040829003613a4a57823560208401355f80613a0e888585614c26565b91509150806001600160a01b0316856001600160a01b0316141580613a305750815b15613a4157613a4185898989614bd3565b50505050611f8f565b611f8f81858585614bd3565b5f613a676002848a8a8a86886143f1565b805460ff16600160d01b65ffffffffffff8716908102610100600160d01b031916919091176101006001600160c81b038916908102919091178355604080518a815260208101929092528101919091529091506001600160a01b0383811691898216918616907f0ec867d4f1b037422566cd0248bae620e6c142dcf5631948271916e8ca8dd2639060600160405180910390a45050505050505050565b5f613b166102d184878786600161471f565b905080613b85576040516323b872dd60e01b81526001600160a01b0386811660048301528581166024830152604482018490528416906323b872dd906064015f604051808303815f87803b158015613b6c575f80fd5b505af1925050508015613b7d575060015b613b85575060015b949350505050565b613b9682614687565b6001600160781b0382165f81815260096020526040808220805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03861690811790915590519092917f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e2736791a35050565b5f546001600160a01b03610100909104163314611d2c576040516208650f60e61b815260040160405180910390fd5b5f80546001600160a01b038381166101008181027fffffffffffffffffffffff0000000000000000000000000000000000000000ff851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b5f6116e2836001600160a01b038416614c6d565b5f816001600160a01b0316600a5a613ccd9190615c66565b6040515f8181818686fa925050503d805f8114613d05576040519150601f19603f3d011682016040523d82523d5f602084013e613d0a565b606091505b50909392505050565b5f7f00000000000000000000000000000000000000000000000000000000000081734603613d6057507f4d8c2ba97605cda93024fa917c2f5b060f10c2949ad80d49e0ff4a348bd1eb3990565b611f10604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f12900c1b40e87470816fa5cb16069bf5b3df9cf052332bf21440c4318ccddcfe918101919091527f2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de60608201524660808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b5f611ffa836001600160a01b038616614cb9565b614cb9565b5f80306001600160a01b03871603613e3c57505f905080611c7f565b6001600160a01b0387165f908152600a602052604090208054630100000081046001600160781b0316907f00000000000000000000000000000000000000000000040303020203020100026107f862010000830460031b1690811c60ff908116927f000000000000000000000000000000000000000000000302010201000000000090921c811691600160901b90041615613f57576001600160a01b03808c165f908152600e60209081526040808320938d1683526002840190915290205460ff1615613f1b575063056c6b9160e31b95505f9450611c7f9350505050565b6001600160a01b0389165f90815260028201602052604090205460ff1615613f555750632a5cb1c360e01b95505f9450611c7f9350505050565b505b60048203613f76575063d73e63af60e01b94505f9350611c7f92505050565b6001600160781b0383165f908152600c602052604090205f19820161400a57883b15614005576001600160a01b0389165f90815260048201602052604090205460ff16614005578c613fcd8d8d8b63ffffffff8516565b61400357893f5f90815260058301602052604090205460ff1661400357506305652c5560e51b96505f9550611c7f945050505050565b505b614088565b600282036140885761401b896120ad565b614088576001600160a01b0389165f90815260048201602052604090205460ff16614088578c6140508d8d8b63ffffffff8516565b61408657893f5f90815260058301602052604090205460ff166140865750636719795560e11b96505f9550611c7f945050505050565b505b896001600160a01b03168b6001600160a01b0316036140c557600383146140c557505091545f9450600160981b900461ffff169250611c7f915050565b600183036141b1578c6140dd8d8d8b63ffffffff8516565b156140ff57505092545f9550600160981b900461ffff169350611c7f92505050565b5f600b5f876001600160781b03166001600160781b031681526020019081526020015f209050806004015f8e6001600160a01b03166001600160a01b031681526020019081526020015f205f9054906101000a900460ff1615614176575063204f370f60e11b97505f9650611c7f95505050505050565b8c3f5f90815260058201602052604090205460ff16156141aa575063204f370f60e11b97505f9650611c7f95505050505050565b50506143c9565b60028303614279576001600160a01b038b165f90815260048201602052604090205460ff16156141f757505091545f9450600160981b900461ffff169250611c7f915050565b8c6142078d8d8b63ffffffff8516565b1561422957505092545f9550600160981b900461ffff169350611c7f92505050565b8b3f5f90815260058301602052604090205460ff161561426057505092545f9550600160981b900461ffff169350611c7f92505050565b5063ef28f90160e01b96505f9550611c7f945050505050565b600383036143c9576001600160a01b038b165f90815260048201602081905260409091205460ff16156142c357505092545f9550600160981b900461ffff169350611c7f92505050565b6001600160a01b038b165f9081526020829052604090205460ff161561430057505092545f9550600160981b900461ffff169350611c7f92505050565b8d6143108e8e8c63ffffffff8516565b1561433357505093545f9650600160981b900461ffff169450611c7f9350505050565b8c3f5f9081526005840160208190526040909120548e9060ff161561437257505095545f9850600160981b900461ffff169650611c7f95505050505050565b508c3f5f908152602082905260409020548d9060ff16156143ad57505095545f9850600160981b900461ffff169650611c7f95505050505050565b5063ef28f90160e01b99505f9850611c7f975050505050505050565b505091545f9b600160981b90910461ffff169a5098505050505050505050565b805f5260045ffd5b5f875f61446089898989896001600160a01b039485165f818152600760209081526040918290205482518083019490945283830197909752949096166060820152608081019290925260a082015260c0808201939093528351808203909301835260e001909252805191012090565b81526020019081526020015f205f836001600160a01b03166001600160a01b031681526020019081526020015f209050979650505050505050565b611bec6102d18c8c8c8c8c8c8c8c8c8c8c614789565b5f806144cd84613e1b87865f9182526020526040902060041c90565b50915081156144e05760019150506116e2565b6144f3846001600160a01b038716614cb9565b9092509050818015612f62575060ff81901c60011495945050505050565b5f6133e28b8b8b60148c8c8c8c8c8c8c6149d5565b8181600481015f61453684614cfa565b90505f805b828110156145cd5761454d8682614d03565b91506145598583613ca1565b156145c557816001600160a01b0316896001600160781b03168b60ff167fda8f3bd170446760f0f965a9b52bf271cb9679b5e0a70059eff2d49425229d1760405160405180910390a46001600160a01b0382165f908152602085905260409020805460ff191660011790555b60010161453b565b50505050505050505050565b6002808301908201600583015f6145ef84614cfa565b90505f805b828110156145cd576146068682614d03565b91506146128583614b14565b1561466b5781896001600160781b03168b60ff167fc8615322788d404dfe307db9eef031bc148d1cec5e270a1fd6528a02b445d44560405160405180910390a45f828152602085905260409020805460ff191660011790555b6001016145f4565b5f6116e2836001600160a01b038416614d0e565b6001600160781b0381165f908152600960205260409020546001600160a01b031633146114ac576040516304e680cb60e41b815260040160405180910390fd5b864211156146e85760405163e3fd7ac360e01b815260040160405180910390fd5b848611156147095760405163de7fafeb60e01b815260040160405180910390fd5b614713848961384d565b612df38383838761398d565b5f805f6147326144b189338a8a8a613e20565b909250905061ffff8116158061474b5750888161ffff16145b15614764576001600160e01b031982161515925061477d565b604051633d29aed360e11b815260040160405180910390fd5b50509695505050505050565b5f61479b8d8d8d8d8b8e8e8a8a614df1565b90506147ad8989888d8b868b8b6146c7565b50505050505050505050505050565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561480957602002820191905f5260205f20905b8154815260200190600101908083116147f5575b50505050509050919050565b6001600160a01b0383165f908152600a60205260409020805460ff161561484f5760405163b1ae736760e01b815260040160405180910390fd5b8054610100900460ff1615614888575f196001600160a01b038416016148885760405163bf729bb160e01b815260040160405180910390fd5b8054630100000090046001600160781b03165f908152600d602090815260408083206001600160a01b038616845260040190915290205460ff16611f8f57604051635e47503160e11b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000011561490c5780825d5050565b5f5460ff161561491d5780825d5050565b9055565b5f80614957565b638da5cb5b5f525f8060205f6004601c865afa60203d1015161561494f575f519150915091565b509160019150565b61496083614928565b91509150915091565b5f806149be565b5f80604051606081016040526391d14854815284816020015285816040015260205f6044601c8401875afa60203d101516156149b0575f519250506149b6565b50600190505b935093915050565b6149c9838587614970565b91509150935093915050565b5f6001600160c81b038a3511156149ff57604051633b0a334360e01b815260040160405180910390fd5b614a0f6003878b8b8b88336143f1565b805490915060ff166122f157805461010090046001600160c81b03165f03614ae357614a56614a4e8a8a8a8e358b8b65ffffffffffff8c168b8b614df1565b8d8d8961398d565b805460ff166101008b356001600160c81b0381169190910279ffffffffffffffffffffffffffffffffffffffffffffffffffff1691909117600160d01b65ffffffffffff87160217825560405190815233906001600160a01b0388169085907f257001e1f7fbfc5bbde5da225c876ab67293f37bda3afb8b35d9a55dfad6f65d9060200160405180910390a45b8054600160d01b900465ffffffffffff164211156133e25760405163e3fd7ac360e01b815260040160405180910390fd5b5f6116e28383614c6d565b5f6116e28383614d0e565b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614b5f5750600190505f614bca565b604080515f81526020810180835288905260ff871691810191909152606081018590526080810184905260019060a0016020604051602081039080840390855afa158015614baf573d5f803e3d5ffd5b5050604051601f1901516001600160a01b0381161593509150505b94509492505050565b836001600160a01b03163b5f03614bfd576040516373c919b560e01b815260040160405180910390fd5b614c0984848484614e1d565b611f8f576040516373c919b560e01b815260040160405180910390fd5b5f807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316601b60ff85901c01614c5f87828885614b2a565b909890975095505050505050565b5f818152600183016020526040812054614cb257508154600181810184555f84815260208082209093018490558454848252828601909352604090209190915561149c565b505f61149c565b5f80614cc483614e99565b9050806001600160a01b03811660011480614cf05750846001600160a01b0316816001600160a01b0316145b9250509250929050565b5f61149c825490565b5f6116e28383614edd565b5f8181526001830160205260408120548015614de8575f614d30600183615c85565b85549091505f90614d4390600190615c85565b9050818114614da2575f865f018281548110614d6157614d61615ba6565b905f5260205f200154905080875f018481548110614d8157614d81615ba6565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080614db357614db3615ca4565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f90556001935050505061149c565b5f91505061149c565b6001600160a01b0385165f908152600760205260408120546133e2611bb88c8c8c8c8b8b8b8b8a614f03565b5f614e8d565b5f604051630b135d3f60e11b81528360048201526040602482015285604482015285856064830137601f19601f87011660640180820160405260205f8284875afa60203d10151615614e8357630b135d3f60e11b5f511492505050613b85565b5050949350505050565b612f6282848688614e23565b5f7f000000000000000000000000000000000000000000000000000000000000000115614ec557505c90565b5f5460ff1615614ed457505c90565b5080545b919050565b5f825f018281548110614ef257614ef2615ba6565b905f5260205f200154905092915050565b60408051602081018490529081018a90526001600160a01b03891660608201526080810188905260a0810187905260c081018690523360e08201526101008101859052610120810182905261014081018490525f906101600161391c565b80356001600160781b0381168114614ed8575f80fd5b5f8083601f840112614f87575f80fd5b50813567ffffffffffffffff811115614f9e575f80fd5b6020830191508360208260051b8501011115614fb8575f80fd5b9250929050565b5f805f60408486031215614fd1575f80fd5b614fda84614f61565b9250602084013567ffffffffffffffff811115614ff5575f80fd5b61500186828701614f77565b9497909650939450505050565b5f6020828403121561501e575f80fd5b81356001600160e01b0319811681146116e2575f80fd5b80356001600160a01b0381168114614ed8575f80fd5b5f806040838503121561505c575f80fd5b61506583614f61565b915061507360208401615035565b90509250929050565b5f6020828403121561508c575f80fd5b6116e282615035565b5f8083601f8401126150a5575f80fd5b50813567ffffffffffffffff8111156150bc575f80fd5b602083019150836020828501011115614fb8575f80fd5b5f805f805f805f805f806101208b8d0312156150ed575f80fd5b6150f68b615035565b995060208b0135985060408b0135975060608b0135965060808b0135955061512060a08c01615035565b945061512e60c08c01615035565b935060e08b013592506101008b013567ffffffffffffffff811115615151575f80fd5b61515d8d828e01615095565b915080935050809150509295989b9194979a5092959850565b5f805f805f805f805f805f806101608d8f031215615192575f80fd5b61519b8d615035565b9b5060208d01359a5060408d0135995060608d0135985060808d013597506151c560a08e01615035565b96506151d360c08e01615035565b955060e08d013594506101008d013593506101208d0135925067ffffffffffffffff6101408e01351115615205575f80fd5b6152168e6101408f01358f01615095565b81935080925050509295989b509295989b509295989b565b5f6020828403121561523e575f80fd5b6116e282614f61565b602080825282518282018190525f9190848201906040850190845b818110156152875783516001600160a01b031683529284019291840191600101615262565b50909695505050505050565b5f805f805f60a086880312156152a7575f80fd5b6152b086615035565b94506152be60208701615035565b93506152cc60408701615035565b94979396509394606081013594506080013592915050565b5f602082840312156152f4575f80fd5b5035919050565b602080825282518282018190525f9190848201906040850190845b8181101561528757835183529284019291840191600101615316565b5f8060408385031215615343575f80fd5b61534c83615035565b946020939093013593505050565b5f805f6060848603121561536c575f80fd5b61537584615035565b925061538360208501615035565b915061539160408501615035565b90509250925092565b5f805f606084860312156153ac575f80fd5b6153b584615035565b95602085013595506040909401359392505050565b80151581146114ac575f80fd5b5f805f805f60a086880312156153eb575f80fd5b6153f486615035565b9450602086013560ff81168114615409575f80fd5b93506040860135615419816153ca565b92506060860135615429816153ca565b91506080860135615439816153ca565b809150509295509295909350565b5f60608284031215615457575f80fd5b50919050565b803565ffffffffffff81168114614ed8575f80fd5b5f805f805f805f805f805f6101808c8e03121561548d575f80fd5b8b3567ffffffffffffffff8111156154a3575f80fd5b6154af8e828f01615095565b909c509a506154c390508d60208e01615447565b98506154d160808d01615035565b975060a08c013596506154e660c08d01615035565b95506154f460e08d01615035565b94506101008c0135935061550b6101208d0161545d565b92506101408c013591506101608c013590509295989b509295989b9093969950565b5f806040838503121561553e575f80fd5b61506583615035565b5f805f805f60a0868803121561555b575f80fd5b61556486615035565b945061557260208701615035565b93506040860135925061558760608701615035565b949793965091946080013592915050565b5f805f805f805f805f805f6101408c8e0312156155b3575f80fd5b6155bc8c615035565b9a5060208c0135995060408c0135985060608c013597506155df60808d01615035565b96506155ed60a08d01615035565b955060c08c0135945060e08c013593506101008c013592506101208c013567ffffffffffffffff81111561561f575f80fd5b61562b8e828f01615095565b915080935050809150509295989b509295989b9093969950565b80356001600160c81b0381168114614ed8575f80fd5b5f805f805f805f805f805f6101408c8e031215615676575f80fd5b8b359a5061568660208d01615035565b995060408c0135985060608c013597506156a260808d01615645565b96506156b060a08d01615035565b95506156be60c08d0161545d565b94506156cc60e08d0161545d565b93506156db6101008d01615035565b92506101208c013567ffffffffffffffff81111561561f575f80fd5b5f8060408385031215615708575f80fd5b61534c83614f61565b5f805f805f805f8060e0898b031215615728575f80fd5b61573189615035565b975060208901359650604089013595506060890135945061575460808a01615035565b935061576260a08a01615035565b925060c089013567ffffffffffffffff81111561577d575f80fd5b6157898b828c01615095565b999c989b5096995094979396929594505050565b5f805f805f8060c087890312156157b2575f80fd5b6157bb87615035565b95506157c960208801615035565b9450604087013593506157de60608801615035565b92506080870135915060a087013590509295509295509295565b5f805f6040848603121561580a575f80fd5b614fda84615035565b5f805f8060808587031215615826575f80fd5b61582f85615035565b935061583d60208601615035565b925061584b60408601615035565b9396929550929360600135925050565b5f805f805f805f805f806101208b8d031215615875575f80fd5b61587e8b615035565b995060208b0135985060408b0135975060608b013596506158a160808c01615035565b95506158af60a08c01615035565b945060c08b0135935060e08b013592506101008b013567ffffffffffffffff811115615151575f80fd5b5f80602083850312156158ea575f80fd5b823567ffffffffffffffff811115615900575f80fd5b61590c85828601615095565b90969095509350505050565b5f805f805f8060c0878903121561592d575f80fd5b8635955061593d60208801615035565b94506040870135935061595260608801615035565b925061596060808801615645565b915061596e60a0880161545d565b90509295509295509295565b5f806040838503121561598b575f80fd5b61599483615035565b915061507360208401614f61565b5f805f805f805f805f806101608b8d0312156159bc575f80fd5b8a3567ffffffffffffffff8111156159d2575f80fd5b6159de8d828e01615095565b909b5099506159f290508c60208d01615447565b9750615a0060808c01615035565b9650615a0e60a08c01615035565b9550615a1c60c08c01615035565b945060e08b01359350615a326101008c0161545d565b92506101208b013591506101408b013590509295989b9194979a5092959850565b5f805f805f805f805f6101008a8c031215615a6c575f80fd5b615a758a615035565b985060208a0135975060408a0135965060608a01359550615a9860808b01615035565b9450615aa660a08b01615035565b935060c08a0135925060e08a013567ffffffffffffffff811115615ac8575f80fd5b615ad48c828d01615095565b915080935050809150509295985092959850929598565b5f805f60608486031215615afd575f80fd5b615b0684615035565b9250615b1460208501615035565b9150604084013590509250925092565b5f805f60408486031215615b36575f80fd5b833567ffffffffffffffff811115615b4c575f80fd5b615b5886828701615095565b9094509250615391905060208501614f61565b5f8060408385031215615b7c575f80fd5b615b8583615035565b9150602083013561ffff81168114615b9b575f80fd5b809150509250929050565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215615bca575f80fd5b81516116e2816153ca565b60208152816020820152818360408301375f818301604090810191909152601f909201601f19160101919050565b5f5b83811015615c1d578181015183820152602001615c05565b50505f910152565b5f8451615c36818460208901615c03565b8201838582375f930192835250909392505050565b5f8251615c5c818460208701615c03565b9190910192915050565b5f82615c8057634e487b7160e01b5f52601260045260245ffd5b500490565b8181038181111561149c57634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603160045260245ffdfe5065726d69744f72646572576974684164646974696f6e616c446174612875696e7432353620746f6b656e547970652c6164647265737320746f6b656e2c75696e743235362069642c75696e7432353620616d6f756e742c75696e743235362073616c742c61646472657373206f70657261746f722c75696e743235362065787069726174696f6e2c75696e74323536206d61737465724e6f6e63652c5065726d69745472616e7366657246726f6d576974684164646974696f6e616c446174612875696e7432353620746f6b656e547970652c6164647265737320746f6b656e2c75696e743235362069642c75696e7432353620616d6f756e742c75696e74323536206e6f6e63652c61646472657373206f70657261746f722c75696e743235362065787069726174696f6e2c75696e74323536206d61737465724e6f6e63652ca26469706673582212204aed5a9438fa1f93a19402978e99446b15ffab9a7272f92ed814de426e3dc30964736f6c63430008180033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c327b16c33fdd558c1ad7daaff1a4081e91049f3000000000000000000000000e0a0004cb92d89cd9b056927df0fe008c16cf86f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000721c006d06dc5c03b6106fa9fe32c10efb1ddb62000000000000000000000000000000000000000000000000000000000000001d43726561746f72546f6b656e5472616e7366657256616c696461746f7200000000000000000000000000000000000000000000000000000000000000000000013300000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : defaultOwner (address): 0xc327B16C33fdd558C1ad7DaaFf1a4081E91049f3
Arg [1] : eoaRegistry_ (address): 0xE0A0004CB92d89CD9b056927DF0FE008c16CF86F
Arg [2] : name (string): CreatorTokenTransferValidator
Arg [3] : version (string): 3
Arg [4] : validatorConfiguration (address): 0x721C006D06DC5c03B6106fa9fe32C10EFB1ddB62
-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 000000000000000000000000c327b16c33fdd558c1ad7daaff1a4081e91049f3
Arg [1] : 000000000000000000000000e0a0004cb92d89cd9b056927df0fe008c16cf86f
Arg [2] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [3] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [4] : 000000000000000000000000721c006d06dc5c03b6106fa9fe32c10efb1ddb62
Arg [5] : 000000000000000000000000000000000000000000000000000000000000001d
Arg [6] : 43726561746f72546f6b656e5472616e7366657256616c696461746f72000000
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [8] : 3300000000000000000000000000000000000000000000000000000000000000
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.