Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 25 from a total of 221 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Add Accounts To ... | 24657865 | 18 hrs ago | IN | 0 ETH | 0.0000032 | ||||
| Set Ruleset Of C... | 24649008 | 47 hrs ago | IN | 0 ETH | 0.00003254 | ||||
| Set Ruleset Of C... | 24649007 | 47 hrs ago | IN | 0 ETH | 0.00003366 | ||||
| Set Ruleset Of C... | 24648997 | 47 hrs ago | IN | 0 ETH | 0.00003334 | ||||
| Apply List To Co... | 24641337 | 3 days ago | IN | 0 ETH | 0.00009344 | ||||
| Add Accounts To ... | 24641140 | 3 days ago | IN | 0 ETH | 0.0002249 | ||||
| Create List Copy | 24641126 | 3 days ago | IN | 0 ETH | 0.0001442 | ||||
| Apply List To Co... | 24636006 | 3 days ago | IN | 0 ETH | 0.00012003 | ||||
| Apply List To Co... | 24636004 | 3 days ago | IN | 0 ETH | 0.00012008 | ||||
| Apply List To Co... | 24634735 | 3 days ago | IN | 0 ETH | 0.00001833 | ||||
| Apply List To Co... | 24634733 | 3 days ago | IN | 0 ETH | 0.00001905 | ||||
| Set Ruleset Of C... | 24631264 | 4 days ago | IN | 0 ETH | 0.00009204 | ||||
| Apply List To Co... | 24631241 | 4 days ago | IN | 0 ETH | 0.00012022 | ||||
| Create List Copy | 24631030 | 4 days ago | IN | 0 ETH | 0.00009183 | ||||
| Add Accounts To ... | 24621116 | 5 days ago | IN | 0 ETH | 0.00007689 | ||||
| Add Accounts To ... | 24620713 | 5 days ago | IN | 0 ETH | 0.00026129 | ||||
| Apply List To Co... | 24620703 | 5 days ago | IN | 0 ETH | 0.00013369 | ||||
| Create List | 24620686 | 5 days ago | IN | 0 ETH | 0.00012137 | ||||
| Apply List To Co... | 24612233 | 7 days ago | IN | 0 ETH | 0.00007007 | ||||
| Apply List To Co... | 24611995 | 7 days ago | IN | 0 ETH | 0.00011462 | ||||
| Add Accounts To ... | 24611987 | 7 days ago | IN | 0 ETH | 0.00024314 | ||||
| Create List | 24611977 | 7 days ago | IN | 0 ETH | 0.00011463 | ||||
| Add Accounts To ... | 24601435 | 8 days ago | IN | 0 ETH | 0.00000864 | ||||
| Apply List To Co... | 24601398 | 8 days ago | IN | 0 ETH | 0.0000029 | ||||
| Add Accounts To ... | 24601389 | 8 days ago | IN | 0 ETH | 0.00001336 |
Latest 2 internal transactions
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x6002601e | 22416280 | 314 days ago | Contract Creation | 0 ETH | |||
| 0x61028060 | 22416280 | 314 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
CreatorTokenTransferValidator
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import "./Constants.sol";
import "./DataTypes.sol";
import "./Errors.sol";
import "./ValidatorBase.sol";
import "./interfaces/IRuleset.sol";
import "./interfaces/IRulesetDelegateCall.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 choose a
* validation ruleset to apply to their collection, global and ruleset-specific options to fine-tune validation
* behavior, and manage blacklists/whitelists/authorizer/expansion lists and expansion settings for rulesets.
*/
contract CreatorTokenTransferValidator is
IEOARegistry,
ITransferValidator,
ValidatorBase,
ERC165,
Tstorish,
PermitC {
using EnumerableSet for EnumerableSet.AddressSet;
using EnumerableSet for EnumerableSet.Bytes32Set;
/*************************************************************************/
/* EVENTS */
/*************************************************************************/
/// @dev Emitted when a new list is created.
event CreatedList(uint256 indexed id, string name);
/// @dev Emitted when the ownership of a list is transferred to a new owner.
event ReassignedListOwnership(uint256 indexed id, address indexed newOwner);
/*************************************************************************/
/* CONSTANTS */
/*************************************************************************/
/// @dev The address of the EOA Registry to use to validate an account is a verified EOA.
address private immutable _eoaRegistry;
/// @dev The address of the management module that implements list and collection settings management.
address private immutable _managementModule;
/// @dev The address of the safe delegate module that implements the safe delegate code checker.
address private immutable _safeDelegateModule;
constructor(
address defaultOwner,
address eoaRegistry_,
address managementModule_,
address safeDelegateModule_,
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) || eoaRegistry_.code.length == 0 ||
managementModule_ == address(0) || managementModule_.code.length == 0 ||
safeDelegateModule_ == address(0) || safeDelegateModule_.code.length == 0) {
revert CreatorTokenTransferValidator__InvalidConstructorArgs();
}
_createDefaultList(defaultOwner);
_eoaRegistry = eoaRegistry_;
_managementModule = managementModule_;
_safeDelegateModule = safeDelegateModule_;
}
/**
* @dev This function is only called during contract construction to create the default list.
*/
function _createDefaultList(address defaultOwner) internal {
uint48 id = 0;
validatorStorage().listOwners[id] = defaultOwner;
emit CreatedList(id, "DEFAULT LIST");
emit ReassignedListOwnership(id, defaultOwner);
}
/*************************************************************************/
/* MODIFIERS */
/*************************************************************************/
/**
* @dev This modifier delegatecalls the specified module with the exact same calldata
* that came into the function, properly handling returndata when necessary.
* Assumes that the complete implementation of a function call is done in an external
* module.
*/
modifier delegateCall(address module) {
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), module, 0, calldatasize(), 0, 0)
let size := returndatasize()
returndatacopy(0, 0, size)
if iszero(result) {
revert(0, size)
}
return(0, size)
}
_;
}
/*************************************************************************/
/* RULESET ADMIN */
/*************************************************************************/
/**
* @notice Registers a ruleset to be used for transfer validation.
*
* @notice The ruleset must be a contract and goes through a sanitization / purity check process.
* The ruleset may not contain any banned opcodes (either undefined as of Prague or any known opcode that
* carries any risk of making state changes on the EVM).
*
* @dev Throws if the `msg.sender` does not own the default list (validator admin).
* @dev Throws if codehash of the ruleset denotes that it is either an uninitialized account or is an EOA.
* @dev Throws if the ruleset is not pure (meaning that it contains an invalid or banned opcode).
*
* @dev <h4>Postconditions:</h4>
* 1. The ruleset is marked as registered in the validator storage.
* 2. A `RulesetRegistered` event is emitted, the first time the ruleset is registered.
* (Subsequent registrations of the same ruleset do not emit this event).
*
* @param ruleset The address of the ruleset to register.
*/
function registerRuleset(address ruleset) external delegateCall(_safeDelegateModule) {}
/**
* @notice Binds a ruleset to a ruleset ID.
*
* @dev Throws if the `msg.sender` does not own the default list (validator admin).
* @dev Throws if the ruleset is not registered.
* @dev Throws if the ruleset ID is RULESET_ID_FIXED_OR_CUSTOM, as this is reserved for fixed rulesets that do not follow the
* automatic update process.
*
* @dev <h4>Postconditions:</h4>
* 1. The ruleset is bound to the ruleset ID.
* 2. A `RulesetBindingUpdated` event is emitted to indicate the ruleset binding has been updated.
* (If the ruleset is already bound to the ruleset ID, no event is emitted).
*
* @param rulesetId The ID of the ruleset to bind.
* @param ruleset The address of the ruleset to bind.
*/
function bindRuleset(uint8 rulesetId, address ruleset) external delegateCall(_safeDelegateModule) {}
/*************************************************************************/
/* APPLY TRANSFER POLICIES */
/*************************************************************************/
/**
* @notice Apply the collection ruleset and options 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 Modular rulesets with options determine the logic governing transfers.
*
* @dev Throws when the ruleset returns a non-zero error selector.
*
* @dev <h4>Postconditions:</h4>
* 1. Transfer is allowed or denied based on the ruleset.
*
* @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(AUTHORIZER_CHECK_TYPE_COLLECTION, msg.sender, caller, from, to, 0, 0);
if (errorSelector != SELECTOR_NO_ERROR) {
_revertCustomErrorSelectorAsm(errorSelector);
}
}
/**
* @notice Apply the collection ruleset and options 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 Modular rulesets with options determine the logic governing transfers.
*
* @dev Throws when the ruleset returns a non-zero error selector.
*
* @dev <h4>Postconditions:</h4>
* 1. Transfer is allowed or denied based on the ruleset.
*
* @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(AUTHORIZER_CHECK_TYPE_TOKEN, msg.sender, caller, from, to, tokenId, 0);
if (errorSelector != SELECTOR_NO_ERROR) {
_revertCustomErrorSelectorAsm(errorSelector);
}
}
/**
* @notice Apply the collection ruleset and options 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 Modular rulesets with options determine the logic governing transfers.
*
* @dev Throws when the ruleset returns a non-zero error selector.
* @dev Throws when authorization mode with amounts are active and the amount exceeds the authorization amount.
*
* @dev <h4>Postconditions:</h4>
* 1. Transfer is allowed or denied based on the ruleset.
*
* @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.
* @param amount The amount of the token being transferred.
*/
function validateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount) external {
(bytes4 errorSelector,) = _validateTransfer(AUTHORIZER_CHECK_TYPE_TOKEN_AND_AMOUNT, msg.sender, caller, from, to, tokenId, amount);
if (errorSelector != SELECTOR_NO_ERROR) {
_revertCustomErrorSelectorAsm(errorSelector);
}
uint256 collectionAndTokenIdSlot = _getTransientOperatorSlot(msg.sender, tokenId);
if (_getTstorish(collectionAndTokenIdSlot) != 0) {
uint256 amountSlot = collectionAndTokenIdSlot + 1;
uint256 authorizedAmount = _getTstorish(amountSlot);
if (amount > authorizedAmount) {
revert CreatorTokenTransferValidator__AmountExceedsAuthorization();
}
unchecked {
_setTstorish(amountSlot, authorizedAmount - amount);
}
}
}
/**
* @notice Apply the collection ruleset and options 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 Modular rulesets with options determine the logic governing transfers.
*
* @dev Throws when the ruleset returns a non-zero error selector.
*
* @dev <h4>Postconditions:</h4>
* 1. Transfer is allowed or denied based on the ruleset.
*
* @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 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.
* 2. The specified amount is stored as the authorized amount.
*
* @param token The address of the token to authorize.
* @param tokenId The token id to set the authorized operator for.
* @param amount The amount of the token to authorize.
*/
function beforeAuthorizedTransferWithAmount(address token, uint256 tokenId, uint256 amount) external {
_setOperatorInTransientStorage(WILDCARD_OPERATOR_ADDRESS, token, tokenId, amount);
}
/**
* @notice Sets the specified 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 specified operator is stored as an authorized operator for transfers.
* 2. The specified amount is stored as the authorized amount for the operator.
*
* @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.
* @param amount The amount of the token to authorize.
*/
function beforeAuthorizedTransferWithAmount(address operator, address token, uint256 tokenId, uint256 amount) external {
_setOperatorInTransientStorage(operator, token, tokenId, amount);
}
/**
* @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 {
_setOperatorInTransientStorage(address(uint160(uint256(BYTES32_ZERO))), token, tokenId, 0);
}
/*************************************************************************/
/* SIMULATION */
/*************************************************************************/
/**
* @notice Simulates transfer validation of a collection with its current ruleset and options.
*
* @dev Authorization mode overrides are not taken into account.
*
* @param collection The address of the collection.
* @param caller The address initiating the transfer.
* @param from The address of the token owner.
* @param to The address of the token receiver.
* @return isTransferAllowed True if the transfer is allowed, false otherwise.
* @return errorCode The error code if the transfer is not allowed.
*/
function validateTransferSim(
address collection,
address caller,
address from,
address to
) external view returns (bool isTransferAllowed, bytes4 errorCode) {
(errorCode,) = _validateTransfer(AUTHORIZER_CHECK_TYPE_COLLECTION, collection, caller, from, to, 0, 0);
isTransferAllowed = errorCode == SELECTOR_NO_ERROR;
}
/**
* @notice Simulates transfer validation of a collection with its current ruleset and options.
*
* @dev Authorization mode overrides are not taken into account.
*
* @param collection The address of the collection.
* @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 isTransferAllowed True if the transfer is allowed, false otherwise.
* @return errorCode The error code if the transfer is not allowed.
*/
function validateTransferSim(
address collection,
address caller,
address from,
address to,
uint256 tokenId
) external view returns (bool isTransferAllowed, bytes4 errorCode) {
(errorCode,) = _validateTransfer(AUTHORIZER_CHECK_TYPE_TOKEN, collection, caller, from, to, tokenId, 0);
isTransferAllowed = errorCode == SELECTOR_NO_ERROR;
}
/**
* @notice Simulates transfer validation of a collection with its current ruleset and options.
*
* @dev Authorization mode overrides are not taken into account.
*
* @param collection The address of the collection.
* @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.
* @param amount The amount of the token being transferred.
* @return isTransferAllowed True if the transfer is allowed, false otherwise.
* @return errorCode The error code if the transfer is not allowed.
*/
function validateTransferSim(
address collection,
address caller,
address from,
address to,
uint256 tokenId,
uint256 amount
) external view returns (bool isTransferAllowed, bytes4 errorCode) {
(errorCode,) = _validateTransfer(AUTHORIZER_CHECK_TYPE_TOKEN_AND_AMOUNT, collection, caller, from, to, tokenId, amount);
isTransferAllowed = errorCode == SELECTOR_NO_ERROR;
}
/*************************************************************************/
/* COLLECTION AND 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 delegateCall(_managementModule) returns (uint48 id) {}
/**
* @notice Creates a new list id, and copies all blacklisted, whitelisted, and authorizer 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, uint48 sourceListId) external delegateCall(_managementModule) returns (uint48 id) {}
/**
* @notice Creates a new list id, and copies all accounts and codehashes from the
* specified source list for each specified list type.
*
* @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 accounts and codehashes from the specified source list / list types are copied
* to the new list.
* 6. An `AddedAccountToList` event is emitted for each account copied.
* 7. An `AddedCodeHashToList` event is emitted for each codehash copied.
*
* @param name The name of the new list.
* @param sourceListId The id of the source list to copy from.
* @param listTypes The list types to copy from the source list.
* @return id The id of the new list.
*/
function createListCopy(string calldata name, uint48 sourceListId, uint8[] calldata listTypes) external delegateCall(_managementModule) returns (uint48 id) {}
/**
* @notice Transfer ownership of a list to a new owner.
*
* @dev Throws when the new owner is the zero address.
* @dev Throws when the caller does not own the specified list.
*
* @dev <h4>Postconditions:</h4>
* 1. The list ownership is transferred to the new owner.
* 2. A `ReassignedListOwnership` event is emitted.
*
* @param id The id of the list.
* @param newOwner The address of the new owner.
*/
function reassignOwnershipOfList(uint48 id, address newOwner) public delegateCall(_managementModule) {}
/**
* @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(uint48 id) public delegateCall(_managementModule) {}
/**
* @notice Set the ruleset id, global / ruleset options, fixed / custom ruleset for a collection.
*
* @dev Throws when the caller is neither collection contract, nor the owner or admin of the specified collection.
* @dev Throws when setting a custom ruleset to an unregistered ruleset address.
* @dev Throws when setting a ruleset id that is not bound to a ruleset address.
* @dev Throws when setting a custom ruleset with a managed ruleset id.
*
* @dev <h4>Postconditions:</h4>
* 1. The ruleset of the specified collection is set to the new value.
* 2. Global options and ruleset-specific options of the specified collection are set to the new value.
* 3. A `SetCollectionRuleset` event is emitted.
* 4. A `SetCollectionSecurityPolicyOptions` event is emitted.
*
* @param collection The address of the collection.
* @param rulesetId The new ruleset id to apply.
* @param customRuleset The address of the custom ruleset to apply. Must be address(0) unless ruleset
* id is RULESET_ID_FIXED_OR_CUSTOM (255).
* @param globalOptions The global options to apply.
* @param rulesetOptions The ruleset-specific options to apply.
*/
function setRulesetOfCollection(
address collection,
uint8 rulesetId,
address customRuleset,
uint8 globalOptions,
uint16 rulesetOptions
) external delegateCall(_managementModule) {}
/**
* @notice Set expansion words and datums for 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. Included expansion words and datums are set for the specified collection.
* 2. A `SetCollectionExpansionWords` event is emitted for each expansion word included in the request.
* 3. A `SetCollectionExpansionDatums` event is emitted for each expansion datum included in the request.
*
* @param collection The address of the collection.
* @param expansionWords The expansion words to set.
* @param expansionDatums The expansion datums to set.
*/
function setExpansionSettingsOfCollection(
address collection,
ExpansionWord[] calldata expansionWords,
ExpansionDatum[] calldata expansionDatums
) external delegateCall(_managementModule) {}
/**
* @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 delegateCall(_managementModule) {}
/**
* @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, uint48 id) public delegateCall(_managementModule) {}
/**
* @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 delegateCall(_managementModule) {}
/**
* @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 delegateCall(_managementModule) {}
/**
* @notice Adds one or more accounts to a list of specified list type.
*
* @dev Throws when the caller does not own the specified list.
*
* @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 listType The type of the list.
* @param accounts The addresses of the accounts to add.
*/
function addAccountsToList(
uint48 id,
uint8 listType,
address[] calldata accounts
) external delegateCall(_managementModule) {}
/**
* @notice Removes one or more accounts from a list of the specified list type.
*
* @dev Throws when the caller does not own the specified list.
*
* @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 listType The type of the list.
* @param accounts The addresses of the accounts to remove.
*/
function removeAccountsFromList(
uint48 id,
uint8 listType,
address[] calldata accounts
) external delegateCall(_managementModule) {}
/**
* @notice Adds one or more codehashes to a list of specified list type.
*
* @dev Throws when the caller does not own the specified list.
*
* @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 listType The type of the list.
* @param codehashes The codehashes to add.
*/
function addCodeHashesToList(
uint48 id,
uint8 listType,
bytes32[] calldata codehashes
) external delegateCall(_managementModule) {}
/**
* @notice Removes one or more codehashes from a list of the specified list type.
*
* @dev Throws when the caller does not own the specified list.
*
* @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 listType The type of the list.
* @param codehashes The codehashes to remove.
*/
function removeCodeHashesFromList(
uint48 id,
uint8 listType,
bytes32[] calldata codehashes
) external delegateCall(_managementModule) {}
/*************************************************************************/
/* RULESET VIEW ACCESSORS */
/*************************************************************************/
/**
* @notice Returns true if the specified ruleset is registered, false otherwise.
*/
function isRulesetRegistered(address ruleset) external view returns (bool) {
return validatorStorage().registeredRulesets[ruleset];
}
/**
* @notice Returns the address of the ruleset currently bound to the specified ruleset id.
*/
function boundRuleset(uint8 rulesetId) external view returns (address) {
if (rulesetId == RULESET_ID_FIXED_OR_CUSTOM) {
return address(0);
}
return validatorStorage().rulesetBindings[rulesetId];
}
/*************************************************************************/
/* COLLECTION AND LIST SETTINGS VIEW ACCESSORS */
/*************************************************************************/
/**
* @notice Returns the id of the list that was created.
*/
function lastListId() external view returns (uint48) {
return validatorStorage().lastListId;
}
/**
* @notice Returns the owner of the specified list id.
*/
function listOwners(uint48 id) external view returns (address) {
return validatorStorage().listOwners[id];
}
/**
* @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:
* Ruleset id, list id, global options, ruleset-specific options, optional custom ruleset address,
* and token type (if registered).
*/
function getCollectionSecurityPolicy(
address collection
) external view returns (CollectionSecurityPolicy memory) {
return validatorStorage().collectionSecurityPolicies[collection];
}
/**
* @notice Returns expansion word settings for a collection.
*
* @param tokenAddress The smart contract address of the token.
* @param keys The expansion word keys to retrieve.
*/
function getCollectionExpansionWords(
address tokenAddress,
bytes32[] calldata keys
) public view returns (bytes32[] memory values) {
if(keys.length > 0) {
mapping (bytes32 => bytes32) storage ptrExpansionWordsForCollection =
validatorStorage().collectionExpansionWords[tokenAddress];
values = new bytes32[](keys.length);
for (uint256 i = 0; i < keys.length; ++i) {
values[i] = ptrExpansionWordsForCollection[keys[i]];
}
}
}
/**
* @notice Returns expansion datum settings for a collection.
*
* @param tokenAddress The smart contract address of the token.
* @param keys The expansion datum keys to retrieve.
*/
function getCollectionExpansionDatums(
address tokenAddress,
bytes32[] calldata keys
) public view returns (bytes[] memory values) {
if(keys.length > 0) {
mapping (bytes32 => bytes) storage ptrExpansionDatumsForCollection =
validatorStorage().collectionExpansionDatums[tokenAddress];
values = new bytes[](keys.length);
for (uint256 i = 0; i < keys.length; ++i) {
values[i] = ptrExpansionDatumsForCollection[keys[i]];
}
}
}
/**
* @notice Get accounts by list id and list type.
* @param id The id of the list.
* @param listType The type of the list.
* @return An array of accounts in the list of the specified type.
*/
function getListAccounts(uint48 id, uint8 listType) public view returns (address[] memory) {
return validatorStorage().lists[listType][id].enumerableAccounts.values();
}
/**
* @notice Get codehashes by list id and list type.
* @param id The id of the list.
* @param listType The type of the list.
* @return An array of codehashes in the list of the specified type.
*/
function getListCodeHashes(uint48 id, uint8 listType) public view returns (bytes32[] memory) {
return validatorStorage().lists[listType][id].enumerableCodehashes.values();
}
/**
* @notice Check if an account is found in a specified list id / list type.
* @param id The id of the list.
* @param listType The type of the list.
* @param account The address of the account to check.
* @return True if the account is in the specified list / type, false otherwise.
*/
function isAccountInList(uint48 id, uint8 listType, address account) public view returns (bool) {
return validatorStorage().lists[listType][id].nonEnumerableAccounts[account];
}
/**
* @notice Check if a codehash is in a specified list / type.
* @param id The id of the list.
* @param listType The type of the list.
* @param codehash The codehash to check.
* @return True if the codehash is in the specified list / type, false otherwise.
*/
function isCodeHashInList(uint48 id, uint8 listType, bytes32 codehash) public view returns (bool) {
return validatorStorage().lists[listType][id].nonEnumerableCodehashes[codehash];
}
/**
* @notice Get accounts in list by collection and list type.
* @param collection The address of the collection.
* @param listType The type of the list.
* @return An array of accounts.
*/
function getListAccountsByCollection(address collection, uint8 listType) external view returns (address[] memory) {
return getListAccounts(validatorStorage().collectionSecurityPolicies[collection].listId, listType);
}
/**
* @notice Get codehashes in list by collection and list type.
* @param collection The address of the collection.
* @param listType The type of the list.
* @return An array of codehashes.
*/
function getListCodeHashesByCollection(address collection, uint8 listType) external view returns (bytes32[] memory) {
return getListCodeHashes(validatorStorage().collectionSecurityPolicies[collection].listId, listType);
}
/**
* @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 validatorStorage().frozenAccounts[collection].enumerableAccounts.values();
}
/**
* @notice Check if an account is in the list by a specified collection and list type.
* @param collection The address of the collection.
* @param listType The type of the list.
* @param account The address of the account to check.
* @return True if the account is in the list / list type of the specified collection, false otherwise.
*/
function isAccountInListByCollection(address collection, uint8 listType, address account) external view returns (bool) {
return isAccountInList(validatorStorage().collectionSecurityPolicies[collection].listId, listType, account);
}
/**
* @notice Check if a codehash is in the list by a specified collection / list type.
* @param collection The address of the collection.
* @param listType The type of the list.
* @param codehash The codehash to check.
* @return True if the codehash is in the list / list type of the specified collection, false otherwise.
*/
function isCodeHashInListByCollection(address collection, uint8 listType, bytes32 codehash) external view returns (bool) {
return isCodeHashInList(validatorStorage().collectionSecurityPolicies[collection].listId, listType, codehash);
}
/**
* @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 validatorStorage().frozenAccounts[collection].nonEnumerableAccounts[account];
}
/**
* @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 Makes a delegatecall to the validator ruleset module that perform the transfer validation logic.
*
* @dev Throws when the `msg.sender` is not equal to address(this). This guarantees that staticcall context
* is properly preserved.
*/
function validateTransferDelegateCall(
uint256 authorizerCheckType,
address collection,
address caller,
address from,
address to,
uint256 tokenId,
uint256 amount) external /*view*/ returns (bytes4 errorSelector, uint16 tokenType) {
if (msg.sender != address(this)) {
revert CreatorTokenTransferValidator__OnlyValidatorCanAccessThisFunction();
}
address validatorModuleAddress;
(
validatorModuleAddress,
tokenType
) = _getCollectionTokenTypeAndValidatorModule(collection);
errorSelector = _delegateCallRuleset(
validatorModuleAddress,
authorizerCheckType,
collection,
caller,
from,
to,
tokenId,
amount
);
}
/**
* @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 */
/*************************************************************************/
/**
* @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(
tokenType == TOKEN_TYPE_ERC721 ? AUTHORIZER_CHECK_TYPE_TOKEN : AUTHORIZER_CHECK_TYPE_TOKEN_AND_AMOUNT,
token,
msg.sender,
from,
to,
id,
amount
);
if (collectionTokenType == DEFAULT_TOKEN_TYPE || collectionTokenType == tokenType) {
isError = SELECTOR_NO_ERROR != selector;
} else {
revert CreatorTokenTransferValidator__TokenTypesDoNotMatch();
}
}
/**
* @notice Apply the collection ruleset and options 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 Modular rulesets with options determine the logic governing transfers.
*
* @dev Throws when the ruleset returns a non-zero error selector.
*
* @dev <h4>Postconditions:</h4>
* 1. Transfer is allowed or denied based on the ruleset.
*
* @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(
uint256 authorizerCheckType,
address collection,
address caller,
address from,
address to,
uint256 tokenId,
uint256 amount
) 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);
}
return IRulesetDelegateCall(address(this)).validateTransferDelegateCall(
authorizerCheckType,
collection,
caller,
from,
to,
tokenId,
amount
);
}
/**
* @dev Internal function used to get the collection token type and validator module address.
*
* @param collection The collection address to get the token type and validator module address for.
* @return validatorModuleAddress The validator module address afor the collection.
* @return tokenType The token type for the collection.
*/
function _getCollectionTokenTypeAndValidatorModule(
address collection
) internal view returns (address validatorModuleAddress, uint16 tokenType) {
CollectionSecurityPolicy storage ptrSecurityPolicy = validatorStorage().collectionSecurityPolicies[collection];
validatorModuleAddress =
ptrSecurityPolicy.rulesetId < RULESET_ID_FIXED_OR_CUSTOM ?
validatorStorage().rulesetBindings[ptrSecurityPolicy.rulesetId] :
ptrSecurityPolicy.customRuleset;
tokenType = ptrSecurityPolicy.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 {
CollectionSecurityPolicy storage collectionSecurityPolicy = validatorStorage().collectionSecurityPolicies[collection];
if (_isFlagSet(collectionSecurityPolicy.globalOptions, FLAG_GLOBAL_DISABLE_AUTHORIZATION_MODE)) {
revert CreatorTokenTransferValidator__AuthorizationDisabledForCollection();
}
if (_isFlagSet(collectionSecurityPolicy.globalOptions, FLAG_GLOBAL_AUTHORIZERS_CANNOT_SET_WILDCARD_OPERATORS)) {
if (operator == WILDCARD_OPERATOR_ADDRESS) {
revert CreatorTokenTransferValidator__WildcardOperatorsCannotBeAuthorizedForCollection();
}
}
if (!validatorStorage().lists[LIST_TYPE_AUTHORIZERS][collectionSecurityPolicy.listId].nonEnumerableAccounts[authorizer]) {
if (!_isFlagSet(collectionSecurityPolicy.globalOptions, FLAG_GLOBAL_CUSTOM_LIST_SUPPLEMENTS_DEFAULT_LIST) ||
!validatorStorage().lists[LIST_TYPE_AUTHORIZERS][DEFAULT_LIST_ID].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 for setting the authorized operator and amount 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 amount The amount of the token that is authorized.
*/
function _setOperatorInTransientStorage(
address operator,
address collection,
uint256 tokenId,
uint256 amount
) internal whenAuthorizerAndOperatorEnabledForCollection(collection, operator, msg.sender) {
_setTstorish(_getTransientOperatorSlot(collection), uint256(uint160(operator)));
uint256 collectionAndTokenIdSlot = _getTransientOperatorSlot(collection, tokenId);
_setTstorish(collectionAndTokenIdSlot, uint256(uint160(operator)));
_setTstorish(collectionAndTokenIdSlot + 1, amount);
}
/**
* @dev Internal function triggered when the Tstore support is activated.
*/
function _onTstoreSupportActivated() internal virtual override {
// Nothing to do here
}
/**
* @dev Internal function used to delegate call the ruleset module for transfer validation and return results.
*/
function _delegateCallRuleset(
address _ruleSet,
uint256 _authorizerCheckType,
address _collection,
address _caller,
address _from,
address _to,
uint256 _tokenId,
uint256 _amount
) internal returns (bytes4 errorSelector) {
bytes4 selector = IRuleset.validateTransfer.selector;
assembly {
let ptr := mload(0x40)
mstore(ptr, selector)
mstore(add(ptr,0x04), _authorizerCheckType)
mstore(add(ptr,0x24), _collection)
mstore(add(ptr,0x44), _caller)
mstore(add(ptr,0x64), _from)
mstore(add(ptr,0x84), _to)
mstore(add(ptr,0xA4), _tokenId)
mstore(add(ptr,0xC4), _amount)
mstore(0x40, add(ptr,0xE4))
let result := delegatecall(gas(), _ruleSet, ptr, 0xE4, 0x00, 0x20)
if iszero(result) {
// Call has failed, retrieve the error message and revert
let size := returndatasize()
returndatacopy(0, 0, size)
revert(0, size)
}
errorSelector := mload(0x00)
}
}
}// 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;
/**************************************************************/
/* LIST TYPES */
/**************************************************************/
uint8 constant LIST_TYPE_BLACKLIST = 0;
uint8 constant LIST_TYPE_WHITELIST = 1;
uint8 constant LIST_TYPE_AUTHORIZERS = 2;
uint8 constant EXPANSION_LIST_TYPE_WHITELIST_EXTENSION_CONTRACTS = 3;
uint8 constant EXPANSION_LIST_TYPE_7702_DELEGATE_WHITELIST = 4;
uint8 constant EXPANSION_LIST_TYPE_7702_DELEGATE_WHITELIST_EXTENSION_CONTRACTS = 5;
/**************************************************************/
/* RULESET IDS */
/**************************************************************/
uint8 constant RULESET_ID_DEFAULT = 0;
uint8 constant RULESET_ID_VANILLA = 1;
uint8 constant RULESET_ID_SOULBOUND = 2;
uint8 constant RULESET_ID_BLACKLIST = 3;
uint8 constant RULESET_ID_WHITELIST = 4;
uint8 constant RULESET_ID_FIXED_OR_CUSTOM = 255;
/**************************************************************/
/* AUTHORIZER CHECK TYPES */
/**************************************************************/
uint256 constant AUTHORIZER_CHECK_TYPE_TOKEN = 1;
uint256 constant AUTHORIZER_CHECK_TYPE_COLLECTION = 2;
uint256 constant AUTHORIZER_CHECK_TYPE_TOKEN_AND_AMOUNT = 3;
/**************************************************************/
/* MISCELLANEOUS */
/**************************************************************/
bytes4 constant LEGACY_TRANSFER_VALIDATOR_INTERFACE_ID = bytes4(0x00000000);
bytes4 constant SELECTOR_NO_ERROR = bytes4(0x00000000);
bytes32 constant BYTES32_ZERO = 0x0000000000000000000000000000000000000000000000000000000000000000;
bytes32 constant DEFAULT_ACCESS_CONTROL_ADMIN_ROLE = 0x0000000000000000000000000000000000000000000000000000000000000000;
address constant WILDCARD_OPERATOR_ADDRESS = address(0x01);
uint48 constant DEFAULT_LIST_ID = 0;
uint16 constant DEFAULT_TOKEN_TYPE = 0;
/**************************************************************/
/* FLAGS - GLOBAL */
/**************************************************************/
// Flags are used to efficiently store and retrieve boolean values in a single uint8.
// Each flag is a power of 2, so they can be combined using bitwise OR (|) and checked using bitwise AND (&).
// For example, to set the first and third flags, you would use: flags = FLAG1 | FLAG3;
// To check if the first flag is set, you would use: if (flags & FLAG1 != 0) { ... }
uint8 constant FLAG_GLOBAL_DISABLE_AUTHORIZATION_MODE = 1 << 0;
uint8 constant FLAG_GLOBAL_AUTHORIZERS_CANNOT_SET_WILDCARD_OPERATORS = 1 << 1;
uint8 constant FLAG_GLOBAL_ENABLE_ACCOUNT_FREEZING_MODE = 1 << 2;
uint8 constant FLAG_GLOBAL_CUSTOM_LIST_SUPPLEMENTS_DEFAULT_LIST = 1 << 3;
/**************************************************************/
/* FLAGS - RULESET WHITELIST */
/**************************************************************/
uint16 constant FLAG_RULESET_WHITELIST_BLOCK_ALL_OTC = 1 << 0;
uint16 constant FLAG_RULESET_WHITELIST_ALLOW_OTC_FOR_7702_DELEGATES = 1 << 1;
uint16 constant FLAG_RULESET_WHITELIST_ALLOW_OTC_FOR_SMART_WALLETS = 1 << 2;
uint16 constant FLAG_RULESET_WHITELIST_BLOCK_SMART_WALLET_RECEIVERS = 1 << 3;
uint16 constant FLAG_RULESET_WHITELIST_BLOCK_UNVERIFIED_EOA_RECEIVERS = 1 << 4;// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import "@limitbreak/tm-core-lib/src/utils/structs/EnumerableSet.sol";
/**
* @dev This struct contains the security policy settings for a collection.
*/
struct CollectionSecurityPolicy {
uint8 rulesetId;
uint48 listId;
address customRuleset;
uint8 globalOptions;
uint16 rulesetOptions;
uint16 tokenType;
}
/**
* @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;
}
/**
* @dev This struct contains a key and value pair for future expansion data words that are 32 bytes long.
*/
struct ExpansionWord {
bytes32 key;
bytes32 value;
}
/**
* @dev This struct contains a key and value pair for future expansion data bytes that are variable length.
*/
struct ExpansionDatum {
bytes32 key;
bytes value;
}
/**
* @dev This struct contains the storage layout for the validator contract, excluding Permit-C and Tstorish data.
*/
struct ValidatorStorage {
/// @notice Keeps track of the most recently created list id.
uint48 lastListId;
/// @dev Used as a collision guard.
mapping (address => address) transientOperator;
/// @notice Mapping of list ids to list owners
mapping (uint48 => address) listOwners;
/// @dev Mapping of collection addresses to their security policy settings
mapping (address => CollectionSecurityPolicy) collectionSecurityPolicies;
/// @dev Mapping of collections to accounts that are frozen for those collections
mapping (address => AccountList) frozenAccounts;
/// @dev Mapping of list ids to list data
mapping (uint8 => mapping (uint48 => List)) lists;
/// @dev Mapping of collection addressses to any future expansion data words settings that may be used in the future
mapping (address collection => mapping (bytes32 extension => bytes32 word)) collectionExpansionWords;
/// @dev Mapping of collection addressses to any future expansion data bytes settings that may be used in the future
mapping (address collection => mapping (bytes32 extension => bytes data)) collectionExpansionDatums;
/// @dev Mapping of addresses to a boolean indicating if they are registered trusted validator modules
mapping (address => bool) registeredRulesets;
/// @dev Mapping of security levels to their current implementation modules
mapping (uint8 => address) rulesetBindings;
}// SPDX-License-Identifier: MIT pragma solidity 0.8.24; /// @dev Thrown when admin attempts to bind a ruleset to the fixed/custom ruleset ID. error CreatorTokenTransferValidator__AdminCannotAssignRulesetToRulesetIdCustom(); /// @dev Thrown when validating transfers with amount if authorization by amount mode is active and the amount /// exceeds the pre-authorized amount. error CreatorTokenTransferValidator__AmountExceedsAuthorization(); /// @dev Thrown when attempting to set a authorized operator when authorization mode is disabled. error CreatorTokenTransferValidator__AuthorizationDisabledForCollection(); /// @dev Thrown when attempting to call a function that requires the caller to be the list owner. error CreatorTokenTransferValidator__CallerDoesNotOwnList(); /// @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 validating a transfer for a collection using whitelists and the operator is not on the whitelist. error CreatorTokenTransferValidator__CallerMustBeWhitelisted(); /// @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 validating a transfer for a collection using whitelists and the operator or from account is not on the whitelist. error CreatorTokenTransferValidator__CallerOrFromMustBeWhitelisted(); /// @dev Thrown when attempting to renounce ownership of the default list id. error CreatorTokenTransferValidator__CannotRenounceOwnershipOfDefaultList(); /// @dev Thrown when setting the ruleset for a collection when a reserved ruleset id is used, but a custom ruleset /// is specified. error CreatorTokenTransferValidator__CannotSetCustomRulesetOnManagedRulesetId(); /// @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 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 the transfer validation logic externally, as staticcall guarantees are needed. error CreatorTokenTransferValidator__OnlyValidatorCanAccessThisFunction(); /// @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 an OTC transfer with EIP-7702 Delegation when disabled by security settings. error CreatorTokenTransferValidator__OTCNotAllowedFor7702Delegates(); /// @dev Thrown when validating an OTC transfer from Smart Wallets when disabled by security settings. error CreatorTokenTransferValidator__OTCNotAllowedForSmartWallets(); /// @dev Thrown when a frozen account is the receiver of a transfer error CreatorTokenTransferValidator__ReceiverAccountIsFrozen(); /// @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 attempting to register a ruleset that is not a contract. error CreatorTokenTransferValidator__RulesetIsNotContract(); /// @dev Thrown when attempting to register a ruleset that is not pure. error CreatorTokenTransferValidator__RulesetIsNotPure(); /// @dev Thrown when admin attempts to bind a ruleset that is not registered, or a collection admin tries to /// set their fixed/custom ruleset to an unregistered ruleset. error CreatorTokenTransferValidator__RulesetIsNotRegistered(); /// @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 attempting to validate a permitted transfer where the permit type does not match the /// collection-defined token type. error CreatorTokenTransferValidator__TokenTypesDoNotMatch(); /// @dev Thrown when an authorizer attempts to set a wildcard authorized operator on collections that don't /// allow wildcards error CreatorTokenTransferValidator__WildcardOperatorsCannotBeAuthorizedForCollection();
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import "./DataTypes.sol";
import "./Errors.sol";
/**
* @title ValidatorBase
* @author Limit Break, Inc.
* @notice Base contract for all Creator Token Validator, Module, and Ruleset contracts.
* Includes some helper functions and modifiers and easy access to validator diamond storage
* to allow modules and rulesets to access the storage of the validator contract.
*/
contract ValidatorBase {
/*************************************************************************/
/* 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(uint48 id) {
_requireCallerOwnsList(id);
_;
}
/*************************************************************************/
/* HELPERS */
/*************************************************************************/
/**
* @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(uint48 id) private view {
if (msg.sender != validatorStorage().listOwners[id]) {
revert CreatorTokenTransferValidator__CallerDoesNotOwnList();
}
}
/**
* @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 view returns (uint256 operatorSlot) {
mapping (address => address) storage _transientOperator = validatorStorage().transientOperator;
assembly {
mstore(0x00, collection)
mstore(0x20, _transientOperator.slot)
operatorSlot := keccak256(0x00, 0x40)
}
}
/**
* @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) }
}
/**
* @notice Returns true if the `flagValue` has the `flag` set, false otherwise.
*
* @dev This function uses the bitwise AND operator to check if the `flag` is set in `flagValue`.
*
* @param flagValue The value to check for the presence of the `flag`.
* @param flag The flag to check for in the `flagValue`.
*/
function _isFlagSet(uint256 flagValue, uint256 flag) internal pure returns (bool flagSet) {
flagSet = (flagValue & flag) != 0;
}
/*************************************************************************/
/* STORAGE */
/*************************************************************************/
/// @dev The base storage slot for Validator V5 contract storage items.
bytes32 constant DIAMOND_STORAGE_VALIDATOR =
0x0000000000000000000000000000000000000000000000000000000000721C05;
/**
* @dev Returns a storage object that follows the Diamond standard storage pattern for
* @dev contract storage across multiple module contracts.
*/
function validatorStorage() internal pure returns (ValidatorStorage storage diamondStorage) {
bytes32 slot = DIAMOND_STORAGE_VALIDATOR;
assembly {
diamondStorage.slot := slot
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
/**
* @title IRuleset
* @author Limit Break, Inc.
* @notice Interface for Creator Token Standards ruleset contracts.
*
* @dev Ruleset contracts are logic-gate contracts used to validate transfers of Creator Tokens
* (ERC20-C / ERC721-C / ERC1155-C). Rulesets are view-only, and may not contain any opcodes
* that could modify the state of the blockchain.
*/
interface IRuleset {
/**
* @notice Validates a transfer of a Creator Token.
*
* @param authorizerCheckType The type of authorizer check to perform.
* @param collection The address of the Creator Token contract.
* @param caller The address of the caller (msg.sender) of the transfer function.
* @param from The address of the sender of the token.
* @param to The address of the recipient of the token.
* @param tokenId The ID of the token.
* @param amount The amount of the token to transfer.
* @return 0x00000000 when the transfer is allowed, or a custom error selector to block a transfer.
*/
function validateTransfer(
uint256 authorizerCheckType,
address collection,
address caller,
address from,
address to,
uint256 tokenId,
uint256 amount) external view returns (bytes4);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
/**
* @title IRulesetDelegateCall
* @author Limit Break, Inc.
* @notice Interface for delegate calling Creator Token Standards ruleset contracts.
*
* @dev Transfer validator implements this interface. It will STATICCALL itself to put itself into a
* state where a ruleset check cannot possibly make any stateful changes, ensuring that they are always read-only.
*/
interface IRulesetDelegateCall {
/**
* @notice Validates a transfer of a Creator Token in the context of a STATICCALL.
*
* @param authorizerCheckType The type of authorizer check to perform.
* @param collection The address of the Creator Token contract.
* @param caller The address of the caller (msg.sender) of the transfer function.
* @param from The address of the sender of the token.
* @param to The address of the recipient of the token.
* @param tokenId The ID of the token.
* @param amount The amount of the token to transfer.
* @return 0x00000000 when the transfer is allowed, or a custom error selector to block a transfer.
* @return The token type (20, 721, 1155) for use in permit transfer checks when applicable.
*/
function validateTransferDelegateCall(
uint256 authorizerCheckType,
address collection,
address caller,
address from,
address to,
uint256 tokenId,
uint256 amount) external view returns (bytes4,uint16);
}{
"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": 1000000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"defaultOwner","type":"address"},{"internalType":"address","name":"eoaRegistry_","type":"address"},{"internalType":"address","name":"managementModule_","type":"address"},{"internalType":"address","name":"safeDelegateModule_","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__AmountExceedsAuthorization","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__AuthorizationDisabledForCollection","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__CallerMustBeAnAuthorizer","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__InvalidConstructorArgs","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__OnlyValidatorCanAccessThisFunction","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":"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"},{"inputs":[],"name":"__activateTstore","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint48","name":"id","type":"uint48"},{"internalType":"uint8","name":"listType","type":"uint8"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"addAccountsToList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint48","name":"id","type":"uint48"},{"internalType":"uint8","name":"listType","type":"uint8"},{"internalType":"bytes32[]","name":"codehashes","type":"bytes32[]"}],"name":"addCodeHashesToList","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":"uint48","name":"id","type":"uint48"}],"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":"amount","type":"uint256"}],"name":"beforeAuthorizedTransferWithAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"beforeAuthorizedTransferWithAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"rulesetId","type":"uint8"},{"internalType":"address","name":"ruleset","type":"address"}],"name":"bindRuleset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"rulesetId","type":"uint8"}],"name":"boundRuleset","outputs":[{"internalType":"address","name":"","type":"address"}],"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":"closePermittedOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"}],"name":"createList","outputs":[{"internalType":"uint48","name":"id","type":"uint48"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint48","name":"sourceListId","type":"uint48"},{"internalType":"uint8[]","name":"listTypes","type":"uint8[]"}],"name":"createListCopy","outputs":[{"internalType":"uint48","name":"id","type":"uint48"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint48","name":"sourceListId","type":"uint48"}],"name":"createListCopy","outputs":[{"internalType":"uint48","name":"id","type":"uint48"}],"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":"address","name":"tokenAddress","type":"address"},{"internalType":"bytes32[]","name":"keys","type":"bytes32[]"}],"name":"getCollectionExpansionDatums","outputs":[{"internalType":"bytes[]","name":"values","type":"bytes[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"bytes32[]","name":"keys","type":"bytes32[]"}],"name":"getCollectionExpansionWords","outputs":[{"internalType":"bytes32[]","name":"values","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"}],"name":"getCollectionSecurityPolicy","outputs":[{"components":[{"internalType":"uint8","name":"rulesetId","type":"uint8"},{"internalType":"uint48","name":"listId","type":"uint48"},{"internalType":"address","name":"customRuleset","type":"address"},{"internalType":"uint8","name":"globalOptions","type":"uint8"},{"internalType":"uint16","name":"rulesetOptions","type":"uint16"},{"internalType":"uint16","name":"tokenType","type":"uint16"}],"internalType":"struct CollectionSecurityPolicy","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":"uint48","name":"id","type":"uint48"},{"internalType":"uint8","name":"listType","type":"uint8"}],"name":"getListAccounts","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint8","name":"listType","type":"uint8"}],"name":"getListAccountsByCollection","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint48","name":"id","type":"uint48"},{"internalType":"uint8","name":"listType","type":"uint8"}],"name":"getListCodeHashes","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint8","name":"listType","type":"uint8"}],"name":"getListCodeHashesByCollection","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":"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":"uint48","name":"id","type":"uint48"},{"internalType":"uint8","name":"listType","type":"uint8"},{"internalType":"address","name":"account","type":"address"}],"name":"isAccountInList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint8","name":"listType","type":"uint8"},{"internalType":"address","name":"account","type":"address"}],"name":"isAccountInListByCollection","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint48","name":"id","type":"uint48"},{"internalType":"uint8","name":"listType","type":"uint8"},{"internalType":"bytes32","name":"codehash","type":"bytes32"}],"name":"isCodeHashInList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint8","name":"listType","type":"uint8"},{"internalType":"bytes32","name":"codehash","type":"bytes32"}],"name":"isCodeHashInListByCollection","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":"ruleset","type":"address"}],"name":"isRulesetRegistered","outputs":[{"internalType":"bool","name":"","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":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint48","name":"id","type":"uint48"}],"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":"uint48","name":"id","type":"uint48"},{"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":"address","name":"ruleset","type":"address"}],"name":"registerRuleset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint48","name":"id","type":"uint48"},{"internalType":"uint8","name":"listType","type":"uint8"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"removeAccountsFromList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint48","name":"id","type":"uint48"},{"internalType":"uint8","name":"listType","type":"uint8"},{"internalType":"bytes32[]","name":"codehashes","type":"bytes32[]"}],"name":"removeCodeHashesFromList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint48","name":"id","type":"uint48"}],"name":"renounceOwnershipOfList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"bytes32","name":"value","type":"bytes32"}],"internalType":"struct ExpansionWord[]","name":"expansionWords","type":"tuple[]"},{"components":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"bytes","name":"value","type":"bytes"}],"internalType":"struct ExpansionDatum[]","name":"expansionDatums","type":"tuple[]"}],"name":"setExpansionSettingsOfCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint8","name":"rulesetId","type":"uint8"},{"internalType":"address","name":"customRuleset","type":"address"},{"internalType":"uint8","name":"globalOptions","type":"uint8"},{"internalType":"uint16","name":"rulesetOptions","type":"uint16"}],"name":"setRulesetOfCollection","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":"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":"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":"amount","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"},{"inputs":[{"internalType":"uint256","name":"authorizerCheckType","type":"uint256"},{"internalType":"address","name":"collection","type":"address"},{"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":"amount","type":"uint256"}],"name":"validateTransferDelegateCall","outputs":[{"internalType":"bytes4","name":"errorSelector","type":"bytes4"},{"internalType":"uint16","name":"tokenType","type":"uint16"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"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":"amount","type":"uint256"}],"name":"validateTransferSim","outputs":[{"internalType":"bool","name":"isTransferAllowed","type":"bool"},{"internalType":"bytes4","name":"errorCode","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"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":"validateTransferSim","outputs":[{"internalType":"bool","name":"isTransferAllowed","type":"bool"},{"internalType":"bytes4","name":"errorCode","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"validateTransferSim","outputs":[{"internalType":"bool","name":"isTransferAllowed","type":"bool"},{"internalType":"bytes4","name":"errorCode","type":"bytes4"}],"stateMutability":"view","type":"function"}]Contract Creation Code
61028060405234801562000011575f80fd5b506040516200670a3803806200670a833981016040819052620000349162000728565b818187466001146200004e57662386f26fc1000062000058565b670494654067e100005b6001600160401b03168383825f6200006f62000369565b90506001600160a01b0381166200009957604051632aea588760e01b815260040160405180910390fd5b620000a48162000382565b5f80516020620066ea833981519152805460ff19169115801592831790915560a0919091526200011157620003e4602090811b6200293a176001600160401b0390811660c052620003eb821b6200294117811660e052620003ef90911b620029451716610100526200014f565b620003f5602090811b6200294b176001600160401b0390811660c05262000419821b6200298017811660e0526200044190911b620029b91716610100525b6001600160a01b0316608052620001663362000467565b8015620001b557620004b6602090811b620029ee176001600160401b0390811661014052620004e8821b62002a54178116610160526200053390911b62002aec1716610180525f1901620001f5565b6200054b602090811b62002b1f176001600160401b03908116610140526200050e821b62002aaf178116610160526200056f90911b62002b5b1716610180525b6101205281516020808401919091206101e05281519082012061020052466101c052620002856101e05161020051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b6101a052506200029790508262000467565b505050506001600160a01b0386161580620002b957506001600160a01b038516155b80620002cd57506001600160a01b0385163b155b80620002e057506001600160a01b038416155b80620002f457506001600160a01b0384163b155b806200030757506001600160a01b038316155b806200031b57506001600160a01b0383163b155b156200033a5760405163c56e5d7360e01b815260040160405180910390fd5b620003458662000575565b50506001600160a01b039283166102205290821661024052166102605250620007f6565b5f696002601e613d5c3d52f35f52600a60165ff0905090565b5f816001600160a01b0316600a5a6200039c9190620007d6565b6040515f8181818686fa925050503d805f8114620003d6576040519150601f19603f3d011682016040523d82523d5f602084013e620003db565b606091505b50909392505050565b80825d5050565b5c90565b5f815d50565b5f80516020620066ea8339815191525460ff1615620004155780825d5050565b9055565b5f5f80516020620066ea8339815191525460ff16156200043857505c90565b5080545b919050565b5f80516020620066ea8339815191525460ff161562000460575f815d50565b5f81555b50565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61012051344703111562000464576001548116156200046457604051636623b92d60e11b815260040160405180910390fd5b61012051344703116200050e5760405163fd2c901360e01b815260040160405180910390fd5b80600154165f03620004645760405163fd2c901360e01b815260040160405180910390fd5b610120515f9034470311156200054857506001545b90565b6001548116156200046457604051636623b92d60e11b815260040160405180910390fd5b60015490565b5f80805262721c0760209081527f3afc1a9185ee9493e6c7b84067661c3f990c1c459276628dc19d8569e33dfa3080546001600160a01b0319166001600160a01b03851617905560408051828152600c928101929092526b1111519055531508131254d560a21b9082015281907f5cc365f89543268cb9f25c255f7f610e9147e733c589bc2732279575f125be149060600160405180910390a26040516001600160a01b0383169065ffffffffffff8316907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e27367905f90a35050565b80516001600160a01b03811681146200043c575f80fd5b634e487b7160e01b5f52604160045260245ffd5b5f82601f8301126200068b575f80fd5b81516001600160401b0380821115620006a857620006a862000667565b604051601f8301601f19908116603f01168101908282118183101715620006d357620006d362000667565b8160405283815260209250866020858801011115620006f0575f80fd5b5f91505b83821015620007135785820183015181830184015290820190620006f4565b5f602085830101528094505050505092915050565b5f805f805f8060c087890312156200073e575f80fd5b620007498762000650565b9550620007596020880162000650565b9450620007696040880162000650565b9350620007796060880162000650565b60808801519093506001600160401b038082111562000796575f80fd5b620007a48a838b016200067b565b935060a0890151915080821115620007ba575f80fd5b50620007c989828a016200067b565b9150509295509295509295565b5f82620007f157634e487b7160e01b5f52601260045260245ffd5b500490565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e05161020051610220516102405161026051615dcc6200091e5f395f6115dc01525f8181611b860152611d2501525f61219601525f613f8c01525f613f6401525f613eeb01525f613f1301525f50505f50505f8181611475015281816114ef0152818161156301528181611a2101528181611b1a01528181611d6501528181611fc6015281816123af015281816125b60152818161263601526127c001525f818161124a015281816129f001528181612a560152612aef01525f50505f81816116c101526116fd01525f81816117690152818161337a015281816133d301528181613406015261370101525f611e3401525f611ebb0152615dcc5ff3fe60806040526004361061057f575f3560e01c806386e11774116102cf578063c5ba65091161017b578063e07cb240116100dc578063f6b8561a11610092578063fb2de5d71161006d578063fb2de5d714611272578063ff924f531461128c578063ffbcb4aa146112d7575f80fd5b8063f6b8561a1461121e578063f6e1ff8914610a5d578063f7a2000a14611238575f80fd5b8063e9a7be29116100c2578063e9a7be29146111c1578063eeca41a6146111e0578063f2fde38b146111ff575f80fd5b8063e07cb24014610aaa578063e34fda85146105d6575f80fd5b8063d5dc239a11610131578063db5f30a811610117578063db5f30a814611142578063dd71105d14611161578063df21dc1d14611180575f80fd5b8063d5dc239a14611104578063db188e6314611123575f80fd5b8063caee23ea11610161578063caee23ea14611080578063ccee9c511461109f578063cfea7ecf146110e5575f80fd5b8063c5ba65091461104c578063c815270e14611066575f80fd5b8063b3992ab111610230578063b97f6f8b116101e6578063c43f946b116101c1578063c43f946b14610fb6578063c44a076a1461100e578063c482160f1461102d575f80fd5b8063b97f6f8b14610f5e578063bc8aa28414610f7d578063c435f43514610f97575f80fd5b8063b89c4b0d11610216578063b89c4b0d14610d81578063b8dcc68f14610da0578063b955455214610dba575f80fd5b8063b3992ab114610d43578063b6e39ba114610d62575f80fd5b8063a029957911610285578063a4e28f7d1161026b578063a4e28f7d14610cab578063a87b03b614610cca578063ad1ff68514610d24575f80fd5b8063a029957914610a5d578063a20df79f14610c91575f80fd5b80638cdfc296116102b55780638cdfc29614610c0e5780638da5cb5b14610c2d5780639c84033414610c77575f80fd5b806386e1177414610bd057806389a9c85514610bef575f80fd5b80634be52a891161042e57806366e8304a1161038f57806378e890ba116103455780638254fcb7116103205780638254fcb714610b645780638567413514610b92578063859840a514610bb1575f80fd5b806378e890ba14610b045780637c1e14b414610b265780637df81b9014610b45575f80fd5b806371be859d1161037557806371be859d14610aaa578063725d07c514610ac45780637423eb3c14610af0575f80fd5b806366e8304a14610a5d578063715018a614610a96575f80fd5b8063539d2602116103e45780635ed5917f116103ca5780635ed5917f14610a3e57806363fc56bc14610a5d5780636498c04514610a77575f80fd5b8063539d260214610a00578063599d2c6214610a1f575f80fd5b80634f3c18fe116104145780634f3c18fe146109a3578063505efb65146109c257806350793315146109e1575f80fd5b80634be52a89146109145780634ca104b814610933575f80fd5b80631bb610e7116104e357806328cc1131116104995780633a0e3160116104745780633a0e3160146108ad5780633e8a0bc9146108cc5780633f6560ee146108e0575f80fd5b806328cc11311461083b5780632d975d141461085a5780633779e6fd14610879575f80fd5b806323c99262116104c957806323c992621461079157806327d21f50146107c2578063285fb8c81461081c575f80fd5b80631bb610e7146106de5780631f2fdc7914610735575f80fd5b8063136439dd1161053857806315ec12791161051e57806315ec1279146106675780631854b2411461069357806319007fc9146106b2575f80fd5b8063136439dd1461063557806314e4f88814610648575f80fd5b80630e14021a116105685780630e14021a146105d85780630f59197d146105f757806312d3848a14610616575f80fd5b806301ffc9a7146105835780630ad38899146105b7575b5f80fd5b34801561058e575f80fd5b506105a261059d3660046149d3565b611305565b60405190151581526020015b60405180910390f35b3480156105c2575f80fd5b506105d66105d1366004614a11565b611460565b005b3480156105e3575f80fd5b506105a26105f2366004614a6f565b61146d565b348015610602575f80fd5b506105a2610611366004614b12565b6114dd565b348015610621575f80fd5b506105a2610630366004614bca565b61155b565b6105d6610643366004614c1b565b6115c9565b348015610653575f80fd5b506105d6610662366004614c42565b6115da565b348015610672575f80fd5b50610686610681366004614c73565b611618565b6040516105ae9190614c9b565b34801561069e575f80fd5b506105d66106ad366004614bca565b611660565b3480156106bd575f80fd5b506106d16106cc366004614d1f565b61179c565b6040516105ae9190614d90565b3480156106e9575f80fd5b506106fd6106f8366004614e44565b611900565b6040805192151583527fffffffff000000000000000000000000000000000000000000000000000000009091166020830152016105ae565b348015610740575f80fd5b506105a261074f366004614ea6565b73ffffffffffffffffffffffffffffffffffffffff9091165f908152600660209081526040808320600885901c845290915290205460ff9091161c6001161590565b34801561079c575f80fd5b5062721c055465ffffffffffff165b60405165ffffffffffff90911681526020016105ae565b3480156107cd575f80fd5b506107e16107dc366004614ece565b611945565b604080517fffffffff00000000000000000000000000000000000000000000000000000000909316835261ffff9091166020830152016105ae565b348015610827575f80fd5b506105d6610836366004614f3a565b6119ad565b348015610846575f80fd5b506105d6610855366004614f7a565b6119bd565b348015610865575f80fd5b506106fd610874366004614faa565b6119ca565b348015610884575f80fd5b5061089861089336600461502d565b611a0e565b604080519283529015156020830152016105ae565b3480156108b8575f80fd5b506105d66108c7366004614ea6565b611a9a565b3480156108d7575f80fd5b506105d6611aab565b3480156108eb575f80fd5b506108ff6108fa3660046150e8565b611ae8565b604080519283526020830191909152016105ae565b34801561091f575f80fd5b506105a261092e366004615128565b611b08565b34801561093e575f80fd5b506105a261094d3660046151d5565b60ff9182165f90815262721c0a6020908152604080832065ffffffffffff96909616835294815284822073ffffffffffffffffffffffffffffffffffffffff939093168252600490920190915291909120541690565b3480156109ae575f80fd5b506107ab6109bd3660046151fe565b611b83565b3480156109cd575f80fd5b506106fd6109dc36600461527c565b611bbe565b3480156109ec575f80fd5b506105d66109fb3660046152cd565b611c01565b348015610a0b575f80fd5b506105d6610a1a36600461530f565b611c0e565b348015610a2a575f80fd5b506105d6610a393660046153ab565b611d23565b348015610a49575f80fd5b506105a2610a58366004615436565b611d5d565b348015610a68575f80fd5b506105d6610a393660046154c2565b348015610a82575f80fd5b506108ff610a9136600461551f565b611dcc565b348015610aa1575f80fd5b506105d6611ded565b348015610ab5575f80fd5b506105d6610a39366004614d1f565b348015610acf575f80fd5b50610ae3610ade366004614a11565b611e00565b6040516105ae9190615560565b348015610afb575f80fd5b506105d6611e32565b348015610b0f575f80fd5b50610b18611f65565b6040519081526020016105ae565b348015610b31575f80fd5b506105d6610b40366004614f3a565b611f73565b348015610b50575f80fd5b506105a2610b5f3660046155ad565b611fbe565b348015610b6f575f80fd5b506105a2610b7e366004614c1b565b5f9081526004602052604090205460ff1690565b348015610b9d575f80fd5b50610686610bac3660046155f5565b61202c565b348015610bbc575f80fd5b50610ae3610bcb366004614c73565b612061565b348015610bdb575f80fd5b506105d6610bea366004614ea6565b6120a2565b348015610bfa575f80fd5b506105a2610c09366004614a11565b61214f565b348015610c19575f80fd5b506105d6610c2836600461560f565b612201565b348015610c38575f80fd5b505f5473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016105ae565b348015610c82575f80fd5b506105d6610a3936600461564e565b348015610c9c575f80fd5b506107ab6109bd366004615676565b348015610cb6575f80fd5b506105a2610cc53660046156bd565b61220d565b348015610cd5575f80fd5b506105a2610ce43660046152cd565b73ffffffffffffffffffffffffffffffffffffffff9182165f90815262721c09602090815260408083209390941682526002909201909152205460ff1690565b348015610d2f575f80fd5b506105d6610d3e36600461551f565b61227a565b348015610d4e575f80fd5b506105a2610d5d3660046156d8565b61239d565b348015610d6d575f80fd5b506105d6610d7c366004614ea6565b612418565b348015610d8c575f80fd5b506105d6610d9b366004614ea6565b612424565b348015610dab575f80fd5b506107ab6109bd366004615756565b348015610dc5575f80fd5b50610ee5610dd4366004614a11565b6040805160c080820183525f80835260208084018290528385018290526060808501839052608080860184905260a095860184905273ffffffffffffffffffffffffffffffffffffffff978816845262721c08835292869020865194850187525460ff808216865265ffffffffffff610100830416938601939093526701000000000000008104909716958401959095527b010000000000000000000000000000000000000000000000000000008604169382019390935261ffff7c010000000000000000000000000000000000000000000000000000000085048116938201939093527e010000000000000000000000000000000000000000000000000000000000009093049091169082015290565b6040516105ae91905f60c08201905060ff835116825265ffffffffffff602084015116602083015273ffffffffffffffffffffffffffffffffffffffff604084015116604083015260ff6060840151166060830152608083015161ffff80821660808501528060a08601511660a0850152505092915050565b348015610f69575f80fd5b506105d6610f78366004615795565b612430565b348015610f88575f80fd5b506105d6610a39366004615806565b348015610fa2575f80fd5b506105d6610fb1366004614c1b565b612450565b348015610fc1575f80fd5b506105a2610fd036600461586b565b60ff9182165f90815262721c0a6020908152604080832065ffffffffffff969096168352948152848220928252600590920190915291909120541690565b348015611019575f80fd5b50610686611028366004614d1f565b61245a565b348015611038575f80fd5b50610ae36110473660046155f5565b612525565b348015611057575f80fd5b506105d6610662366004614a11565b348015611071575f80fd5b506105d6610a393660046158a4565b34801561108b575f80fd5b506105d661109a3660046155ad565b612557565b3480156110aa575f80fd5b506105a26110b9366004614a11565b73ffffffffffffffffffffffffffffffffffffffff165f90815262721c0d602052604090205460ff1690565b3480156110f0575f80fd5b506108986110ff3660046158be565b6125a3565b34801561110f575f80fd5b506105a261111e36600461596f565b61262e565b34801561112e575f80fd5b506105d661113d366004615756565b61269c565b34801561114d575f80fd5b506105d661115c366004615a07565b6127ac565b34801561116c575f80fd5b506105a261117b3660046155ad565b6127b8565b34801561118b575f80fd5b50610b1861119a366004614a11565b73ffffffffffffffffffffffffffffffffffffffff165f9081526007602052604090205490565b3480156111cc575f80fd5b50610c526111db366004615a30565b61281b565b3480156111eb575f80fd5b506105a26111fa366004615a49565b61287a565b34801561120a575f80fd5b506105d6611219366004614a11565b6128dc565b348015611229575f80fd5b506105d6610a39366004615a64565b348015611243575f80fd5b50600180547f0000000000000000000000000000000000000000000000000000000000000000909101906108ff565b34801561127d575f80fd5b506105d6610a39366004615a7d565b348015611297575f80fd5b50610c526112a6366004615a64565b65ffffffffffff165f90815262721c07602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b3480156112e2575f80fd5b506105a26112f1366004614c1b565b5f9081526005602052604090205460ff1690565b5f7fffffffff000000000000000000000000000000000000000000000000000000008216158061137657507fffffffff0000000000000000000000000000000000000000000000000000000082167f1bb3460e00000000000000000000000000000000000000000000000000000000145b806113c257507fffffffff0000000000000000000000000000000000000000000000000000000082167fc058083400000000000000000000000000000000000000000000000000000000145b8061140e57507fffffffff0000000000000000000000000000000000000000000000000000000082167f89a9c85500000000000000000000000000000000000000000000000000000000145b8061145a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b61146a815f612424565b50565b5f61149c60107f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b6114b06104838c8c8b8d8c8c8b8b8b612b61565b6114bd8b87878d88612c59565b905080156114cf576114cf868a612d1c565b9a9950505050505050505050565b5f836114e881612d97565b61151660107f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b6115298e8e8d8f8e8e8d8b8b8f8f612dde565b8c6115378f8b8b848c612c59565b92508215611549576115498a8e612d1c565b50509c9b505050505050505050505050565b5f61158a60027f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b5f61159b876104838787875f612df4565b90506115aa8588888787612c59565b915081156115bf576115bf81885f8681612f7d565b5095945050505050565b6115d16130d0565b61146a816130d8565b7f0000000000000000000000000000000000000000000000000000000000000000365f80375f80365f845af43d805f803e8161161457805ffd5b805ff35b73ffffffffffffffffffffffffffffffffffffffff82165f90815262721c08602052604090205460609061165990610100900465ffffffffffff168361202c565b9392505050565b5f611671600333888888888861311d565b5090507fffffffff000000000000000000000000000000000000000000000000000000008116156116a5576116a58161320f565b335f90815260208490526040902060041c6116e38163ffffffff7f000000000000000000000000000000000000000000000000000000000000000016565b15611793575f6116f4826001615ab2565b90505f611724827f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b905080851115611760576040517ff9e7abe700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611790828683037f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b50505b50505050505050565b606081156116595773ffffffffffffffffffffffffffffffffffffffff84165f90815262721c0c602052604090208267ffffffffffffffff8111156117e3576117e3615aea565b60405190808252806020026020018201604052801561181657816020015b60608152602001906001900390816118015790505b5091505f5b838110156118f757815f86868481811061183757611837615b17565b9050602002013581526020019081526020015f20805461185690615b44565b80601f016020809104026020016040519081016040528092919081815260200182805461188290615b44565b80156118cd5780601f106118a4576101008083540402835291602001916118cd565b820191905f5260205f20905b8154815290600101906020018083116118b057829003601f168201915b50505050508382815181106118e4576118e4615b17565b602090810291909101015260010161181b565b50509392505050565b5f80611912600389898989898961311d565b507fffffffff00000000000000000000000000000000000000000000000000000000811615999098509650505050505050565b5f80333014611980576040517ffa103f6700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61198a89613217565b9250905061199e818b8b8b8b8b8b8b6132d2565b92505097509795505050505050565b6119b8838383611f73565b505050565b6119b8600184848461333f565b5f806119dc600188888888885f61311d565b507fffffffff000000000000000000000000000000000000000000000000000000008116159890975095505050505050565b5f8082611a1a81613437565b611a4860407f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b5f611a5b8f8f8f8f8f8f8e8e8e8e61347e565b9050611a6f818e8e8e8e8e8c612c596134a3565b90945092508215611a8857611a88818b88876001612f7d565b50509b509b9950505050505050505050565b611aa7600183835f613699565b5050565b335f8181526007602052604080822080546001019055517f8e8cebe67607ce50a14a2e3261437f641a7b33ecc053e3d9c90b25ae5e66c6569190a2565b5f80611afa6002888888888887613741565b915091509550959350505050565b5f83611b1381612d97565b611b4160207f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b611b548d5f8d8f8e8e8d8b8b8f8f613802565b611b618d8a8a5f8b613817565b91508115611b7357611b73898d612d1c565b509b9a5050505050505050505050565b5f7f0000000000000000000000000000000000000000000000000000000000000000365f80375f80365f845af43d805f803e8161161457805ffd5b5f80611bd06002878787875f8061311d565b507fffffffff0000000000000000000000000000000000000000000000000000000081161597909650945050505050565b611aa782825f6001613699565b8365ffffffffffff16421115611c50576040517f827aed8000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611c598b613947565b611c638389613999565b611cef611ce7611ce28d8d8d8c78ffffffffffffffffffffffffffffffffffffffffffffffffff168e8d8d65ffffffffffff168d65ffffffffffff1660075f8f73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054613a13565b613ac0565b838386613b07565b65ffffffffffff851615611d035784611d05565b425b9450611d168b8b8b8a89888c613c04565b5050505050505050505050565b7f0000000000000000000000000000000000000000000000000000000000000000365f80375f80365f845af43d805f803e8161161457805ffd5b5f611d8c60087f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b611da26102d18a8a60018b8b8b60018b8b612b61565b611dae85858b8b613cff565b90508015611dc057611dc08588612d1c565b98975050505050505050565b5f80611dde6003898989898989613741565b91509150965096945050505050565b611df5613dad565b611dfe5f613dfd565b565b73ffffffffffffffffffffffffffffffffffffffff81165f90815262721c096020526040902060609061145a90613e71565b7f000000000000000000000000000000000000000000000000000000000000000080611e7f57507fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff165b15611eb6576040517ff45b98b000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611edf7f0000000000000000000000000000000000000000000000000000000000000000613e7d565b611f15576040517f70a4078f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b0080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055611dfe80565b5f611f6e613ee8565b905090565b5f611f846002338686865f8061311d565b5090507fffffffff00000000000000000000000000000000000000000000000000000000811615611fb857611fb88161320f565b50505050565b5f611fed60017f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b5f611fff866102d18686600180612df4565b905061200d86868686613cff565b915081156120235761202381875f600181612f7d565b50949350505050565b60ff81165f90815262721c0a6020908152604080832065ffffffffffff86168452909152902060609061165990600201613e71565b73ffffffffffffffffffffffffffffffffffffffff82165f90815262721c08602052604090205460609061165990610100900465ffffffffffff1683612525565b6120aa6130d0565b6120b35f6130d8565b8015611aa7575f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f811461210f576040519150601f19603f3d011682016040523d82523d5f602084013e612114565b606091505b50509050806119b8576040517f3f1df14400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f89a9c85500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301525f917f0000000000000000000000000000000000000000000000000000000000000000909116906389a9c85590602401602060405180830381865afa1580156121dd573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061145a9190615b8f565b611fb88484848461333f565b73ffffffffffffffffffffffffffffffffffffffff8381165f90815262721c08602090815260408083205460ff808816855262721c0a845282852061010090920465ffffffffffff168552908352818420948616845260049094019091528120549091165b949350505050565b3373ffffffffffffffffffffffffffffffffffffffff871614806122b357503373ffffffffffffffffffffffffffffffffffffffff8616145b6122e9576040517feda7110300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6122f284613947565b5f612303600388878787878c613fdc565b805490915060ff1661236b57600281556040516001815273ffffffffffffffffffffffffffffffffffffffff878116919089169084907f705db7ac401a8091bb37a7838ad73d1fa8e1c663cb345f347fefe71280e3f03b9060200160405180910390a4611793565b6040517f8cbf875200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f836123a881612d97565b6123d660087f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b6123eb8c8c60018d8d8d60018b8b8f8f6140ad565b6123f788888e8e613cff565b9150811561240957612409888b612d1c565b509a9950505050505050505050565b611aa75f83838261333f565b611aa75f838382613699565b61243986613947565b61244886868685853389613c04565b505050505050565b61146a3382613999565b606081156116595773ffffffffffffffffffffffffffffffffffffffff84165f90815262721c0b602052604090208267ffffffffffffffff8111156124a1576124a1615aea565b6040519080825280602002602001820160405280156124ca578160200160208202803683370190505b5091505f5b838110156118f757815f8686848181106124eb576124eb615b17565b9050602002013581526020019081526020015f205483828151811061251257612512615b17565b60209081029190910101526001016124cf565b60ff81165f90815262721c0a6020908152604080832065ffffffffffff86168452909152902060609061165990613e71565b5f612568600133878787875f61311d565b5090507fffffffff0000000000000000000000000000000000000000000000000000000081161561259c5761259c8161320f565b5050505050565b5f80826125af81613437565b6125dd60807f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b5f6125f08e8e8e8e5f8f8e8e8e8e6140c3565b9050612604818d8d5f8e8e8c6138176134a3565b9094509250821561261d5761261d818b88876001612f7d565b50509a509a98505050505050505050565b5f61265d60207f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b61267060148b5f8b8d8c8c8b8b8b612b61565b61267d8a87875f88613817565b9050801561268f5761268f868a612d1c565b9998505050505050505050565b600160045f6040518060e0016040528060a58152602001615cf260a5913985856040516020016126ce93929190615bae565b6040516020818303038152906040528051906020012081526020019081526020015f205f6101000a81548160ff021916908315150217905550600160055f6040518060c00160405280609d8152602001615c55609d9139858560405160200161273993929190615bae565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529181528151602092830120835290820192909252015f2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790555050565b6119b88383835f613699565b5f6127e760047f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b5f6127f7866014865f875f612df4565b90506128068487875f87613817565b915081156120235761202381875f8681612f7d565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0160ff83160161284d57505f919050565b5060ff165f90815262721c0e602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff83165f90815262721c08602090815260408083205460ff808716855262721c0a845282852061010090920465ffffffffffff16855290835281842085855260050190925282205416612272565b6128e4613dad565b73ffffffffffffffffffffffffffffffffffffffff8116612931576040517f3e58254b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61146a81613dfd565b80825d5050565b5c90565b5f815d50565b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff161561297c5780825d5050565b9055565b5f7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff16156129b057505c90565b5080545b919050565b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff16156129e9575f815d50565b5f9055565b7f0000000000000000000000000000000000000000000000000000000000000000344703111561146a5760015481161561146a576040517fcc47725a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000034470311612aaf576040517ffd2c901300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600154165f0361146a576040517ffd2c901300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f7f00000000000000000000000000000000000000000000000000000000000000003447031115612b1c57506001545b90565b60015481161561146a576040517fcc47725a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015490565b5f612c47611ce28c8c8c8c8c8c60075f8e73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054604080517f932b8553b8e35bbee682d275cbe1cf115e14a777e2ca3266b4797369fb6317d36020808301919091528183019990995273ffffffffffffffffffffffffffffffffffffffff979097166060880152608087019590955260a086019390935260c08501919091523360e085015261010084015261012080840191909152815180840390910181526101409092019052805191012090565b9050611d168787868b898689896140d8565b5f612c6a6104838787878787614162565b905080612d13576040517ff242432a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301528581166024830152604482018590526064820184905260a060848301525f60a483015287169063f242432a9060c4015f604051808303815f87803b158015612cfa575f80fd5b505af1925050508015612d0b575060015b612d13575060015b95945050505050565b73ffffffffffffffffffffffffffffffffffffffff82165f908152600660209081526040808320600885901c845290915290208054600160ff84161b908118918290551615611aa7576040517fe4adc0bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8181526004602052604090205460ff1661146a576040517f4722506e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611d166104838c8c8c8c8c8c8c8c8c8c8c61420e565b5f612e056002888888888633613fdc565b8054909150427a01000000000000000000000000000000000000000000000000000090910465ffffffffffff161015612e6a576040517f827aed8000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8054610100900478ffffffffffffffffffffffffffffffffffffffffffffffffff16831115612ec5576040517ffee142c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8115612ef65780547fffffffffffff00000000000000000000000000000000000000000000000000ff168155612f73565b805478ffffffffffffffffffffffffffffffffffffffffffffffffff61010090910481161015612f7357805478ffffffffffffffffffffffffffffffffffffffffffffffffff6101008083048216869003909116027fffffffffffff00000000000000000000000000000000000000000000000000ff9091161781555b9695505050505050565b811561259c57801561304e5784547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0078ffffffffffffffffffffffffffffffffffffffffffffffffff6101008084048216860190911602167fffffffffffff000000000000000000000000000000000000000000000000000090911617855560405182815273ffffffffffffffffffffffffffffffffffffffff85169084907f83e0ca2c1392f14286fa1e41c797789d48c5827572e8bcc352d8943c1961eaf09060200160405180910390a361259c565b845478ffffffffffffffffffffffffffffffffffffffffffffffffff6101009091048116101561259c57845478ffffffffffffffffffffffffffffffffffffffffffffffffff61010080830482168501909116027fffffffffffff00000000000000000000000000000000000000000000000000ff9091161785555050505050565b611dfe613dad565b600180549082905560408051828152602081018490527fe0d8d9ad73c586e8cf60ffd390b6f3654200a2d8857eb6abba4f6842a1210aae910160405180910390a15050565b5f803073ffffffffffffffffffffffffffffffffffffffff88160361314657505f905080613203565b6040517f27d21f50000000000000000000000000000000000000000000000000000000008152600481018a905273ffffffffffffffffffffffffffffffffffffffff808a166024830152808916604483015280881660648301528616608482015260a4810185905260c4810184905230906327d21f509060e4016040805180830381865afa1580156131da573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906131fe9190615bd4565b915091505b97509795505050505050565b805f5260045ffd5b73ffffffffffffffffffffffffffffffffffffffff81165f90815262721c0860205260408120805482919060ff90811610613274578054670100000000000000900473ffffffffffffffffffffffffffffffffffffffff166132a0565b805460ff165f90815262721c0e602052604090205473ffffffffffffffffffffffffffffffffffffffff165b905490947e0100000000000000000000000000000000000000000000000000000000000090910461ffff169350915050565b5f80630be200ea60e01b90506040518181528960048201528860248201528760448201528660648201528560848201528460a48201528360c482015260e4810160405260205f60e4838e5af490508061332e573d805f803e805ffd5b50505f519998505050505050505050565b82843361334d838383614241565b5f86815262721c06602052604090206133a1905b8873ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b5f86815260208690526040902060041c6133f58173ffffffffffffffffffffffffffffffffffffffff8a1663ffffffff7f000000000000000000000000000000000000000000000000000000000000000016565b61342d613403826001615ab2565b867f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b5050505050505050565b5f8181526005602052604090205460ff1661146a576040517f4722506e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6134948b8b8b6104838c8c8c8c8c8c8c61446c565b9b9a5050505050505050505050565b87546020880135905f90610100900478ffffffffffffffffffffffffffffffffffffffffffffffffff168211156134f9578954610100900478ffffffffffffffffffffffffffffffffffffffffffffffffff1691505b8860400135821015613537576040517fb9ff981500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b895478ffffffffffffffffffffffffffffffffffffffffffffffffff6101008083048216859003909116027fffffffffffff00000000000000000000000000000000000000000000000000ff909116178a55604051828152339073ffffffffffffffffffffffffffffffffffffffff88169086907f2203cb053e6b01ec07e87d67d288d360ae164171185684936663b7d8fa9c534c9060200160405180910390a48954610100900478ffffffffffffffffffffffffffffffffffffffffffffffffff165f036136795789547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001178a556040515f8152339073ffffffffffffffffffffffffffffffffffffffff88169086907f705db7ac401a8091bb37a7838ad73d1fa8e1c663cb345f347fefe71280e3f03b9060200160405180910390a45b61368a8887878a868863ffffffff16565b90509850989650505050505050565b8284336136a7838383614241565b5f86815262721c0660205260409020613728908873ffffffffffffffffffffffffffffffffffffffff16866136dc575f6136fe565b7f80000000000000000000000000000000000000000000000000000000000000005b177f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b61179361336187875f9182526020526040902060041c90565b5f805f6137538a8a898989898e613fdc565b8054909150427a01000000000000000000000000000000000000000000000000000090910465ffffffffffff16106137ac578054610100900478ffffffffffffffffffffffffffffffffffffffffffffffffff166137ae565b5f5b905478ffffffffffffffffffffffffffffffffffffffffffffffffff9091169a7a01000000000000000000000000000000000000000000000000000090910465ffffffffffff169950975050505050505050565b611d1660148c8c8c8c8c8c8c8c8c8c8c61420e565b5f61382760148787875f87614162565b905080612d13576040805173ffffffffffffffffffffffffffffffffffffffff87811660248301528681166044830152606480830186905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905291515f928392908a16916138cc9190615c01565b5f604051808303815f865af19150503d805f8114613905576040519150601f19603f3d011682016040523d82523d5f602084013e61390a565b606091505b50915091508161391d576001925061393c565b80511561393c57808060200190518101906139389190615b8f565b1592505b505095945050505050565b6102d1811480613958575061048381145b806139635750601481145b61146a576040517f9d36a97900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82165f908152600660209081526040808320600885901c845290915290208054600160ff84161b9081189182905516611aa7576040517fd979627300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080517ff9c04f8b028fcfa3315ea5accaee4589194a685f07cda0392e6ba9550706111960208201529081018a905273ffffffffffffffffffffffffffffffffffffffff808a1660608301526080820189905260a0820188905260c08201879052851660e08201526101008101849052610120810183905261014081018290525f90610160015b6040516020818303038152906040528051906020012090509998505050505050505050565b5f61145a613acc613ee8565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b6041829003613b85578235602084013560408501355f90811a9080613b2e8984878761464e565b915091508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16141580613b6a5750815b15613b7b57613b7b868a8a8a614722565b5050505050611fb8565b6040829003613bf857823560208401355f80613ba28885856147b4565b915091508073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16141580613bde5750815b15613bef57613bef85898989614722565b50505050611fb8565b611fb881858585614722565b5f613c156002848a8a8a8688613fdc565b805460ff167a01000000000000000000000000000000000000000000000000000065ffffffffffff87169081027fffffffffffff00000000000000000000000000000000000000000000000000ff169190911761010078ffffffffffffffffffffffffffffffffffffffffffffffffff8916908102919091178355604080518a8152602081019290925281019190915290915073ffffffffffffffffffffffffffffffffffffffff83811691898216918616907f0ec867d4f1b037422566cd0248bae620e6c142dcf5631948271916e8ca8dd2639060600160405180910390a45050505050505050565b5f613d116102d1848787866001614162565b905080612272576040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301528581166024830152604482018490528416906323b872dd906064015f604051808303815f87803b158015613d8d575f80fd5b505af1925050508015613d9e575060015b61227257506001949350505050565b5f5473ffffffffffffffffffffffffffffffffffffffff163314611dfe576040517f021943c000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60605f611659836147fb565b5f8173ffffffffffffffffffffffffffffffffffffffff16600a5a613ea29190615c1c565b6040515f8181818686fa925050503d805f8114613eda576040519150601f19603f3d011682016040523d82523d5f602084013e613edf565b606091505b50909392505050565b5f7f00000000000000000000000000000000000000000000000000000000000000004603613f3557507f000000000000000000000000000000000000000000000000000000000000000090565b611f6e604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b5f875f614058898989898973ffffffffffffffffffffffffffffffffffffffff9485165f818152600760209081526040918290205482518083019490945283830197909752949096166060820152608081019290925260a082015260c0808201939093528351808203909301835260e001909252805191012090565b81526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f209050979650505050505050565b611d166102d18c8c8c8c8c8c8c8c8c8c8c61420e565b5f6134948b8b8b60148c8c8c8c8c8c8c61446c565b86421115614112576040517fe3fd7ac300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8486111561414c576040517fde7fafeb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6141568489613999565b61342d83838387613b07565b5f805f6141866102d18a1461417857600361417b565b60015b89338a8a8a8a61311d565b909250905061ffff8116158061419f5750888161ffff16145b156141d0577fffffffff00000000000000000000000000000000000000000000000000000000821615159250614202565b6040517f7a535da600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50509695505050505050565b5f6142208d8d8d8d8b8e8e8a8a614854565b90506142328989888d8b868b8b6140d8565b50505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff83165f90815262721c086020526040902080547b010000000000000000000000000000000000000000000000000000009004600116156142c2576040517fb1ae736700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80547b0100000000000000000000000000000000000000000000000000000090046002161561435a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff84160161435a576040517fbf729bb100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8054610100900465ffffffffffff165f9081527f7e074e02264140693c3fbf3ca5a7e5aa542554b2d564345f76c58d7f98bdbbff6020908152604080832073ffffffffffffffffffffffffffffffffffffffff8616845260040190915290205460ff16611fb85780547b0100000000000000000000000000000000000000000000000000000090046008161580614435575073ffffffffffffffffffffffffffffffffffffffff82165f9081527f442599b958bf0d8fbe0ddbf2d50f16197374228cad346cd58d2da01fd8e057f8602052604090205460ff16155b15611fb8576040517fbc8ea06200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f78ffffffffffffffffffffffffffffffffffffffffffffffffff8a3511156144c1576040517f3b0a334300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6144d16003878b8b8b8833613fdc565b805490915060ff1661236b578054610100900478ffffffffffffffffffffffffffffffffffffffffffffffffff165f036145ed5761452a6145228a8a8a8e358b8b65ffffffffffff8c168b8b614854565b8d8d89613b07565b805460ff166101008b3578ffffffffffffffffffffffffffffffffffffffffffffffffff81169190910279ffffffffffffffffffffffffffffffffffffffffffffffffffff16919091177a01000000000000000000000000000000000000000000000000000065ffffffffffff871602178255604051908152339073ffffffffffffffffffffffffffffffffffffffff88169085907f257001e1f7fbfc5bbde5da225c876ab67293f37bda3afb8b35d9a55dfad6f65d9060200160405180910390a45b80547a010000000000000000000000000000000000000000000000000000900465ffffffffffff16421115613494576040517fe3fd7ac300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156146835750600190505f614719565b604080515f81526020810180835288905260ff871691810191909152606081018590526080810184905260019060a0016020604051602081039080840390855afa1580156146d3573d5f803e3d5ffd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015173ffffffffffffffffffffffffffffffffffffffff81161593509150505b94509492505050565b8373ffffffffffffffffffffffffffffffffffffffff163b5f03614772576040517f73c919b500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61477e8484848461488d565b611fb8576040517f73c919b500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316601b60ff85901c016147ed8782888561464e565b909890975095505050505050565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561484857602002820191905f5260205f20905b815481526020019060010190808311614834575b50505050509050919050565b73ffffffffffffffffffffffffffffffffffffffff85165f90815260076020526040812054613494611ce28c8c8c8c8b8b8b8b8a61493b565b5f61492f565b5f6040517f1626ba7e0000000000000000000000000000000000000000000000000000000081528360048201526040602482015285604482015285856064830137601f19601f87011660640180820160405260205f8284875afa60203d10151615614925577f1626ba7e000000000000000000000000000000000000000000000000000000005f511492505050612272565b5050949350505050565b612d1382848688614893565b60408051602081018490529081018a905273ffffffffffffffffffffffffffffffffffffffff891660608201526080810188905260a0810187905260c081018690523360e08201526101008101859052610120810182905261014081018490525f9061016001613a9b565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461146a575f80fd5b5f602082840312156149e3575f80fd5b8135611659816149a6565b803573ffffffffffffffffffffffffffffffffffffffff811681146129b4575f80fd5b5f60208284031215614a21575f80fd5b611659826149ee565b5f8083601f840112614a3a575f80fd5b50813567ffffffffffffffff811115614a51575f80fd5b602083019150836020828501011115614a68575f80fd5b9250929050565b5f805f805f805f805f806101208b8d031215614a89575f80fd5b614a928b6149ee565b995060208b0135985060408b0135975060608b0135965060808b01359550614abc60a08c016149ee565b9450614aca60c08c016149ee565b935060e08b013592506101008b013567ffffffffffffffff811115614aed575f80fd5b614af98d828e01614a2a565b915080935050809150509295989b9194979a5092959850565b5f805f805f805f805f805f806101608d8f031215614b2e575f80fd5b614b378d6149ee565b9b5060208d01359a5060408d0135995060608d0135985060808d01359750614b6160a08e016149ee565b9650614b6f60c08e016149ee565b955060e08d013594506101008d013593506101208d0135925067ffffffffffffffff6101408e01351115614ba1575f80fd5b614bb28e6101408f01358f01614a2a565b81935080925050509295989b509295989b509295989b565b5f805f805f60a08688031215614bde575f80fd5b614be7866149ee565b9450614bf5602087016149ee565b9350614c03604087016149ee565b94979396509394606081013594506080013592915050565b5f60208284031215614c2b575f80fd5b5035919050565b803560ff811681146129b4575f80fd5b5f8060408385031215614c53575f80fd5b614c5c83614c32565b9150614c6a602084016149ee565b90509250929050565b5f8060408385031215614c84575f80fd5b614c8d836149ee565b9150614c6a60208401614c32565b602080825282518282018190525f9190848201906040850190845b81811015614cd257835183529284019291840191600101614cb6565b50909695505050505050565b5f8083601f840112614cee575f80fd5b50813567ffffffffffffffff811115614d05575f80fd5b6020830191508360208260051b8501011115614a68575f80fd5b5f805f60408486031215614d31575f80fd5b614d3a846149ee565b9250602084013567ffffffffffffffff811115614d55575f80fd5b614d6186828701614cde565b9497909650939450505050565b5f5b83811015614d88578181015183820152602001614d70565b50505f910152565b5f602080830181845280855180835260408601915060408160051b87010192508387015f5b82811015614e37577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845281518051808752614dfa818989018a8501614d6e565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01695909501860194509285019290850190600101614db5565b5092979650505050505050565b5f805f805f8060c08789031215614e59575f80fd5b614e62876149ee565b9550614e70602088016149ee565b9450614e7e604088016149ee565b9350614e8c606088016149ee565b92506080870135915060a087013590509295509295509295565b5f8060408385031215614eb7575f80fd5b614ec0836149ee565b946020939093013593505050565b5f805f805f805f60e0888a031215614ee4575f80fd5b87359650614ef4602089016149ee565b9550614f02604089016149ee565b9450614f10606089016149ee565b9350614f1e608089016149ee565b925060a0880135915060c0880135905092959891949750929550565b5f805f60608486031215614f4c575f80fd5b614f55846149ee565b9250614f63602085016149ee565b9150614f71604085016149ee565b90509250925092565b5f805f60608486031215614f8c575f80fd5b614f95846149ee565b95602085013595506040909401359392505050565b5f805f805f60a08688031215614fbe575f80fd5b614fc7866149ee565b9450614fd5602087016149ee565b9350614fe3604087016149ee565b9250614ff1606087016149ee565b949793965091946080013592915050565b5f60608284031215615012575f80fd5b50919050565b803565ffffffffffff811681146129b4575f80fd5b5f805f805f805f805f805f6101808c8e031215615048575f80fd5b8b3567ffffffffffffffff81111561505e575f80fd5b61506a8e828f01614a2a565b909c509a5061507e90508d60208e01615002565b985061508c60808d016149ee565b975060a08c013596506150a160c08d016149ee565b95506150af60e08d016149ee565b94506101008c013593506150c66101208d01615018565b92506101408c013591506101608c013590509295989b509295989b9093969950565b5f805f805f60a086880312156150fc575f80fd5b615105866149ee565b9450615113602087016149ee565b935060408601359250614ff1606087016149ee565b5f805f805f805f805f805f6101408c8e031215615143575f80fd5b61514c8c6149ee565b9a5060208c0135995060408c0135985060608c0135975061516f60808d016149ee565b965061517d60a08d016149ee565b955060c08c0135945060e08c013593506101008c013592506101208c013567ffffffffffffffff8111156151af575f80fd5b6151bb8e828f01614a2a565b915080935050809150509295989b509295989b9093969950565b5f805f606084860312156151e7575f80fd5b6151f084615018565b9250614f6360208501614c32565b5f805f805f60608688031215615212575f80fd5b853567ffffffffffffffff80821115615229575f80fd5b61523589838a01614a2a565b909750955085915061524960208901615018565b9450604088013591508082111561525e575f80fd5b5061526b88828901614cde565b969995985093965092949392505050565b5f805f806080858703121561528f575f80fd5b615298856149ee565b93506152a6602086016149ee565b92506152b4604086016149ee565b91506152c2606086016149ee565b905092959194509250565b5f80604083850312156152de575f80fd5b614c5c836149ee565b803578ffffffffffffffffffffffffffffffffffffffffffffffffff811681146129b4575f80fd5b5f805f805f805f805f805f6101408c8e03121561532a575f80fd5b8b359a5061533a60208d016149ee565b995060408c0135985060608c0135975061535660808d016152e7565b965061536460a08d016149ee565b955061537260c08d01615018565b945061538060e08d01615018565b935061538f6101008d016149ee565b92506101208c013567ffffffffffffffff8111156151af575f80fd5b5f805f805f606086880312156153bf575f80fd5b6153c8866149ee565b9450602086013567ffffffffffffffff808211156153e4575f80fd5b818801915088601f8301126153f7575f80fd5b813581811115615405575f80fd5b8960208260061b8501011115615419575f80fd5b60208301965080955050604088013591508082111561525e575f80fd5b5f805f805f805f8060e0898b03121561544d575f80fd5b615456896149ee565b975060208901359650604089013595506060890135945061547960808a016149ee565b935061548760a08a016149ee565b925060c089013567ffffffffffffffff8111156154a2575f80fd5b6154ae8b828c01614a2a565b999c989b5096995094979396929594505050565b5f805f80606085870312156154d5575f80fd5b6154de85615018565b93506154ec60208601614c32565b9250604085013567ffffffffffffffff811115615507575f80fd5b61551387828801614cde565b95989497509550505050565b5f805f805f8060c08789031215615534575f80fd5b61553d876149ee565b955061554b602088016149ee565b945060408701359350614e8c606088016149ee565b602080825282518282018190525f9190848201906040850190845b81811015614cd257835173ffffffffffffffffffffffffffffffffffffffff168352928401929184019160010161557b565b5f805f80608085870312156155c0575f80fd5b6155c9856149ee565b93506155d7602086016149ee565b92506155e5604086016149ee565b9396929550929360600135925050565b5f8060408385031215615606575f80fd5b614c8d83615018565b5f805f8060808587031215615622575f80fd5b61562b856149ee565b9350615639602086016149ee565b93969395505050506040820135916060013590565b5f806040838503121561565f575f80fd5b615668836149ee565b9150614c6a60208401615018565b5f805f60408486031215615688575f80fd5b833567ffffffffffffffff81111561569e575f80fd5b6156aa86828701614a2a565b9094509250614f71905060208501615018565b5f805f606084860312156156cf575f80fd5b6151f0846149ee565b5f805f805f805f805f806101208b8d0312156156f2575f80fd5b6156fb8b6149ee565b995060208b0135985060408b0135975060608b0135965061571e60808c016149ee565b955061572c60a08c016149ee565b945060c08b0135935060e08b013592506101008b013567ffffffffffffffff811115614aed575f80fd5b5f8060208385031215615767575f80fd5b823567ffffffffffffffff81111561577d575f80fd5b61578985828601614a2a565b90969095509350505050565b5f805f805f8060c087890312156157aa575f80fd5b863595506157ba602088016149ee565b9450604087013593506157cf606088016149ee565b92506157dd608088016152e7565b91506157eb60a08801615018565b90509295509295509295565b61ffff8116811461146a575f80fd5b5f805f805f60a0868803121561581a575f80fd5b615823866149ee565b945061583160208701614c32565b935061583f604087016149ee565b925061584d60608701614c32565b9150608086013561585d816157f7565b809150509295509295909350565b5f805f6060848603121561587d575f80fd5b61588684615018565b925061589460208501614c32565b9150604084013590509250925092565b5f80604083850312156158b5575f80fd5b614c5c83615018565b5f805f805f805f805f806101608b8d0312156158d8575f80fd5b8a3567ffffffffffffffff8111156158ee575f80fd5b6158fa8d828e01614a2a565b909b50995061590e90508c60208d01615002565b975061591c60808c016149ee565b965061592a60a08c016149ee565b955061593860c08c016149ee565b945060e08b0135935061594e6101008c01615018565b92506101208b013591506101408b013590509295989b9194979a5092959850565b5f805f805f805f805f6101008a8c031215615988575f80fd5b6159918a6149ee565b985060208a0135975060408a0135965060608a013595506159b460808b016149ee565b94506159c260a08b016149ee565b935060c08a0135925060e08a013567ffffffffffffffff8111156159e4575f80fd5b6159f08c828d01614a2a565b915080935050809150509295985092959850929598565b5f805f60608486031215615a19575f80fd5b615a22846149ee565b9250615894602085016149ee565b5f60208284031215615a40575f80fd5b61165982614c32565b5f805f60608486031215615a5b575f80fd5b615886846149ee565b5f60208284031215615a74575f80fd5b61165982615018565b5f8060408385031215615a8e575f80fd5b615a97836149ee565b91506020830135615aa7816157f7565b809150509250929050565b8082018082111561145a577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b600181811c90821680615b5857607f821691505b602082108103615012577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60208284031215615b9f575f80fd5b81518015158114611659575f80fd5b5f8451615bbf818460208901614d6e565b8201838582375f930192835250909392505050565b5f8060408385031215615be5575f80fd5b8251615bf0816149a6565b6020840151909250615aa7816157f7565b5f8251615c12818460208701614d6e565b9190910192915050565b5f82615c4f577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b50049056fe5065726d69744f72646572576974684164646974696f6e616c446174612875696e7432353620746f6b656e547970652c6164647265737320746f6b656e2c75696e743235362069642c75696e7432353620616d6f756e742c75696e743235362073616c742c61646472657373206f70657261746f722c75696e743235362065787069726174696f6e2c75696e74323536206d61737465724e6f6e63652c5065726d69745472616e7366657246726f6d576974684164646974696f6e616c446174612875696e7432353620746f6b656e547970652c6164647265737320746f6b656e2c75696e743235362069642c75696e7432353620616d6f756e742c75696e74323536206e6f6e63652c61646472657373206f70657261746f722c75696e743235362065787069726174696f6e2c75696e74323536206d61737465724e6f6e63652ca26469706673582212203c722515cb1b94dd8d752f9b83ae90dcbec2eb559da6ba5732cbef23b095379164736f6c63430008180033dacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b00000000000000000000000000591aa9dff01b8144dc17cb416001d9ac84b951cd000000000000000000000000e0a0004dfa318fc38298ae81a666710eadceba5c000000000000000000000000721c002d2cae3522602b93a0c48e11dc573a15e3000000000000000000000000721c0086cc4f335407cc84a38ce7dcb1560476b000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000001d43726561746f72546f6b656e5472616e7366657256616c696461746f7200000000000000000000000000000000000000000000000000000000000000000000013500000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x60806040526004361061057f575f3560e01c806386e11774116102cf578063c5ba65091161017b578063e07cb240116100dc578063f6b8561a11610092578063fb2de5d71161006d578063fb2de5d714611272578063ff924f531461128c578063ffbcb4aa146112d7575f80fd5b8063f6b8561a1461121e578063f6e1ff8914610a5d578063f7a2000a14611238575f80fd5b8063e9a7be29116100c2578063e9a7be29146111c1578063eeca41a6146111e0578063f2fde38b146111ff575f80fd5b8063e07cb24014610aaa578063e34fda85146105d6575f80fd5b8063d5dc239a11610131578063db5f30a811610117578063db5f30a814611142578063dd71105d14611161578063df21dc1d14611180575f80fd5b8063d5dc239a14611104578063db188e6314611123575f80fd5b8063caee23ea11610161578063caee23ea14611080578063ccee9c511461109f578063cfea7ecf146110e5575f80fd5b8063c5ba65091461104c578063c815270e14611066575f80fd5b8063b3992ab111610230578063b97f6f8b116101e6578063c43f946b116101c1578063c43f946b14610fb6578063c44a076a1461100e578063c482160f1461102d575f80fd5b8063b97f6f8b14610f5e578063bc8aa28414610f7d578063c435f43514610f97575f80fd5b8063b89c4b0d11610216578063b89c4b0d14610d81578063b8dcc68f14610da0578063b955455214610dba575f80fd5b8063b3992ab114610d43578063b6e39ba114610d62575f80fd5b8063a029957911610285578063a4e28f7d1161026b578063a4e28f7d14610cab578063a87b03b614610cca578063ad1ff68514610d24575f80fd5b8063a029957914610a5d578063a20df79f14610c91575f80fd5b80638cdfc296116102b55780638cdfc29614610c0e5780638da5cb5b14610c2d5780639c84033414610c77575f80fd5b806386e1177414610bd057806389a9c85514610bef575f80fd5b80634be52a891161042e57806366e8304a1161038f57806378e890ba116103455780638254fcb7116103205780638254fcb714610b645780638567413514610b92578063859840a514610bb1575f80fd5b806378e890ba14610b045780637c1e14b414610b265780637df81b9014610b45575f80fd5b806371be859d1161037557806371be859d14610aaa578063725d07c514610ac45780637423eb3c14610af0575f80fd5b806366e8304a14610a5d578063715018a614610a96575f80fd5b8063539d2602116103e45780635ed5917f116103ca5780635ed5917f14610a3e57806363fc56bc14610a5d5780636498c04514610a77575f80fd5b8063539d260214610a00578063599d2c6214610a1f575f80fd5b80634f3c18fe116104145780634f3c18fe146109a3578063505efb65146109c257806350793315146109e1575f80fd5b80634be52a89146109145780634ca104b814610933575f80fd5b80631bb610e7116104e357806328cc1131116104995780633a0e3160116104745780633a0e3160146108ad5780633e8a0bc9146108cc5780633f6560ee146108e0575f80fd5b806328cc11311461083b5780632d975d141461085a5780633779e6fd14610879575f80fd5b806323c99262116104c957806323c992621461079157806327d21f50146107c2578063285fb8c81461081c575f80fd5b80631bb610e7146106de5780631f2fdc7914610735575f80fd5b8063136439dd1161053857806315ec12791161051e57806315ec1279146106675780631854b2411461069357806319007fc9146106b2575f80fd5b8063136439dd1461063557806314e4f88814610648575f80fd5b80630e14021a116105685780630e14021a146105d85780630f59197d146105f757806312d3848a14610616575f80fd5b806301ffc9a7146105835780630ad38899146105b7575b5f80fd5b34801561058e575f80fd5b506105a261059d3660046149d3565b611305565b60405190151581526020015b60405180910390f35b3480156105c2575f80fd5b506105d66105d1366004614a11565b611460565b005b3480156105e3575f80fd5b506105a26105f2366004614a6f565b61146d565b348015610602575f80fd5b506105a2610611366004614b12565b6114dd565b348015610621575f80fd5b506105a2610630366004614bca565b61155b565b6105d6610643366004614c1b565b6115c9565b348015610653575f80fd5b506105d6610662366004614c42565b6115da565b348015610672575f80fd5b50610686610681366004614c73565b611618565b6040516105ae9190614c9b565b34801561069e575f80fd5b506105d66106ad366004614bca565b611660565b3480156106bd575f80fd5b506106d16106cc366004614d1f565b61179c565b6040516105ae9190614d90565b3480156106e9575f80fd5b506106fd6106f8366004614e44565b611900565b6040805192151583527fffffffff000000000000000000000000000000000000000000000000000000009091166020830152016105ae565b348015610740575f80fd5b506105a261074f366004614ea6565b73ffffffffffffffffffffffffffffffffffffffff9091165f908152600660209081526040808320600885901c845290915290205460ff9091161c6001161590565b34801561079c575f80fd5b5062721c055465ffffffffffff165b60405165ffffffffffff90911681526020016105ae565b3480156107cd575f80fd5b506107e16107dc366004614ece565b611945565b604080517fffffffff00000000000000000000000000000000000000000000000000000000909316835261ffff9091166020830152016105ae565b348015610827575f80fd5b506105d6610836366004614f3a565b6119ad565b348015610846575f80fd5b506105d6610855366004614f7a565b6119bd565b348015610865575f80fd5b506106fd610874366004614faa565b6119ca565b348015610884575f80fd5b5061089861089336600461502d565b611a0e565b604080519283529015156020830152016105ae565b3480156108b8575f80fd5b506105d66108c7366004614ea6565b611a9a565b3480156108d7575f80fd5b506105d6611aab565b3480156108eb575f80fd5b506108ff6108fa3660046150e8565b611ae8565b604080519283526020830191909152016105ae565b34801561091f575f80fd5b506105a261092e366004615128565b611b08565b34801561093e575f80fd5b506105a261094d3660046151d5565b60ff9182165f90815262721c0a6020908152604080832065ffffffffffff96909616835294815284822073ffffffffffffffffffffffffffffffffffffffff939093168252600490920190915291909120541690565b3480156109ae575f80fd5b506107ab6109bd3660046151fe565b611b83565b3480156109cd575f80fd5b506106fd6109dc36600461527c565b611bbe565b3480156109ec575f80fd5b506105d66109fb3660046152cd565b611c01565b348015610a0b575f80fd5b506105d6610a1a36600461530f565b611c0e565b348015610a2a575f80fd5b506105d6610a393660046153ab565b611d23565b348015610a49575f80fd5b506105a2610a58366004615436565b611d5d565b348015610a68575f80fd5b506105d6610a393660046154c2565b348015610a82575f80fd5b506108ff610a9136600461551f565b611dcc565b348015610aa1575f80fd5b506105d6611ded565b348015610ab5575f80fd5b506105d6610a39366004614d1f565b348015610acf575f80fd5b50610ae3610ade366004614a11565b611e00565b6040516105ae9190615560565b348015610afb575f80fd5b506105d6611e32565b348015610b0f575f80fd5b50610b18611f65565b6040519081526020016105ae565b348015610b31575f80fd5b506105d6610b40366004614f3a565b611f73565b348015610b50575f80fd5b506105a2610b5f3660046155ad565b611fbe565b348015610b6f575f80fd5b506105a2610b7e366004614c1b565b5f9081526004602052604090205460ff1690565b348015610b9d575f80fd5b50610686610bac3660046155f5565b61202c565b348015610bbc575f80fd5b50610ae3610bcb366004614c73565b612061565b348015610bdb575f80fd5b506105d6610bea366004614ea6565b6120a2565b348015610bfa575f80fd5b506105a2610c09366004614a11565b61214f565b348015610c19575f80fd5b506105d6610c2836600461560f565b612201565b348015610c38575f80fd5b505f5473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016105ae565b348015610c82575f80fd5b506105d6610a3936600461564e565b348015610c9c575f80fd5b506107ab6109bd366004615676565b348015610cb6575f80fd5b506105a2610cc53660046156bd565b61220d565b348015610cd5575f80fd5b506105a2610ce43660046152cd565b73ffffffffffffffffffffffffffffffffffffffff9182165f90815262721c09602090815260408083209390941682526002909201909152205460ff1690565b348015610d2f575f80fd5b506105d6610d3e36600461551f565b61227a565b348015610d4e575f80fd5b506105a2610d5d3660046156d8565b61239d565b348015610d6d575f80fd5b506105d6610d7c366004614ea6565b612418565b348015610d8c575f80fd5b506105d6610d9b366004614ea6565b612424565b348015610dab575f80fd5b506107ab6109bd366004615756565b348015610dc5575f80fd5b50610ee5610dd4366004614a11565b6040805160c080820183525f80835260208084018290528385018290526060808501839052608080860184905260a095860184905273ffffffffffffffffffffffffffffffffffffffff978816845262721c08835292869020865194850187525460ff808216865265ffffffffffff610100830416938601939093526701000000000000008104909716958401959095527b010000000000000000000000000000000000000000000000000000008604169382019390935261ffff7c010000000000000000000000000000000000000000000000000000000085048116938201939093527e010000000000000000000000000000000000000000000000000000000000009093049091169082015290565b6040516105ae91905f60c08201905060ff835116825265ffffffffffff602084015116602083015273ffffffffffffffffffffffffffffffffffffffff604084015116604083015260ff6060840151166060830152608083015161ffff80821660808501528060a08601511660a0850152505092915050565b348015610f69575f80fd5b506105d6610f78366004615795565b612430565b348015610f88575f80fd5b506105d6610a39366004615806565b348015610fa2575f80fd5b506105d6610fb1366004614c1b565b612450565b348015610fc1575f80fd5b506105a2610fd036600461586b565b60ff9182165f90815262721c0a6020908152604080832065ffffffffffff969096168352948152848220928252600590920190915291909120541690565b348015611019575f80fd5b50610686611028366004614d1f565b61245a565b348015611038575f80fd5b50610ae36110473660046155f5565b612525565b348015611057575f80fd5b506105d6610662366004614a11565b348015611071575f80fd5b506105d6610a393660046158a4565b34801561108b575f80fd5b506105d661109a3660046155ad565b612557565b3480156110aa575f80fd5b506105a26110b9366004614a11565b73ffffffffffffffffffffffffffffffffffffffff165f90815262721c0d602052604090205460ff1690565b3480156110f0575f80fd5b506108986110ff3660046158be565b6125a3565b34801561110f575f80fd5b506105a261111e36600461596f565b61262e565b34801561112e575f80fd5b506105d661113d366004615756565b61269c565b34801561114d575f80fd5b506105d661115c366004615a07565b6127ac565b34801561116c575f80fd5b506105a261117b3660046155ad565b6127b8565b34801561118b575f80fd5b50610b1861119a366004614a11565b73ffffffffffffffffffffffffffffffffffffffff165f9081526007602052604090205490565b3480156111cc575f80fd5b50610c526111db366004615a30565b61281b565b3480156111eb575f80fd5b506105a26111fa366004615a49565b61287a565b34801561120a575f80fd5b506105d6611219366004614a11565b6128dc565b348015611229575f80fd5b506105d6610a39366004615a64565b348015611243575f80fd5b50600180547f0000000000000000000000000000000000000000000000000494654067e0ffff909101906108ff565b34801561127d575f80fd5b506105d6610a39366004615a7d565b348015611297575f80fd5b50610c526112a6366004615a64565b65ffffffffffff165f90815262721c07602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b3480156112e2575f80fd5b506105a26112f1366004614c1b565b5f9081526005602052604090205460ff1690565b5f7fffffffff000000000000000000000000000000000000000000000000000000008216158061137657507fffffffff0000000000000000000000000000000000000000000000000000000082167f1bb3460e00000000000000000000000000000000000000000000000000000000145b806113c257507fffffffff0000000000000000000000000000000000000000000000000000000082167fc058083400000000000000000000000000000000000000000000000000000000145b8061140e57507fffffffff0000000000000000000000000000000000000000000000000000000082167f89a9c85500000000000000000000000000000000000000000000000000000000145b8061145a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b61146a815f612424565b50565b5f61149c60107f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b6114b06104838c8c8b8d8c8c8b8b8b612b61565b6114bd8b87878d88612c59565b905080156114cf576114cf868a612d1c565b9a9950505050505050505050565b5f836114e881612d97565b61151660107f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b6115298e8e8d8f8e8e8d8b8b8f8f612dde565b8c6115378f8b8b848c612c59565b92508215611549576115498a8e612d1c565b50509c9b505050505050505050505050565b5f61158a60027f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b5f61159b876104838787875f612df4565b90506115aa8588888787612c59565b915081156115bf576115bf81885f8681612f7d565b5095945050505050565b6115d16130d0565b61146a816130d8565b7f000000000000000000000000721c0086cc4f335407cc84a38ce7dcb1560476b0365f80375f80365f845af43d805f803e8161161457805ffd5b805ff35b73ffffffffffffffffffffffffffffffffffffffff82165f90815262721c08602052604090205460609061165990610100900465ffffffffffff168361202c565b9392505050565b5f611671600333888888888861311d565b5090507fffffffff000000000000000000000000000000000000000000000000000000008116156116a5576116a58161320f565b335f90815260208490526040902060041c6116e38163ffffffff7f000000000000000000000000000000000000000000000000000003eb0000294116565b15611793575f6116f4826001615ab2565b90505f611724827f000000000000000000000000000000000000000000000000000003eb0000294163ffffffff16565b905080851115611760576040517ff9e7abe700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611790828683037f000000000000000000000000000000000000000000000000000003e40000293a63ffffffff16565b50505b50505050505050565b606081156116595773ffffffffffffffffffffffffffffffffffffffff84165f90815262721c0c602052604090208267ffffffffffffffff8111156117e3576117e3615aea565b60405190808252806020026020018201604052801561181657816020015b60608152602001906001900390816118015790505b5091505f5b838110156118f757815f86868481811061183757611837615b17565b9050602002013581526020019081526020015f20805461185690615b44565b80601f016020809104026020016040519081016040528092919081815260200182805461188290615b44565b80156118cd5780601f106118a4576101008083540402835291602001916118cd565b820191905f5260205f20905b8154815290600101906020018083116118b057829003601f168201915b50505050508382815181106118e4576118e4615b17565b602090810291909101015260010161181b565b50509392505050565b5f80611912600389898989898961311d565b507fffffffff00000000000000000000000000000000000000000000000000000000811615999098509650505050505050565b5f80333014611980576040517ffa103f6700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61198a89613217565b9250905061199e818b8b8b8b8b8b8b6132d2565b92505097509795505050505050565b6119b8838383611f73565b505050565b6119b8600184848461333f565b5f806119dc600188888888885f61311d565b507fffffffff000000000000000000000000000000000000000000000000000000008116159890975095505050505050565b5f8082611a1a81613437565b611a4860407f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b5f611a5b8f8f8f8f8f8f8e8e8e8e61347e565b9050611a6f818e8e8e8e8e8c612c596134a3565b90945092508215611a8857611a88818b88876001612f7d565b50509b509b9950505050505050505050565b611aa7600183835f613699565b5050565b335f8181526007602052604080822080546001019055517f8e8cebe67607ce50a14a2e3261437f641a7b33ecc053e3d9c90b25ae5e66c6569190a2565b5f80611afa6002888888888887613741565b915091509550959350505050565b5f83611b1381612d97565b611b4160207f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b611b548d5f8d8f8e8e8d8b8b8f8f613802565b611b618d8a8a5f8b613817565b91508115611b7357611b73898d612d1c565b509b9a5050505050505050505050565b5f7f000000000000000000000000721c002d2cae3522602b93a0c48e11dc573a15e3365f80375f80365f845af43d805f803e8161161457805ffd5b5f80611bd06002878787875f8061311d565b507fffffffff0000000000000000000000000000000000000000000000000000000081161597909650945050505050565b611aa782825f6001613699565b8365ffffffffffff16421115611c50576040517f827aed8000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611c598b613947565b611c638389613999565b611cef611ce7611ce28d8d8d8c78ffffffffffffffffffffffffffffffffffffffffffffffffff168e8d8d65ffffffffffff168d65ffffffffffff1660075f8f73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054613a13565b613ac0565b838386613b07565b65ffffffffffff851615611d035784611d05565b425b9450611d168b8b8b8a89888c613c04565b5050505050505050505050565b7f000000000000000000000000721c002d2cae3522602b93a0c48e11dc573a15e3365f80375f80365f845af43d805f803e8161161457805ffd5b5f611d8c60087f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b611da26102d18a8a60018b8b8b60018b8b612b61565b611dae85858b8b613cff565b90508015611dc057611dc08588612d1c565b98975050505050505050565b5f80611dde6003898989898989613741565b91509150965096945050505050565b611df5613dad565b611dfe5f613dfd565b565b73ffffffffffffffffffffffffffffffffffffffff81165f90815262721c096020526040902060609061145a90613e71565b7f000000000000000000000000000000000000000000000000000000000000000180611e7f57507fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff165b15611eb6576040517ff45b98b000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611edf7f00000000000000000000000079a95940c17a9a8148633a11ff9d0ddcffd9c00d613e7d565b611f15576040517f70a4078f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b0080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055611dfe80565b5f611f6e613ee8565b905090565b5f611f846002338686865f8061311d565b5090507fffffffff00000000000000000000000000000000000000000000000000000000811615611fb857611fb88161320f565b50505050565b5f611fed60017f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b5f611fff866102d18686600180612df4565b905061200d86868686613cff565b915081156120235761202381875f600181612f7d565b50949350505050565b60ff81165f90815262721c0a6020908152604080832065ffffffffffff86168452909152902060609061165990600201613e71565b73ffffffffffffffffffffffffffffffffffffffff82165f90815262721c08602052604090205460609061165990610100900465ffffffffffff1683612525565b6120aa6130d0565b6120b35f6130d8565b8015611aa7575f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f811461210f576040519150601f19603f3d011682016040523d82523d5f602084013e612114565b606091505b50509050806119b8576040517f3f1df14400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f89a9c85500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301525f917f000000000000000000000000e0a0004dfa318fc38298ae81a666710eadceba5c909116906389a9c85590602401602060405180830381865afa1580156121dd573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061145a9190615b8f565b611fb88484848461333f565b73ffffffffffffffffffffffffffffffffffffffff8381165f90815262721c08602090815260408083205460ff808816855262721c0a845282852061010090920465ffffffffffff168552908352818420948616845260049094019091528120549091165b949350505050565b3373ffffffffffffffffffffffffffffffffffffffff871614806122b357503373ffffffffffffffffffffffffffffffffffffffff8616145b6122e9576040517feda7110300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6122f284613947565b5f612303600388878787878c613fdc565b805490915060ff1661236b57600281556040516001815273ffffffffffffffffffffffffffffffffffffffff878116919089169084907f705db7ac401a8091bb37a7838ad73d1fa8e1c663cb345f347fefe71280e3f03b9060200160405180910390a4611793565b6040517f8cbf875200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f836123a881612d97565b6123d660087f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b6123eb8c8c60018d8d8d60018b8b8f8f6140ad565b6123f788888e8e613cff565b9150811561240957612409888b612d1c565b509a9950505050505050505050565b611aa75f83838261333f565b611aa75f838382613699565b61243986613947565b61244886868685853389613c04565b505050505050565b61146a3382613999565b606081156116595773ffffffffffffffffffffffffffffffffffffffff84165f90815262721c0b602052604090208267ffffffffffffffff8111156124a1576124a1615aea565b6040519080825280602002602001820160405280156124ca578160200160208202803683370190505b5091505f5b838110156118f757815f8686848181106124eb576124eb615b17565b9050602002013581526020019081526020015f205483828151811061251257612512615b17565b60209081029190910101526001016124cf565b60ff81165f90815262721c0a6020908152604080832065ffffffffffff86168452909152902060609061165990613e71565b5f612568600133878787875f61311d565b5090507fffffffff0000000000000000000000000000000000000000000000000000000081161561259c5761259c8161320f565b5050505050565b5f80826125af81613437565b6125dd60807f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b5f6125f08e8e8e8e5f8f8e8e8e8e6140c3565b9050612604818d8d5f8e8e8c6138176134a3565b9094509250821561261d5761261d818b88876001612f7d565b50509a509a98505050505050505050565b5f61265d60207f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b61267060148b5f8b8d8c8c8b8b8b612b61565b61267d8a87875f88613817565b9050801561268f5761268f868a612d1c565b9998505050505050505050565b600160045f6040518060e0016040528060a58152602001615cf260a5913985856040516020016126ce93929190615bae565b6040516020818303038152906040528051906020012081526020019081526020015f205f6101000a81548160ff021916908315150217905550600160055f6040518060c00160405280609d8152602001615c55609d9139858560405160200161273993929190615bae565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529181528151602092830120835290820192909252015f2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790555050565b6119b88383835f613699565b5f6127e760047f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b5f6127f7866014865f875f612df4565b90506128068487875f87613817565b915081156120235761202381875f8681612f7d565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0160ff83160161284d57505f919050565b5060ff165f90815262721c0e602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff83165f90815262721c08602090815260408083205460ff808716855262721c0a845282852061010090920465ffffffffffff16855290835281842085855260050190925282205416612272565b6128e4613dad565b73ffffffffffffffffffffffffffffffffffffffff8116612931576040517f3e58254b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61146a81613dfd565b80825d5050565b5c90565b5f815d50565b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff161561297c5780825d5050565b9055565b5f7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff16156129b057505c90565b5080545b919050565b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff16156129e9575f815d50565b5f9055565b7f0000000000000000000000000000000000000000000000000494654067e0ffff344703111561146a5760015481161561146a576040517fcc47725a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000494654067e0ffff34470311612aaf576040517ffd2c901300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600154165f0361146a576040517ffd2c901300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f7f0000000000000000000000000000000000000000000000000494654067e0ffff3447031115612b1c57506001545b90565b60015481161561146a576040517fcc47725a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015490565b5f612c47611ce28c8c8c8c8c8c60075f8e73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054604080517f932b8553b8e35bbee682d275cbe1cf115e14a777e2ca3266b4797369fb6317d36020808301919091528183019990995273ffffffffffffffffffffffffffffffffffffffff979097166060880152608087019590955260a086019390935260c08501919091523360e085015261010084015261012080840191909152815180840390910181526101409092019052805191012090565b9050611d168787868b898689896140d8565b5f612c6a6104838787878787614162565b905080612d13576040517ff242432a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301528581166024830152604482018590526064820184905260a060848301525f60a483015287169063f242432a9060c4015f604051808303815f87803b158015612cfa575f80fd5b505af1925050508015612d0b575060015b612d13575060015b95945050505050565b73ffffffffffffffffffffffffffffffffffffffff82165f908152600660209081526040808320600885901c845290915290208054600160ff84161b908118918290551615611aa7576040517fe4adc0bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8181526004602052604090205460ff1661146a576040517f4722506e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611d166104838c8c8c8c8c8c8c8c8c8c8c61420e565b5f612e056002888888888633613fdc565b8054909150427a01000000000000000000000000000000000000000000000000000090910465ffffffffffff161015612e6a576040517f827aed8000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8054610100900478ffffffffffffffffffffffffffffffffffffffffffffffffff16831115612ec5576040517ffee142c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8115612ef65780547fffffffffffff00000000000000000000000000000000000000000000000000ff168155612f73565b805478ffffffffffffffffffffffffffffffffffffffffffffffffff61010090910481161015612f7357805478ffffffffffffffffffffffffffffffffffffffffffffffffff6101008083048216869003909116027fffffffffffff00000000000000000000000000000000000000000000000000ff9091161781555b9695505050505050565b811561259c57801561304e5784547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0078ffffffffffffffffffffffffffffffffffffffffffffffffff6101008084048216860190911602167fffffffffffff000000000000000000000000000000000000000000000000000090911617855560405182815273ffffffffffffffffffffffffffffffffffffffff85169084907f83e0ca2c1392f14286fa1e41c797789d48c5827572e8bcc352d8943c1961eaf09060200160405180910390a361259c565b845478ffffffffffffffffffffffffffffffffffffffffffffffffff6101009091048116101561259c57845478ffffffffffffffffffffffffffffffffffffffffffffffffff61010080830482168501909116027fffffffffffff00000000000000000000000000000000000000000000000000ff9091161785555050505050565b611dfe613dad565b600180549082905560408051828152602081018490527fe0d8d9ad73c586e8cf60ffd390b6f3654200a2d8857eb6abba4f6842a1210aae910160405180910390a15050565b5f803073ffffffffffffffffffffffffffffffffffffffff88160361314657505f905080613203565b6040517f27d21f50000000000000000000000000000000000000000000000000000000008152600481018a905273ffffffffffffffffffffffffffffffffffffffff808a166024830152808916604483015280881660648301528616608482015260a4810185905260c4810184905230906327d21f509060e4016040805180830381865afa1580156131da573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906131fe9190615bd4565b915091505b97509795505050505050565b805f5260045ffd5b73ffffffffffffffffffffffffffffffffffffffff81165f90815262721c0860205260408120805482919060ff90811610613274578054670100000000000000900473ffffffffffffffffffffffffffffffffffffffff166132a0565b805460ff165f90815262721c0e602052604090205473ffffffffffffffffffffffffffffffffffffffff165b905490947e0100000000000000000000000000000000000000000000000000000000000090910461ffff169350915050565b5f80630be200ea60e01b90506040518181528960048201528860248201528760448201528660648201528560848201528460a48201528360c482015260e4810160405260205f60e4838e5af490508061332e573d805f803e805ffd5b50505f519998505050505050505050565b82843361334d838383614241565b5f86815262721c06602052604090206133a1905b8873ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000003e40000293a63ffffffff16565b5f86815260208690526040902060041c6133f58173ffffffffffffffffffffffffffffffffffffffff8a1663ffffffff7f000000000000000000000000000000000000000000000000000003e40000293a16565b61342d613403826001615ab2565b867f000000000000000000000000000000000000000000000000000003e40000293a63ffffffff16565b5050505050505050565b5f8181526005602052604090205460ff1661146a576040517f4722506e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6134948b8b8b6104838c8c8c8c8c8c8c61446c565b9b9a5050505050505050505050565b87546020880135905f90610100900478ffffffffffffffffffffffffffffffffffffffffffffffffff168211156134f9578954610100900478ffffffffffffffffffffffffffffffffffffffffffffffffff1691505b8860400135821015613537576040517fb9ff981500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b895478ffffffffffffffffffffffffffffffffffffffffffffffffff6101008083048216859003909116027fffffffffffff00000000000000000000000000000000000000000000000000ff909116178a55604051828152339073ffffffffffffffffffffffffffffffffffffffff88169086907f2203cb053e6b01ec07e87d67d288d360ae164171185684936663b7d8fa9c534c9060200160405180910390a48954610100900478ffffffffffffffffffffffffffffffffffffffffffffffffff165f036136795789547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001178a556040515f8152339073ffffffffffffffffffffffffffffffffffffffff88169086907f705db7ac401a8091bb37a7838ad73d1fa8e1c663cb345f347fefe71280e3f03b9060200160405180910390a45b61368a8887878a868863ffffffff16565b90509850989650505050505050565b8284336136a7838383614241565b5f86815262721c0660205260409020613728908873ffffffffffffffffffffffffffffffffffffffff16866136dc575f6136fe565b7f80000000000000000000000000000000000000000000000000000000000000005b177f000000000000000000000000000000000000000000000000000003e40000293a63ffffffff16565b61179361336187875f9182526020526040902060041c90565b5f805f6137538a8a898989898e613fdc565b8054909150427a01000000000000000000000000000000000000000000000000000090910465ffffffffffff16106137ac578054610100900478ffffffffffffffffffffffffffffffffffffffffffffffffff166137ae565b5f5b905478ffffffffffffffffffffffffffffffffffffffffffffffffff9091169a7a01000000000000000000000000000000000000000000000000000090910465ffffffffffff169950975050505050505050565b611d1660148c8c8c8c8c8c8c8c8c8c8c61420e565b5f61382760148787875f87614162565b905080612d13576040805173ffffffffffffffffffffffffffffffffffffffff87811660248301528681166044830152606480830186905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905291515f928392908a16916138cc9190615c01565b5f604051808303815f865af19150503d805f8114613905576040519150601f19603f3d011682016040523d82523d5f602084013e61390a565b606091505b50915091508161391d576001925061393c565b80511561393c57808060200190518101906139389190615b8f565b1592505b505095945050505050565b6102d1811480613958575061048381145b806139635750601481145b61146a576040517f9d36a97900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82165f908152600660209081526040808320600885901c845290915290208054600160ff84161b9081189182905516611aa7576040517fd979627300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080517ff9c04f8b028fcfa3315ea5accaee4589194a685f07cda0392e6ba9550706111960208201529081018a905273ffffffffffffffffffffffffffffffffffffffff808a1660608301526080820189905260a0820188905260c08201879052851660e08201526101008101849052610120810183905261014081018290525f90610160015b6040516020818303038152906040528051906020012090509998505050505050505050565b5f61145a613acc613ee8565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b6041829003613b85578235602084013560408501355f90811a9080613b2e8984878761464e565b915091508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16141580613b6a5750815b15613b7b57613b7b868a8a8a614722565b5050505050611fb8565b6040829003613bf857823560208401355f80613ba28885856147b4565b915091508073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16141580613bde5750815b15613bef57613bef85898989614722565b50505050611fb8565b611fb881858585614722565b5f613c156002848a8a8a8688613fdc565b805460ff167a01000000000000000000000000000000000000000000000000000065ffffffffffff87169081027fffffffffffff00000000000000000000000000000000000000000000000000ff169190911761010078ffffffffffffffffffffffffffffffffffffffffffffffffff8916908102919091178355604080518a8152602081019290925281019190915290915073ffffffffffffffffffffffffffffffffffffffff83811691898216918616907f0ec867d4f1b037422566cd0248bae620e6c142dcf5631948271916e8ca8dd2639060600160405180910390a45050505050505050565b5f613d116102d1848787866001614162565b905080612272576040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301528581166024830152604482018490528416906323b872dd906064015f604051808303815f87803b158015613d8d575f80fd5b505af1925050508015613d9e575060015b61227257506001949350505050565b5f5473ffffffffffffffffffffffffffffffffffffffff163314611dfe576040517f021943c000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60605f611659836147fb565b5f8173ffffffffffffffffffffffffffffffffffffffff16600a5a613ea29190615c1c565b6040515f8181818686fa925050503d805f8114613eda576040519150601f19603f3d011682016040523d82523d5f602084013e613edf565b606091505b50909392505050565b5f7f00000000000000000000000000000000000000000000000000000000000000014603613f3557507fec95d0f2c68c8c5148e97ae1ea60999070f59b143437390cf2e6ebb12701e84d90565b611f6e604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f12900c1b40e87470816fa5cb16069bf5b3df9cf052332bf21440c4318ccddcfe918101919091527fceebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c160608201524660808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b5f875f614058898989898973ffffffffffffffffffffffffffffffffffffffff9485165f818152600760209081526040918290205482518083019490945283830197909752949096166060820152608081019290925260a082015260c0808201939093528351808203909301835260e001909252805191012090565b81526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f209050979650505050505050565b611d166102d18c8c8c8c8c8c8c8c8c8c8c61420e565b5f6134948b8b8b60148c8c8c8c8c8c8c61446c565b86421115614112576040517fe3fd7ac300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8486111561414c576040517fde7fafeb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6141568489613999565b61342d83838387613b07565b5f805f6141866102d18a1461417857600361417b565b60015b89338a8a8a8a61311d565b909250905061ffff8116158061419f5750888161ffff16145b156141d0577fffffffff00000000000000000000000000000000000000000000000000000000821615159250614202565b6040517f7a535da600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50509695505050505050565b5f6142208d8d8d8d8b8e8e8a8a614854565b90506142328989888d8b868b8b6140d8565b50505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff83165f90815262721c086020526040902080547b010000000000000000000000000000000000000000000000000000009004600116156142c2576040517fb1ae736700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80547b0100000000000000000000000000000000000000000000000000000090046002161561435a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff84160161435a576040517fbf729bb100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8054610100900465ffffffffffff165f9081527f7e074e02264140693c3fbf3ca5a7e5aa542554b2d564345f76c58d7f98bdbbff6020908152604080832073ffffffffffffffffffffffffffffffffffffffff8616845260040190915290205460ff16611fb85780547b0100000000000000000000000000000000000000000000000000000090046008161580614435575073ffffffffffffffffffffffffffffffffffffffff82165f9081527f442599b958bf0d8fbe0ddbf2d50f16197374228cad346cd58d2da01fd8e057f8602052604090205460ff16155b15611fb8576040517fbc8ea06200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f78ffffffffffffffffffffffffffffffffffffffffffffffffff8a3511156144c1576040517f3b0a334300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6144d16003878b8b8b8833613fdc565b805490915060ff1661236b578054610100900478ffffffffffffffffffffffffffffffffffffffffffffffffff165f036145ed5761452a6145228a8a8a8e358b8b65ffffffffffff8c168b8b614854565b8d8d89613b07565b805460ff166101008b3578ffffffffffffffffffffffffffffffffffffffffffffffffff81169190910279ffffffffffffffffffffffffffffffffffffffffffffffffffff16919091177a01000000000000000000000000000000000000000000000000000065ffffffffffff871602178255604051908152339073ffffffffffffffffffffffffffffffffffffffff88169085907f257001e1f7fbfc5bbde5da225c876ab67293f37bda3afb8b35d9a55dfad6f65d9060200160405180910390a45b80547a010000000000000000000000000000000000000000000000000000900465ffffffffffff16421115613494576040517fe3fd7ac300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156146835750600190505f614719565b604080515f81526020810180835288905260ff871691810191909152606081018590526080810184905260019060a0016020604051602081039080840390855afa1580156146d3573d5f803e3d5ffd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015173ffffffffffffffffffffffffffffffffffffffff81161593509150505b94509492505050565b8373ffffffffffffffffffffffffffffffffffffffff163b5f03614772576040517f73c919b500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61477e8484848461488d565b611fb8576040517f73c919b500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316601b60ff85901c016147ed8782888561464e565b909890975095505050505050565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561484857602002820191905f5260205f20905b815481526020019060010190808311614834575b50505050509050919050565b73ffffffffffffffffffffffffffffffffffffffff85165f90815260076020526040812054613494611ce28c8c8c8c8b8b8b8b8a61493b565b5f61492f565b5f6040517f1626ba7e0000000000000000000000000000000000000000000000000000000081528360048201526040602482015285604482015285856064830137601f19601f87011660640180820160405260205f8284875afa60203d10151615614925577f1626ba7e000000000000000000000000000000000000000000000000000000005f511492505050612272565b5050949350505050565b612d1382848688614893565b60408051602081018490529081018a905273ffffffffffffffffffffffffffffffffffffffff891660608201526080810188905260a0810187905260c081018690523360e08201526101008101859052610120810182905261014081018490525f9061016001613a9b565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461146a575f80fd5b5f602082840312156149e3575f80fd5b8135611659816149a6565b803573ffffffffffffffffffffffffffffffffffffffff811681146129b4575f80fd5b5f60208284031215614a21575f80fd5b611659826149ee565b5f8083601f840112614a3a575f80fd5b50813567ffffffffffffffff811115614a51575f80fd5b602083019150836020828501011115614a68575f80fd5b9250929050565b5f805f805f805f805f806101208b8d031215614a89575f80fd5b614a928b6149ee565b995060208b0135985060408b0135975060608b0135965060808b01359550614abc60a08c016149ee565b9450614aca60c08c016149ee565b935060e08b013592506101008b013567ffffffffffffffff811115614aed575f80fd5b614af98d828e01614a2a565b915080935050809150509295989b9194979a5092959850565b5f805f805f805f805f805f806101608d8f031215614b2e575f80fd5b614b378d6149ee565b9b5060208d01359a5060408d0135995060608d0135985060808d01359750614b6160a08e016149ee565b9650614b6f60c08e016149ee565b955060e08d013594506101008d013593506101208d0135925067ffffffffffffffff6101408e01351115614ba1575f80fd5b614bb28e6101408f01358f01614a2a565b81935080925050509295989b509295989b509295989b565b5f805f805f60a08688031215614bde575f80fd5b614be7866149ee565b9450614bf5602087016149ee565b9350614c03604087016149ee565b94979396509394606081013594506080013592915050565b5f60208284031215614c2b575f80fd5b5035919050565b803560ff811681146129b4575f80fd5b5f8060408385031215614c53575f80fd5b614c5c83614c32565b9150614c6a602084016149ee565b90509250929050565b5f8060408385031215614c84575f80fd5b614c8d836149ee565b9150614c6a60208401614c32565b602080825282518282018190525f9190848201906040850190845b81811015614cd257835183529284019291840191600101614cb6565b50909695505050505050565b5f8083601f840112614cee575f80fd5b50813567ffffffffffffffff811115614d05575f80fd5b6020830191508360208260051b8501011115614a68575f80fd5b5f805f60408486031215614d31575f80fd5b614d3a846149ee565b9250602084013567ffffffffffffffff811115614d55575f80fd5b614d6186828701614cde565b9497909650939450505050565b5f5b83811015614d88578181015183820152602001614d70565b50505f910152565b5f602080830181845280855180835260408601915060408160051b87010192508387015f5b82811015614e37577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845281518051808752614dfa818989018a8501614d6e565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01695909501860194509285019290850190600101614db5565b5092979650505050505050565b5f805f805f8060c08789031215614e59575f80fd5b614e62876149ee565b9550614e70602088016149ee565b9450614e7e604088016149ee565b9350614e8c606088016149ee565b92506080870135915060a087013590509295509295509295565b5f8060408385031215614eb7575f80fd5b614ec0836149ee565b946020939093013593505050565b5f805f805f805f60e0888a031215614ee4575f80fd5b87359650614ef4602089016149ee565b9550614f02604089016149ee565b9450614f10606089016149ee565b9350614f1e608089016149ee565b925060a0880135915060c0880135905092959891949750929550565b5f805f60608486031215614f4c575f80fd5b614f55846149ee565b9250614f63602085016149ee565b9150614f71604085016149ee565b90509250925092565b5f805f60608486031215614f8c575f80fd5b614f95846149ee565b95602085013595506040909401359392505050565b5f805f805f60a08688031215614fbe575f80fd5b614fc7866149ee565b9450614fd5602087016149ee565b9350614fe3604087016149ee565b9250614ff1606087016149ee565b949793965091946080013592915050565b5f60608284031215615012575f80fd5b50919050565b803565ffffffffffff811681146129b4575f80fd5b5f805f805f805f805f805f6101808c8e031215615048575f80fd5b8b3567ffffffffffffffff81111561505e575f80fd5b61506a8e828f01614a2a565b909c509a5061507e90508d60208e01615002565b985061508c60808d016149ee565b975060a08c013596506150a160c08d016149ee565b95506150af60e08d016149ee565b94506101008c013593506150c66101208d01615018565b92506101408c013591506101608c013590509295989b509295989b9093969950565b5f805f805f60a086880312156150fc575f80fd5b615105866149ee565b9450615113602087016149ee565b935060408601359250614ff1606087016149ee565b5f805f805f805f805f805f6101408c8e031215615143575f80fd5b61514c8c6149ee565b9a5060208c0135995060408c0135985060608c0135975061516f60808d016149ee565b965061517d60a08d016149ee565b955060c08c0135945060e08c013593506101008c013592506101208c013567ffffffffffffffff8111156151af575f80fd5b6151bb8e828f01614a2a565b915080935050809150509295989b509295989b9093969950565b5f805f606084860312156151e7575f80fd5b6151f084615018565b9250614f6360208501614c32565b5f805f805f60608688031215615212575f80fd5b853567ffffffffffffffff80821115615229575f80fd5b61523589838a01614a2a565b909750955085915061524960208901615018565b9450604088013591508082111561525e575f80fd5b5061526b88828901614cde565b969995985093965092949392505050565b5f805f806080858703121561528f575f80fd5b615298856149ee565b93506152a6602086016149ee565b92506152b4604086016149ee565b91506152c2606086016149ee565b905092959194509250565b5f80604083850312156152de575f80fd5b614c5c836149ee565b803578ffffffffffffffffffffffffffffffffffffffffffffffffff811681146129b4575f80fd5b5f805f805f805f805f805f6101408c8e03121561532a575f80fd5b8b359a5061533a60208d016149ee565b995060408c0135985060608c0135975061535660808d016152e7565b965061536460a08d016149ee565b955061537260c08d01615018565b945061538060e08d01615018565b935061538f6101008d016149ee565b92506101208c013567ffffffffffffffff8111156151af575f80fd5b5f805f805f606086880312156153bf575f80fd5b6153c8866149ee565b9450602086013567ffffffffffffffff808211156153e4575f80fd5b818801915088601f8301126153f7575f80fd5b813581811115615405575f80fd5b8960208260061b8501011115615419575f80fd5b60208301965080955050604088013591508082111561525e575f80fd5b5f805f805f805f8060e0898b03121561544d575f80fd5b615456896149ee565b975060208901359650604089013595506060890135945061547960808a016149ee565b935061548760a08a016149ee565b925060c089013567ffffffffffffffff8111156154a2575f80fd5b6154ae8b828c01614a2a565b999c989b5096995094979396929594505050565b5f805f80606085870312156154d5575f80fd5b6154de85615018565b93506154ec60208601614c32565b9250604085013567ffffffffffffffff811115615507575f80fd5b61551387828801614cde565b95989497509550505050565b5f805f805f8060c08789031215615534575f80fd5b61553d876149ee565b955061554b602088016149ee565b945060408701359350614e8c606088016149ee565b602080825282518282018190525f9190848201906040850190845b81811015614cd257835173ffffffffffffffffffffffffffffffffffffffff168352928401929184019160010161557b565b5f805f80608085870312156155c0575f80fd5b6155c9856149ee565b93506155d7602086016149ee565b92506155e5604086016149ee565b9396929550929360600135925050565b5f8060408385031215615606575f80fd5b614c8d83615018565b5f805f8060808587031215615622575f80fd5b61562b856149ee565b9350615639602086016149ee565b93969395505050506040820135916060013590565b5f806040838503121561565f575f80fd5b615668836149ee565b9150614c6a60208401615018565b5f805f60408486031215615688575f80fd5b833567ffffffffffffffff81111561569e575f80fd5b6156aa86828701614a2a565b9094509250614f71905060208501615018565b5f805f606084860312156156cf575f80fd5b6151f0846149ee565b5f805f805f805f805f806101208b8d0312156156f2575f80fd5b6156fb8b6149ee565b995060208b0135985060408b0135975060608b0135965061571e60808c016149ee565b955061572c60a08c016149ee565b945060c08b0135935060e08b013592506101008b013567ffffffffffffffff811115614aed575f80fd5b5f8060208385031215615767575f80fd5b823567ffffffffffffffff81111561577d575f80fd5b61578985828601614a2a565b90969095509350505050565b5f805f805f8060c087890312156157aa575f80fd5b863595506157ba602088016149ee565b9450604087013593506157cf606088016149ee565b92506157dd608088016152e7565b91506157eb60a08801615018565b90509295509295509295565b61ffff8116811461146a575f80fd5b5f805f805f60a0868803121561581a575f80fd5b615823866149ee565b945061583160208701614c32565b935061583f604087016149ee565b925061584d60608701614c32565b9150608086013561585d816157f7565b809150509295509295909350565b5f805f6060848603121561587d575f80fd5b61588684615018565b925061589460208501614c32565b9150604084013590509250925092565b5f80604083850312156158b5575f80fd5b614c5c83615018565b5f805f805f805f805f806101608b8d0312156158d8575f80fd5b8a3567ffffffffffffffff8111156158ee575f80fd5b6158fa8d828e01614a2a565b909b50995061590e90508c60208d01615002565b975061591c60808c016149ee565b965061592a60a08c016149ee565b955061593860c08c016149ee565b945060e08b0135935061594e6101008c01615018565b92506101208b013591506101408b013590509295989b9194979a5092959850565b5f805f805f805f805f6101008a8c031215615988575f80fd5b6159918a6149ee565b985060208a0135975060408a0135965060608a013595506159b460808b016149ee565b94506159c260a08b016149ee565b935060c08a0135925060e08a013567ffffffffffffffff8111156159e4575f80fd5b6159f08c828d01614a2a565b915080935050809150509295985092959850929598565b5f805f60608486031215615a19575f80fd5b615a22846149ee565b9250615894602085016149ee565b5f60208284031215615a40575f80fd5b61165982614c32565b5f805f60608486031215615a5b575f80fd5b615886846149ee565b5f60208284031215615a74575f80fd5b61165982615018565b5f8060408385031215615a8e575f80fd5b615a97836149ee565b91506020830135615aa7816157f7565b809150509250929050565b8082018082111561145a577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b600181811c90821680615b5857607f821691505b602082108103615012577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60208284031215615b9f575f80fd5b81518015158114611659575f80fd5b5f8451615bbf818460208901614d6e565b8201838582375f930192835250909392505050565b5f8060408385031215615be5575f80fd5b8251615bf0816149a6565b6020840151909250615aa7816157f7565b5f8251615c12818460208701614d6e565b9190910192915050565b5f82615c4f577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b50049056fe5065726d69744f72646572576974684164646974696f6e616c446174612875696e7432353620746f6b656e547970652c6164647265737320746f6b656e2c75696e743235362069642c75696e7432353620616d6f756e742c75696e743235362073616c742c61646472657373206f70657261746f722c75696e743235362065787069726174696f6e2c75696e74323536206d61737465724e6f6e63652c5065726d69745472616e7366657246726f6d576974684164646974696f6e616c446174612875696e7432353620746f6b656e547970652c6164647265737320746f6b656e2c75696e743235362069642c75696e7432353620616d6f756e742c75696e74323536206e6f6e63652c61646472657373206f70657261746f722c75696e743235362065787069726174696f6e2c75696e74323536206d61737465724e6f6e63652ca26469706673582212203c722515cb1b94dd8d752f9b83ae90dcbec2eb559da6ba5732cbef23b095379164736f6c63430008180033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000591aa9dff01b8144dc17cb416001d9ac84b951cd000000000000000000000000e0a0004dfa318fc38298ae81a666710eadceba5c000000000000000000000000721c002d2cae3522602b93a0c48e11dc573a15e3000000000000000000000000721c0086cc4f335407cc84a38ce7dcb1560476b000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000001d43726561746f72546f6b656e5472616e7366657256616c696461746f7200000000000000000000000000000000000000000000000000000000000000000000013500000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : defaultOwner (address): 0x591Aa9dfF01B8144DC17Cb416001D9aC84b951cd
Arg [1] : eoaRegistry_ (address): 0xE0A0004Dfa318fc38298aE81a666710eaDCEba5C
Arg [2] : managementModule_ (address): 0x721C002d2CAe3522602b93a0c48e11dC573A15E3
Arg [3] : safeDelegateModule_ (address): 0x721C0086CC4f335407cC84a38cE7dcb1560476B0
Arg [4] : name (string): CreatorTokenTransferValidator
Arg [5] : version (string): 5
-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 000000000000000000000000591aa9dff01b8144dc17cb416001d9ac84b951cd
Arg [1] : 000000000000000000000000e0a0004dfa318fc38298ae81a666710eadceba5c
Arg [2] : 000000000000000000000000721c002d2cae3522602b93a0c48e11dc573a15e3
Arg [3] : 000000000000000000000000721c0086cc4f335407cc84a38ce7dcb1560476b0
Arg [4] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [6] : 000000000000000000000000000000000000000000000000000000000000001d
Arg [7] : 43726561746f72546f6b656e5472616e7366657256616c696461746f72000000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [9] : 3500000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.