Overview
APE Balance
0 APE
APE Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 8 from a total of 8 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Set Transfer Sec... | 8901525 | 10 days ago | IN | 0 APE | 0.00097778 | ||||
Set Transfer Sec... | 8884097 | 10 days ago | IN | 0 APE | 0.00097714 | ||||
Set Transfer Sec... | 8879665 | 10 days ago | IN | 0 APE | 0.00097714 | ||||
Set Transfer Sec... | 8879485 | 10 days ago | IN | 0 APE | 0.00097717 | ||||
Set Transfer Sec... | 4748460 | 79 days ago | IN | 0 APE | 0.00115127 | ||||
Apply List To Co... | 4748391 | 79 days ago | IN | 0 APE | 0.00103596 | ||||
Set Transfer Sec... | 4748320 | 79 days ago | IN | 0 APE | 0.00115033 | ||||
Set Token Type O... | 4748136 | 79 days ago | IN | 0 APE | 0.00148416 |
Latest 2 internal transactions
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
4620013 | 80 days ago | Contract Creation | 0 APE | |||
4620013 | 80 days ago | Contract Creation | 0 APE |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
CreatorTokenTransferValidator
Compiler Version
v0.8.24+commit.e11b9ed9
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; import "./Constants.sol"; import "./DataTypes.sol"; import "@limitbreak/permit-c/PermitC.sol"; import "@limitbreak/tm-core-lib/src/utils/introspection/ERC165.sol"; import "@limitbreak/tm-core-lib/src/utils/structs/EnumerableSet.sol"; import "@limitbreak/tm-core-lib/src/utils/token/IEOARegistry.sol"; import "@limitbreak/tm-core-lib/src/utils/token/ITransferValidator.sol"; import "@limitbreak/tm-core-lib/src/utils/misc/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 * - Level 9: Soulbound Token, No Transfers Allowed. */ 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 attempting to renounce or transfer ownership of the default list id. error CreatorTokenTransferValidator__CannotReassignOwnershipOfDefaultList(); /// @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; /// @dev Used as a collision guard. uint256 private _transientOperatorSlotHolder; /// @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 ) Tstorish() PermitC( name, version, defaultOwner, block.chainid == 1 ? 0.33 ether : 0.01 ether ) { 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 Throws when list id is zero (default 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 Throws when list id is zero (default 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 { if (id == DEFAULT_LIST_ID) { revert CreatorTokenTransferValidator__CannotReassignOwnershipOfDefaultList(); } _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) { assembly { mstore(0x00, collection) mstore(0x20, _transientOperatorSlotHolder.slot) operatorSlot := keccak256(0x00, 0x40) } } /** * @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) } } /** * @dev Internal function triggered when the Tstore support is activated. */ function _onTstoreSupportActivated() internal virtual override { // Nothing to do here } }
// 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 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 (last updated v4.9.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.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SignedMath.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 `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @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); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.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 message) { // 32 is the length in bytes of hash, // enforced by the type signature above /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") mstore(0x1c, hash) message := keccak256(0x00, 0x3c) } } /** * @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 data) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, "\x19\x01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) data := keccak256(ptr, 0x42) } } /** * @dev Returns an Ethereum Signed Data with intended validator, created from a * `validator` and `data` according to the version 0 of EIP-191. * * See {recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x00", validator, data)); } }
// 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.9.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) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 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 256, 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 << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
//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 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.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 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 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; 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 // 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 // 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); } }
pragma solidity ^0.8.4; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC-165 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); * } * ``` */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
pragma solidity ^0.8.4; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * 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[ERC 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); }
pragma solidity ^0.8.24; library StorageTstorish { // keccak256(abi.encode(uint256(keccak256("storage.Tstorish")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant DATA_STORAGE_SLOT = 0xdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b00; struct Data { // Indicates if TSTORE support has been activated during or post-deployment. bool tstoreSupport; } function data() internal pure returns (Data storage ptr) { bytes32 slot = DATA_STORAGE_SLOT; assembly { ptr.slot := slot } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "./StorageTstorish.sol"; /** * @title Tstorish * @notice Based on https://github.com/ProjectOpenSea/tstorish/commit/a81ed74453ed7b9fe7e96a9906bc4def19b73e33 */ abstract contract Tstorish { /* * ------------------------------------------------------------------------+ * 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 tstore test contract address. address private immutable _tloadTestContract; // Declare an immutable variable to store the initial TSTORE support status. bool internal immutable _tstoreInitialSupport; // Declare an immutable function type variable for the _setTstorish function // based on chain support for tstore at time of deployment. function(uint256,uint256) internal immutable _setTstorish; // Declare an immutable function type variable for the _getTstorish function // based on chain support for tstore at time of deployment. function(uint256) view returns (uint256) internal immutable _getTstorish; // Declare an immutable function type variable for the _clearTstorish function // based on chain support for tstore at time of deployment. function(uint256) internal immutable _clearTstorish; // 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. _tstoreInitialSupport = StorageTstorish.data().tstoreSupport = _testTload(tloadTestContract); if (_tstoreInitialSupport) { // If TSTORE is supported, set functions to their versions that use // tstore/tload directly without support checks. _setTstorish = _setTstore; _getTstorish = _getTstore; _clearTstorish = _clearTstore; } else { // If TSTORE is not supported, set functions to their versions that // fallback to sstore/sload until tstoreSupport is true. _setTstorish = _setTstorishWithSstoreFallback; _getTstorish = _getTstorishWithSloadFallback; _clearTstorish = _clearTstorishWithSstoreFallback; } // Set the address of the deployed TLOAD test contract as an immutable. _tloadTestContract = tloadTestContract; } /** * @dev Called internally when tstore is activated by an external call to * `__activateTstore`. Developers must override this function and handle * relevant transfers of data from regular storage to transient storage *OR* * revert the transaction if it is in a state that should not support the activation * of tstore. */ function _onTstoreSupportActivated() internal virtual; /** * @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 { // Determine if TSTORE can potentially be activated. if (_tstoreInitialSupport || StorageTstorish.data().tstoreSupport) { revert TStoreAlreadyActivated(); } // Determine if TSTORE can be activated and revert if not. if (!_testTload(_tloadTestContract)) { revert TStoreNotSupported(); } // Mark TSTORE as activated. StorageTstorish.data().tstoreSupport = true; _onTstoreSupportActivated(); } /** * @dev Private function to set a TSTORISH value. Assigned to _setTstorish * internal function variable at construction if chain has tstore support. * * @param storageSlot The slot to write the TSTORISH value to. * @param value The value to write to the given storage slot. */ function _setTstore(uint256 storageSlot, uint256 value) internal { assembly { tstore(storageSlot, value) } } /** * @dev Private function to set a TSTORISH value with sstore fallback. * Assigned to _setTstorish internal function variable at construction * if chain does not have tstore support. * * @param storageSlot The slot to write the TSTORISH value to. * @param value The value to write to the given storage slot. */ function _setTstorishWithSstoreFallback(uint256 storageSlot, uint256 value) internal { if (StorageTstorish.data().tstoreSupport) { assembly { tstore(storageSlot, value) } } else { assembly { sstore(storageSlot, value) } } } /** * @dev Private function to read a TSTORISH value. Assigned to _getTstorish * internal function variable at construction if chain has tstore support. * * @param storageSlot The slot to read the TSTORISH value from. * * @return value The TSTORISH value at the given storage slot. */ function _getTstore( uint256 storageSlot ) internal view returns (uint256 value) { assembly { value := tload(storageSlot) } } /** * @dev Private function to read a TSTORISH value with sload fallback. * Assigned to _getTstorish internal function variable at construction * if chain does not have tstore support. * * @param storageSlot The slot to read the TSTORISH value from. * * @return value The TSTORISH value at the given storage slot. */ function _getTstorishWithSloadFallback( uint256 storageSlot ) internal view returns (uint256 value) { if (StorageTstorish.data().tstoreSupport) { assembly { value := tload(storageSlot) } } else { assembly { value := sload(storageSlot) } } } /** * @dev Private function to clear a TSTORISH value. Assigned to _clearTstorish internal * function variable at construction if chain has tstore support. * * @param storageSlot The slot to clear the TSTORISH value for. */ function _clearTstore(uint256 storageSlot) internal { assembly { tstore(storageSlot, 0) } } /** * @dev Private function to clear a TSTORISH value with sstore fallback. * Assigned to _clearTstorish internal function variable at construction * if chain does not have tstore support. * * @param storageSlot The slot to clear the TSTORISH value for. */ function _clearTstorishWithSstoreFallback(uint256 storageSlot) internal { if (StorageTstorish.data().tstoreSupport) { assembly { tstore(storageSlot, 0) } } else { assembly { sstore(storageSlot, 0) } } } /** * @dev Private function to copy a value from storage to transient storage at the same slot. * Useful when tstore is activated on a chain that didn't initially support it. */ function _copyFromStorageToTransient(uint256 storageSlot) internal { if (StorageTstorish.data().tstoreSupport) { assembly { tstore(storageSlot, sload(storageSlot)) } } else { revert TStoreNotSupported(); } } /** * @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 }(""); } }
pragma solidity ^0.8.4; /** * @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. * * ```solidity * 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 is the index of the value in the `values` array plus 1. // Position 0 is used to mean a value is not in the set. mapping(bytes32 value => uint256) _positions; } /** * @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._positions[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 cache the value's position to prevent multiple reads from the same storage slot uint256 position = set._positions[value]; if (position != 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 valueIndex = position - 1; uint256 lastIndex = set._values.length - 1; if (valueIndex != lastIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the lastValue to the index where the value to delete is set._values[valueIndex] = lastValue; // Update the tracked position of the lastValue (that was just moved) set._positions[lastValue] = position; } // Delete the slot where the moved value was stored set._values.pop(); // Delete the tracked position for the deleted slot delete set._positions[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._positions[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; } }
pragma solidity ^0.8.4; import "../introspection/IERC165.sol"; interface IEOARegistry is IERC165 { function isVerifiedEOA(address account) external view returns (bool); }
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.24; /** * @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); /// @dev Constant value for the default validator list ID. uint120 constant DEFAULT_LIST_ID = 0;
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; struct CollectionSecurityPolicyV3 { bool disableAuthorizationMode; bool authorizersCannotSetWildcardOperators; uint8 transferSecurityLevel; uint120 listId; bool enableAccountFreezingMode; uint16 tokenType; }
{ "remappings": [ "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "@limitbreak/tm-core-lib/=lib/tm-core-lib/", "@limitbreak/permit-c/=lib/PermitC/src/", "@openzeppelin/=lib/PermitC/lib/openzeppelin-contracts/", "@rari-capital/solmate/=lib/PermitC/lib/solmate/", "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/PermitC/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/", "tm-core-lib/=lib/tm-core-lib/src/" ], "optimizer": { "enabled": true, "runs": 777 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "evmVersion": "cancun", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"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"}],"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__CannotReassignOwnershipOfDefaultList","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
61028060405234801562000011575f80fd5b506040516200676a3803806200676a8339810160408190526200003491620006dc565b818185466001146200004e57662386f26fc1000062000058565b670494654067e100005b6001600160401b03168383825f6200006f62000317565b90506001600160a01b0381166200009957604051632aea588760e01b815260040160405180910390fd5b620000a48162000330565b5f805160206200674a833981519152805460ff19169115801592831790915560a091909152620001115762000392602090811b62002c2b176001600160401b0390811660c05262000399821b62002c3217811660e0526200039d90911b62002c361716610100526200014f565b620003a3602090811b62002c3c176001600160401b0390811660c052620003c7821b62002c7117811660e052620003ef90911b62002caa1716610100525b6001600160a01b0316608052620001663362000415565b8015620001b55762000464602090811b62002cdf176001600160401b039081166101405262000496821b62002d2c17811661016052620004e190911b62002d921716610180525f1901620001f5565b620004f9602090811b62002dc5176001600160401b0390811661014052620004bc821b62002d6e178116610160526200051d90911b62002de81716610180525b6101205281516020808401919091206101e05281519082012061020052466101c052620002856101e05161020051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b6101a052506200029790508262000415565b505050506001600160a01b0384161580620002b957506001600160a01b038316155b15620002d85760405163c56e5d7360e01b815260040160405180910390fd5b620002e38462000523565b50506001600160a01b0316610260525069040303020203020100026102205269030201020100000000006102405262000787565b5f696002601e613d5c3d52f35f52600a60165ff0905090565b5f816001600160a01b0316600a5a6200034a919062000767565b6040515f8181818686fa925050503d805f811462000384576040519150601f19603f3d011682016040523d82523d5f602084013e62000389565b606091505b50909392505050565b80825d5050565b5c90565b5f815d50565b5f805160206200674a8339815191525460ff1615620003c35780825d5050565b9055565b5f5f805160206200674a8339815191525460ff1615620003e657505c90565b5080545b919050565b5f805160206200674a8339815191525460ff16156200040e575f815d50565b5f81555b50565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61012051344703111562000412576001548116156200041257604051636623b92d60e11b815260040160405180910390fd5b6101205134470311620004bc5760405163fd2c901360e01b815260040160405180910390fd5b80600154165f03620004125760405163fd2c901360e01b815260040160405180910390fd5b610120515f903447031115620004f657506001545b90565b6001548116156200041257604051636623b92d60e11b815260040160405180910390fd5b60015490565b5f808052600a6020527f13da86008ba1c6922daee3e07db95305ef49ebced9f5467a0b8613fcc6b343e380546001600160a01b0384166001600160a01b031990911617905560405181907f5cc365f89543268cb9f25c255f7f610e9147e733c589bc2732279575f125be1490620005ba906020808252600c908201526b1111519055531508131254d560a21b604082015260600190565b60405180910390a26040516001600160a01b038316906001600160781b038316907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e27367905f90a35050565b80516001600160a01b0381168114620003ea575f80fd5b634e487b7160e01b5f52604160045260245ffd5b5f82601f8301126200063f575f80fd5b81516001600160401b03808211156200065c576200065c6200061b565b604051601f8301601f19908116603f011681019082821181831017156200068757620006876200061b565b8160405283815260209250866020858801011115620006a4575f80fd5b5f91505b83821015620006c75785820183015181830184015290820190620006a8565b5f602085830101528094505050505092915050565b5f805f8060808587031215620006f0575f80fd5b620006fb8562000604565b93506200070b6020860162000604565b60408601519093506001600160401b038082111562000728575f80fd5b62000736888389016200062f565b935060608701519150808211156200074c575f80fd5b506200075b878288016200062f565b91505092959194509250565b5f826200078257634e487b7160e01b5f52601260045260245ffd5b500490565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e05161020051610220516102405161026051615eb06200089a5f395f6120ed01525f8181610dc20152613f7c01525f8181610d950152613f4501525f613e9001525f613e6801525f613def01525f613e1701525f50505f50505f81816114b20152818161152c015281816115c3015281816118c401528181611a6301528181611bfc01528181611fbc01528181612344015281816125de0152818161265e01526127ac01525f818161138101528181612ce101528181612d2e0152612d9501525f50505f614d6101525f818161330a015261335601525f611e4501525f611eb30152615eb05ff3fe6080604052600436106105c1575f3560e01c80638254fcb7116102f0578063b97f6f8b11610191578063ddae38f2116100e7578063e34fda8511610092578063f7a2000a1161006d578063f7a2000a1461136f578063fb2de5d7146113a9578063ffbcb4aa146113c8575f80fd5b8063e34fda85146105e4578063e991dc3014611331578063f2fde38b14611350575f80fd5b8063df21dc1d116100c2578063df21dc1d146112bf578063df5fd29a146112f3578063e07cb24014611312575f80fd5b8063ddae38f214611262578063de02cbb114611281578063def0125b146112a0575f80fd5b8063d415f62f11610147578063db5f30a811610122578063db5f30a814611205578063dd71105d14611224578063dda964e314611243575f80fd5b8063d415f62f1461117f578063d5dc239a146111c7578063db188e63146111e6575f80fd5b8063c435f43511610177578063c435f43514611122578063caee23ea14611141578063cfea7ecf14611160575f80fd5b8063b97f6f8b146110e4578063bf7bfd7e14611103575f80fd5b8063a5d56b4611610246578063b67d8f99116101fc578063b89c4b0d116101d7578063b89c4b0d14610f73578063b8dcc68f14610f92578063b955455214610fb1575f80fd5b8063b67d8f9914610ee3578063b6e39ba114610f02578063b70510f514610f21575f80fd5b8063ad1ff6851161022c578063ad1ff68514610e71578063ae602f4414610e90578063b3992ab114610ec4575f80fd5b8063a5d56b4614610e07578063a87b03b614610e26575f80fd5b80638da5cb5b116102a6578063982d03c011610281578063982d03c014610d585780639c2a9c6f14610d77578063a1cc5cc114610de8575f80fd5b80638da5cb5b14610cea5780638e28800f14610d1a5780639340a7cc14610d39575f80fd5b806389631626116102d65780638963162614610c8d57806389a9c85514610cac5780638b6ee86514610ccb575f80fd5b80638254fcb714610c4057806386e1177414610c6e575f80fd5b80633e5c139d116104655780636498c045116103bb578063725d07c5116103665780637bac97de116103415780637bac97de14610be35780637c1e14b414610c025780637df81b9014610c21575f80fd5b8063725d07c514610b8e5780637423eb3c14610bad57806378e890ba14610bc1575f80fd5b8063715018a611610396578063715018a614610b3c5780637161ac8d14610b5057806371be859d14610b6f575f80fd5b80636498c04514610adf5780636971082814610afe5780636bfab91d14610b1d575f80fd5b80634c9d0b451161041b578063539d2602116103f6578063539d260214610a595780635e17263d14610a785780635ed5917f14610ac0575f80fd5b80634c9d0b45146109fc5780635079331514610a1b578063515f7b2814610a3a575f80fd5b80633f6560ee1161044b5780633f6560ee1461098a578063409dc573146109be5780634be52a89146109dd575f80fd5b80633e5c139d146109575780633e8a0bc914610976575f80fd5b80631854b2411161051a5780632c7fe70a116104d05780633779e6fd116104ab5780633779e6fd146108e55780633a0e3160146109195780633cda743a14610938575f80fd5b80632c7fe70a146108885780632eb0b98a146108a7578063317e3e8d146108c6575f80fd5b806323c992621161050057806323c9926214610813578063285fb8c81461084a57806328cc113114610869575f80fd5b80631854b241146107a55780631f2fdc79146107c4575f80fd5b80630f59197d1161057a578063136439dd11610555578063136439dd1461071457806316a17ce01461072757806316f18d7414610779575f80fd5b80630f59197d146106aa57806310b5c6a0146106c957806312d3848a146106f5575f80fd5b8063057497cb116105aa578063057497cb1461061a5780630ad388991461066c5780630e14021a1461068b575f80fd5b806301549930146105c557806301ffc9a7146105e6575b5f80fd5b3480156105d0575f80fd5b506105e46105df36600461503f565b6113f6565b005b3480156105f1575f80fd5b5061060561060036600461508e565b61141e565b60405190151581526020015b60405180910390f35b348015610625575f80fd5b506106056106343660046150cb565b6001600160781b0382165f908152600d602090815260408083206001600160a01b038516845260040190915290205460ff1692915050565b348015610677575f80fd5b506105e46106863660046150fc565b61149d565b348015610696575f80fd5b506106056106a5366004615153565b6114aa565b3480156106b5575f80fd5b506106056106c43660046151f6565b61151a565b3480156106d4575f80fd5b506106e86106e33660046152ae565b611598565b60405161061191906152c7565b348015610700575f80fd5b5061060561070f366004615313565b6115bb565b6105e4610722366004615364565b611629565b348015610732575f80fd5b506106056107413660046150cb565b6001600160781b0382165f908152600c602090815260408083206001600160a01b038516845260040190915290205460ff1692915050565b348015610784575f80fd5b506107986107933660046150fc565b61163a565b604051610611919061537b565b3480156107b0575f80fd5b506105e46107bf366004615313565b61166e565b3480156107cf575f80fd5b506106056107de3660046153b2565b6001600160a01b039091165f908152600660209081526040808320600885901c845290915290205460ff9091161c6001161590565b34801561081e575f80fd5b50600854610832906001600160781b031681565b6040516001600160781b039091168152602001610611565b348015610855575f80fd5b506105e46108643660046153da565b611681565b348015610874575f80fd5b506105e461088336600461541a565b61168c565b348015610893575f80fd5b506106056108a23660046153b2565b611699565b3480156108b2575f80fd5b506105e46108c136600461503f565b6116e4565b3480156108d1575f80fd5b506105e46108e0366004615457565b611745565b3480156108f0575f80fd5b506109046108ff3660046154f2565b6118b1565b60408051928352901515602083015201610611565b348015610924575f80fd5b506105e46109333660046153b2565b61193d565b348015610943575f80fd5b506106056109523660046155ad565b61194e565b348015610962575f80fd5b506106e86109713660046150fc565b61199b565b348015610981575f80fd5b506105e46119cf565b348015610995575f80fd5b506109a96109a43660046155c7565b611a0c565b60408051928352602083019190915201610611565b3480156109c9575f80fd5b506105e46109d836600461503f565b611a2c565b3480156109e8575f80fd5b506106056109f7366004615618565b611a51565b348015610a07575f80fd5b50610798610a163660046152ae565b611acc565b348015610a26575f80fd5b506105e4610a353660046155ad565b611af2565b348015610a45575f80fd5b506105e4610a5436600461503f565b611aff565b348015610a64575f80fd5b506105e4610a733660046156db565b611b24565b348015610a83575f80fd5b50610605610a92366004615777565b6001600160781b03919091165f908152600d6020908152604080832093835260059093019052205460ff1690565b348015610acb575f80fd5b50610605610ada366004615791565b611bf4565b348015610aea575f80fd5b506109a9610af936600461581d565b611c63565b348015610b09575f80fd5b506105e4610b1836600461503f565b611c85565b348015610b28575f80fd5b506105e4610b373660046150cb565b611ce5565b348015610b47575f80fd5b506105e4611d16565b348015610b5b575f80fd5b50610798610b6a3660046152ae565b611d29565b348015610b7a575f80fd5b506105e4610b89366004615878565b611d4f565b348015610b99575f80fd5b506106e8610ba83660046150fc565b611e20565b348015610bb8575f80fd5b506105e4611e43565b348015610bcc575f80fd5b50610bd5611f26565b604051908152602001610611565b348015610bee575f80fd5b50610605610bfd3660046155ad565b611f34565b348015610c0d575f80fd5b506105e4610c1c3660046153da565b611f81565b348015610c2c575f80fd5b50610605610c3b366004615893565b611fb4565b348015610c4b575f80fd5b50610605610c5a366004615364565b5f9081526004602052604090205460ff1690565b348015610c79575f80fd5b506105e4610c883660046153b2565b612022565b348015610c98575f80fd5b506106e8610ca73660046152ae565b6120a9565b348015610cb7575f80fd5b50610605610cc63660046150fc565b6120cc565b348015610cd6575f80fd5b506105e4610ce53660046152ae565b612158565b348015610cf5575f80fd5b505f546001600160a01b03165b6040516001600160a01b039091168152602001610611565b348015610d25575f80fd5b50610605610d343660046155ad565b612162565b348015610d44575f80fd5b50610798610d533660046150fc565b6121af565b348015610d63575f80fd5b506106e8610d723660046150fc565b6121e3565b348015610d82575f80fd5b506109a9610d91366004615364565b60ff7f000000000000000000000000000000000000000000000000000000000000000060039290921b91821c8116927f000000000000000000000000000000000000000000000000000000000000000090921c1690565b348015610df3575f80fd5b506105e4610e0236600461503f565b612217565b348015610e12575f80fd5b506105e4610e2136600461503f565b61223c565b348015610e31575f80fd5b50610605610e403660046155ad565b6001600160a01b039182165f908152600f602090815260408083209390941682526002909201909152205460ff1690565b348015610e7c575f80fd5b506105e4610e8b36600461581d565b61225f565b348015610e9b575f80fd5b50610d02610eaa3660046152ae565b600a6020525f90815260409020546001600160a01b031681565b348015610ecf575f80fd5b50610605610ede3660046158db565b612332565b348015610eee575f80fd5b50610605610efd3660046153b2565b6123ad565b348015610f0d575f80fd5b506105e4610f1c3660046153b2565b6123f5565b348015610f2c575f80fd5b50610605610f3b3660046150cb565b6001600160781b0382165f908152600e602090815260408083206001600160a01b038516845260040190915290205460ff1692915050565b348015610f7e575f80fd5b506105e4610f8d3660046153b2565b6123fb565b348015610f9d575f80fd5b50610832610fac366004615959565b612407565b348015610fbc575f80fd5b50611083610fcb3660046150fc565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a0810191909152506001600160a01b03165f908152600b6020908152604091829020825160c081018452905460ff8082161515835261010082048116151593830193909352620100008104831693820193909352630100000083046001600160781b03166060820152600160901b830490911615156080820152600160981b90910461ffff1660a082015290565b60405161061191905f60c08201905082511515825260208301511515602083015260ff60408401511660408301526001600160781b03606084015116606083015260808301511515608083015261ffff60a08401511660a083015292915050565b3480156110ef575f80fd5b506105e46110fe366004615998565b6124c7565b34801561110e575f80fd5b506105e461111d3660046159fa565b6124e7565b34801561112d575f80fd5b506105e461113c366004615364565b612594565b34801561114c575f80fd5b506105e461115b366004615893565b61259e565b34801561116b575f80fd5b5061090461117a366004615a22565b6125cb565b34801561118a575f80fd5b50610605611199366004615777565b6001600160781b03919091165f908152600c6020908152604080832093835260059093019052205460ff1690565b3480156111d2575f80fd5b506106056111e1366004615ad3565b612656565b3480156111f1575f80fd5b506105e4611200366004615959565b6126c4565b348015611210575f80fd5b506105e461121f366004615b6b565b612798565b34801561122f575f80fd5b5061060561123e366004615893565b6127a4565b34801561124e575f80fd5b506106e861125d3660046152ae565b612807565b34801561126d575f80fd5b506105e461127c36600461503f565b61282a565b34801561128c575f80fd5b5061083261129b366004615ba4565b61284f565b3480156112ab575f80fd5b506105e46112ba36600461503f565b6129dd565b3480156112ca575f80fd5b50610bd56112d93660046150fc565b6001600160a01b03165f9081526007602052604090205490565b3480156112fe575f80fd5b506105e461130d36600461503f565b612a00565b34801561131d575f80fd5b506105e461132c366004615878565b612a61565b34801561133c575f80fd5b506106e861134b3660046150fc565b612b2f565b34801561135b575f80fd5b506105e461136a3660046150fc565b612b63565b34801561137a575f80fd5b50600180547f0000000000000000000000000000000000000000000000000000000000000000909101906109a9565b3480156113b4575f80fd5b506105e46113c3366004615beb565b612b9b565b3480156113d3575f80fd5b506106056113e2366004615364565b5f9081526005602052604090205460ff1690565b6001600160781b0383165f908152600c6020526040812061141991858585612dee565b505050565b5f6001600160e01b03198216158061144657506001600160e01b03198216630dd9a30760e11b145b8061146157506001600160e01b03198216633016020d60e21b145b8061147c57506001600160e01b031982166389a9c85560e01b145b8061149757506301ffc9a760e01b6001600160e01b03198316145b92915050565b6114a7815f6123fb565b50565b5f6114d960107f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b6114ed6104838c8c8b8d8c8c8b8b8b612eb6565b6114fa8b87878d88612f87565b9050801561150c5761150c868a613024565b9a9950505050505050505050565b5f8361152581613079565b61155360107f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b6115668e8e8d8f8e8e8d8b8b8f8f6130a7565b8c6115748f8b8b848c612f87565b92508215611586576115868a8e613024565b50509c9b505050505050505050505050565b6001600160781b0381165f908152600c60205260409020606090611497906130bd565b5f6115ea60027f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b5f6115fb876104838787875f6130c9565b905061160a8588888787612f87565b9150811561161f5761161f81885f86816131a5565b5095945050505050565b611631613280565b6114a781613288565b6001600160a01b0381165f908152600b602052604090205460609061149790630100000090046001600160781b0316611d29565b61167a8585858561259e565b5050505050565b611419838383611f81565b611419600184845f6132cd565b6001600160a01b0382165f908152600b6020908152604080832054630100000090046001600160781b03168352600c825280832084845260050190915281205460ff165b9392505050565b611419600d5f856001600160781b03166001600160781b031681526020019081526020015f206001858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061337d92505050565b600960ff8516111561176a576040516317c5702360e01b815260040160405180910390fd5b6117738561342f565b6001600160a01b0385165f818152600b6020908152604091829020805462ff00ff19166201000060ff8a1690810260ff1916919091178815151772ff00000000000000000000000000000000ff0019166101008815150272ff000000000000000000000000000000000000191617600160901b871515021790915591519182527fb39d8f1e6f05413a407e46fc950eb92e9f5b3d65a47c3f0bdc7a2741a6ec0f7d910160405180910390a260408051841515815283151560208201526001600160a01b038716917f9c615afab54584e53810beb24cced6ca36919dfc62bff2d4a0d244906c41c2ac910160405180910390a2846001600160a01b03167f9c6e8620d0004b9dd8b49560e2de8ced6f409f529cc23d0bb9e5a106d5c43242826040516118a2911515815260200190565b60405180910390a25050505050565b5f80826118bd816134a3565b6118eb60407f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b5f6118fe8f8f8f8f8f8f8e8e8e8e6134d1565b9050611912818e8e8e8e8e8c612f876134f6565b9094509250821561192b5761192b818b888760016131a5565b50509b509b9950505050505050505050565b61194a600183835f6132cd565b5050565b6001600160a01b038281165f908152600b6020908152604080832054630100000090046001600160781b03168352600e82528083209385168352600490930190529081205460ff166116dd565b6001600160a01b0381165f908152600b602052604090205460609061149790630100000090046001600160781b0316612807565b335f8181526007602052604080822080546001019055517f8e8cebe67607ce50a14a2e3261437f641a7b33ecc053e3d9c90b25ae5e66c6569190a2565b5f80611a1e600288888888888761363c565b915091509550959350505050565b6001600160781b0383165f908152600d602052604090206114199060018585856136ab565b5f83611a5c81613079565b611a8a60207f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b611a9d8d5f8d8f8e8e8d8b8b8f8f613754565b611aaa8d8a8a5f8b613769565b91508115611abc57611abc898d613024565b509b9a5050505050505050505050565b6001600160781b0381165f908152600d60205260409020606090611497906002016130bd565b61194a82825f60016132cd565b6001600160781b0383165f908152600d60205260409020611419906001858585613873565b8365ffffffffffff16421115611b4d57604051630104f5db60e71b815260040160405180910390fd5b611b568b613919565b611b608389613952565b611bc0611bb8611bb38d8d8d8c6001600160c81b03168e8d8d65ffffffffffff168d65ffffffffffff1660075f8f6001600160a01b03166001600160a01b031681526020019081526020015f20546139a6565b613a46565b838386613a72565b65ffffffffffff851615611bd45784611bd6565b425b9450611be78b8b8b8a89888c613b3b565b5050505050505050505050565b5f611c2360087f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b611c396102d18a8a60018b8b8b60018b8b612eb6565b611c4585858b8b613be9565b90508015611c5757611c578588613024565b98975050505050505050565b5f80611c75600389898989898961363c565b915091505b965096945050505050565b611419600c5f856001600160781b03166001600160781b031681526020019081526020015f205f858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061337d92505050565b6001600160a01b038116611d0c576040516303e9dcb360e31b815260040160405180910390fd5b61194a8282613c72565b611d1e613d02565b611d275f613d2b565b565b6001600160781b0381165f908152600c60205260409020606090611497906002016130bd565b611d588361342f565b6001600160a01b0383165f908152600f60205260408120905b8281101561167a575f848483818110611d8c57611d8c615c26565b9050602002016020810190611da191906150fc565b9050611dad8382613d7a565b15611e1757806001600160a01b0316866001600160a01b03167f1138edbff75f319641eb242dbcacee294ebc2a473eb6aa1454a7706da5bf96b060405160405180910390a36001600160a01b0381165f9081526002840160205260409020805460ff191660011790555b50600101611d71565b6001600160a01b0381165f908152600f60205260409020606090611497906130bd565b7f000000000000000000000000000000000000000000000000000000000000000080611e9057507fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff165b15611eae57604051630f45b98b60e41b815260040160405180910390fd5b611ed77f0000000000000000000000000000000000000000000000000000000000000000613d8e565b611ef4576040516370a4078f60e01b815260040160405180910390fd5b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b00805460ff19166001179055611d2780565b5f611f2f613dec565b905090565b6001600160a01b038281165f908152600b6020908152604080832054630100000090046001600160781b03168352600c82528083209385168352600490930190529081205460ff166116dd565b5f611f92613ee0338686865f613efd565b5090506001600160e01b0319811615611fae57611fae816144c6565b50505050565b5f611fe360017f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b5f611ff5866102d186866001806130c9565b905061200386868686613be9565b915081156120195761201981875f6001816131a5565b50949350505050565b61202a613280565b6120335f613288565b801561194a575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114612082576040519150601f19603f3d011682016040523d82523d5f602084013e612087565b606091505b505090508061141957604051630fc77c5160e21b815260040160405180910390fd5b6001600160781b0381165f908152600d60205260409020606090611497906130bd565b6040516389a9c85560e01b81526001600160a01b0382811660048301525f917f0000000000000000000000000000000000000000000000000000000000000000909116906389a9c85590602401602060405180830381865afa158015612134573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114979190615c3a565b6114a7815f613c72565b6001600160a01b038281165f908152600b6020908152604080832054630100000090046001600160781b03168352600d82528083209385168352600490930190529081205460ff166116dd565b6001600160a01b0381165f908152600b602052604090205460609061149790630100000090046001600160781b0316611acc565b6001600160a01b0381165f908152600b602052604090205460609061149790630100000090046001600160781b0316611598565b6001600160781b0383165f908152600d60205260409020611419906001858585612dee565b6001600160781b0383165f908152600c60205260408120611419918585856136ab565b336001600160a01b038716148061227e5750336001600160a01b038616145b61229b5760405163eda7110360e01b815260040160405180910390fd5b6122a484613919565b5f6122b5600388878787878c6144ce565b805490915060ff166123105760028155604051600181526001600160a01b03878116919089169084907f705db7ac401a8091bb37a7838ad73d1fa8e1c663cb345f347fefe71280e3f03b9060200160405180910390a4612329565b60405163465fc3a960e11b815260040160405180910390fd5b50505050505050565b5f8361233d81613079565b61236b60087f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b6123808c8c60018d8d8d60018b8b8f8f614578565b61238c88888e8e613be9565b9150811561239e5761239e888b613024565b509a9950505050505050505050565b6001600160a01b0382165f908152600b6020908152604080832054630100000090046001600160781b03168352600d825280832084845260050190915281205460ff166116dd565b61194a82825b61194a5f8383826132cd565b600880546001600160781b038082166001019081166effffffffffffffffffffffffffffff1990921682179092555f818152600a60205260409081902080546001600160a01b03191633179055517f5cc365f89543268cb9f25c255f7f610e9147e733c589bc2732279575f125be14906124849086908690615c55565b60405180910390a260405133906001600160781b038316907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e27367905f90a392915050565b6124d086613919565b6124df86868685853389613b3b565b505050505050565b6124f08261342f565b6008546001600160781b03908116908216111561252057604051637b8b439360e11b815260040160405180910390fd5b6001600160a01b0382165f818152600b6020526040808220805471ffffffffffffffffffffffffffffff000000191663010000006001600160781b0387169081029190911790915590519092917fa66ff5557b7dc1562bb5e83306e15b513a25aa7537369bce38fc29c20847a79191a35050565b6114a73382613952565b5f6125af61458e3387878787613efd565b5090506001600160e01b031981161561167a5761167a816144c6565b5f80826125d7816134a3565b61260560807f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b5f6126188e8e8e8e5f8f8e8e8e8e6145f3565b905061262c818d8d5f8e8e8c6137696134f6565b9094509250821561264557612645818b888760016131a5565b50509a509a98505050505050505050565b5f61268560207f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b61269860148b5f8b8d8c8c8b8b8b612eb6565b6126a58a87875f88613769565b905080156126b7576126b7868a613024565b9998505050505050505050565b600160045f6040518060e0016040528060a58152602001615dd660a5913985856040516020016126f693929190615ca5565b6040516020818303038152906040528051906020012081526020019081526020015f205f6101000a81548160ff021916908315150217905550600160055f6040518060c00160405280609d8152602001615d39609d9139858560405160200161276193929190615ca5565b60408051808303601f190181529181528151602092830120835290820192909252015f20805460ff19169115159190911790555050565b6114198383835f6132cd565b5f6127d360047f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b5f6127e3866014865f875f6130c9565b90506127f28487875f87613769565b915081156120195761201981875f86816131a5565b6001600160781b0381165f908152600e60205260409020606090611497906130bd565b6001600160781b0383165f908152600e60205260409020611419906002858585612dee565b600880546effffffffffffffffffffffffffffff19811660016001600160781b03928316908101808416929092179093559190831611156128a357604051637b8b439360e11b815260040160405180910390fd5b6001600160781b0381165f818152600a60205260409081902080546001600160a01b03191633179055517f5cc365f89543268cb9f25c255f7f610e9147e733c589bc2732279575f125be14906128fc9087908790615c55565b60405180910390a260405133906001600160781b038316907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e27367905f90a36001600160781b038083165f908152600c60208181526040808420600d808452828620600e808652848820988a16885295855283872091855283872095909452918520909592949293919261299090888886614608565b61299c5f8888866146bb565b6129a96001888785614608565b6129b660018887856146bb565b6129c36002888684614608565b6129d060028886846146bb565b5050505050509392505050565b6001600160781b0383165f908152600c6020526040812061141991858585613873565b611419600e5f856001600160781b03166001600160781b031681526020019081526020015f206002858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061337d92505050565b612a6a8361342f565b6001600160a01b0383165f908152600f60205260408120905b8281101561167a575f848483818110612a9e57612a9e615c26565b9050602002016020810190612ab391906150fc565b9050612abf8382614755565b15612b2657806001600160a01b0316866001600160a01b03167f208795fcac393398e42038456348398d8cac9067232f671ab240444cb51b1d2060405160405180910390a36001600160a01b0381165f9081526002840160205260409020805460ff191690555b50600101612a83565b6001600160a01b0381165f908152600b602052604090205460609061149790630100000090046001600160781b03166120a9565b612b6b613d02565b6001600160a01b038116612b9257604051633e58254b60e01b815260040160405180910390fd5b6114a781613d2b565b612ba48261342f565b6001600160a01b0382165f818152600b602090815260409182902080547fffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffff16600160981b61ffff87169081029190911790915591519182527fa5c37ab91519073edd58e608f19f7ce383fd171f4f22c3612a1d0a7c1047794a910160405180910390a25050565b80825d5050565b5c90565b5f815d50565b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff1615612c6d5780825d5050565b9055565b5f7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff1615612ca157505c90565b5080545b919050565b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff1615612cda575f815d50565b5f9055565b7f000000000000000000000000000000000000000000000000000000000000000034470311156114a7576001548116156114a757604051636623b92d60e11b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000034470311612d6e5760405163fd2c901360e01b815260040160405180910390fd5b80600154165f036114a75760405163fd2c901360e01b815260040160405180910390fd5b5f7f00000000000000000000000000000000000000000000000000000000000000003447031115612dc257506001545b90565b6001548116156114a757604051636623b92d60e11b815260040160405180910390fd5b60015490565b82612df881614769565b5f805b83811015612eac57848482818110612e1557612e15615c26565b9050602002016020810190612e2a91906150fc565b9150612e368883613d7a565b15612ea457816001600160a01b0316866001600160781b03168860ff167fda8f3bd170446760f0f965a9b52bf271cb9679b5e0a70059eff2d49425229d1760405160405180910390a46001600160a01b0382165f9081526004890160205260409020805460ff191660011790555b600101612dfb565b5050505050505050565b5f612f75611bb38c8c8c8c8c8c60075f8e6001600160a01b03166001600160a01b031681526020019081526020015f2054604080517f932b8553b8e35bbee682d275cbe1cf115e14a777e2ca3266b4797369fb6317d3602080830191909152818301999099526001600160a01b03979097166060880152608087019590955260a086019390935260c08501919091523360e085015261010084015261012080840191909152815180840390910181526101409092019052805191012090565b9050611be78787868b898689896147a9565b5f612f986104838787878787614801565b90508061301b57604051637921219560e11b81526001600160a01b0386811660048301528581166024830152604482018590526064820184905260a060848301525f60a483015287169063f242432a9060c4015f604051808303815f87803b158015613002575f80fd5b505af1925050508015613013575060015b61301b575060015b95945050505050565b6001600160a01b0382165f908152600660209081526040808320600885901c845290915290208054600160ff84161b90811891829055161561194a5760405163e4adc0bf60e01b815260040160405180910390fd5b5f8181526004602052604090205460ff166114a757604051632391283760e11b815260040160405180910390fd5b611be76104838c8c8c8c8c8c8c8c8c8c8c61486b565b60605f6116dd8361489e565b5f6130da60028888888886336144ce565b805490915042600160d01b90910465ffffffffffff16101561310f57604051630104f5db60e71b815260040160405180910390fd5b805461010090046001600160c81b031683111561313f5760405163fee142c560e01b815260040160405180910390fd5b8115613159578054610100600160d01b031916815561319b565b80546001600160c81b036101009091048116101561319b5780546001600160c81b03610100808304821686900390911602610100600160d01b03199091161781555b9695505050505050565b811561167a57801561323957845460ff196001600160c81b036101008084048216860190911602167fffffffffffff00000000000000000000000000000000000000000000000000009091161785556040518281526001600160a01b0385169084907f83e0ca2c1392f14286fa1e41c797789d48c5827572e8bcc352d8943c1961eaf09060200160405180910390a361167a565b84546001600160c81b036101009091048116101561167a5784546001600160c81b036101008083048216850190911602610100600160d01b03199091161785555050505050565b611d27613d02565b600180549082905560408051828152602081018490527fe0d8d9ad73c586e8cf60ffd390b6f3654200a2d8857eb6abba4f6842a1210aae910160405180910390a15050565b8284336132db8383836148f7565b5f86815260096020526040902061333190886001600160a01b031686613301575f613307565b600160ff1b5b177f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b61232961334a87875f9182526020526040902060041c90565b886001600160a01b03167f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b8161338781614769565b5f805b8351811015612329578381815181106133a5576133a5615c26565b602090810291909101015191506133bc8783614755565b1561342757816001600160a01b0316856001600160781b03168760ff167f503012490a650739416858609e898957b874d17415a062945179c5735797884060405160405180910390a46001600160a01b0382165f9081526004880160205260409020805460ff191690555b60010161338a565b336001600160a01b0382168103613444575050565b5f61344e836149c1565b509050806001600160a01b0316826001600160a01b03160361346f57505050565b5f61347b848285614a09565b509050801561348a5750505050565b604051637f954ba160e01b815260040160405180910390fd5b5f8181526005602052604090205460ff166114a757604051632391283760e11b815260040160405180910390fd5b5f6134e78b8b8b6104838c8c8c8c8c8c8c614a75565b9b9a5050505050505050505050565b87546020880135905f9061010090046001600160c81b031682111561352857895461010090046001600160c81b031691505b886040013582101561354d5760405163b9ff981560e01b815260040160405180910390fd5b89546001600160c81b03610100808304821685900390911602610100600160d01b0319909116178a5560405182815233906001600160a01b0388169086907f2203cb053e6b01ec07e87d67d288d360ae164171185684936663b7d8fa9c534c9060200160405180910390a4895461010090046001600160c81b03165f0361361c57895460ff19166001178a556040515f815233906001600160a01b0388169086907f705db7ac401a8091bb37a7838ad73d1fa8e1c663cb345f347fefe71280e3f03b9060200160405180910390a45b61362d8887878a868863ffffffff16565b90509850989650505050505050565b5f805f61364e8a8a898989898e6144ce565b805490915042600160d01b90910465ffffffffffff161061367e57805461010090046001600160c81b0316613680565b5f5b90546001600160c81b039091169a600160d01b90910465ffffffffffff169950975050505050505050565b826136b581614769565b5f805b83811015612eac578484828181106136d2576136d2615c26565b9050602002013591506136f18289600201614bb490919063ffffffff16565b1561374c5781866001600160781b03168860ff167fc8615322788d404dfe307db9eef031bc148d1cec5e270a1fd6528a02b445d44560405160405180910390a45f8281526005890160205260409020805460ff191660011790555b6001016136b8565b611be760148c8c8c8c8c8c8c8c8c8c8c61486b565b5f61377960148787875f87614801565b90508061301b57604080516001600160a01b0387811660248301528681166044830152606480830186905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166323b872dd60e01b17905291515f928392908a16916137f89190615ccb565b5f604051808303815f865af19150503d805f8114613831576040519150601f19603f3d011682016040523d82523d5f602084013e613836565b606091505b5091509150816138495760019250613868565b80511561386857808060200190518101906138649190615c3a565b1592505b505095945050505050565b8261387d81614769565b5f805b83811015612eac5784848281811061389a5761389a615c26565b9050602002013591506138b98289600201614bbf90919063ffffffff16565b156139115781866001600160781b03168860ff167f061d78094976b1d9ae7bb858f141c915b46152756409caadb07482983c2ca30160405160405180910390a45f8281526005890160205260409020805460ff191690555b600101613880565b6102d181148061392a575061048381145b806139355750601481145b6114a757604051639d36a97960e01b815260040160405180910390fd5b6001600160a01b0382165f908152600660209081526040808320600885901c845290915290208054600160ff84161b908118918290551661194a5760405163d979627360e01b815260040160405180910390fd5b604080517ff9c04f8b028fcfa3315ea5accaee4589194a685f07cda0392e6ba9550706111960208201529081018a90526001600160a01b03808a1660608301526080820189905260a0820188905260c08201879052851660e08201526101008101849052610120810183905261014081018290525f90610160015b6040516020818303038152906040528051906020012090509998505050505050505050565b5f611497613a52613dec565b8360405161190160f01b8152600281019290925260228201526042902090565b6041829003613ad6578235602084013560408501355f90811a9080613a9989848787614bca565b91509150806001600160a01b0316866001600160a01b0316141580613abb5750815b15613acc57613acc868a8a8a614c73565b5050505050611fae565b6040829003613b2f57823560208401355f80613af3888585614cc6565b91509150806001600160a01b0316856001600160a01b0316141580613b155750815b15613b2657613b2685898989614c73565b50505050611fae565b611fae81858585614c73565b5f613b4c6002848a8a8a86886144ce565b805460ff16600160d01b65ffffffffffff8716908102610100600160d01b031916919091176101006001600160c81b038916908102919091178355604080518a815260208101929092528101919091529091506001600160a01b0383811691898216918616907f0ec867d4f1b037422566cd0248bae620e6c142dcf5631948271916e8ca8dd2639060600160405180910390a45050505050505050565b5f613bfb6102d1848787866001614801565b905080613c6a576040516323b872dd60e01b81526001600160a01b0386811660048301528581166024830152604482018490528416906323b872dd906064015f604051808303815f87803b158015613c51575f80fd5b505af1925050508015613c62575060015b613c6a575060015b949350505050565b6001600160781b038216613c995760405163519973e760e01b815260040160405180910390fd5b613ca282614769565b6001600160781b0382165f818152600a602052604080822080546001600160a01b0319166001600160a01b03861690811790915590519092917f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e2736791a35050565b5f546001600160a01b03163314611d27576040516208650f60e61b815260040160405180910390fd5b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f6116dd836001600160a01b038416614d0d565b5f816001600160a01b0316600a5a613da69190615ce6565b6040515f8181818686fa925050503d805f8114613dde576040519150601f19603f3d011682016040523d82523d5f602084013e613de3565b606091505b50909392505050565b5f7f00000000000000000000000000000000000000000000000000000000000000004603613e3957507f000000000000000000000000000000000000000000000000000000000000000090565b611f2f604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b5f838152600960205260408120612019908490614d59565b614d59565b5f80306001600160a01b03871603613f1957505f905080611c7a565b6001600160a01b0387165f908152600b602052604090208054630100000081046001600160781b0316907f00000000000000000000000000000000000000000000000000000000000000006107f862010000830460031b1690811c60ff908116927f000000000000000000000000000000000000000000000000000000000000000090921c811691600160901b90041615614034576001600160a01b03808c165f908152600f60209081526040808320938d1683526002840190915290205460ff1615613ff8575063056c6b9160e31b95505f9450611c7a9350505050565b6001600160a01b0389165f90815260028201602052604090205460ff16156140325750632a5cb1c360e01b95505f9450611c7a9350505050565b505b60048203614053575063d73e63af60e01b94505f9350611c7a92505050565b6001600160781b0383165f908152600d602052604090205f1982016140e757883b156140e2576001600160a01b0389165f90815260048201602052604090205460ff166140e2578c6140aa8d8d8b63ffffffff8516565b6140e057893f5f90815260058301602052604090205460ff166140e057506305652c5560e51b96505f9550611c7a945050505050565b505b614165565b60028203614165576140f8896120cc565b614165576001600160a01b0389165f90815260048201602052604090205460ff16614165578c61412d8d8d8b63ffffffff8516565b61416357893f5f90815260058301602052604090205460ff166141635750636719795560e11b96505f9550611c7a945050505050565b505b896001600160a01b03168b6001600160a01b0316036141a257600383146141a257505091545f9450600160981b900461ffff169250611c7a915050565b6001830361428e578c6141ba8d8d8b63ffffffff8516565b156141dc57505092545f9550600160981b900461ffff169350611c7a92505050565b5f600c5f876001600160781b03166001600160781b031681526020019081526020015f209050806004015f8e6001600160a01b03166001600160a01b031681526020019081526020015f205f9054906101000a900460ff1615614253575063204f370f60e11b97505f9650611c7a95505050505050565b8c3f5f90815260058201602052604090205460ff1615614287575063204f370f60e11b97505f9650611c7a95505050505050565b50506144a6565b60028303614356576001600160a01b038b165f90815260048201602052604090205460ff16156142d457505091545f9450600160981b900461ffff169250611c7a915050565b8c6142e48d8d8b63ffffffff8516565b1561430657505092545f9550600160981b900461ffff169350611c7a92505050565b8b3f5f90815260058301602052604090205460ff161561433d57505092545f9550600160981b900461ffff169350611c7a92505050565b5063ef28f90160e01b96505f9550611c7a945050505050565b600383036144a6576001600160a01b038b165f90815260048201602081905260409091205460ff16156143a057505092545f9550600160981b900461ffff169350611c7a92505050565b6001600160a01b038b165f9081526020829052604090205460ff16156143dd57505092545f9550600160981b900461ffff169350611c7a92505050565b8d6143ed8e8e8c63ffffffff8516565b1561441057505093545f9650600160981b900461ffff169450611c7a9350505050565b8c3f5f9081526005840160208190526040909120548e9060ff161561444f57505095545f9850600160981b900461ffff169650611c7a95505050505050565b508c3f5f908152602082905260409020548d9060ff161561448a57505095545f9850600160981b900461ffff169650611c7a95505050505050565b5063ef28f90160e01b99505f9850611c7a975050505050505050565b505091545f9b600160981b90910461ffff169a5098505050505050505050565b805f5260045ffd5b5f875f61453d89898989896001600160a01b039485165f818152600760209081526040918290205482518083019490945283830197909752949096166060820152608081019290925260a082015260c0808201939093528351808203909301835260e001909252805191012090565b81526020019081526020015f205f836001600160a01b03166001600160a01b031681526020019081526020015f209050979650505050505050565b611be76102d18c8c8c8c8c8c8c8c8c8c8c61486b565b5f806145aa84613ef887865f9182526020526040902060041c90565b50915081156145bd5760019150506116dd565b6145d584613ef8875f90815260096020526040902090565b909250905081801561301b575060ff81901c60011495945050505050565b5f6134e78b8b8b60148c8c8c8c8c8c8c614a75565b8181600481015f61461884614dbe565b90505f805b828110156146af5761462f8682614dc7565b915061463b8583613d7a565b156146a757816001600160a01b0316896001600160781b03168b60ff167fda8f3bd170446760f0f965a9b52bf271cb9679b5e0a70059eff2d49425229d1760405160405180910390a46001600160a01b0382165f908152602085905260409020805460ff191660011790555b60010161461d565b50505050505050505050565b6002808301908201600583015f6146d184614dbe565b90505f805b828110156146af576146e88682614dc7565b91506146f48583614bb4565b1561474d5781896001600160781b03168b60ff167fc8615322788d404dfe307db9eef031bc148d1cec5e270a1fd6528a02b445d44560405160405180910390a45f828152602085905260409020805460ff191660011790555b6001016146d6565b5f6116dd836001600160a01b038416614dd2565b6001600160781b0381165f908152600a60205260409020546001600160a01b031633146114a7576040516304e680cb60e41b815260040160405180910390fd5b864211156147ca5760405163e3fd7ac360e01b815260040160405180910390fd5b848611156147eb5760405163de7fafeb60e01b815260040160405180910390fd5b6147f58489613952565b612eac83838387613a72565b5f805f61481461458e89338a8a8a613efd565b909250905061ffff8116158061482d5750888161ffff16145b15614846576001600160e01b031982161515925061485f565b604051633d29aed360e11b815260040160405180910390fd5b50509695505050505050565b5f61487d8d8d8d8d8b8e8e8a8a614eb5565b905061488f8989888d8b868b8b6147a9565b50505050505050505050505050565b6060815f018054806020026020016040519081016040528092919081815260200182805480156148eb57602002820191905f5260205f20905b8154815260200190600101908083116148d7575b50505050509050919050565b6001600160a01b0383165f908152600b60205260409020805460ff16156149315760405163b1ae736760e01b815260040160405180910390fd5b8054610100900460ff161561496a575f196001600160a01b0384160161496a5760405163bf729bb160e01b815260040160405180910390fd5b8054630100000090046001600160781b03165f908152600e602090815260408083206001600160a01b038616845260040190915290205460ff16611fae57604051635e47503160e11b815260040160405180910390fd5b5f806149f7565b638da5cb5b5f525f8060205f6004601c865afa60203d101516156149ef575f519150915091565b509160019150565b614a00836149c8565b91509150915091565b5f80614a5e565b5f80604051606081016040526391d14854815284816020015285816040015260205f6044601c8401875afa60203d10151615614a50575f51925050614a56565b50600190505b935093915050565b614a69838587614a10565b91509150935093915050565b5f6001600160c81b038a351115614a9f57604051633b0a334360e01b815260040160405180910390fd5b614aaf6003878b8b8b88336144ce565b805490915060ff1661231057805461010090046001600160c81b03165f03614b8357614af6614aee8a8a8a8e358b8b65ffffffffffff8c168b8b614eb5565b8d8d89613a72565b805460ff166101008b356001600160c81b0381169190910279ffffffffffffffffffffffffffffffffffffffffffffffffffff1691909117600160d01b65ffffffffffff87160217825560405190815233906001600160a01b0388169085907f257001e1f7fbfc5bbde5da225c876ab67293f37bda3afb8b35d9a55dfad6f65d9060200160405180910390a45b8054600160d01b900465ffffffffffff164211156134e75760405163e3fd7ac360e01b815260040160405180910390fd5b5f6116dd8383614d0d565b5f6116dd8383614dd2565b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614bff5750600190505f614c6a565b604080515f81526020810180835288905260ff871691810191909152606081018590526080810184905260019060a0016020604051602081039080840390855afa158015614c4f573d5f803e3d5ffd5b5050604051601f1901516001600160a01b0381161593509150505b94509492505050565b836001600160a01b03163b5f03614c9d576040516373c919b560e01b815260040160405180910390fd5b614ca984848484614ee1565b611fae576040516373c919b560e01b815260040160405180910390fd5b5f807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316601b60ff85901c01614cff87828885614bca565b909890975095505050505050565b5f818152600183016020526040812054614d5257508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155611497565b505f611497565b5f80614d88837f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b9050806001600160a01b03811660011480614db45750846001600160a01b0316816001600160a01b0316145b9250509250929050565b5f611497825490565b5f6116dd8383614f5d565b5f8181526001830160205260408120548015614eac575f614df4600183615d05565b85549091505f90614e0790600190615d05565b9050808214614e66575f865f018281548110614e2557614e25615c26565b905f5260205f200154905080875f018481548110614e4557614e45615c26565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080614e7757614e77615d24565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050611497565b5f915050611497565b6001600160a01b0385165f908152600760205260408120546134e7611bb38c8c8c8c8b8b8b8b8a614f83565b5f614f51565b5f604051630b135d3f60e11b81528360048201526040602482015285604482015285856064830137601f19601f87011660640180820160405260205f8284875afa60203d10151615614f4757630b135d3f60e11b5f511492505050613c6a565b5050949350505050565b61301b82848688614ee7565b5f825f018281548110614f7257614f72615c26565b905f5260205f200154905092915050565b60408051602081018490529081018a90526001600160a01b03891660608201526080810188905260a0810187905260c081018690523360e08201526101008101859052610120810182905261014081018490525f9061016001613a21565b80356001600160781b0381168114612ca5575f80fd5b5f8083601f840112615007575f80fd5b50813567ffffffffffffffff81111561501e575f80fd5b6020830191508360208260051b8501011115615038575f80fd5b9250929050565b5f805f60408486031215615051575f80fd5b61505a84614fe1565b9250602084013567ffffffffffffffff811115615075575f80fd5b61508186828701614ff7565b9497909650939450505050565b5f6020828403121561509e575f80fd5b81356001600160e01b0319811681146116dd575f80fd5b80356001600160a01b0381168114612ca5575f80fd5b5f80604083850312156150dc575f80fd5b6150e583614fe1565b91506150f3602084016150b5565b90509250929050565b5f6020828403121561510c575f80fd5b6116dd826150b5565b5f8083601f840112615125575f80fd5b50813567ffffffffffffffff81111561513c575f80fd5b602083019150836020828501011115615038575f80fd5b5f805f805f805f805f806101208b8d03121561516d575f80fd5b6151768b6150b5565b995060208b0135985060408b0135975060608b0135965060808b013595506151a060a08c016150b5565b94506151ae60c08c016150b5565b935060e08b013592506101008b013567ffffffffffffffff8111156151d1575f80fd5b6151dd8d828e01615115565b915080935050809150509295989b9194979a5092959850565b5f805f805f805f805f805f806101608d8f031215615212575f80fd5b61521b8d6150b5565b9b5060208d01359a5060408d0135995060608d0135985060808d0135975061524560a08e016150b5565b965061525360c08e016150b5565b955060e08d013594506101008d013593506101208d0135925067ffffffffffffffff6101408e01351115615285575f80fd5b6152968e6101408f01358f01615115565b81935080925050509295989b509295989b509295989b565b5f602082840312156152be575f80fd5b6116dd82614fe1565b602080825282518282018190525f9190848201906040850190845b818110156153075783516001600160a01b0316835292840192918401916001016152e2565b50909695505050505050565b5f805f805f60a08688031215615327575f80fd5b615330866150b5565b945061533e602087016150b5565b935061534c604087016150b5565b94979396509394606081013594506080013592915050565b5f60208284031215615374575f80fd5b5035919050565b602080825282518282018190525f9190848201906040850190845b8181101561530757835183529284019291840191600101615396565b5f80604083850312156153c3575f80fd5b6153cc836150b5565b946020939093013593505050565b5f805f606084860312156153ec575f80fd5b6153f5846150b5565b9250615403602085016150b5565b9150615411604085016150b5565b90509250925092565b5f805f6060848603121561542c575f80fd5b615435846150b5565b95602085013595506040909401359392505050565b80151581146114a7575f80fd5b5f805f805f60a0868803121561546b575f80fd5b615474866150b5565b9450602086013560ff81168114615489575f80fd5b935060408601356154998161544a565b925060608601356154a98161544a565b915060808601356154b98161544a565b809150509295509295909350565b5f606082840312156154d7575f80fd5b50919050565b803565ffffffffffff81168114612ca5575f80fd5b5f805f805f805f805f805f6101808c8e03121561550d575f80fd5b8b3567ffffffffffffffff811115615523575f80fd5b61552f8e828f01615115565b909c509a5061554390508d60208e016154c7565b985061555160808d016150b5565b975060a08c0135965061556660c08d016150b5565b955061557460e08d016150b5565b94506101008c0135935061558b6101208d016154dd565b92506101408c013591506101608c013590509295989b509295989b9093969950565b5f80604083850312156155be575f80fd5b6150e5836150b5565b5f805f805f60a086880312156155db575f80fd5b6155e4866150b5565b94506155f2602087016150b5565b935060408601359250615607606087016150b5565b949793965091946080013592915050565b5f805f805f805f805f805f6101408c8e031215615633575f80fd5b61563c8c6150b5565b9a5060208c0135995060408c0135985060608c0135975061565f60808d016150b5565b965061566d60a08d016150b5565b955060c08c0135945060e08c013593506101008c013592506101208c013567ffffffffffffffff81111561569f575f80fd5b6156ab8e828f01615115565b915080935050809150509295989b509295989b9093969950565b80356001600160c81b0381168114612ca5575f80fd5b5f805f805f805f805f805f6101408c8e0312156156f6575f80fd5b8b359a5061570660208d016150b5565b995060408c0135985060608c0135975061572260808d016156c5565b965061573060a08d016150b5565b955061573e60c08d016154dd565b945061574c60e08d016154dd565b935061575b6101008d016150b5565b92506101208c013567ffffffffffffffff81111561569f575f80fd5b5f8060408385031215615788575f80fd5b6153cc83614fe1565b5f805f805f805f8060e0898b0312156157a8575f80fd5b6157b1896150b5565b97506020890135965060408901359550606089013594506157d460808a016150b5565b93506157e260a08a016150b5565b925060c089013567ffffffffffffffff8111156157fd575f80fd5b6158098b828c01615115565b999c989b5096995094979396929594505050565b5f805f805f8060c08789031215615832575f80fd5b61583b876150b5565b9550615849602088016150b5565b94506040870135935061585e606088016150b5565b92506080870135915060a087013590509295509295509295565b5f805f6040848603121561588a575f80fd5b61505a846150b5565b5f805f80608085870312156158a6575f80fd5b6158af856150b5565b93506158bd602086016150b5565b92506158cb604086016150b5565b9396929550929360600135925050565b5f805f805f805f805f806101208b8d0312156158f5575f80fd5b6158fe8b6150b5565b995060208b0135985060408b0135975060608b0135965061592160808c016150b5565b955061592f60a08c016150b5565b945060c08b0135935060e08b013592506101008b013567ffffffffffffffff8111156151d1575f80fd5b5f806020838503121561596a575f80fd5b823567ffffffffffffffff811115615980575f80fd5b61598c85828601615115565b90969095509350505050565b5f805f805f8060c087890312156159ad575f80fd5b863595506159bd602088016150b5565b9450604087013593506159d2606088016150b5565b92506159e0608088016156c5565b91506159ee60a088016154dd565b90509295509295509295565b5f8060408385031215615a0b575f80fd5b615a14836150b5565b91506150f360208401614fe1565b5f805f805f805f805f806101608b8d031215615a3c575f80fd5b8a3567ffffffffffffffff811115615a52575f80fd5b615a5e8d828e01615115565b909b509950615a7290508c60208d016154c7565b9750615a8060808c016150b5565b9650615a8e60a08c016150b5565b9550615a9c60c08c016150b5565b945060e08b01359350615ab26101008c016154dd565b92506101208b013591506101408b013590509295989b9194979a5092959850565b5f805f805f805f805f6101008a8c031215615aec575f80fd5b615af58a6150b5565b985060208a0135975060408a0135965060608a01359550615b1860808b016150b5565b9450615b2660a08b016150b5565b935060c08a0135925060e08a013567ffffffffffffffff811115615b48575f80fd5b615b548c828d01615115565b915080935050809150509295985092959850929598565b5f805f60608486031215615b7d575f80fd5b615b86846150b5565b9250615b94602085016150b5565b9150604084013590509250925092565b5f805f60408486031215615bb6575f80fd5b833567ffffffffffffffff811115615bcc575f80fd5b615bd886828701615115565b9094509250615411905060208501614fe1565b5f8060408385031215615bfc575f80fd5b615c05836150b5565b9150602083013561ffff81168114615c1b575f80fd5b809150509250929050565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215615c4a575f80fd5b81516116dd8161544a565b60208152816020820152818360408301375f818301604090810191909152601f909201601f19160101919050565b5f5b83811015615c9d578181015183820152602001615c85565b50505f910152565b5f8451615cb6818460208901615c83565b8201838582375f930192835250909392505050565b5f8251615cdc818460208701615c83565b9190910192915050565b5f82615d0057634e487b7160e01b5f52601260045260245ffd5b500490565b8181038181111561149757634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603160045260245ffdfe5065726d69744f72646572576974684164646974696f6e616c446174612875696e7432353620746f6b656e547970652c6164647265737320746f6b656e2c75696e743235362069642c75696e7432353620616d6f756e742c75696e743235362073616c742c61646472657373206f70657261746f722c75696e743235362065787069726174696f6e2c75696e74323536206d61737465724e6f6e63652c5065726d69745472616e7366657246726f6d576974684164646974696f6e616c446174612875696e7432353620746f6b656e547970652c6164647265737320746f6b656e2c75696e743235362069642c75696e7432353620616d6f756e742c75696e74323536206e6f6e63652c61646472657373206f70657261746f722c75696e743235362065787069726174696f6e2c75696e74323536206d61737465724e6f6e63652ca2646970667358221220a90ba9bdaeca58f1ff72597bd40a48511cb4d6531d0ea891d978e9112f6daab564736f6c63430008180033dacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b00000000000000000000000000591aa9dff01b8144dc17cb416001d9ac84b951cd000000000000000000000000e0a0004dfa318fc38298ae81a666710eadceba5c000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000001d43726561746f72546f6b656e5472616e7366657256616c696461746f7200000000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106105c1575f3560e01c80638254fcb7116102f0578063b97f6f8b11610191578063ddae38f2116100e7578063e34fda8511610092578063f7a2000a1161006d578063f7a2000a1461136f578063fb2de5d7146113a9578063ffbcb4aa146113c8575f80fd5b8063e34fda85146105e4578063e991dc3014611331578063f2fde38b14611350575f80fd5b8063df21dc1d116100c2578063df21dc1d146112bf578063df5fd29a146112f3578063e07cb24014611312575f80fd5b8063ddae38f214611262578063de02cbb114611281578063def0125b146112a0575f80fd5b8063d415f62f11610147578063db5f30a811610122578063db5f30a814611205578063dd71105d14611224578063dda964e314611243575f80fd5b8063d415f62f1461117f578063d5dc239a146111c7578063db188e63146111e6575f80fd5b8063c435f43511610177578063c435f43514611122578063caee23ea14611141578063cfea7ecf14611160575f80fd5b8063b97f6f8b146110e4578063bf7bfd7e14611103575f80fd5b8063a5d56b4611610246578063b67d8f99116101fc578063b89c4b0d116101d7578063b89c4b0d14610f73578063b8dcc68f14610f92578063b955455214610fb1575f80fd5b8063b67d8f9914610ee3578063b6e39ba114610f02578063b70510f514610f21575f80fd5b8063ad1ff6851161022c578063ad1ff68514610e71578063ae602f4414610e90578063b3992ab114610ec4575f80fd5b8063a5d56b4614610e07578063a87b03b614610e26575f80fd5b80638da5cb5b116102a6578063982d03c011610281578063982d03c014610d585780639c2a9c6f14610d77578063a1cc5cc114610de8575f80fd5b80638da5cb5b14610cea5780638e28800f14610d1a5780639340a7cc14610d39575f80fd5b806389631626116102d65780638963162614610c8d57806389a9c85514610cac5780638b6ee86514610ccb575f80fd5b80638254fcb714610c4057806386e1177414610c6e575f80fd5b80633e5c139d116104655780636498c045116103bb578063725d07c5116103665780637bac97de116103415780637bac97de14610be35780637c1e14b414610c025780637df81b9014610c21575f80fd5b8063725d07c514610b8e5780637423eb3c14610bad57806378e890ba14610bc1575f80fd5b8063715018a611610396578063715018a614610b3c5780637161ac8d14610b5057806371be859d14610b6f575f80fd5b80636498c04514610adf5780636971082814610afe5780636bfab91d14610b1d575f80fd5b80634c9d0b451161041b578063539d2602116103f6578063539d260214610a595780635e17263d14610a785780635ed5917f14610ac0575f80fd5b80634c9d0b45146109fc5780635079331514610a1b578063515f7b2814610a3a575f80fd5b80633f6560ee1161044b5780633f6560ee1461098a578063409dc573146109be5780634be52a89146109dd575f80fd5b80633e5c139d146109575780633e8a0bc914610976575f80fd5b80631854b2411161051a5780632c7fe70a116104d05780633779e6fd116104ab5780633779e6fd146108e55780633a0e3160146109195780633cda743a14610938575f80fd5b80632c7fe70a146108885780632eb0b98a146108a7578063317e3e8d146108c6575f80fd5b806323c992621161050057806323c9926214610813578063285fb8c81461084a57806328cc113114610869575f80fd5b80631854b241146107a55780631f2fdc79146107c4575f80fd5b80630f59197d1161057a578063136439dd11610555578063136439dd1461071457806316a17ce01461072757806316f18d7414610779575f80fd5b80630f59197d146106aa57806310b5c6a0146106c957806312d3848a146106f5575f80fd5b8063057497cb116105aa578063057497cb1461061a5780630ad388991461066c5780630e14021a1461068b575f80fd5b806301549930146105c557806301ffc9a7146105e6575b5f80fd5b3480156105d0575f80fd5b506105e46105df36600461503f565b6113f6565b005b3480156105f1575f80fd5b5061060561060036600461508e565b61141e565b60405190151581526020015b60405180910390f35b348015610625575f80fd5b506106056106343660046150cb565b6001600160781b0382165f908152600d602090815260408083206001600160a01b038516845260040190915290205460ff1692915050565b348015610677575f80fd5b506105e46106863660046150fc565b61149d565b348015610696575f80fd5b506106056106a5366004615153565b6114aa565b3480156106b5575f80fd5b506106056106c43660046151f6565b61151a565b3480156106d4575f80fd5b506106e86106e33660046152ae565b611598565b60405161061191906152c7565b348015610700575f80fd5b5061060561070f366004615313565b6115bb565b6105e4610722366004615364565b611629565b348015610732575f80fd5b506106056107413660046150cb565b6001600160781b0382165f908152600c602090815260408083206001600160a01b038516845260040190915290205460ff1692915050565b348015610784575f80fd5b506107986107933660046150fc565b61163a565b604051610611919061537b565b3480156107b0575f80fd5b506105e46107bf366004615313565b61166e565b3480156107cf575f80fd5b506106056107de3660046153b2565b6001600160a01b039091165f908152600660209081526040808320600885901c845290915290205460ff9091161c6001161590565b34801561081e575f80fd5b50600854610832906001600160781b031681565b6040516001600160781b039091168152602001610611565b348015610855575f80fd5b506105e46108643660046153da565b611681565b348015610874575f80fd5b506105e461088336600461541a565b61168c565b348015610893575f80fd5b506106056108a23660046153b2565b611699565b3480156108b2575f80fd5b506105e46108c136600461503f565b6116e4565b3480156108d1575f80fd5b506105e46108e0366004615457565b611745565b3480156108f0575f80fd5b506109046108ff3660046154f2565b6118b1565b60408051928352901515602083015201610611565b348015610924575f80fd5b506105e46109333660046153b2565b61193d565b348015610943575f80fd5b506106056109523660046155ad565b61194e565b348015610962575f80fd5b506106e86109713660046150fc565b61199b565b348015610981575f80fd5b506105e46119cf565b348015610995575f80fd5b506109a96109a43660046155c7565b611a0c565b60408051928352602083019190915201610611565b3480156109c9575f80fd5b506105e46109d836600461503f565b611a2c565b3480156109e8575f80fd5b506106056109f7366004615618565b611a51565b348015610a07575f80fd5b50610798610a163660046152ae565b611acc565b348015610a26575f80fd5b506105e4610a353660046155ad565b611af2565b348015610a45575f80fd5b506105e4610a5436600461503f565b611aff565b348015610a64575f80fd5b506105e4610a733660046156db565b611b24565b348015610a83575f80fd5b50610605610a92366004615777565b6001600160781b03919091165f908152600d6020908152604080832093835260059093019052205460ff1690565b348015610acb575f80fd5b50610605610ada366004615791565b611bf4565b348015610aea575f80fd5b506109a9610af936600461581d565b611c63565b348015610b09575f80fd5b506105e4610b1836600461503f565b611c85565b348015610b28575f80fd5b506105e4610b373660046150cb565b611ce5565b348015610b47575f80fd5b506105e4611d16565b348015610b5b575f80fd5b50610798610b6a3660046152ae565b611d29565b348015610b7a575f80fd5b506105e4610b89366004615878565b611d4f565b348015610b99575f80fd5b506106e8610ba83660046150fc565b611e20565b348015610bb8575f80fd5b506105e4611e43565b348015610bcc575f80fd5b50610bd5611f26565b604051908152602001610611565b348015610bee575f80fd5b50610605610bfd3660046155ad565b611f34565b348015610c0d575f80fd5b506105e4610c1c3660046153da565b611f81565b348015610c2c575f80fd5b50610605610c3b366004615893565b611fb4565b348015610c4b575f80fd5b50610605610c5a366004615364565b5f9081526004602052604090205460ff1690565b348015610c79575f80fd5b506105e4610c883660046153b2565b612022565b348015610c98575f80fd5b506106e8610ca73660046152ae565b6120a9565b348015610cb7575f80fd5b50610605610cc63660046150fc565b6120cc565b348015610cd6575f80fd5b506105e4610ce53660046152ae565b612158565b348015610cf5575f80fd5b505f546001600160a01b03165b6040516001600160a01b039091168152602001610611565b348015610d25575f80fd5b50610605610d343660046155ad565b612162565b348015610d44575f80fd5b50610798610d533660046150fc565b6121af565b348015610d63575f80fd5b506106e8610d723660046150fc565b6121e3565b348015610d82575f80fd5b506109a9610d91366004615364565b60ff7f000000000000000000000000000000000000000000000403030202030201000260039290921b91821c8116927f000000000000000000000000000000000000000000000302010201000000000090921c1690565b348015610df3575f80fd5b506105e4610e0236600461503f565b612217565b348015610e12575f80fd5b506105e4610e2136600461503f565b61223c565b348015610e31575f80fd5b50610605610e403660046155ad565b6001600160a01b039182165f908152600f602090815260408083209390941682526002909201909152205460ff1690565b348015610e7c575f80fd5b506105e4610e8b36600461581d565b61225f565b348015610e9b575f80fd5b50610d02610eaa3660046152ae565b600a6020525f90815260409020546001600160a01b031681565b348015610ecf575f80fd5b50610605610ede3660046158db565b612332565b348015610eee575f80fd5b50610605610efd3660046153b2565b6123ad565b348015610f0d575f80fd5b506105e4610f1c3660046153b2565b6123f5565b348015610f2c575f80fd5b50610605610f3b3660046150cb565b6001600160781b0382165f908152600e602090815260408083206001600160a01b038516845260040190915290205460ff1692915050565b348015610f7e575f80fd5b506105e4610f8d3660046153b2565b6123fb565b348015610f9d575f80fd5b50610832610fac366004615959565b612407565b348015610fbc575f80fd5b50611083610fcb3660046150fc565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a0810191909152506001600160a01b03165f908152600b6020908152604091829020825160c081018452905460ff8082161515835261010082048116151593830193909352620100008104831693820193909352630100000083046001600160781b03166060820152600160901b830490911615156080820152600160981b90910461ffff1660a082015290565b60405161061191905f60c08201905082511515825260208301511515602083015260ff60408401511660408301526001600160781b03606084015116606083015260808301511515608083015261ffff60a08401511660a083015292915050565b3480156110ef575f80fd5b506105e46110fe366004615998565b6124c7565b34801561110e575f80fd5b506105e461111d3660046159fa565b6124e7565b34801561112d575f80fd5b506105e461113c366004615364565b612594565b34801561114c575f80fd5b506105e461115b366004615893565b61259e565b34801561116b575f80fd5b5061090461117a366004615a22565b6125cb565b34801561118a575f80fd5b50610605611199366004615777565b6001600160781b03919091165f908152600c6020908152604080832093835260059093019052205460ff1690565b3480156111d2575f80fd5b506106056111e1366004615ad3565b612656565b3480156111f1575f80fd5b506105e4611200366004615959565b6126c4565b348015611210575f80fd5b506105e461121f366004615b6b565b612798565b34801561122f575f80fd5b5061060561123e366004615893565b6127a4565b34801561124e575f80fd5b506106e861125d3660046152ae565b612807565b34801561126d575f80fd5b506105e461127c36600461503f565b61282a565b34801561128c575f80fd5b5061083261129b366004615ba4565b61284f565b3480156112ab575f80fd5b506105e46112ba36600461503f565b6129dd565b3480156112ca575f80fd5b50610bd56112d93660046150fc565b6001600160a01b03165f9081526007602052604090205490565b3480156112fe575f80fd5b506105e461130d36600461503f565b612a00565b34801561131d575f80fd5b506105e461132c366004615878565b612a61565b34801561133c575f80fd5b506106e861134b3660046150fc565b612b2f565b34801561135b575f80fd5b506105e461136a3660046150fc565b612b63565b34801561137a575f80fd5b50600180547f000000000000000000000000000000000000000000000000002386f26fc0ffff909101906109a9565b3480156113b4575f80fd5b506105e46113c3366004615beb565b612b9b565b3480156113d3575f80fd5b506106056113e2366004615364565b5f9081526005602052604090205460ff1690565b6001600160781b0383165f908152600c6020526040812061141991858585612dee565b505050565b5f6001600160e01b03198216158061144657506001600160e01b03198216630dd9a30760e11b145b8061146157506001600160e01b03198216633016020d60e21b145b8061147c57506001600160e01b031982166389a9c85560e01b145b8061149757506301ffc9a760e01b6001600160e01b03198316145b92915050565b6114a7815f6123fb565b50565b5f6114d960107f0000000000000000000000000000000000000000000000000000046400002cdf63ffffffff16565b6114ed6104838c8c8b8d8c8c8b8b8b612eb6565b6114fa8b87878d88612f87565b9050801561150c5761150c868a613024565b9a9950505050505050505050565b5f8361152581613079565b61155360107f0000000000000000000000000000000000000000000000000000046400002cdf63ffffffff16565b6115668e8e8d8f8e8e8d8b8b8f8f6130a7565b8c6115748f8b8b848c612f87565b92508215611586576115868a8e613024565b50509c9b505050505050505050505050565b6001600160781b0381165f908152600c60205260409020606090611497906130bd565b5f6115ea60027f0000000000000000000000000000000000000000000000000000046400002cdf63ffffffff16565b5f6115fb876104838787875f6130c9565b905061160a8588888787612f87565b9150811561161f5761161f81885f86816131a5565b5095945050505050565b611631613280565b6114a781613288565b6001600160a01b0381165f908152600b602052604090205460609061149790630100000090046001600160781b0316611d29565b61167a8585858561259e565b5050505050565b611419838383611f81565b611419600184845f6132cd565b6001600160a01b0382165f908152600b6020908152604080832054630100000090046001600160781b03168352600c825280832084845260050190915281205460ff165b9392505050565b611419600d5f856001600160781b03166001600160781b031681526020019081526020015f206001858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061337d92505050565b600960ff8516111561176a576040516317c5702360e01b815260040160405180910390fd5b6117738561342f565b6001600160a01b0385165f818152600b6020908152604091829020805462ff00ff19166201000060ff8a1690810260ff1916919091178815151772ff00000000000000000000000000000000ff0019166101008815150272ff000000000000000000000000000000000000191617600160901b871515021790915591519182527fb39d8f1e6f05413a407e46fc950eb92e9f5b3d65a47c3f0bdc7a2741a6ec0f7d910160405180910390a260408051841515815283151560208201526001600160a01b038716917f9c615afab54584e53810beb24cced6ca36919dfc62bff2d4a0d244906c41c2ac910160405180910390a2846001600160a01b03167f9c6e8620d0004b9dd8b49560e2de8ced6f409f529cc23d0bb9e5a106d5c43242826040516118a2911515815260200190565b60405180910390a25050505050565b5f80826118bd816134a3565b6118eb60407f0000000000000000000000000000000000000000000000000000046400002cdf63ffffffff16565b5f6118fe8f8f8f8f8f8f8e8e8e8e6134d1565b9050611912818e8e8e8e8e8c612f876134f6565b9094509250821561192b5761192b818b888760016131a5565b50509b509b9950505050505050505050565b61194a600183835f6132cd565b5050565b6001600160a01b038281165f908152600b6020908152604080832054630100000090046001600160781b03168352600e82528083209385168352600490930190529081205460ff166116dd565b6001600160a01b0381165f908152600b602052604090205460609061149790630100000090046001600160781b0316612807565b335f8181526007602052604080822080546001019055517f8e8cebe67607ce50a14a2e3261437f641a7b33ecc053e3d9c90b25ae5e66c6569190a2565b5f80611a1e600288888888888761363c565b915091509550959350505050565b6001600160781b0383165f908152600d602052604090206114199060018585856136ab565b5f83611a5c81613079565b611a8a60207f0000000000000000000000000000000000000000000000000000046400002cdf63ffffffff16565b611a9d8d5f8d8f8e8e8d8b8b8f8f613754565b611aaa8d8a8a5f8b613769565b91508115611abc57611abc898d613024565b509b9a5050505050505050505050565b6001600160781b0381165f908152600d60205260409020606090611497906002016130bd565b61194a82825f60016132cd565b6001600160781b0383165f908152600d60205260409020611419906001858585613873565b8365ffffffffffff16421115611b4d57604051630104f5db60e71b815260040160405180910390fd5b611b568b613919565b611b608389613952565b611bc0611bb8611bb38d8d8d8c6001600160c81b03168e8d8d65ffffffffffff168d65ffffffffffff1660075f8f6001600160a01b03166001600160a01b031681526020019081526020015f20546139a6565b613a46565b838386613a72565b65ffffffffffff851615611bd45784611bd6565b425b9450611be78b8b8b8a89888c613b3b565b5050505050505050505050565b5f611c2360087f0000000000000000000000000000000000000000000000000000046400002cdf63ffffffff16565b611c396102d18a8a60018b8b8b60018b8b612eb6565b611c4585858b8b613be9565b90508015611c5757611c578588613024565b98975050505050505050565b5f80611c75600389898989898961363c565b915091505b965096945050505050565b611419600c5f856001600160781b03166001600160781b031681526020019081526020015f205f858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061337d92505050565b6001600160a01b038116611d0c576040516303e9dcb360e31b815260040160405180910390fd5b61194a8282613c72565b611d1e613d02565b611d275f613d2b565b565b6001600160781b0381165f908152600c60205260409020606090611497906002016130bd565b611d588361342f565b6001600160a01b0383165f908152600f60205260408120905b8281101561167a575f848483818110611d8c57611d8c615c26565b9050602002016020810190611da191906150fc565b9050611dad8382613d7a565b15611e1757806001600160a01b0316866001600160a01b03167f1138edbff75f319641eb242dbcacee294ebc2a473eb6aa1454a7706da5bf96b060405160405180910390a36001600160a01b0381165f9081526002840160205260409020805460ff191660011790555b50600101611d71565b6001600160a01b0381165f908152600f60205260409020606090611497906130bd565b7f000000000000000000000000000000000000000000000000000000000000000180611e9057507fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff165b15611eae57604051630f45b98b60e41b815260040160405180910390fd5b611ed77f0000000000000000000000005c783489945249e2f8d2c1f494cc3aaf4039560a613d8e565b611ef4576040516370a4078f60e01b815260040160405180910390fd5b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b00805460ff19166001179055611d2780565b5f611f2f613dec565b905090565b6001600160a01b038281165f908152600b6020908152604080832054630100000090046001600160781b03168352600c82528083209385168352600490930190529081205460ff166116dd565b5f611f92613ee0338686865f613efd565b5090506001600160e01b0319811615611fae57611fae816144c6565b50505050565b5f611fe360017f0000000000000000000000000000000000000000000000000000046400002cdf63ffffffff16565b5f611ff5866102d186866001806130c9565b905061200386868686613be9565b915081156120195761201981875f6001816131a5565b50949350505050565b61202a613280565b6120335f613288565b801561194a575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114612082576040519150601f19603f3d011682016040523d82523d5f602084013e612087565b606091505b505090508061141957604051630fc77c5160e21b815260040160405180910390fd5b6001600160781b0381165f908152600d60205260409020606090611497906130bd565b6040516389a9c85560e01b81526001600160a01b0382811660048301525f917f000000000000000000000000e0a0004dfa318fc38298ae81a666710eadceba5c909116906389a9c85590602401602060405180830381865afa158015612134573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114979190615c3a565b6114a7815f613c72565b6001600160a01b038281165f908152600b6020908152604080832054630100000090046001600160781b03168352600d82528083209385168352600490930190529081205460ff166116dd565b6001600160a01b0381165f908152600b602052604090205460609061149790630100000090046001600160781b0316611acc565b6001600160a01b0381165f908152600b602052604090205460609061149790630100000090046001600160781b0316611598565b6001600160781b0383165f908152600d60205260409020611419906001858585612dee565b6001600160781b0383165f908152600c60205260408120611419918585856136ab565b336001600160a01b038716148061227e5750336001600160a01b038616145b61229b5760405163eda7110360e01b815260040160405180910390fd5b6122a484613919565b5f6122b5600388878787878c6144ce565b805490915060ff166123105760028155604051600181526001600160a01b03878116919089169084907f705db7ac401a8091bb37a7838ad73d1fa8e1c663cb345f347fefe71280e3f03b9060200160405180910390a4612329565b60405163465fc3a960e11b815260040160405180910390fd5b50505050505050565b5f8361233d81613079565b61236b60087f0000000000000000000000000000000000000000000000000000046400002cdf63ffffffff16565b6123808c8c60018d8d8d60018b8b8f8f614578565b61238c88888e8e613be9565b9150811561239e5761239e888b613024565b509a9950505050505050505050565b6001600160a01b0382165f908152600b6020908152604080832054630100000090046001600160781b03168352600d825280832084845260050190915281205460ff166116dd565b61194a82825b61194a5f8383826132cd565b600880546001600160781b038082166001019081166effffffffffffffffffffffffffffff1990921682179092555f818152600a60205260409081902080546001600160a01b03191633179055517f5cc365f89543268cb9f25c255f7f610e9147e733c589bc2732279575f125be14906124849086908690615c55565b60405180910390a260405133906001600160781b038316907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e27367905f90a392915050565b6124d086613919565b6124df86868685853389613b3b565b505050505050565b6124f08261342f565b6008546001600160781b03908116908216111561252057604051637b8b439360e11b815260040160405180910390fd5b6001600160a01b0382165f818152600b6020526040808220805471ffffffffffffffffffffffffffffff000000191663010000006001600160781b0387169081029190911790915590519092917fa66ff5557b7dc1562bb5e83306e15b513a25aa7537369bce38fc29c20847a79191a35050565b6114a73382613952565b5f6125af61458e3387878787613efd565b5090506001600160e01b031981161561167a5761167a816144c6565b5f80826125d7816134a3565b61260560807f0000000000000000000000000000000000000000000000000000046400002cdf63ffffffff16565b5f6126188e8e8e8e5f8f8e8e8e8e6145f3565b905061262c818d8d5f8e8e8c6137696134f6565b9094509250821561264557612645818b888760016131a5565b50509a509a98505050505050505050565b5f61268560207f0000000000000000000000000000000000000000000000000000046400002cdf63ffffffff16565b61269860148b5f8b8d8c8c8b8b8b612eb6565b6126a58a87875f88613769565b905080156126b7576126b7868a613024565b9998505050505050505050565b600160045f6040518060e0016040528060a58152602001615dd660a5913985856040516020016126f693929190615ca5565b6040516020818303038152906040528051906020012081526020019081526020015f205f6101000a81548160ff021916908315150217905550600160055f6040518060c00160405280609d8152602001615d39609d9139858560405160200161276193929190615ca5565b60408051808303601f190181529181528151602092830120835290820192909252015f20805460ff19169115159190911790555050565b6114198383835f6132cd565b5f6127d360047f0000000000000000000000000000000000000000000000000000046400002cdf63ffffffff16565b5f6127e3866014865f875f6130c9565b90506127f28487875f87613769565b915081156120195761201981875f86816131a5565b6001600160781b0381165f908152600e60205260409020606090611497906130bd565b6001600160781b0383165f908152600e60205260409020611419906002858585612dee565b600880546effffffffffffffffffffffffffffff19811660016001600160781b03928316908101808416929092179093559190831611156128a357604051637b8b439360e11b815260040160405180910390fd5b6001600160781b0381165f818152600a60205260409081902080546001600160a01b03191633179055517f5cc365f89543268cb9f25c255f7f610e9147e733c589bc2732279575f125be14906128fc9087908790615c55565b60405180910390a260405133906001600160781b038316907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e27367905f90a36001600160781b038083165f908152600c60208181526040808420600d808452828620600e808652848820988a16885295855283872091855283872095909452918520909592949293919261299090888886614608565b61299c5f8888866146bb565b6129a96001888785614608565b6129b660018887856146bb565b6129c36002888684614608565b6129d060028886846146bb565b5050505050509392505050565b6001600160781b0383165f908152600c6020526040812061141991858585613873565b611419600e5f856001600160781b03166001600160781b031681526020019081526020015f206002858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061337d92505050565b612a6a8361342f565b6001600160a01b0383165f908152600f60205260408120905b8281101561167a575f848483818110612a9e57612a9e615c26565b9050602002016020810190612ab391906150fc565b9050612abf8382614755565b15612b2657806001600160a01b0316866001600160a01b03167f208795fcac393398e42038456348398d8cac9067232f671ab240444cb51b1d2060405160405180910390a36001600160a01b0381165f9081526002840160205260409020805460ff191690555b50600101612a83565b6001600160a01b0381165f908152600b602052604090205460609061149790630100000090046001600160781b03166120a9565b612b6b613d02565b6001600160a01b038116612b9257604051633e58254b60e01b815260040160405180910390fd5b6114a781613d2b565b612ba48261342f565b6001600160a01b0382165f818152600b602090815260409182902080547fffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffff16600160981b61ffff87169081029190911790915591519182527fa5c37ab91519073edd58e608f19f7ce383fd171f4f22c3612a1d0a7c1047794a910160405180910390a25050565b80825d5050565b5c90565b5f815d50565b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff1615612c6d5780825d5050565b9055565b5f7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff1615612ca157505c90565b5080545b919050565b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff1615612cda575f815d50565b5f9055565b7f000000000000000000000000000000000000000000000000002386f26fc0ffff34470311156114a7576001548116156114a757604051636623b92d60e11b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000002386f26fc0ffff34470311612d6e5760405163fd2c901360e01b815260040160405180910390fd5b80600154165f036114a75760405163fd2c901360e01b815260040160405180910390fd5b5f7f000000000000000000000000000000000000000000000000002386f26fc0ffff3447031115612dc257506001545b90565b6001548116156114a757604051636623b92d60e11b815260040160405180910390fd5b60015490565b82612df881614769565b5f805b83811015612eac57848482818110612e1557612e15615c26565b9050602002016020810190612e2a91906150fc565b9150612e368883613d7a565b15612ea457816001600160a01b0316866001600160781b03168860ff167fda8f3bd170446760f0f965a9b52bf271cb9679b5e0a70059eff2d49425229d1760405160405180910390a46001600160a01b0382165f9081526004890160205260409020805460ff191660011790555b600101612dfb565b5050505050505050565b5f612f75611bb38c8c8c8c8c8c60075f8e6001600160a01b03166001600160a01b031681526020019081526020015f2054604080517f932b8553b8e35bbee682d275cbe1cf115e14a777e2ca3266b4797369fb6317d3602080830191909152818301999099526001600160a01b03979097166060880152608087019590955260a086019390935260c08501919091523360e085015261010084015261012080840191909152815180840390910181526101409092019052805191012090565b9050611be78787868b898689896147a9565b5f612f986104838787878787614801565b90508061301b57604051637921219560e11b81526001600160a01b0386811660048301528581166024830152604482018590526064820184905260a060848301525f60a483015287169063f242432a9060c4015f604051808303815f87803b158015613002575f80fd5b505af1925050508015613013575060015b61301b575060015b95945050505050565b6001600160a01b0382165f908152600660209081526040808320600885901c845290915290208054600160ff84161b90811891829055161561194a5760405163e4adc0bf60e01b815260040160405180910390fd5b5f8181526004602052604090205460ff166114a757604051632391283760e11b815260040160405180910390fd5b611be76104838c8c8c8c8c8c8c8c8c8c8c61486b565b60605f6116dd8361489e565b5f6130da60028888888886336144ce565b805490915042600160d01b90910465ffffffffffff16101561310f57604051630104f5db60e71b815260040160405180910390fd5b805461010090046001600160c81b031683111561313f5760405163fee142c560e01b815260040160405180910390fd5b8115613159578054610100600160d01b031916815561319b565b80546001600160c81b036101009091048116101561319b5780546001600160c81b03610100808304821686900390911602610100600160d01b03199091161781555b9695505050505050565b811561167a57801561323957845460ff196001600160c81b036101008084048216860190911602167fffffffffffff00000000000000000000000000000000000000000000000000009091161785556040518281526001600160a01b0385169084907f83e0ca2c1392f14286fa1e41c797789d48c5827572e8bcc352d8943c1961eaf09060200160405180910390a361167a565b84546001600160c81b036101009091048116101561167a5784546001600160c81b036101008083048216850190911602610100600160d01b03199091161785555050505050565b611d27613d02565b600180549082905560408051828152602081018490527fe0d8d9ad73c586e8cf60ffd390b6f3654200a2d8857eb6abba4f6842a1210aae910160405180910390a15050565b8284336132db8383836148f7565b5f86815260096020526040902061333190886001600160a01b031686613301575f613307565b600160ff1b5b177f0000000000000000000000000000000000000000000000000000039200002c2b63ffffffff16565b61232961334a87875f9182526020526040902060041c90565b886001600160a01b03167f0000000000000000000000000000000000000000000000000000039200002c2b63ffffffff16565b8161338781614769565b5f805b8351811015612329578381815181106133a5576133a5615c26565b602090810291909101015191506133bc8783614755565b1561342757816001600160a01b0316856001600160781b03168760ff167f503012490a650739416858609e898957b874d17415a062945179c5735797884060405160405180910390a46001600160a01b0382165f9081526004880160205260409020805460ff191690555b60010161338a565b336001600160a01b0382168103613444575050565b5f61344e836149c1565b509050806001600160a01b0316826001600160a01b03160361346f57505050565b5f61347b848285614a09565b509050801561348a5750505050565b604051637f954ba160e01b815260040160405180910390fd5b5f8181526005602052604090205460ff166114a757604051632391283760e11b815260040160405180910390fd5b5f6134e78b8b8b6104838c8c8c8c8c8c8c614a75565b9b9a5050505050505050505050565b87546020880135905f9061010090046001600160c81b031682111561352857895461010090046001600160c81b031691505b886040013582101561354d5760405163b9ff981560e01b815260040160405180910390fd5b89546001600160c81b03610100808304821685900390911602610100600160d01b0319909116178a5560405182815233906001600160a01b0388169086907f2203cb053e6b01ec07e87d67d288d360ae164171185684936663b7d8fa9c534c9060200160405180910390a4895461010090046001600160c81b03165f0361361c57895460ff19166001178a556040515f815233906001600160a01b0388169086907f705db7ac401a8091bb37a7838ad73d1fa8e1c663cb345f347fefe71280e3f03b9060200160405180910390a45b61362d8887878a868863ffffffff16565b90509850989650505050505050565b5f805f61364e8a8a898989898e6144ce565b805490915042600160d01b90910465ffffffffffff161061367e57805461010090046001600160c81b0316613680565b5f5b90546001600160c81b039091169a600160d01b90910465ffffffffffff169950975050505050505050565b826136b581614769565b5f805b83811015612eac578484828181106136d2576136d2615c26565b9050602002013591506136f18289600201614bb490919063ffffffff16565b1561374c5781866001600160781b03168860ff167fc8615322788d404dfe307db9eef031bc148d1cec5e270a1fd6528a02b445d44560405160405180910390a45f8281526005890160205260409020805460ff191660011790555b6001016136b8565b611be760148c8c8c8c8c8c8c8c8c8c8c61486b565b5f61377960148787875f87614801565b90508061301b57604080516001600160a01b0387811660248301528681166044830152606480830186905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166323b872dd60e01b17905291515f928392908a16916137f89190615ccb565b5f604051808303815f865af19150503d805f8114613831576040519150601f19603f3d011682016040523d82523d5f602084013e613836565b606091505b5091509150816138495760019250613868565b80511561386857808060200190518101906138649190615c3a565b1592505b505095945050505050565b8261387d81614769565b5f805b83811015612eac5784848281811061389a5761389a615c26565b9050602002013591506138b98289600201614bbf90919063ffffffff16565b156139115781866001600160781b03168860ff167f061d78094976b1d9ae7bb858f141c915b46152756409caadb07482983c2ca30160405160405180910390a45f8281526005890160205260409020805460ff191690555b600101613880565b6102d181148061392a575061048381145b806139355750601481145b6114a757604051639d36a97960e01b815260040160405180910390fd5b6001600160a01b0382165f908152600660209081526040808320600885901c845290915290208054600160ff84161b908118918290551661194a5760405163d979627360e01b815260040160405180910390fd5b604080517ff9c04f8b028fcfa3315ea5accaee4589194a685f07cda0392e6ba9550706111960208201529081018a90526001600160a01b03808a1660608301526080820189905260a0820188905260c08201879052851660e08201526101008101849052610120810183905261014081018290525f90610160015b6040516020818303038152906040528051906020012090509998505050505050505050565b5f611497613a52613dec565b8360405161190160f01b8152600281019290925260228201526042902090565b6041829003613ad6578235602084013560408501355f90811a9080613a9989848787614bca565b91509150806001600160a01b0316866001600160a01b0316141580613abb5750815b15613acc57613acc868a8a8a614c73565b5050505050611fae565b6040829003613b2f57823560208401355f80613af3888585614cc6565b91509150806001600160a01b0316856001600160a01b0316141580613b155750815b15613b2657613b2685898989614c73565b50505050611fae565b611fae81858585614c73565b5f613b4c6002848a8a8a86886144ce565b805460ff16600160d01b65ffffffffffff8716908102610100600160d01b031916919091176101006001600160c81b038916908102919091178355604080518a815260208101929092528101919091529091506001600160a01b0383811691898216918616907f0ec867d4f1b037422566cd0248bae620e6c142dcf5631948271916e8ca8dd2639060600160405180910390a45050505050505050565b5f613bfb6102d1848787866001614801565b905080613c6a576040516323b872dd60e01b81526001600160a01b0386811660048301528581166024830152604482018490528416906323b872dd906064015f604051808303815f87803b158015613c51575f80fd5b505af1925050508015613c62575060015b613c6a575060015b949350505050565b6001600160781b038216613c995760405163519973e760e01b815260040160405180910390fd5b613ca282614769565b6001600160781b0382165f818152600a602052604080822080546001600160a01b0319166001600160a01b03861690811790915590519092917f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e2736791a35050565b5f546001600160a01b03163314611d27576040516208650f60e61b815260040160405180910390fd5b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f6116dd836001600160a01b038416614d0d565b5f816001600160a01b0316600a5a613da69190615ce6565b6040515f8181818686fa925050503d805f8114613dde576040519150601f19603f3d011682016040523d82523d5f602084013e613de3565b606091505b50909392505050565b5f7f00000000000000000000000000000000000000000000000000000000000081734603613e3957507fc7e2da31f9bc617958d3365fd9cae13a712ab9e3380c8cbdd963c2f68350a2f590565b611f2f604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f12900c1b40e87470816fa5cb16069bf5b3df9cf052332bf21440c4318ccddcfe918101919091527f13600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c06060608201524660808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b5f838152600960205260408120612019908490614d59565b614d59565b5f80306001600160a01b03871603613f1957505f905080611c7a565b6001600160a01b0387165f908152600b602052604090208054630100000081046001600160781b0316907f00000000000000000000000000000000000000000000040303020203020100026107f862010000830460031b1690811c60ff908116927f000000000000000000000000000000000000000000000302010201000000000090921c811691600160901b90041615614034576001600160a01b03808c165f908152600f60209081526040808320938d1683526002840190915290205460ff1615613ff8575063056c6b9160e31b95505f9450611c7a9350505050565b6001600160a01b0389165f90815260028201602052604090205460ff16156140325750632a5cb1c360e01b95505f9450611c7a9350505050565b505b60048203614053575063d73e63af60e01b94505f9350611c7a92505050565b6001600160781b0383165f908152600d602052604090205f1982016140e757883b156140e2576001600160a01b0389165f90815260048201602052604090205460ff166140e2578c6140aa8d8d8b63ffffffff8516565b6140e057893f5f90815260058301602052604090205460ff166140e057506305652c5560e51b96505f9550611c7a945050505050565b505b614165565b60028203614165576140f8896120cc565b614165576001600160a01b0389165f90815260048201602052604090205460ff16614165578c61412d8d8d8b63ffffffff8516565b61416357893f5f90815260058301602052604090205460ff166141635750636719795560e11b96505f9550611c7a945050505050565b505b896001600160a01b03168b6001600160a01b0316036141a257600383146141a257505091545f9450600160981b900461ffff169250611c7a915050565b6001830361428e578c6141ba8d8d8b63ffffffff8516565b156141dc57505092545f9550600160981b900461ffff169350611c7a92505050565b5f600c5f876001600160781b03166001600160781b031681526020019081526020015f209050806004015f8e6001600160a01b03166001600160a01b031681526020019081526020015f205f9054906101000a900460ff1615614253575063204f370f60e11b97505f9650611c7a95505050505050565b8c3f5f90815260058201602052604090205460ff1615614287575063204f370f60e11b97505f9650611c7a95505050505050565b50506144a6565b60028303614356576001600160a01b038b165f90815260048201602052604090205460ff16156142d457505091545f9450600160981b900461ffff169250611c7a915050565b8c6142e48d8d8b63ffffffff8516565b1561430657505092545f9550600160981b900461ffff169350611c7a92505050565b8b3f5f90815260058301602052604090205460ff161561433d57505092545f9550600160981b900461ffff169350611c7a92505050565b5063ef28f90160e01b96505f9550611c7a945050505050565b600383036144a6576001600160a01b038b165f90815260048201602081905260409091205460ff16156143a057505092545f9550600160981b900461ffff169350611c7a92505050565b6001600160a01b038b165f9081526020829052604090205460ff16156143dd57505092545f9550600160981b900461ffff169350611c7a92505050565b8d6143ed8e8e8c63ffffffff8516565b1561441057505093545f9650600160981b900461ffff169450611c7a9350505050565b8c3f5f9081526005840160208190526040909120548e9060ff161561444f57505095545f9850600160981b900461ffff169650611c7a95505050505050565b508c3f5f908152602082905260409020548d9060ff161561448a57505095545f9850600160981b900461ffff169650611c7a95505050505050565b5063ef28f90160e01b99505f9850611c7a975050505050505050565b505091545f9b600160981b90910461ffff169a5098505050505050505050565b805f5260045ffd5b5f875f61453d89898989896001600160a01b039485165f818152600760209081526040918290205482518083019490945283830197909752949096166060820152608081019290925260a082015260c0808201939093528351808203909301835260e001909252805191012090565b81526020019081526020015f205f836001600160a01b03166001600160a01b031681526020019081526020015f209050979650505050505050565b611be76102d18c8c8c8c8c8c8c8c8c8c8c61486b565b5f806145aa84613ef887865f9182526020526040902060041c90565b50915081156145bd5760019150506116dd565b6145d584613ef8875f90815260096020526040902090565b909250905081801561301b575060ff81901c60011495945050505050565b5f6134e78b8b8b60148c8c8c8c8c8c8c614a75565b8181600481015f61461884614dbe565b90505f805b828110156146af5761462f8682614dc7565b915061463b8583613d7a565b156146a757816001600160a01b0316896001600160781b03168b60ff167fda8f3bd170446760f0f965a9b52bf271cb9679b5e0a70059eff2d49425229d1760405160405180910390a46001600160a01b0382165f908152602085905260409020805460ff191660011790555b60010161461d565b50505050505050505050565b6002808301908201600583015f6146d184614dbe565b90505f805b828110156146af576146e88682614dc7565b91506146f48583614bb4565b1561474d5781896001600160781b03168b60ff167fc8615322788d404dfe307db9eef031bc148d1cec5e270a1fd6528a02b445d44560405160405180910390a45f828152602085905260409020805460ff191660011790555b6001016146d6565b5f6116dd836001600160a01b038416614dd2565b6001600160781b0381165f908152600a60205260409020546001600160a01b031633146114a7576040516304e680cb60e41b815260040160405180910390fd5b864211156147ca5760405163e3fd7ac360e01b815260040160405180910390fd5b848611156147eb5760405163de7fafeb60e01b815260040160405180910390fd5b6147f58489613952565b612eac83838387613a72565b5f805f61481461458e89338a8a8a613efd565b909250905061ffff8116158061482d5750888161ffff16145b15614846576001600160e01b031982161515925061485f565b604051633d29aed360e11b815260040160405180910390fd5b50509695505050505050565b5f61487d8d8d8d8d8b8e8e8a8a614eb5565b905061488f8989888d8b868b8b6147a9565b50505050505050505050505050565b6060815f018054806020026020016040519081016040528092919081815260200182805480156148eb57602002820191905f5260205f20905b8154815260200190600101908083116148d7575b50505050509050919050565b6001600160a01b0383165f908152600b60205260409020805460ff16156149315760405163b1ae736760e01b815260040160405180910390fd5b8054610100900460ff161561496a575f196001600160a01b0384160161496a5760405163bf729bb160e01b815260040160405180910390fd5b8054630100000090046001600160781b03165f908152600e602090815260408083206001600160a01b038616845260040190915290205460ff16611fae57604051635e47503160e11b815260040160405180910390fd5b5f806149f7565b638da5cb5b5f525f8060205f6004601c865afa60203d101516156149ef575f519150915091565b509160019150565b614a00836149c8565b91509150915091565b5f80614a5e565b5f80604051606081016040526391d14854815284816020015285816040015260205f6044601c8401875afa60203d10151615614a50575f51925050614a56565b50600190505b935093915050565b614a69838587614a10565b91509150935093915050565b5f6001600160c81b038a351115614a9f57604051633b0a334360e01b815260040160405180910390fd5b614aaf6003878b8b8b88336144ce565b805490915060ff1661231057805461010090046001600160c81b03165f03614b8357614af6614aee8a8a8a8e358b8b65ffffffffffff8c168b8b614eb5565b8d8d89613a72565b805460ff166101008b356001600160c81b0381169190910279ffffffffffffffffffffffffffffffffffffffffffffffffffff1691909117600160d01b65ffffffffffff87160217825560405190815233906001600160a01b0388169085907f257001e1f7fbfc5bbde5da225c876ab67293f37bda3afb8b35d9a55dfad6f65d9060200160405180910390a45b8054600160d01b900465ffffffffffff164211156134e75760405163e3fd7ac360e01b815260040160405180910390fd5b5f6116dd8383614d0d565b5f6116dd8383614dd2565b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614bff5750600190505f614c6a565b604080515f81526020810180835288905260ff871691810191909152606081018590526080810184905260019060a0016020604051602081039080840390855afa158015614c4f573d5f803e3d5ffd5b5050604051601f1901516001600160a01b0381161593509150505b94509492505050565b836001600160a01b03163b5f03614c9d576040516373c919b560e01b815260040160405180910390fd5b614ca984848484614ee1565b611fae576040516373c919b560e01b815260040160405180910390fd5b5f807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316601b60ff85901c01614cff87828885614bca565b909890975095505050505050565b5f818152600183016020526040812054614d5257508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155611497565b505f611497565b5f80614d88837f0000000000000000000000000000000000000000000000000000039900002c3263ffffffff16565b9050806001600160a01b03811660011480614db45750846001600160a01b0316816001600160a01b0316145b9250509250929050565b5f611497825490565b5f6116dd8383614f5d565b5f8181526001830160205260408120548015614eac575f614df4600183615d05565b85549091505f90614e0790600190615d05565b9050808214614e66575f865f018281548110614e2557614e25615c26565b905f5260205f200154905080875f018481548110614e4557614e45615c26565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080614e7757614e77615d24565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050611497565b5f915050611497565b6001600160a01b0385165f908152600760205260408120546134e7611bb38c8c8c8c8b8b8b8b8a614f83565b5f614f51565b5f604051630b135d3f60e11b81528360048201526040602482015285604482015285856064830137601f19601f87011660640180820160405260205f8284875afa60203d10151615614f4757630b135d3f60e11b5f511492505050613c6a565b5050949350505050565b61301b82848688614ee7565b5f825f018281548110614f7257614f72615c26565b905f5260205f200154905092915050565b60408051602081018490529081018a90526001600160a01b03891660608201526080810188905260a0810187905260c081018690523360e08201526101008101859052610120810182905261014081018490525f9061016001613a21565b80356001600160781b0381168114612ca5575f80fd5b5f8083601f840112615007575f80fd5b50813567ffffffffffffffff81111561501e575f80fd5b6020830191508360208260051b8501011115615038575f80fd5b9250929050565b5f805f60408486031215615051575f80fd5b61505a84614fe1565b9250602084013567ffffffffffffffff811115615075575f80fd5b61508186828701614ff7565b9497909650939450505050565b5f6020828403121561509e575f80fd5b81356001600160e01b0319811681146116dd575f80fd5b80356001600160a01b0381168114612ca5575f80fd5b5f80604083850312156150dc575f80fd5b6150e583614fe1565b91506150f3602084016150b5565b90509250929050565b5f6020828403121561510c575f80fd5b6116dd826150b5565b5f8083601f840112615125575f80fd5b50813567ffffffffffffffff81111561513c575f80fd5b602083019150836020828501011115615038575f80fd5b5f805f805f805f805f806101208b8d03121561516d575f80fd5b6151768b6150b5565b995060208b0135985060408b0135975060608b0135965060808b013595506151a060a08c016150b5565b94506151ae60c08c016150b5565b935060e08b013592506101008b013567ffffffffffffffff8111156151d1575f80fd5b6151dd8d828e01615115565b915080935050809150509295989b9194979a5092959850565b5f805f805f805f805f805f806101608d8f031215615212575f80fd5b61521b8d6150b5565b9b5060208d01359a5060408d0135995060608d0135985060808d0135975061524560a08e016150b5565b965061525360c08e016150b5565b955060e08d013594506101008d013593506101208d0135925067ffffffffffffffff6101408e01351115615285575f80fd5b6152968e6101408f01358f01615115565b81935080925050509295989b509295989b509295989b565b5f602082840312156152be575f80fd5b6116dd82614fe1565b602080825282518282018190525f9190848201906040850190845b818110156153075783516001600160a01b0316835292840192918401916001016152e2565b50909695505050505050565b5f805f805f60a08688031215615327575f80fd5b615330866150b5565b945061533e602087016150b5565b935061534c604087016150b5565b94979396509394606081013594506080013592915050565b5f60208284031215615374575f80fd5b5035919050565b602080825282518282018190525f9190848201906040850190845b8181101561530757835183529284019291840191600101615396565b5f80604083850312156153c3575f80fd5b6153cc836150b5565b946020939093013593505050565b5f805f606084860312156153ec575f80fd5b6153f5846150b5565b9250615403602085016150b5565b9150615411604085016150b5565b90509250925092565b5f805f6060848603121561542c575f80fd5b615435846150b5565b95602085013595506040909401359392505050565b80151581146114a7575f80fd5b5f805f805f60a0868803121561546b575f80fd5b615474866150b5565b9450602086013560ff81168114615489575f80fd5b935060408601356154998161544a565b925060608601356154a98161544a565b915060808601356154b98161544a565b809150509295509295909350565b5f606082840312156154d7575f80fd5b50919050565b803565ffffffffffff81168114612ca5575f80fd5b5f805f805f805f805f805f6101808c8e03121561550d575f80fd5b8b3567ffffffffffffffff811115615523575f80fd5b61552f8e828f01615115565b909c509a5061554390508d60208e016154c7565b985061555160808d016150b5565b975060a08c0135965061556660c08d016150b5565b955061557460e08d016150b5565b94506101008c0135935061558b6101208d016154dd565b92506101408c013591506101608c013590509295989b509295989b9093969950565b5f80604083850312156155be575f80fd5b6150e5836150b5565b5f805f805f60a086880312156155db575f80fd5b6155e4866150b5565b94506155f2602087016150b5565b935060408601359250615607606087016150b5565b949793965091946080013592915050565b5f805f805f805f805f805f6101408c8e031215615633575f80fd5b61563c8c6150b5565b9a5060208c0135995060408c0135985060608c0135975061565f60808d016150b5565b965061566d60a08d016150b5565b955060c08c0135945060e08c013593506101008c013592506101208c013567ffffffffffffffff81111561569f575f80fd5b6156ab8e828f01615115565b915080935050809150509295989b509295989b9093969950565b80356001600160c81b0381168114612ca5575f80fd5b5f805f805f805f805f805f6101408c8e0312156156f6575f80fd5b8b359a5061570660208d016150b5565b995060408c0135985060608c0135975061572260808d016156c5565b965061573060a08d016150b5565b955061573e60c08d016154dd565b945061574c60e08d016154dd565b935061575b6101008d016150b5565b92506101208c013567ffffffffffffffff81111561569f575f80fd5b5f8060408385031215615788575f80fd5b6153cc83614fe1565b5f805f805f805f8060e0898b0312156157a8575f80fd5b6157b1896150b5565b97506020890135965060408901359550606089013594506157d460808a016150b5565b93506157e260a08a016150b5565b925060c089013567ffffffffffffffff8111156157fd575f80fd5b6158098b828c01615115565b999c989b5096995094979396929594505050565b5f805f805f8060c08789031215615832575f80fd5b61583b876150b5565b9550615849602088016150b5565b94506040870135935061585e606088016150b5565b92506080870135915060a087013590509295509295509295565b5f805f6040848603121561588a575f80fd5b61505a846150b5565b5f805f80608085870312156158a6575f80fd5b6158af856150b5565b93506158bd602086016150b5565b92506158cb604086016150b5565b9396929550929360600135925050565b5f805f805f805f805f806101208b8d0312156158f5575f80fd5b6158fe8b6150b5565b995060208b0135985060408b0135975060608b0135965061592160808c016150b5565b955061592f60a08c016150b5565b945060c08b0135935060e08b013592506101008b013567ffffffffffffffff8111156151d1575f80fd5b5f806020838503121561596a575f80fd5b823567ffffffffffffffff811115615980575f80fd5b61598c85828601615115565b90969095509350505050565b5f805f805f8060c087890312156159ad575f80fd5b863595506159bd602088016150b5565b9450604087013593506159d2606088016150b5565b92506159e0608088016156c5565b91506159ee60a088016154dd565b90509295509295509295565b5f8060408385031215615a0b575f80fd5b615a14836150b5565b91506150f360208401614fe1565b5f805f805f805f805f806101608b8d031215615a3c575f80fd5b8a3567ffffffffffffffff811115615a52575f80fd5b615a5e8d828e01615115565b909b509950615a7290508c60208d016154c7565b9750615a8060808c016150b5565b9650615a8e60a08c016150b5565b9550615a9c60c08c016150b5565b945060e08b01359350615ab26101008c016154dd565b92506101208b013591506101408b013590509295989b9194979a5092959850565b5f805f805f805f805f6101008a8c031215615aec575f80fd5b615af58a6150b5565b985060208a0135975060408a0135965060608a01359550615b1860808b016150b5565b9450615b2660a08b016150b5565b935060c08a0135925060e08a013567ffffffffffffffff811115615b48575f80fd5b615b548c828d01615115565b915080935050809150509295985092959850929598565b5f805f60608486031215615b7d575f80fd5b615b86846150b5565b9250615b94602085016150b5565b9150604084013590509250925092565b5f805f60408486031215615bb6575f80fd5b833567ffffffffffffffff811115615bcc575f80fd5b615bd886828701615115565b9094509250615411905060208501614fe1565b5f8060408385031215615bfc575f80fd5b615c05836150b5565b9150602083013561ffff81168114615c1b575f80fd5b809150509250929050565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215615c4a575f80fd5b81516116dd8161544a565b60208152816020820152818360408301375f818301604090810191909152601f909201601f19160101919050565b5f5b83811015615c9d578181015183820152602001615c85565b50505f910152565b5f8451615cb6818460208901615c83565b8201838582375f930192835250909392505050565b5f8251615cdc818460208701615c83565b9190910192915050565b5f82615d0057634e487b7160e01b5f52601260045260245ffd5b500490565b8181038181111561149757634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603160045260245ffdfe5065726d69744f72646572576974684164646974696f6e616c446174612875696e7432353620746f6b656e547970652c6164647265737320746f6b656e2c75696e743235362069642c75696e7432353620616d6f756e742c75696e743235362073616c742c61646472657373206f70657261746f722c75696e743235362065787069726174696f6e2c75696e74323536206d61737465724e6f6e63652c5065726d69745472616e7366657246726f6d576974684164646974696f6e616c446174612875696e7432353620746f6b656e547970652c6164647265737320746f6b656e2c75696e743235362069642c75696e7432353620616d6f756e742c75696e74323536206e6f6e63652c61646472657373206f70657261746f722c75696e743235362065787069726174696f6e2c75696e74323536206d61737465724e6f6e63652ca2646970667358221220a90ba9bdaeca58f1ff72597bd40a48511cb4d6531d0ea891d978e9112f6daab564736f6c63430008180033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000591aa9dff01b8144dc17cb416001d9ac84b951cd000000000000000000000000e0a0004dfa318fc38298ae81a666710eadceba5c000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000001d43726561746f72546f6b656e5472616e7366657256616c696461746f7200000000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : defaultOwner (address): 0x591Aa9dfF01B8144DC17Cb416001D9aC84b951cd
Arg [1] : eoaRegistry_ (address): 0xE0A0004Dfa318fc38298aE81a666710eaDCEba5C
Arg [2] : name (string): CreatorTokenTransferValidator
Arg [3] : version (string): 4
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 000000000000000000000000591aa9dff01b8144dc17cb416001d9ac84b951cd
Arg [1] : 000000000000000000000000e0a0004dfa318fc38298ae81a666710eadceba5c
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [3] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [4] : 000000000000000000000000000000000000000000000000000000000000001d
Arg [5] : 43726561746f72546f6b656e5472616e7366657256616c696461746f72000000
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [7] : 3400000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode Sourcemap
5860:96010:30:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;51266:191;;;;;;;;;;-1:-1:-1;51266:191:30;;;;;:::i;:::-;;:::i;:::-;;67887:434;;;;;;;;;;-1:-1:-1;67887:434:30;;;;;:::i;:::-;;:::i;:::-;;;1549:14:32;;1542:22;1524:41;;1512:2;1497:18;67887:434:30;;;;;;;;60458:155;;;;;;;;;;-1:-1:-1;60458:155:30;;;;;:::i;:::-;-1:-1:-1;;;;;60561:14:30;;60538:4;60561:14;;;:10;:14;;;;;;;;-1:-1:-1;;;;;60561:45:30;;;;:36;;:45;;;;;;;;60458:155;;;;;35234:107;;;;;;;;;;-1:-1:-1;35234:107:30;;;;;:::i;:::-;;:::i;21865:670:17:-;;;;;;;;;;-1:-1:-1;21865:670:17;;;;;:::i;:::-;;:::i;24672:1085::-;;;;;;;;;;-1:-1:-1;24672:1085:17;;;;;:::i;:::-;;:::i;58310:149:30:-;;;;;;;;;;-1:-1:-1;58310:149:30;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;45782:558:17:-;;;;;;;;;;-1:-1:-1;45782:558:17;;;;;:::i;:::-;;:::i;8427:134:13:-;;;;;;:::i;:::-;;:::i;60009:155:30:-;;;;;;;;;;-1:-1:-1;60009:155:30;;;;;:::i;:::-;-1:-1:-1;;;;;60112:14:30;;60089:4;60112:14;;;:10;:14;;;;;;;;-1:-1:-1;;;;;60112:45:30;;;;:36;;:45;;;;;;;;60009:155;;;;;63672:202;;;;;;;;;;-1:-1:-1;63672:202:30;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;27588:174::-;;;;;;;;;;-1:-1:-1;27588:174:30;;;;;:::i;:::-;;:::i;42005:203:17:-;;;;;;;;;;-1:-1:-1;42005:203:17;;;;;:::i;:::-;-1:-1:-1;;;;;42125:23:17;;;42089:12;42125:23;;;:16;:23;;;;;;;;42166:1;42157:10;;;42125:44;;;;;;;;:60;;;;;257:1:14;42124:68:17;42123:78;;42005:203;14465:25:30;;;;;;;;;;-1:-1:-1;14465:25:30;;;;-1:-1:-1;;;;;14465:25:30;;;;;;-1:-1:-1;;;;;7292:45:32;;;7274:64;;7262:2;7247:18;14465:25:30;7128:216:32;30231:146:30;;;;;;;;;;-1:-1:-1;30231:146:30;;;;;:::i;:::-;;:::i;37363:202::-;;;;;;;;;;-1:-1:-1;37363:202:30;;;;;:::i;:::-;;:::i;66676:212::-;;;;;;;;;;-1:-1:-1;66676:212:30;;;;;:::i;:::-;;:::i;55719:201::-;;;;;;;;;;-1:-1:-1;55719:201:30;;;;;:::i;:::-;;:::i;44636:1080::-;;;;;;;;;;-1:-1:-1;44636:1080:30;;;;;:::i;:::-;;:::i;34140:1232:17:-;;;;;;;;;;-1:-1:-1;34140:1232:17;;;;;:::i;:::-;;:::i;:::-;;;;10796:25:32;;;10864:14;;10857:22;10852:2;10837:18;;10830:50;10769:18;34140:1232:17;10628:258:32;36266:172:30;;;;;;;;;;-1:-1:-1;36266:172:30;;;;;:::i;:::-;;:::i;65661:206::-;;;;;;;;;;-1:-1:-1;65661:206:30;;;;;:::i;:::-;;:::i;62920:196::-;;;;;;;;;;-1:-1:-1;62920:196:30;;;;;:::i;:::-;;:::i;42477:143:17:-;;;;;;;;;;;;;:::i;13192:320::-;;;;;;;;;;-1:-1:-1;13192:320:17;;;;;:::i;:::-;;:::i;:::-;;;;11807:25:32;;;11863:2;11848:18;;11841:34;;;;11780:18;13192:320:17;11633:248:32;54245:199:30;;;;;;;;;;-1:-1:-1;54245:199:30;;;;;:::i;:::-;;:::i;30017:962:17:-;;;;;;;;;;-1:-1:-1;30017:962:17;;;;;:::i;:::-;;:::i;59562:153:30:-;;;;;;;;;;-1:-1:-1;59562:153:30;;;;;:::i;:::-;;:::i;34293:149::-;;;;;;;;;;-1:-1:-1;34293:149:30;;;;;:::i;:::-;;:::i;57940:209::-;;;;;;;;;;-1:-1:-1;57940:209:30;;;;;:::i;:::-;;:::i;11182:1326:17:-;;;;;;;;;;-1:-1:-1;11182:1326:17;;;;;:::i;:::-;;:::i;61790:160:30:-;;;;;;;;;;-1:-1:-1;61790:160:30;;;;;:::i;:::-;-1:-1:-1;;;;;61895:14:30;;;;61872:4;61895:14;;;:10;:14;;;;;;;;:48;;;:38;;;;:48;;;;;;;61790:160;16967:568:17;;;;;;;;;;-1:-1:-1;16967:568:17;;;;;:::i;:::-;;:::i;40812:338::-;;;;;;;;;;-1:-1:-1;40812:338:17;;;;;:::i;:::-;;:::i;54981:201:30:-;;;;;;;;;;-1:-1:-1;54981:201:30;;;;;:::i;:::-;;:::i;42453:272::-;;;;;;;;;;-1:-1:-1;42453:272:30;;;;;:::i;:::-;;:::i;1938:101:21:-;;;;;;;;;;;;;:::i;59243:153:30:-;;;;;;;;;;-1:-1:-1;59243:153:30;;;;;:::i;:::-;;:::i;48073:664::-;;;;;;;;;;-1:-1:-1;48073:664:30;;;;;:::i;:::-;;:::i;63298:178::-;;;;;;;;;;-1:-1:-1;63298:178:30;;;;;:::i;:::-;;:::i;4954:532:25:-;;;;;;;;;;;;;:::i;51854:132:17:-;;;;;;;;;;;;;:::i;:::-;;;17048:25:32;;;17036:2;17021:18;51854:132:17;16902:177:32;64595:208:30;;;;;;;;;;-1:-1:-1;64595:208:30;;;;;:::i;:::-;;:::i;21866:325::-;;;;;;;;;;-1:-1:-1;21866:325:30;;;;;:::i;:::-;;:::i;44149:515:17:-;;;;;;;;;;-1:-1:-1;44149:515:17;;;;;:::i;:::-;;:::i;31240:167::-;;;;;;;;;;-1:-1:-1;31240:167:17;;;;;:::i;:::-;31325:17;31369:31;;;:25;:31;;;;;;;;;31240:167;9506:334:13;;;;;;;;;;-1:-1:-1;9506:334:13;;;;;:::i;:::-;;:::i;58620:149:30:-;;;;;;;;;;-1:-1:-1;58620:149:30;;;;;:::i;:::-;;:::i;67529:140::-;;;;;;;;;;-1:-1:-1;67529:140:30;;;;;:::i;:::-;;:::i;43171:109::-;;;;;;;;;;-1:-1:-1;43171:109:30;;;;;:::i;:::-;;:::i;1321:85:21:-;;;;;;;;;;-1:-1:-1;1367:7:21;1393:6;-1:-1:-1;;;;;1393:6:21;1321:85;;;-1:-1:-1;;;;;17841:55:32;;;17823:74;;17811:2;17796:18;1321:85:21;17677:226:32;65126:208:30;;;;;;;;;;-1:-1:-1;65126:208:30;;;;;:::i;:::-;;:::i;64070:202::-;;;;;;;;;;-1:-1:-1;64070:202:30;;;;;:::i;:::-;;:::i;62142:198::-;;;;;;;;;;-1:-1:-1;62142:198:30;;;;;:::i;:::-;;:::i;30779:309::-;;;;;;;;;;-1:-1:-1;30779:309:30;;;;;:::i;:::-;30929:69;30956:24;30994:1;30985:10;;;;30956:40;;;30929:69;;;31037:26;:42;;;31008:73;;30779:309;51987:191;;;;;;;;;;-1:-1:-1;51987:191:30;;;;;:::i;:::-;;:::i;53475:199::-;;;;;;;;;;-1:-1:-1;53475:199:30;;;;;:::i;:::-;;:::i;66181:185::-;;;;;;;;;;-1:-1:-1;66181:185:30;;;;;:::i;:::-;-1:-1:-1;;;;;66302:26:30;;;66279:4;66302:26;;;:14;:26;;;;;;;;:57;;;;;;:48;;;;:57;;;;;;;;66181:185;39400:843:17;;;;;;;;;;-1:-1:-1;39400:843:17;;;;;:::i;:::-;;:::i;14639:46:30:-;;;;;;;;;;-1:-1:-1;14639:46:30;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;14639:46:30;;;19514:883:17;;;;;;;;;;-1:-1:-1;19514:883:17;;;;;:::i;:::-;;:::i;67198:212:30:-;;;;;;;;;;-1:-1:-1;67198:212:30;;;;;:::i;:::-;;:::i;38344:140::-;;;;;;;;;;-1:-1:-1;38344:140:30;;;;;:::i;:::-;;:::i;60911:155::-;;;;;;;;;;-1:-1:-1;60911:155:30;;;;;:::i;:::-;-1:-1:-1;;;;;61013:15:30;;60990:4;61013:15;;;:11;:15;;;;;;;;-1:-1:-1;;;;;61013:46:30;;;;:37;;:46;;;;;;;;60911:155;;;;;33068:183;;;;;;;;;;-1:-1:-1;33068:183:30;;;;;:::i;:::-;;:::i;39274:267::-;;;;;;;;;;-1:-1:-1;39274:267:30;;;;;:::i;:::-;;:::i;50545:191::-;;;;;;;;;;-1:-1:-1;50545:191:30;;;;;:::i;:::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;50691:38:30;;;;;:26;:38;;;;;;;;;50684:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;50684:45:30;;;;;-1:-1:-1;;;50684:45:30;;;;;;;;;;;-1:-1:-1;;;50684:45:30;;;;;;;;;;50545:191;;;;;;;19487:4:32;19529:3;19518:9;19514:19;19506:27;;19580:6;19574:13;19567:21;19560:29;19549:9;19542:48;19660:4;19652:6;19648:17;19642:24;19635:32;19628:40;19621:4;19610:9;19606:20;19599:70;19737:4;19729;19721:6;19717:17;19711:24;19707:35;19700:4;19689:9;19685:20;19678:65;-1:-1:-1;;;;;19803:4:32;19795:6;19791:17;19785:24;19781:63;19774:4;19763:9;19759:20;19752:93;19915:4;19907:6;19903:17;19897:24;19890:32;19883:40;19876:4;19865:9;19861:20;19854:70;19992:6;19984:4;19976:6;19972:17;19966:24;19962:37;19955:4;19944:9;19940:20;19933:67;19305:701;;;;;9000:321:17;;;;;;;;;;-1:-1:-1;9000:321:17;;;;;:::i;:::-;;:::i;47101:367:30:-;;;;;;;;;;-1:-1:-1;47101:367:30;;;;;:::i;:::-;;:::i;41641:118:17:-;;;;;;;;;;-1:-1:-1;41641:118:17;;;;;:::i;:::-;;:::i;24718:343:30:-;;;;;;;;;;-1:-1:-1;24718:343:30;;;;;:::i;:::-;;:::i;37432:1208:17:-;;;;;;;;;;-1:-1:-1;37432:1208:17;;;;;:::i;:::-;;:::i;61348:160:30:-;;;;;;;;;;-1:-1:-1;61348:160:30;;;;;:::i;:::-;-1:-1:-1;;;;;61453:14:30;;;;61430:4;61453:14;;;:10;:14;;;;;;;;:48;;;:38;;;;:48;;;;;;;61348:160;27235:646:17;;;;;;;;;;-1:-1:-1;27235:646:17;;;;;:::i;:::-;;:::i;14814:704::-;;;;;;;;;;-1:-1:-1;14814:704:17;;;;;:::i;:::-;;:::i;32116:173:30:-;;;;;;;;;;-1:-1:-1;32116:173:30;;;;;:::i;:::-;;:::i;47406:534:17:-;;;;;;;;;;-1:-1:-1;47406:534:17;;;;;:::i;:::-;;:::i;58928:149:30:-;;;;;;;;;;-1:-1:-1;58928:149:30;;;;;:::i;:::-;;:::i;52708:196::-;;;;;;;;;;-1:-1:-1;52708:196:30;;;;;:::i;:::-;;:::i;40567:1339::-;;;;;;;;;;-1:-1:-1;40567:1339:30;;;;;:::i;:::-;;:::i;57197:209::-;;;;;;;;;;-1:-1:-1;57197:209:30;;;;;:::i;:::-;;:::i;42798:112:17:-;;;;;;;;;;-1:-1:-1;42798:112:17;;;;;:::i;:::-;-1:-1:-1;;;;;42883:20:17;42857:7;42883:20;;;:13;:20;;;;;;;42798:112;56457:206:30;;;;;;;;;;-1:-1:-1;56457:206:30;;;;;:::i;:::-;;:::i;49362:686::-;;;;;;;;;;-1:-1:-1;49362:686:30;;;;;:::i;:::-;;:::i;62532:198::-;;;;;;;;;;-1:-1:-1;62532:198:30;;;;;:::i;:::-;;:::i;2188:191:21:-;;;;;;;;;;-1:-1:-1;2188:191:21;;;;;:::i;:::-;;:::i;10156:308:13:-;;;;;;;;;;-1:-1:-1;10402:1:13;10434:13;;10371:28;:32;;;;10156:308;;46232:294:30;;;;;;;;;;-1:-1:-1;46232:294:30;;;;;:::i;:::-;;:::i;31665:161:17:-;;;;;;;;;;-1:-1:-1;31665:161:17;;;;;:::i;:::-;31747:17;31791:28;;;:22;:28;;;;;;;;;31665:161;51266:191:30;-1:-1:-1;;;;;51400:14:30;;;;;;:10;:14;;;;;51381:69;;51411:2;51441:8;;51381:18;:69::i;:::-;51266:191;;;:::o;67887:434::-;67989:4;-1:-1:-1;;;;;;68024:53:30;;;;:120;;-1:-1:-1;;;;;;;68093:51:30;;-1:-1:-1;;;68093:51:30;68024:120;:177;;;-1:-1:-1;;;;;;;68160:41:30;;-1:-1:-1;;;68160:41:30;68024:177;:238;;;-1:-1:-1;;;;;;;68217:45:30;;-1:-1:-1;;;68217:45:30;68024:238;:290;;;-1:-1:-1;;;;;;;;;;732:40:22;;;68278:36:30;68005:309;67887:434;-1:-1:-1;;67887:434:30:o;35234:107::-;35301:33;35325:5;35332:1;35301:23;:33::i;:::-;35234:107;:::o;21865:670:17:-;22160:12;22184:59;3140:6:14;22184:17:17;:59;;:::i;:::-;22254:121;838:4:14;22295:5:17;22302:2;22306:12;22320:5;22327:10;22339:5;22346:14;22362:12;;22254:20;:121::i;:::-;22395:58;22416:5;22423;22430:2;22434;22438:14;22395:20;:58::i;:::-;22385:68;;22468:7;22464:65;;;22491:27;22505:5;22512;22491:13;:27::i;:::-;21865:670;;;;;;;;;;;;:::o;24672:1085::-;25112:12;25083:18;7336:66;7383:18;7336:46;:66::i;:::-;25136:59:::1;3140:6:14;25136:17:17;:59;;:::i;:::-;25206:292;25265:5;25284:2;25300:12;25326:5;25345:10;25369:5;25388:14;25416:12;;25442:14;25470:18;25206:45;:292::i;:::-;25592:2:::0;25614:61:::1;25635:5:::0;25642;25649:2;25592;25660:14;25614:20:::1;:61::i;:::-;25604:71;;25690:7;25686:65;;;25713:27;25727:5;25734;25713:13;:27::i;:::-;25126:631;24672:1085:::0;;;;;;;;;;;;;;;:::o;58310:149:30:-;-1:-1:-1;;;;;58410:14:30;;;;;;:10;:14;;;;;58375:16;;58410:42;;:40;:42::i;45782:558:17:-;45945:12;45969:58;2725:6:14;45969:17:17;:58;;:::i;:::-;46038:31;46072:76;46096:5;838:4:14;46123:5:17;46130:2;46134:6;46142:5;46072:23;:76::i;:::-;46038:110;;46168:50;46189:5;46196;46203:2;46207;46211:6;46168:20;:50::i;:::-;46158:60;;46233:7;46229:105;;;46256:67;46278:8;46288:5;144:1:14;46309:6:17;144:1:14;46256:21:17;:67::i;:::-;45959:381;45782:558;;;;;;;:::o;8427:134:13:-;7797:35;:33;:35::i;:::-;8521:33:::1;8539:14;8521:17;:33::i;63672:202:30:-:0;-1:-1:-1;;;;;63821:38:30;;;;;;:26;:38;;;;;:45;63761:16;;63796:71;;63821:45;;;-1:-1:-1;;;;;63821:45:30;63796:24;:71::i;27588:174::-;27712:43;27729:6;27737:4;27743:2;27747:7;27712:16;:43::i;:::-;27588:174;;;;;:::o;30231:146::-;30336:34;30353:6;30361:4;30367:2;30336:16;:34::i;37363:202::-;37478:80;14093:4;37536:5;37543:7;37552:5;37478:30;:80::i;66676:212::-;-1:-1:-1;;;;;66825:38:30;;66780:4;66825:38;;;:26;:38;;;;;;;;:45;;;;-1:-1:-1;;;;;66825:45:30;61453:14;;:10;:14;;;;;:48;;;:38;;:48;;;;;;;;66803:78;66796:85;66676:212;-1:-1:-1;;;66676:212:30:o;55719:201::-;55839:74;55863:10;:14;55874:2;-1:-1:-1;;;;;55863:14:30;-1:-1:-1;;;;;55863:14:30;;;;;;;;;;;;3584:1:29;55900:2:30;55904:8;;55839:74;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;55839:23:30;;-1:-1:-1;;;55839:74:30:i;44636:1080::-;3432:1:29;44875:36:30;;;;44871:135;;;44934:61;;-1:-1:-1;;;44934:61:30;;;;;;;;;;;44871:135;45016:53;45058:10;45016:41;:53::i;:::-;-1:-1:-1;;;;;45079:38:30;;;;;;:26;:38;;;;;;;;;:68;;-1:-1:-1;;45157:90:30;45079:68;;;;;;;-1:-1:-1;;45157:90:30;;;;;;;;;-1:-1:-1;;45370:92:30;45079:68;45257:103;;;;-1:-1:-1;;45370:92:30;;-1:-1:-1;;;45370:92:30;;;;;;;;45477:43;;24300:36:32;;;45477:43:30;;24273:18:32;45477:43:30;;;;;;;45535:91;;;24534:14:32;;24527:22;24509:41;;24593:14;;24586:22;24581:2;24566:18;;24559:50;-1:-1:-1;;;;;45535:91:30;;;;;24482:18:32;45535:91:30;;;;;;;45671:10;-1:-1:-1;;;;;45641:68:30;;45683:25;45641:68;;;;1549:14:32;1542:22;1524:41;;1512:2;1497:18;;1384:187;45641:68:30;;;;;;;;44636:1080;;;;;:::o;34140:1232:17:-;34540:22;34564:12;34511:18;7509:63;7553:18;7509:43;:63::i;:::-;34588:55:::1;3408:6:14;34588:17:17;:55;;:::i;:::-;34654:34;34691:241;34731:12;;34757:16;34787:5;34806:2;34822:5;34841:4;34859:10;34883:7;34904:18;34691:26;:241::i;:::-;34654:278;;35005:240;35037:11;35066:16;35100:5;35124:2;35145:5;35169:2;35190:7;35215:20;35005:14;:240::i;:::-;34943:302:::0;;-1:-1:-1;34943:302:17;-1:-1:-1;35256:110:17;::::1;;;35283:72;35305:11;35318:5;35325:7;35334:14;35350:4;35283:21;:72::i;:::-;34578:794;34140:1232:::0;;;;;;;;;;;;;;;:::o;36266:172:30:-;36351:80;14093:4;36409:5;36416:7;36425:5;36351:30;:80::i;:::-;36266:172;;:::o;65661:206::-;-1:-1:-1;;;;;65805:38:30;;;65762:4;65805:38;;;:26;:38;;;;;;;;:45;;;;-1:-1:-1;;;;;65805:45:30;61013:15;;:11;:15;;;;;:46;;;;;:37;;;;:46;;;;;;;;65785:75;60911:155;62920:196;-1:-1:-1;;;;;63063:38:30;;;;;;:26;:38;;;;;:45;63006:16;;63041:68;;63063:45;;;-1:-1:-1;;;;;63063:45:30;63041:21;:68::i;42477:143:17:-;42554:10;42540:25;;;;:13;:25;;;;;;:27;;;;;;42593:20;;;42540:25;42593:20;42477:143::o;13192:320::-;13362:21;;13422:83;13433:18;13453:5;13460:8;13470:9;13481:5;13488:2;13362:21;13422:10;:83::i;:::-;13415:90;;;;13192:320;;;;;;;;:::o;54245:199:30:-;-1:-1:-1;;;;;54385:14:30;;;;;;:10;:14;;;;;54364:73;;3584:1:29;54396:2:30;54426:10;;54364:20;:73::i;30017:962:17:-;30435:12;30406:18;7336:66;7383:18;7336:46;:66::i;:::-;30459:57:::1;3277:6:14;30459:17:17;:57;;:::i;:::-;30527:292;30584:5;202:1:14;30621:12:17;30647:5;30666:10;30690:5;30709:14;30737:12;;30763:14;30791:18;30527:43;:292::i;:::-;30839:58;30858:5;30865;30872:2;202:1:14;30882:14:17;30839:18;:58::i;:::-;30829:68;;30912:7;30908:65;;;30935:27;30949:5;30956;30935:13;:27::i;:::-;30017:962:::0;;;;;;;;;;;;;;:::o;59562:153:30:-;-1:-1:-1;;;;;59664:14:30;;;;;;:10;:14;;;;;59629:16;;59664:44;;:35;;:42;:44::i;34293:149::-;34379:56;34410:8;34420:5;34427:1;34430:4;34379:30;:56::i;57940:209::-;-1:-1:-1;;;;;58090:14:30;;;;;;:10;:14;;;;;58064:78;;3584:1:29;58101:2:30;58131:10;;58064:25;:78::i;11182:1326:17:-;11530:11;11512:29;;:15;:29;11508:114;;;11564:47;;-1:-1:-1;;;11564:47:17;;;;;;;;;;;11508:114;11631:33;11654:9;11631:22;:33::i;:::-;11674:38;11699:5;11706;11674:24;:38::i;:::-;11722:470;11758:378;11792:330;11844:9;11875:5;11902:2;11926:6;-1:-1:-1;;;;;11792:330:17;11954:5;11981:8;12011:18;11792:330;;12051:11;11792:330;;12084:13;:20;12098:5;-1:-1:-1;;;;;12084:20:17;-1:-1:-1;;;;;12084:20:17;;;;;;;;;;;;;11792:30;:330::i;:::-;11758:16;:378::i;:::-;12150:12;;12177:5;11722:22;:470::i;:::-;12339:23;;;;:70;;12391:18;12339:70;;;12372:15;12339:70;12318:91;;12420:81;12435:9;12446:5;12453:2;12457:6;12465:18;12485:5;12492:8;12420:14;:81::i;:::-;11182:1326;;;;;;;;;;;:::o;16967:568::-;17199:12;17223:58;2999:6:14;17223:17:17;:58;;:::i;:::-;17292:100;701:3:14;17332:5:17;17339:2;257:1:14;17348:5:17;17355:10;17367:5;257:1:14;17379:12:17;;17292:20;:100::i;:::-;17412:41;17432:5;17439:2;17443:5;17450:2;17412:19;:41::i;:::-;17402:51;;17468:7;17464:65;;;17491:27;17505:5;17512;17491:13;:27::i;:::-;16967:568;;;;;;;;;;:::o;40812:338::-;41008:21;41031:18;41068:75;41079:15;41096:5;41103:8;41113:9;41124:5;41131:2;41135:7;41068:10;:75::i;:::-;41061:82;;;;40812:338;;;;;;;;;;:::o;54981:201:30:-;55101:74;55125:10;:14;55136:2;-1:-1:-1;;;;;55125:14:30;-1:-1:-1;;;;;55125:14:30;;;;;;;;;;;;3508:1:29;55162:2:30;55166:8;;55101:74;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;55101:23:30;;-1:-1:-1;;;55101:74:30:i;42453:272::-;-1:-1:-1;;;;;42536:22:30;;42533:137;;42581:78;;-1:-1:-1;;;42581:78:30;;;;;;;;;;;42533:137;42680:38;42705:2;42709:8;42680:24;:38::i;1938:101:21:-;1214:13;:11;:13::i;:::-;2002:30:::1;2029:1;2002:18;:30::i;:::-;1938:101::o:0;59243:153:30:-;-1:-1:-1;;;;;59345:14:30;;;;;;:10;:14;;;;;59310:16;;59345:44;;:35;;:42;:44::i;48073:664::-;48186:53;48228:10;48186:41;:53::i;:::-;-1:-1:-1;;;;;48281:26:30;;48250:28;48281:26;;;:14;:26;;;;;;48318:413;48338:27;;;48318:413;;;48382:23;48408:16;;48425:1;48408:19;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;48382:45;-1:-1:-1;48446:48:30;:8;48382:45;48446:31;:48::i;:::-;48442:219;;;48558:15;-1:-1:-1;;;;;48519:55:30;48546:10;-1:-1:-1;;;;;48519:55:30;;;;;;;;;;;-1:-1:-1;;;;;48592:47:30;;;;;;:30;;;:47;;;;;:54;;-1:-1:-1;;48592:54:30;48642:4;48592:54;;;48442:219;-1:-1:-1;48703:3:30;;48318:413;;63298:178;-1:-1:-1;;;;;63415:26:30;;;;;;:14;:26;;;;;63380:16;;63415:54;;:52;:54::i;4954:532:25:-;5066:21;:61;;;-1:-1:-1;212:66:24;5091:36:25;;;5066:61;5062:123;;;5150:24;;-1:-1:-1;;;5150:24:25;;;;;;;;;;;5062:123;5267:30;5278:18;5267:10;:30::i;:::-;5262:89;;5320:20;;-1:-1:-1;;;5320:20:25;;;;;;;;;;;5262:89;212:66:24;5398:43:25;;-1:-1:-1;;5398:43:25;5437:4;5398:43;;;5452:27;;:::i;51854:132:17:-;51906:23;51959:20;:18;:20::i;:::-;51941:38;;51854:132;:::o;64595:208:30:-;-1:-1:-1;;;;;64741:38:30;;;64697:4;64741:38;;;:26;:38;;;;;;;;:45;;;;-1:-1:-1;;;;;64741:45:30;60112:14;;:10;:14;;;;;:45;;;;;:36;;;;:45;;;;;;;;64720:76;60009:155;21866:325;21957:20;21982:84;22000:32;22034:10;22046:6;22054:4;22060:2;22064:1;21982:17;:84::i;:::-;-1:-1:-1;21956:110:30;-1:-1:-1;;;;;;;22080:34:30;;;22076:109;;22130:44;22160:13;22130:29;:44::i;:::-;21946:245;21866:325;;;:::o;44149:515:17:-;44287:12;44311:57;2587:6:14;44311:17:17;:57;;:::i;:::-;44379:31;44413:71;44437:5;701:3:14;44463:5:17;44470:2;257:1:14;44479:4:17;44413:23;:71::i;:::-;44379:105;;44504:41;44524:5;44531:2;44535:5;44542:2;44504:19;:41::i;:::-;44494:51;;44560:7;44556:102;;;44583:64;44605:8;44615:5;144:1:14;257;144;44583:21:17;:64::i;:::-;44301:363;44149:515;;;;;;:::o;9506:334:13:-;7797:35;:33;:35::i;:::-;9614:20:::1;9632:1;9614:17;:20::i;:::-;9649:18:::0;;9645:189:::1;;9684:12;9702:10;-1:-1:-1::0;;;;;9702:15:13::1;9725:14;9702:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9683:61;;;9762:7;9758:65;;9778:45;;-1:-1:-1::0;;;9778:45:13::1;;;;;;;;;;;58620:149:30::0;-1:-1:-1;;;;;58720:14:30;;;;;;:10;:14;;;;;58685:16;;58720:42;;:40;:42::i;67529:140::-;67613:49;;-1:-1:-1;;;67613:49:30;;-1:-1:-1;;;;;17841:55:32;;;67613:49:30;;;17823:74:32;67590:4:30;;67626:12;67613:40;;;;;;17796:18:32;;67613:49:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;43171:109::-;43233:40;43258:2;43270:1;43233:24;:40::i;65126:208::-;-1:-1:-1;;;;;65272:38:30;;;65228:4;65272:38;;;:26;:38;;;;;;;;:45;;;;-1:-1:-1;;;;;65272:45:30;60561:14;;:10;:14;;;;;:45;;;;;:36;;;;:45;;;;;;;;65251:76;60458:155;64070:202;-1:-1:-1;;;;;64219:38:30;;;;;;:26;:38;;;;;:45;64159:16;;64194:71;;64219:45;;;-1:-1:-1;;;;;64219:45:30;64194:24;:71::i;62142:198::-;-1:-1:-1;;;;;62287:38:30;;;;;;:26;:38;;;;;:45;62229:16;;62264:69;;62287:45;;;-1:-1:-1;;;;;62287:45:30;62264:22;:69::i;51987:191::-;-1:-1:-1;;;;;52121:14:30;;;;;;:10;:14;;;;;52102:69;;3584:1:29;52132:2:30;52162:8;;52102:18;:69::i;53475:199::-;-1:-1:-1;;;;;53615:14:30;;;;;;:10;:14;;;;;53594:73;;53626:2;53656:10;;53594:20;:73::i;39400:843:17:-;39603:10;-1:-1:-1;;;;;39603:19:17;;;;:45;;-1:-1:-1;39626:10:17;-1:-1:-1;;;;;39626:22:17;;;39603:45;39598:123;;39672:38;;-1:-1:-1;;;39672:38:17;;;;;;;;;;;39598:123;39730:33;39753:9;39730:22;:33::i;:::-;39773:34;39810:86;39832:15;39849:5;39856:9;39867:5;39874:2;39878:7;39887:8;39810:21;:86::i;:::-;39915:17;;39773:123;;-1:-1:-1;39915:37:17;:17;39911:326;;567:1:14;40059:26:17;;40104:43;;39968:41;1524::32;;-1:-1:-1;;;;;40104:43:17;;;;;;;;40116:7;;40104:43;;1512:2:32;1497:18;40104:43:17;;;;;;;39911:326;;;40185:41;;-1:-1:-1;;;40185:41:17;;;;;;;;;;;39911:326;39588:655;39400:843;;;;;;:::o;19514:883::-;19890:12;19861:18;7336:66;7383:18;7336:46;:66::i;:::-;19914:58:::1;2999:6:14;19914:17:17;:58;;:::i;:::-;19983:271;20041:5;20060:2;257:1:14;20093:5:17;20112:10;20136:5;257:1:14;20172:12:17;;20198:14;20226:18;19983:44;:271::i;:::-;20274:41;20294:5;20301:2;20305:5;20312:2;20274:19;:41::i;:::-;20264:51;;20330:7;20326:65;;;20353:27;20367:5;20374;20353:13;:27::i;:::-;19514:883:::0;;;;;;;;;;;;;:::o;67198:212:30:-;-1:-1:-1;;;;;67347:38:30;;67302:4;67347:38;;;:26;:38;;;;;;;;:45;;;;-1:-1:-1;;;;;67347:45:30;61895:14;;:10;:14;;;;;:48;;;:38;;:48;;;;;;;;67325:78;61790:160;38344:140;38438:39;38462:5;38469:7;33068:183;33150:94;13959:66;33222:5;33229:7;13959:66;33150:30;:94::i;39274:267::-;39385:10;39383:12;;-1:-1:-1;;;;;39383:12:30;;;;;;;;-1:-1:-1;;39383:12:30;;;;;;;;39332:10;39416:14;;;:10;:14;;;;;;;:27;;-1:-1:-1;;;;;;39416:27:30;39433:10;39416:27;;;39459:21;;;;;39475:4;;;;39459:21;:::i;:::-;;;;;;;;39495:39;;39523:10;;-1:-1:-1;;;;;39495:39:30;;;;;;;;39274:267;;;;:::o;9000:321:17:-;9193:33;9216:9;9193:22;:33::i;:::-;9236:78;9251:9;9262:5;9269:2;9273:6;9281:10;9293;9305:8;9236:14;:78::i;:::-;9000:321;;;;;;:::o;47101:367:30:-;47181:53;47223:10;47181:41;:53::i;:::-;47254:10;;-1:-1:-1;;;;;47254:10:30;;;47249:15;;;;47245:102;;;47287:49;;-1:-1:-1;;;47287:49:30;;;;;;;;;;;47245:102;-1:-1:-1;;;;;47357:38:30;;;;;;:26;:38;;;;;;:50;;-1:-1:-1;;47357:50:30;;-1:-1:-1;;;;;47357:50:30;;;;;;;;;;;;47422:39;;47357:50;;:38;47422:39;;;47101:367;;:::o;41641:118:17:-;41709:43;41734:10;41746:5;41709:24;:43::i;24718:343:30:-;24826:20;24851:85;24869:27;24898:10;24910:6;24918:4;24924:2;24928:7;24851:17;:85::i;:::-;-1:-1:-1;24825:111:30;-1:-1:-1;;;;;;;24950:34:30;;;24946:109;;25000:44;25030:13;25000:29;:44::i;37432:1208:17:-;37810:22;37834:12;37781:18;7509:63;7553:18;7509:43;:63::i;:::-;37858:53:::1;3534:6:14;37858:17:17;:53;;:::i;:::-;37922:34;37959:241;37997:12;;38023:16;38053:5;202:1:14;38090:5:17;38109:4;38127:10;38151:7;38172:18;37959:24;:241::i;:::-;37922:278;;38273:240;38305:11;38334:16;38368:5;202:1:14;38415:5:17;38439:2;38460:7;38485:18;38273:14;:240::i;:::-;38211:302:::0;;-1:-1:-1;38211:302:17;-1:-1:-1;38524:110:17;::::1;;;38551:72;38573:11;38586:5;38593:7;38602:14;38618:4;38551:21;:72::i;:::-;37848:792;37432:1208:::0;;;;;;;;;;;;;;:::o;27235:646::-;27508:12;27532:57;3277:6:14;27532:17:17;:57;;:::i;:::-;27600:121;972:2:14;27639:5:17;202:1:14;27652:12:17;27666:5;27673:10;27685:5;27692:14;27708:12;;27600:20;:121::i;:::-;27741:58;27760:5;27767;27774:2;202:1:14;27784:14:17;27741:18;:58::i;:::-;27731:68;;27814:7;27810:65;;;27837:27;27851:5;27858;27837:13;:27::i;:::-;27235:646;;;;;;;;;;;:::o;14814:704::-;15210:4;14911:25;:296;15043:49;;;;;;;;;;;;;;;;;15119:24;;15004:161;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;14950:247;;;;;;14911:296;;;;;;;;;;;;:303;;;;;;;;;;;;;;;;;;15507:4;15225:22;:279;15354:35;;;;;;;;;;;;;;;;;15416:24;;15315:147;;;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;15315:147:17;;;;;;15261:233;;15315:147;15261:233;;;;15225:279;;;;;;;;;;-1:-1:-1;15225:279:17;:286;;-1:-1:-1;;15225:286:17;;;;;;;;;;-1:-1:-1;;14814:704:17:o;32116:173:30:-;32219:63;32250:8;32260:5;32267:7;32276:5;32219:30;:63::i;47406:534:17:-;47547:12;47571:56;2859:6:14;47571:17:17;:56;;:::i;:::-;47638:31;47672:76;47696:5;972:2:14;47721:5:17;202:1:14;47734:6:17;47742:5;47672:23;:76::i;:::-;47638:110;;47768:50;47787:5;47794;47801:2;202:1:14;47811:6:17;47768:18;:50::i;:::-;47758:60;;47833:7;47829:105;;;47856:67;47878:8;47888:5;144:1:14;47909:6:17;144:1:14;47856:21:17;:67::i;58928:149:30:-;-1:-1:-1;;;;;59027:15:30;;;;;;:11;:15;;;;;58992:16;;59027:43;;:41;:43::i;52708:196::-;-1:-1:-1;;;;;52844:15:30;;;;;;:11;:15;;;;;52825:72;;3662:1:29;52856:2:30;52888:8;;52825:18;:72::i;40567:1339::-;40706:10;40704:12;;-1:-1:-1;;40704:12:30;;;-1:-1:-1;;;;;40704:12:30;;;;;;;;;;;;;;;;;40765:21;;;;40761:116;;;40813:49;;-1:-1:-1;;;40813:49:30;;;;;;;;;;;40761:116;-1:-1:-1;;;;;40897:14:30;;;;;;:10;:14;;;;;;;:27;;-1:-1:-1;;;;;;40897:27:30;40914:10;40897:27;;;40940:21;;;;;40956:4;;;;40940:21;:::i;:::-;;;;;;;;40976:39;;41004:10;;-1:-1:-1;;;;;40976:39:30;;;;;;;;-1:-1:-1;;;;;41057:24:30;;;41026:28;41057:24;;;:10;:24;;;;;;;;41122:10;:24;;;;;;41189:11;:25;;;;;;41255:14;;;;;;;;;;;41310;;;;;;41367:15;;;;;;;41057:24;;41122;;41189:25;;41255:14;;41393:74;;41266:2;41057:24;41255:14;41393:15;:74::i;:::-;41477;3508:1:29;41514:2:30;41518:15;41535;41477;:74::i;:::-;41561;3584:1:29;41598:2:30;41602:15;41619;41561;:74::i;:::-;41645;3584:1:29;41682:2:30;41686:15;41703;41645;:74::i;:::-;41729:80;3662:1:29;41768:2:30;41772:17;41791;41729:15;:80::i;:::-;41819;3662:1:29;41858:2:30;41862:17;41881;41819:15;:80::i;:::-;40665:1241;;;;;;40567:1339;;;;;:::o;57197:209::-;-1:-1:-1;;;;;57347:14:30;;;;;;:10;:14;;;;;57321:78;;57358:2;57388:10;;57321:25;:78::i;56457:206::-;56579:77;56603:11;:15;56615:2;-1:-1:-1;;;;;56603:15:30;-1:-1:-1;;;;;56603:15:30;;;;;;;;;;;;3662:1:29;56643:2:30;56647:8;;56579:77;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;56579:23:30;;-1:-1:-1;;;56579:77:30:i;49362:686::-;49479:53;49521:10;49479:41;:53::i;:::-;-1:-1:-1;;;;;49574:26:30;;49543:28;49574:26;;;:14;:26;;;;;;49611:431;49631:29;;;49611:431;;;49677:25;49705:18;;49724:1;49705:21;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;49677:49;-1:-1:-1;49745:53:30;:8;49677:49;49745:34;:53::i;:::-;49741:231;;;49864:17;-1:-1:-1;;;;;49823:59:30;49852:10;-1:-1:-1;;;;;49823:59:30;;;;;;;;;;;-1:-1:-1;;;;;49900:49:30;;49952:5;49900:49;;;:30;;;:49;;;;;:57;;-1:-1:-1;;49900:57:30;;;49741:231;-1:-1:-1;50014:3:30;;49611:431;;62532:198;-1:-1:-1;;;;;62677:38:30;;;;;;:26;:38;;;;;:45;62619:16;;62654:69;;62677:45;;;-1:-1:-1;;;;;62677:45:30;62654:22;:69::i;2188:191:21:-;1214:13;:11;:13::i;:::-;-1:-1:-1;;;;;2271:22:21;::::1;2268:66;;2302:32;;-1:-1:-1::0;;;2302:32:21::1;;;;;;;;;;;2268:66;2344:28;2363:8;2344:18;:28::i;46232:294:30:-:0;46346:53;46388:10;46346:41;:53::i;:::-;-1:-1:-1;;;;;46409:38:30;;;;;;:26;:38;;;;;;;;;:60;;;;-1:-1:-1;;;46409:60:30;;;;;;;;;;;;;46484:35;;26485:38:32;;;46484:35:30;;26458:18:32;46484:35:30;;;;;;;46232:294;;:::o;5818:140:25:-;5936:5;5923:11;5916:26;5818:140;;:::o;6999:169::-;7134:18;;6999:169::o;8171:123::-;8276:1;8263:11;8256:22;8171:123;:::o;6333:331::-;212:66:24;6432:36:25;;;6428:230;;;6531:5;6518:11;6511:26;36266:172:30;;:::o;6428:230:25:-;6608:26;;6333:331::o;7546:360::-;7643:13;212:66:24;7672:36:25;;;7668:232;;;-1:-1:-1;7760:18:25;;7546:360::o;7668:232::-;-1:-1:-1;7858:18:25;;7668:232;7546:360;;;:::o;8602:310::-;212:66:24;8688:36:25;;;8684:222;;;8787:1;8774:11;8767:22;35234:107:30;:::o;8684:222:25:-;8880:1;8860:22;;8602:310::o;11336:288:13:-;11455:28;14901:9;14877:21;:33;11425:58;11421:197;;;11503:13;;:22;;:26;11499:109;;11556:37;;-1:-1:-1;;;11556:37:13;;;;;;;;;;;12555:336;12672:28;14901:9;14877:21;:33;12641:59;12637:248;;12723:40;;-1:-1:-1;;;12723:40:13;;;;;;;;;;;12637:248;12800:6;12784:13;;:22;12810:1;12784:27;12780:105;;12834:40;;-1:-1:-1;;;12834:40:13;;;;;;;;;;;13634:228;13703:22;13771:28;14901:9;14877:21;:33;13741:58;13737:119;;;-1:-1:-1;13832:13:13;;13737:119;13634:228;:::o;11894:195::-;11986:13;;:22;;:26;11982:101;;12035:37;;-1:-1:-1;;;12035:37:13;;;;;;;;;;;14027:143;14150:13;;;14027:143::o;73981:553:30:-;74146:2;19112:26;19135:2;19112:22;:26::i;:::-;74160:15:::1;::::0;74185:343:::1;74205:19:::0;;::::1;74185:343;;;74251:8;;74260:1;74251:11;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;74241:21:::0;-1:-1:-1;74281:36:30::1;:4:::0;74241:21;74281:27:::1;:36::i;:::-;74277:181;;;74375:7;-1:-1:-1::0;;;;;74342:41:30::1;74371:2;-1:-1:-1::0;;;;;74342:41:30::1;74361:8;74342:41;;;;;;;;;;;;-1:-1:-1::0;;;;;74401:35:30;::::1;;::::0;;;:26:::1;::::0;::::1;:35;::::0;;;;:42;;-1:-1:-1;;74401:42:30::1;74439:4;74401:42;::::0;;74277:181:::1;74500:3;;74185:343;;;;74150:384;73981:553:::0;;;;;;:::o;65416:793:17:-;65713:14;65730:273;65760:233;65808:9;65835:5;65858:2;65878:12;65908:5;65931:10;65959:13;:20;65973:5;-1:-1:-1;;;;;65959:20:17;-1:-1:-1;;;;;65959:20:17;;;;;;;;;;;;;2503:270:19;;;1652:160:14;2503:270:19;;;;29786:25:32;;;;29827:18;;;29820:34;;;;-1:-1:-1;;;;;29951:15:32;;;;29931:18;;;29924:43;29983:18;;;29976:34;;;;30026:19;;;30019:35;;;;30070:19;;;30063:35;;;;2692:10:19;30114:19:32;;;30107:44;30167:19;;;30160:35;30211:19;;;;30204:35;;;;2503:270:19;;;;;;;;;;29758:19:32;;;;2503:270:19;;2480:303;;;;;;2217:573;65730:273:17;65713:290;;66014:188;66044:5;66063:10;66087:14;66115:12;66141:5;66160:6;66180:12;;66014:16;:188::i;49770:442::-;49933:12;49967:69;838:4:14;50007:5:17;50014;50021:2;50025;50029:6;49967:19;:69::i;:::-;49957:79;;50052:7;50047:159;;50079:59;;-1:-1:-1;;;50079:59:17;;-1:-1:-1;;;;;26908:15:32;;;50079:59:17;;;26890:34:32;26960:15;;;26940:18;;;26933:43;26992:18;;;26985:34;;;27035:18;;;27028:34;;;27099:3;27078:19;;;27071:32;-1:-1:-1;27119:19:32;;;27112:30;50079:32:17;;;;;27159:19:32;;50079:59:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;50075:121;;-1:-1:-1;50177:4:17;50075:121;49770:442;;;;;;;:::o;85323:320::-;-1:-1:-1;;;;;85432:25:17;;202:1:14;85432:25:17;;;:16;:25;;;;;;;;85475:1;85466:10;;;85432:46;;;;;;;:71;;257:1:14;85525:19:17;;;;85432:71;;;;;;;85424:121;:129;85420:207;;85580:32;;-1:-1:-1;;;85580:32:17;;;;;;;;;;;59978:248;60090:45;;;;:25;:45;;;;;;;;60085:135;;60158:51;;-1:-1:-1;;;60158:51:17;;;;;;;;;;;67380:687;67743:317;838:4:14;67827:5:17;67846:2;67862:12;67888:5;67907:10;67931:5;67950:14;67978:12;;68004:14;68032:18;67743:38;:317::i;10064:300:26:-;10127:16;10155:22;10180:19;10188:3;10180:7;:19::i;62002:843:17:-;62205:31;62259:96;62281:18;62301:5;62308:9;62319:5;62326:2;62205:31;62344:10;62259:21;:96::i;:::-;62378:19;;;;-1:-1:-1;62400:15:17;-1:-1:-1;;;62378:19:17;;;;;:37;62374:122;;;62438:47;;-1:-1:-1;;;62438:47:17;;;;;;;;;;;62374:122;62509:15;;;;;-1:-1:-1;;;;;62509:15:17;-1:-1:-1;;62505:112:17;;;62556:50;;-1:-1:-1;;;62556:50:17;;;;;;;;;;;62505:112;62630:15;62627:212;;;62661:19;;-1:-1:-1;;;;;;62661:19:17;;;62627:212;;;62701:15;;-1:-1:-1;;;;;62701:15:17;;;;;;:35;62697:142;;;62780:34;;-1:-1:-1;;;;;62780:34:17;;;;;;;;;;;;;-1:-1:-1;;;;;;62780:34:17;;;;;;62697:142;62002:843;;;;;;;;:::o;86103:825::-;86311:18;;86307:615;;86349:13;86345:567;;;86489:42;;-1:-1:-1;;;;;;;86489:42:17;;;;;;;;;;;;86568:33;;;;;;;;86624:45;;17048:25:32;;;-1:-1:-1;;;;;86624:45:17;;;86638:7;;86624:45;;17036:2:32;17021:18;86624:45:17;;;;;;;86345:567;;;86694:15;;-1:-1:-1;;;;;86694:15:17;;;;;;:35;86690:222;;;86837:42;;-1:-1:-1;;;;;86837:42:17;;;;;;;;;;;;-1:-1:-1;;;;;;86837:42:17;;;;;;86103:825;;;;;:::o;90443:106::-;90529:13;:11;:13::i;10646:222:13:-;10740:13;;;10764:30;;;;10810:51;;;11807:25:32;;;11863:2;11848:18;;11841:34;;;10810:51:13;;11780:18:32;10810:51:13;;;;;;;10706:162;10646:222;:::o;94575:474:30:-;94786:10;94798:8;94808:10;94003:77;94047:10;94059:8;94069:10;94003:43;:77::i;:::-;98709:20;98764:24;;;98814:33;98808:4;98801:47;98893:4;98877:21;;94830:114:::1;::::0;94933:8:::1;-1:-1:-1::0;;;;;94917:26:30::1;94883:15;:30;;94912:1;94883:30;;;-1:-1:-1::0;;;94883:30:30::1;94882:61;94830:12;:114;;:::i;:::-;94954:88;94967:46;94993:10;95005:7;98120:20:::0;98175:24;;;98219:4;98212:21;98285:4;98269:21;;98266:1;98262:29;;98002:304;94967:46:::1;95031:8;-1:-1:-1::0;;;;;95015:26:30::1;94954:12;:88;;:::i;76414:564::-:0;76584:2;19112:26;19135:2;19112:22;:26::i;:::-;76598:15:::1;::::0;76623:349:::1;76647:8;:15;76643:1;:19;76623:349;;;76689:8;76698:1;76689:11;;;;;;;;:::i;:::-;;::::0;;::::1;::::0;;;;;;;-1:-1:-1;76718:39:30::1;:4:::0;76689:11;76718:30:::1;:39::i;:::-;76714:188;;;76819:7;-1:-1:-1::0;;;;;76782:45:30::1;76815:2;-1:-1:-1::0;;;;;76782:45:30::1;76805:8;76782:45;;;;;;;;;;;;-1:-1:-1::0;;;;;76852:35:30;::::1;;::::0;;;:26:::1;::::0;::::1;:35;::::0;;;;76845:42;;-1:-1:-1;;76845:42:30::1;::::0;;76714:188:::1;76944:3;;76623:349;;68933:614:::0;69047:10;-1:-1:-1;;;;;69079:22:30;;;;69076:58;;69117:7;68933:614;:::o;69076:58::-;69145:21;69171:24;69182:12;69171:10;:24::i;:::-;69144:51;;;69218:13;-1:-1:-1;;;;;69208:23:30;:6;-1:-1:-1;;;;;69208:23:30;;69205:59;;69247:7;;68933:614;:::o;69205:59::-;69275:26;69306:69;69319:12;69275:26;69368:6;69306:12;:69::i;:::-;69274:101;;;69388:21;69385:57;;;69425:7;;;68933:614;:::o;69385:57::-;69459:81;;-1:-1:-1;;;69459:81:30;;;;;;;;;;;60477:242:17;60586:42;;;;:22;:42;;;;;;;;60581:132;;60651:51;;-1:-1:-1;;;60651:51:17;;;;;;;;;;;77475:657;77799:34;77859:266;77892:12;;77918:16;838:4:14;77980:5:17;77999:2;78015:5;78034:4;78052:10;78076:7;78097:18;77859:19;:266::i;:::-;77845:280;77475:657;-1:-1:-1;;;;;;;;;;;77475:657:17:o;83908:1132::-;84405:18;;84329:36;;;;;84264:22;;84405:18;;;-1:-1:-1;;;;;84405:18:17;84388:35;;84384:101;;;84456:18;;;;;-1:-1:-1;;;;;84456:18:17;;-1:-1:-1;84384:101:17;84516:16;:34;;;84499:14;:51;84495:136;;;84573:47;;-1:-1:-1;;;84573:47:17;;;;;;;;;;;84495:136;84665:45;;-1:-1:-1;;;;;84665:45:17;;;;;;;;;;;;;-1:-1:-1;;;;;;84665:45:17;;;;;;84729:55;;17048:25:32;;;84757:10:17;;-1:-1:-1;;;;;84729:55:17;;;84741:7;;84729:55;;17036:2:32;17021:18;84729:55:17;;;;;;;84809:18;;;;;-1:-1:-1;;;;;84809:18:17;;:23;84805:157;;84848:38;;-1:-1:-1;;84848:38:17;459:1:14;84848:38:17;;;84905:46;;-1:-1:-1;1524:41:32;;84933:10:17;;-1:-1:-1;;;;;84905:46:17;;;84917:7;;84905:46;;1512:2:32;1497:18;84905:46:17;;;;;;;84805:157;84982:51;84996:5;85003;85010:2;85014;85018:14;84982:13;:51;;:::i;:::-;84972:61;;83908:1132;;;;;;;;;;;:::o;89640:578::-;89920:21;89943:18;89973:30;90006:81;90028:10;90040:5;90047:9;90058:5;90065:2;90069:7;90078:8;90006:21;:81::i;:::-;90113:18;;;;-1:-1:-1;90134:15:17;-1:-1:-1;;;90113:18:17;;;;;:36;:57;;90156:14;;;;;-1:-1:-1;;;;;90156:14:17;90113:57;;;90152:1;90113:57;90193:18;;-1:-1:-1;;;;;90097:73:17;;;;-1:-1:-1;;;90193:18:17;;;;;;-1:-1:-1;90097:73:17;-1:-1:-1;;;;;;;;89640:578:17:o;75184:571:30:-;75353:2;19112:26;19135:2;19112:22;:26::i;:::-;75367:16:::1;::::0;75393:356:::1;75413:21:::0;;::::1;75393:356;;;75462:10;;75473:1;75462:13;;;;;;;:::i;:::-;;;;;;;75451:24;;75494:39;75524:8;75494:4;:25;;:29;;:39;;;;:::i;:::-;75490:189;;;75592:8;75588:2;-1:-1:-1::0;;;;;75558:43:30::1;75578:8;75558:43;;;;;;;;;;;;75619:38;::::0;;;:28:::1;::::0;::::1;:38;::::0;;;;:45;;-1:-1:-1;;75619:45:30::1;75660:4;75619:45;::::0;;75490:189:::1;75721:3;;75393:356;;69235:683:17::0;69596:315;972:2:14;69678:5:17;69697:2;69713:12;69739:5;69758:10;69782:5;69801:14;69829:12;;69855:14;69883:18;69596:38;:315::i;50898:614::-;51065:12;51099:69;972:2:14;51137:5:17;51144;51151:2;202:1:14;51161:6:17;51099:19;:69::i;:::-;51089:79;;51184:7;51179:327;;51254:71;;;-1:-1:-1;;;;;27470:15:32;;;51254:71:17;;;27452:34:32;27522:15;;;27502:18;;;27495:43;27554:18;;;;27547:34;;;51254:71:17;;;;;;;;;;27364:18:32;;;;51254:71:17;;;;;;;;;-1:-1:-1;;;51254:71:17;;;51243:83;;-1:-1:-1;;;;51243:10:17;;;;:83;;51254:71;51243:83;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;51207:119;;;;51345:7;51340:156;;51382:4;51372:14;;51340:156;;;51411:11;;:15;51407:89;;51468:4;51457:24;;;;;;;;;;;;:::i;:::-;51456:25;51446:35;;51407:89;51193:313;;50898:614;;;;;;;:::o;77651:585:30:-;77828:2;19112:26;19135:2;19112:22;:26::i;:::-;77842:16:::1;::::0;77868:362:::1;77888:21:::0;;::::1;77868:362;;;77937:10;;77948:1;77937:13;;;;;;;:::i;:::-;;;;;;;77926:24;;77968:42;78001:8;77968:4;:25;;:32;;:42;;;;:::i;:::-;77964:196;;;78073:8;78069:2;-1:-1:-1::0;;;;;78035:47:30::1;78059:8;78035:47;;;;;;;;;;;;78107:38;::::0;;;:28:::1;::::0;::::1;:38;::::0;;;;78100:45;;-1:-1:-1;;78100:45:30::1;::::0;;77964:196:::1;78202:3;;77868:362;;86934:306:17::0;701:3:14;87026:9:17;:30;:78;;;;838:4:14;87073:9:17;:31;87026:78;:124;;;;972:2:14;87121:9:17;:29;87026:124;87008:226;;87196:27;;-1:-1:-1;;;87196:27:17;;;;;;;;;;;61004:335;-1:-1:-1;;;;;61124:25:17;;202:1:14;61124:25:17;;;:16;:25;;;;;;;;61167:1;61158:10;;;61124:46;;;;;;;:71;;257:1:14;61217:19:17;;;;61124:71;;;;;;;61116:121;61112:211;;61272:36;;-1:-1:-1;;;61272:36:17;;;;;;;;;;;908:670:19;1258:303;;;1314:195:14;1258:303:19;;;28283:25:32;28324:18;;;28317:34;;;-1:-1:-1;;;;;28448:15:32;;;28428:18;;;28421:43;28480:18;;;28473:34;;;28523:19;;;28516:35;;;28567:19;;;28560:35;;;28632:15;;28611:19;;;28604:44;28664:19;;;28657:35;;;28708:19;;;28701:35;;;28752:19;;;28745:35;;;1204:12:19;;28255:19:32;;1258:303:19;;;;;;;;;;;;;1235:336;;;;;;1228:343;;908:670;;;;;;;;;;;:::o;4292:165:20:-;4369:7;4395:55;4417:20;:18;:20::i;:::-;4439:10;8536:4:9;8530:11;-1:-1:-1;;;8554:23:9;;8606:4;8597:14;;8590:39;;;;8658:4;8649:14;;8642:34;8712:4;8697:20;;;8336:397;52615:1385:17;52751:2;52731:22;;;52727:1267;;52975:30;;53062:2;53040:25;;53027:39;53131:2;53109:25;;53096:39;52769:9;53088:48;;;;52769:9;53196:30;53210:6;53088:48;52975:30;53027:39;53196:13;:30::i;:::-;53163:63;;;;53253:6;-1:-1:-1;;;;;53244:15:17;:5;-1:-1:-1;;;;;53244:15:17;;;:26;;;;53263:7;53244:26;53240:114;;;53290:49;53314:5;53321:6;53329:9;;53290:23;:49::i;:::-;52755:609;;;;;52727:1267;;;53394:2;53374:22;;;53370:624;;53596:30;;53684:2;53662:25;;53649:39;53412:9;;53748:28;53762:6;53596:30;53649:39;53748:13;:28::i;:::-;53715:61;;;;53803:6;-1:-1:-1;;;;;53794:15:17;:5;-1:-1:-1;;;;;53794:15:17;;;:26;;;;53813:7;53794:26;53790:114;;;53840:49;53864:5;53871:6;53879:9;;53840:23;:49::i;:::-;53398:516;;;;53370:624;;;53934:49;53958:5;53965:6;53973:9;;53934:23;:49::i;75829:510::-;76047:31;76081:94;76103:18;76123:5;76130:9;76141:5;76148:2;76047:31;76166:8;76081:21;:94::i;:::-;76194:32;;76236:24;;-1:-1:-1;;;76194:32:17;;;;;;-1:-1:-1;;;;;;76236:24:17;;;;;76194:32;-1:-1:-1;;;;;76236:24:17;;;;;;;;;;;76276:56;;;28991:25:32;;;29047:2;29032:18;;29025:93;;;;29134:18;;29127:55;;;;76194:32:17;;-1:-1:-1;;;;;;76276:56:17;;;;;;;;;;;;;28979:2:32;28964:18;76276:56:17;;;;;;;76037:302;75829:510;;;;;;;:::o;48621:409::-;48759:12;48793:65;701:3:14;48832:5:17;48839;48846:2;48850;257:1:14;48793:19:17;:65::i;:::-;48783:75;;48874:7;48869:155;;48901:42;;-1:-1:-1;;;48901:42:17;;-1:-1:-1;;;;;27470:15:32;;;48901:42:17;;;27452:34:32;27522:15;;;27502:18;;;27495:43;27554:18;;;27547:34;;;48901:27:17;;;;;27364:18:32;;48901:42:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;48897:117;;-1:-1:-1;48995:4:17;48897:117;48621:409;;;;;;:::o;78709:340:30:-;-1:-1:-1;;;;;78795:21:30;;78791:128;;78839:69;;-1:-1:-1;;;78839:69:30;;;;;;;;;;;78791:128;78929:26;78952:2;78929:22;:26::i;:::-;-1:-1:-1;;;;;78965:14:30;;;;;;:10;:14;;;;;;:25;;-1:-1:-1;;;;;;78965:25:30;-1:-1:-1;;;;;78965:25:30;;;;;;;;79005:37;;78965:25;;:14;79005:37;;;78709:340;;:::o;1479:124:21:-;1367:7;1393:6;-1:-1:-1;;;;;1393:6:21;719:10:7;1537:23:21;1534:62;;1569:27;;-1:-1:-1;;;1569:27:21;;;;;;;;;;;2533:187;2606:16;2625:6;;-1:-1:-1;;;;;2641:17:21;;;-1:-1:-1;;;;;;2641:17:21;;;;;;2673:40;;2625:6;;;;;;;2673:40;;2606:16;2673:40;2596:124;2533:187;:::o;8110:150:26:-;8180:4;8203:50;8208:3;-1:-1:-1;;;;;8228:23:26;;8203:4;:50::i;10291:407:25:-;10374:7;10636:17;-1:-1:-1;;;;;10636:28:25;10683:2;10671:9;:14;;;;:::i;:::-;10636:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;10627:64:25;;10291:407;-1:-1:-1;;;10291:407:25:o;3251:230:20:-;3304:7;3344:14;3327:13;:31;3323:152;;-1:-1:-1;3381:22:20;;3251:230::o;3323:152::-;3441:23;3578:81;;;1857:95;3578:81;;;30912:25:32;3601:11:20;30953:18:32;;;30946:34;;;;3614:14:20;30996:18:32;;;30989:34;3630:13:20;31039:18:32;;;31032:34;3653:4:20;31082:19:32;;;31075:84;3542:7:20;;30884:19:32;;3578:81:20;;;;;;;;;;;;3568:92;;;;;;3561:99;;3487:180;;96402:271:30;96554:17;98764:24;;;98814:33;98808:4;98801:47;98893:4;98877:21;;96602:64;;96620:6;;96602:17;:64::i;96628:37::-;96602:17;:64::i;84206:6983::-;84478:6;;84525:4;-1:-1:-1;;;;;84507:23:30;;;84503:454;;-1:-1:-1;3760:10:29;;-1:-1:-1;3760:10:29;84900:46:30;;84503:454;-1:-1:-1;;;;;85029:38:30;;84967:59;85029:38;;;:26;:38;;;;;85095:31;;;;;-1:-1:-1;;;;;85095:31:30;;30956:24;30985:10;85234:46;;;30994:1;30985:10;;30956:40;;;85234:46;30929:69;;;;31037:26;:42;;;31008:73;;;-1:-1:-1;;;85296:50:30;;;85292:535;;;-1:-1:-1;;;;;85402:26:30;;;85362:37;85402:26;;;:14;:26;;;;;;;;85459:45;;;;;:39;;;:45;;;;;;;;85455:174;;;-1:-1:-1;;;;85532:61:30;-1:-1:-1;14150:1:30;;-1:-1:-1;85524:90:30;;-1:-1:-1;;;;85524:90:30;85455:174;-1:-1:-1;;;;;85647:43:30;;;;;;:39;;;:43;;;;;;;;85643:174;;;-1:-1:-1;;;;85718:63:30;-1:-1:-1;14150:1:30;;-1:-1:-1;85710:92:30;;-1:-1:-1;;;;85710:92:30;85643:174;85348:479;85292:535;1352:1:29;85841:17:30;:43;85837:159;;-1:-1:-1;;;;85908:56:30;-1:-1:-1;14150:1:30;;-1:-1:-1;85900:85:30;;-1:-1:-1;;;85900:85:30;85837:159;-1:-1:-1;;;;;86031:18:30;;86006:22;86031:18;;;:10;:18;;;;;-1:-1:-1;;86064:51:30;;86060:1511;;79850:20;;86135:25;86131:674;;-1:-1:-1;;;;;86185:35:30;;;;;;:31;;;:35;;;;;;;;86180:611;;86411:22;86459:46;86477:10;86489:6;86497:7;86459:46;;;:::i;:::-;86455:318;;80260:20;;86538:54;;;;:33;;;:54;;;;;;;;86533:218;;-1:-1:-1;;;;86632:71:30;-1:-1:-1;14150:1:30;;-1:-1:-1;86624:100:30;;-1:-1:-1;;;;;86624:100:30;86533:218;86222:569;86180:611;86060:1511;;;469:1:29;86825:19:30;:47;86821:750;;86893:17;86907:2;86893:13;:17::i;:::-;86888:673;;-1:-1:-1;;;;;86935:35:30;;;;;;:31;;;:35;;;;;;;;86930:617;;87161:22;87209:46;87227:10;87239:6;87247:7;87209:46;;;:::i;:::-;87205:324;;80260:20;;87288:54;;;;:33;;;:54;;;;;;;;87283:224;;-1:-1:-1;;;;87382:77:30;-1:-1:-1;14150:1:30;;-1:-1:-1;87374:106:30;;-1:-1:-1;;;;;87374:106:30;87283:224;86972:575;86930:617;87595:4;-1:-1:-1;;;;;87585:14:30;:6;-1:-1:-1;;;;;87585:14:30;;87581:215;;1243:1:29;87619:17:30;:70;87615:171;;-1:-1:-1;;87736:34:30;;3760:10:29;;-1:-1:-1;;;;87736:34:30;;;;;-1:-1:-1;87709:62:30;;-1:-1:-1;;87709:62:30;87615:171;945:1:29;87810:17:30;:69;87806:3304;;88054:22;88093:46;88111:10;88123:6;88131:7;88093:46;;;:::i;:::-;88090:146;;;-1:-1:-1;;88186:34:30;;3760:10:29;;-1:-1:-1;;;;88186:34:30;;;;;-1:-1:-1;88159:62:30;;-1:-1:-1;;;88159:62:30;88090:146;88250:22;88275:10;:18;88286:6;-1:-1:-1;;;;;88275:18:30;-1:-1:-1;;;;;88275:18:30;;;;;;;;;;;;88250:43;;88311:9;:31;;:39;88343:6;-1:-1:-1;;;;;88311:39:30;-1:-1:-1;;;;;88311:39:30;;;;;;;;;;;;;;;;;;;;;;88307:168;;;-1:-1:-1;;;;88378:61:30;-1:-1:-1;14150:1:30;;-1:-1:-1;88370:90:30;;-1:-1:-1;;;;;;88370:90:30;88307:168;80260:20;;88493:58;;;;:33;;;:58;;;;;;;;88489:187;;;-1:-1:-1;;;;88579:61:30;-1:-1:-1;14150:1:30;;-1:-1:-1;88571:90:30;;-1:-1:-1;;;;;;88571:90:30;88489:187;87881:805;;87806:3304;;;1108:1:29;88696:17:30;:69;88692:2418;;-1:-1:-1;;;;;88785:39:30;;;;;;:31;;;:39;;;;;;;;88781:140;;;-1:-1:-1;;88871:34:30;;3760:10:29;;-1:-1:-1;;;;88871:34:30;;;;;-1:-1:-1;88844:62:30;;-1:-1:-1;;88844:62:30;88781:140;89094:22;89134:46;89152:10;89164:6;89172:7;89134:46;;;:::i;:::-;89130:147;;;-1:-1:-1;;89227:34:30;;3760:10:29;;-1:-1:-1;;;;89227:34:30;;;;;-1:-1:-1;89200:62:30;;-1:-1:-1;;;89200:62:30;89130:147;80260:20;;89295:58;;;;:33;;;:58;;;;;;;;89291:159;;;-1:-1:-1;;89400:34:30;;3760:10:29;;-1:-1:-1;;;;89400:34:30;;;;;-1:-1:-1;89373:62:30;;-1:-1:-1;;;89373:62:30;89291:159;-1:-1:-1;;;;89472:63:30;-1:-1:-1;14150:1:30;;-1:-1:-1;89464:92:30;;-1:-1:-1;;;;;89464:92:30;88692:2418;1243:1:29;89577:17:30;:70;89573:1537;;-1:-1:-1;;;;;89765:24:30;;89663:49;89765:24;;;89715:31;;;89765:24;;;;;;;;;;;89761:125;;;-1:-1:-1;;89836:34:30;;3760:10:29;;-1:-1:-1;;;;89836:34:30;;;;;-1:-1:-1;89809:62:30;;-1:-1:-1;;;89809:62:30;89761:125;-1:-1:-1;;;;;89904:22:30;;;;;;;;;;;;;;;;89900:123;;;-1:-1:-1;;89973:34:30;;3760:10:29;;-1:-1:-1;;;;89973:34:30;;;;;-1:-1:-1;89946:62:30;;-1:-1:-1;;;89946:62:30;89900:123;90196:22;90235:46;90253:10;90265:6;90273:7;90235:46;;;:::i;:::-;90232:146;;;-1:-1:-1;;90328:34:30;;3760:10:29;;-1:-1:-1;;;;90328:34:30;;;;;-1:-1:-1;90301:62:30;;-1:-1:-1;;;;90301:62:30;90232:146;80260:20;;90392:50;90599:46;;;90445:33;;;90599:46;;;;;;;;;90575:6;;90599:46;;90595:147;;;-1:-1:-1;;90692:34:30;;3760:10:29;;-1:-1:-1;;;;90692:34:30;;;;;-1:-1:-1;90665:62:30;;-1:-1:-1;;;;;;90665:62:30;90595:147;-1:-1:-1;80260:20:30;;90850:46;;;;;;;;;;;;90828:4;;90850:46;;90846:147;;;-1:-1:-1;;90943:34:30;;3760:10:29;;-1:-1:-1;;;;90943:34:30;;;;;-1:-1:-1;90916:62:30;;-1:-1:-1;;;;;;90916:62:30;90846:147;-1:-1:-1;;;;91015:63:30;-1:-1:-1;14150:1:30;;-1:-1:-1;91007:92:30;;-1:-1:-1;;;;;;;;91007:92:30;89573:1537;-1:-1:-1;;91147:34:30;;3760:10:29;;-1:-1:-1;;;91147:34:30;;;;;;-1:-1:-1;84206:6983:30;-1:-1:-1;;;;;;;;;84206:6983:30:o;91368:182::-;91489:13;91483:4;91476:27;91529:4;91523;91516:18;63403:434:17;63693:31;63747:10;:73;63758:61;63780:7;63789:9;63800:5;63807:2;63811:7;-1:-1:-1;;;;;64490:20:17;;;64402:11;64490:20;;;:13;:20;;;;;;;;;;64441:70;;;;;31518:34:32;;;;31568:18;;;31561:34;;;;31631:15;;;;31611:18;;;31604:43;31663:18;;;31656:34;;;;31706:19;;;31699:35;31750:19;;;;31743:35;;;;64441:70:17;;;;;;;;;;31429:19:32;;64441:70:17;;;64431:81;;;;;;64271:248;63758:61;63747:73;;;;;;;;;;;:83;63821:8;-1:-1:-1;;;;;63747:83:17;-1:-1:-1;;;;;63747:83:17;;;;;;;;;;;;63736:94;;63403:434;;;;;;;;;:::o;71087:685::-;71449:316;701:3:14;71532:5:17;71551:2;71567:12;71593:5;71612:10;71636:5;71655:14;71683:12;;71709:14;71737:18;71449:38;:316::i;95502:501:30:-;95645:17;95674;95720:73;95738:6;95746:46;95772:10;95784:7;98120:20;98175:24;;;98219:4;98212:21;98285:4;98269:21;;98266:1;98262:29;;98002:304;95720:73;-1:-1:-1;95701:92:30;-1:-1:-1;95803:29:30;;;;95828:4;95821:11;;;;;95803:29;95870:64;95888:6;95896:37;95922:10;98709:20;98764:24;;;98814:33;98808:4;98801:47;98893:4;98877:21;;;98631:283;95870:64;95842:92;;-1:-1:-1;95842:92:30;-1:-1:-1;95842:92:30;95959:37;;;;;95988:3;95975:9;:16;;95995:1;95975:21;95944:52;95502:501;-1:-1:-1;;;;;95502:501:30:o;79264:653:17:-;79586:34;79646:264;79679:12;;79705:16;972:2:14;79765:5:17;79784:2;79800:5;79819:4;79837:10;79861:7;79882:18;79646:19;:264::i;70579:864:30:-;70799:11;70883:9;70979:31;;;70753:43;71043:19;70799:11;71043:17;:19::i;:::-;71020:42;-1:-1:-1;71072:15:30;;71097:340;71121:12;71117:1;:16;71097:340;;;71160:16;:10;71174:1;71160:13;:16::i;:::-;71150:26;-1:-1:-1;71195:21:30;:8;71150:26;71195:12;:21::i;:::-;71191:176;;;71289:7;-1:-1:-1;;;;;71241:56:30;71270:17;-1:-1:-1;;;;;71241:56:30;71260:8;71241:56;;;;;;;;;;;;-1:-1:-1;;;;;71315:30:30;;;;;;;;;;;;;:37;;-1:-1:-1;;71315:37:30;71348:4;71315:37;;;71191:176;71409:3;;71097:340;;;;70743:700;;;;;70579:864;;;;:::o;72482:875::-;72702:32;;;;;72788:30;;72886:33;;;72656:43;72952:19;72702:32;72952:17;:19::i;:::-;72929:42;-1:-1:-1;72981:16:30;;73007:344;73031:12;73027:1;:16;73007:344;;;73071:16;:10;73085:1;73071:13;:16::i;:::-;73060:27;-1:-1:-1;73105:22:30;:8;73060:27;73105:12;:22::i;:::-;73101:180;;;73201:8;73182:17;-1:-1:-1;;;;;73152:58:30;73172:8;73152:58;;;;;;;;;;;;73228:31;;;;;;;;;;;:38;;-1:-1:-1;;73228:38:30;73262:4;73228:38;;;73101:180;73323:3;;73007:344;;8428:156:26;8501:4;8524:53;8532:3;-1:-1:-1;;;;;8552:23:26;;8524:7;:53::i;79280:192:30:-;-1:-1:-1;;;;;79365:14:30;;;;;;:10;:14;;;;;;-1:-1:-1;;;;;79365:14:30;79351:10;:28;79347:119;;79402:53;;-1:-1:-1;;;79402:53:30;;;;;;;;;;;74659:610:17;74932:10;74914:15;:28;74910:115;;;74965:49;;-1:-1:-1;;;74965:49:17;;;;;;;;;;;74910:115;75056:12;75039:14;:29;75035:118;;;75091:51;;-1:-1:-1;;;75091:51:17;;;;;;;;;;;75035:118;75163:38;75188:5;75195;75163:24;:38::i;:::-;75211:51;75234:6;75242:12;;75256:5;75211:22;:51::i;80852:611:30:-;81058:12;81083:15;81100:26;81130:79;81148:27;81177:5;81184:10;81196:4;81202:2;81206;81130:17;:79::i;:::-;81082:127;;-1:-1:-1;81082:127:30;-1:-1:-1;81223:41:30;;;;;:77;;;81291:9;81268:19;:32;;;81223:77;81219:238;;;-1:-1:-1;;;;;;81326:29:30;;;;;-1:-1:-1;81219:238:30;;;81393:53;;-1:-1:-1;;;81393:53:30;;;;;;;;;;;81219:238;81072:391;;80852:611;;;;;;;;:::o;72891:869:17:-;73274:14;73291:255;73338:9;73361:5;73381:2;73398:12;73425:5;73444;73464:10;73489:14;73518:18;73291:33;:255::i;:::-;73274:272;;73565:188;73595:5;73614:10;73638:14;73666:12;73692:5;73711:6;73731:12;;73565:16;:188::i;:::-;73264:496;72891:869;;;;;;;;;;;;:::o;5375:109:26:-;5431:16;5466:3;:11;;5459:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5375:109;;;:::o;92260:888:30:-;-1:-1:-1;;;;;92489:38:30;;92427:59;92489:38;;;:26;:38;;;;;92542:49;;;;92538:154;;;92614:67;;-1:-1:-1;;;92614:67:30;;;;;;;;;;;92538:154;92706:62;;;;;;;92702:256;;;-1:-1:-1;;;;;;;92788:37:30;;;92784:164;;92852:81;;-1:-1:-1;;;92852:81:30;;;;;;;;;;;92784:164;92985:31;;;;;-1:-1:-1;;;;;92985:31:30;92973:44;;;;:11;:44;;;;;;;;-1:-1:-1;;;;;92973:78:30;;;;:66;;:78;;;;;;;;92968:174;;93074:57;;-1:-1:-1;;;93074:57:30;;;;;;;;;;;99488:560;99566:13;99581:12;99628:349;;;99714:10;99708:4;99701:24;99666:6;99674:8;99836:4;99830;99824;99818;99803:13;99796:5;99785:56;99777:4;99759:16;99756:26;99749:34;99745:97;99742:188;;;99881:4;99875:11;99865:21;;99628:349;;;:::o;99742:188::-;-1:-1:-1;99628:349:30;99959:4;;-1:-1:-1;99628:349:30:o;:::-;100008:24;100019:12;100008:24;:::i;:::-;99990:42;;;;99488:560;;;:::o;100830:838::-;100957:12;100971;101018:560;;;101075:8;101085;101129:4;101123:11;101173:4;101168:3;101164:14;101158:4;101151:28;101208:10;101203:3;101196:23;101259:5;101253:3;101247:4;101243:14;101236:29;101305:8;101299:3;101293:4;101289:14;101282:32;101435:4;101429;101423;101416;101411:3;101407:14;101392:13;101385:5;101374:66;101366:4;101348:16;101345:26;101338:34;101334:107;101331:200;;;101482:4;101476:11;101464:23;;101508:5;;;101331:200;;101560:4;101548:16;;101018:560;;;;;;;:::o;:::-;101611:41;101644:7;101638:4;101624:12;101611:41;:::i;:::-;101591:61;;;;100830:838;;;;;;:::o;81104:1752:17:-;81448:34;-1:-1:-1;;;;;81498:33:17;;:53;81494:129;;;81574:38;;-1:-1:-1;;;81574:38:17;;;;;;;;;;;81494:129;81647:88;81669:15;81686:5;81693:9;81704:5;81711:2;81715:7;81724:10;81647:21;:88::i;:::-;81750:17;;81633:102;;-1:-1:-1;81750:37:17;:17;81746:1104;;81807:18;;;;;-1:-1:-1;;;;;81807:18:17;;:23;81803:809;;81850:512;81894:387;81953:9;81988:5;82020:2;82049:33;;82108:5;82139:4;81894:387;;;82207:7;82241:18;81894:33;:387::i;:::-;82304:12;;82339:5;81850:22;:512::i;:::-;82381:63;;82462:35;;82381:63;82410:33;;-1:-1:-1;;;;;82381:63:17;;;;;;82462:35;;;;;;-1:-1:-1;;;82462:35:17;;;;;;;82523:74;;17048:25:32;;;82551:10:17;;-1:-1:-1;;;;;82523:74:17;;;82535:7;;82523:74;;17036:2:32;17021:18;82523:74:17;;;;;;;81803:809;82648:22;;-1:-1:-1;;;82648:22:17;;;;82630:15;:40;82626:135;;;82697:49;;-1:-1:-1;;;82697:49:17;;;;;;;;;;;5724:123:26;5794:4;5817:23;5822:3;5834:5;5817:4;:23::i;6015:129::-;6088:4;6111:26;6119:3;6131:5;6111:7;:26::i;56184:470:17:-;56276:12;;56333:66;56320:79;;56316:244;;;-1:-1:-1;56532:4:17;;-1:-1:-1;56546:1:17;56524:25;;56316:244;56579:26;;;;;;;;;;;;30477:25:32;;;30550:4;30538:17;;30518:18;;;30511:45;;;;30572:18;;;30565:34;;;30615:18;;;30608:34;;;56579:26:17;;30449:19:32;;56579:26:17;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;56579:26:17;;-1:-1:-1;;56579:26:17;;-1:-1:-1;;;;;56626:20:17;;;;-1:-1:-1;56579:26:17;-1:-1:-1;;56184:470:17;;;;;;;;:::o;54405:361::-;54520:6;-1:-1:-1;;;;;54520:18:17;;54542:1;54520:23;54517:104;;54566:44;;-1:-1:-1;;;54566:44:17;;;;;;;;;;;54517:104;54636:46;54658:6;54666:4;54672:9;;54636:21;:46::i;:::-;54631:129;;54705:44;;-1:-1:-1;;;54705:44:17;;;;;;;;;;;55211:315;55295:12;;1118:66:14;55371:19:17;;55442:2;55434:3;55428:9;;;55414:30;55479;55493:6;55414:30;55504:1;55371:19;55479:13;:30::i;:::-;55459:50;;;;-1:-1:-1;55211:315:17;-1:-1:-1;;;;;;55211:315:17:o;2035:406:26:-;2098:4;4154:21;;;:14;;;:21;;;;;;2114:321;;-1:-1:-1;2156:23:26;;;;;;;;:11;:23;;;;;;;;;;;;;2338:18;;2314:21;;;:14;;;:21;;;;;;:42;;;;2370:11;;2114:321;-1:-1:-1;2419:5:26;2412:12;;97254:335:30;97334:17;97353;97394:18;97407:4;97394:12;:18;;:::i;:::-;97382:30;-1:-1:-1;97382:30:30;-1:-1:-1;;;;;97503:47:30;;14093:4;97503:47;;:79;;;97576:6;-1:-1:-1;;;;;97554:28:30;:18;-1:-1:-1;;;;;97554:28:30;;97503:79;97488:94;;97372:217;97254:335;;;;;:::o;8911:115:26:-;8974:7;9000:19;9008:3;4350:18;;4268:107;9368:156;9442:7;9492:22;9496:3;9508:5;9492:3;:22::i;2609:1368::-;2675:4;2804:21;;;:14;;;:21;;;;;;2840:13;;2836:1135;;3207:18;3228:12;3239:1;3228:8;:12;:::i;:::-;3274:18;;3207:33;;-1:-1:-1;3254:17:26;;3274:22;;3295:1;;3274:22;:::i;:::-;3254:42;;3329:9;3315:10;:23;3311:378;;3358:17;3378:3;:11;;3390:9;3378:22;;;;;;;;:::i;:::-;;;;;;;;;3358:42;;3525:9;3499:3;:11;;3511:10;3499:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;3638:25;;;:14;;;:25;;;;;:36;;;3311:378;3767:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;3870:3;:14;;:21;3885:5;3870:21;;;;;;;;;;;3863:28;;;3913:4;3906:11;;;;;;;2836:1135;3955:5;3948:12;;;;;88007:877:17;-1:-1:-1;;;;;88425:20:17;;88314:14;88425:20;;;:13;:20;;;;;;88477:400;88511:352;88581:9;88612:5;88640:2;88665:6;88694:5;88722:10;88755:14;88792:18;88425:20;88511:48;:352::i;57105:1792::-;57243:12;57290:1496;;;57376:8;57420:4;57414:11;-1:-1:-1;;;57515:3:17;57508:26;57642:5;57635:4;57630:3;57626:14;57619:29;57762:4;57755;57750:3;57746:14;57739:28;57855:16;57848:4;57843:3;57839:14;57832:40;57995:16;57977;57970:4;57965:3;57961:14;57948:64;58194:4;58190:9;58183:4;58165:16;58161:27;58157:43;58151:4;58147:54;58286:10;58281:3;58277:20;58271:4;58264:34;58572:4;58566;58554:10;58549:3;58540:7;58533:5;58522:55;58514:4;58496:16;58493:26;58486:34;58482:96;58479:293;;;-1:-1:-1;;;58707:4:17;58701:11;58698:30;58686:42;;58749:5;;;;58479:293;;;57290:1496;;;;;;:::o;:::-;58810:71;58864:16;58846;58840:4;58832:6;58810:71;:::i;4717:118:26:-;4784:7;4810:3;:11;;4822:5;4810:18;;;;;;;;:::i;:::-;;;;;;;;;4803:25;;4717:118;;;;:::o;3619:691:19:-;3995:298;;;;;;28283:25:32;;;28324:18;;;28317:34;;;-1:-1:-1;;;;;28448:15:32;;28428:18;;;28421:43;28480:18;;;28473:34;;;28523:19;;;28516:35;;;28567:19;;;28560:35;;;4180:10:19;28611:19:32;;;28604:44;28664:19;;;28657:35;;;28708:19;;;28701:35;;;28752:19;;;28745:35;;;3941:12:19;;28255:19:32;;3995:298:19;27884:902:32;14:186;82:20;;-1:-1:-1;;;;;131:44:32;;121:55;;111:83;;190:1;187;180:12;205:367;268:8;278:6;332:3;325:4;317:6;313:17;309:27;299:55;;350:1;347;340:12;299:55;-1:-1:-1;373:20:32;;416:18;405:30;;402:50;;;448:1;445;438:12;402:50;485:4;477:6;473:17;461:29;;545:3;538:4;528:6;525:1;521:14;513:6;509:27;505:38;502:47;499:67;;;562:1;559;552:12;499:67;205:367;;;;;:::o;577:511::-;672:6;680;688;741:2;729:9;720:7;716:23;712:32;709:52;;;757:1;754;747:12;709:52;780:29;799:9;780:29;:::i;:::-;770:39;;860:2;849:9;845:18;832:32;887:18;879:6;876:30;873:50;;;919:1;916;909:12;873:50;958:70;1020:7;1011:6;1000:9;996:22;958:70;:::i;:::-;577:511;;1047:8;;-1:-1:-1;932:96:32;;-1:-1:-1;;;;577:511:32:o;1093:286::-;1151:6;1204:2;1192:9;1183:7;1179:23;1175:32;1172:52;;;1220:1;1217;1210:12;1172:52;1246:23;;-1:-1:-1;;;;;;1298:32:32;;1288:43;;1278:71;;1345:1;1342;1335:12;1576:196;1644:20;;-1:-1:-1;;;;;1693:54:32;;1683:65;;1673:93;;1762:1;1759;1752:12;1777:260;1845:6;1853;1906:2;1894:9;1885:7;1881:23;1877:32;1874:52;;;1922:1;1919;1912:12;1874:52;1945:29;1964:9;1945:29;:::i;:::-;1935:39;;1993:38;2027:2;2016:9;2012:18;1993:38;:::i;:::-;1983:48;;1777:260;;;;;:::o;2042:186::-;2101:6;2154:2;2142:9;2133:7;2129:23;2125:32;2122:52;;;2170:1;2167;2160:12;2122:52;2193:29;2212:9;2193:29;:::i;2233:347::-;2284:8;2294:6;2348:3;2341:4;2333:6;2329:17;2325:27;2315:55;;2366:1;2363;2356:12;2315:55;-1:-1:-1;2389:20:32;;2432:18;2421:30;;2418:50;;;2464:1;2461;2454:12;2418:50;2501:4;2493:6;2489:17;2477:29;;2553:3;2546:4;2537:6;2529;2525:19;2521:30;2518:39;2515:59;;;2570:1;2567;2560:12;2585:977;2727:6;2735;2743;2751;2759;2767;2775;2783;2791;2799;2852:3;2840:9;2831:7;2827:23;2823:33;2820:53;;;2869:1;2866;2859:12;2820:53;2892:29;2911:9;2892:29;:::i;:::-;2882:39;;2968:2;2957:9;2953:18;2940:32;2930:42;;3019:2;3008:9;3004:18;2991:32;2981:42;;3070:2;3059:9;3055:18;3042:32;3032:42;;3121:3;3110:9;3106:19;3093:33;3083:43;;3145:39;3179:3;3168:9;3164:19;3145:39;:::i;:::-;3135:49;;3203:39;3237:3;3226:9;3222:19;3203:39;:::i;:::-;3193:49;;3289:3;3278:9;3274:19;3261:33;3251:43;;3345:3;3334:9;3330:19;3317:33;3373:18;3365:6;3362:30;3359:50;;;3405:1;3402;3395:12;3359:50;3444:58;3494:7;3485:6;3474:9;3470:22;3444:58;:::i;:::-;3418:84;;3521:8;3511:18;;;3548:8;3538:18;;;2585:977;;;;;;;;;;;;;:::o;3567:1121::-;3727:6;3735;3743;3751;3759;3767;3775;3783;3791;3799;3807:7;3816;3870:3;3858:9;3849:7;3845:23;3841:33;3838:53;;;3887:1;3884;3877:12;3838:53;3910:29;3929:9;3910:29;:::i;:::-;3900:39;;3986:2;3975:9;3971:18;3958:32;3948:42;;4037:2;4026:9;4022:18;4009:32;3999:42;;4088:2;4077:9;4073:18;4060:32;4050:42;;4139:3;4128:9;4124:19;4111:33;4101:43;;4163:39;4197:3;4186:9;4182:19;4163:39;:::i;:::-;4153:49;;4221:39;4255:3;4244:9;4240:19;4221:39;:::i;:::-;4211:49;;4307:3;4296:9;4292:19;4279:33;4269:43;;4359:3;4348:9;4344:19;4331:33;4321:43;;4411:3;4400:9;4396:19;4383:33;4373:43;;4466:18;4459:3;4448:9;4444:19;4431:33;4428:57;4425:77;;;4498:1;4495;4488:12;4425:77;4539:85;4616:7;4608:3;4597:9;4593:19;4580:33;4569:9;4565:49;4539:85;:::i;:::-;4644:9;4633:20;;4673:9;4662:20;;;;3567:1121;;;;;;;;;;;;;;:::o;4693:186::-;4752:6;4805:2;4793:9;4784:7;4780:23;4776:32;4773:52;;;4821:1;4818;4811:12;4773:52;4844:29;4863:9;4844:29;:::i;4884:681::-;5055:2;5107:21;;;5177:13;;5080:18;;;5199:22;;;5026:4;;5055:2;5278:15;;;;5252:2;5237:18;;;5026:4;5321:218;5335:6;5332:1;5329:13;5321:218;;;5400:13;;-1:-1:-1;;;;;5396:62:32;5384:75;;5514:15;;;;5479:12;;;;5357:1;5350:9;5321:218;;;-1:-1:-1;5556:3:32;;4884:681;-1:-1:-1;;;;;;4884:681:32:o;5570:472::-;5665:6;5673;5681;5689;5697;5750:3;5738:9;5729:7;5725:23;5721:33;5718:53;;;5767:1;5764;5757:12;5718:53;5790:29;5809:9;5790:29;:::i;:::-;5780:39;;5838:38;5872:2;5861:9;5857:18;5838:38;:::i;:::-;5828:48;;5895:38;5929:2;5918:9;5914:18;5895:38;:::i;:::-;5570:472;;;;-1:-1:-1;5885:48:32;;5980:2;5965:18;;5952:32;;-1:-1:-1;6031:3:32;6016:19;6003:33;;5570:472;-1:-1:-1;;5570:472:32:o;6047:180::-;6106:6;6159:2;6147:9;6138:7;6134:23;6130:32;6127:52;;;6175:1;6172;6165:12;6127:52;-1:-1:-1;6198:23:32;;6047:180;-1:-1:-1;6047:180:32:o;6232:632::-;6403:2;6455:21;;;6525:13;;6428:18;;;6547:22;;;6374:4;;6403:2;6626:15;;;;6600:2;6585:18;;;6374:4;6669:169;6683:6;6680:1;6677:13;6669:169;;;6744:13;;6732:26;;6813:15;;;;6778:12;;;;6705:1;6698:9;6669:169;;6869:254;6937:6;6945;6998:2;6986:9;6977:7;6973:23;6969:32;6966:52;;;7014:1;7011;7004:12;6966:52;7037:29;7056:9;7037:29;:::i;:::-;7027:39;7113:2;7098:18;;;;7085:32;;-1:-1:-1;;;6869:254:32:o;7349:334::-;7426:6;7434;7442;7495:2;7483:9;7474:7;7470:23;7466:32;7463:52;;;7511:1;7508;7501:12;7463:52;7534:29;7553:9;7534:29;:::i;:::-;7524:39;;7582:38;7616:2;7605:9;7601:18;7582:38;:::i;:::-;7572:48;;7639:38;7673:2;7662:9;7658:18;7639:38;:::i;:::-;7629:48;;7349:334;;;;;:::o;7688:322::-;7765:6;7773;7781;7834:2;7822:9;7813:7;7809:23;7805:32;7802:52;;;7850:1;7847;7840:12;7802:52;7873:29;7892:9;7873:29;:::i;:::-;7863:39;7949:2;7934:18;;7921:32;;-1:-1:-1;8000:2:32;7985:18;;;7972:32;;7688:322;-1:-1:-1;;;7688:322:32:o;8274:118::-;8360:5;8353:13;8346:21;8339:5;8336:32;8326:60;;8382:1;8379;8372:12;8397:750;8481:6;8489;8497;8505;8513;8566:3;8554:9;8545:7;8541:23;8537:33;8534:53;;;8583:1;8580;8573:12;8534:53;8606:29;8625:9;8606:29;:::i;:::-;8596:39;;8685:2;8674:9;8670:18;8657:32;8729:4;8722:5;8718:16;8711:5;8708:27;8698:55;;8749:1;8746;8739:12;8698:55;8772:5;-1:-1:-1;8829:2:32;8814:18;;8801:32;8842:30;8801:32;8842:30;:::i;:::-;8891:7;-1:-1:-1;8950:2:32;8935:18;;8922:32;8963:30;8922:32;8963:30;:::i;:::-;9012:7;-1:-1:-1;9071:3:32;9056:19;;9043:33;9085:30;9043:33;9085:30;:::i;:::-;9134:7;9124:17;;;8397:750;;;;;;;;:::o;9152:164::-;9221:5;9266:2;9257:6;9252:3;9248:16;9244:25;9241:45;;;9282:1;9279;9272:12;9241:45;-1:-1:-1;9304:6:32;9152:164;-1:-1:-1;9152:164:32:o;9321:167::-;9388:20;;9448:14;9437:26;;9427:37;;9417:65;;9478:1;9475;9468:12;9493:1130;9679:6;9687;9695;9703;9711;9719;9727;9735;9743;9751;9759:7;9813:3;9801:9;9792:7;9788:23;9784:33;9781:53;;;9830:1;9827;9820:12;9781:53;9870:9;9857:23;9903:18;9895:6;9892:30;9889:50;;;9935:1;9932;9925:12;9889:50;9974:58;10024:7;10015:6;10004:9;10000:22;9974:58;:::i;:::-;10051:8;;-1:-1:-1;9948:84:32;-1:-1:-1;10105:72:32;;-1:-1:-1;10169:7:32;10164:2;10149:18;;10105:72;:::i;:::-;10095:82;;10196:39;10230:3;10219:9;10215:19;10196:39;:::i;:::-;10186:49;;10282:3;10271:9;10267:19;10254:33;10244:43;;10306:39;10340:3;10329:9;10325:19;10306:39;:::i;:::-;10296:49;;10364:39;10398:3;10387:9;10383:19;10364:39;:::i;:::-;10354:49;;10450:3;10439:9;10435:19;10422:33;10412:43;;10474:38;10507:3;10496:9;10492:19;10474:38;:::i;:::-;10464:48;;10559:3;10548:9;10544:19;10531:33;10521:43;;10612:3;10601:9;10597:19;10584:33;10573:44;;9493:1130;;;;;;;;;;;;;;:::o;10891:260::-;10959:6;10967;11020:2;11008:9;10999:7;10995:23;10991:32;10988:52;;;11036:1;11033;11026:12;10988:52;11059:29;11078:9;11059:29;:::i;11156:472::-;11251:6;11259;11267;11275;11283;11336:3;11324:9;11315:7;11311:23;11307:33;11304:53;;;11353:1;11350;11343:12;11304:53;11376:29;11395:9;11376:29;:::i;:::-;11366:39;;11424:38;11458:2;11447:9;11443:18;11424:38;:::i;:::-;11414:48;;11509:2;11498:9;11494:18;11481:32;11471:42;;11532:38;11566:2;11555:9;11551:18;11532:38;:::i;:::-;11156:472;;;;-1:-1:-1;11156:472:32;;11617:3;11602:19;11589:33;;11156:472;-1:-1:-1;;11156:472:32:o;12402:1050::-;12553:6;12561;12569;12577;12585;12593;12601;12609;12617;12625;12633:7;12687:3;12675:9;12666:7;12662:23;12658:33;12655:53;;;12704:1;12701;12694:12;12655:53;12727:29;12746:9;12727:29;:::i;:::-;12717:39;;12803:2;12792:9;12788:18;12775:32;12765:42;;12854:2;12843:9;12839:18;12826:32;12816:42;;12905:2;12894:9;12890:18;12877:32;12867:42;;12928:39;12962:3;12951:9;12947:19;12928:39;:::i;:::-;12918:49;;12986:39;13020:3;13009:9;13005:19;12986:39;:::i;:::-;12976:49;;13072:3;13061:9;13057:19;13044:33;13034:43;;13124:3;13113:9;13109:19;13096:33;13086:43;;13176:3;13165:9;13161:19;13148:33;13138:43;;13232:3;13221:9;13217:19;13204:33;13260:18;13252:6;13249:30;13246:50;;;13292:1;13289;13282:12;13246:50;13332:58;13382:7;13373:6;13362:9;13358:22;13332:58;:::i;:::-;13305:85;;13409:8;13399:18;;;13437:9;13426:20;;;12402:1050;;;;;;;;;;;;;;:::o;13457:206::-;13525:20;;-1:-1:-1;;;;;13574:64:32;;13564:75;;13554:103;;13653:1;13650;13643:12;13668:1064;13817:6;13825;13833;13841;13849;13857;13865;13873;13881;13889;13897:7;13951:3;13939:9;13930:7;13926:23;13922:33;13919:53;;;13968:1;13965;13958:12;13919:53;14004:9;13991:23;13981:33;;14033:38;14067:2;14056:9;14052:18;14033:38;:::i;:::-;14023:48;;14118:2;14107:9;14103:18;14090:32;14080:42;;14169:2;14158:9;14154:18;14141:32;14131:42;;14192:39;14226:3;14215:9;14211:19;14192:39;:::i;:::-;14182:49;;14250:39;14284:3;14273:9;14269:19;14250:39;:::i;:::-;14240:49;;14308:38;14341:3;14330:9;14326:19;14308:38;:::i;:::-;14298:48;;14365:38;14398:3;14387:9;14383:19;14365:38;:::i;:::-;14355:48;;14422:39;14456:3;14445:9;14441:19;14422:39;:::i;:::-;14412:49;;14512:3;14501:9;14497:19;14484:33;14540:18;14532:6;14529:30;14526:50;;;14572:1;14569;14562:12;14737:254;14805:6;14813;14866:2;14854:9;14845:7;14841:23;14837:32;14834:52;;;14882:1;14879;14872:12;14834:52;14905:29;14924:9;14905:29;:::i;14996:839::-;15120:6;15128;15136;15144;15152;15160;15168;15176;15229:3;15217:9;15208:7;15204:23;15200:33;15197:53;;;15246:1;15243;15236:12;15197:53;15269:29;15288:9;15269:29;:::i;:::-;15259:39;;15345:2;15334:9;15330:18;15317:32;15307:42;;15396:2;15385:9;15381:18;15368:32;15358:42;;15447:2;15436:9;15432:18;15419:32;15409:42;;15470:39;15504:3;15493:9;15489:19;15470:39;:::i;:::-;15460:49;;15528:39;15562:3;15551:9;15547:19;15528:39;:::i;:::-;15518:49;;15618:3;15607:9;15603:19;15590:33;15646:18;15638:6;15635:30;15632:50;;;15678:1;15675;15668:12;15632:50;15717:58;15767:7;15758:6;15747:9;15743:22;15717:58;:::i;:::-;14996:839;;;;-1:-1:-1;14996:839:32;;-1:-1:-1;14996:839:32;;;;;;15794:8;-1:-1:-1;;;14996:839:32:o;15840:541::-;15944:6;15952;15960;15968;15976;15984;16037:3;16025:9;16016:7;16012:23;16008:33;16005:53;;;16054:1;16051;16044:12;16005:53;16077:29;16096:9;16077:29;:::i;:::-;16067:39;;16125:38;16159:2;16148:9;16144:18;16125:38;:::i;:::-;16115:48;;16210:2;16199:9;16195:18;16182:32;16172:42;;16233:38;16267:2;16256:9;16252:18;16233:38;:::i;:::-;16223:48;;16318:3;16307:9;16303:19;16290:33;16280:43;;16370:3;16359:9;16355:19;16342:33;16332:43;;15840:541;;;;;;;;:::o;16386:511::-;16481:6;16489;16497;16550:2;16538:9;16529:7;16525:23;16521:32;16518:52;;;16566:1;16563;16556:12;16518:52;16589:29;16608:9;16589:29;:::i;17084:403::-;17170:6;17178;17186;17194;17247:3;17235:9;17226:7;17222:23;17218:33;17215:53;;;17264:1;17261;17254:12;17215:53;17287:29;17306:9;17287:29;:::i;:::-;17277:39;;17335:38;17369:2;17358:9;17354:18;17335:38;:::i;:::-;17325:48;;17392:38;17426:2;17415:9;17411:18;17392:38;:::i;:::-;17084:403;;;;-1:-1:-1;17382:48:32;;17477:2;17462:18;17449:32;;-1:-1:-1;;17084:403:32:o;17908:977::-;18050:6;18058;18066;18074;18082;18090;18098;18106;18114;18122;18175:3;18163:9;18154:7;18150:23;18146:33;18143:53;;;18192:1;18189;18182:12;18143:53;18215:29;18234:9;18215:29;:::i;:::-;18205:39;;18291:2;18280:9;18276:18;18263:32;18253:42;;18342:2;18331:9;18327:18;18314:32;18304:42;;18393:2;18382:9;18378:18;18365:32;18355:42;;18416:39;18450:3;18439:9;18435:19;18416:39;:::i;:::-;18406:49;;18474:39;18508:3;18497:9;18493:19;18474:39;:::i;:::-;18464:49;;18560:3;18549:9;18545:19;18532:33;18522:43;;18612:3;18601:9;18597:19;18584:33;18574:43;;18668:3;18657:9;18653:19;18640:33;18696:18;18688:6;18685:30;18682:50;;;18728:1;18725;18718:12;18890:410;18961:6;18969;19022:2;19010:9;19001:7;18997:23;18993:32;18990:52;;;19038:1;19035;19028:12;18990:52;19078:9;19065:23;19111:18;19103:6;19100:30;19097:50;;;19143:1;19140;19133:12;19097:50;19182:58;19232:7;19223:6;19212:9;19208:22;19182:58;:::i;:::-;19259:8;;19156:84;;-1:-1:-1;18890:410:32;-1:-1:-1;;;;18890:410:32:o;20011:545::-;20114:6;20122;20130;20138;20146;20154;20207:3;20195:9;20186:7;20182:23;20178:33;20175:53;;;20224:1;20221;20214:12;20175:53;20260:9;20247:23;20237:33;;20289:38;20323:2;20312:9;20308:18;20289:38;:::i;:::-;20279:48;;20374:2;20363:9;20359:18;20346:32;20336:42;;20397:38;20431:2;20420:9;20416:18;20397:38;:::i;:::-;20387:48;;20454:39;20488:3;20477:9;20473:19;20454:39;:::i;:::-;20444:49;;20512:38;20545:3;20534:9;20530:19;20512:38;:::i;:::-;20502:48;;20011:545;;;;;;;;:::o;20561:260::-;20629:6;20637;20690:2;20678:9;20669:7;20665:23;20661:32;20658:52;;;20706:1;20703;20696:12;20658:52;20729:29;20748:9;20729:29;:::i;:::-;20719:39;;20777:38;20811:2;20800:9;20796:18;20777:38;:::i;20826:1059::-;21003:6;21011;21019;21027;21035;21043;21051;21059;21067;21075;21128:3;21116:9;21107:7;21103:23;21099:33;21096:53;;;21145:1;21142;21135:12;21096:53;21185:9;21172:23;21218:18;21210:6;21207:30;21204:50;;;21250:1;21247;21240:12;21204:50;21289:58;21339:7;21330:6;21319:9;21315:22;21289:58;:::i;:::-;21366:8;;-1:-1:-1;21263:84:32;-1:-1:-1;21420:72:32;;-1:-1:-1;21484:7:32;21479:2;21464:18;;21420:72;:::i;:::-;21410:82;;21511:39;21545:3;21534:9;21530:19;21511:39;:::i;:::-;21501:49;;21569:39;21603:3;21592:9;21588:19;21569:39;:::i;:::-;21559:49;;21627:39;21661:3;21650:9;21646:19;21627:39;:::i;:::-;21617:49;;21713:3;21702:9;21698:19;21685:33;21675:43;;21737:38;21770:3;21759:9;21755:19;21737:38;:::i;:::-;21727:48;;21822:3;21811:9;21807:19;21794:33;21784:43;;21874:3;21863:9;21859:19;21846:33;21836:43;;20826:1059;;;;;;;;;;;;;:::o;21890:908::-;22023:6;22031;22039;22047;22055;22063;22071;22079;22087;22140:3;22128:9;22119:7;22115:23;22111:33;22108:53;;;22157:1;22154;22147:12;22108:53;22180:29;22199:9;22180:29;:::i;:::-;22170:39;;22256:2;22245:9;22241:18;22228:32;22218:42;;22307:2;22296:9;22292:18;22279:32;22269:42;;22358:2;22347:9;22343:18;22330:32;22320:42;;22381:39;22415:3;22404:9;22400:19;22381:39;:::i;:::-;22371:49;;22439:39;22473:3;22462:9;22458:19;22439:39;:::i;:::-;22429:49;;22525:3;22514:9;22510:19;22497:33;22487:43;;22581:3;22570:9;22566:19;22553:33;22609:18;22601:6;22598:30;22595:50;;;22641:1;22638;22631:12;22595:50;22680:58;22730:7;22721:6;22710:9;22706:22;22680:58;:::i;:::-;22654:84;;22757:8;22747:18;;;22784:8;22774:18;;;21890:908;;;;;;;;;;;:::o;22803:328::-;22880:6;22888;22896;22949:2;22937:9;22928:7;22924:23;22920:32;22917:52;;;22965:1;22962;22955:12;22917:52;22988:29;23007:9;22988:29;:::i;:::-;22978:39;;23036:38;23070:2;23059:9;23055:18;23036:38;:::i;:::-;23026:48;;23121:2;23110:9;23106:18;23093:32;23083:42;;22803:328;;;;;:::o;23136:484::-;23216:6;23224;23232;23285:2;23273:9;23264:7;23260:23;23256:32;23253:52;;;23301:1;23298;23291:12;23253:52;23341:9;23328:23;23374:18;23366:6;23363:30;23360:50;;;23406:1;23403;23396:12;23360:50;23445:58;23495:7;23486:6;23475:9;23471:22;23445:58;:::i;:::-;23522:8;;-1:-1:-1;23419:84:32;-1:-1:-1;23576:38:32;;-1:-1:-1;23610:2:32;23595:18;;23576:38;:::i;23807:346::-;23874:6;23882;23935:2;23923:9;23914:7;23910:23;23906:32;23903:52;;;23951:1;23948;23941:12;23903:52;23974:29;23993:9;23974:29;:::i;:::-;23964:39;;24053:2;24042:9;24038:18;24025:32;24097:6;24090:5;24086:18;24079:5;24076:29;24066:57;;24119:1;24116;24109:12;24066:57;24142:5;24132:15;;;23807:346;;;;;:::o;24620:127::-;24681:10;24676:3;24672:20;24669:1;24662:31;24712:4;24709:1;24702:15;24736:4;24733:1;24726:15;24962:245;25029:6;25082:2;25070:9;25061:7;25057:23;25053:32;25050:52;;;25098:1;25095;25088:12;25050:52;25130:9;25124:16;25149:28;25171:5;25149:28;:::i;25212:390::-;25371:2;25360:9;25353:21;25410:6;25405:2;25394:9;25390:18;25383:34;25467:6;25459;25454:2;25443:9;25439:18;25426:48;25523:1;25494:22;;;25518:2;25490:31;;;25483:42;;;;25586:2;25565:15;;;-1:-1:-1;;25561:29:32;25546:45;25542:54;;25212:390;-1:-1:-1;25212:390:32:o;25607:250::-;25692:1;25702:113;25716:6;25713:1;25710:13;25702:113;;;25792:11;;;25786:18;25773:11;;;25766:39;25738:2;25731:10;25702:113;;;-1:-1:-1;;25849:1:32;25831:16;;25824:27;25607:250::o;25862:474::-;26051:3;26089:6;26083:13;26105:66;26164:6;26159:3;26152:4;26144:6;26140:17;26105:66;:::i;:::-;26193:16;;26246:6;26238;26193:16;26218:35;26310:1;26272:18;;26299:13;;;-1:-1:-1;26272:18:32;;25862:474;-1:-1:-1;;;25862:474:32:o;27592:287::-;27721:3;27759:6;27753:13;27775:66;27834:6;27829:3;27822:4;27814:6;27810:17;27775:66;:::i;:::-;27857:16;;;;;27592:287;-1:-1:-1;;27592:287:32:o;29193:217::-;29233:1;29259;29249:132;;29303:10;29298:3;29294:20;29291:1;29284:31;29338:4;29335:1;29328:15;29366:4;29363:1;29356:15;29249:132;-1:-1:-1;29395:9:32;;29193:217::o;31789:225::-;31856:9;;;31877:11;;;31874:134;;;31930:10;31925:3;31921:20;31918:1;31911:31;31965:4;31962:1;31955:15;31993:4;31990:1;31983:15;32019:127;32080:10;32075:3;32071:20;32068:1;32061:31;32111:4;32108:1;32101:15;32135:4;32132:1;32125:15
Swarm Source
ipfs://a90ba9bdaeca58f1ff72597bd40a48511cb4d6531d0ea891d978e9112f6daab5
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.