Source Code
Latest 25 from a total of 126 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Set Ruleset Of C... | 48195757 | 12 days ago | IN | 0 MON | 0.00780238 | ||||
| Set Ruleset Of C... | 48195263 | 12 days ago | IN | 0 MON | 0.0078036 | ||||
| Apply List To Co... | 44059284 | 31 days ago | IN | 0 MON | 0.01041246 | ||||
| Apply List To Co... | 44059052 | 31 days ago | IN | 0 MON | 0.01041246 | ||||
| Apply List To Co... | 42364375 | 39 days ago | IN | 0 MON | 0.01469645 | ||||
| Set Ruleset Of C... | 41831495 | 41 days ago | IN | 0 MON | 0.00859743 | ||||
| Set Ruleset Of C... | 41547290 | 43 days ago | IN | 0 MON | 0.00859743 | ||||
| Apply List To Co... | 41518494 | 43 days ago | IN | 0 MON | 0.0073122 | ||||
| Add Accounts To ... | 41517562 | 43 days ago | IN | 0 MON | 0.02383372 | ||||
| Create List Copy | 41517197 | 43 days ago | IN | 0 MON | 0.10809674 | ||||
| Apply List To Co... | 41409972 | 43 days ago | IN | 0 MON | 0.01119439 | ||||
| Apply List To Co... | 41360237 | 43 days ago | IN | 0 MON | 0.01048164 | ||||
| Apply List To Co... | 40747422 | 46 days ago | IN | 0 MON | 0.01564731 | ||||
| Apply List To Co... | 40697859 | 47 days ago | IN | 0 MON | 0.01141389 | ||||
| Apply List To Co... | 40696933 | 47 days ago | IN | 0 MON | 0.01130634 | ||||
| Set Ruleset Of C... | 40579609 | 47 days ago | IN | 0 MON | 0.01177315 | ||||
| Apply List To Co... | 40575738 | 47 days ago | IN | 0 MON | 0.01124927 | ||||
| Apply List To Co... | 40575645 | 47 days ago | IN | 0 MON | 0.01119256 | ||||
| Apply List To Co... | 40572977 | 47 days ago | IN | 0 MON | 0.01119439 | ||||
| Add Accounts To ... | 40568450 | 47 days ago | IN | 0 MON | 0.0328597 | ||||
| Add Accounts To ... | 40567554 | 47 days ago | IN | 0 MON | 0.03268675 | ||||
| Add Accounts To ... | 40567428 | 47 days ago | IN | 0 MON | 0.03330808 | ||||
| Add Accounts To ... | 40567113 | 47 days ago | IN | 0 MON | 0.03299421 | ||||
| Set Ruleset Of C... | 40502769 | 47 days ago | IN | 0 MON | 0.01182947 | ||||
| Apply List To Co... | 40304257 | 48 days ago | IN | 0 MON | 0.01173961 |
Latest 2 internal transactions
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 33603564 | 80 days ago | Contract Creation | 0 MON | |||
| 33603564 | 80 days ago | Contract Creation | 0 MON |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
CreatorTokenTransferValidator
Compiler Version
v0.8.24+commit.e11b9ed9
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import "./Constants.sol";
import "./DataTypes.sol";
import "./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",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false
}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
0x60806040526004361061057f575f3560e01c806386e11774116102cf578063c5ba65091161017b578063e07cb240116100dc578063f6b8561a11610092578063fb2de5d71161006d578063fb2de5d714611272578063ff924f531461128c578063ffbcb4aa146112d7575f80fd5b8063f6b8561a1461121e578063f6e1ff8914610a5d578063f7a2000a14611238575f80fd5b8063e9a7be29116100c2578063e9a7be29146111c1578063eeca41a6146111e0578063f2fde38b146111ff575f80fd5b8063e07cb24014610aaa578063e34fda85146105d6575f80fd5b8063d5dc239a11610131578063db5f30a811610117578063db5f30a814611142578063dd71105d14611161578063df21dc1d14611180575f80fd5b8063d5dc239a14611104578063db188e6314611123575f80fd5b8063caee23ea11610161578063caee23ea14611080578063ccee9c511461109f578063cfea7ecf146110e5575f80fd5b8063c5ba65091461104c578063c815270e14611066575f80fd5b8063b3992ab111610230578063b97f6f8b116101e6578063c43f946b116101c1578063c43f946b14610fb6578063c44a076a1461100e578063c482160f1461102d575f80fd5b8063b97f6f8b14610f5e578063bc8aa28414610f7d578063c435f43514610f97575f80fd5b8063b89c4b0d11610216578063b89c4b0d14610d81578063b8dcc68f14610da0578063b955455214610dba575f80fd5b8063b3992ab114610d43578063b6e39ba114610d62575f80fd5b8063a029957911610285578063a4e28f7d1161026b578063a4e28f7d14610cab578063a87b03b614610cca578063ad1ff68514610d24575f80fd5b8063a029957914610a5d578063a20df79f14610c91575f80fd5b80638cdfc296116102b55780638cdfc29614610c0e5780638da5cb5b14610c2d5780639c84033414610c77575f80fd5b806386e1177414610bd057806389a9c85514610bef575f80fd5b80634be52a891161042e57806366e8304a1161038f57806378e890ba116103455780638254fcb7116103205780638254fcb714610b645780638567413514610b92578063859840a514610bb1575f80fd5b806378e890ba14610b045780637c1e14b414610b265780637df81b9014610b45575f80fd5b806371be859d1161037557806371be859d14610aaa578063725d07c514610ac45780637423eb3c14610af0575f80fd5b806366e8304a14610a5d578063715018a614610a96575f80fd5b8063539d2602116103e45780635ed5917f116103ca5780635ed5917f14610a3e57806363fc56bc14610a5d5780636498c04514610a77575f80fd5b8063539d260214610a00578063599d2c6214610a1f575f80fd5b80634f3c18fe116104145780634f3c18fe146109a3578063505efb65146109c257806350793315146109e1575f80fd5b80634be52a89146109145780634ca104b814610933575f80fd5b80631bb610e7116104e357806328cc1131116104995780633a0e3160116104745780633a0e3160146108ad5780633e8a0bc9146108cc5780633f6560ee146108e0575f80fd5b806328cc11311461083b5780632d975d141461085a5780633779e6fd14610879575f80fd5b806323c99262116104c957806323c992621461079157806327d21f50146107c2578063285fb8c81461081c575f80fd5b80631bb610e7146106de5780631f2fdc7914610735575f80fd5b8063136439dd1161053857806315ec12791161051e57806315ec1279146106675780631854b2411461069357806319007fc9146106b2575f80fd5b8063136439dd1461063557806314e4f88814610648575f80fd5b80630e14021a116105685780630e14021a146105d85780630f59197d146105f757806312d3848a14610616575f80fd5b806301ffc9a7146105835780630ad38899146105b7575b5f80fd5b34801561058e575f80fd5b506105a261059d3660046149d3565b611305565b60405190151581526020015b60405180910390f35b3480156105c2575f80fd5b506105d66105d1366004614a11565b611460565b005b3480156105e3575f80fd5b506105a26105f2366004614a6f565b61146d565b348015610602575f80fd5b506105a2610611366004614b12565b6114dd565b348015610621575f80fd5b506105a2610630366004614bca565b61155b565b6105d6610643366004614c1b565b6115c9565b348015610653575f80fd5b506105d6610662366004614c42565b6115da565b348015610672575f80fd5b50610686610681366004614c73565b611618565b6040516105ae9190614c9b565b34801561069e575f80fd5b506105d66106ad366004614bca565b611660565b3480156106bd575f80fd5b506106d16106cc366004614d1f565b61179c565b6040516105ae9190614d90565b3480156106e9575f80fd5b506106fd6106f8366004614e44565b611900565b6040805192151583527fffffffff000000000000000000000000000000000000000000000000000000009091166020830152016105ae565b348015610740575f80fd5b506105a261074f366004614ea6565b73ffffffffffffffffffffffffffffffffffffffff9091165f908152600660209081526040808320600885901c845290915290205460ff9091161c6001161590565b34801561079c575f80fd5b5062721c055465ffffffffffff165b60405165ffffffffffff90911681526020016105ae565b3480156107cd575f80fd5b506107e16107dc366004614ece565b611945565b604080517fffffffff00000000000000000000000000000000000000000000000000000000909316835261ffff9091166020830152016105ae565b348015610827575f80fd5b506105d6610836366004614f3a565b6119ad565b348015610846575f80fd5b506105d6610855366004614f7a565b6119bd565b348015610865575f80fd5b506106fd610874366004614faa565b6119ca565b348015610884575f80fd5b5061089861089336600461502d565b611a0e565b604080519283529015156020830152016105ae565b3480156108b8575f80fd5b506105d66108c7366004614ea6565b611a9a565b3480156108d7575f80fd5b506105d6611aab565b3480156108eb575f80fd5b506108ff6108fa3660046150e8565b611ae8565b604080519283526020830191909152016105ae565b34801561091f575f80fd5b506105a261092e366004615128565b611b08565b34801561093e575f80fd5b506105a261094d3660046151d5565b60ff9182165f90815262721c0a6020908152604080832065ffffffffffff96909616835294815284822073ffffffffffffffffffffffffffffffffffffffff939093168252600490920190915291909120541690565b3480156109ae575f80fd5b506107ab6109bd3660046151fe565b611b83565b3480156109cd575f80fd5b506106fd6109dc36600461527c565b611bbe565b3480156109ec575f80fd5b506105d66109fb3660046152cd565b611c01565b348015610a0b575f80fd5b506105d6610a1a36600461530f565b611c0e565b348015610a2a575f80fd5b506105d6610a393660046153ab565b611d23565b348015610a49575f80fd5b506105a2610a58366004615436565b611d5d565b348015610a68575f80fd5b506105d6610a393660046154c2565b348015610a82575f80fd5b506108ff610a9136600461551f565b611dcc565b348015610aa1575f80fd5b506105d6611ded565b348015610ab5575f80fd5b506105d6610a39366004614d1f565b348015610acf575f80fd5b50610ae3610ade366004614a11565b611e00565b6040516105ae9190615560565b348015610afb575f80fd5b506105d6611e32565b348015610b0f575f80fd5b50610b18611f65565b6040519081526020016105ae565b348015610b31575f80fd5b506105d6610b40366004614f3a565b611f73565b348015610b50575f80fd5b506105a2610b5f3660046155ad565b611fbe565b348015610b6f575f80fd5b506105a2610b7e366004614c1b565b5f9081526004602052604090205460ff1690565b348015610b9d575f80fd5b50610686610bac3660046155f5565b61202c565b348015610bbc575f80fd5b50610ae3610bcb366004614c73565b612061565b348015610bdb575f80fd5b506105d6610bea366004614ea6565b6120a2565b348015610bfa575f80fd5b506105a2610c09366004614a11565b61214f565b348015610c19575f80fd5b506105d6610c2836600461560f565b612201565b348015610c38575f80fd5b505f5473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016105ae565b348015610c82575f80fd5b506105d6610a3936600461564e565b348015610c9c575f80fd5b506107ab6109bd366004615676565b348015610cb6575f80fd5b506105a2610cc53660046156bd565b61220d565b348015610cd5575f80fd5b506105a2610ce43660046152cd565b73ffffffffffffffffffffffffffffffffffffffff9182165f90815262721c09602090815260408083209390941682526002909201909152205460ff1690565b348015610d2f575f80fd5b506105d6610d3e36600461551f565b61227a565b348015610d4e575f80fd5b506105a2610d5d3660046156d8565b61239d565b348015610d6d575f80fd5b506105d6610d7c366004614ea6565b612418565b348015610d8c575f80fd5b506105d6610d9b366004614ea6565b612424565b348015610dab575f80fd5b506107ab6109bd366004615756565b348015610dc5575f80fd5b50610ee5610dd4366004614a11565b6040805160c080820183525f80835260208084018290528385018290526060808501839052608080860184905260a095860184905273ffffffffffffffffffffffffffffffffffffffff978816845262721c08835292869020865194850187525460ff808216865265ffffffffffff610100830416938601939093526701000000000000008104909716958401959095527b010000000000000000000000000000000000000000000000000000008604169382019390935261ffff7c010000000000000000000000000000000000000000000000000000000085048116938201939093527e010000000000000000000000000000000000000000000000000000000000009093049091169082015290565b6040516105ae91905f60c08201905060ff835116825265ffffffffffff602084015116602083015273ffffffffffffffffffffffffffffffffffffffff604084015116604083015260ff6060840151166060830152608083015161ffff80821660808501528060a08601511660a0850152505092915050565b348015610f69575f80fd5b506105d6610f78366004615795565b612430565b348015610f88575f80fd5b506105d6610a39366004615806565b348015610fa2575f80fd5b506105d6610fb1366004614c1b565b612450565b348015610fc1575f80fd5b506105a2610fd036600461586b565b60ff9182165f90815262721c0a6020908152604080832065ffffffffffff969096168352948152848220928252600590920190915291909120541690565b348015611019575f80fd5b50610686611028366004614d1f565b61245a565b348015611038575f80fd5b50610ae36110473660046155f5565b612525565b348015611057575f80fd5b506105d6610662366004614a11565b348015611071575f80fd5b506105d6610a393660046158a4565b34801561108b575f80fd5b506105d661109a3660046155ad565b612557565b3480156110aa575f80fd5b506105a26110b9366004614a11565b73ffffffffffffffffffffffffffffffffffffffff165f90815262721c0d602052604090205460ff1690565b3480156110f0575f80fd5b506108986110ff3660046158be565b6125a3565b34801561110f575f80fd5b506105a261111e36600461596f565b61262e565b34801561112e575f80fd5b506105d661113d366004615756565b61269c565b34801561114d575f80fd5b506105d661115c366004615a07565b6127ac565b34801561116c575f80fd5b506105a261117b3660046155ad565b6127b8565b34801561118b575f80fd5b50610b1861119a366004614a11565b73ffffffffffffffffffffffffffffffffffffffff165f9081526007602052604090205490565b3480156111cc575f80fd5b50610c526111db366004615a30565b61281b565b3480156111eb575f80fd5b506105a26111fa366004615a49565b61287a565b34801561120a575f80fd5b506105d6611219366004614a11565b6128dc565b348015611229575f80fd5b506105d6610a39366004615a64565b348015611243575f80fd5b50600180547f000000000000000000000000000000000000000000000000002386f26fc0ffff909101906108ff565b34801561127d575f80fd5b506105d6610a39366004615a7d565b348015611297575f80fd5b50610c526112a6366004615a64565b65ffffffffffff165f90815262721c07602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b3480156112e2575f80fd5b506105a26112f1366004614c1b565b5f9081526005602052604090205460ff1690565b5f7fffffffff000000000000000000000000000000000000000000000000000000008216158061137657507fffffffff0000000000000000000000000000000000000000000000000000000082167f1bb3460e00000000000000000000000000000000000000000000000000000000145b806113c257507fffffffff0000000000000000000000000000000000000000000000000000000082167fc058083400000000000000000000000000000000000000000000000000000000145b8061140e57507fffffffff0000000000000000000000000000000000000000000000000000000082167f89a9c85500000000000000000000000000000000000000000000000000000000145b8061145a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b61146a815f612424565b50565b5f61149c60107f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b6114b06104838c8c8b8d8c8c8b8b8b612b61565b6114bd8b87878d88612c59565b905080156114cf576114cf868a612d1c565b9a9950505050505050505050565b5f836114e881612d97565b61151660107f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b6115298e8e8d8f8e8e8d8b8b8f8f612dde565b8c6115378f8b8b848c612c59565b92508215611549576115498a8e612d1c565b50509c9b505050505050505050505050565b5f61158a60027f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b5f61159b876104838787875f612df4565b90506115aa8588888787612c59565b915081156115bf576115bf81885f8681612f7d565b5095945050505050565b6115d16130d0565b61146a816130d8565b7f000000000000000000000000721c0086cc4f335407cc84a38ce7dcb1560476b0365f80375f80365f845af43d805f803e8161161457805ffd5b805ff35b73ffffffffffffffffffffffffffffffffffffffff82165f90815262721c08602052604090205460609061165990610100900465ffffffffffff168361202c565b9392505050565b5f611671600333888888888861311d565b5090507fffffffff000000000000000000000000000000000000000000000000000000008116156116a5576116a58161320f565b335f90815260208490526040902060041c6116e38163ffffffff7f000000000000000000000000000000000000000000000000000003eb0000294116565b15611793575f6116f4826001615ab2565b90505f611724827f000000000000000000000000000000000000000000000000000003eb0000294163ffffffff16565b905080851115611760576040517ff9e7abe700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611790828683037f000000000000000000000000000000000000000000000000000003e40000293a63ffffffff16565b50505b50505050505050565b606081156116595773ffffffffffffffffffffffffffffffffffffffff84165f90815262721c0c602052604090208267ffffffffffffffff8111156117e3576117e3615aea565b60405190808252806020026020018201604052801561181657816020015b60608152602001906001900390816118015790505b5091505f5b838110156118f757815f86868481811061183757611837615b17565b9050602002013581526020019081526020015f20805461185690615b44565b80601f016020809104026020016040519081016040528092919081815260200182805461188290615b44565b80156118cd5780601f106118a4576101008083540402835291602001916118cd565b820191905f5260205f20905b8154815290600101906020018083116118b057829003601f168201915b50505050508382815181106118e4576118e4615b17565b602090810291909101015260010161181b565b50509392505050565b5f80611912600389898989898961311d565b507fffffffff00000000000000000000000000000000000000000000000000000000811615999098509650505050505050565b5f80333014611980576040517ffa103f6700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61198a89613217565b9250905061199e818b8b8b8b8b8b8b6132d2565b92505097509795505050505050565b6119b8838383611f73565b505050565b6119b8600184848461333f565b5f806119dc600188888888885f61311d565b507fffffffff000000000000000000000000000000000000000000000000000000008116159890975095505050505050565b5f8082611a1a81613437565b611a4860407f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b5f611a5b8f8f8f8f8f8f8e8e8e8e61347e565b9050611a6f818e8e8e8e8e8c612c596134a3565b90945092508215611a8857611a88818b88876001612f7d565b50509b509b9950505050505050505050565b611aa7600183835f613699565b5050565b335f8181526007602052604080822080546001019055517f8e8cebe67607ce50a14a2e3261437f641a7b33ecc053e3d9c90b25ae5e66c6569190a2565b5f80611afa6002888888888887613741565b915091509550959350505050565b5f83611b1381612d97565b611b4160207f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b611b548d5f8d8f8e8e8d8b8b8f8f613802565b611b618d8a8a5f8b613817565b91508115611b7357611b73898d612d1c565b509b9a5050505050505050505050565b5f7f000000000000000000000000721c002d2cae3522602b93a0c48e11dc573a15e3365f80375f80365f845af43d805f803e8161161457805ffd5b5f80611bd06002878787875f8061311d565b507fffffffff0000000000000000000000000000000000000000000000000000000081161597909650945050505050565b611aa782825f6001613699565b8365ffffffffffff16421115611c50576040517f827aed8000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611c598b613947565b611c638389613999565b611cef611ce7611ce28d8d8d8c78ffffffffffffffffffffffffffffffffffffffffffffffffff168e8d8d65ffffffffffff168d65ffffffffffff1660075f8f73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054613a13565b613ac0565b838386613b07565b65ffffffffffff851615611d035784611d05565b425b9450611d168b8b8b8a89888c613c04565b5050505050505050505050565b7f000000000000000000000000721c002d2cae3522602b93a0c48e11dc573a15e3365f80375f80365f845af43d805f803e8161161457805ffd5b5f611d8c60087f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b611da26102d18a8a60018b8b8b60018b8b612b61565b611dae85858b8b613cff565b90508015611dc057611dc08588612d1c565b98975050505050505050565b5f80611dde6003898989898989613741565b91509150965096945050505050565b611df5613dad565b611dfe5f613dfd565b565b73ffffffffffffffffffffffffffffffffffffffff81165f90815262721c096020526040902060609061145a90613e71565b7f000000000000000000000000000000000000000000000000000000000000000180611e7f57507fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff165b15611eb6576040517ff45b98b000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611edf7f00000000000000000000000079a95940c17a9a8148633a11ff9d0ddcffd9c00d613e7d565b611f15576040517f70a4078f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b0080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055611dfe80565b5f611f6e613ee8565b905090565b5f611f846002338686865f8061311d565b5090507fffffffff00000000000000000000000000000000000000000000000000000000811615611fb857611fb88161320f565b50505050565b5f611fed60017f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b5f611fff866102d18686600180612df4565b905061200d86868686613cff565b915081156120235761202381875f600181612f7d565b50949350505050565b60ff81165f90815262721c0a6020908152604080832065ffffffffffff86168452909152902060609061165990600201613e71565b73ffffffffffffffffffffffffffffffffffffffff82165f90815262721c08602052604090205460609061165990610100900465ffffffffffff1683612525565b6120aa6130d0565b6120b35f6130d8565b8015611aa7575f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f811461210f576040519150601f19603f3d011682016040523d82523d5f602084013e612114565b606091505b50509050806119b8576040517f3f1df14400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f89a9c85500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301525f917f000000000000000000000000e0a0004dfa318fc38298ae81a666710eadceba5c909116906389a9c85590602401602060405180830381865afa1580156121dd573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061145a9190615b8f565b611fb88484848461333f565b73ffffffffffffffffffffffffffffffffffffffff8381165f90815262721c08602090815260408083205460ff808816855262721c0a845282852061010090920465ffffffffffff168552908352818420948616845260049094019091528120549091165b949350505050565b3373ffffffffffffffffffffffffffffffffffffffff871614806122b357503373ffffffffffffffffffffffffffffffffffffffff8616145b6122e9576040517feda7110300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6122f284613947565b5f612303600388878787878c613fdc565b805490915060ff1661236b57600281556040516001815273ffffffffffffffffffffffffffffffffffffffff878116919089169084907f705db7ac401a8091bb37a7838ad73d1fa8e1c663cb345f347fefe71280e3f03b9060200160405180910390a4611793565b6040517f8cbf875200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f836123a881612d97565b6123d660087f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b6123eb8c8c60018d8d8d60018b8b8f8f6140ad565b6123f788888e8e613cff565b9150811561240957612409888b612d1c565b509a9950505050505050505050565b611aa75f83838261333f565b611aa75f838382613699565b61243986613947565b61244886868685853389613c04565b505050505050565b61146a3382613999565b606081156116595773ffffffffffffffffffffffffffffffffffffffff84165f90815262721c0b602052604090208267ffffffffffffffff8111156124a1576124a1615aea565b6040519080825280602002602001820160405280156124ca578160200160208202803683370190505b5091505f5b838110156118f757815f8686848181106124eb576124eb615b17565b9050602002013581526020019081526020015f205483828151811061251257612512615b17565b60209081029190910101526001016124cf565b60ff81165f90815262721c0a6020908152604080832065ffffffffffff86168452909152902060609061165990613e71565b5f612568600133878787875f61311d565b5090507fffffffff0000000000000000000000000000000000000000000000000000000081161561259c5761259c8161320f565b5050505050565b5f80826125af81613437565b6125dd60807f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b5f6125f08e8e8e8e5f8f8e8e8e8e6140c3565b9050612604818d8d5f8e8e8c6138176134a3565b9094509250821561261d5761261d818b88876001612f7d565b50509a509a98505050505050505050565b5f61265d60207f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b61267060148b5f8b8d8c8c8b8b8b612b61565b61267d8a87875f88613817565b9050801561268f5761268f868a612d1c565b9998505050505050505050565b600160045f6040518060e0016040528060a58152602001615cf260a5913985856040516020016126ce93929190615bae565b6040516020818303038152906040528051906020012081526020019081526020015f205f6101000a81548160ff021916908315150217905550600160055f6040518060c00160405280609d8152602001615c55609d9139858560405160200161273993929190615bae565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529181528151602092830120835290820192909252015f2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790555050565b6119b88383835f613699565b5f6127e760047f000000000000000000000000000000000000000000000000000004b6000029ee63ffffffff16565b5f6127f7866014865f875f612df4565b90506128068487875f87613817565b915081156120235761202381875f8681612f7d565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0160ff83160161284d57505f919050565b5060ff165f90815262721c0e602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff83165f90815262721c08602090815260408083205460ff808716855262721c0a845282852061010090920465ffffffffffff16855290835281842085855260050190925282205416612272565b6128e4613dad565b73ffffffffffffffffffffffffffffffffffffffff8116612931576040517f3e58254b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61146a81613dfd565b80825d5050565b5c90565b5f815d50565b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff161561297c5780825d5050565b9055565b5f7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff16156129b057505c90565b5080545b919050565b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff16156129e9575f815d50565b5f9055565b7f000000000000000000000000000000000000000000000000002386f26fc0ffff344703111561146a5760015481161561146a576040517fcc47725a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000002386f26fc0ffff34470311612aaf576040517ffd2c901300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600154165f0361146a576040517ffd2c901300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f7f000000000000000000000000000000000000000000000000002386f26fc0ffff3447031115612b1c57506001545b90565b60015481161561146a576040517fcc47725a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015490565b5f612c47611ce28c8c8c8c8c8c60075f8e73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054604080517f932b8553b8e35bbee682d275cbe1cf115e14a777e2ca3266b4797369fb6317d36020808301919091528183019990995273ffffffffffffffffffffffffffffffffffffffff979097166060880152608087019590955260a086019390935260c08501919091523360e085015261010084015261012080840191909152815180840390910181526101409092019052805191012090565b9050611d168787868b898689896140d8565b5f612c6a6104838787878787614162565b905080612d13576040517ff242432a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301528581166024830152604482018590526064820184905260a060848301525f60a483015287169063f242432a9060c4015f604051808303815f87803b158015612cfa575f80fd5b505af1925050508015612d0b575060015b612d13575060015b95945050505050565b73ffffffffffffffffffffffffffffffffffffffff82165f908152600660209081526040808320600885901c845290915290208054600160ff84161b908118918290551615611aa7576040517fe4adc0bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8181526004602052604090205460ff1661146a576040517f4722506e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611d166104838c8c8c8c8c8c8c8c8c8c8c61420e565b5f612e056002888888888633613fdc565b8054909150427a01000000000000000000000000000000000000000000000000000090910465ffffffffffff161015612e6a576040517f827aed8000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8054610100900478ffffffffffffffffffffffffffffffffffffffffffffffffff16831115612ec5576040517ffee142c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8115612ef65780547fffffffffffff00000000000000000000000000000000000000000000000000ff168155612f73565b805478ffffffffffffffffffffffffffffffffffffffffffffffffff61010090910481161015612f7357805478ffffffffffffffffffffffffffffffffffffffffffffffffff6101008083048216869003909116027fffffffffffff00000000000000000000000000000000000000000000000000ff9091161781555b9695505050505050565b811561259c57801561304e5784547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0078ffffffffffffffffffffffffffffffffffffffffffffffffff6101008084048216860190911602167fffffffffffff000000000000000000000000000000000000000000000000000090911617855560405182815273ffffffffffffffffffffffffffffffffffffffff85169084907f83e0ca2c1392f14286fa1e41c797789d48c5827572e8bcc352d8943c1961eaf09060200160405180910390a361259c565b845478ffffffffffffffffffffffffffffffffffffffffffffffffff6101009091048116101561259c57845478ffffffffffffffffffffffffffffffffffffffffffffffffff61010080830482168501909116027fffffffffffff00000000000000000000000000000000000000000000000000ff9091161785555050505050565b611dfe613dad565b600180549082905560408051828152602081018490527fe0d8d9ad73c586e8cf60ffd390b6f3654200a2d8857eb6abba4f6842a1210aae910160405180910390a15050565b5f803073ffffffffffffffffffffffffffffffffffffffff88160361314657505f905080613203565b6040517f27d21f50000000000000000000000000000000000000000000000000000000008152600481018a905273ffffffffffffffffffffffffffffffffffffffff808a166024830152808916604483015280881660648301528616608482015260a4810185905260c4810184905230906327d21f509060e4016040805180830381865afa1580156131da573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906131fe9190615bd4565b915091505b97509795505050505050565b805f5260045ffd5b73ffffffffffffffffffffffffffffffffffffffff81165f90815262721c0860205260408120805482919060ff90811610613274578054670100000000000000900473ffffffffffffffffffffffffffffffffffffffff166132a0565b805460ff165f90815262721c0e602052604090205473ffffffffffffffffffffffffffffffffffffffff165b905490947e0100000000000000000000000000000000000000000000000000000000000090910461ffff169350915050565b5f80630be200ea60e01b90506040518181528960048201528860248201528760448201528660648201528560848201528460a48201528360c482015260e4810160405260205f60e4838e5af490508061332e573d805f803e805ffd5b50505f519998505050505050505050565b82843361334d838383614241565b5f86815262721c06602052604090206133a1905b8873ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000003e40000293a63ffffffff16565b5f86815260208690526040902060041c6133f58173ffffffffffffffffffffffffffffffffffffffff8a1663ffffffff7f000000000000000000000000000000000000000000000000000003e40000293a16565b61342d613403826001615ab2565b867f000000000000000000000000000000000000000000000000000003e40000293a63ffffffff16565b5050505050505050565b5f8181526005602052604090205460ff1661146a576040517f4722506e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6134948b8b8b6104838c8c8c8c8c8c8c61446c565b9b9a5050505050505050505050565b87546020880135905f90610100900478ffffffffffffffffffffffffffffffffffffffffffffffffff168211156134f9578954610100900478ffffffffffffffffffffffffffffffffffffffffffffffffff1691505b8860400135821015613537576040517fb9ff981500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b895478ffffffffffffffffffffffffffffffffffffffffffffffffff6101008083048216859003909116027fffffffffffff00000000000000000000000000000000000000000000000000ff909116178a55604051828152339073ffffffffffffffffffffffffffffffffffffffff88169086907f2203cb053e6b01ec07e87d67d288d360ae164171185684936663b7d8fa9c534c9060200160405180910390a48954610100900478ffffffffffffffffffffffffffffffffffffffffffffffffff165f036136795789547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001178a556040515f8152339073ffffffffffffffffffffffffffffffffffffffff88169086907f705db7ac401a8091bb37a7838ad73d1fa8e1c663cb345f347fefe71280e3f03b9060200160405180910390a45b61368a8887878a868863ffffffff16565b90509850989650505050505050565b8284336136a7838383614241565b5f86815262721c0660205260409020613728908873ffffffffffffffffffffffffffffffffffffffff16866136dc575f6136fe565b7f80000000000000000000000000000000000000000000000000000000000000005b177f000000000000000000000000000000000000000000000000000003e40000293a63ffffffff16565b61179361336187875f9182526020526040902060041c90565b5f805f6137538a8a898989898e613fdc565b8054909150427a01000000000000000000000000000000000000000000000000000090910465ffffffffffff16106137ac578054610100900478ffffffffffffffffffffffffffffffffffffffffffffffffff166137ae565b5f5b905478ffffffffffffffffffffffffffffffffffffffffffffffffff9091169a7a01000000000000000000000000000000000000000000000000000090910465ffffffffffff169950975050505050505050565b611d1660148c8c8c8c8c8c8c8c8c8c8c61420e565b5f61382760148787875f87614162565b905080612d13576040805173ffffffffffffffffffffffffffffffffffffffff87811660248301528681166044830152606480830186905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905291515f928392908a16916138cc9190615c01565b5f604051808303815f865af19150503d805f8114613905576040519150601f19603f3d011682016040523d82523d5f602084013e61390a565b606091505b50915091508161391d576001925061393c565b80511561393c57808060200190518101906139389190615b8f565b1592505b505095945050505050565b6102d1811480613958575061048381145b806139635750601481145b61146a576040517f9d36a97900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82165f908152600660209081526040808320600885901c845290915290208054600160ff84161b9081189182905516611aa7576040517fd979627300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080517ff9c04f8b028fcfa3315ea5accaee4589194a685f07cda0392e6ba9550706111960208201529081018a905273ffffffffffffffffffffffffffffffffffffffff808a1660608301526080820189905260a0820188905260c08201879052851660e08201526101008101849052610120810183905261014081018290525f90610160015b6040516020818303038152906040528051906020012090509998505050505050505050565b5f61145a613acc613ee8565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b6041829003613b85578235602084013560408501355f90811a9080613b2e8984878761464e565b915091508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16141580613b6a5750815b15613b7b57613b7b868a8a8a614722565b5050505050611fb8565b6040829003613bf857823560208401355f80613ba28885856147b4565b915091508073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16141580613bde5750815b15613bef57613bef85898989614722565b50505050611fb8565b611fb881858585614722565b5f613c156002848a8a8a8688613fdc565b805460ff167a01000000000000000000000000000000000000000000000000000065ffffffffffff87169081027fffffffffffff00000000000000000000000000000000000000000000000000ff169190911761010078ffffffffffffffffffffffffffffffffffffffffffffffffff8916908102919091178355604080518a8152602081019290925281019190915290915073ffffffffffffffffffffffffffffffffffffffff83811691898216918616907f0ec867d4f1b037422566cd0248bae620e6c142dcf5631948271916e8ca8dd2639060600160405180910390a45050505050505050565b5f613d116102d1848787866001614162565b905080612272576040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301528581166024830152604482018490528416906323b872dd906064015f604051808303815f87803b158015613d8d575f80fd5b505af1925050508015613d9e575060015b61227257506001949350505050565b5f5473ffffffffffffffffffffffffffffffffffffffff163314611dfe576040517f021943c000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60605f611659836147fb565b5f8173ffffffffffffffffffffffffffffffffffffffff16600a5a613ea29190615c1c565b6040515f8181818686fa925050503d805f8114613eda576040519150601f19603f3d011682016040523d82523d5f602084013e613edf565b606091505b50909392505050565b5f7f000000000000000000000000000000000000000000000000000000000000008f4603613f3557507f388e51789c13d2bbb342d4135594d5cdcada31d3c67ba2f1c4c9d256705dca5490565b611f6e604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f12900c1b40e87470816fa5cb16069bf5b3df9cf052332bf21440c4318ccddcfe918101919091527fceebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c160608201524660808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b5f875f614058898989898973ffffffffffffffffffffffffffffffffffffffff9485165f818152600760209081526040918290205482518083019490945283830197909752949096166060820152608081019290925260a082015260c0808201939093528351808203909301835260e001909252805191012090565b81526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f209050979650505050505050565b611d166102d18c8c8c8c8c8c8c8c8c8c8c61420e565b5f6134948b8b8b60148c8c8c8c8c8c8c61446c565b86421115614112576040517fe3fd7ac300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8486111561414c576040517fde7fafeb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6141568489613999565b61342d83838387613b07565b5f805f6141866102d18a1461417857600361417b565b60015b89338a8a8a8a61311d565b909250905061ffff8116158061419f5750888161ffff16145b156141d0577fffffffff00000000000000000000000000000000000000000000000000000000821615159250614202565b6040517f7a535da600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50509695505050505050565b5f6142208d8d8d8d8b8e8e8a8a614854565b90506142328989888d8b868b8b6140d8565b50505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff83165f90815262721c086020526040902080547b010000000000000000000000000000000000000000000000000000009004600116156142c2576040517fb1ae736700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80547b0100000000000000000000000000000000000000000000000000000090046002161561435a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff84160161435a576040517fbf729bb100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8054610100900465ffffffffffff165f9081527f7e074e02264140693c3fbf3ca5a7e5aa542554b2d564345f76c58d7f98bdbbff6020908152604080832073ffffffffffffffffffffffffffffffffffffffff8616845260040190915290205460ff16611fb85780547b0100000000000000000000000000000000000000000000000000000090046008161580614435575073ffffffffffffffffffffffffffffffffffffffff82165f9081527f442599b958bf0d8fbe0ddbf2d50f16197374228cad346cd58d2da01fd8e057f8602052604090205460ff16155b15611fb8576040517fbc8ea06200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f78ffffffffffffffffffffffffffffffffffffffffffffffffff8a3511156144c1576040517f3b0a334300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6144d16003878b8b8b8833613fdc565b805490915060ff1661236b578054610100900478ffffffffffffffffffffffffffffffffffffffffffffffffff165f036145ed5761452a6145228a8a8a8e358b8b65ffffffffffff8c168b8b614854565b8d8d89613b07565b805460ff166101008b3578ffffffffffffffffffffffffffffffffffffffffffffffffff81169190910279ffffffffffffffffffffffffffffffffffffffffffffffffffff16919091177a01000000000000000000000000000000000000000000000000000065ffffffffffff871602178255604051908152339073ffffffffffffffffffffffffffffffffffffffff88169085907f257001e1f7fbfc5bbde5da225c876ab67293f37bda3afb8b35d9a55dfad6f65d9060200160405180910390a45b80547a010000000000000000000000000000000000000000000000000000900465ffffffffffff16421115613494576040517fe3fd7ac300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156146835750600190505f614719565b604080515f81526020810180835288905260ff871691810191909152606081018590526080810184905260019060a0016020604051602081039080840390855afa1580156146d3573d5f803e3d5ffd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015173ffffffffffffffffffffffffffffffffffffffff81161593509150505b94509492505050565b8373ffffffffffffffffffffffffffffffffffffffff163b5f03614772576040517f73c919b500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61477e8484848461488d565b611fb8576040517f73c919b500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316601b60ff85901c016147ed8782888561464e565b909890975095505050505050565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561484857602002820191905f5260205f20905b815481526020019060010190808311614834575b50505050509050919050565b73ffffffffffffffffffffffffffffffffffffffff85165f90815260076020526040812054613494611ce28c8c8c8c8b8b8b8b8a61493b565b5f61492f565b5f6040517f1626ba7e0000000000000000000000000000000000000000000000000000000081528360048201526040602482015285604482015285856064830137601f19601f87011660640180820160405260205f8284875afa60203d10151615614925577f1626ba7e000000000000000000000000000000000000000000000000000000005f511492505050612272565b5050949350505050565b612d1382848688614893565b60408051602081018490529081018a905273ffffffffffffffffffffffffffffffffffffffff891660608201526080810188905260a0810187905260c081018690523360e08201526101008101859052610120810182905261014081018490525f9061016001613a9b565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461146a575f80fd5b5f602082840312156149e3575f80fd5b8135611659816149a6565b803573ffffffffffffffffffffffffffffffffffffffff811681146129b4575f80fd5b5f60208284031215614a21575f80fd5b611659826149ee565b5f8083601f840112614a3a575f80fd5b50813567ffffffffffffffff811115614a51575f80fd5b602083019150836020828501011115614a68575f80fd5b9250929050565b5f805f805f805f805f806101208b8d031215614a89575f80fd5b614a928b6149ee565b995060208b0135985060408b0135975060608b0135965060808b01359550614abc60a08c016149ee565b9450614aca60c08c016149ee565b935060e08b013592506101008b013567ffffffffffffffff811115614aed575f80fd5b614af98d828e01614a2a565b915080935050809150509295989b9194979a5092959850565b5f805f805f805f805f805f806101608d8f031215614b2e575f80fd5b614b378d6149ee565b9b5060208d01359a5060408d0135995060608d0135985060808d01359750614b6160a08e016149ee565b9650614b6f60c08e016149ee565b955060e08d013594506101008d013593506101208d0135925067ffffffffffffffff6101408e01351115614ba1575f80fd5b614bb28e6101408f01358f01614a2a565b81935080925050509295989b509295989b509295989b565b5f805f805f60a08688031215614bde575f80fd5b614be7866149ee565b9450614bf5602087016149ee565b9350614c03604087016149ee565b94979396509394606081013594506080013592915050565b5f60208284031215614c2b575f80fd5b5035919050565b803560ff811681146129b4575f80fd5b5f8060408385031215614c53575f80fd5b614c5c83614c32565b9150614c6a602084016149ee565b90509250929050565b5f8060408385031215614c84575f80fd5b614c8d836149ee565b9150614c6a60208401614c32565b602080825282518282018190525f9190848201906040850190845b81811015614cd257835183529284019291840191600101614cb6565b50909695505050505050565b5f8083601f840112614cee575f80fd5b50813567ffffffffffffffff811115614d05575f80fd5b6020830191508360208260051b8501011115614a68575f80fd5b5f805f60408486031215614d31575f80fd5b614d3a846149ee565b9250602084013567ffffffffffffffff811115614d55575f80fd5b614d6186828701614cde565b9497909650939450505050565b5f5b83811015614d88578181015183820152602001614d70565b50505f910152565b5f602080830181845280855180835260408601915060408160051b87010192508387015f5b82811015614e37577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845281518051808752614dfa818989018a8501614d6e565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01695909501860194509285019290850190600101614db5565b5092979650505050505050565b5f805f805f8060c08789031215614e59575f80fd5b614e62876149ee565b9550614e70602088016149ee565b9450614e7e604088016149ee565b9350614e8c606088016149ee565b92506080870135915060a087013590509295509295509295565b5f8060408385031215614eb7575f80fd5b614ec0836149ee565b946020939093013593505050565b5f805f805f805f60e0888a031215614ee4575f80fd5b87359650614ef4602089016149ee565b9550614f02604089016149ee565b9450614f10606089016149ee565b9350614f1e608089016149ee565b925060a0880135915060c0880135905092959891949750929550565b5f805f60608486031215614f4c575f80fd5b614f55846149ee565b9250614f63602085016149ee565b9150614f71604085016149ee565b90509250925092565b5f805f60608486031215614f8c575f80fd5b614f95846149ee565b95602085013595506040909401359392505050565b5f805f805f60a08688031215614fbe575f80fd5b614fc7866149ee565b9450614fd5602087016149ee565b9350614fe3604087016149ee565b9250614ff1606087016149ee565b949793965091946080013592915050565b5f60608284031215615012575f80fd5b50919050565b803565ffffffffffff811681146129b4575f80fd5b5f805f805f805f805f805f6101808c8e031215615048575f80fd5b8b3567ffffffffffffffff81111561505e575f80fd5b61506a8e828f01614a2a565b909c509a5061507e90508d60208e01615002565b985061508c60808d016149ee565b975060a08c013596506150a160c08d016149ee565b95506150af60e08d016149ee565b94506101008c013593506150c66101208d01615018565b92506101408c013591506101608c013590509295989b509295989b9093969950565b5f805f805f60a086880312156150fc575f80fd5b615105866149ee565b9450615113602087016149ee565b935060408601359250614ff1606087016149ee565b5f805f805f805f805f805f6101408c8e031215615143575f80fd5b61514c8c6149ee565b9a5060208c0135995060408c0135985060608c0135975061516f60808d016149ee565b965061517d60a08d016149ee565b955060c08c0135945060e08c013593506101008c013592506101208c013567ffffffffffffffff8111156151af575f80fd5b6151bb8e828f01614a2a565b915080935050809150509295989b509295989b9093969950565b5f805f606084860312156151e7575f80fd5b6151f084615018565b9250614f6360208501614c32565b5f805f805f60608688031215615212575f80fd5b853567ffffffffffffffff80821115615229575f80fd5b61523589838a01614a2a565b909750955085915061524960208901615018565b9450604088013591508082111561525e575f80fd5b5061526b88828901614cde565b969995985093965092949392505050565b5f805f806080858703121561528f575f80fd5b615298856149ee565b93506152a6602086016149ee565b92506152b4604086016149ee565b91506152c2606086016149ee565b905092959194509250565b5f80604083850312156152de575f80fd5b614c5c836149ee565b803578ffffffffffffffffffffffffffffffffffffffffffffffffff811681146129b4575f80fd5b5f805f805f805f805f805f6101408c8e03121561532a575f80fd5b8b359a5061533a60208d016149ee565b995060408c0135985060608c0135975061535660808d016152e7565b965061536460a08d016149ee565b955061537260c08d01615018565b945061538060e08d01615018565b935061538f6101008d016149ee565b92506101208c013567ffffffffffffffff8111156151af575f80fd5b5f805f805f606086880312156153bf575f80fd5b6153c8866149ee565b9450602086013567ffffffffffffffff808211156153e4575f80fd5b818801915088601f8301126153f7575f80fd5b813581811115615405575f80fd5b8960208260061b8501011115615419575f80fd5b60208301965080955050604088013591508082111561525e575f80fd5b5f805f805f805f8060e0898b03121561544d575f80fd5b615456896149ee565b975060208901359650604089013595506060890135945061547960808a016149ee565b935061548760a08a016149ee565b925060c089013567ffffffffffffffff8111156154a2575f80fd5b6154ae8b828c01614a2a565b999c989b5096995094979396929594505050565b5f805f80606085870312156154d5575f80fd5b6154de85615018565b93506154ec60208601614c32565b9250604085013567ffffffffffffffff811115615507575f80fd5b61551387828801614cde565b95989497509550505050565b5f805f805f8060c08789031215615534575f80fd5b61553d876149ee565b955061554b602088016149ee565b945060408701359350614e8c606088016149ee565b602080825282518282018190525f9190848201906040850190845b81811015614cd257835173ffffffffffffffffffffffffffffffffffffffff168352928401929184019160010161557b565b5f805f80608085870312156155c0575f80fd5b6155c9856149ee565b93506155d7602086016149ee565b92506155e5604086016149ee565b9396929550929360600135925050565b5f8060408385031215615606575f80fd5b614c8d83615018565b5f805f8060808587031215615622575f80fd5b61562b856149ee565b9350615639602086016149ee565b93969395505050506040820135916060013590565b5f806040838503121561565f575f80fd5b615668836149ee565b9150614c6a60208401615018565b5f805f60408486031215615688575f80fd5b833567ffffffffffffffff81111561569e575f80fd5b6156aa86828701614a2a565b9094509250614f71905060208501615018565b5f805f606084860312156156cf575f80fd5b6151f0846149ee565b5f805f805f805f805f806101208b8d0312156156f2575f80fd5b6156fb8b6149ee565b995060208b0135985060408b0135975060608b0135965061571e60808c016149ee565b955061572c60a08c016149ee565b945060c08b0135935060e08b013592506101008b013567ffffffffffffffff811115614aed575f80fd5b5f8060208385031215615767575f80fd5b823567ffffffffffffffff81111561577d575f80fd5b61578985828601614a2a565b90969095509350505050565b5f805f805f8060c087890312156157aa575f80fd5b863595506157ba602088016149ee565b9450604087013593506157cf606088016149ee565b92506157dd608088016152e7565b91506157eb60a08801615018565b90509295509295509295565b61ffff8116811461146a575f80fd5b5f805f805f60a0868803121561581a575f80fd5b615823866149ee565b945061583160208701614c32565b935061583f604087016149ee565b925061584d60608701614c32565b9150608086013561585d816157f7565b809150509295509295909350565b5f805f6060848603121561587d575f80fd5b61588684615018565b925061589460208501614c32565b9150604084013590509250925092565b5f80604083850312156158b5575f80fd5b614c5c83615018565b5f805f805f805f805f806101608b8d0312156158d8575f80fd5b8a3567ffffffffffffffff8111156158ee575f80fd5b6158fa8d828e01614a2a565b909b50995061590e90508c60208d01615002565b975061591c60808c016149ee565b965061592a60a08c016149ee565b955061593860c08c016149ee565b945060e08b0135935061594e6101008c01615018565b92506101208b013591506101408b013590509295989b9194979a5092959850565b5f805f805f805f805f6101008a8c031215615988575f80fd5b6159918a6149ee565b985060208a0135975060408a0135965060608a013595506159b460808b016149ee565b94506159c260a08b016149ee565b935060c08a0135925060e08a013567ffffffffffffffff8111156159e4575f80fd5b6159f08c828d01614a2a565b915080935050809150509295985092959850929598565b5f805f60608486031215615a19575f80fd5b615a22846149ee565b9250615894602085016149ee565b5f60208284031215615a40575f80fd5b61165982614c32565b5f805f60608486031215615a5b575f80fd5b615886846149ee565b5f60208284031215615a74575f80fd5b61165982615018565b5f8060408385031215615a8e575f80fd5b615a97836149ee565b91506020830135615aa7816157f7565b809150509250929050565b8082018082111561145a577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b600181811c90821680615b5857607f821691505b602082108103615012577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60208284031215615b9f575f80fd5b81518015158114611659575f80fd5b5f8451615bbf818460208901614d6e565b8201838582375f930192835250909392505050565b5f8060408385031215615be5575f80fd5b8251615bf0816149a6565b6020840151909250615aa7816157f7565b5f8251615c12818460208701614d6e565b9190910192915050565b5f82615c4f577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b50049056fe5065726d69744f72646572576974684164646974696f6e616c446174612875696e7432353620746f6b656e547970652c6164647265737320746f6b656e2c75696e743235362069642c75696e7432353620616d6f756e742c75696e743235362073616c742c61646472657373206f70657261746f722c75696e743235362065787069726174696f6e2c75696e74323536206d61737465724e6f6e63652c5065726d69745472616e7366657246726f6d576974684164646974696f6e616c446174612875696e7432353620746f6b656e547970652c6164647265737320746f6b656e2c75696e743235362069642c75696e7432353620616d6f756e742c75696e74323536206e6f6e63652c61646472657373206f70657261746f722c75696e743235362065787069726174696f6e2c75696e74323536206d61737465724e6f6e63652ca26469706673582212203c722515cb1b94dd8d752f9b83ae90dcbec2eb559da6ba5732cbef23b095379164736f6c63430008180033
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
Deployed Bytecode Sourcemap
1178:59377:30:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;48555:434;;;;;;;;;;-1:-1:-1;48555:434:30;;;;;:::i;:::-;;:::i;:::-;;;611:14:36;;604:22;586:41;;574:2;559:18;48555:434:30;;;;;;;;17364:107;;;;;;;;;;-1:-1:-1;17364:107:30;;;;;:::i;:::-;;:::i;:::-;;21865:670:17;;;;;;;;;;-1:-1:-1;21865:670:17;;;;;:::i;:::-;;:::i;24672:1085::-;;;;;;;;;;-1:-1:-1;24672:1085:17;;;;;:::i;:::-;;:::i;45782:558::-;;;;;;;;;;-1:-1:-1;45782:558:17;;;;;:::i;:::-;;:::i;8427:134:13:-;;;;;;:::i;:::-;;:::i;7076:100:30:-;;;;;;;;;;-1:-1:-1;7076:100:30;;;;;:::i;:::-;;:::i;44506:233::-;;;;;;;;;;-1:-1:-1;44506:233:30;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;11215:916::-;;;;;;;;;;-1:-1:-1;11215:916:30;;;;;:::i;:::-;;:::i;41379:545::-;;;;;;;;;;-1:-1:-1;41379:545:30;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;25184:443::-;;;;;;;;;;-1:-1:-1;25184:443:30;;;;;:::i;:::-;;:::i;:::-;;;;8493:14:36;;8486:22;8468:41;;8557:66;8545:79;;;8540:2;8525:18;;8518:107;8441:18;25184:443:30;8302:329:36;42005:203:17;;;;;;;;;;-1:-1:-1;42005:203:17;;;;;:::i;:::-;42125:23;;;;42089:12;42125:23;;;:16;:23;;;;;;;;42166:1;42157:10;;;42125:44;;;;;;;;:60;;;;;257:1:14;42124:68:17;42123:78;;42005:203;39429:106:30;;;;;;;;;;-1:-1:-1;4767:66:33;39499:29:30;;;39429:106;;;9069:14:36;9057:27;;;9039:46;;9027:2;9012:18;39429:106:30;8895:196:36;47466:858:30;;;;;;;;;;-1:-1:-1;47466:858:30;;;;;:::i;:::-;;:::i;:::-;;;;9917:66:36;9905:79;;;9887:98;;10033:6;10021:19;;;10016:2;10001:18;;9994:47;9860:18;47466:858:30;9717:330:36;13072:146:30;;;;;;;;;;-1:-1:-1;13072:146:30;;;;;:::i;:::-;;:::i;19627:199::-;;;;;;;;;;-1:-1:-1;19627:199:30;;;;;:::i;:::-;;:::i;24047:402::-;;;;;;;;;;-1:-1:-1;24047:402:30;;;;;:::i;:::-;;:::i;34140:1232:17:-;;;;;;;;;;-1:-1:-1;34140:1232:17;;;;;:::i;:::-;;:::i;:::-;;;;12845:25:36;;;12913:14;;12906:22;12901:2;12886:18;;12879:50;12818:18;34140:1232:17;12677:258:36;18396:172:30;;;;;;;;;;-1:-1:-1;18396:172:30;;;;;:::i;:::-;;:::i;42477:143:17:-;;;;;;;;;;;;;:::i;13192:320::-;;;;;;;;;;-1:-1:-1;13192:320:17;;;;;:::i;:::-;;:::i;:::-;;;;13591:25:36;;;13647:2;13632:18;;13625:34;;;;13564:18;13192:320:17;13417:248:36;30017:962:17;;;;;;;;;;-1:-1:-1;30017:962:17;;;;;:::i;:::-;;:::i;43099:189:30:-;;;;;;;;;;-1:-1:-1;43099:189:30;;;;;:::i;:::-;43212:34;;;;43189:4;43212:34;;;:24;:34;;;;;;;;:38;;;;;;;;;;;;;:69;;;;;;;:60;;;;:69;;;;;;;;;;43099:189;28719:158;;;;;;;;;;-1:-1:-1;28719:158:30;;;;;:::i;:::-;;:::i;23009:376::-;;;;;;;;;;-1:-1:-1;23009:376:30;;;;;:::i;:::-;;:::i;16423:149::-;;;;;;;;;;-1:-1:-1;16423:149:30;;;;;:::i;:::-;;:::i;11182:1326:17:-;;;;;;;;;;-1:-1:-1;11182:1326:17;;;;;:::i;:::-;;:::i;32381:220:30:-;;;;;;;;;;-1:-1:-1;32381:220:30;;;;;:::i;:::-;;:::i;16967:568:17:-;;;;;;;;;;-1:-1:-1;16967:568:17;;;;;:::i;:::-;;:::i;38094:165:30:-;;;;;;;;;;-1:-1:-1;38094:165:30;;;;;:::i;40812:338:17:-;;;;;;;;;;-1:-1:-1;40812:338:17;;;;;:::i;:::-;;:::i;1938:101:21:-;;;;;;;;;;;;;:::i;34538:137:30:-;;;;;;;;;;-1:-1:-1;34538:137:30;;;;;:::i;44921:197::-;;;;;;;;;;-1:-1:-1;44921:197:30;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;4954:532:25:-;;;;;;;;;;;;;:::i;51854:132:17:-;;;;;;;;;;;;;:::i;:::-;;;22820:25:36;;;22808:2;22793:18;51854:132:17;22674:177:36;8358:328:30;;;;;;;;;;-1:-1:-1;8358:328:30;;;;;:::i;:::-;;:::i;44149:515:17:-;;;;;;;;;;-1:-1:-1;44149:515:17;;;;;:::i;:::-;;:::i;31240:167::-;;;;;;;;;;-1:-1:-1;31240:167:17;;;;;:::i;:::-;31325:17;31369:31;;;:25;:31;;;;;;;;;31240:167;42571:185:30;;;;;;;;;;-1:-1:-1;42571:185:30;;;;;:::i;:::-;;:::i;44036:229::-;;;;;;;;;;-1:-1:-1;44036:229:30;;;;;:::i;:::-;;:::i;9506:334:13:-;;;;;;;;;;-1:-1:-1;9506:334:13;;;;;:::i;:::-;;:::i;47037:140:30:-;;;;;;;;;;-1:-1:-1;47037:140:30;;;;;:::i;:::-;;:::i;20992:200::-;;;;;;;;;;-1:-1:-1;20992:200:30;;;;;:::i;:::-;;:::i;1321:85:21:-;;;;;;;;;;-1:-1:-1;1367:7:21;1393:6;;;1321:85;;;24286:42:36;24274:55;;;24256:74;;24244:2;24229:18;1321:85:21;24110:226:36;33830:103:30;;;;;;;;;;-1:-1:-1;33830:103:30;;;;;:::i;27560:130::-;;;;;;;;;;-1:-1:-1;27560:130:30;;;;;:::i;45514:243::-;;;;;;;;;;-1:-1:-1;45514:243:30;;;;;:::i;:::-;;:::i;46699:204::-;;;;;;;;;;-1:-1:-1;46699:204:30;;;;;:::i;:::-;46820:45;;;;46797:4;46820:45;;;:33;:45;;;;;;;;:76;;;;;;:67;;;;:76;;;;;;;;46699:204;39400:843:17;;;;;;;;;;-1:-1:-1;39400:843:17;;;;;:::i;:::-;;:::i;19514:883::-;;;;;;;;;;-1:-1:-1;19514:883:17;;;;;:::i;:::-;;:::i;21971:191:30:-;;;;;;;;;;-1:-1:-1;21971:191:30;;;;;:::i;:::-;;:::i;15198:183::-;;;;;;;;;;-1:-1:-1;15198:183:30;;;;;:::i;:::-;;:::i;26417:103::-;;;;;;;;;;-1:-1:-1;26417:103:30;;;;;:::i;40150:208::-;;;;;;;;;;-1:-1:-1;40150:208:30;;;;;:::i;:::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40294:57:30;;;;;;:45;:57;;;;;;40287:64;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40150:208;;;;;;;26999:4:36;27041:3;27030:9;27026:19;27018:27;;27091:4;27082:6;27076:13;27072:24;27061:9;27054:43;27165:14;27157:4;27149:6;27145:17;27139:24;27135:45;27128:4;27117:9;27113:20;27106:75;27249:42;27241:4;27233:6;27229:17;27223:24;27219:73;27212:4;27201:9;27197:20;27190:103;27361:4;27353;27345:6;27341:17;27335:24;27331:35;27324:4;27313:9;27309:20;27302:65;27414:4;27406:6;27402:17;27396:24;27439:6;27501:2;27487:12;27483:21;27476:4;27465:9;27461:20;27454:51;27573:2;27565:4;27557:6;27553:17;27547:24;27543:33;27536:4;27525:9;27521:20;27514:63;;;26823:760;;;;;9000:321:17;;;;;;;;;;-1:-1:-1;9000:321:17;;;;;:::i;:::-;;:::i;31364:226:30:-;;;;;;;;;;-1:-1:-1;31364:226:30;;;;;:::i;41641:118:17:-;;;;;;;;;;-1:-1:-1;41641:118:17;;;;;:::i;:::-;;:::i;43605:194:30:-;;;;;;;;;;-1:-1:-1;43605:194:30;;;;;:::i;:::-;43720:34;;;;43697:4;43720:34;;;:24;:34;;;;;;;;:38;;;;;;;;;;;;;:72;;;:24;:62;;;:72;;;;;;;;;;43605:194;40594:547;;;;;;;;;;-1:-1:-1;40594:547:30;;;;;:::i;:::-;;:::i;42155:181::-;;;;;;;;;;-1:-1:-1;42155:181:30;;;;;:::i;:::-;;:::i;6174:87::-;;;;;;;;;;-1:-1:-1;6174:87:30;;;;;:::i;29368:103::-;;;;;;;;;;-1:-1:-1;29368:103:30;;;;;:::i;9685:346::-;;;;;;;;;;-1:-1:-1;9685:346:30;;;;;:::i;:::-;;:::i;38607:145::-;;;;;;;;;;-1:-1:-1;38607:145:30;;;;;:::i;:::-;38699:46;;38676:4;38699:46;;;:37;:46;;;;;;;;;38607:145;37432:1208:17;;;;;;;;;;-1:-1:-1;37432:1208:17;;;;;:::i;:::-;;:::i;27235:646::-;;;;;;;;;;-1:-1:-1;27235:646:17;;;;;:::i;:::-;;:::i;14814:704::-;;;;;;;;;;-1:-1:-1;14814:704:17;;;;;:::i;:::-;;:::i;14246:173:30:-;;;;;;;;;;-1:-1:-1;14246:173:30;;;;;:::i;:::-;;:::i;47406:534:17:-;;;;;;;;;;-1:-1:-1;47406:534:17;;;;;:::i;:::-;;:::i;42798:112::-;;;;;;;;;;-1:-1:-1;42798:112:17;;;;;:::i;:::-;42883:20;;42857:7;42883:20;;;:13;:20;;;;;;;42798:112;38869:237:30;;;;;;;;;;-1:-1:-1;38869:237:30;;;;;:::i;:::-;;:::i;46138:247::-;;;;;;;;;;-1:-1:-1;46138:247:30;;;;;:::i;:::-;;:::i;2188:191:21:-;;;;;;;;;;-1:-1:-1;2188:191:21;;;;;:::i;:::-;;:::i;29917:85:30:-;;;;;;;;;;-1:-1:-1;29917:85:30;;;;;:::i;10156:308:13:-;;;;;;;;;;-1:-1:-1;10402:1:13;10434:13;;10371:28;:32;;;;10156:308;;33117:138:30;;;;;;;;;;-1:-1:-1;33117:138:30;;;;;:::i;39616:120::-;;;;;;;;;;-1:-1:-1;39616:120:30;;;;;:::i;:::-;39696:33;;39670:7;39696:33;;;:29;:33;;;;;;;;;39616:120;31665:161:17;;;;;;;;;;-1:-1:-1;31665:161:17;;;;;:::i;:::-;31747:17;31791:28;;;:22;:28;;;;;;;;;31665:161;48555:434:30;48657:4;48692:53;;;;;:120;;-1:-1:-1;48761:51:30;;;48776:36;48761:51;48692:120;:177;;;-1:-1:-1;48828:41:30;;;48843:26;48828:41;48692:177;:238;;;-1:-1:-1;48885:45:30;;;48900:30;48885:45;48692:238;:290;;;-1:-1:-1;747:25:22;732:40;;;;48946:36:30;48673:309;48555:434;-1:-1:-1;;48555:434:30:o;17364:107::-;17431:33;17455:5;17462:1;17431:23;:33::i;:::-;17364:107;:::o;21865:670:17:-;22160:12;22184:59;3140:6:14;22184:17:17;:59;;:::i;:::-;22254:121;838:4:14;22295:5:17;22302:2;22306:12;22320:5;22327:10;22339:5;22346:14;22362:12;;22254:20;:121::i;:::-;22395:58;22416:5;22423;22430:2;22434;22438:14;22395:20;:58::i;:::-;22385:68;;22468:7;22464:65;;;22491:27;22505:5;22512;22491:13;:27::i;:::-;21865:670;;;;;;;;;;;;:::o;24672:1085::-;25112:12;25083:18;7336:66;7383:18;7336:46;:66::i;:::-;25136:59:::1;3140:6:14;25136:17:17;:59;;:::i;:::-;25206:292;25265:5;25284:2;25300:12;25326:5;25345:10;25369:5;25388:14;25416:12;;25442:14;25470:18;25206:45;:292::i;:::-;25592:2:::0;25614:61:::1;25635:5:::0;25642;25649:2;25592;25660:14;25614:20:::1;:61::i;:::-;25604:71;;25690:7;25686:65;;;25713:27;25727:5;25734;25713:13;:27::i;:::-;25126:631;24672:1085:::0;;;;;;;;;;;;;;;:::o;45782:558::-;45945:12;45969:58;2725:6:14;45969:17:17;:58;;:::i;:::-;46038:31;46072:76;46096:5;838:4:14;46123:5:17;46130:2;46134:6;46142:5;46072:23;:76::i;:::-;46038:110;;46168:50;46189:5;46196;46203:2;46207;46211:6;46168:20;:50::i;:::-;46158:60;;46233:7;46229:105;;;46256:67;46278:8;46288:5;144:1:14;46309:6:17;144:1:14;46256:21:17;:67::i;:::-;45959:381;45782:558;;;;;;;:::o;8427:134:13:-;7797:35;:33;:35::i;:::-;8521:33:::1;8539:14;8521:17;:33::i;7076:100:30:-:0;7153:19;4545:14;4542:1;4539;4526:34;4637:1;4634;4618:14;4615:1;4607:6;4600:5;4587:52;4664:16;4714:4;4711:1;4708;4693:26;4742:6;4732:65;;4778:4;4775:1;4768:15;4732:65;4820:4;4817:1;4810:15;44506:233;44657:57;;;;;;;:45;:57;;;;;:64;44604:16;;44639:93;;44657:64;;;;;44723:8;44639:17;:93::i;:::-;44632:100;44506:233;-1:-1:-1;;;44506:233:30:o;11215:916::-;11336:20;11361:104;1400:1:29;11419:10:30;11431:6;11439:4;11445:2;11449:7;11458:6;11361:17;:104::i;:::-;-1:-1:-1;11335:130:30;-1:-1:-1;11479:34:30;;;;11475:109;;11529:44;11559:13;11529:29;:44::i;:::-;11655:10;11594:32;2233:24:33;;;2277:4;2270:21;;;2343:4;2327:21;;2324:1;2320:29;11689:38:30;2320:29:33;11689:38:30;:12;:38;:::i;:::-;:43;11685:440;;11748:18;11769:28;:24;11796:1;11769:28;:::i;:::-;11748:49;;11811:24;11838;11851:10;11838:12;:24;;:::i;:::-;11811:51;;11890:16;11881:6;:25;11877:130;;;11933:59;;;;;;;;;;;;;;11877:130;12049:51;12062:10;12093:6;12074:16;:25;12049:12;:51;;:::i;:::-;11734:391;;11685:440;11325:806;;11215:916;;;;;:::o;41379:545::-;41508:21;41544:15;;41541:377;;41661:58;;;41575:66;41661:58;;;:44;:58;;;;;41755:4;41743:24;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;41734:33;;41786:9;41781:127;41801:15;;;41781:127;;;41853:31;:40;41885:4;;41890:1;41885:7;;;;;;;:::i;:::-;;;;;;;41853:40;;;;;;;;;;;41841:52;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:6;41848:1;41841:9;;;;;;;;:::i;:::-;;;;;;;;;;:52;41818:3;;41781:127;;;;41561:357;41379:545;;;;;:::o;25184:443::-;25389:22;25413:16;25456:104;1400:1:29;25514:10:30;25526:6;25534:4;25540:2;25544:7;25553:6;25456:17;:104::i;:::-;-1:-1:-1;25590:30:30;;;;;25441:119;;-1:-1:-1;25184:443:30;-1:-1:-1;;;;;;;25184:443:30:o;47466:858::-;47714:20;;47769:10;47791:4;47769:27;47765:132;;47819:67;;;;;;;;;;;;;;47765:132;47907:30;48019:53;48061:10;48019:41;:53::i;:::-;47947:125;-1:-1:-1;47947:125:30;-1:-1:-1;48099:218:30;47947:125;48169:19;48202:10;48226:6;48246:4;48264:2;48280:7;48301:6;48099:20;:218::i;:::-;48083:234;;47754:570;47466:858;;;;;;;;;;:::o;13072:146::-;13177:34;13194:6;13202:4;13208:2;13177:16;:34::i;:::-;13072:146;;;:::o;19627:199::-;19738:81;2007:4:29;19796:5:30;19803:7;19812:6;19738:30;:81::i;24047:402::-;24227:22;24251:16;24294:88;1284:1:29;24341:10:30;24353:6;24361:4;24367:2;24371:7;24380:1;24294:17;:88::i;:::-;-1:-1:-1;24412:30:30;;;;;24279:103;;-1:-1:-1;24047:402:30;-1:-1:-1;;;;;;24047:402:30:o;34140:1232:17:-;34540:22;34564:12;34511:18;7509:63;7553:18;7509:43;:63::i;:::-;34588:55:::1;3408:6:14;34588:17:17;:55;;:::i;:::-;34654:34;34691:241;34731:12;;34757:16;34787:5;34806:2;34822:5;34841:4;34859:10;34883:7;34904:18;34691:26;:241::i;:::-;34654:278;;35005:240;35037:11;35066:16;35100:5;35124:2;35145:5;35169:2;35190:7;35215:20;35005:14;:240::i;:::-;34943:302:::0;;-1:-1:-1;34943:302:17;-1:-1:-1;35256:110:17;::::1;;;35283:72;35305:11;35318:5;35325:7;35334:14;35350:4;35283:21;:72::i;:::-;34578:794;34140:1232:::0;;;;;;;;;;;;;;;:::o;18396:172:30:-;18481:80;2007:4:29;18539:5:30;18546:7;18555:5;18481:30;:80::i;:::-;18396:172;;:::o;42477:143:17:-;42554:10;42540:25;;;;:13;:25;;;;;;:27;;;;;;42593:20;;;42540:25;42593:20;42477:143::o;13192:320::-;13362:21;;13422:83;13433:18;13453:5;13460:8;13470:9;13481:5;13488:2;13362:21;13422:10;:83::i;:::-;13415:90;;;;13192:320;;;;;;;;:::o;30017:962::-;30435:12;30406:18;7336:66;7383:18;7336:46;:66::i;:::-;30459:57:::1;3277:6:14;30459:17:17;:57;;:::i;:::-;30527:292;30584:5;202:1:14;30621:12:17;30647:5;30666:10;30690:5;30709:14;30737:12;;30763:14;30791:18;30527:43;:292::i;:::-;30839:58;30858:5;30865;30872:2;202:1:14;30882:14:17;30839:18;:58::i;:::-;30829:68;;30912:7;30908:65;;;30935:27;30949:5;30956;30935:13;:27::i;:::-;30017:962:::0;;;;;;;;;;;;;;:::o;28719:158:30:-;28864:9;28836:17;4545:14;4542:1;4539;4526:34;4637:1;4634;4618:14;4615:1;4607:6;4600:5;4587:52;4664:16;4714:4;4711:1;4708;4693:26;4742:6;4732:65;;4778:4;4775:1;4768:15;23009:376;23164:22;23188:16;23231:87;1339:1:29;23283:10:30;23295:6;23303:4;23309:2;23313:1;23316;23231:17;:87::i;:::-;-1:-1:-1;23348:30:30;;;;;23216:102;;-1:-1:-1;23009:376:30;-1:-1:-1;;;;;23009:376:30:o;16423:149::-;16509:56;16540:8;16550:5;16557:1;16560:4;16509:30;:56::i;11182:1326:17:-;11530:11;11512:29;;:15;:29;11508:114;;;11564:47;;;;;;;;;;;;;;11508:114;11631:33;11654:9;11631:22;:33::i;:::-;11674:38;11699:5;11706;11674:24;:38::i;:::-;11722:470;11758:378;11792:330;11844:9;11875:5;11902:2;11926:6;11792:330;;11954:5;11981:8;12011:18;11792:330;;12051:11;11792:330;;12084:13;:20;12098:5;12084:20;;;;;;;;;;;;;;;;11792:30;:330::i;:::-;11758:16;:378::i;:::-;12150:12;;12177:5;11722:22;:470::i;:::-;12339:23;;;;:70;;12391:18;12339:70;;;12372:15;12339:70;12318:91;;12420:81;12435:9;12446:5;12453:2;12457:6;12465:18;12485:5;12492:8;12420:14;:81::i;:::-;11182:1326;;;;;;;;;;;:::o;32381:220:30:-;32580:17;4545:14;4542:1;4539;4526:34;4637:1;4634;4618:14;4615:1;4607:6;4600:5;4587:52;4664:16;4714:4;4711:1;4708;4693:26;4742:6;4732:65;;4778:4;4775:1;4768:15;16967:568:17;17199:12;17223:58;2999:6:14;17223:17:17;:58;;:::i;:::-;17292:100;701:3:14;17332:5:17;17339:2;257:1:14;17348:5:17;17355:10;17367:5;257:1:14;17379:12:17;;17292:20;:100::i;:::-;17412:41;17432:5;17439:2;17443:5;17450:2;17412:19;:41::i;:::-;17402:51;;17468:7;17464:65;;;17491:27;17505:5;17512;17491:13;:27::i;:::-;16967:568;;;;;;;;;;:::o;40812:338::-;41008:21;41031:18;41068:75;41079:15;41096:5;41103:8;41113:9;41124:5;41131:2;41135:7;41068:10;:75::i;:::-;41061:82;;;;40812:338;;;;;;;;;:::o;1938:101:21:-;1214:13;:11;:13::i;:::-;2002:30:::1;2029:1;2002:18;:30::i;:::-;1938:101::o:0;44921:197:30:-;45038:45;;;;;;;:33;:45;;;;;45003:16;;45038:73;;:71;:73::i;4954:532:25:-;5066:21;:61;;;-1:-1:-1;212:66:24;5091:36:25;;;5066:61;5062:123;;;5150:24;;;;;;;;;;;;;;5062:123;5267:30;5278:18;5267:10;:30::i;:::-;5262:89;;5320:20;;;;;;;;;;;;;;5262:89;212:66:24;5398:43:25;;;;5437:4;5398:43;;;5452:27;;:::i;51854:132:17:-;51906:23;51959:20;:18;:20::i;:::-;51941:38;;51854:132;:::o;8358:328:30:-;8449:20;8474:87;1339:1:29;8526:10:30;8538:6;8546:4;8552:2;8556:1;8559;8474:17;:87::i;:::-;-1:-1:-1;8448:113:30;-1:-1:-1;8575:34:30;;;;8571:109;;8625:44;8655:13;8625:29;:44::i;:::-;8438:248;8358:328;;;:::o;44149:515:17:-;44287:12;44311:57;2587:6:14;44311:17:17;:57;;:::i;:::-;44379:31;44413:71;44437:5;701:3:14;44463:5:17;44470:2;257:1:14;44479:4:17;44413:23;:71::i;:::-;44379:105;;44504:41;44524:5;44531:2;44535:5;44542:2;44504:19;:41::i;:::-;44494:51;;44560:7;44556:102;;;44583:64;44605:8;44615:5;144:1:14;257;144;44583:21:17;:64::i;:::-;44301:363;44149:515;;;;;;:::o;42571:185:30:-;42681:34;;;;;;;:24;:34;;;;;;;;:38;;;;;;;;;;42646:16;;42681:68;;:59;;:66;:68::i;44036:229::-;44183:57;;;;;;;:45;:57;;;;;:64;44132:16;;44167:91;;44183:64;;;;;44249:8;44167:15;:91::i;9506:334:13:-;7797:35;:33;:35::i;:::-;9614:20:::1;9632:1;9614:17;:20::i;:::-;9649:18:::0;;9645:189:::1;;9684:12;9702:10;:15;;9725:14;9702:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9683:61;;;9762:7;9758:65;;9778:45;;;;;;;;;;;;;;47037:140:30::0;47121:49;;;;;:40;24274:55:36;;;47121:49:30;;;24256:74:36;47098:4:30;;47134:12;47121:40;;;;;;24229:18:36;;47121:49:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;20992:200::-;21121:64;21152:8;21162:5;21169:7;21178:6;21121:30;:64::i;45514:243::-;45666:57;;;;45627:4;45666:57;;;:45;:57;;;;;;;;:64;43212:34;;;;;;:24;:34;;;;;45666:64;;;;;;43212:38;;;;;;;;:69;;;;;:60;;;;:69;;;;;;45627:4;;43212:69;45650:100;45643:107;45514:243;-1:-1:-1;;;;45514:243:30:o;39400:843:17:-;39603:10;:19;;;;;:45;;-1:-1:-1;39626:10:17;:22;;;;39603:45;39598:123;;39672:38;;;;;;;;;;;;;;39598:123;39730:33;39753:9;39730:22;:33::i;:::-;39773:34;39810:86;39832:15;39849:5;39856:9;39867:5;39874:2;39878:7;39887:8;39810:21;:86::i;:::-;39915:17;;39773:123;;-1:-1:-1;39915:37:17;:17;39911:326;;567:1:14;40059:26:17;;40104:43;;39968:41;586::36;;40104:43:17;;;;;;;;;40116:7;;40104:43;;574:2:36;559:18;40104:43:17;;;;;;;39911:326;;;40185:41;;;;;;;;;;;;;;19514:883;19890:12;19861:18;7336:66;7383:18;7336:46;:66::i;:::-;19914:58:::1;2999:6:14;19914:17:17;:58;;:::i;:::-;19983:271;20041:5;20060:2;257:1:14;20093:5:17;20112:10;20136:5;257:1:14;20172:12:17;;20198:14;20226:18;19983:44;:271::i;:::-;20274:41;20294:5;20301:2;20305:5;20312:2;20274:19;:41::i;:::-;20264:51;;20330:7;20326:65;;;20353:27;20367:5;20374;20353:13;:27::i;:::-;19514:883:::0;;;;;;;;;;;;;:::o;21971:191:30:-;22065:90;1765:66:29;22137:5:30;22144:7;1765:66:29;22065:30:30;:90::i;15198:183::-;15280:94;1765:66:29;15352:5:30;15359:7;1765:66:29;15280:30:30;:94::i;9000:321:17:-;9193:33;9216:9;9193:22;:33::i;:::-;9236:78;9251:9;9262:5;9269:2;9273:6;9281:10;9293;9305:8;9236:14;:78::i;:::-;9000:321;;;;;;:::o;41641:118::-;41709:43;41734:10;41746:5;41709:24;:43::i;40594:547:30:-;40722:23;40760:15;;40757:378;;40878:57;;;40791:67;40878:57;;;:43;:57;;;;;40973:4;40959:26;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;40959:26:30;;40950:35;;41004:9;40999:126;41019:15;;;40999:126;;;41071:30;:39;41102:4;;41107:1;41102:7;;;;;;;:::i;:::-;;;;;;;41071:39;;;;;;;;;;;;41059:6;41066:1;41059:9;;;;;;;;:::i;:::-;;;;;;;;;;:51;41036:3;;40999:126;;42155:181;42263:34;;;;;;;:24;:34;;;;;;;;:38;;;;;;;;;;42228:16;;42263:66;;:64;:66::i;9685:346::-;9793:20;9818:88;1284:1:29;9865:10:30;9877:6;9885:4;9891:2;9895:7;9904:1;9818:17;:88::i;:::-;-1:-1:-1;9792:114:30;-1:-1:-1;9920:34:30;;;;9916:109;;9970:44;10000:13;9970:29;:44::i;:::-;9782:249;9685:346;;;;:::o;37432:1208:17:-;37810:22;37834:12;37781:18;7509:63;7553:18;7509:43;:63::i;:::-;37858:53:::1;3534:6:14;37858:17:17;:53;;:::i;:::-;37922:34;37959:241;37997:12;;38023:16;38053:5;202:1:14;38090:5:17;38109:4;38127:10;38151:7;38172:18;37959:24;:241::i;:::-;37922:278;;38273:240;38305:11;38334:16;38368:5;202:1:14;38415:5:17;38439:2;38460:7;38485:18;38273:14;:240::i;:::-;38211:302:::0;;-1:-1:-1;38211:302:17;-1:-1:-1;38524:110:17;::::1;;;38551:72;38573:11;38586:5;38593:7;38602:14;38618:4;38551:21;:72::i;:::-;37848:792;37432:1208:::0;;;;;;;;;;;;;;:::o;27235:646::-;27508:12;27532:57;3277:6:14;27532:17:17;:57;;:::i;:::-;27600:121;972:2:14;27639:5:17;202:1:14;27652:12:17;27666:5;27673:10;27685:5;27692:14;27708:12;;27600:20;:121::i;:::-;27741:58;27760:5;27767;27774:2;202:1:14;27784:14:17;27741:18;:58::i;:::-;27731:68;;27814:7;27810:65;;;27837:27;27851:5;27858;27837:13;:27::i;:::-;27235:646;;;;;;;;;;;:::o;14814:704::-;15210:4;14911:25;:296;15043:49;;;;;;;;;;;;;;;;;15119:24;;15004:161;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;14950:247;;;;;;14911:296;;;;;;;;;;;;:303;;;;;;;;;;;;;;;;;;15507:4;15225:22;:279;15354:35;;;;;;;;;;;;;;;;;15416:24;;15315:147;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;15261:233;;15315:147;15261:233;;;;15225:279;;;;;;;;;;-1:-1:-1;15225:279:17;:286;;;;;;;;;;;;;-1:-1:-1;;14814:704:17:o;14246:173:30:-;14349:63;14380:8;14390:5;14397:7;14406:5;14349:30;:63::i;47406:534:17:-;47547:12;47571:56;2859:6:14;47571:17:17;:56;;:::i;:::-;47638:31;47672:76;47696:5;972:2:14;47721:5:17;202:1:14;47734:6:17;47742:5;47672:23;:76::i;:::-;47638:110;;47768:50;47787:5;47794;47801:2;202:1:14;47811:6:17;47768:18;:50::i;:::-;47758:60;;47833:7;47829:105;;;47856:67;47878:8;47888:5;144:1:14;47909:6:17;144:1:14;47856:21:17;:67::i;38869:237:30:-;38931:7;38954:39;1035:3:29;38954:39:30;;;38950:87;;-1:-1:-1;39024:1:30;;38869:237;-1:-1:-1;38869:237:30:o;38950:87::-;-1:-1:-1;39054:45:30;;;;;;:34;:45;;;;;;;;;38869:237::o;46138:247::-;46293:57;;;46253:4;46293:57;;;:45;:57;;;;;;;;:64;43720:34;;;;;;:24;:34;;;;;46293:64;;;;;;43720:38;;;;;;;;:72;;;:24;:62;:72;;;;;;;46276:102;43605:194;2188:191:21;1214:13;:11;:13::i;:::-;2271:22:::1;::::0;::::1;2268:66;;2302:32;;;;;;;;;;;;;;2268:66;2344:28;2363:8;2344:18;:28::i;5818:140:25:-:0;5936:5;5923:11;5916:26;5818:140;;:::o;6999:169::-;7134:18;;6999:169::o;8171:123::-;8276:1;8263:11;8256:22;8171:123;:::o;6333:331::-;212:66:24;6432:36:25;;;6428:230;;;6531:5;6518:11;6511:26;18396:172:30;;:::o;6428:230:25:-;6608:26;;6333:331::o;7546:360::-;7643:13;212:66:24;7672:36:25;;;7668:232;;;-1:-1:-1;7760:18:25;;7546:360::o;7668:232::-;-1:-1:-1;7858:18:25;;7668:232;7546:360;;;:::o;8602:310::-;212:66:24;8688:36:25;;;8684:222;;;8787:1;8774:11;8767:22;17364:107:30;:::o;8684:222:25:-;8880:1;8860:22;;8602:310::o;11336:288:13:-;11455:28;14901:9;14877:21;:33;11425:58;11421:197;;;11503:13;;:22;;:26;11499:109;;11556:37;;;;;;;;;;;;;;12555:336;12672:28;14901:9;14877:21;:33;12641:59;12637:248;;12723:40;;;;;;;;;;;;;;12637:248;12800:6;12784:13;;:22;12810:1;12784:27;12780:105;;12834:40;;;;;;;;;;;;;;13634:228;13703:22;13771:28;14901:9;14877:21;:33;13741:58;13737:119;;;-1:-1:-1;13832:13:13;;13737:119;13634:228;:::o;11894:195::-;11986:13;;:22;;:26;11982:101;;12035:37;;;;;;;;;;;;;;14027:143;14150:13;;;14027:143::o;65416:793:17:-;65713:14;65730:273;65760:233;65808:9;65835:5;65858:2;65878:12;65908:5;65931:10;65959:13;:20;65973:5;65959:20;;;;;;;;;;;;;;;;2503:270:19;;;1652:160:14;2503:270:19;;;;39390:25:36;;;;39431:18;;;39424:34;;;;39477:42;39555:15;;;;39535:18;;;39528:43;39587:18;;;39580:34;;;;39630:19;;;39623:35;;;;39674:19;;;39667:35;;;;2692:10:19;39718:19:36;;;39711:44;39771:19;;;39764:35;39815:19;;;;39808:35;;;;2503:270:19;;;;;;;;;;39362:19:36;;;;2503:270:19;;2480:303;;;;;;2217:573;65730:273:17;65713:290;;66014:188;66044:5;66063:10;66087:14;66115:12;66141:5;66160:6;66180:12;;66014:16;:188::i;49770:442::-;49933:12;49967:69;838:4:14;50007:5:17;50014;50021:2;50025;50029:6;49967:19;:69::i;:::-;49957:79;;50052:7;50047:159;;50079:59;;;;;:32;35360:15:36;;;50079:59:17;;;35342:34:36;35412:15;;;35392:18;;;35385:43;35444:18;;;35437:34;;;35487:18;;;35480:34;;;35551:3;35530:19;;;35523:32;-1:-1:-1;35571:19:36;;;35564:30;50079:32:17;;;;;35611:19:36;;50079:59:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;50075:121;;-1:-1:-1;50177:4:17;50075:121;49770:442;;;;;;;:::o;85323:320::-;85432:25;;;202:1:14;85432:25:17;;;:16;:25;;;;;;;;85475:1;85466:10;;;85432:46;;;;;;;:71;;257:1:14;85525:19:17;;;;85432:71;;;;;;;85424:121;:129;85420:207;;85580:32;;;;;;;;;;;;;;59978:248;60090:45;;;;:25;:45;;;;;;;;60085:135;;60158:51;;;;;;;;;;;;;;67380:687;67743:317;838:4:14;67827:5:17;67846:2;67862:12;67888:5;67907:10;67931:5;67950:14;67978:12;;68004:14;68032:18;67743:38;:317::i;62002:843::-;62205:31;62259:96;62281:18;62301:5;62308:9;62319:5;62326:2;62205:31;62344:10;62259:21;:96::i;:::-;62378:19;;;;-1:-1:-1;62400:15:17;62378:19;;;;;;:37;62374:122;;;62438:47;;;;;;;;;;;;;;62374:122;62509:15;;;;;;;-1:-1:-1;;62505:112:17;;;62556:50;;;;;;;;;;;;;;62505:112;62630:15;62627:212;;;62661:19;;;;;;62627:212;;;62701:15;;62719:17;62701:15;;;;;;:35;62697:142;;;62780:34;;;;;;;;;;;;;;;;;;;;;;;62697:142;62002:843;;;;;;;;:::o;86103:825::-;86311:18;;86307:615;;86349:13;86345:567;;;86489:42;;86568:33;86489:42;;;;;;;;;;;;;86568:33;;;;;;;;86624:45;;22820:25:36;;;86624:45:17;;;;86638:7;;86624:45;;22808:2:36;22793:18;86624:45:17;;;;;;;86345:567;;;86694:15;;86712:17;86694:15;;;;;;:35;86690:222;;;86837:42;;;;;;;;;;;;;;;;;;;;;;86103:825;;;;;:::o;90443:106::-;90529:13;:11;:13::i;10646:222:13:-;10740:13;;;10764:30;;;;10810:51;;;13591:25:36;;;13647:2;13632:18;;13625:34;;;10810:51:13;;13564:18:36;10810:51:13;;;;;;;10706:162;10646:222;:::o;51844:968:30:-;52083:6;;52130:4;52112:23;;;;52108:454;;-1:-1:-1;1720:10:29;;-1:-1:-1;1720:10:29;52505:46:30;;52108:454;52579:226;;;;;;;;35956:25:36;;;36000:42;36078:15;;;36058:18;;;36051:43;36130:15;;;36110:18;;;36103:43;36182:15;;;36162:18;;;36155:43;36235:15;;36214:19;;;36207:44;36267:19;;;36260:35;;;36311:19;;;36304:35;;;52608:4:30;;52579:64;;35928:19:36;;52579:226:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;52572:233;;;;51844:968;;;;;;;;;;;:::o;53951:182::-;54072:13;54066:4;54059:27;54112:4;54106;54099:18;53206:566;53427:57;;;53314:30;53427:57;;;:45;:57;;;;;53533:27;;53314:30;;53427:57;1035:3:29;53533:27:30;;;:56;:182;;53684:31;;;;;;;53533:182;;;53640:27;;;;53605:63;;;;:34;:63;;;;;;;;53533:182;53738:27;;;;;;;;;;;-1:-1:-1;53495:220:30;-1:-1:-1;;53206:566:30:o;59381:1172::-;59650:20;59682:15;59700:34;;;59682:52;;59784:4;59778:11;59814:8;59809:3;59802:21;59858:20;59851:4;59847:3;59843:13;59836:43;59914:11;59907:4;59903:3;59899:13;59892:34;59961:7;59954:4;59950:3;59946:13;59939:30;60004:5;59997:4;59993:3;59989:13;59982:28;60045:3;60038:4;60034:3;60030:13;60023:26;60084:8;60077:4;60073:3;60069:13;60062:31;60128:7;60121:4;60117:3;60113:13;60106:30;60170:4;60166:3;60162:13;60156:4;60149:27;60251:4;60245;60239;60234:3;60224:8;60217:5;60204:52;60190:66;;60279:6;60269:227;;60391:16;60445:4;60442:1;60439;60424:26;60477:4;60474:1;60467:15;60269:227;-1:-1:-1;;60532:4:30;60526:11;;59381:1172;-1:-1:-1;;;;;;;;;59381:1172:30:o;58478:562::-;58683:10;58695:8;58705:10;56982:77;57026:10;57038:8;57048:10;56982:43;:77::i;:::-;2767:20:33;2926:24;;;2857:36;2970:4;2963:37;3045:4;3029:21;;58727:79:30::1;::::0;58740:37:::1;58795:8;58779:26;;58727:12;:79;;:::i;:::-;58816:32;2233:24:33::0;;;2277:4;2270:21;;;2343:4;2327:21;;2324:1;2320:29;58907:66:30::1;2320:29:33::0;58946:26:30::1;::::0;::::1;58907:66;:12;:66;:::i;:::-;58983:50;58996:28;:24:::0;59023:1:::1;58996:28;:::i;:::-;59026:6;58983:12;:50;;:::i;:::-;58717:323;58478:562:::0;;;;;;;:::o;60477:242:17:-;60586:42;;;;:22;:42;;;;;;;;60581:132;;60651:51;;;;;;;;;;;;;;77475:657;77799:34;77859:266;77892:12;;77918:16;838:4:14;77980:5:17;77999:2;78015:5;78034:4;78052:10;78076:7;78097:18;77859:19;:266::i;:::-;77845:280;77475:657;-1:-1:-1;;;;;;;;;;;77475:657:17:o;83908:1132::-;84405:18;;84329:36;;;;;84264:22;;84405:18;;;;;84388:35;;84384:101;;;84456:18;;;;;;;;-1:-1:-1;84384:101:17;84516:16;:34;;;84499:14;:51;84495:136;;;84573:47;;;;;;;;;;;;;;84495:136;84665:45;;;;;;;;;;;;;;;;;;;;;;;84729:55;;22820:25:36;;;84757:10:17;;84729:55;;;;84741:7;;84729:55;;22808:2:36;22793:18;84729:55:17;;;;;;;84809:18;;;;;;;;:23;84805:157;;84848:38;;;;459:1:14;84848:38:17;;;84905:46;;-1:-1:-1;586:41:36;;84933:10:17;;84905:46;;;;84917:7;;84905:46;;574:2:36;559:18;84905:46:17;;;;;;;84805:157;84982:51;84996:5;85003;85010:2;85014;85018:14;84982:13;:51;;:::i;:::-;84972:61;;83908:1132;;;;;;;;;;;:::o;57554:474:30:-;57765:10;57777:8;57787:10;56982:77;57026:10;57038:8;57048:10;56982:43;:77::i;:::-;2767:20:33;2926:24;;;2857:36;2970:4;2963:37;3045:4;3029:21;;57809:114:30::1;::::0;57912:8:::1;57896:26;;57862:15;:30;;57891:1;57862:30;;;57880:8;57862:30;57861:61;57809:12;:114;;:::i;:::-;57933:88;57946:46;57972:10;57984:7;2178:20:33::0;2233:24;;;2277:4;2270:21;2343:4;2327:21;;2324:1;2320:29;;2060:304;89640:578:17;89920:21;89943:18;89973:30;90006:81;90028:10;90040:5;90047:9;90058:5;90065:2;90069:7;90078:8;90006:21;:81::i;:::-;90113:18;;;;-1:-1:-1;90134:15:17;90113:18;;;;;;:36;:57;;90156:14;;;;;;;90113:57;;;90152:1;90113:57;90193:18;;90097:73;;;;;90193:18;;;;;;;-1:-1:-1;90097:73:17;-1:-1:-1;;;;;;;;89640:578:17:o;69235:683::-;69596:315;972:2:14;69678:5:17;69697:2;69713:12;69739:5;69758:10;69782:5;69801:14;69829:12;;69855:14;69883:18;69596:38;:315::i;50898:614::-;51065:12;51099:69;972:2:14;51137:5:17;51144;51151:2;202:1:14;51161:6:17;51099:19;:69::i;:::-;51089:79;;51184:7;51179:327;;51254:71;;;51243:10;37017:15:36;;;51254:71:17;;;36999:34:36;37069:15;;;37049:18;;;37042:43;37101:18;;;;37094:34;;;51254:71:17;;;;;;;;;;36911:18:36;;;;51254:71:17;;;;;;;;;51277:28;51254:71;;;51243:83;;-1:-1:-1;;;;51243:10:17;;;;:83;;51254:71;51243:83;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;51207:119;;;;51345:7;51340:156;;51382:4;51372:14;;51340:156;;;51411:11;;:15;51407:89;;51468:4;51457:24;;;;;;;;;;;;:::i;:::-;51456:25;51446:35;;51407:89;51193:313;;50898:614;;;;;;;:::o;86934:306::-;701:3:14;87026:9:17;:30;:78;;;;838:4:14;87073:9:17;:31;87026:78;:124;;;;972:2:14;87121:9:17;:29;87026:124;87008:226;;87196:27;;;;;;;;;;;;;;61004:335;61124:25;;;202:1:14;61124:25:17;;;:16;:25;;;;;;;;61167:1;61158:10;;;61124:46;;;;;;;:71;;257:1:14;61217:19:17;;;;61124:71;;;;;;;61116:121;61112:211;;61272:36;;;;;;;;;;;;;;908:670:19;1258:303;;;1314:195:14;1258:303:19;;;37830:25:36;37871:18;;;37864:34;;;37917:42;37995:15;;;37975:18;;;37968:43;38027:18;;;38020:34;;;38070:19;;;38063:35;;;38114:19;;;38107:35;;;38179:15;;38158:19;;;38151:44;38211:19;;;38204:35;;;38255:19;;;38248:35;;;38299:19;;;38292:35;;;1204:12:19;;37802:19:36;;1258:303:19;;;;;;;;;;;;;1235:336;;;;;;1228:343;;908:670;;;;;;;;;;;:::o;4292:165:20:-;4369:7;4395:55;4417:20;:18;:20::i;:::-;4439:10;8536:4:9;8530:11;8566:10;8554:23;;8606:4;8597:14;;8590:39;;;;8658:4;8649:14;;8642:34;8712:4;8697:20;;;8336:397;52615:1385:17;52751:2;52731:22;;;52727:1267;;52975:30;;53062:2;53040:25;;53027:39;53131:2;53109:25;;53096:39;52769:9;53088:48;;;;52769:9;53196:30;53210:6;53088:48;52975:30;53027:39;53196:13;:30::i;:::-;53163:63;;;;53253:6;53244:15;;:5;:15;;;;:26;;;;53263:7;53244:26;53240:114;;;53290:49;53314:5;53321:6;53329:9;;53290:23;:49::i;:::-;52755:609;;;;;52727:1267;;;53394:2;53374:22;;;53370:624;;53596:30;;53684:2;53662:25;;53649:39;53412:9;;53748:28;53762:6;53596:30;53649:39;53748:13;:28::i;:::-;53715:61;;;;53803:6;53794:15;;:5;:15;;;;:26;;;;53813:7;53794:26;53790:114;;;53840:49;53864:5;53871:6;53879:9;;53840:23;:49::i;:::-;53398:516;;;;53370:624;;;53934:49;53958:5;53965:6;53973:9;;53934:23;:49::i;75829:510::-;76047:31;76081:94;76103:18;76123:5;76130:9;76141:5;76148:2;76047:31;76166:8;76081:21;:94::i;:::-;76194:32;;76236:24;;76194:32;;;;;;;76236:24;;;;;;76194:32;76236:24;;;;;;;;;;;;76276:56;;;38538:25:36;;;38594:2;38579:18;;38572:93;;;;38681:18;;38674:55;;;;76194:32:17;;-1:-1:-1;76276:56:17;;;;;;;;;;;;;;38526:2:36;38511:18;76276:56:17;;;;;;;76037:302;75829:510;;;;;;;:::o;48621:409::-;48759:12;48793:65;701:3:14;48832:5:17;48839;48846:2;48850;257:1:14;48793:19:17;:65::i;:::-;48783:75;;48874:7;48869:155;;48901:42;;;;;:27;37017:15:36;;;48901:42:17;;;36999:34:36;37069:15;;;37049:18;;;37042:43;37101:18;;;37094:34;;;48901:27:17;;;;;36911:18:36;;48901:42:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;48897:117;;-1:-1:-1;48995:4:17;48621:409;;;;;;:::o;1479:124:21:-;1367:7;1393:6;1537:23;1393:6;719:10:7;1537:23:21;1534:62;;1569:27;;;;;;;;;;;;;;2533:187;2606:16;2625:6;;;2641:17;;;;;;;;;;2673:40;;2625:6;;;;;;;2673:40;;2606:16;2673:40;2596:124;2533:187;:::o;10064:300:26:-;10127:16;10155:22;10180:19;10188:3;10180:7;:19::i;10291:407:25:-;10374:7;10636:17;:28;;10683:2;10671:9;:14;;;;:::i;:::-;10636:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;10627:64:25;;10291:407;-1:-1:-1;;;10291:407:25:o;3251:230:20:-;3304:7;3344:14;3327:13;:31;3323:152;;-1:-1:-1;3381:22:20;;3251:230::o;3323:152::-;3441:23;3578:81;;;1857:95;3578:81;;;40516:25:36;3601:11:20;40557:18:36;;;40550:34;;;;3614:14:20;40600:18:36;;;40593:34;3630:13:20;40643:18:36;;;40636:34;3653:4:20;40686:19:36;;;40679:84;3542:7:20;;40488:19:36;;3578:81:20;;;;;;;;;;;;3568:92;;;;;;3561:99;;3487:180;;63403:434:17;63693:31;63747:10;:73;63758:61;63780:7;63789:9;63800:5;63807:2;63811:7;64490:20;;;;64402:11;64490:20;;;:13;:20;;;;;;;;;;64441:70;;;;;41122:34:36;;;;41172:18;;;41165:34;;;;41235:15;;;;41215:18;;;41208:43;41267:18;;;41260:34;;;;41310:19;;;41303:35;41354:19;;;;41347:35;;;;64441:70:17;;;;;;;;;;41033:19:36;;64441:70:17;;;64431:81;;;;;;64271:248;63758:61;63747:73;;;;;;;;;;;:83;63821:8;63747:83;;;;;;;;;;;;;;;63736:94;;63403:434;;;;;;;;;:::o;71087:685::-;71449:316;701:3:14;71532:5:17;71551:2;71567:12;71593:5;71612:10;71636:5;71655:14;71683:12;;71709:14;71737:18;71449:38;:316::i;79264:653::-;79586:34;79646:264;79679:12;;79705:16;972:2:14;79765:5:17;79784:2;79800:5;79819:4;79837:10;79861:7;79882:18;79646:19;:264::i;74659:610::-;74932:10;74914:15;:28;74910:115;;;74965:49;;;;;;;;;;;;;;74910:115;75056:12;75039:14;:29;75035:118;;;75091:51;;;;;;;;;;;;;;75035:118;75163:38;75188:5;75195;75163:24;:38::i;:::-;75211:51;75234:6;75242:12;;75256:5;75211:22;:51::i;49794:835:30:-;49996:12;50021:15;50038:26;50081:293;701:3:14;50116:9:30;:30;:101;;1400:1:29;50116:101:30;;;1284:1:29;50116:101:30;50236:5;50260:10;50289:4;50312:2;50333;50354:6;50081:17;:293::i;:::-;50020:354;;-1:-1:-1;50020:354:30;-1:-1:-1;50389:41:30;;;;;:77;;;50457:9;50434:19;:32;;;50389:77;50385:238;;;50492:29;;;;;;-1:-1:-1;50385:238:30;;;50559:53;;;;;;;;;;;;;;50385:238;50010:619;;49794:835;;;;;;;;:::o;72891:869:17:-;73274:14;73291:255;73338:9;73361:5;73381:2;73398:12;73425:5;73444;73464:10;73489:14;73518:18;73291:33;:255::i;:::-;73274:272;;73565:188;73595:5;73614:10;73638:14;73666:12;73692:5;73711:6;73731:12;;73565:16;:188::i;:::-;73264:496;72891:869;;;;;;;;;;;;:::o;54843:1284:30:-;55070:57;;;55010;55070;;;:45;:57;;;;;55153:38;;;;;2713:6:29;4361:16:33;4360:23;55138:195:30;;55255:67;;;;;;;;;;;;;;55138:195;55358:38;;;;;2792:6:29;4361:16:33;4360:23;55343:299:30;;55472:37;;;;;55468:164;;55536:81;;;;;;;;;;;;;;55468:164;55705:31;;;;;;;55657:47;:80;;;:47;;:80;;;:47;:80;;;:114;;;;;:102;;:114;;;;;;:47;:114;55652:469;;55803:38;;;;;2932:6:29;4361:16:33;4360:23;;55791:221:30;;-1:-1:-1;55914:98:30;;;:47;:98;;;:86;:47;:98;:47;:98;;;:47;:98;55913:99;55791:221;55787:324;;;56039:57;;;;;;;;;;;;;;81104:1752:17;81448:34;81534:17;81498:33;;:53;81494:129;;;81574:38;;;;;;;;;;;;;;81494:129;81647:88;81669:15;81686:5;81693:9;81704:5;81711:2;81715:7;81724:10;81647:21;:88::i;:::-;81750:17;;81633:102;;-1:-1:-1;81750:37:17;:17;81746:1104;;81807:18;;;;;;;;:23;81803:809;;81850:512;81894:387;81953:9;81988:5;82020:2;82049:33;;82108:5;82139:4;81894:387;;;82207:7;82241:18;81894:33;:387::i;:::-;82304:12;;82339:5;81850:22;:512::i;:::-;82381:63;;82462:35;;82381:63;82410:33;;82381:63;;;;;;;82462:35;;;;;;;;;;;;;;82523:74;;22820:25:36;;;82551:10:17;;82523:74;;;;82535:7;;82523:74;;22808:2:36;22793:18;82523:74:17;;;;;;;81803:809;82648:22;;;;;;;82630:15;:40;82626:135;;;82697:49;;;;;;;;;;;;;;56184:470;56276:12;;56333:66;56320:79;;56316:244;;;-1:-1:-1;56532:4:17;;-1:-1:-1;56546:1:17;56524:25;;56316:244;56579:26;;;;;;;;;;;;40081:25:36;;;40154:4;40142:17;;40122:18;;;40115:45;;;;40176:18;;;40169:34;;;40219:18;;;40212:34;;;56579:26:17;;40053:19:36;;56579:26:17;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;56579:26:17;;;;;56626:20;;;;;-1:-1:-1;56579:26:17;-1:-1:-1;;56184:470:17;;;;;;;;:::o;54405:361::-;54520:6;:18;;;54542:1;54520:23;54517:104;;54566:44;;;;;;;;;;;;;;54517:104;54636:46;54658:6;54666:4;54672:9;;54636:21;:46::i;:::-;54631:129;;54705:44;;;;;;;;;;;;;;55211:315;55295:12;;1118:66:14;55371:19:17;;55442:2;55434:3;55428:9;;;55414:30;55479;55493:6;55414:30;55504:1;55371:19;55479:13;:30::i;:::-;55459:50;;;;-1:-1:-1;55211:315:17;-1:-1:-1;;;;;;55211:315:17:o;5375:109:26:-;5431:16;5466:3;:11;;5459:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5375:109;;;:::o;88007:877:17:-;88425:20;;;88314:14;88425:20;;;:13;:20;;;;;;88477:400;88511:352;88581:9;88612:5;88640:2;88665:6;88694:5;88722:10;88755:14;88792:18;88425:20;88511:48;:352::i;57105:1792::-;57243:12;57290:1496;;;57376:8;57420:4;57414:11;57520:13;57515:3;57508:26;57642:5;57635:4;57630:3;57626:14;57619:29;57762:4;57755;57750:3;57746:14;57739:28;57855:16;57848:4;57843:3;57839:14;57832:40;57995:16;57977;57970:4;57965:3;57961:14;57948:64;58194:4;58190:9;58183:4;58165:16;58161:27;58157:43;58151:4;58147:54;58286:10;58281:3;58277:20;58271:4;58264:34;58572:4;58566;58554:10;58549:3;58540:7;58533:5;58522:55;58514:4;58496:16;58493:26;58486:34;58482:96;58479:293;;;58714:13;58707:4;58701:11;58698:30;58686:42;;58749:5;;;;58479:293;;;57290:1496;;;;;;:::o;:::-;58810:71;58864:16;58846;58840:4;58832:6;58810:71;:::i;3619:691:19:-;3995:298;;;;;;37830:25:36;;;37871:18;;;37864:34;;;37917:42;37995:15;;37975:18;;;37968:43;38027:18;;;38020:34;;;38070:19;;;38063:35;;;38114:19;;;38107:35;;;4180:10:19;38158:19:36;;;38151:44;38211:19;;;38204:35;;;38255:19;;;38248:35;;;38299:19;;;38292:35;;;3941:12:19;;37802:19:36;;3995:298:19;37431:902:36;14:177;99:66;92:5;88:78;81:5;78:89;68:117;;181:1;178;171:12;196:245;254:6;307:2;295:9;286:7;282:23;278:32;275:52;;;323:1;320;313:12;275:52;362:9;349:23;381:30;405:5;381:30;:::i;638:196::-;706:20;;766:42;755:54;;745:65;;735:93;;824:1;821;814:12;839:186;898:6;951:2;939:9;930:7;926:23;922:32;919:52;;;967:1;964;957:12;919:52;990:29;1009:9;990:29;:::i;1030:347::-;1081:8;1091:6;1145:3;1138:4;1130:6;1126:17;1122:27;1112:55;;1163:1;1160;1153:12;1112:55;-1:-1:-1;1186:20:36;;1229:18;1218:30;;1215:50;;;1261:1;1258;1251:12;1215:50;1298:4;1290:6;1286:17;1274:29;;1350:3;1343:4;1334:6;1326;1322:19;1318:30;1315:39;1312:59;;;1367:1;1364;1357:12;1312:59;1030:347;;;;;:::o;1382:977::-;1524:6;1532;1540;1548;1556;1564;1572;1580;1588;1596;1649:3;1637:9;1628:7;1624:23;1620:33;1617:53;;;1666:1;1663;1656:12;1617:53;1689:29;1708:9;1689:29;:::i;:::-;1679:39;;1765:2;1754:9;1750:18;1737:32;1727:42;;1816:2;1805:9;1801:18;1788:32;1778:42;;1867:2;1856:9;1852:18;1839:32;1829:42;;1918:3;1907:9;1903:19;1890:33;1880:43;;1942:39;1976:3;1965:9;1961:19;1942:39;:::i;:::-;1932:49;;2000:39;2034:3;2023:9;2019:19;2000:39;:::i;:::-;1990:49;;2086:3;2075:9;2071:19;2058:33;2048:43;;2142:3;2131:9;2127:19;2114:33;2170:18;2162:6;2159:30;2156:50;;;2202:1;2199;2192:12;2156:50;2241:58;2291:7;2282:6;2271:9;2267:22;2241:58;:::i;:::-;2215:84;;2318:8;2308:18;;;2345:8;2335:18;;;1382:977;;;;;;;;;;;;;:::o;2364:1121::-;2524:6;2532;2540;2548;2556;2564;2572;2580;2588;2596;2604:7;2613;2667:3;2655:9;2646:7;2642:23;2638:33;2635:53;;;2684:1;2681;2674:12;2635:53;2707:29;2726:9;2707:29;:::i;:::-;2697:39;;2783:2;2772:9;2768:18;2755:32;2745:42;;2834:2;2823:9;2819:18;2806:32;2796:42;;2885:2;2874:9;2870:18;2857:32;2847:42;;2936:3;2925:9;2921:19;2908:33;2898:43;;2960:39;2994:3;2983:9;2979:19;2960:39;:::i;:::-;2950:49;;3018:39;3052:3;3041:9;3037:19;3018:39;:::i;:::-;3008:49;;3104:3;3093:9;3089:19;3076:33;3066:43;;3156:3;3145:9;3141:19;3128:33;3118:43;;3208:3;3197:9;3193:19;3180:33;3170:43;;3263:18;3256:3;3245:9;3241:19;3228:33;3225:57;3222:77;;;3295:1;3292;3285:12;3222:77;3336:85;3413:7;3405:3;3394:9;3390:19;3377:33;3366:9;3362:49;3336:85;:::i;:::-;3441:9;3430:20;;3470:9;3459:20;;;;2364:1121;;;;;;;;;;;;;;:::o;3490:472::-;3585:6;3593;3601;3609;3617;3670:3;3658:9;3649:7;3645:23;3641:33;3638:53;;;3687:1;3684;3677:12;3638:53;3710:29;3729:9;3710:29;:::i;:::-;3700:39;;3758:38;3792:2;3781:9;3777:18;3758:38;:::i;:::-;3748:48;;3815:38;3849:2;3838:9;3834:18;3815:38;:::i;:::-;3490:472;;;;-1:-1:-1;3805:48:36;;3900:2;3885:18;;3872:32;;-1:-1:-1;3951:3:36;3936:19;3923:33;;3490:472;-1:-1:-1;;3490:472:36:o;3967:180::-;4026:6;4079:2;4067:9;4058:7;4054:23;4050:32;4047:52;;;4095:1;4092;4085:12;4047:52;-1:-1:-1;4118:23:36;;3967:180;-1:-1:-1;3967:180:36:o;4152:156::-;4218:20;;4278:4;4267:16;;4257:27;;4247:55;;4298:1;4295;4288:12;4313:256;4379:6;4387;4440:2;4428:9;4419:7;4415:23;4411:32;4408:52;;;4456:1;4453;4446:12;4408:52;4479:27;4496:9;4479:27;:::i;:::-;4469:37;;4525:38;4559:2;4548:9;4544:18;4525:38;:::i;:::-;4515:48;;4313:256;;;;;:::o;4574:::-;4640:6;4648;4701:2;4689:9;4680:7;4676:23;4672:32;4669:52;;;4717:1;4714;4707:12;4669:52;4740:29;4759:9;4740:29;:::i;:::-;4730:39;;4788:36;4820:2;4809:9;4805:18;4788:36;:::i;4835:632::-;5006:2;5058:21;;;5128:13;;5031:18;;;5150:22;;;4977:4;;5006:2;5229:15;;;;5203:2;5188:18;;;4977:4;5272:169;5286:6;5283:1;5280:13;5272:169;;;5347:13;;5335:26;;5416:15;;;;5381:12;;;;5308:1;5301:9;5272:169;;;-1:-1:-1;5458:3:36;;4835:632;-1:-1:-1;;;;;;4835:632:36:o;5472:367::-;5535:8;5545:6;5599:3;5592:4;5584:6;5580:17;5576:27;5566:55;;5617:1;5614;5607:12;5566:55;-1:-1:-1;5640:20:36;;5683:18;5672:30;;5669:50;;;5715:1;5712;5705:12;5669:50;5752:4;5744:6;5740:17;5728:29;;5812:3;5805:4;5795:6;5792:1;5788:14;5780:6;5776:27;5772:38;5769:47;5766:67;;;5829:1;5826;5819:12;5844:511;5939:6;5947;5955;6008:2;5996:9;5987:7;5983:23;5979:32;5976:52;;;6024:1;6021;6014:12;5976:52;6047:29;6066:9;6047:29;:::i;:::-;6037:39;;6127:2;6116:9;6112:18;6099:32;6154:18;6146:6;6143:30;6140:50;;;6186:1;6183;6176:12;6140:50;6225:70;6287:7;6278:6;6267:9;6263:22;6225:70;:::i;:::-;5844:511;;6314:8;;-1:-1:-1;6199:96:36;;-1:-1:-1;;;;5844:511:36:o;6360:250::-;6445:1;6455:113;6469:6;6466:1;6463:13;6455:113;;;6545:11;;;6539:18;6526:11;;;6519:39;6491:2;6484:10;6455:113;;;-1:-1:-1;;6602:1:36;6584:16;;6577:27;6360:250::o;6615:1130::-;6775:4;6804:2;6844;6833:9;6829:18;6874:2;6863:9;6856:21;6897:6;6932;6926:13;6963:6;6955;6948:22;7001:2;6990:9;6986:18;6979:25;;7063:2;7053:6;7050:1;7046:14;7035:9;7031:30;7027:39;7013:53;;7101:2;7093:6;7089:15;7122:1;7132:584;7146:6;7143:1;7140:13;7132:584;;;7235:66;7223:9;7215:6;7211:22;7207:95;7202:3;7195:108;7332:6;7326:13;7374:2;7368:9;7405:8;7397:6;7390:24;7427:74;7492:8;7487:2;7479:6;7475:15;7470:2;7466;7462:11;7427:74;:::i;:::-;7558:2;7544:17;7563:66;7540:90;7528:103;;;;7524:112;;;-1:-1:-1;7694:12:36;;;;7659:15;;;;7168:1;7161:9;7132:584;;;-1:-1:-1;7733:6:36;;6615:1130;-1:-1:-1;;;;;;;6615:1130:36:o;7750:547::-;7854:6;7862;7870;7878;7886;7894;7947:3;7935:9;7926:7;7922:23;7918:33;7915:53;;;7964:1;7961;7954:12;7915:53;7987:29;8006:9;7987:29;:::i;:::-;7977:39;;8035:38;8069:2;8058:9;8054:18;8035:38;:::i;:::-;8025:48;;8092:38;8126:2;8115:9;8111:18;8092:38;:::i;:::-;8082:48;;8149:38;8183:2;8172:9;8168:18;8149:38;:::i;:::-;8139:48;;8234:3;8223:9;8219:19;8206:33;8196:43;;8286:3;8275:9;8271:19;8258:33;8248:43;;7750:547;;;;;;;;:::o;8636:254::-;8704:6;8712;8765:2;8753:9;8744:7;8740:23;8736:32;8733:52;;;8781:1;8778;8771:12;8733:52;8804:29;8823:9;8804:29;:::i;:::-;8794:39;8880:2;8865:18;;;;8852:32;;-1:-1:-1;;;8636:254:36:o;9096:616::-;9209:6;9217;9225;9233;9241;9249;9257;9310:3;9298:9;9289:7;9285:23;9281:33;9278:53;;;9327:1;9324;9317:12;9278:53;9363:9;9350:23;9340:33;;9392:38;9426:2;9415:9;9411:18;9392:38;:::i;:::-;9382:48;;9449:38;9483:2;9472:9;9468:18;9449:38;:::i;:::-;9439:48;;9506:38;9540:2;9529:9;9525:18;9506:38;:::i;:::-;9496:48;;9563:39;9597:3;9586:9;9582:19;9563:39;:::i;:::-;9553:49;;9649:3;9638:9;9634:19;9621:33;9611:43;;9701:3;9690:9;9686:19;9673:33;9663:43;;9096:616;;;;;;;;;;:::o;10052:334::-;10129:6;10137;10145;10198:2;10186:9;10177:7;10173:23;10169:32;10166:52;;;10214:1;10211;10204:12;10166:52;10237:29;10256:9;10237:29;:::i;:::-;10227:39;;10285:38;10319:2;10308:9;10304:18;10285:38;:::i;:::-;10275:48;;10342:38;10376:2;10365:9;10361:18;10342:38;:::i;:::-;10332:48;;10052:334;;;;;:::o;10391:322::-;10468:6;10476;10484;10537:2;10525:9;10516:7;10512:23;10508:32;10505:52;;;10553:1;10550;10543:12;10505:52;10576:29;10595:9;10576:29;:::i;:::-;10566:39;10652:2;10637:18;;10624:32;;-1:-1:-1;10703:2:36;10688:18;;;10675:32;;10391:322;-1:-1:-1;;;10391:322:36:o;10718:478::-;10813:6;10821;10829;10837;10845;10898:3;10886:9;10877:7;10873:23;10869:33;10866:53;;;10915:1;10912;10905:12;10866:53;10938:29;10957:9;10938:29;:::i;:::-;10928:39;;10986:38;11020:2;11009:9;11005:18;10986:38;:::i;:::-;10976:48;;11043:38;11077:2;11066:9;11062:18;11043:38;:::i;:::-;11033:48;;11100:38;11134:2;11123:9;11119:18;11100:38;:::i;:::-;10718:478;;;;-1:-1:-1;10718:478:36;;11185:3;11170:19;11157:33;;10718:478;-1:-1:-1;;10718:478:36:o;11201:164::-;11270:5;11315:2;11306:6;11301:3;11297:16;11293:25;11290:45;;;11331:1;11328;11321:12;11290:45;-1:-1:-1;11353:6:36;11201:164;-1:-1:-1;11201:164:36:o;11370:167::-;11437:20;;11497:14;11486:26;;11476:37;;11466:65;;11527:1;11524;11517:12;11542:1130;11728:6;11736;11744;11752;11760;11768;11776;11784;11792;11800;11808:7;11862:3;11850:9;11841:7;11837:23;11833:33;11830:53;;;11879:1;11876;11869:12;11830:53;11919:9;11906:23;11952:18;11944:6;11941:30;11938:50;;;11984:1;11981;11974:12;11938:50;12023:58;12073:7;12064:6;12053:9;12049:22;12023:58;:::i;:::-;12100:8;;-1:-1:-1;11997:84:36;-1:-1:-1;12154:72:36;;-1:-1:-1;12218:7:36;12213:2;12198:18;;12154:72;:::i;:::-;12144:82;;12245:39;12279:3;12268:9;12264:19;12245:39;:::i;:::-;12235:49;;12331:3;12320:9;12316:19;12303:33;12293:43;;12355:39;12389:3;12378:9;12374:19;12355:39;:::i;:::-;12345:49;;12413:39;12447:3;12436:9;12432:19;12413:39;:::i;:::-;12403:49;;12499:3;12488:9;12484:19;12471:33;12461:43;;12523:38;12556:3;12545:9;12541:19;12523:38;:::i;:::-;12513:48;;12608:3;12597:9;12593:19;12580:33;12570:43;;12661:3;12650:9;12646:19;12633:33;12622:44;;11542:1130;;;;;;;;;;;;;;:::o;12940:472::-;13035:6;13043;13051;13059;13067;13120:3;13108:9;13099:7;13095:23;13091:33;13088:53;;;13137:1;13134;13127:12;13088:53;13160:29;13179:9;13160:29;:::i;:::-;13150:39;;13208:38;13242:2;13231:9;13227:18;13208:38;:::i;:::-;13198:48;;13293:2;13282:9;13278:18;13265:32;13255:42;;13316:38;13350:2;13339:9;13335:18;13316:38;:::i;13670:1050::-;13821:6;13829;13837;13845;13853;13861;13869;13877;13885;13893;13901:7;13955:3;13943:9;13934:7;13930:23;13926:33;13923:53;;;13972:1;13969;13962:12;13923:53;13995:29;14014:9;13995:29;:::i;:::-;13985:39;;14071:2;14060:9;14056:18;14043:32;14033:42;;14122:2;14111:9;14107:18;14094:32;14084:42;;14173:2;14162:9;14158:18;14145:32;14135:42;;14196:39;14230:3;14219:9;14215:19;14196:39;:::i;:::-;14186:49;;14254:39;14288:3;14277:9;14273:19;14254:39;:::i;:::-;14244:49;;14340:3;14329:9;14325:19;14312:33;14302:43;;14392:3;14381:9;14377:19;14364:33;14354:43;;14444:3;14433:9;14429:19;14416:33;14406:43;;14500:3;14489:9;14485:19;14472:33;14528:18;14520:6;14517:30;14514:50;;;14560:1;14557;14550:12;14514:50;14600:58;14650:7;14641:6;14630:9;14626:22;14600:58;:::i;:::-;14573:85;;14677:8;14667:18;;;14705:9;14694:20;;;13670:1050;;;;;;;;;;;;;;:::o;14725:328::-;14799:6;14807;14815;14868:2;14856:9;14847:7;14843:23;14839:32;14836:52;;;14884:1;14881;14874:12;14836:52;14907:28;14925:9;14907:28;:::i;:::-;14897:38;;14954:36;14986:2;14975:9;14971:18;14954:36;:::i;15058:816::-;15171:6;15179;15187;15195;15203;15256:2;15244:9;15235:7;15231:23;15227:32;15224:52;;;15272:1;15269;15262:12;15224:52;15312:9;15299:23;15341:18;15382:2;15374:6;15371:14;15368:34;;;15398:1;15395;15388:12;15368:34;15437:58;15487:7;15478:6;15467:9;15463:22;15437:58;:::i;:::-;15514:8;;-1:-1:-1;15411:84:36;-1:-1:-1;15411:84:36;;-1:-1:-1;15568:37:36;15601:2;15586:18;;15568:37;:::i;:::-;15558:47;;15658:2;15647:9;15643:18;15630:32;15614:48;;15687:2;15677:8;15674:16;15671:36;;;15703:1;15700;15693:12;15671:36;;15742:72;15806:7;15795:8;15784:9;15780:24;15742:72;:::i;:::-;15058:816;;;;-1:-1:-1;15058:816:36;;-1:-1:-1;15833:8:36;;15716:98;15058:816;-1:-1:-1;;;15058:816:36:o;15879:409::-;15965:6;15973;15981;15989;16042:3;16030:9;16021:7;16017:23;16013:33;16010:53;;;16059:1;16056;16049:12;16010:53;16082:29;16101:9;16082:29;:::i;:::-;16072:39;;16130:38;16164:2;16153:9;16149:18;16130:38;:::i;:::-;16120:48;;16187:38;16221:2;16210:9;16206:18;16187:38;:::i;:::-;16177:48;;16244:38;16278:2;16267:9;16263:18;16244:38;:::i;:::-;16234:48;;15879:409;;;;;;;:::o;16293:260::-;16361:6;16369;16422:2;16410:9;16401:7;16397:23;16393:32;16390:52;;;16438:1;16435;16428:12;16390:52;16461:29;16480:9;16461:29;:::i;16558:206::-;16626:20;;16686:52;16675:64;;16665:75;;16655:103;;16754:1;16751;16744:12;16769:1064;16918:6;16926;16934;16942;16950;16958;16966;16974;16982;16990;16998:7;17052:3;17040:9;17031:7;17027:23;17023:33;17020:53;;;17069:1;17066;17059:12;17020:53;17105:9;17092:23;17082:33;;17134:38;17168:2;17157:9;17153:18;17134:38;:::i;:::-;17124:48;;17219:2;17208:9;17204:18;17191:32;17181:42;;17270:2;17259:9;17255:18;17242:32;17232:42;;17293:39;17327:3;17316:9;17312:19;17293:39;:::i;:::-;17283:49;;17351:39;17385:3;17374:9;17370:19;17351:39;:::i;:::-;17341:49;;17409:38;17442:3;17431:9;17427:19;17409:38;:::i;:::-;17399:48;;17466:38;17499:3;17488:9;17484:19;17466:38;:::i;:::-;17456:48;;17523:39;17557:3;17546:9;17542:19;17523:39;:::i;:::-;17513:49;;17613:3;17602:9;17598:19;17585:33;17641:18;17633:6;17630:30;17627:50;;;17673:1;17670;17663:12;17838:1071;18036:6;18044;18052;18060;18068;18121:2;18109:9;18100:7;18096:23;18092:32;18089:52;;;18137:1;18134;18127:12;18089:52;18160:29;18179:9;18160:29;:::i;:::-;18150:39;;18240:2;18229:9;18225:18;18212:32;18263:18;18304:2;18296:6;18293:14;18290:34;;;18320:1;18317;18310:12;18290:34;18358:6;18347:9;18343:22;18333:32;;18403:7;18396:4;18392:2;18388:13;18384:27;18374:55;;18425:1;18422;18415:12;18374:55;18465:2;18452:16;18491:2;18483:6;18480:14;18477:34;;;18507:1;18504;18497:12;18477:34;18560:7;18555:2;18545:6;18542:1;18538:14;18534:2;18530:23;18526:32;18523:45;18520:65;;;18581:1;18578;18571:12;18520:65;18612:2;18608;18604:11;18594:21;;18634:6;18624:16;;;18693:2;18682:9;18678:18;18665:32;18649:48;;18722:2;18712:8;18709:16;18706:36;;;18738:1;18735;18728:12;18914:839;19038:6;19046;19054;19062;19070;19078;19086;19094;19147:3;19135:9;19126:7;19122:23;19118:33;19115:53;;;19164:1;19161;19154:12;19115:53;19187:29;19206:9;19187:29;:::i;:::-;19177:39;;19263:2;19252:9;19248:18;19235:32;19225:42;;19314:2;19303:9;19299:18;19286:32;19276:42;;19365:2;19354:9;19350:18;19337:32;19327:42;;19388:39;19422:3;19411:9;19407:19;19388:39;:::i;:::-;19378:49;;19446:39;19480:3;19469:9;19465:19;19446:39;:::i;:::-;19436:49;;19536:3;19525:9;19521:19;19508:33;19564:18;19556:6;19553:30;19550:50;;;19596:1;19593;19586:12;19550:50;19635:58;19685:7;19676:6;19665:9;19661:22;19635:58;:::i;:::-;18914:839;;;;-1:-1:-1;18914:839:36;;-1:-1:-1;18914:839:36;;;;;;19712:8;-1:-1:-1;;;18914:839:36:o;19758:579::-;19859:6;19867;19875;19883;19936:2;19924:9;19915:7;19911:23;19907:32;19904:52;;;19952:1;19949;19942:12;19904:52;19975:28;19993:9;19975:28;:::i;:::-;19965:38;;20022:36;20054:2;20043:9;20039:18;20022:36;:::i;:::-;20012:46;;20109:2;20098:9;20094:18;20081:32;20136:18;20128:6;20125:30;20122:50;;;20168:1;20165;20158:12;20122:50;20207:70;20269:7;20260:6;20249:9;20245:22;20207:70;:::i;:::-;19758:579;;;;-1:-1:-1;20296:8:36;-1:-1:-1;;;;19758:579:36:o;20342:541::-;20446:6;20454;20462;20470;20478;20486;20539:3;20527:9;20518:7;20514:23;20510:33;20507:53;;;20556:1;20553;20546:12;20507:53;20579:29;20598:9;20579:29;:::i;:::-;20569:39;;20627:38;20661:2;20650:9;20646:18;20627:38;:::i;:::-;20617:48;;20712:2;20701:9;20697:18;20684:32;20674:42;;20735:38;20769:2;20758:9;20754:18;20735:38;:::i;21988:681::-;22159:2;22211:21;;;22281:13;;22184:18;;;22303:22;;;22130:4;;22159:2;22382:15;;;;22356:2;22341:18;;;22130:4;22425:218;22439:6;22436:1;22433:13;22425:218;;;22504:13;;22519:42;22500:62;22488:75;;22618:15;;;;22583:12;;;;22461:1;22454:9;22425:218;;22856:403;22942:6;22950;22958;22966;23019:3;23007:9;22998:7;22994:23;22990:33;22987:53;;;23036:1;23033;23026:12;22987:53;23059:29;23078:9;23059:29;:::i;:::-;23049:39;;23107:38;23141:2;23130:9;23126:18;23107:38;:::i;:::-;23097:48;;23164:38;23198:2;23187:9;23183:18;23164:38;:::i;:::-;22856:403;;;;-1:-1:-1;23154:48:36;;23249:2;23234:18;23221:32;;-1:-1:-1;;22856:403:36:o;23449:254::-;23514:6;23522;23575:2;23563:9;23554:7;23550:23;23546:32;23543:52;;;23591:1;23588;23581:12;23543:52;23614:28;23632:9;23614:28;:::i;23708:397::-;23794:6;23802;23810;23818;23871:3;23859:9;23850:7;23846:23;23842:33;23839:53;;;23888:1;23885;23878:12;23839:53;23911:29;23930:9;23911:29;:::i;:::-;23901:39;;23959:38;23993:2;23982:9;23978:18;23959:38;:::i;:::-;23708:397;;23949:48;;-1:-1:-1;;;;24044:2:36;24029:18;;24016:32;;24095:2;24080:18;24067:32;;23708:397::o;24341:258::-;24408:6;24416;24469:2;24457:9;24448:7;24444:23;24440:32;24437:52;;;24485:1;24482;24475:12;24437:52;24508:29;24527:9;24508:29;:::i;:::-;24498:39;;24556:37;24589:2;24578:9;24574:18;24556:37;:::i;24604:482::-;24683:6;24691;24699;24752:2;24740:9;24731:7;24727:23;24723:32;24720:52;;;24768:1;24765;24758:12;24720:52;24808:9;24795:23;24841:18;24833:6;24830:30;24827:50;;;24873:1;24870;24863:12;24827:50;24912:58;24962:7;24953:6;24942:9;24938:22;24912:58;:::i;:::-;24989:8;;-1:-1:-1;24886:84:36;-1:-1:-1;25043:37:36;;-1:-1:-1;25076:2:36;25061:18;;25043:37;:::i;25091:330::-;25166:6;25174;25182;25235:2;25223:9;25214:7;25210:23;25206:32;25203:52;;;25251:1;25248;25241:12;25203:52;25274:29;25293:9;25274:29;:::i;25426:977::-;25568:6;25576;25584;25592;25600;25608;25616;25624;25632;25640;25693:3;25681:9;25672:7;25668:23;25664:33;25661:53;;;25710:1;25707;25700:12;25661:53;25733:29;25752:9;25733:29;:::i;:::-;25723:39;;25809:2;25798:9;25794:18;25781:32;25771:42;;25860:2;25849:9;25845:18;25832:32;25822:42;;25911:2;25900:9;25896:18;25883:32;25873:42;;25934:39;25968:3;25957:9;25953:19;25934:39;:::i;:::-;25924:49;;25992:39;26026:3;26015:9;26011:19;25992:39;:::i;:::-;25982:49;;26078:3;26067:9;26063:19;26050:33;26040:43;;26130:3;26119:9;26115:19;26102:33;26092:43;;26186:3;26175:9;26171:19;26158:33;26214:18;26206:6;26203:30;26200:50;;;26246:1;26243;26236:12;26408:410;26479:6;26487;26540:2;26528:9;26519:7;26515:23;26511:32;26508:52;;;26556:1;26553;26546:12;26508:52;26596:9;26583:23;26629:18;26621:6;26618:30;26615:50;;;26661:1;26658;26651:12;26615:50;26700:58;26750:7;26741:6;26730:9;26726:22;26700:58;:::i;:::-;26777:8;;26674:84;;-1:-1:-1;26408:410:36;-1:-1:-1;;;;26408:410:36:o;27588:545::-;27691:6;27699;27707;27715;27723;27731;27784:3;27772:9;27763:7;27759:23;27755:33;27752:53;;;27801:1;27798;27791:12;27752:53;27837:9;27824:23;27814:33;;27866:38;27900:2;27889:9;27885:18;27866:38;:::i;:::-;27856:48;;27951:2;27940:9;27936:18;27923:32;27913:42;;27974:38;28008:2;27997:9;27993:18;27974:38;:::i;:::-;27964:48;;28031:39;28065:3;28054:9;28050:19;28031:39;:::i;:::-;28021:49;;28089:38;28122:3;28111:9;28107:19;28089:38;:::i;:::-;28079:48;;27588:545;;;;;;;;:::o;28138:117::-;28223:6;28216:5;28212:18;28205:5;28202:29;28192:57;;28245:1;28242;28235:12;28260:535;28350:6;28358;28366;28374;28382;28435:3;28423:9;28414:7;28410:23;28406:33;28403:53;;;28452:1;28449;28442:12;28403:53;28475:29;28494:9;28475:29;:::i;:::-;28465:39;;28523:36;28555:2;28544:9;28540:18;28523:36;:::i;:::-;28513:46;;28578:38;28612:2;28601:9;28597:18;28578:38;:::i;:::-;28568:48;;28635:36;28667:2;28656:9;28652:18;28635:36;:::i;:::-;28625:46;;28721:3;28710:9;28706:19;28693:33;28735:30;28759:5;28735:30;:::i;:::-;28784:5;28774:15;;;28260:535;;;;;;;;:::o;28800:322::-;28874:6;28882;28890;28943:2;28931:9;28922:7;28918:23;28914:32;28911:52;;;28959:1;28956;28949:12;28911:52;28982:28;29000:9;28982:28;:::i;:::-;28972:38;;29029:36;29061:2;29050:9;29046:18;29029:36;:::i;:::-;29019:46;;29112:2;29101:9;29097:18;29084:32;29074:42;;28800:322;;;;;:::o;29127:258::-;29194:6;29202;29255:2;29243:9;29234:7;29230:23;29226:32;29223:52;;;29271:1;29268;29261:12;29223:52;29294:28;29312:9;29294:28;:::i;29390:1059::-;29567:6;29575;29583;29591;29599;29607;29615;29623;29631;29639;29692:3;29680:9;29671:7;29667:23;29663:33;29660:53;;;29709:1;29706;29699:12;29660:53;29749:9;29736:23;29782:18;29774:6;29771:30;29768:50;;;29814:1;29811;29804:12;29768:50;29853:58;29903:7;29894:6;29883:9;29879:22;29853:58;:::i;:::-;29930:8;;-1:-1:-1;29827:84:36;-1:-1:-1;29984:72:36;;-1:-1:-1;30048:7:36;30043:2;30028:18;;29984:72;:::i;:::-;29974:82;;30075:39;30109:3;30098:9;30094:19;30075:39;:::i;:::-;30065:49;;30133:39;30167:3;30156:9;30152:19;30133:39;:::i;:::-;30123:49;;30191:39;30225:3;30214:9;30210:19;30191:39;:::i;:::-;30181:49;;30277:3;30266:9;30262:19;30249:33;30239:43;;30301:38;30334:3;30323:9;30319:19;30301:38;:::i;:::-;30291:48;;30386:3;30375:9;30371:19;30358:33;30348:43;;30438:3;30427:9;30423:19;30410:33;30400:43;;29390:1059;;;;;;;;;;;;;:::o;30454:908::-;30587:6;30595;30603;30611;30619;30627;30635;30643;30651;30704:3;30692:9;30683:7;30679:23;30675:33;30672:53;;;30721:1;30718;30711:12;30672:53;30744:29;30763:9;30744:29;:::i;:::-;30734:39;;30820:2;30809:9;30805:18;30792:32;30782:42;;30871:2;30860:9;30856:18;30843:32;30833:42;;30922:2;30911:9;30907:18;30894:32;30884:42;;30945:39;30979:3;30968:9;30964:19;30945:39;:::i;:::-;30935:49;;31003:39;31037:3;31026:9;31022:19;31003:39;:::i;:::-;30993:49;;31089:3;31078:9;31074:19;31061:33;31051:43;;31145:3;31134:9;31130:19;31117:33;31173:18;31165:6;31162:30;31159:50;;;31205:1;31202;31195:12;31159:50;31244:58;31294:7;31285:6;31274:9;31270:22;31244:58;:::i;:::-;31218:84;;31321:8;31311:18;;;31348:8;31338:18;;;30454:908;;;;;;;;;;;:::o;31367:328::-;31444:6;31452;31460;31513:2;31501:9;31492:7;31488:23;31484:32;31481:52;;;31529:1;31526;31519:12;31481:52;31552:29;31571:9;31552:29;:::i;:::-;31542:39;;31600:38;31634:2;31623:9;31619:18;31600:38;:::i;31882:182::-;31939:6;31992:2;31980:9;31971:7;31967:23;31963:32;31960:52;;;32008:1;32005;31998:12;31960:52;32031:27;32048:9;32031:27;:::i;32069:324::-;32144:6;32152;32160;32213:2;32201:9;32192:7;32188:23;32184:32;32181:52;;;32229:1;32226;32219:12;32181:52;32252:29;32271:9;32252:29;:::i;32398:184::-;32456:6;32509:2;32497:9;32488:7;32484:23;32480:32;32477:52;;;32525:1;32522;32515:12;32477:52;32548:28;32566:9;32548:28;:::i;32587:319::-;32654:6;32662;32715:2;32703:9;32694:7;32690:23;32686:32;32683:52;;;32731:1;32728;32721:12;32683:52;32754:29;32773:9;32754:29;:::i;:::-;32744:39;;32833:2;32822:9;32818:18;32805:32;32846:30;32870:5;32846:30;:::i;:::-;32895:5;32885:15;;;32587:319;;;;;:::o;32911:279::-;32976:9;;;32997:10;;;32994:190;;;33040:77;33037:1;33030:88;33141:4;33138:1;33131:15;33169:4;33166:1;33159:15;33195:184;33247:77;33244:1;33237:88;33344:4;33341:1;33334:15;33368:4;33365:1;33358:15;33384:184;33436:77;33433:1;33426:88;33533:4;33530:1;33523:15;33557:4;33554:1;33547:15;33573:437;33652:1;33648:12;;;;33695;;;33716:61;;33770:4;33762:6;33758:17;33748:27;;33716:61;33823:2;33815:6;33812:14;33792:18;33789:38;33786:218;;33860:77;33857:1;33850:88;33961:4;33958:1;33951:15;33989:4;33986:1;33979:15;34225:277;34292:6;34345:2;34333:9;34324:7;34320:23;34316:32;34313:52;;;34361:1;34358;34351:12;34313:52;34393:9;34387:16;34446:5;34439:13;34432:21;34425:5;34422:32;34412:60;;34468:1;34465;34458:12;34507:474;34696:3;34734:6;34728:13;34750:66;34809:6;34804:3;34797:4;34789:6;34785:17;34750:66;:::i;:::-;34838:16;;34891:6;34883;34838:16;34863:35;34955:1;34917:18;;34944:13;;;-1:-1:-1;34917:18:36;;34507:474;-1:-1:-1;;;34507:474:36:o;36350:381::-;36427:6;36435;36488:2;36476:9;36467:7;36463:23;36459:32;36456:52;;;36504:1;36501;36494:12;36456:52;36536:9;36530:16;36555:30;36579:5;36555:30;:::i;:::-;36654:2;36639:18;;36633:25;36604:5;;-1:-1:-1;36667:32:36;36633:25;36667:32;:::i;37139:287::-;37268:3;37306:6;37300:13;37322:66;37381:6;37376:3;37369:4;37361:6;37357:17;37322:66;:::i;:::-;37404:16;;;;;37139:287;-1:-1:-1;;37139:287:36:o;38740:274::-;38780:1;38806;38796:189;;38841:77;38838:1;38831:88;38942:4;38939:1;38932:15;38970:4;38967:1;38960:15;38796:189;-1:-1:-1;38999:9:36;;38740:274::o
Swarm Source
ipfs://3c722515cb1b94dd8d752f9b83ae90dcbec2eb559da6ba5732cbef23b0953791
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in MON
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.