Overview
ETH Balance
0 ETH
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 506,871 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Create Account | 83406574 | 7 mins ago | IN | 0 ETH | 0.00000314 | ||||
Create Account | 83406553 | 9 mins ago | IN | 0 ETH | 0.00000314 | ||||
Create Account | 83406480 | 21 mins ago | IN | 0 ETH | 0.00000314 | ||||
Create Account | 83406080 | 1 hr ago | IN | 0 ETH | 0.00000314 | ||||
Create Account | 83405962 | 1 hr ago | IN | 0 ETH | 0.00000314 | ||||
Create Account | 83405884 | 1 hr ago | IN | 0 ETH | 0.00000314 | ||||
Create Account | 83405645 | 1 hr ago | IN | 0 ETH | 0.00000314 | ||||
Create Account | 83405441 | 2 hrs ago | IN | 0 ETH | 0.00000314 | ||||
Create Account | 83405437 | 2 hrs ago | IN | 0 ETH | 0.00000314 | ||||
Create Account | 83405257 | 2 hrs ago | IN | 0 ETH | 0.00000315 | ||||
Create Account | 83405212 | 3 hrs ago | IN | 0 ETH | 0.00000315 | ||||
Create Account | 83405186 | 3 hrs ago | IN | 0 ETH | 0.00000315 | ||||
Create Account | 83405169 | 3 hrs ago | IN | 0 ETH | 0.00000315 | ||||
Create Account | 83405158 | 3 hrs ago | IN | 0 ETH | 0.00000315 | ||||
Create Account | 83405105 | 3 hrs ago | IN | 0 ETH | 0.00000315 | ||||
Create Account | 83405037 | 3 hrs ago | IN | 0 ETH | 0.00000315 | ||||
Create Account | 83404870 | 3 hrs ago | IN | 0 ETH | 0.00000315 | ||||
Create Account | 83404862 | 3 hrs ago | IN | 0 ETH | 0.00000315 | ||||
Create Account | 83404674 | 4 hrs ago | IN | 0 ETH | 0.00000315 | ||||
Create Account | 83404624 | 4 hrs ago | IN | 0 ETH | 0.00000315 | ||||
Create Account | 83404594 | 4 hrs ago | IN | 0 ETH | 0.00000315 | ||||
Create Account | 83404545 | 4 hrs ago | IN | 0 ETH | 0.00000315 | ||||
Create Account | 83404524 | 4 hrs ago | IN | 0 ETH | 0.00000315 | ||||
Create Account | 83404501 | 4 hrs ago | IN | 0 ETH | 0.00000315 | ||||
Create Account | 83403924 | 5 hrs ago | IN | 0 ETH | 0.00000315 |
Latest 25 internal transactions (View All)
Advanced mode:
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 Source Code Verified (Exact Match)
Contract Name:
ManagedAccountFactory
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 20 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; // Utils import "@thirdweb-dev/dynamic-contracts/src/presets/BaseRouter.sol"; import "../utils/BaseAccountFactory.sol"; // Extensions import "../../../extension/upgradeable//PermissionsEnumerable.sol"; import "../../../extension/upgradeable//ContractMetadata.sol"; // Smart wallet implementation import { ManagedAccount, IEntryPoint } from "./ManagedAccount.sol"; // $$\ $$\ $$\ $$\ $$\ // $$ | $$ | \__| $$ | $$ | // $$$$$$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$\ $$$$$$\ $$$$$$$\ // \_$$ _| $$ __$$\ $$ |$$ __$$\ $$ __$$ |$$ | $$ | $$ |$$ __$$\ $$ __$$\ // $$ | $$ | $$ |$$ |$$ | \__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ | // $$ |$$\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ | // \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ | // \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/ contract ManagedAccountFactory is BaseAccountFactory, ContractMetadata, PermissionsEnumerable, BaseRouter { /*/////////////////////////////////////////////////////////////// Constructor //////////////////////////////////////////////////////////////*/ constructor( address _defaultAdmin, IEntryPoint _entrypoint, Extension[] memory _defaultExtensions ) BaseRouter(_defaultExtensions) BaseAccountFactory(payable(address(new ManagedAccount(_entrypoint, address(this)))), address(_entrypoint)) { __BaseRouter_init(); _setupRole(DEFAULT_ADMIN_ROLE, _defaultAdmin); bytes32 _extensionRole = keccak256("EXTENSION_ROLE"); _setupRole(_extensionRole, _defaultAdmin); _setRoleAdmin(_extensionRole, _extensionRole); } /*/////////////////////////////////////////////////////////////// Internal functions //////////////////////////////////////////////////////////////*/ /// @dev Called in `createAccount`. Initializes the account contract created in `createAccount`. function _initializeAccount(address _account, address _admin, bytes calldata _data) internal override { ManagedAccount(payable(_account)).initialize(_admin, _data); } /// @dev Returns whether all relevant permission and other checks are met before any upgrade. function _isAuthorizedCallToUpgrade() internal view virtual override returns (bool) { return hasRole(keccak256("EXTENSION_ROLE"), msg.sender); } /// @dev Returns whether contract metadata can be set in the given execution context. function _canSetContractURI() internal view virtual override returns (bool) { return hasRole(DEFAULT_ADMIN_ROLE, msg.sender); } /// @notice Returns the sender in the given execution context. function _msgSender() internal view override(Multicall, Permissions) returns (address) { return msg.sender; } }
// SPDX-License-Identifier: Apache 2.0 pragma solidity ^0.8.0; abstract contract ERC1271 { // bytes4(keccak256("isValidSignature(bytes32,bytes)") bytes4 internal constant MAGICVALUE = 0x1626ba7e; /** * @dev Should return whether the signature provided is valid for the provided hash * @param _hash Hash of the data to be signed * @param _signature Signature byte array associated with _hash * * MUST return the bytes4 magic value 0x1626ba7e when function passes. * MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5) * MUST allow external calls */ function isValidSignature(bytes32 _hash, bytes memory _signature) public view virtual returns (bytes4 magicValue); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./interface/IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * [EIP](https://eips.ethereum.org/EIPS/eip-165). * * 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 * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified) * 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: Apache 2.0 pragma solidity ^0.8.0; /// @author thirdweb import "../lib/Address.sol"; import "./interface/IMulticall.sol"; /** * @dev Provides a function to batch together multiple calls in a single external call. * * _Available since v4.1._ */ contract Multicall is IMulticall { /** * @notice Receives and executes a batch of function calls on this contract. * @dev Receives and executes a batch of function calls on this contract. * * @param data The bytes data that makes up the batch of function calls to execute. * @return results The bytes data that makes up the result of the batch of function calls executed. */ function multicall(bytes[] calldata data) external returns (bytes[] memory results) { results = new bytes[](data.length); address sender = _msgSender(); bool isForwarder = msg.sender != sender; for (uint256 i = 0; i < data.length; i++) { if (isForwarder) { results[i] = Address.functionDelegateCall(address(this), abi.encodePacked(data[i], sender)); } else { results[i] = Address.functionDelegateCall(address(this), data[i]); } } return results; } /// @notice Returns the sender in the given execution context. function _msgSender() internal view virtual returns (address) { return msg.sender; } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; /// @author thirdweb interface IAccountPermissions { /*/////////////////////////////////////////////////////////////// Types //////////////////////////////////////////////////////////////*/ /** * @notice The payload that must be signed by an authorized wallet to set permissions for a signer to use the smart wallet. * * @param signer The addres of the signer to give permissions. * @param approvedTargets The list of approved targets that a role holder can call using the smart wallet. * @param nativeTokenLimitPerTransaction The maximum value that can be transferred by a role holder in a single transaction. * @param permissionStartTimestamp The UNIX timestamp at and after which a signer has permission to use the smart wallet. * @param permissionEndTimestamp The UNIX timestamp at and after which a signer no longer has permission to use the smart wallet. * @param reqValidityStartTimestamp The UNIX timestamp at and after which a signature is valid. * @param reqValidityEndTimestamp The UNIX timestamp at and after which a signature is invalid/expired. * @param uid A unique non-repeatable ID for the payload. * @param isAdmin Whether the signer should be an admin. */ struct SignerPermissionRequest { address signer; uint8 isAdmin; address[] approvedTargets; uint256 nativeTokenLimitPerTransaction; uint128 permissionStartTimestamp; uint128 permissionEndTimestamp; uint128 reqValidityStartTimestamp; uint128 reqValidityEndTimestamp; bytes32 uid; } /** * @notice The permissions that a signer has to use the smart wallet. * * @param signer The address of the signer. * @param approvedTargets The list of approved targets that a role holder can call using the smart wallet. * @param nativeTokenLimitPerTransaction The maximum value that can be transferred by a role holder in a single transaction. * @param startTimestamp The UNIX timestamp at and after which a signer has permission to use the smart wallet. * @param endTimestamp The UNIX timestamp at and after which a signer no longer has permission to use the smart wallet. */ struct SignerPermissions { address signer; address[] approvedTargets; uint256 nativeTokenLimitPerTransaction; uint128 startTimestamp; uint128 endTimestamp; } /** * @notice Internal struct for storing permissions for a signer (without approved targets). * * @param nativeTokenLimitPerTransaction The maximum value that can be transferred by a role holder in a single transaction. * @param startTimestamp The UNIX timestamp at and after which a signer has permission to use the smart wallet. * @param endTimestamp The UNIX timestamp at and after which a signer no longer has permission to use the smart wallet. */ struct SignerPermissionsStatic { uint256 nativeTokenLimitPerTransaction; uint128 startTimestamp; uint128 endTimestamp; } /*/////////////////////////////////////////////////////////////// Events //////////////////////////////////////////////////////////////*/ /// @notice Emitted when permissions for a signer are updated. event SignerPermissionsUpdated( address indexed authorizingSigner, address indexed targetSigner, SignerPermissionRequest permissions ); /// @notice Emitted when an admin is set or removed. event AdminUpdated(address indexed signer, bool isAdmin); /*/////////////////////////////////////////////////////////////// View functions //////////////////////////////////////////////////////////////*/ /// @notice Returns whether the given account is an admin. function isAdmin(address signer) external view returns (bool); /// @notice Returns whether the given account is an active signer on the account. function isActiveSigner(address signer) external view returns (bool); /// @notice Returns the restrictions under which a signer can use the smart wallet. function getPermissionsForSigner(address signer) external view returns (SignerPermissions memory permissions); /// @notice Returns all active and inactive signers of the account. function getAllSigners() external view returns (SignerPermissions[] memory signers); /// @notice Returns all signers with active permissions to use the account. function getAllActiveSigners() external view returns (SignerPermissions[] memory signers); /// @notice Returns all admins of the account. function getAllAdmins() external view returns (address[] memory admins); /// @dev Verifies that a request is signed by an authorized account. function verifySignerPermissionRequest( SignerPermissionRequest calldata req, bytes calldata signature ) external view returns (bool success, address signer); /*/////////////////////////////////////////////////////////////// External functions //////////////////////////////////////////////////////////////*/ /// @notice Sets the permissions for a given signer. function setPermissionsForSigner(SignerPermissionRequest calldata req, bytes calldata signature) external; }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; /// @author thirdweb /** * Thirdweb's `ContractMetadata` is a contract extension for any base contracts. It lets you set a metadata URI * for you contract. * * Additionally, `ContractMetadata` is necessary for NFT contracts that want royalties to get distributed on OpenSea. */ interface IContractMetadata { /// @dev Returns the metadata URI of the contract. function contractURI() external view returns (string memory); /** * @dev Sets contract URI for the storefront-level metadata of the contract. * Only module admin can call this function. */ function setContractURI(string calldata _uri) external; /// @dev Emitted when the contract URI is updated. event ContractURIUpdated(string prevURI, string newURI); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @author thirdweb /** * @dev Provides a function to batch together multiple calls in a single external call. * * _Available since v4.1._ */ interface IMulticall { /** * @dev Receives and executes a batch of function calls on this contract. */ function multicall(bytes[] calldata data) external returns (bytes[] memory results); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; /// @author thirdweb /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IPermissions { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; /// @author thirdweb import "./IPermissions.sol"; /** * @dev External interface of AccessControlEnumerable declared to support ERC165 detection. */ interface IPermissionsEnumerable is IPermissions { /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * [forum post](https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296) * for more information. */ function getRoleMember(bytes32 role, uint256 index) external view returns (address); /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) external view returns (uint256); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; /// @author thirdweb import "../interface/IAccountPermissions.sol"; import "../../external-deps/openzeppelin/utils/cryptography/EIP712.sol"; import "../../external-deps/openzeppelin/utils/structs/EnumerableSet.sol"; library AccountPermissionsStorage { /// @custom:storage-location erc7201:account.permissions.storage /// @dev keccak256(abi.encode(uint256(keccak256("account.permissions.storage")) - 1)) & ~bytes32(uint256(0xff)) bytes32 public constant ACCOUNT_PERMISSIONS_STORAGE_POSITION = 0x3181e78fc1b109bc611fd2406150bf06e33faa75f71cba12c3e1fd670f2def00; struct Data { /// @dev The set of all admins of the wallet. EnumerableSet.AddressSet allAdmins; /// @dev The set of all signers with permission to use the account. EnumerableSet.AddressSet allSigners; /// @dev Map from address => whether the address is an admin. mapping(address => bool) isAdmin; /// @dev Map from signer address => active restrictions for that signer. mapping(address => IAccountPermissions.SignerPermissionsStatic) signerPermissions; /// @dev Map from signer address => approved target the signer can call using the account contract. mapping(address => EnumerableSet.AddressSet) approvedTargets; /// @dev Mapping from a signed request UID => whether the request is processed. mapping(bytes32 => bool) executed; } function data() internal pure returns (Data storage data_) { bytes32 position = ACCOUNT_PERMISSIONS_STORAGE_POSITION; assembly { data_.slot := position } } } abstract contract AccountPermissions is IAccountPermissions, EIP712 { using ECDSA for bytes32; using EnumerableSet for EnumerableSet.AddressSet; bytes32 private constant TYPEHASH = keccak256( "SignerPermissionRequest(address signer,uint8 isAdmin,address[] approvedTargets,uint256 nativeTokenLimitPerTransaction,uint128 permissionStartTimestamp,uint128 permissionEndTimestamp,uint128 reqValidityStartTimestamp,uint128 reqValidityEndTimestamp,bytes32 uid)" ); function _onlyAdmin() internal virtual { require(isAdmin(msg.sender), "!admin"); } /*/////////////////////////////////////////////////////////////// External functions //////////////////////////////////////////////////////////////*/ /// @notice Sets the permissions for a given signer. function setPermissionsForSigner(SignerPermissionRequest calldata _req, bytes calldata _signature) external { address targetSigner = _req.signer; require( _req.reqValidityStartTimestamp <= block.timestamp && block.timestamp < _req.reqValidityEndTimestamp, "!period" ); (bool success, address signer) = verifySignerPermissionRequest(_req, _signature); require(success, "!sig"); _accountPermissionsStorage().executed[_req.uid] = true; //isAdmin > 0, set admin or remove admin if (_req.isAdmin > 0) { //isAdmin = 1, set admin //isAdmin > 1, remove admin bool _isAdmin = _req.isAdmin == 1; _setAdmin(targetSigner, _isAdmin); return; } require(!isAdmin(targetSigner), "admin"); _accountPermissionsStorage().allSigners.add(targetSigner); _accountPermissionsStorage().signerPermissions[targetSigner] = SignerPermissionsStatic( _req.nativeTokenLimitPerTransaction, _req.permissionStartTimestamp, _req.permissionEndTimestamp ); address[] memory currentTargets = _accountPermissionsStorage().approvedTargets[targetSigner].values(); uint256 len = currentTargets.length; for (uint256 i = 0; i < len; i += 1) { _accountPermissionsStorage().approvedTargets[targetSigner].remove(currentTargets[i]); } len = _req.approvedTargets.length; for (uint256 i = 0; i < len; i += 1) { _accountPermissionsStorage().approvedTargets[targetSigner].add(_req.approvedTargets[i]); } _afterSignerPermissionsUpdate(_req); emit SignerPermissionsUpdated(signer, targetSigner, _req); } /*/////////////////////////////////////////////////////////////// View functions //////////////////////////////////////////////////////////////*/ /// @notice Returns whether the given account is an admin. function isAdmin(address _account) public view virtual returns (bool) { return _accountPermissionsStorage().isAdmin[_account]; } /// @notice Returns whether the given account is an active signer on the account. function isActiveSigner(address signer) public view returns (bool) { SignerPermissionsStatic memory permissions = _accountPermissionsStorage().signerPermissions[signer]; return permissions.startTimestamp <= block.timestamp && block.timestamp < permissions.endTimestamp && _accountPermissionsStorage().approvedTargets[signer].length() > 0; } /// @notice Returns the restrictions under which a signer can use the smart wallet. function getPermissionsForSigner(address signer) external view returns (SignerPermissions memory) { SignerPermissionsStatic memory permissions = _accountPermissionsStorage().signerPermissions[signer]; return SignerPermissions( signer, _accountPermissionsStorage().approvedTargets[signer].values(), permissions.nativeTokenLimitPerTransaction, permissions.startTimestamp, permissions.endTimestamp ); } /// @dev Verifies that a request is signed by an authorized account. function verifySignerPermissionRequest( SignerPermissionRequest calldata req, bytes calldata signature ) public view virtual returns (bool success, address signer) { signer = _recoverAddress(_encodeRequest(req), signature); success = !_accountPermissionsStorage().executed[req.uid] && isAdmin(signer); } /// @notice Returns all active and inactive signers of the account. function getAllSigners() external view returns (SignerPermissions[] memory signers) { address[] memory allSigners = _accountPermissionsStorage().allSigners.values(); uint256 len = allSigners.length; signers = new SignerPermissions[](len); for (uint256 i = 0; i < len; i += 1) { address signer = allSigners[i]; SignerPermissionsStatic memory permissions = _accountPermissionsStorage().signerPermissions[signer]; signers[i] = SignerPermissions( signer, _accountPermissionsStorage().approvedTargets[signer].values(), permissions.nativeTokenLimitPerTransaction, permissions.startTimestamp, permissions.endTimestamp ); } } /// @notice Returns all signers with active permissions to use the account. function getAllActiveSigners() external view returns (SignerPermissions[] memory signers) { address[] memory allSigners = _accountPermissionsStorage().allSigners.values(); uint256 len = allSigners.length; uint256 numOfActiveSigners = 0; for (uint256 i = 0; i < len; i += 1) { if (isActiveSigner(allSigners[i])) { numOfActiveSigners++; } else { allSigners[i] = address(0); } } signers = new SignerPermissions[](numOfActiveSigners); uint256 index = 0; for (uint256 i = 0; i < len; i += 1) { if (allSigners[i] != address(0)) { address signer = allSigners[i]; SignerPermissionsStatic memory permissions = _accountPermissionsStorage().signerPermissions[signer]; signers[index++] = SignerPermissions( signer, _accountPermissionsStorage().approvedTargets[signer].values(), permissions.nativeTokenLimitPerTransaction, permissions.startTimestamp, permissions.endTimestamp ); } } } /// @notice Returns all admins of the account. function getAllAdmins() external view returns (address[] memory) { return _accountPermissionsStorage().allAdmins.values(); } /*/////////////////////////////////////////////////////////////// Internal functions //////////////////////////////////////////////////////////////*/ /// @notice Runs after every `changeRole` run. function _afterSignerPermissionsUpdate(SignerPermissionRequest calldata _req) internal virtual; /// @notice Makes the given account an admin. function _setAdmin(address _account, bool _isAdmin) internal virtual { _accountPermissionsStorage().isAdmin[_account] = _isAdmin; if (_isAdmin) { _accountPermissionsStorage().allAdmins.add(_account); } else { _accountPermissionsStorage().allAdmins.remove(_account); } emit AdminUpdated(_account, _isAdmin); } /// @dev Returns the address of the signer of the request. function _recoverAddress(bytes memory _encoded, bytes calldata _signature) internal view virtual returns (address) { return _hashTypedDataV4(keccak256(_encoded)).recover(_signature); } /// @dev Encodes a request for recovery of the signer in `recoverAddress`. function _encodeRequest(SignerPermissionRequest calldata _req) internal pure virtual returns (bytes memory) { return abi.encode( TYPEHASH, _req.signer, _req.isAdmin, keccak256(abi.encodePacked(_req.approvedTargets)), _req.nativeTokenLimitPerTransaction, _req.permissionStartTimestamp, _req.permissionEndTimestamp, _req.reqValidityStartTimestamp, _req.reqValidityEndTimestamp, _req.uid ); } /// @dev Returns the AccountPermissions storage. function _accountPermissionsStorage() internal pure returns (AccountPermissionsStorage.Data storage data) { data = AccountPermissionsStorage.data(); } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; /// @author thirdweb import "../interface/IContractMetadata.sol"; /** * @author thirdweb.com * * @title Contract Metadata * @notice Thirdweb's `ContractMetadata` is a contract extension for any base contracts. It lets you set a metadata URI * for you contract. * Additionally, `ContractMetadata` is necessary for NFT contracts that want royalties to get distributed on OpenSea. */ library ContractMetadataStorage { /// @custom:storage-location erc7201:contract.metadata.storage /// @dev keccak256(abi.encode(uint256(keccak256("contract.metadata.storage")) - 1)) & ~bytes32(uint256(0xff)) bytes32 public constant CONTRACT_METADATA_STORAGE_POSITION = 0x4bc804ba64359c0e35e5ed5d90ee596ecaa49a3a930ddcb1470ea0dd625da900; struct Data { /// @notice Returns the contract metadata URI. string contractURI; } function data() internal pure returns (Data storage data_) { bytes32 position = CONTRACT_METADATA_STORAGE_POSITION; assembly { data_.slot := position } } } abstract contract ContractMetadata is IContractMetadata { /** * @notice Lets a contract admin set the URI for contract-level metadata. * @dev Caller should be authorized to setup contractURI, e.g. contract admin. * See {_canSetContractURI}. * Emits {ContractURIUpdated Event}. * * @param _uri keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE") */ function setContractURI(string memory _uri) external override { if (!_canSetContractURI()) { revert("Not authorized"); } _setupContractURI(_uri); } /// @dev Lets a contract admin set the URI for contract-level metadata. function _setupContractURI(string memory _uri) internal { string memory prevURI = _contractMetadataStorage().contractURI; _contractMetadataStorage().contractURI = _uri; emit ContractURIUpdated(prevURI, _uri); } /// @notice Returns the contract metadata URI. function contractURI() public view virtual override returns (string memory) { return _contractMetadataStorage().contractURI; } /// @dev Returns the AccountPermissions storage. function _contractMetadataStorage() internal pure returns (ContractMetadataStorage.Data storage data) { data = ContractMetadataStorage.data(); } /// @dev Returns whether contract metadata can be set in the given execution context. function _canSetContractURI() internal view virtual returns (bool); }
// SPDX-License-Identifier: Apache 2.0 pragma solidity ^0.8.0; import "../../lib/Address.sol"; library InitStorage { /// @custom:storage-location erc7201:init.storage /// @dev keccak256(abi.encode(uint256(keccak256("init.storage")) - 1)) & ~bytes32(uint256(0xff)) bytes32 constant INIT_STORAGE_POSITION = 0x322cf19c484104d3b1a9c2982ebae869ede3fa5f6c4703ca41b9a48c76ee0300; /// @dev Layout of the entrypoint contract's storage. struct Data { uint8 initialized; bool initializing; } /// @dev Returns the entrypoint contract's data at the relevant storage location. function data() internal pure returns (Data storage data_) { bytes32 position = INIT_STORAGE_POSITION; assembly { data_.slot := position } } } abstract contract Initializable { /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`. */ modifier initializer() { uint8 _initialized = _initStorage().initialized; bool _initializing = _initStorage().initializing; bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initStorage().initialized = 1; if (isTopLevelCall) { _initStorage().initializing = true; } _; if (isTopLevelCall) { _initStorage().initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original * initialization step. This is essential to configure modules that are added through upgrades and that require * initialization. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. */ modifier reinitializer(uint8 version) { uint8 _initialized = _initStorage().initialized; bool _initializing = _initStorage().initializing; require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initStorage().initialized = version; _initStorage().initializing = true; _; _initStorage().initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initStorage().initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. */ function _disableInitializers() internal virtual { uint8 _initialized = _initStorage().initialized; bool _initializing = _initStorage().initializing; require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initStorage().initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /// @dev Returns the InitStorage storage. function _initStorage() internal pure returns (InitStorage.Data storage data) { data = InitStorage.data(); } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; /// @author thirdweb import "../interface/IPermissions.sol"; import "../../lib/Strings.sol"; /** * @title Permissions * @dev This contracts provides extending-contracts with role-based access control mechanisms */ library PermissionsStorage { /// @custom:storage-location erc7201:permissions.storage /// @dev keccak256(abi.encode(uint256(keccak256("permissions.storage")) - 1)) & ~bytes32(uint256(0xff)) bytes32 public constant PERMISSIONS_STORAGE_POSITION = 0x0a7b0f5c59907924802379ebe98cdc23e2ee7820f63d30126e10b3752010e500; struct Data { /// @dev Map from keccak256 hash of a role => a map from address => whether address has role. mapping(bytes32 => mapping(address => bool)) _hasRole; /// @dev Map from keccak256 hash of a role to role admin. See {getRoleAdmin}. mapping(bytes32 => bytes32) _getRoleAdmin; } function data() internal pure returns (Data storage data_) { bytes32 position = PERMISSIONS_STORAGE_POSITION; assembly { data_.slot := position } } } contract Permissions is IPermissions { /// @dev Default admin role for all roles. Only accounts with this role can grant/revoke other roles. bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /// @dev Modifier that checks if an account has the specified role; reverts otherwise. modifier onlyRole(bytes32 role) { _checkRole(role, _msgSender()); _; } /** * @notice Checks whether an account has a particular role. * @dev Returns `true` if `account` has been granted `role`. * * @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE") * @param account Address of the account for which the role is being checked. */ function hasRole(bytes32 role, address account) public view override returns (bool) { return _permissionsStorage()._hasRole[role][account]; } /** * @notice Checks whether an account has a particular role; * role restrictions can be swtiched on and off. * * @dev Returns `true` if `account` has been granted `role`. * Role restrictions can be swtiched on and off: * - If address(0) has ROLE, then the ROLE restrictions * don't apply. * - If address(0) does not have ROLE, then the ROLE * restrictions will apply. * * @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE") * @param account Address of the account for which the role is being checked. */ function hasRoleWithSwitch(bytes32 role, address account) public view returns (bool) { if (!_permissionsStorage()._hasRole[role][address(0)]) { return _permissionsStorage()._hasRole[role][account]; } return true; } /** * @notice Returns the admin role that controls the specified role. * @dev See {grantRole} and {revokeRole}. * To change a role's admin, use {_setRoleAdmin}. * * @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE") */ function getRoleAdmin(bytes32 role) external view override returns (bytes32) { return _permissionsStorage()._getRoleAdmin[role]; } /** * @notice Grants a role to an account, if not previously granted. * @dev Caller must have admin role for the `role`. * Emits {RoleGranted Event}. * * @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE") * @param account Address of the account to which the role is being granted. */ function grantRole(bytes32 role, address account) public virtual override { _checkRole(_permissionsStorage()._getRoleAdmin[role], _msgSender()); if (_permissionsStorage()._hasRole[role][account]) { revert("Can only grant to non holders"); } _setupRole(role, account); } /** * @notice Revokes role from an account. * @dev Caller must have admin role for the `role`. * Emits {RoleRevoked Event}. * * @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE") * @param account Address of the account from which the role is being revoked. */ function revokeRole(bytes32 role, address account) public virtual override { _checkRole(_permissionsStorage()._getRoleAdmin[role], _msgSender()); _revokeRole(role, account); } /** * @notice Revokes role from the account. * @dev Caller must have the `role`, with caller being the same as `account`. * Emits {RoleRevoked Event}. * * @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE") * @param account Address of the account from which the role is being revoked. */ function renounceRole(bytes32 role, address account) public virtual override { if (_msgSender() != account) { revert("Can only renounce for self"); } _revokeRole(role, account); } /// @dev Sets `adminRole` as `role`'s admin role. function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = _permissionsStorage()._getRoleAdmin[role]; _permissionsStorage()._getRoleAdmin[role] = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /// @dev Sets up `role` for `account` function _setupRole(bytes32 role, address account) internal virtual { _permissionsStorage()._hasRole[role][account] = true; emit RoleGranted(role, account, _msgSender()); } /// @dev Revokes `role` from `account` function _revokeRole(bytes32 role, address account) internal virtual { _checkRole(role, account); delete _permissionsStorage()._hasRole[role][account]; emit RoleRevoked(role, account, _msgSender()); } /// @dev Checks `role` for `account`. Reverts with a message including the required role. function _checkRole(bytes32 role, address account) internal view virtual { if (!_permissionsStorage()._hasRole[role][account]) { revert( string( abi.encodePacked( "Permissions: account ", Strings.toHexString(uint160(account), 20), " is missing role ", Strings.toHexString(uint256(role), 32) ) ) ); } } /// @dev Checks `role` for `account`. Reverts with a message including the required role. function _checkRoleWithSwitch(bytes32 role, address account) internal view virtual { if (!hasRoleWithSwitch(role, account)) { revert( string( abi.encodePacked( "Permissions: account ", Strings.toHexString(uint160(account), 20), " is missing role ", Strings.toHexString(uint256(role), 32) ) ) ); } } function _msgSender() internal view virtual returns (address sender) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /// @dev Returns the Permissions storage. function _permissionsStorage() internal pure returns (PermissionsStorage.Data storage data) { data = PermissionsStorage.data(); } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; /// @author thirdweb import "../interface/IPermissionsEnumerable.sol"; import "./Permissions.sol"; /** * @title PermissionsEnumerable * @dev This contracts provides extending-contracts with role-based access control mechanisms. * Also provides interfaces to view all members with a given role, and total count of members. */ library PermissionsEnumerableStorage { /// @custom:storage-location erc7201:extension.manager.storage bytes32 public constant PERMISSIONS_ENUMERABLE_STORAGE_POSITION = keccak256(abi.encode(uint256(keccak256("permissions.enumerable.storage")) - 1)) & ~bytes32(uint256(0xff)); /** * @notice A data structure to store data of members for a given role. * * @param index Current index in the list of accounts that have a role. * @param members map from index => address of account that has a role * @param indexOf map from address => index which the account has. */ struct RoleMembers { uint256 index; mapping(uint256 => address) members; mapping(address => uint256) indexOf; } struct Data { /// @dev map from keccak256 hash of a role to its members' data. See {RoleMembers}. mapping(bytes32 => RoleMembers) roleMembers; } function data() internal pure returns (Data storage data_) { bytes32 position = PERMISSIONS_ENUMERABLE_STORAGE_POSITION; assembly { data_.slot := position } } } contract PermissionsEnumerable is IPermissionsEnumerable, Permissions { /** * @notice Returns the role-member from a list of members for a role, * at a given index. * @dev Returns `member` who has `role`, at `index` of role-members list. * See struct {RoleMembers}, and mapping {roleMembers} * * @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE") * @param index Index in list of current members for the role. * * @return member Address of account that has `role` */ function getRoleMember(bytes32 role, uint256 index) external view override returns (address member) { uint256 currentIndex = _permissionsEnumerableStorage().roleMembers[role].index; uint256 check; for (uint256 i = 0; i < currentIndex; i += 1) { if (_permissionsEnumerableStorage().roleMembers[role].members[i] != address(0)) { if (check == index) { member = _permissionsEnumerableStorage().roleMembers[role].members[i]; return member; } check += 1; } else if ( hasRole(role, address(0)) && i == _permissionsEnumerableStorage().roleMembers[role].indexOf[address(0)] ) { check += 1; } } } /** * @notice Returns total number of accounts that have a role. * @dev Returns `count` of accounts that have `role`. * See struct {RoleMembers}, and mapping {roleMembers} * * @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE") * * @return count Total number of accounts that have `role` */ function getRoleMemberCount(bytes32 role) external view override returns (uint256 count) { uint256 currentIndex = _permissionsEnumerableStorage().roleMembers[role].index; for (uint256 i = 0; i < currentIndex; i += 1) { if (_permissionsEnumerableStorage().roleMembers[role].members[i] != address(0)) { count += 1; } } if (hasRole(role, address(0))) { count += 1; } } /// @dev Revokes `role` from `account`, and removes `account` from {roleMembers} /// See {_removeMember} function _revokeRole(bytes32 role, address account) internal virtual override { super._revokeRole(role, account); _removeMember(role, account); } /// @dev Grants `role` to `account`, and adds `account` to {roleMembers} /// See {_addMember} function _setupRole(bytes32 role, address account) internal virtual override { super._setupRole(role, account); _addMember(role, account); } /// @dev adds `account` to {roleMembers}, for `role` function _addMember(bytes32 role, address account) internal { uint256 idx = _permissionsEnumerableStorage().roleMembers[role].index; _permissionsEnumerableStorage().roleMembers[role].index += 1; _permissionsEnumerableStorage().roleMembers[role].members[idx] = account; _permissionsEnumerableStorage().roleMembers[role].indexOf[account] = idx; } /// @dev removes `account` from {roleMembers}, for `role` function _removeMember(bytes32 role, address account) internal { uint256 idx = _permissionsEnumerableStorage().roleMembers[role].indexOf[account]; delete _permissionsEnumerableStorage().roleMembers[role].members[idx]; delete _permissionsEnumerableStorage().roleMembers[role].indexOf[account]; } /// @dev Returns the PermissionsEnumerable storage. function _permissionsEnumerableStorage() internal pure returns (PermissionsEnumerableStorage.Data storage data) { data = PermissionsEnumerableStorage.data(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (proxy/Clones.sol) pragma solidity ^0.8.0; /** * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for * deploying minimal proxy contracts, also known as "clones". * * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies * > a minimal bytecode implementation that delegates all calls to a known, fixed address. * * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the * deterministic method. * * _Available since v3.4._ */ library Clones { /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create opcode, which should never revert. */ function clone(address implementation) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes // of the `implementation` address with the bytecode before the address. mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) instance := create(0, 0x09, 0x37) } require(instance != address(0), "ERC1167: create failed"); } /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create2 opcode and a `salt` to deterministically deploy * the clone. Using the same `implementation` and `salt` multiple time will revert, since * the clones cannot be deployed twice at the same address. */ function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes // of the `implementation` address with the bytecode before the address. mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) instance := create2(0, 0x09, 0x37, salt) } require(instance != address(0), "ERC1167: create2 failed"); } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress( address implementation, bytes32 salt, address deployer ) internal pure returns (address predicted) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(add(ptr, 0x38), deployer) mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff) mstore(add(ptr, 0x14), implementation) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73) mstore(add(ptr, 0x58), salt) mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37)) predicted := keccak256(add(ptr, 0x43), 0x55) } } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress( address implementation, bytes32 salt ) internal view returns (address predicted) { return predictDeterministicAddress(implementation, salt, address(this)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol) pragma solidity ^0.8.0; import "../../../../eip/interface/IERC165.sol"; /** * @dev _Available since v3.1._ */ interface IERC1155Receiver is IERC165 { /** * @dev Handles the receipt of a single ERC1155 token type. This function is * called at the end of a `safeTransferFrom` after the balance has been updated. * * NOTE: To accept the transfer, this must return * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` * (i.e. 0xf23a6e61, or its own function selector). * * @param operator The address which initiated the transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param id The ID of the token being transferred * @param value The amount of tokens being transferred * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed */ function onERC1155Received( address operator, address from, uint256 id, uint256 value, bytes calldata data ) external returns (bytes4); /** * @dev Handles the receipt of a multiple ERC1155 token types. This function * is called at the end of a `safeBatchTransferFrom` after the balances have * been updated. * * NOTE: To accept the transfer(s), this must return * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` * (i.e. 0xbc197c81, or its own function selector). * * @param operator The address which initiated the batch transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param ids An array containing ids of each token being transferred (order and length must match values array) * @param values An array containing amounts of each token being transferred (order and length must match ids array) * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed */ function onERC1155BatchReceived( address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/utils/ERC1155Holder.sol) pragma solidity ^0.8.0; import "./ERC1155Receiver.sol"; /** * Simple implementation of `ERC1155Receiver` that will allow a contract to hold ERC1155 tokens. * * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be * stuck. * * @dev _Available since v3.1._ */ contract ERC1155Holder is ERC1155Receiver { function onERC1155Received( address, address, uint256, uint256, bytes memory ) public virtual override returns (bytes4) { return this.onERC1155Received.selector; } function onERC1155BatchReceived( address, address, uint256[] memory, uint256[] memory, bytes memory ) public virtual override returns (bytes4) { return this.onERC1155BatchReceived.selector; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC1155/utils/ERC1155Receiver.sol) pragma solidity ^0.8.0; import "../IERC1155Receiver.sol"; import "../../../../../eip/ERC165.sol"; /** * @dev _Available since v3.1._ */ abstract contract ERC1155Receiver is ERC165, IERC1155Receiver { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/utils/ERC721Holder.sol) pragma solidity ^0.8.0; import "../IERC721Receiver.sol"; /** * @dev Implementation of the {IERC721Receiver} interface. * * Accepts all token transfers. * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}. */ contract ERC721Holder is IERC721Receiver { /** * @dev See {IERC721Receiver-onERC721Received}. * * Always returns `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) { return this.onERC721Received.selector; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../../../../lib/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/cryptography/draft-EIP712.sol) pragma solidity ^0.8.0; import "./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]. * * _Available since v3.4._ */ abstract contract EIP712 { /* solhint-disable var-name-mixedcase */ // 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 _CACHED_DOMAIN_SEPARATOR; uint256 private immutable _CACHED_CHAIN_ID; address private immutable _CACHED_THIS; bytes32 private immutable _HASHED_NAME; bytes32 private immutable _HASHED_VERSION; bytes32 private immutable _TYPE_HASH; /* solhint-enable var-name-mixedcase */ /** * @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) { bytes32 hashedName = keccak256(bytes(name)); bytes32 hashedVersion = keccak256(bytes(version)); bytes32 typeHash = keccak256( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ); _HASHED_NAME = hashedName; _HASHED_VERSION = hashedVersion; _CACHED_CHAIN_ID = block.chainid; _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion); _CACHED_THIS = address(this); _TYPE_HASH = typeHash; } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) { return _CACHED_DOMAIN_SEPARATOR; } else { return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION); } } function _buildDomainSeparator( bytes32 typeHash, bytes32 nameHash, bytes32 versionHash ) private view returns (bytes32) { return keccak256(abi.encode(typeHash, nameHash, versionHash, 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.7.0) (utils/structs/EnumerableSet.sol) pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { return _values(set._inner); } // 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 on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.1; /// @author thirdweb, OpenZeppelin Contracts (v4.9.0) /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{ value: value }(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; /// @author thirdweb /// Credits: https://github.com/GNSPS/solidity-bytes-utils/blob/master/contracts/BytesLib.sol library BytesLib { function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; /// @author thirdweb /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @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] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte, /// and the alphabets are capitalized conditionally according to /// https://eips.ethereum.org/EIPS/eip-55 function toHexStringChecksummed(address value) internal pure returns (string memory str) { str = toHexString(value); /// @solidity memory-safe-assembly assembly { let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...` let o := add(str, 0x22) let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... ` let t := shl(240, 136) // `0b10001000 << 240` for { let i := 0 } 1 { } { mstore(add(i, i), mul(t, byte(i, hashed))) i := add(i, 1) if eq(i, 20) { break } } mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask))))) o := add(o, 0x20) mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask))))) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. function toHexString(address value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(address value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { str := mload(0x40) // Allocate the memory. // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x28 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80. mstore(0x40, add(str, 0x80)) // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) str := add(str, 2) mstore(str, 40) let o := add(str, 0x20) mstore(add(o, 40), 0) value := shl(96, value) // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let i := 0 } 1 { } { let p := add(o, add(i, i)) let temp := byte(i, value) mstore8(add(p, 1), mload(and(temp, 15))) mstore8(p, mload(shr(4, temp))) i := add(i, 1) if eq(i, 20) { break } } } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexString(bytes memory raw) internal pure returns (string memory str) { str = toHexStringNoPrefix(raw); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { let length := mload(raw) str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix. mstore(str, add(length, length)) // Store the length of the output. // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let o := add(str, 0x20) let end := add(raw, length) for { } iszero(eq(raw, end)) { } { raw := add(raw, 1) mstore8(add(o, 1), mload(and(mload(raw), 15))) mstore8(o, mload(and(shr(4, mload(raw)), 15))) o := add(o, 2) } mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; import "../utils/UserOperation.sol"; interface IAccount { /** * Validate user's signature and nonce * the entryPoint will make the call to the recipient only if this validation call returns successfully. * signature failure should be reported by returning SIG_VALIDATION_FAILED (1). * This allows making a "simulation call" without a valid signature * Other failures (e.g. nonce mismatch, or invalid signature format) should still revert to signal failure. * * @dev Must validate caller is the entryPoint. * Must validate the signature and nonce * @param userOp the operation that is about to be executed. * @param userOpHash hash of the user's request data. can be used as the basis for signature. * @param missingAccountFunds missing funds on the account's deposit in the entrypoint. * This is the minimum amount to transfer to the sender(entryPoint) to be able to make the call. * The excess is left as a deposit in the entrypoint, for future calls. * can be withdrawn anytime using "entryPoint.withdrawTo()" * In case there is a paymaster in the request (or the current deposit is high enough), this value will be zero. * @return validationData packaged ValidationData structure. use `_packValidationData` and `_unpackValidationData` to encode and decode * <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure, * otherwise, an address of an "authorizer" contract. * <6-byte> validUntil - last timestamp this operation is valid. 0 for "indefinite" * <6-byte> validAfter - first timestamp this operation is valid * If an account doesn't use time-range, it is enough to return SIG_VALIDATION_FAILED value (1) for signature failure. * Note that the validation code cannot use block.timestamp (or block.number) directly. */ function validateUserOp( UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds ) external returns (uint256 validationData); }
// SPDX-License-Identifier: Apache 2.0 pragma solidity ^0.8.12; import "./IAccount.sol"; import "../../../extension/interface/IAccountPermissions.sol"; import "../../../extension/interface/IMulticall.sol"; interface IAccountCore is IAccount, IAccountPermissions, IMulticall { /// @dev Returns the address of the factory from which the account was created. function factory() external view returns (address); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; import "./IAccountFactoryCore.sol"; interface IAccountFactory is IAccountFactoryCore { /*/////////////////////////////////////////////////////////////// Callback Functions //////////////////////////////////////////////////////////////*/ /// @notice Callback function for an Account to register its signers. function onSignerAdded(address signer, bytes32 salt) external; /// @notice Callback function for an Account to un-register its signers. function onSignerRemoved(address signer, bytes32 salt) external; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; interface IAccountFactoryCore { /*/////////////////////////////////////////////////////////////// Events //////////////////////////////////////////////////////////////*/ /// @notice Emitted when a new Account is created. event AccountCreated(address indexed account, address indexed accountAdmin); /// @notice Emitted when a new signer is added to an Account. event SignerAdded(address indexed account, address indexed signer); /// @notice Emitted when a new signer is added to an Account. event SignerRemoved(address indexed account, address indexed signer); /*/////////////////////////////////////////////////////////////// Extension Functions //////////////////////////////////////////////////////////////*/ /// @notice Deploys a new Account for admin. function createAccount(address admin, bytes calldata _data) external returns (address account); /*/////////////////////////////////////////////////////////////// View Functions //////////////////////////////////////////////////////////////*/ /// @notice Returns the address of the Account implementation. function accountImplementation() external view returns (address); /// @notice Returns all accounts created on the factory. function getAllAccounts() external view returns (address[] memory); /// @notice Returns the address of an Account that would be deployed with the given admin signer. function getAddress(address adminSigner, bytes calldata data) external view returns (address); /// @notice Returns all accounts on which a signer has (active or inactive) permissions. function getAccountsOfSigner(address signer) external view returns (address[] memory accounts); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; import "../utils/UserOperation.sol"; /** * Aggregated Signatures validator. */ interface IAggregator { /** * validate aggregated signature. * revert if the aggregated signature does not match the given list of operations. */ function validateSignatures(UserOperation[] calldata userOps, bytes calldata signature) external view; /** * validate signature of a single userOp * This method is should be called by bundler after EntryPoint.simulateValidation() returns (reverts) with ValidationResultWithAggregation * First it validates the signature over the userOp. Then it returns data to be used when creating the handleOps. * @param userOp the userOperation received from the user. * @return sigForUserOp the value to put into the signature field of the userOp when calling handleOps. * (usually empty, unless account and aggregator support some kind of "multisig" */ function validateUserOpSignature(UserOperation calldata userOp) external view returns (bytes memory sigForUserOp); /** * aggregate multiple signatures into a single value. * This method is called off-chain to calculate the signature to pass with handleOps() * bundler MAY use optimized custom code perform this aggregation * @param userOps array of UserOperations to collect the signatures from. * @return aggregatedSignature the aggregated signature */ function aggregateSignatures( UserOperation[] calldata userOps ) external view returns (bytes memory aggregatedSignature); }
/** ** Account-Abstraction (EIP-4337) singleton EntryPoint implementation. ** Only one instance required on each chain. **/ // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; /* solhint-disable avoid-low-level-calls */ /* solhint-disable no-inline-assembly */ /* solhint-disable reason-string */ import "../utils/UserOperation.sol"; import "./IStakeManager.sol"; import "./IAggregator.sol"; import "./INonceManager.sol"; interface IEntryPoint is IStakeManager, INonceManager { /*** * An event emitted after each successful request * @param userOpHash - unique identifier for the request (hash its entire content, except signature). * @param sender - the account that generates this request. * @param paymaster - if non-null, the paymaster that pays for this request. * @param nonce - the nonce value from the request. * @param success - true if the sender transaction succeeded, false if reverted. * @param actualGasCost - actual amount paid (by account or paymaster) for this UserOperation. * @param actualGasUsed - total gas used by this UserOperation (including preVerification, creation, validation and execution). */ event UserOperationEvent( bytes32 indexed userOpHash, address indexed sender, address indexed paymaster, uint256 nonce, bool success, uint256 actualGasCost, uint256 actualGasUsed ); /** * account "sender" was deployed. * @param userOpHash the userOp that deployed this account. UserOperationEvent will follow. * @param sender the account that is deployed * @param factory the factory used to deploy this account (in the initCode) * @param paymaster the paymaster used by this UserOp */ event AccountDeployed(bytes32 indexed userOpHash, address indexed sender, address factory, address paymaster); /** * An event emitted if the UserOperation "callData" reverted with non-zero length * @param userOpHash the request unique identifier. * @param sender the sender of this request * @param nonce the nonce used in the request * @param revertReason - the return bytes from the (reverted) call to "callData". */ event UserOperationRevertReason( bytes32 indexed userOpHash, address indexed sender, uint256 nonce, bytes revertReason ); /** * an event emitted by handleOps(), before starting the execution loop. * any event emitted before this event, is part of the validation. */ event BeforeExecution(); /** * signature aggregator used by the following UserOperationEvents within this bundle. */ event SignatureAggregatorChanged(address indexed aggregator); /** * a custom revert error of handleOps, to identify the offending op. * NOTE: if simulateValidation passes successfully, there should be no reason for handleOps to fail on it. * @param opIndex - index into the array of ops to the failed one (in simulateValidation, this is always zero) * @param reason - revert reason * The string starts with a unique code "AAmn", where "m" is "1" for factory, "2" for account and "3" for paymaster issues, * so a failure can be attributed to the correct entity. * Should be caught in off-chain handleOps simulation and not happen on-chain. * Useful for mitigating DoS attempts against batchers or for troubleshooting of factory/account/paymaster reverts. */ error FailedOp(uint256 opIndex, string reason); /** * error case when a signature aggregator fails to verify the aggregated signature it had created. */ error SignatureValidationFailed(address aggregator); /** * Successful result from simulateValidation. * @param returnInfo gas and time-range returned values * @param senderInfo stake information about the sender * @param factoryInfo stake information about the factory (if any) * @param paymasterInfo stake information about the paymaster (if any) */ error ValidationResult(ReturnInfo returnInfo, StakeInfo senderInfo, StakeInfo factoryInfo, StakeInfo paymasterInfo); /** * Successful result from simulateValidation, if the account returns a signature aggregator * @param returnInfo gas and time-range returned values * @param senderInfo stake information about the sender * @param factoryInfo stake information about the factory (if any) * @param paymasterInfo stake information about the paymaster (if any) * @param aggregatorInfo signature aggregation info (if the account requires signature aggregator) * bundler MUST use it to verify the signature, or reject the UserOperation */ error ValidationResultWithAggregation( ReturnInfo returnInfo, StakeInfo senderInfo, StakeInfo factoryInfo, StakeInfo paymasterInfo, AggregatorStakeInfo aggregatorInfo ); /** * return value of getSenderAddress */ error SenderAddressResult(address sender); /** * return value of simulateHandleOp */ error ExecutionResult( uint256 preOpGas, uint256 paid, uint48 validAfter, uint48 validUntil, bool targetSuccess, bytes targetResult ); //UserOps handled, per aggregator struct UserOpsPerAggregator { UserOperation[] userOps; // aggregator address IAggregator aggregator; // aggregated signature bytes signature; } /** * Execute a batch of UserOperation. * no signature aggregator is used. * if any account requires an aggregator (that is, it returned an aggregator when * performing simulateValidation), then handleAggregatedOps() must be used instead. * @param ops the operations to execute * @param beneficiary the address to receive the fees */ function handleOps(UserOperation[] calldata ops, address payable beneficiary) external; /** * Execute a batch of UserOperation with Aggregators * @param opsPerAggregator the operations to execute, grouped by aggregator (or address(0) for no-aggregator accounts) * @param beneficiary the address to receive the fees */ function handleAggregatedOps( UserOpsPerAggregator[] calldata opsPerAggregator, address payable beneficiary ) external; /** * generate a request Id - unique identifier for this request. * the request ID is a hash over the content of the userOp (except the signature), the entrypoint and the chainid. */ function getUserOpHash(UserOperation calldata userOp) external view returns (bytes32); /** * Simulate a call to account.validateUserOp and paymaster.validatePaymasterUserOp. * @dev this method always revert. Successful result is ValidationResult error. other errors are failures. * @dev The node must also verify it doesn't use banned opcodes, and that it doesn't reference storage outside the account's data. * @param userOp the user operation to validate. */ function simulateValidation(UserOperation calldata userOp) external; /** * gas and return values during simulation * @param preOpGas the gas used for validation (including preValidationGas) * @param prefund the required prefund for this operation * @param sigFailed validateUserOp's (or paymaster's) signature check failed * @param validAfter - first timestamp this UserOp is valid (merging account and paymaster time-range) * @param validUntil - last timestamp this UserOp is valid (merging account and paymaster time-range) * @param paymasterContext returned by validatePaymasterUserOp (to be passed into postOp) */ struct ReturnInfo { uint256 preOpGas; uint256 prefund; bool sigFailed; uint48 validAfter; uint48 validUntil; bytes paymasterContext; } /** * returned aggregated signature info. * the aggregator returned by the account, and its current stake. */ struct AggregatorStakeInfo { address aggregator; StakeInfo stakeInfo; } /** * Get counterfactual sender address. * Calculate the sender contract address that will be generated by the initCode and salt in the UserOperation. * this method always revert, and returns the address in SenderAddressResult error * @param initCode the constructor code to be passed into the UserOperation. */ function getSenderAddress(bytes memory initCode) external; /** * simulate full execution of a UserOperation (including both validation and target execution) * this method will always revert with "ExecutionResult". * it performs full validation of the UserOperation, but ignores signature error. * an optional target address is called after the userop succeeds, and its value is returned * (before the entire call is reverted) * Note that in order to collect the success/failure of the target call, it must be executed * with trace enabled to track the emitted events. * @param op the UserOperation to simulate * @param target if nonzero, a target address to call after userop simulation. If called, the targetSuccess and targetResult * are set to the return from that call. * @param targetCallData callData to pass to target address */ function simulateHandleOp(UserOperation calldata op, address target, bytes calldata targetCallData) external; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; interface INonceManager { /** * Return the next nonce for this sender. * Within a given key, the nonce values are sequenced (starting with zero, and incremented by one on each userop) * But UserOp with different keys can come with arbitrary order. * * @param sender the account address * @param key the high 192 bit of the nonce * @return nonce a full nonce to pass for next UserOp with this sender. */ function getNonce(address sender, uint192 key) external view returns (uint256 nonce); /** * Manually increment the nonce of the sender. * This method is exposed just for completeness.. * Account does NOT need to call it, neither during validation, nor elsewhere, * as the EntryPoint will update the nonce regardless. * Possible use-case is call it with various keys to "initialize" their nonces to one, so that future * UserOperations will not pay extra for the first transaction with a given key. */ function incrementNonce(uint192 key) external; }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.12; /** * manage deposits and stakes. * deposit is just a balance used to pay for UserOperations (either by a paymaster or an account) * stake is value locked for at least "unstakeDelay" by the staked entity. */ interface IStakeManager { event Deposited(address indexed account, uint256 totalDeposit); event Withdrawn(address indexed account, address withdrawAddress, uint256 amount); /// Emitted when stake or unstake delay are modified event StakeLocked(address indexed account, uint256 totalStaked, uint256 unstakeDelaySec); /// Emitted once a stake is scheduled for withdrawal event StakeUnlocked(address indexed account, uint256 withdrawTime); event StakeWithdrawn(address indexed account, address withdrawAddress, uint256 amount); /** * @param deposit the entity's deposit * @param staked true if this entity is staked. * @param stake actual amount of ether staked for this entity. * @param unstakeDelaySec minimum delay to withdraw the stake. * @param withdrawTime - first block timestamp where 'withdrawStake' will be callable, or zero if already locked * @dev sizes were chosen so that (deposit,staked, stake) fit into one cell (used during handleOps) * and the rest fit into a 2nd cell. * 112 bit allows for 10^15 eth * 48 bit for full timestamp * 32 bit allows 150 years for unstake delay */ struct DepositInfo { uint112 deposit; bool staked; uint112 stake; uint32 unstakeDelaySec; uint48 withdrawTime; } //API struct used by getStakeInfo and simulateValidation struct StakeInfo { uint256 stake; uint256 unstakeDelaySec; } /// @return info - full deposit information of given account function getDepositInfo(address account) external view returns (DepositInfo memory info); /// @return the deposit (for gas payment) of the account function balanceOf(address account) external view returns (uint256); /** * add to the deposit of the given account */ function depositTo(address account) external payable; /** * add to the account's stake - amount and delay * any pending unstake is first cancelled. * @param _unstakeDelaySec the new lock duration before the deposit can be withdrawn. */ function addStake(uint32 _unstakeDelaySec) external payable; /** * attempt to unlock the stake. * the value can be withdrawn (using withdrawStake) after the unstake delay. */ function unlockStake() external; /** * withdraw from the (unlocked) stake. * must first call unlockStake and wait for the unstakeDelay to pass * @param withdrawAddress the address to send withdrawn value. */ function withdrawStake(address payable withdrawAddress) external; /** * withdraw from the deposit. * @param withdrawAddress the address to send withdrawn value. * @param withdrawAmount the amount to withdraw. */ function withdrawTo(address payable withdrawAddress, uint256 withdrawAmount) external; }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.11; /* solhint-disable avoid-low-level-calls */ /* solhint-disable no-inline-assembly */ /* solhint-disable reason-string */ // $$\ $$\ $$\ $$\ $$\ // $$ | $$ | \__| $$ | $$ | // $$$$$$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$\ $$$$$$\ $$$$$$$\ // \_$$ _| $$ __$$\ $$ |$$ __$$\ $$ __$$ |$$ | $$ | $$ |$$ __$$\ $$ __$$\ // $$ | $$ | $$ |$$ |$$ | \__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ | // $$ |$$\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ | // \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ | // \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/ import "../utils/AccountCore.sol"; import "@thirdweb-dev/dynamic-contracts/src/core/Router.sol"; import "@thirdweb-dev/dynamic-contracts/src/interface/IRouterState.sol"; contract ManagedAccount is AccountCore, Router, IRouterState { constructor(IEntryPoint _entrypoint, address _factory) AccountCore(_entrypoint, _factory) {} /// @notice Returns the implementation contract address for a given function signature. function getImplementationForFunction(bytes4 _functionSelector) public view virtual override returns (address) { return Router(payable(factory)).getImplementationForFunction(_functionSelector); } /// @notice Returns all extensions of the Router. function getAllExtensions() external view returns (Extension[] memory) { return IRouterState(payable(factory)).getAllExtensions(); } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.11; /* solhint-disable avoid-low-level-calls */ /* solhint-disable no-inline-assembly */ /* solhint-disable reason-string */ // Base import "./../utils/BaseAccount.sol"; // Fixed Extensions import "../../../extension/Multicall.sol"; import "../../../extension/upgradeable/Initializable.sol"; import "../../../extension/upgradeable/AccountPermissions.sol"; // Utils import "./Helpers.sol"; import "./AccountCoreStorage.sol"; import "./BaseAccountFactory.sol"; import { AccountExtension } from "./AccountExtension.sol"; import "../../../external-deps/openzeppelin/utils/cryptography/ECDSA.sol"; import "../interface/IAccountCore.sol"; // $$\ $$\ $$\ $$\ $$\ // $$ | $$ | \__| $$ | $$ | // $$$$$$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$\ $$$$$$\ $$$$$$$\ // \_$$ _| $$ __$$\ $$ |$$ __$$\ $$ __$$ |$$ | $$ | $$ |$$ __$$\ $$ __$$\ // $$ | $$ | $$ |$$ |$$ | \__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ | // $$ |$$\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ | // \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ | // \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/ contract AccountCore is IAccountCore, Initializable, Multicall, BaseAccount, AccountPermissions { using ECDSA for bytes32; using EnumerableSet for EnumerableSet.AddressSet; /*/////////////////////////////////////////////////////////////// State //////////////////////////////////////////////////////////////*/ /// @notice EIP 4337 factory for this contract. address public immutable factory; /// @notice EIP 4337 Entrypoint contract. IEntryPoint private immutable entrypointContract; /*/////////////////////////////////////////////////////////////// Constructor, Initializer, Modifiers //////////////////////////////////////////////////////////////*/ constructor(IEntryPoint _entrypoint, address _factory) EIP712("Account", "1") { _disableInitializers(); factory = _factory; entrypointContract = _entrypoint; } /// @notice Initializes the smart contract wallet. function initialize(address _defaultAdmin, bytes calldata _data) public virtual initializer { // This is passed as data in the `_registerOnFactory()` call in `AccountExtension` / `Account`. AccountCoreStorage.data().creationSalt = _generateSalt(_defaultAdmin, _data); _setAdmin(_defaultAdmin, true); } /*/////////////////////////////////////////////////////////////// View functions //////////////////////////////////////////////////////////////*/ /// @notice Returns the EIP 4337 entrypoint contract. function entryPoint() public view virtual override returns (IEntryPoint) { address entrypointOverride = AccountCoreStorage.data().entrypointOverride; if (address(entrypointOverride) != address(0)) { return IEntryPoint(entrypointOverride); } return entrypointContract; } /** @notice Returns whether a signer is authorized to perform transactions using the account. Validity of the signature is based upon signer permission start/end timestamps, txn target, and txn value. Account admins will always return true, and signers with address(0) as the only approved target will skip target checks. @param _signer The signer to check. @param _userOp The user operation to check. @return Whether the signer is authorized to perform the transaction. */ /* solhint-disable*/ function isValidSigner(address _signer, UserOperation calldata _userOp) public view virtual returns (bool) { // First, check if the signer is an admin. if (_accountPermissionsStorage().isAdmin[_signer]) { return true; } SignerPermissionsStatic memory permissions = _accountPermissionsStorage().signerPermissions[_signer]; EnumerableSet.AddressSet storage approvedTargets = _accountPermissionsStorage().approvedTargets[_signer]; // If not an admin, check if the signer is active. if ( permissions.startTimestamp > block.timestamp || block.timestamp >= permissions.endTimestamp || approvedTargets.length() == 0 ) { // Account: no active permissions. return false; } // Extract the function signature from the userOp calldata and check whether the signer is attempting to call `execute` or `executeBatch`. bytes4 sig = getFunctionSignature(_userOp.callData); // if address(0) is the only approved target, set isWildCard to true (wildcard approved). bool isWildCard = approvedTargets.length() == 1 && approvedTargets.at(0) == address(0); // checking target and value for `execute` if (sig == AccountExtension.execute.selector) { // Extract the `target` and `value` arguments from the calldata for `execute`. (address target, uint256 value) = decodeExecuteCalldata(_userOp.callData); // if wildcard target is not approved, check that the target is in the approvedTargets set. if (!isWildCard) { // Check if the target is approved. if (!approvedTargets.contains(target)) { // Account: target not approved. return false; } } // Check if the value is within the allowed range. if (permissions.nativeTokenLimitPerTransaction < value) { // Account: value too high OR Account: target not approved. return false; } } // checking target and value for `executeBatch` else if (sig == AccountExtension.executeBatch.selector) { // Extract the `target` and `value` array arguments from the calldata for `executeBatch`. (address[] memory targets, uint256[] memory values, ) = decodeExecuteBatchCalldata(_userOp.callData); // if wildcard target is not approved, check that the targets are in the approvedTargets set. if (!isWildCard) { for (uint256 i = 0; i < targets.length; i++) { if (!approvedTargets.contains(targets[i])) { // If any target is not approved, break the loop. return false; } } } // For each target+value pair, check if the value is within the allowed range. for (uint256 i = 0; i < targets.length; i++) { if (permissions.nativeTokenLimitPerTransaction < values[i]) { // Account: value too high OR Account: target not approved. return false; } } } else { // Account: calling invalid fn. return false; } return true; } /* solhint-enable */ /*/////////////////////////////////////////////////////////////// External functions //////////////////////////////////////////////////////////////*/ /// @notice Overrides the Entrypoint contract being used. function setEntrypointOverride(IEntryPoint _entrypointOverride) public virtual { _onlyAdmin(); AccountCoreStorage.data().entrypointOverride = address(_entrypointOverride); } /*/////////////////////////////////////////////////////////////// Internal functions //////////////////////////////////////////////////////////////*/ /// @dev Returns the salt used when deploying an Account. function _generateSalt(address _admin, bytes memory _data) internal view virtual returns (bytes32) { return keccak256(abi.encode(_admin, _data)); } function getFunctionSignature(bytes calldata data) internal pure returns (bytes4 functionSelector) { require(data.length >= 4, "!Data"); return bytes4(data[:4]); } function decodeExecuteCalldata(bytes calldata data) internal pure returns (address _target, uint256 _value) { require(data.length >= 4 + 32 + 32, "!Data"); // Decode the address, which is bytes 4 to 35 _target = abi.decode(data[4:36], (address)); // Decode the value, which is bytes 36 to 68 _value = abi.decode(data[36:68], (uint256)); } function decodeExecuteBatchCalldata( bytes calldata data ) internal pure returns (address[] memory _targets, uint256[] memory _values, bytes[] memory _callData) { require(data.length >= 4 + 32 + 32 + 32, "!Data"); (_targets, _values, _callData) = abi.decode(data[4:], (address[], uint256[], bytes[])); } /// @notice Validates the signature of a user operation. function _validateSignature( UserOperation calldata userOp, bytes32 userOpHash ) internal virtual override returns (uint256 validationData) { bytes32 hash = userOpHash.toEthSignedMessageHash(); address signer = hash.recover(userOp.signature); if (!isValidSigner(signer, userOp)) return SIG_VALIDATION_FAILED; SignerPermissionsStatic memory permissions = _accountPermissionsStorage().signerPermissions[signer]; uint48 validAfter = uint48(permissions.startTimestamp); uint48 validUntil = uint48(permissions.endTimestamp); return _packValidationData(ValidationData(address(0), validAfter, validUntil)); } /// @notice Makes the given account an admin. function _setAdmin(address _account, bool _isAdmin) internal virtual override { super._setAdmin(_account, _isAdmin); if (factory.code.length > 0) { if (_isAdmin) { BaseAccountFactory(factory).onSignerAdded(_account, AccountCoreStorage.data().creationSalt); } else { BaseAccountFactory(factory).onSignerRemoved(_account, AccountCoreStorage.data().creationSalt); } } } /// @notice Runs after every `changeRole` run. function _afterSignerPermissionsUpdate(SignerPermissionRequest calldata _req) internal virtual override { if (factory.code.length > 0) { BaseAccountFactory(factory).onSignerAdded(_req.signer, AccountCoreStorage.data().creationSalt); } } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.11; library AccountCoreStorage { /// @custom:storage-location erc7201:account.core.storage /// @dev keccak256(abi.encode(uint256(keccak256("account.core.storage")) - 1)) & ~bytes32(uint256(0xff)) bytes32 public constant ACCOUNT_CORE_STORAGE_POSITION = 0x036f52c1827dab135f7fd44ca0bddde297e2f659c710e0ec53e975f22b548300; struct Data { address entrypointOverride; bytes32 creationSalt; } function data() internal pure returns (Data storage acountCoreData) { bytes32 position = ACCOUNT_CORE_STORAGE_POSITION; assembly { acountCoreData.slot := position } } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.11; /* solhint-disable avoid-low-level-calls */ /* solhint-disable no-inline-assembly */ /* solhint-disable reason-string */ // Extensions import "../../../extension/upgradeable/AccountPermissions.sol"; import "../../../extension/upgradeable/ContractMetadata.sol"; import "../../../external-deps/openzeppelin/token/ERC721/utils/ERC721Holder.sol"; import "../../../external-deps/openzeppelin/token/ERC1155/utils/ERC1155Holder.sol"; // Utils import "../../../eip/ERC1271.sol"; import "../../../external-deps/openzeppelin/utils/cryptography/ECDSA.sol"; import "../../../external-deps/openzeppelin/utils/structs/EnumerableSet.sol"; import "./BaseAccountFactory.sol"; import "./AccountCore.sol"; import "./AccountCoreStorage.sol"; // $$\ $$\ $$\ $$\ $$\ // $$ | $$ | \__| $$ | $$ | // $$$$$$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$\ $$$$$$\ $$$$$$$\ // \_$$ _| $$ __$$\ $$ |$$ __$$\ $$ __$$ |$$ | $$ | $$ |$$ __$$\ $$ __$$\ // $$ | $$ | $$ |$$ |$$ | \__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ | // $$ |$$\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ | // \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ | // \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/ contract AccountExtension is ContractMetadata, ERC1271, AccountPermissions, ERC721Holder, ERC1155Holder { using ECDSA for bytes32; using EnumerableSet for EnumerableSet.AddressSet; bytes32 private constant MSG_TYPEHASH = keccak256("AccountMessage(bytes message)"); /*/////////////////////////////////////////////////////////////// Constructor, Initializer, Modifiers //////////////////////////////////////////////////////////////*/ /// @notice Checks whether the caller is the EntryPoint contract or the admin. modifier onlyAdminOrEntrypoint() virtual { require( msg.sender == address(AccountCore(payable(address(this))).entryPoint()) || isAdmin(msg.sender), "Account: not admin or EntryPoint." ); _; } // solhint-disable-next-line no-empty-blocks receive() external payable virtual {} constructor() EIP712("Account", "1") {} /*/////////////////////////////////////////////////////////////// View functions //////////////////////////////////////////////////////////////*/ /// @notice See {IERC165-supportsInterface}. function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155Receiver) returns (bool) { return interfaceId == type(IERC1155Receiver).interfaceId || interfaceId == type(IERC721Receiver).interfaceId || super.supportsInterface(interfaceId); } /** * @notice See EIP-1271 * * @param _hash The original message hash of the data to sign (before mixing this contract's domain separator) * @param _signature The signature produced on signing the typed data hash (result of `getMessageHash(abi.encode(rawData))`) */ function isValidSignature( bytes32 _hash, bytes memory _signature ) public view virtual override returns (bytes4 magicValue) { bytes32 targetDigest = getMessageHash(_hash); address signer = targetDigest.recover(_signature); if (isAdmin(signer)) { return MAGICVALUE; } address caller = msg.sender; EnumerableSet.AddressSet storage approvedTargets = _accountPermissionsStorage().approvedTargets[signer]; require( approvedTargets.contains(caller) || (approvedTargets.length() == 1 && approvedTargets.at(0) == address(0)), "Account: caller not approved target." ); if (isActiveSigner(signer)) { magicValue = MAGICVALUE; } } /** * @notice Returns the hash of message that should be signed for EIP1271 verification. * @param _hash The message hash to sign for the EIP-1271 origin verifying contract. * @return messageHash The digest to sign for EIP-1271 verification. */ function getMessageHash(bytes32 _hash) public view returns (bytes32) { bytes32 messageHash = keccak256(abi.encode(_hash)); bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, messageHash)); return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash)); } /*/////////////////////////////////////////////////////////////// External functions //////////////////////////////////////////////////////////////*/ /// @notice Executes a transaction (called directly from an admin, or by entryPoint) function execute(address _target, uint256 _value, bytes calldata _calldata) external virtual onlyAdminOrEntrypoint { _registerOnFactory(); _call(_target, _value, _calldata); } /// @notice Executes a sequence transaction (called directly from an admin, or by entryPoint) function executeBatch( address[] calldata _target, uint256[] calldata _value, bytes[] calldata _calldata ) external virtual onlyAdminOrEntrypoint { _registerOnFactory(); require(_target.length == _calldata.length && _target.length == _value.length, "Account: wrong array lengths."); for (uint256 i = 0; i < _target.length; i++) { _call(_target[i], _value[i], _calldata[i]); } } /// @notice Deposit funds for this account in Entrypoint. function addDeposit() public payable { AccountCore(payable(address(this))).entryPoint().depositTo{ value: msg.value }(address(this)); } /// @notice Withdraw funds for this account from Entrypoint. function withdrawDepositTo(address payable withdrawAddress, uint256 amount) public { _onlyAdmin(); AccountCore(payable(address(this))).entryPoint().withdrawTo(withdrawAddress, amount); } /*/////////////////////////////////////////////////////////////// Internal functions //////////////////////////////////////////////////////////////*/ /// @dev Registers the account on the factory if it hasn't been registered yet. function _registerOnFactory() internal virtual { address factory = AccountCore(payable(address(this))).factory(); BaseAccountFactory factoryContract = BaseAccountFactory(factory); if (!factoryContract.isRegistered(address(this))) { factoryContract.onRegister(AccountCoreStorage.data().creationSalt); } } /// @dev Calls a target contract and reverts if it fails. function _call(address _target, uint256 value, bytes memory _calldata) internal returns (bytes memory result) { bool success; (success, result) = _target.call{ value: value }(_calldata); if (!success) { assembly { revert(add(result, 32), mload(result)) } } } /// @dev Returns whether contract metadata can be set in the given execution context. function _canSetContractURI() internal view virtual override returns (bool) { return isAdmin(msg.sender) || msg.sender == address(this); } function _afterSignerPermissionsUpdate(SignerPermissionRequest calldata _req) internal virtual override {} }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; /* solhint-disable avoid-low-level-calls */ /* solhint-disable no-empty-blocks */ import "../interface/IAccount.sol"; import "../interface/IEntrypoint.sol"; import "./Helpers.sol"; /** * Basic account implementation. * this contract provides the basic logic for implementing the IAccount interface - validateUserOp * specific account implementation should inherit it and provide the account-specific logic */ abstract contract BaseAccount is IAccount { using UserOperationLib for UserOperation; //return value in case of signature failure, with no time-range. // equivalent to _packValidationData(true,0,0); uint256 internal constant SIG_VALIDATION_FAILED = 1; /** * Return the account nonce. * This method returns the next sequential nonce. * For a nonce of a specific key, use `entrypoint.getNonce(account, key)` */ function getNonce() public view virtual returns (uint256) { return entryPoint().getNonce(address(this), 0); } /** * return the entryPoint used by this account. * subclass should return the current entryPoint used by this account. */ function entryPoint() public view virtual returns (IEntryPoint); /** * Validate user's signature and nonce. * subclass doesn't need to override this method. Instead, it should override the specific internal validation methods. */ function validateUserOp( UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds ) external virtual override returns (uint256 validationData) { _requireFromEntryPoint(); validationData = _validateSignature(userOp, userOpHash); _validateNonce(userOp.nonce); _payPrefund(missingAccountFunds); } /** * ensure the request comes from the known entrypoint. */ function _requireFromEntryPoint() internal view virtual { require(msg.sender == address(entryPoint()), "account: not from EntryPoint"); } /** * validate the signature is valid for this message. * @param userOp validate the userOp.signature field * @param userOpHash convenient field: the hash of the request, to check the signature against * (also hashes the entrypoint and chain id) * @return validationData signature and time-range of this operation * <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure, * otherwise, an address of an "authorizer" contract. * <6-byte> validUntil - last timestamp this operation is valid. 0 for "indefinite" * <6-byte> validAfter - first timestamp this operation is valid * If the account doesn't use time-range, it is enough to return SIG_VALIDATION_FAILED value (1) for signature failure. * Note that the validation code cannot use block.timestamp (or block.number) directly. */ function _validateSignature( UserOperation calldata userOp, bytes32 userOpHash ) internal virtual returns (uint256 validationData); /** * Validate the nonce of the UserOperation. * This method may validate the nonce requirement of this account. * e.g. * To limit the nonce to use sequenced UserOps only (no "out of order" UserOps): * `require(nonce < type(uint64).max)` * For a hypothetical account that *requires* the nonce to be out-of-order: * `require(nonce & type(uint64).max == 0)` * * The actual nonce uniqueness is managed by the EntryPoint, and thus no other * action is needed by the account itself. * * @param nonce to validate * * solhint-disable-next-line no-empty-blocks */ function _validateNonce(uint256 nonce) internal view virtual {} /** * sends to the entrypoint (msg.sender) the missing funds for this transaction. * subclass MAY override this method for better funds management * (e.g. send to the entryPoint more than the minimum required, so that in future transactions * it will not be required to send again) * @param missingAccountFunds the minimum value this method should send the entrypoint. * this value MAY be zero, in case there is enough deposit, or the userOp has a paymaster. */ function _payPrefund(uint256 missingAccountFunds) internal virtual { if (missingAccountFunds != 0) { (bool success, ) = payable(msg.sender).call{ value: missingAccountFunds, gas: type(uint256).max }(""); (success); //ignore failure (its EntryPoint's job to verify, not account.) } } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; // Utils import "../../../extension/Multicall.sol"; import "../../../external-deps/openzeppelin/proxy/Clones.sol"; import "../../../external-deps/openzeppelin/utils/structs/EnumerableSet.sol"; import "../utils/BaseAccount.sol"; import "../../../extension/interface/IAccountPermissions.sol"; import "../../../lib/BytesLib.sol"; // Interface import "../interface/IEntrypoint.sol"; import "../interface/IAccountFactory.sol"; // $$\ $$\ $$\ $$\ $$\ // $$ | $$ | \__| $$ | $$ | // $$$$$$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$\ $$$$$$\ $$$$$$$\ // \_$$ _| $$ __$$\ $$ |$$ __$$\ $$ __$$ |$$ | $$ | $$ |$$ __$$\ $$ __$$\ // $$ | $$ | $$ |$$ |$$ | \__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ | // $$ |$$\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ | // \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ | // \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/ abstract contract BaseAccountFactory is IAccountFactory, Multicall { using EnumerableSet for EnumerableSet.AddressSet; /*/////////////////////////////////////////////////////////////// State //////////////////////////////////////////////////////////////*/ address public immutable accountImplementation; address public immutable entrypoint; EnumerableSet.AddressSet private allAccounts; mapping(address => EnumerableSet.AddressSet) internal accountsOfSigner; /*/////////////////////////////////////////////////////////////// Constructor //////////////////////////////////////////////////////////////*/ constructor(address _accountImpl, address _entrypoint) { accountImplementation = _accountImpl; entrypoint = _entrypoint; } /*/////////////////////////////////////////////////////////////// External functions //////////////////////////////////////////////////////////////*/ /// @notice Deploys a new Account for admin. function createAccount(address _admin, bytes calldata _data) external virtual override returns (address) { address impl = accountImplementation; bytes32 salt = _generateSalt(_admin, _data); address account = Clones.predictDeterministicAddress(impl, salt); if (account.code.length > 0) { return account; } account = Clones.cloneDeterministic(impl, salt); if (msg.sender != entrypoint) { require(allAccounts.add(account), "AccountFactory: account already registered"); } _initializeAccount(account, _admin, _data); emit AccountCreated(account, _admin); return account; } /// @notice Callback function for an Account to register itself on the factory. function onRegister(bytes32 _salt) external { address account = msg.sender; require(_isAccountOfFactory(account, _salt), "AccountFactory: not an account."); require(allAccounts.add(account), "AccountFactory: account already registered"); } function onSignerAdded(address _signer, bytes32 _salt) external { address account = msg.sender; require(_isAccountOfFactory(account, _salt), "AccountFactory: not an account."); bool isNewSigner = accountsOfSigner[_signer].add(account); if (isNewSigner) { emit SignerAdded(account, _signer); } } /// @notice Callback function for an Account to un-register its signers. function onSignerRemoved(address _signer, bytes32 _salt) external { address account = msg.sender; require(_isAccountOfFactory(account, _salt), "AccountFactory: not an account."); bool isAccount = accountsOfSigner[_signer].remove(account); if (isAccount) { emit SignerRemoved(account, _signer); } } /*/////////////////////////////////////////////////////////////// View functions //////////////////////////////////////////////////////////////*/ /// @notice Returns whether an account is registered on this factory. function isRegistered(address _account) external view returns (bool) { return allAccounts.contains(_account); } /// @notice Returns the total number of accounts. function totalAccounts() external view returns (uint256) { return allAccounts.length(); } /// @notice Returns all accounts between the given indices. function getAccounts(uint256 _start, uint256 _end) external view returns (address[] memory accounts) { require(_start < _end && _end <= allAccounts.length(), "BaseAccountFactory: invalid indices"); uint256 len = _end - _start; accounts = new address[](_end - _start); for (uint256 i = 0; i < len; i += 1) { accounts[i] = allAccounts.at(i + _start); } } /// @notice Returns all accounts created on the factory. function getAllAccounts() external view returns (address[] memory) { return allAccounts.values(); } /// @notice Returns the address of an Account that would be deployed with the given admin signer. function getAddress(address _adminSigner, bytes calldata _data) public view returns (address) { bytes32 salt = _generateSalt(_adminSigner, _data); return Clones.predictDeterministicAddress(accountImplementation, salt); } /// @notice Returns all accounts that the given address is a signer of. function getAccountsOfSigner(address signer) external view returns (address[] memory accounts) { return accountsOfSigner[signer].values(); } /*/////////////////////////////////////////////////////////////// Internal functions //////////////////////////////////////////////////////////////*/ /// @dev Returns whether the caller is an account deployed by this factory. function _isAccountOfFactory(address _account, bytes32 _salt) internal view virtual returns (bool) { address predicted = Clones.predictDeterministicAddress(accountImplementation, _salt); return _account == predicted; } function _getImplementation(address cloneAddress) internal view returns (address) { bytes memory code = cloneAddress.code; return BytesLib.toAddress(code, 10); } /// @dev Returns the salt used when deploying an Account. function _generateSalt(address _admin, bytes memory _data) internal view virtual returns (bytes32) { return keccak256(abi.encode(_admin, _data)); } /// @dev Called in `createAccount`. Initializes the account contract created in `createAccount`. function _initializeAccount(address _account, address _admin, bytes calldata _data) internal virtual; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; /* solhint-disable no-inline-assembly */ /* solhint-disable func-visibility */ /** * returned data from validateUserOp. * validateUserOp returns a uint256, with is created by `_packedValidationData` and parsed by `_parseValidationData` * @param aggregator - address(0) - the account validated the signature by itself. * address(1) - the account failed to validate the signature. * otherwise - this is an address of a signature aggregator that must be used to validate the signature. * @param validAfter - this UserOp is valid only after this timestamp. * @param validaUntil - this UserOp is valid only up to this timestamp. */ struct ValidationData { address aggregator; uint48 validAfter; uint48 validUntil; } //extract sigFailed, validAfter, validUntil. // also convert zero validUntil to type(uint48).max function _parseValidationData(uint256 validationData) pure returns (ValidationData memory data) { address aggregator = address(uint160(validationData)); uint48 validUntil = uint48(validationData >> 160); if (validUntil == 0) { validUntil = type(uint48).max; } uint48 validAfter = uint48(validationData >> (48 + 160)); return ValidationData(aggregator, validAfter, validUntil); } // intersect account and paymaster ranges. function _intersectTimeRange( uint256 validationData, uint256 paymasterValidationData ) pure returns (ValidationData memory) { ValidationData memory accountValidationData = _parseValidationData(validationData); ValidationData memory pmValidationData = _parseValidationData(paymasterValidationData); address aggregator = accountValidationData.aggregator; if (aggregator == address(0)) { aggregator = pmValidationData.aggregator; } uint48 validAfter = accountValidationData.validAfter; uint48 validUntil = accountValidationData.validUntil; uint48 pmValidAfter = pmValidationData.validAfter; uint48 pmValidUntil = pmValidationData.validUntil; if (validAfter < pmValidAfter) validAfter = pmValidAfter; if (validUntil > pmValidUntil) validUntil = pmValidUntil; return ValidationData(aggregator, validAfter, validUntil); } /** * helper to pack the return value for validateUserOp * @param data - the ValidationData to pack */ function _packValidationData(ValidationData memory data) pure returns (uint256) { return uint160(data.aggregator) | (uint256(data.validUntil) << 160) | (uint256(data.validAfter) << (160 + 48)); } /** * helper to pack the return value for validateUserOp, when not using an aggregator * @param sigFailed - true for signature failure, false for success * @param validUntil last timestamp this UserOperation is valid (or zero for infinite) * @param validAfter first timestamp this UserOperation is valid */ function _packValidationData(bool sigFailed, uint48 validUntil, uint48 validAfter) pure returns (uint256) { return (sigFailed ? 1 : 0) | (uint256(validUntil) << 160) | (uint256(validAfter) << (160 + 48)); } /** * keccak function over calldata. * @dev copy calldata into memory, do keccak and drop allocated memory. Strangely, this is more efficient than letting solidity do it. */ function calldataKeccak(bytes calldata data) pure returns (bytes32 ret) { assembly { let mem := mload(0x40) let len := data.length calldatacopy(mem, data.offset, len) ret := keccak256(mem, len) } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; /* solhint-disable no-inline-assembly */ import { calldataKeccak } from "./Helpers.sol"; /** * User Operation struct * @param sender the sender account of this request. * @param nonce unique value the sender uses to verify it is not a replay. * @param initCode if set, the account contract will be created by this constructor/ * @param callData the method call to execute on this account. * @param callGasLimit the gas limit passed to the callData method call. * @param verificationGasLimit gas used for validateUserOp and validatePaymasterUserOp. * @param preVerificationGas gas not calculated by the handleOps method, but added to the gas paid. Covers batch overhead. * @param maxFeePerGas same as EIP-1559 gas parameter. * @param maxPriorityFeePerGas same as EIP-1559 gas parameter. * @param paymasterAndData if set, this field holds the paymaster address and paymaster-specific data. the paymaster will pay for the transaction instead of the sender. * @param signature sender-verified signature over the entire request, the EntryPoint address and the chain ID. */ struct UserOperation { address sender; uint256 nonce; bytes initCode; bytes callData; uint256 callGasLimit; uint256 verificationGasLimit; uint256 preVerificationGas; uint256 maxFeePerGas; uint256 maxPriorityFeePerGas; bytes paymasterAndData; bytes signature; } /** * Utility functions helpful when working with UserOperation structs. */ library UserOperationLib { function getSender(UserOperation calldata userOp) internal pure returns (address) { address data; //read sender from userOp, which is first userOp member (saves 800 gas...) assembly { data := calldataload(userOp) } return address(uint160(data)); } //relayer/block builder might submit the TX with higher priorityFee, but the user should not // pay above what he signed for. function gasPrice(UserOperation calldata userOp) internal view returns (uint256) { unchecked { uint256 maxFeePerGas = userOp.maxFeePerGas; uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas; if (maxFeePerGas == maxPriorityFeePerGas) { //legacy mode (for networks that don't support basefee opcode) return maxFeePerGas; } return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee); } } function pack(UserOperation calldata userOp) internal pure returns (bytes memory ret) { address sender = getSender(userOp); uint256 nonce = userOp.nonce; bytes32 hashInitCode = calldataKeccak(userOp.initCode); bytes32 hashCallData = calldataKeccak(userOp.callData); uint256 callGasLimit = userOp.callGasLimit; uint256 verificationGasLimit = userOp.verificationGasLimit; uint256 preVerificationGas = userOp.preVerificationGas; uint256 maxFeePerGas = userOp.maxFeePerGas; uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas; bytes32 hashPaymasterAndData = calldataKeccak(userOp.paymasterAndData); return abi.encode( sender, nonce, hashInitCode, hashCallData, callGasLimit, verificationGasLimit, preVerificationGas, maxFeePerGas, maxPriorityFeePerGas, hashPaymasterAndData ); } function hash(UserOperation calldata userOp) internal pure returns (bytes32) { return keccak256(pack(userOp)); } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./utils/Bytecode.sol"; /** @title A key-value storage with auto-generated keys for storing chunks of data with a lower write & read cost. @author Agustin Aguilar <[email protected]> Readme: https://github.com/0xsequence/sstore2#readme */ library SSTORE2 { error WriteError(); /** @notice Stores `_data` and returns `pointer` as key for later retrieval @dev The pointer is a contract address with `_data` as code @param _data to be written @return pointer Pointer to the written `_data` */ function write(bytes memory _data) internal returns (address pointer) { // Append 00 to _data so contract can't be called // Build init code bytes memory code = Bytecode.creationCodeFor( abi.encodePacked( hex'00', _data ) ); // Deploy contract using create assembly { pointer := create(0, add(code, 32), mload(code)) } // Address MUST be non-zero if (pointer == address(0)) revert WriteError(); } /** @notice Reads the contents of the `_pointer` code as data, skips the first byte @dev The function is intended for reading pointers generated by `write` @param _pointer to be read @return data read from `_pointer` contract */ function read(address _pointer) internal view returns (bytes memory) { return Bytecode.codeAt(_pointer, 1, type(uint256).max); } /** @notice Reads the contents of the `_pointer` code as data, skips the first byte @dev The function is intended for reading pointers generated by `write` @param _pointer to be read @param _start number of bytes to skip @return data read from `_pointer` contract */ function read(address _pointer, uint256 _start) internal view returns (bytes memory) { return Bytecode.codeAt(_pointer, _start + 1, type(uint256).max); } /** @notice Reads the contents of the `_pointer` code as data, skips the first byte @dev The function is intended for reading pointers generated by `write` @param _pointer to be read @param _start number of bytes to skip @param _end index before which to end extraction @return data read from `_pointer` contract */ function read(address _pointer, uint256 _start, uint256 _end) internal view returns (bytes memory) { return Bytecode.codeAt(_pointer, _start + 1, _end + 1); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library Bytecode { error InvalidCodeAtRange(uint256 _size, uint256 _start, uint256 _end); /** @notice Generate a creation code that results on a contract with `_code` as bytecode @param _code The returning value of the resulting `creationCode` @return creationCode (constructor) for new contract */ function creationCodeFor(bytes memory _code) internal pure returns (bytes memory) { /* 0x00 0x63 0x63XXXXXX PUSH4 _code.length size 0x01 0x80 0x80 DUP1 size size 0x02 0x60 0x600e PUSH1 14 14 size size 0x03 0x60 0x6000 PUSH1 00 0 14 size size 0x04 0x39 0x39 CODECOPY size 0x05 0x60 0x6000 PUSH1 00 0 size 0x06 0xf3 0xf3 RETURN <CODE> */ return abi.encodePacked( hex"63", uint32(_code.length), hex"80_60_0E_60_00_39_60_00_F3", _code ); } /** @notice Returns the size of the code on a given address @param _addr Address that may or may not contain code @return size of the code on the given `_addr` */ function codeSize(address _addr) internal view returns (uint256 size) { assembly { size := extcodesize(_addr) } } /** @notice Returns the code of a given address @dev It will fail if `_end < _start` @param _addr Address that may or may not contain code @param _start number of bytes of code to skip on read @param _end index before which to end extraction @return oCode read from `_addr` deployed bytecode Forked from: https://gist.github.com/KardanovIR/fe98661df9338c842b4a30306d507fbd */ function codeAt(address _addr, uint256 _start, uint256 _end) internal view returns (bytes memory oCode) { uint256 csize = codeSize(_addr); if (csize == 0) return bytes(""); if (_start > csize) return bytes(""); if (_end < _start) revert InvalidCodeAtRange(csize, _start, _end); unchecked { uint256 reqSize = _end - _start; uint256 maxSize = csize - _start; uint256 size = maxSize < reqSize ? maxSize : reqSize; assembly { // allocate output byte array - this could also be done without assembly // by using o_code = new bytes(size) oCode := mload(0x40) // new "memory end" including padding mstore(0x40, add(oCode, and(add(add(size, 0x20), 0x1f), not(0x1f)))) // store length in memory mstore(oCode, size) // actually retrieve the code, this needs assembly extcodecopy(_addr, add(oCode, 0x20), _start, size) } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../interface/IRouter.sol"; /// @title ERC-7504 Dynamic Contracts: Router. /// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts) /// @notice Routes an incoming call to an appropriate implementation address. abstract contract Router is IRouter { /** * @notice delegateCalls the appropriate implementation address for the given incoming function call. * @dev The implementation address to delegateCall MUST be retrieved from calling `getImplementationForFunction` with the * incoming call's function selector. */ fallback() external payable virtual { if(msg.data.length == 0) return; address implementation = getImplementationForFunction(msg.sig); require(implementation != address(0), "Router: function does not exist."); _delegate(implementation); } /// @dev delegateCalls an `implementation` smart contract. function _delegate(address implementation) internal virtual { assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize()) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize()) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } /** * @notice Returns the implementation address to delegateCall for the given function selector. * @param _functionSelector The function selector to get the implementation address for. * @return implementation The implementation address to delegateCall for the given function selector. */ function getImplementationForFunction(bytes4 _functionSelector) public view virtual returns (address implementation); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title IExtension /// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts) /// @notice Provides an `Extension` abstraction for a router's implementation contracts. interface IExtension { /*/////////////////////////////////////////////////////////////// Structs //////////////////////////////////////////////////////////////*/ /** * @notice An interface to describe an extension's metadata. * * @param name The unique name of the extension. * @param metadataURI The URI where the metadata for the extension lives. * @param implementation The implementation smart contract address of the extension. */ struct ExtensionMetadata { string name; string metadataURI; address implementation; } /** * @notice An interface to describe an extension's function. * * @param functionSelector The 4 byte selector of the function. * @param functionSignature Function signature as a string. E.g. "transfer(address,address,uint256)" */ struct ExtensionFunction { bytes4 functionSelector; string functionSignature; } /** * @notice An interface to describe an extension. * * @param metadata The extension's metadata; it's name, metadata URI and implementation contract address. * @param functions The functions that belong to the extension. */ struct Extension { ExtensionMetadata metadata; ExtensionFunction[] functions; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IExtension.sol"; /// @title IExtensionManager /// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts) /// @notice Defined storage and API for managing a router's extensions. interface IExtensionManager is IExtension { /*/////////////////////////////////////////////////////////////// Events //////////////////////////////////////////////////////////////*/ /// @dev Emitted when a extension is added. event ExtensionAdded(string indexed name, address indexed implementation, Extension extension); /// @dev Emitted when a extension is replaced. event ExtensionReplaced(string indexed name, address indexed implementation, Extension extension); /// @dev Emitted when a extension is removed. event ExtensionRemoved(string indexed name, Extension extension); /// @dev Emitted when a function is enabled i.e. made callable. event FunctionEnabled(string indexed name, bytes4 indexed functionSelector, ExtensionFunction extFunction, ExtensionMetadata extMetadata); /// @dev Emitted when a function is disabled i.e. made un-callable. event FunctionDisabled(string indexed name, bytes4 indexed functionSelector, ExtensionMetadata extMetadata); /*/////////////////////////////////////////////////////////////// External functions //////////////////////////////////////////////////////////////*/ /** * @notice Add a new extension to the router. * @param extension The extension to add. */ function addExtension(Extension memory extension) external; /** * @notice Fully replace an existing extension of the router. * @dev The extension with name `extension.name` is the extension being replaced. * @param extension The extension to replace or overwrite. */ function replaceExtension(Extension memory extension) external; /** * @notice Remove an existing extension from the router. * @param extensionName The name of the extension to remove. */ function removeExtension(string memory extensionName) external; /** * @notice Enables a single function in an existing extension. * @dev Makes the given function callable on the router. * * @param extensionName The name of the extension to which `extFunction` belongs. * @param extFunction The function to enable. */ function enableFunctionInExtension(string memory extensionName, ExtensionFunction memory extFunction) external; /** * @notice Disables a single function in an Extension. * * @param extensionName The name of the extension to which the function of `functionSelector` belongs. * @param functionSelector The function to disable. */ function disableFunctionInExtension(string memory extensionName, bytes4 functionSelector) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title ERC-7504 Dynamic Contracts: IRouter. /// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts) /// @notice Routes an incoming call to an appropriate implementation address. /// @dev Fallback function delegateCalls `getImplementationForFunction(msg.sig)` for a given incoming call. /// NOTE: The ERC-165 identifier for this interface is 0xce0b6013. interface IRouter { /** * @notice delegateCalls the appropriate implementation address for the given incoming function call. * @dev The implementation address to delegateCall MUST be retrieved from calling `getImplementationForFunction` with the * incoming call's function selector. */ fallback() external payable; /*/////////////////////////////////////////////////////////////// View Functions //////////////////////////////////////////////////////////////*/ /** * @notice Returns the implementation address to delegateCall for the given function selector. * @param _functionSelector The function selector to get the implementation address for. * @return implementation The implementation address to delegateCall for the given function selector. */ function getImplementationForFunction(bytes4 _functionSelector) external view returns (address implementation); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IExtension.sol"; /// @title ERC-7504 Dynamic Contracts: IRouterState. /// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts) /// @notice Defines an API to expose a router's extensions. interface IRouterState is IExtension { /*/////////////////////////////////////////////////////////////// View Functions //////////////////////////////////////////////////////////////*/ /** * @notice Returns all extensions of the Router. * @return allExtensions An array of all extensions. */ function getAllExtensions() external view returns (Extension[] memory allExtensions); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IExtension.sol"; /// @title IRouterStateGetters. /// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts) /// @notice Helper view functions to inspect a router's state. interface IRouterStateGetters is IExtension { /*/////////////////////////////////////////////////////////////// View functions //////////////////////////////////////////////////////////////*/ /** * @notice Returns the extension metadata for a given function. * @param functionSelector The function selector to get the extension metadata for. * @return metadata The extension metadata for a given function. */ function getMetadataForFunction(bytes4 functionSelector) external view returns (ExtensionMetadata memory metadata); /** * @notice Returns the extension metadata and functions for a given extension. * @param extensionName The name of the extension to get the metadata and functions for. * @return extension The extension metadata and functions for a given extension. */ function getExtension(string memory extensionName) external view returns (Extension memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title BaseRouterStorage /// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts) /// @notice Defined storage for base router library BaseRouterStorage { /// @custom:storage-location erc7201:base.router.storage bytes32 public constant BASE_ROUTER_STORAGE_POSITION = keccak256(abi.encode(uint256(keccak256("base.router.storage")) - 1)); struct Data { /// @dev Mapping used only for checking default extension validity in constructor. mapping(bytes4 => bool) functionMap; /// @dev Mapping used only for checking default extension validity in constructor. mapping(string => bool) extensionMap; } /// @dev Returns access to base router storage. function data() internal pure returns (Data storage data_) { bytes32 position = BASE_ROUTER_STORAGE_POSITION; assembly { data_.slot := position } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./StringSet.sol"; import "../interface/IExtension.sol"; /// @title IExtensionManagerStorage /// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts) /// @notice Defined storage for managing a router's extensions. library ExtensionManagerStorage { /// @custom:storage-location erc7201:extension.manager.storage bytes32 public constant EXTENSION_MANAGER_STORAGE_POSITION = keccak256(abi.encode(uint256(keccak256("extension.manager.storage")) - 1)); struct Data { /// @dev Set of names of all extensions of the router. StringSet.Set extensionNames; /// @dev Mapping from extension name => `Extension` i.e. extension metadata and functions. mapping(string => IExtension.Extension) extensions; /// @dev Mapping from function selector => metadata of the extension the function belongs to. mapping(bytes4 => IExtension.ExtensionMetadata) extensionMetadata; } /// @dev Returns access to the extension manager's storage. function data() internal pure returns (Data storage data_) { bytes32 position = EXTENSION_MANAGER_STORAGE_POSITION; assembly { data_.slot := position } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library StringSet { struct Set { // Storage of set values string[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(string => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, string memory value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, string memory value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { string memory lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, string memory value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (string memory) { 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 (string[] memory) { return set._values; } /** * @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, string memory value) internal returns (bool) { return _add(set, 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(Set storage set, string memory value) internal returns (bool) { return _remove(set, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Set storage set, string memory value) internal view returns (bool) { return _contains(set, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Set storage set) internal view returns (uint256) { return _length(set); } /** * @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) internal view returns (string memory) { return _at(set, 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) internal view returns (string[] memory) { return _values(set); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { Router, IRouter } from "../core/Router.sol"; import { IRouterState } from "../interface/IRouterState.sol"; import { IRouterStateGetters } from "../interface/IRouterStateGetters.sol"; import { BaseRouterStorage } from "../lib/BaseRouterStorage.sol"; import { ExtensionManager } from "./ExtensionManager.sol"; import { StringSet } from "../lib/StringSet.sol"; import "lib/sstore2/contracts/SSTORE2.sol"; /// @title BaseRouter /// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts) /// @notice A router with an API to manage its extensions. abstract contract BaseRouter is Router, ExtensionManager { using StringSet for StringSet.Set; /// @notice The address where the router's default extension set is stored. address public immutable defaultExtensions; /// @notice Initialize the Router with a set of default extensions. constructor(Extension[] memory _extensions) { address pointer; if(_extensions.length > 0) { _validateExtensions(_extensions); pointer = SSTORE2.write(abi.encode(_extensions)); } defaultExtensions = pointer; } /// @notice Initialize the Router with a set of default extensions. function __BaseRouter_init() internal { if(defaultExtensions == address(0)) { return; } bytes memory data = SSTORE2.read(defaultExtensions); Extension[] memory defaults = abi.decode(data, (Extension[])); // Unchecked since we already validated extensions in constructor. __BaseRouter_init_unchecked(defaults); } /// @notice Initializes the Router with a set of extensions. function __BaseRouter_init_checked(Extension[] memory _extensions) internal { _validateExtensions(_extensions); __BaseRouter_init_unchecked(_extensions); } /// @notice Initializes the Router with a set of extensions. function __BaseRouter_init_unchecked(Extension[] memory _extensions) internal { for(uint256 i = 0; i < _extensions.length; i += 1) { Extension memory extension = _extensions[i]; // Store: new extension name. _extensionManagerStorage().extensionNames.add(extension.metadata.name); // 1. Store: metadata for extension. _setMetadataForExtension(extension.metadata.name, extension.metadata); uint256 len = extension.functions.length; for (uint256 j = 0; j < len; j += 1) { // 2. Store: name -> extension.functions map _extensionManagerStorage().extensions[extension.metadata.name].functions.push(extension.functions[j]); // 3. Store: metadata for function. _setMetadataForFunction(extension.functions[j].functionSelector, extension.metadata); } emit ExtensionAdded(extension.metadata.name, extension.metadata.implementation, extension); } } /// @notice Returns the implementation contract address for a given function signature. function getImplementationForFunction(bytes4 _functionSelector) public view virtual override returns (address) { return getMetadataForFunction(_functionSelector).implementation; } /// @dev Validates default extensions. function _validateExtensions(Extension[] memory _extensions) internal { uint256 len = _extensions.length; bool isValid = true; for (uint256 i = 0; i < len; i += 1) { isValid = _isValidExtension(_extensions[i]); if(!isValid) { break; } } require(isValid, "BaseRouter: invalid extension."); } function _isValidExtension(Extension memory _extension) internal returns (bool isValid) { isValid = bytes(_extension.metadata.name).length > 0 // non-empty name && !BaseRouterStorage.data().extensionMap[_extension.metadata.name] // unused name && _extension.metadata.implementation != address(0); // non-empty implementation BaseRouterStorage.data().extensionMap[_extension.metadata.name] = true; if(!isValid) { return false; } uint256 len = _extension.functions.length; for(uint256 i = 0; i < len; i += 1) { if(!isValid) { break; } ExtensionFunction memory _extFunction = _extension.functions[i]; /** * Note: `bytes4(0)` is the function selector for the `receive` function. * So, we maintain a special fn selector-signature mismatch check for the `receive` function. **/ bool mismatch = false; if(_extFunction.functionSelector == bytes4(0)) { mismatch = keccak256(abi.encode(_extFunction.functionSignature)) != keccak256(abi.encode("receive()")); } else { mismatch = _extFunction.functionSelector != bytes4(keccak256(abi.encodePacked(_extFunction.functionSignature))); } // No fn signature-selector mismatch and no duplicate function. isValid = !mismatch && !BaseRouterStorage.data().functionMap[_extFunction.functionSelector]; BaseRouterStorage.data().functionMap[_extFunction.functionSelector] = true; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../interface/IExtensionManager.sol"; import "../interface/IRouterState.sol"; import "../interface/IRouterStateGetters.sol"; import "../lib/ExtensionManagerStorage.sol"; /// @title ExtensionManager /// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts) /// @notice Defined storage and API for managing a router's extensions. abstract contract ExtensionManager is IExtensionManager, IRouterState, IRouterStateGetters { using StringSet for StringSet.Set; /*/////////////////////////////////////////////////////////////// Modifier //////////////////////////////////////////////////////////////*/ /// @notice Checks that a call to any external function is authorized. modifier onlyAuthorizedCall() { require(_isAuthorizedCallToUpgrade(), "ExtensionManager: unauthorized."); _; } /*/////////////////////////////////////////////////////////////// View functions //////////////////////////////////////////////////////////////*/ /** * @notice Returns all extensions of the Router. * @return allExtensions An array of all extensions. */ function getAllExtensions() external view virtual override returns (Extension[] memory allExtensions) { string[] memory names = _extensionManagerStorage().extensionNames.values(); uint256 len = names.length; allExtensions = new Extension[](len); for (uint256 i = 0; i < len; i += 1) { allExtensions[i] = _getExtension(names[i]); } } /** * @notice Returns the extension metadata for a given function. * @param functionSelector The function selector to get the extension metadata for. * @return metadata The extension metadata for a given function. */ function getMetadataForFunction(bytes4 functionSelector) public view virtual returns (ExtensionMetadata memory) { return _extensionManagerStorage().extensionMetadata[functionSelector]; } /** * @notice Returns the extension metadata and functions for a given extension. * @param extensionName The name of the extension to get the metadata and functions for. * @return extension The extension metadata and functions for a given extension. */ function getExtension(string memory extensionName) public view virtual returns (Extension memory) { return _getExtension(extensionName); } /*/////////////////////////////////////////////////////////////// External functions //////////////////////////////////////////////////////////////*/ /** * @notice Add a new extension to the router. * @param _extension The extension to add. */ function addExtension(Extension memory _extension) public virtual onlyAuthorizedCall { _addExtension(_extension); } /** * @notice Fully replace an existing extension of the router. * @dev The extension with name `extension.name` is the extension being replaced. * @param _extension The extension to replace or overwrite. */ function replaceExtension(Extension memory _extension) public virtual onlyAuthorizedCall { _replaceExtension(_extension); } /** * @notice Remove an existing extension from the router. * @param _extensionName The name of the extension to remove. */ function removeExtension(string memory _extensionName) public virtual onlyAuthorizedCall { _removeExtension(_extensionName); } /** * @notice Enables a single function in an existing extension. * @dev Makes the given function callable on the router. * * @param _extensionName The name of the extension to which `extFunction` belongs. * @param _function The function to enable. */ function enableFunctionInExtension(string memory _extensionName, ExtensionFunction memory _function) public virtual onlyAuthorizedCall { _enableFunctionInExtension(_extensionName, _function); } /** * @notice Disables a single function in an Extension. * * @param _extensionName The name of the extension to which the function of `functionSelector` belongs. * @param _functionSelector The function to disable. */ function disableFunctionInExtension(string memory _extensionName, bytes4 _functionSelector) public virtual onlyAuthorizedCall { _disableFunctionInExtension(_extensionName, _functionSelector); } /*/////////////////////////////////////////////////////////////// Internal functions //////////////////////////////////////////////////////////////*/ /// @dev Add a new extension to the router. function _addExtension(Extension memory _extension) internal virtual { // Check: extension namespace must not already exist. // Check: provided extension namespace must not be empty. // Check: provided extension implementation must be non-zero. // Store: new extension name. require(_canAddExtension(_extension), "ExtensionManager: cannot add extension."); // 1. Store: metadata for extension. _setMetadataForExtension(_extension.metadata.name, _extension.metadata); uint256 len = _extension.functions.length; for (uint256 i = 0; i < len; i += 1) { // 2. Store: function for extension. _addToFunctionMap(_extension.metadata.name, _extension.functions[i]); // 3. Store: metadata for function. _setMetadataForFunction(_extension.functions[i].functionSelector, _extension.metadata); } emit ExtensionAdded(_extension.metadata.name, _extension.metadata.implementation, _extension); } /// @dev Fully replace an existing extension of the router. function _replaceExtension(Extension memory _extension) internal virtual { // Check: extension namespace must already exist. // Check: provided extension implementation must be non-zero. require(_canReplaceExtension(_extension), "ExtensionManager: cannot replace extension."); // 1. Store: metadata for extension. _setMetadataForExtension(_extension.metadata.name, _extension.metadata); // 2. Delete: existing extension.functions and metadata for each function. _removeAllFunctionsFromExtension(_extension.metadata.name); uint256 len = _extension.functions.length; for (uint256 i = 0; i < len; i += 1) { // 2. Store: function for extension. _addToFunctionMap(_extension.metadata.name, _extension.functions[i]); // 3. Store: metadata for function. _setMetadataForFunction(_extension.functions[i].functionSelector, _extension.metadata); } emit ExtensionReplaced(_extension.metadata.name, _extension.metadata.implementation, _extension); } /// @dev Remove an existing extension from the router. function _removeExtension(string memory _extensionName) internal virtual { // Check: extension namespace must already exist. // Delete: extension namespace. require(_canRemoveExtension(_extensionName), "ExtensionManager: cannot remove extension."); Extension memory extension = _extensionManagerStorage().extensions[_extensionName]; // 1. Delete: metadata for extension. _deleteMetadataForExtension(_extensionName); // 2. Delete: existing extension.functions and metadata for each function. _removeAllFunctionsFromExtension(_extensionName); emit ExtensionRemoved(_extensionName, extension); } /// @dev Makes the given function callable on the router. function _enableFunctionInExtension(string memory _extensionName, ExtensionFunction memory _function) internal virtual { // Check: extension namespace must already exist. require(_canEnableFunctionInExtension(_extensionName, _function), "ExtensionManager: cannot Store: function for extension."); // 1. Store: function for extension. _addToFunctionMap(_extensionName, _function); ExtensionMetadata memory metadata = _extensionManagerStorage().extensions[_extensionName].metadata; // 2. Store: metadata for function. _setMetadataForFunction(_function.functionSelector, metadata); emit FunctionEnabled(_extensionName, _function.functionSelector, _function, metadata); } /// @dev Disables a single function in an Extension. function _disableFunctionInExtension(string memory _extensionName, bytes4 _functionSelector) public virtual onlyAuthorizedCall { // Check: extension namespace must already exist. // Check: function must be mapped to provided extension. require(_canDisableFunctionInExtension(_extensionName, _functionSelector), "ExtensionManager: cannot remove function from extension."); ExtensionMetadata memory extMetadata = _extensionManagerStorage().extensionMetadata[_functionSelector]; // 1. Delete: function from extension. _deleteFromFunctionMap(_extensionName, _functionSelector); // 2. Delete: metadata for function. _deleteMetadataForFunction(_functionSelector); emit FunctionDisabled(_extensionName, _functionSelector, extMetadata); } /// @dev Returns the Extension for a given name. function _getExtension(string memory _extensionName) internal view returns (Extension memory) { return _extensionManagerStorage().extensions[_extensionName]; } /// @dev Sets the ExtensionMetadata for a given extension. function _setMetadataForExtension(string memory _extensionName, ExtensionMetadata memory _metadata) internal { _extensionManagerStorage().extensions[_extensionName].metadata = _metadata; } /// @dev Deletes the ExtensionMetadata for a given extension. function _deleteMetadataForExtension(string memory _extensionName) internal { delete _extensionManagerStorage().extensions[_extensionName].metadata; } /// @dev Sets the ExtensionMetadata for a given function. function _setMetadataForFunction(bytes4 _functionSelector, ExtensionMetadata memory _metadata) internal { _extensionManagerStorage().extensionMetadata[_functionSelector] = _metadata; } /// @dev Deletes the ExtensionMetadata for a given function. function _deleteMetadataForFunction(bytes4 _functionSelector) internal { delete _extensionManagerStorage().extensionMetadata[_functionSelector]; } /// @dev Adds a function to the function map of an extension. function _addToFunctionMap(string memory _extensionName, ExtensionFunction memory _extFunction) internal virtual { /** * Note: `bytes4(0)` is the function selector for the `receive` function. * So, we maintain a special fn selector-signature mismatch check for the `receive` function. **/ bool mismatch = false; if(_extFunction.functionSelector == bytes4(0)) { mismatch = keccak256(abi.encode(_extFunction.functionSignature)) != keccak256(abi.encode("receive()")); } else { mismatch = _extFunction.functionSelector != bytes4(keccak256(abi.encodePacked(_extFunction.functionSignature))); } // Check: function selector and signature must match. require( !mismatch, "ExtensionManager: fn selector and signature mismatch." ); // Check: function must not already be mapped to an implementation. require( _extensionManagerStorage().extensionMetadata[_extFunction.functionSelector].implementation == address(0), "ExtensionManager: function impl already exists." ); // Store: name -> extension.functions map _extensionManagerStorage().extensions[_extensionName].functions.push(_extFunction); } /// @dev Deletes a function from an extension's function map. function _deleteFromFunctionMap(string memory _extensionName, bytes4 _functionSelector) internal { ExtensionFunction[] memory extensionFunctions = _extensionManagerStorage().extensions[_extensionName].functions; uint256 len = extensionFunctions.length; for (uint256 i = 0; i < len; i += 1) { if(extensionFunctions[i].functionSelector == _functionSelector) { // Delete: particular function from name -> extension.functions map _extensionManagerStorage().extensions[_extensionName].functions[i] = _extensionManagerStorage().extensions[_extensionName].functions[len - 1]; _extensionManagerStorage().extensions[_extensionName].functions.pop(); break; } } } /// @dev Removes all functions from an Extension. function _removeAllFunctionsFromExtension(string memory _extensionName) internal { ExtensionFunction[] memory functions = _extensionManagerStorage().extensions[_extensionName].functions; // Delete: existing name -> extension.functions map delete _extensionManagerStorage().extensions[_extensionName].functions; for(uint256 i = 0; i < functions.length; i += 1) { // Delete: metadata for function. _deleteMetadataForFunction(functions[i].functionSelector); } } /// @dev Returns whether a new extension can be added in the given execution context. function _canAddExtension(Extension memory _extension) internal virtual returns (bool) { // Check: provided extension namespace must not be empty. require(bytes(_extension.metadata.name).length > 0, "ExtensionManager: empty name."); // Check: extension namespace must not already exist. // Store: new extension name. require(_extensionManagerStorage().extensionNames.add(_extension.metadata.name), "ExtensionManager: extension already exists."); // Check: extension implementation must be non-zero. require(_extension.metadata.implementation != address(0), "ExtensionManager: adding extension without implementation."); return true; } /// @dev Returns whether an extension can be replaced in the given execution context. function _canReplaceExtension(Extension memory _extension) internal virtual returns (bool) { // Check: extension namespace must already exist. require(_extensionManagerStorage().extensionNames.contains(_extension.metadata.name), "ExtensionManager: extension does not exist."); // Check: extension implementation must be non-zero. require(_extension.metadata.implementation != address(0), "ExtensionManager: adding extension without implementation."); return true; } /// @dev Returns whether an extension can be removed in the given execution context. function _canRemoveExtension(string memory _extensionName) internal virtual returns (bool) { // Check: extension namespace must already exist. // Delete: extension namespace. require(_extensionManagerStorage().extensionNames.remove(_extensionName), "ExtensionManager: extension does not exist."); return true; } /// @dev Returns whether a function can be enabled in an extension in the given execution context. function _canEnableFunctionInExtension(string memory _extensionName, ExtensionFunction memory) internal view virtual returns (bool) { // Check: extension namespace must already exist. require(_extensionManagerStorage().extensionNames.contains(_extensionName), "ExtensionManager: extension does not exist."); return true; } /// @dev Returns whether a function can be disabled in an extension in the given execution context. function _canDisableFunctionInExtension(string memory _extensionName, bytes4 _functionSelector) internal view virtual returns (bool) { // Check: extension namespace must already exist. require(_extensionManagerStorage().extensionNames.contains(_extensionName), "ExtensionManager: extension does not exist."); // Check: function must be mapped to provided extension. require(keccak256(abi.encode(_extensionManagerStorage().extensionMetadata[_functionSelector].name)) == keccak256(abi.encode(_extensionName)), "ExtensionManager: incorrect extension."); return true; } /// @dev Returns the ExtensionManager storage. function _extensionManagerStorage() internal pure returns (ExtensionManagerStorage.Data storage data) { data = ExtensionManagerStorage.data(); } /// @dev To override; returns whether all relevant permission and other checks are met before any upgrade. function _isAuthorizedCallToUpgrade() internal view virtual returns (bool); }
{ "optimizer": { "enabled": true, "runs": 20 }, "evmVersion": "london", "remappings": [ ":@chainlink/=lib/chainlink/", ":@ds-test/=lib/ds-test/src/", ":@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", ":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", ":@std/=lib/forge-std/src/", ":@thirdweb-dev/dynamic-contracts/=lib/dynamic-contracts/", ":ERC721A-Upgradeable/=lib/ERC721A-Upgradeable/contracts/", ":ERC721A/=lib/ERC721A/contracts/", ":chainlink/=lib/chainlink/contracts/", ":contracts/=contracts/", ":ds-test/=lib/ds-test/src/", ":dynamic-contracts/=lib/dynamic-contracts/src/", ":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", ":erc721a-upgradeable/=lib/ERC721A-Upgradeable/", ":erc721a/=lib/ERC721A/", ":forge-std/=lib/forge-std/src/", ":lib/sstore2/=lib/dynamic-contracts/lib/sstore2/", ":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", ":openzeppelin-contracts/=lib/openzeppelin-contracts/", ":openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/", ":sstore2/=lib/dynamic-contracts/lib/sstore2/contracts/" ], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_defaultAdmin","type":"address"},{"internalType":"contract IEntryPoint","name":"_entrypoint","type":"address"},{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"functions","type":"tuple[]"}],"internalType":"struct IExtension.Extension[]","name":"_defaultExtensions","type":"tuple[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"_size","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"InvalidCodeAtRange","type":"error"},{"inputs":[],"name":"WriteError","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"accountAdmin","type":"address"}],"name":"AccountCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"prevURI","type":"string"},{"indexed":false,"internalType":"string","name":"newURI","type":"string"}],"name":"ContractURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"name","type":"string"},{"indexed":true,"internalType":"address","name":"implementation","type":"address"},{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"functions","type":"tuple[]"}],"indexed":false,"internalType":"struct IExtension.Extension","name":"extension","type":"tuple"}],"name":"ExtensionAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"name","type":"string"},{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"functions","type":"tuple[]"}],"indexed":false,"internalType":"struct IExtension.Extension","name":"extension","type":"tuple"}],"name":"ExtensionRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"name","type":"string"},{"indexed":true,"internalType":"address","name":"implementation","type":"address"},{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"functions","type":"tuple[]"}],"indexed":false,"internalType":"struct IExtension.Extension","name":"extension","type":"tuple"}],"name":"ExtensionReplaced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"name","type":"string"},{"indexed":true,"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"indexed":false,"internalType":"struct IExtension.ExtensionMetadata","name":"extMetadata","type":"tuple"}],"name":"FunctionDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"name","type":"string"},{"indexed":true,"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"indexed":false,"internalType":"struct IExtension.ExtensionFunction","name":"extFunction","type":"tuple"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"indexed":false,"internalType":"struct IExtension.ExtensionMetadata","name":"extMetadata","type":"tuple"}],"name":"FunctionEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"signer","type":"address"}],"name":"SignerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"signer","type":"address"}],"name":"SignerRemoved","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_extensionName","type":"string"},{"internalType":"bytes4","name":"_functionSelector","type":"bytes4"}],"name":"_disableFunctionInExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"accountImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"functions","type":"tuple[]"}],"internalType":"struct IExtension.Extension","name":"_extension","type":"tuple"}],"name":"addExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"createAccount","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultExtensions","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_extensionName","type":"string"},{"internalType":"bytes4","name":"_functionSelector","type":"bytes4"}],"name":"disableFunctionInExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_extensionName","type":"string"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction","name":"_function","type":"tuple"}],"name":"enableFunctionInExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"entrypoint","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"getAccounts","outputs":[{"internalType":"address[]","name":"accounts","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"getAccountsOfSigner","outputs":[{"internalType":"address[]","name":"accounts","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_adminSigner","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"getAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllAccounts","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllExtensions","outputs":[{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"functions","type":"tuple[]"}],"internalType":"struct IExtension.Extension[]","name":"allExtensions","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"extensionName","type":"string"}],"name":"getExtension","outputs":[{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"functions","type":"tuple[]"}],"internalType":"struct IExtension.Extension","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_functionSelector","type":"bytes4"}],"name":"getImplementationForFunction","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"}],"name":"getMetadataForFunction","outputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"member","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRoleWithSwitch","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isRegistered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_salt","type":"bytes32"}],"name":"onRegister","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"},{"internalType":"bytes32","name":"_salt","type":"bytes32"}],"name":"onSignerAdded","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"},{"internalType":"bytes32","name":"_salt","type":"bytes32"}],"name":"onSignerRemoved","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_extensionName","type":"string"}],"name":"removeExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"functions","type":"tuple[]"}],"internalType":"struct IExtension.Extension","name":"_extension","type":"tuple"}],"name":"replaceExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_uri","type":"string"}],"name":"setContractURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalAccounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60e06040523480156200001157600080fd5b506040516200990938038062009909833981016040819052620000349162000ffc565b808230604051620000459062000c23565b6001600160a01b03928316815291166020820152604001604051809103906000f08015801562000079573d6000803e3d6000fd5b506001600160a01b03908116608052831660a052805160009015620000d357620000a3826200013a565b620000d082604051602001620000ba91906200116e565b60408051601f19818403018152919052620001ee565b90505b6001600160a01b031660c05250620000ea62000259565b620000f7600084620002ac565b7f55add213c41f3851b4506717b8af695a4256979dff496dcaae7789f6121331aa620001248185620002ac565b620001308180620002c4565b505050506200147f565b8051600160005b82811015620001955762000177848281518110620001635762000163620011d6565b60200260200101516200032b60201b60201c565b9150811562000195576200018d60018262001202565b905062000141565b5080620001e95760405162461bcd60e51b815260206004820152601e60248201527f42617365526f757465723a20696e76616c696420657874656e73696f6e2e000060448201526064015b60405180910390fd5b505050565b6000806200021e8360405160200162000208919062001218565b60408051601f198184030181529190526200058d565b90508051602082016000f091506001600160a01b038216620002535760405163046a55db60e11b815260040160405180910390fd5b50919050565b60c0516001600160a01b03166200026c57565b60006200028160c051620005bb60201b60201c565b90506000818060200190518101906200029b919062001240565b9050620002a881620005d3565b5050565b620002b88282620007ad565b620002a8828262000827565b60008281527f0a7b0f5c59907924802379ebe98cdc23e2ee7820f63d30126e10b3752010e5016020526040808220805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b805151516000901580159062000376575062000346620008f5565b60010182600001516000015160405162000361919062001278565b9081526040519081900360200190205460ff16155b80156200039057508151604001516001600160a01b031615155b905060016200039e620008f5565b600101836000015160000151604051620003b9919062001278565b908152604051908190036020019020805491151560ff1990921691909117905580620003e757506000919050565b60208201515160005b818110156200058657821562000586576000846020015182815181106200041b576200041b620011d6565b602090810291909101015180519091506000906001600160e01b031916620004b8576040516020016200046b9060208082526009908201526872656365697665282960b81b604082015260600190565b60405160208183030381529060405280519060200120826020015160405160200162000498919062001296565b604051602081830303815290604052805190602001201415905062000501565b602080830151604051620004cd920162001278565b604051602081830303815290604052805190602001206001600160e01b03191682600001516001600160e01b031916141590505b8015801562000536575062000515620008f5565b82516001600160e01b0319166000908152602091909152604090205460ff16155b9450600162000544620008f5565b92516001600160e01b03191660009081526020939093526040909220805460ff191692151592909217909155506200057e60018262001202565b9050620003f0565b5050919050565b6060815182604051602001620005a5929190620012ab565b6040516020818303038152906040529050919050565b6060620005cd82600160001962000956565b92915050565b60005b8151811015620002a8576000828281518110620005f757620005f7620011d6565b60200260200101519050620006258160000151600001516200061e62000a1460201b60201c565b9062000a20565b5080518051620006359162000a2e565b60208101515160005b818110156200072f576200065162000a14565b6002018360000151600001516040516200066c919062001278565b908152602001604051809103902060030183602001518281518110620006965762000696620011d6565b6020908102919091018101518254600180820185556000948552938390208251600290920201805463ffffffff191660e09290921c919091178155918101519092820190620006e6908262001388565b5050506200071a83602001518281518110620007065762000706620011d6565b602090810291909101015151845162000ab0565b6200072760018262001202565b90506200063e565b508151604080820151915190516001600160a01b039092169162000754919062001278565b60405180910390207fbb37a605de78ba6bc667aeaf438d0aae8247e6f48a8fad23730e4fbbb480abf3846040516200078d919062001454565b60405180910390a350620007a5905060018262001202565b9050620005d6565b60008281527f0a7b0f5c59907924802379ebe98cdc23e2ee7820f63d30126e10b3752010e500602090815260408083206001600160a01b0385168085529252808320805460ff1916600117905551339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b60006200083362000ae8565b60008481526020919091526040902054905060016200085162000ae8565b60008581526020919091526040812080549091906200087290849062001202565b909155508290506200088362000ae8565b6000858152602091825260408082208583526001019092522080546001600160a01b0319166001600160a01b039290921691909117905580620008c562000ae8565b6000948552602090815260408086206001600160a01b03909516865260029094019052919092205550565b905090565b6000806200092560017f11c19c8d567686e9e4073585fe511ac02fcfc0ce76ceba4592185bf5bec3cd1f62001469565b6040516020016200093891815260200190565b60408051601f19818403018152919052805160209091012092915050565b6060833b60008190036200097b57505060408051602081019091526000815262000a0d565b808411156200099b57505060408051602081019091526000815262000a0d565b83831015620009cf5760405163162544fd60e11b8152600481018290526024810185905260448101849052606401620001e0565b8383038482036000828210620009e65782620009e8565b815b60408051603f8301601f19168101909152818152955090508087602087018a3c505050505b9392505050565b6000620008f062000af4565b600062000a0d838362000b24565b8062000a3962000a14565b6002018360405162000a4c919062001278565b9081526040519081900360200190208151819062000a6b908262001388565b506020820151600182019062000a82908262001388565b5060409190910151600290910180546001600160a01b0319166001600160a01b039092169190911790555050565b8062000abb62000a14565b6001600160e01b031984166000908152600391909101602052604090208151819062000a6b908262001388565b6000620008f062000b8f565b6000806200092560017f775b9fab5634a62bb2a682c067408edbed43efd726183d2e2af744334d47acb762001469565b600062000b32838362000bf4565b62000b865782546001810184556000848152602090200162000b55838262001388565b508254604051600185019062000b6d90859062001278565b90815260405190819003602001902055506001620005cd565b506000620005cd565b60008060ff1962000bc260017f0c4ba382c0009cf238e4c1ca1a52f51c61e6248a70bdfb34e5ed49d5578a5c0c62001469565b60405160200162000bd591815260200190565b60408051601f1981840301815291905280516020909101201692915050565b6000826001018260405162000c0a919062001278565b9081526040519081900360200190205415159392505050565b613891806200607883390190565b6001600160a01b038116811462000c4757600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b038111828210171562000c855762000c8562000c4a565b60405290565b604051606081016001600160401b038111828210171562000c855762000c8562000c4a565b604051601f8201601f191681016001600160401b038111828210171562000cdb5762000cdb62000c4a565b604052919050565b60006001600160401b0382111562000cff5762000cff62000c4a565b5060051b60200190565b60005b8381101562000d2657818101518382015260200162000d0c565b50506000910152565b600082601f83011262000d4157600080fd5b81516001600160401b0381111562000d5d5762000d5d62000c4a565b62000d72601f8201601f191660200162000cb0565b81815284602083860101111562000d8857600080fd5b62000d9b82602083016020870162000d09565b949350505050565b600082601f83011262000db557600080fd5b8151602062000dce62000dc88362000ce3565b62000cb0565b82815260059290921b8401810191818101908684111562000dee57600080fd5b8286015b8481101562000e905780516001600160401b038082111562000e145760008081fd5b908801906040828b03601f190181131562000e2f5760008081fd5b62000e3962000c60565b838801516001600160e01b03198116811462000e555760008081fd5b815290830151908282111562000e6b5760008081fd5b62000e7b8c898487010162000d2f565b81890152865250505091830191830162000df2565b509695505050505050565b600082601f83011262000ead57600080fd5b8151602062000ec062000dc88362000ce3565b82815260059290921b8401810191818101908684111562000ee057600080fd5b8286015b8481101562000e905780516001600160401b038082111562000f0557600080fd5b90880190601f196040838c038201121562000f1f57600080fd5b62000f2962000c60565b878401518381111562000f3b57600080fd5b84016060818e038401121562000f5057600080fd5b62000f5a62000c8b565b9250888101518481111562000f6e57600080fd5b62000f7e8e8b8385010162000d2f565b84525060408101518481111562000f9457600080fd5b62000fa48e8b8385010162000d2f565b848b0152506060015162000fb88162000c31565b80604084015250818152604084015191508282111562000fd757600080fd5b62000fe78c898487010162000da3565b81890152865250505091830191830162000ee4565b6000806000606084860312156200101257600080fd5b83516200101f8162000c31565b6020850151909350620010328162000c31565b60408501519092506001600160401b038111156200104f57600080fd5b6200105d8682870162000e9b565b9150509250925092565b600081518084526200108181602086016020860162000d09565b601f01601f19169290920160200192915050565b60006040825160408552805160606040870152620010b760a087018262001067565b9050602080830151603f19888403016060890152620010d7838262001067565b604094909401516001600160a01b03166080890152508581015187840382890152805180855290820193925081830190600581901b8401830160005b828110156200116057858203601f19018452865180516001600160e01b03191683528501518583018990526200114c8984018262001067565b978601979486019492505060010162001113565b509998505050505050505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b82811015620011c957603f19888603018452620011b685835162001095565b9450928501929085019060010162001197565b5092979650505050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115620005cd57620005cd620011ec565b60008152600082516200123381600185016020870162000d09565b9190910160010192915050565b6000602082840312156200125357600080fd5b81516001600160401b038111156200126a57600080fd5b62000d9b8482850162000e9b565b600082516200128c81846020870162000d09565b9190910192915050565b60208152600062000a0d602083018462001067565b606360f81b815260e083901b6001600160e01b03191660018201526880600e6000396000f360b81b60058201528151600090620012f081600e85016020870162000d09565b91909101600e019392505050565b600181811c908216806200131357607f821691505b6020821081036200025357634e487b7160e01b600052602260045260246000fd5b601f821115620001e9576000816000526020600020601f850160051c810160208610156200135f5750805b601f850160051c820191505b8181101562001380578281556001016200136b565b505050505050565b81516001600160401b03811115620013a457620013a462000c4a565b620013bc81620013b58454620012fe565b8462001334565b602080601f831160018114620013f45760008415620013db5750858301515b600019600386901b1c1916600185901b17855562001380565b600085815260208120601f198616915b82811015620014255788860151825594840194600190910190840162001404565b5085821015620014445787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60208152600062000a0d602083018462001095565b81810381811115620005cd57620005cd620011ec565b60805160a05160c051614bad620014cb600039600061038401526000818161056101526114c70152600081816102aa01528181610d9d0152818161142301526117a10152614bad6000f3fe6080604052600436106101a45760003560e01c80639387a380116100e85780639387a380146104ad578063938e3d7b146104cd578063a0dbaefd146104ed578063a217fddf1461051a578063a32fa5b31461052f578063a65d69d41461054f578063ac9650d814610583578063c0562f6d146105b0578063c22707ee146105d0578063c3c5a547146105fd578063ca15c8731461061d578063ce0b60131461063d578063d547741f1461065d578063d8fd8f441461067d578063e05688fe1461069d578063e68a7c3b146106bd578063e8a3d485146106dd578063ee7d2adf146106ff576101a4565b806308e93d0a1461022d5780630b61e12b146102585780630e6254fd1461027857806311464fbe14610298578063248a9ca3146102e45780632f2ff15d1461031257806336568abe14610332578063429eed8014610352578063463c4864146103725780634a00cc48146103a6578063512cf914146103c857806358451f97146103e857806383a03f8c146103fd5780638856a1131461041d5780638878ed331461043d5780639010d07c1461045d57806391d148541461047d575b366000036101ae57005b60006101c56000356001600160e01b03191661071f565b90506001600160a01b0381166102225760405162461bcd60e51b815260206004820181905260248201527f526f757465723a2066756e6374696f6e20646f6573206e6f742065786973742e60448201526064015b60405180910390fd5b61022b81610734565b005b34801561023957600080fd5b5061024261075d565b60405161024f9190613d38565b60405180910390f35b34801561026457600080fd5b5061022b610273366004613da1565b61076e565b34801561028457600080fd5b50610242610293366004613dcb565b610806565b3480156102a457600080fd5b506102cc7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161024f565b3480156102f057600080fd5b506103046102ff366004613de6565b610830565b60405190815260200161024f565b34801561031e57600080fd5b5061022b61032d366004613dff565b61084e565b34801561033e57600080fd5b5061022b61034d366004613dff565b6108f8565b34801561035e57600080fd5b5061022b61036d366004613f42565b610957565b34801561037e57600080fd5b506102cc7f000000000000000000000000000000000000000000000000000000000000000081565b3480156103b257600080fd5b506103bb610bce565b60405161024f91906140c5565b3480156103d457600080fd5b5061022b6103e3366004613f42565b610c9d565b3480156103f457600080fd5b50610304610ccb565b34801561040957600080fd5b5061022b610418366004613de6565b610cd7565b34801561042957600080fd5b5061022b610438366004614181565b610d25565b34801561044957600080fd5b506102cc6104583660046141e4565b610d53565b34801561046957600080fd5b506102cc610478366004614266565b610dcd565b34801561048957600080fd5b5061049d610498366004613dff565b610edb565b604051901515815260200161024f565b3480156104b957600080fd5b5061022b6104c8366004613da1565b610f0f565b3480156104d957600080fd5b5061022b6104e8366004614288565b610fa6565b3480156104f957600080fd5b5061050d6105083660046142bc565b610ff7565b60405161024f91906142d7565b34801561052657600080fd5b50610304600081565b34801561053b57600080fd5b5061049d61054a366004613dff565b61116d565b34801561055b57600080fd5b506102cc7f000000000000000000000000000000000000000000000000000000000000000081565b34801561058f57600080fd5b506105a361059e3660046142ea565b6111d0565b60405161024f919061435e565b3480156105bc57600080fd5b5061022b6105cb366004614453565b61132c565b3480156105dc57600080fd5b506105f06105eb366004614288565b611359565b60405161024f9190614544565b34801561060957600080fd5b5061049d610618366004613dcb565b61136a565b34801561062957600080fd5b50610304610638366004613de6565b611376565b34801561064957600080fd5b506102cc6106583660046142bc565b61071f565b34801561066957600080fd5b5061022b610678366004613dff565b611413565b34801561068957600080fd5b506102cc6106983660046141e4565b61141e565b3480156106a957600080fd5b5061022b6106b8366004614453565b611569565b3480156106c957600080fd5b506102426106d8366004614266565b611596565b3480156106e957600080fd5b506106f26116c7565b60405161024f9190614557565b34801561070b57600080fd5b5061022b61071a366004614288565b61175f565b600061072a82610ff7565b6040015192915050565b3660008037600080366000845af43d6000803e808015610753573d6000f35b3d6000fd5b505050565b6060610769600061178c565b905090565b336107798183611799565b6107955760405162461bcd60e51b81526004016102199061456a565b6001600160a01b03831660009081526002602052604081206107b790836117dd565b9050801561080057836001600160a01b0316826001600160a01b03167f12146497b3b826918ec47f0cac7272a09ed06b30c16c030e99ec48ff5dd60b4760405160405180910390a35b50505050565b6001600160a01b038116600090815260026020526040902060609061082a9061178c565b92915050565b600061083a6117f2565b600092835260010160205250604090205490565b6108726108596117f2565b6000848152600191909101602052604090205433611816565b61087a6117f2565b6000838152602091825260408082206001600160a01b0385168352909252205460ff16156108ea5760405162461bcd60e51b815260206004820152601d60248201527f43616e206f6e6c79206772616e7420746f206e6f6e20686f6c646572730000006044820152606401610219565b6108f4828261189b565b5050565b336001600160a01b0382161461094d5760405162461bcd60e51b815260206004820152601a60248201527921b0b71037b7363c903932b737bab731b2903337b91039b2b63360311b6044820152606401610219565b6108f482826118af565b61095f6118c3565b61097b5760405162461bcd60e51b8152600401610219906145a1565b61098582826118ef565b6109f25760405162461bcd60e51b815260206004820152603860248201527f457874656e73696f6e4d616e616765723a2063616e6e6f742072656d6f766520604482015277333ab731ba34b7b710333937b69032bc3a32b739b4b7b71760411b6064820152608401610219565b60006109fc6119ee565b6001600160e01b031983166000908152600391909101602052604090819020815160608101909252805482908290610a33906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054610a5f906145d8565b8015610aac5780601f10610a8157610100808354040283529160200191610aac565b820191906000526020600020905b815481529060010190602001808311610a8f57829003601f168201915b50505050508152602001600182018054610ac5906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054610af1906145d8565b8015610b3e5780601f10610b1357610100808354040283529160200191610b3e565b820191906000526020600020905b815481529060010190602001808311610b2157829003601f168201915b5050509183525050600291909101546001600160a01b03166020909101529050610b6883836119f8565b610b7182611cc5565b816001600160e01b03191683604051610b8a919061460c565b60405180910390207fbb931a9651175c9c82f86afbf6ad37a9141aa8d1d42bf798739be245a12e4e8883604051610bc191906142d7565b60405180910390a3505050565b60606000610be2610bdd6119ee565b611d18565b8051909150806001600160401b03811115610bff57610bff613e2b565b604051908082528060200260200182016040528015610c3857816020015b610c25613c4f565b815260200190600190039081610c1d5790505b50925060005b81811015610c9757610c68838281518110610c5b57610c5b614628565b6020026020010151611d23565b848281518110610c7a57610c7a614628565b6020908102919091010152610c90600182614654565b9050610c3e565b50505090565b610ca56118c3565b610cc15760405162461bcd60e51b8152600401610219906145a1565b6108f48282610957565b60006107696000611fac565b33610ce28183611799565b610cfe5760405162461bcd60e51b81526004016102199061456a565b610d096000826117dd565b6108f45760405162461bcd60e51b815260040161021990614667565b610d2d6118c3565b610d495760405162461bcd60e51b8152600401610219906145a1565b6108f48282611fb6565b600080610d968585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061220592505050565b9050610dc27f000000000000000000000000000000000000000000000000000000000000000082612238565b9150505b9392505050565b600080610dd8612298565b600085815260209190915260408120549150805b82811015610ed2576000610dfe612298565b60008881526020918252604080822085835260010190925220546001600160a01b031614610e7657848203610e6457610e35612298565b600087815260209182526040808220938252600190930190915220546001600160a01b0316925061082a915050565b610e6f600183614654565b9150610ec0565b610e81866000610edb565b8015610ead5750610e90612298565b600087815260209182526040808220828052600201909252205481145b15610ec057610ebd600183614654565b91505b610ecb600182614654565b9050610dec565b50505092915050565b6000610ee56117f2565b6000938452602090815260408085206001600160a01b039490941685529290525090205460ff1690565b33610f1a8183611799565b610f365760405162461bcd60e51b81526004016102199061456a565b6001600160a01b0383166000908152600260205260408120610f5890836122a2565b9050801561080057836001600160a01b0316826001600160a01b03167f98d1ebbe00ae92a5de96a0f49742a8afa89f42363592bc2e7cfaaed68b45e7a660405160405180910390a350505050565b610fae6122b7565b610feb5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606401610219565b610ff4816122c3565b50565b610fff613c6f565b6110076119ee565b6001600160e01b03198316600090815260039190910160205260409081902081516060810190925280548290829061103e906145d8565b80601f016020809104026020016040519081016040528092919081815260200182805461106a906145d8565b80156110b75780601f1061108c576101008083540402835291602001916110b7565b820191906000526020600020905b81548152906001019060200180831161109a57829003601f168201915b505050505081526020016001820180546110d0906145d8565b80601f01602080910402602001604051908101604052809291908181526020018280546110fc906145d8565b80156111495780601f1061111e57610100808354040283529160200191611149565b820191906000526020600020905b81548152906001019060200180831161112c57829003601f168201915b5050509183525050600291909101546001600160a01b031660209091015292915050565b60006111776117f2565b600084815260209182526040808220828052909252205460ff166111c75761119d6117f2565b6000848152602091825260408082206001600160a01b0386168352909252205460ff16905061082a565b50600192915050565b6060816001600160401b038111156111ea576111ea613e2b565b60405190808252806020026020018201604052801561121d57816020015b60608152602001906001900390816112085790505b509050336000805b84811015610ed25781156112a4576112823087878481811061124957611249614628565b905060200281019061125b91906146b1565b8660405160200161126e939291906146fe565b6040516020818303038152906040526123aa565b84828151811061129457611294614628565b6020026020010181905250611324565b611306308787848181106112ba576112ba614628565b90506020028101906112cc91906146b1565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506123aa92505050565b84828151811061131857611318614628565b60200260200101819052505b600101611225565b6113346118c3565b6113505760405162461bcd60e51b8152600401610219906145a1565b610ff4816123cf565b611361613c4f565b61082a82611d23565b600061082a8183612538565b600080611381612298565b6000848152602091909152604081205491505b818110156113ee5760006113a6612298565b60008681526020918252604080822085835260010190925220546001600160a01b0316146113dc576113d9600184614654565b92505b6113e7600182614654565b9050611394565b506113fa836000610edb565b1561140d5761140a600183614654565b91505b50919050565b61094d6108596117f2565b6000807f0000000000000000000000000000000000000000000000000000000000000000905060006114868686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061220592505050565b905060006114948383612238565b90506001600160a01b0381163b156114b0579250610dc6915050565b6114ba838361255a565b9050336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611513576114f76000826117dd565b6115135760405162461bcd60e51b815260040161021990614667565b61151f818888886125f1565b866001600160a01b0316816001600160a01b03167fac631f3001b55ea1509cf3d7e74898f85392a61a76e8149181ae1259622dabc860405160405180910390a39695505050505050565b6115716118c3565b61158d5760405162461bcd60e51b8152600401610219906145a1565b610ff481612659565b606081831080156115b057506115ac6000611fac565b8211155b6116085760405162461bcd60e51b815260206004820152602360248201527f426173654163636f756e74466163746f72793a20696e76616c696420696e646960448201526263657360e81b6064820152608401610219565b6000611614848461471f565b9050611620848461471f565b6001600160401b0381111561163757611637613e2b565b604051908082528060200260200182016040528015611660578160200160208202803683370190505b50915060005b818110156116bf5761168361167b8683614654565b600090612783565b83828151811061169557611695614628565b6001600160a01b03909216602092830291909101909101526116b8600182614654565b9050611666565b505092915050565b60606116d161278f565b80546116dc906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611708906145d8565b80156117555780601f1061172a57610100808354040283529160200191611755565b820191906000526020600020905b81548152906001019060200180831161173857829003601f168201915b5050505050905090565b6117676118c3565b6117835760405162461bcd60e51b8152600401610219906145a1565b610ff4816127b3565b60606000610dc683612afd565b6000806117c67f000000000000000000000000000000000000000000000000000000000000000084612238565b6001600160a01b0385811691161491505092915050565b6000610dc6836001600160a01b038416612b59565b7f0a7b0f5c59907924802379ebe98cdc23e2ee7820f63d30126e10b3752010e50090565b61181e6117f2565b6000838152602091825260408082206001600160a01b0385168352909252205460ff166108f457611859816001600160a01b03166014612ba8565b611864836020612ba8565b604051602001611875929190614732565b60408051601f198184030181529082905262461bcd60e51b825261021991600401614557565b6118a58282612d43565b6108f48282612dac565b6118b98282612e6b565b6108f48282612ed4565b60006107697f55add213c41f3851b4506717b8af695a4256979dff496dcaae7789f6121331aa33610edb565b6000611903836118fd6119ee565b90612f63565b61191f5760405162461bcd60e51b81526004016102199061479f565b826040516020016119309190614557565b6040516020818303038152906040528051906020012061194e6119ee565b6001600160e01b0319841660009081526003919091016020908152604091829020915161197c9291016147ea565b60405160208183030381529060405280519060200120146111c75760405162461bcd60e51b815260206004820152602660248201527f457874656e73696f6e4d616e616765723a20696e636f727265637420657874656044820152653739b4b7b71760d11b6064820152608401610219565b6000610769612f6f565b6000611a026119ee565b60020183604051611a13919061460c565b9081526020016040518091039020600301805480602002602001604051908101604052809291908181526020016000905b82821015611b215760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b03191682526001810180549293919291840191611a90906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611abc906145d8565b8015611b095780601f10611ade57610100808354040283529160200191611b09565b820191906000526020600020905b815481529060010190602001808311611aec57829003601f168201915b50505050508152505081526020019060010190611a44565b5050825192935060009150505b81811015611cbe57836001600160e01b031916838281518110611b5357611b53614628565b6020026020010151600001516001600160e01b03191603611cac57611b766119ee565b60020185604051611b87919061460c565b908152604051908190036020019020600301611ba460018461471f565b81548110611bb457611bb4614628565b9060005260206000209060020201611bca6119ee565b60020186604051611bdb919061460c565b90815260200160405180910390206003018281548110611bfd57611bfd614628565b600091825260209091208254600290920201805463ffffffff191663ffffffff909216919091178155600180820190611c38908401826148d7565b50905050611c446119ee565b60020185604051611c55919061460c565b9081526020016040518091039020600301805480611c7557611c756149ad565b600082815260208120600260001990930192830201805463ffffffff1916815590611ca36001830182613c99565b50509055611cbe565b611cb7600182614654565b9050611b2e565b5050505050565b611ccd6119ee565b6001600160e01b0319821660009081526003919091016020526040812090611cf58282613c99565b611d03600183016000613c99565b5060020180546001600160a01b031916905550565b606061082a82612fcd565b611d2b613c4f565b611d336119ee565b60020182604051611d44919061460c565b9081526040805191829003602001822060a08301825280549091839190820190839082908290611d73906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611d9f906145d8565b8015611dec5780601f10611dc157610100808354040283529160200191611dec565b820191906000526020600020905b815481529060010190602001808311611dcf57829003601f168201915b50505050508152602001600182018054611e05906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611e31906145d8565b8015611e7e5780601f10611e5357610100808354040283529160200191611e7e565b820191906000526020600020905b815481529060010190602001808311611e6157829003601f168201915b5050509183525050600291909101546001600160a01b03166020918201529082526003830180546040805182850281018501909152818152938301939260009084015b82821015611f9e5760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b03191682526001810180549293919291840191611f0d906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611f39906145d8565b8015611f865780601f10611f5b57610100808354040283529160200191611f86565b820191906000526020600020905b815481529060010190602001808311611f6957829003601f168201915b50505050508152505081526020019060010190611ec1565b505050915250909392505050565b600061082a825490565b611fc082826130aa565b61202c5760405162461bcd60e51b815260206004820152603760248201527f457874656e73696f6e4d616e616765723a2063616e6e6f742053746f72653a20604482015276333ab731ba34b7b7103337b91032bc3a32b739b4b7b71760491b6064820152608401610219565b61203682826130d4565b60006120406119ee565b60020183604051612051919061460c565b9081526040805191829003602001822060608301909152805482908290612077906145d8565b80601f01602080910402602001604051908101604052809291908181526020018280546120a3906145d8565b80156120f05780601f106120c5576101008083540402835291602001916120f0565b820191906000526020600020905b8154815290600101906020018083116120d357829003601f168201915b50505050508152602001600182018054612109906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054612135906145d8565b80156121825780601f1061215757610100808354040283529160200191612182565b820191906000526020600020905b81548152906001019060200180831161216557829003601f168201915b5050509183525050600291909101546001600160a01b031660209091015282519091506121af9082613322565b81600001516001600160e01b031916836040516121cc919061460c565b60405180910390207f681115194e519bda23de4da5218f3bc38f5585eab7c6b7d5fa66caa4602f574d8484604051610bc19291906149c3565b6000828260405160200161221a9291906149e8565b60405160208183030381529060405280519060200120905092915050565b6040513060388201526f5af43d82803e903d91602b57fd5bf3ff602482015260148101839052733d602d80600a3d3981f3363d3d373d3d3d363d738152605881018290526037600c82012060788201526055604390910120600090610dc6565b6000610769613399565b6000610dc6836001600160a01b0384166133fb565b60006107698133610edb565b60006122cd61278f565b80546122d8906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054612304906145d8565b80156123515780601f1061232657610100808354040283529160200191612351565b820191906000526020600020905b81548152906001019060200180831161233457829003601f168201915b505050505090508161236161278f565b9061236c9082614a0c565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a16818360405161239e929190614abd565b60405180910390a15050565b6060610dc68383604051806060016040528060278152602001614b51602791396134ee565b6123d881613566565b6124385760405162461bcd60e51b815260206004820152602b60248201527f457874656e73696f6e4d616e616765723a2063616e6e6f74207265706c61636560448201526a1032bc3a32b739b4b7b71760a91b6064820152608401610219565b805180516124459161361a565b80515161245190613651565b60208101515160005b818110156124d2576124918360000151600001518460200151838151811061248457612484614628565b60200260200101516130d4565b6124c0836020015182815181106124aa576124aa614628565b6020026020010151600001518460000151613322565b6124cb600182614654565b905061245a565b508151604080820151915190516001600160a01b03909216916124f5919061460c565b60405180910390207f5f1ef2b136db521971a88818ce904a8e310082338afdc100212a3127066421588460405161252c9190614544565b60405180910390a35050565b6001600160a01b03811660009081526001830160205260408120541515610dc6565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b03811661082a5760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b6044820152606401610219565b60405163347d5e2560e21b81526001600160a01b0385169063d1f578949061262190869086908690600401614ae2565b600060405180830381600087803b15801561263b57600080fd5b505af115801561264f573d6000803e3d6000fd5b5050505050505050565b612662816137fa565b6126be5760405162461bcd60e51b815260206004820152602760248201527f457874656e73696f6e4d616e616765723a2063616e6e6f74206164642065787460448201526632b739b4b7b71760c91b6064820152608401610219565b805180516126cb9161361a565b60208101515160005b81811015612729576126fe8360000151600001518460200151838151811061248457612484614628565b612717836020015182815181106124aa576124aa614628565b612722600182614654565b90506126d4565b508151604080820151915190516001600160a01b039092169161274c919061460c565b60405180910390207fbb37a605de78ba6bc667aeaf438d0aae8247e6f48a8fad23730e4fbbb480abf38460405161252c9190614544565b6000610dc683836138c2565b7f4bc804ba64359c0e35e5ed5d90ee596ecaa49a3a930ddcb1470ea0dd625da90090565b6127bc816138ec565b61281b5760405162461bcd60e51b815260206004820152602a60248201527f457874656e73696f6e4d616e616765723a2063616e6e6f742072656d6f76652060448201526932bc3a32b739b4b7b71760b11b6064820152608401610219565b60006128256119ee565b60020182604051612836919061460c565b9081526040805191829003602001822060a08301825280549091839190820190839082908290612865906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054612891906145d8565b80156128de5780601f106128b3576101008083540402835291602001916128de565b820191906000526020600020905b8154815290600101906020018083116128c157829003601f168201915b505050505081526020016001820180546128f7906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054612923906145d8565b80156129705780601f1061294557610100808354040283529160200191612970565b820191906000526020600020905b81548152906001019060200180831161295357829003601f168201915b5050509183525050600291909101546001600160a01b03166020918201529082526003830180546040805182850281018501909152818152938301939260009084015b82821015612a905760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b031916825260018101805492939192918401916129ff906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054612a2b906145d8565b8015612a785780601f10612a4d57610100808354040283529160200191612a78565b820191906000526020600020905b815481529060010190602001808311612a5b57829003601f168201915b505050505081525050815260200190600101906129b3565b50505050815250509050612aa38261391c565b612aac82613651565b81604051612aba919061460c565b60405180910390207f3169a23cec9ad1a25ab59bbe00ecf8973dd840c745775ea8877041ef5ce65bcc82604051612af19190614544565b60405180910390a25050565b606081600001805480602002602001604051908101604052809291908181526020018280548015612b4d57602002820191906000526020600020905b815481526020019060010190808311612b39575b50505050509050919050565b6000818152600183016020526040812054612ba05750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561082a565b50600061082a565b60606000612bb7836002614b22565b612bc2906002614654565b6001600160401b03811115612bd957612bd9613e2b565b6040519080825280601f01601f191660200182016040528015612c03576020820181803683370190505b509050600360fc1b81600081518110612c1e57612c1e614628565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110612c4d57612c4d614628565b60200101906001600160f81b031916908160001a9053506000612c71846002614b22565b612c7c906001614654565b90505b6001811115612cf4576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110612cb057612cb0614628565b1a60f81b828281518110612cc657612cc6614628565b60200101906001600160f81b031916908160001a90535060049490941c93612ced81614b39565b9050612c7f565b508315610dc65760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610219565b6001612d4d6117f2565b6000848152602091825260408082206001600160a01b0386168084529352808220805460ff1916941515949094179093559151339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b6000612db6612298565b6000848152602091909152604090205490506001612dd2612298565b6000858152602091909152604081208054909190612df1908490614654565b90915550829050612e00612298565b6000858152602091825260408082208583526001019092522080546001600160a01b0319166001600160a01b039290921691909117905580612e40612298565b6000948552602090815260408086206001600160a01b03909516865260029094019052919092205550565b612e758282611816565b612e7d6117f2565b6000838152602091825260408082206001600160a01b0385168084529352808220805460ff191690555133929185917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000612ede612298565b6000848152602091825260408082206001600160a01b038616835260020190925220549050612f0b612298565b6000848152602091825260408082208483526001019092522080546001600160a01b0319169055612f3a612298565b6000938452602090815260408085206001600160a01b0390941685526002909301905250812055565b6000610dc68383613950565b600080612f9d60017f775b9fab5634a62bb2a682c067408edbed43efd726183d2e2af744334d47acb761471f565b604051602001612faf91815260200190565b60408051601f19818403018152919052805160209091012092915050565b606081600001805480602002602001604051908101604052809291908181526020016000905b8282101561309f578382906000526020600020018054613012906145d8565b80601f016020809104026020016040519081016040528092919081815260200182805461303e906145d8565b801561308b5780601f106130605761010080835404028352916020019161308b565b820191906000526020600020905b81548152906001019060200180831161306e57829003601f168201915b505050505081526020019060010190612ff3565b505050509050919050565b60006130b8836118fd6119ee565b6111c75760405162461bcd60e51b81526004016102199061479f565b80516000906001600160e01b03191661315e576040516020016131149060208082526009908201526872656365697665282960b81b604082015260600190565b60405160208183030381529060405280519060200120826020015160405160200161313f9190614557565b60405160208183030381529060405280519060200120141590506131a5565b602080830151604051613171920161460c565b604051602081830303815290604052805190602001206001600160e01b03191682600001516001600160e01b031916141590505b80156132115760405162461bcd60e51b815260206004820152603560248201527f457874656e73696f6e4d616e616765723a20666e2073656c6563746f7220616e604482015274321039b4b3b730ba3ab9329036b4b9b6b0ba31b41760591b6064820152608401610219565b600061321b6119ee565b83516001600160e01b031916600090815260039190910160205260409020600201546001600160a01b0316146132ab5760405162461bcd60e51b815260206004820152602f60248201527f457874656e73696f6e4d616e616765723a2066756e6374696f6e20696d706c2060448201526e30b63932b0b23c9032bc34b9ba399760891b6064820152608401610219565b6132b36119ee565b600201836040516132c4919061460c565b908152604051602091819003820190206003018054600180820183556000928352918390208551600290920201805463ffffffff191660e09290921c9190911781559184015184929182019061331a9082614a0c565b505050505050565b8061332b6119ee565b6001600160e01b03198416600090815260039190910160205260409020815181906133569082614a0c565b506020820151600182019061336b9082614a0c565b5060409190910151600290910180546001600160a01b0319166001600160a01b039092169190911790555050565b60008060ff196133ca60017f0c4ba382c0009cf238e4c1ca1a52f51c61e6248a70bdfb34e5ed49d5578a5c0c61471f565b6040516020016133dc91815260200190565b60408051601f1981840301815291905280516020909101201692915050565b600081815260018301602052604081205480156134e457600061341f60018361471f565b85549091506000906134339060019061471f565b905081811461349857600086600001828154811061345357613453614628565b906000526020600020015490508087600001848154811061347657613476614628565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806134a9576134a96149ad565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061082a565b600091505061082a565b6060600080856001600160a01b03168560405161350b919061460c565b600060405180830381855af49150503d8060008114613546576040519150601f19603f3d011682016040523d82523d6000602084013e61354b565b606091505b509150915061355c8683838761397d565b9695505050505050565b805151600090613578906118fd6119ee565b6135945760405162461bcd60e51b81526004016102199061479f565b8151604001516001600160a01b03166136125760405162461bcd60e51b815260206004820152603a60248201527f457874656e73696f6e4d616e616765723a20616464696e6720657874656e736960448201527937b7103bb4ba3437baba1034b6b83632b6b2b73a30ba34b7b71760311b6064820152608401610219565b506001919050565b806136236119ee565b60020183604051613634919061460c565b908152604051908190036020019020815181906133569082614a0c565b600061365b6119ee565b6002018260405161366c919061460c565b9081526020016040518091039020600301805480602002602001604051908101604052809291908181526020016000905b8282101561377a5760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b031916825260018101805492939192918401916136e9906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054613715906145d8565b80156137625780601f1061373757610100808354040283529160200191613762565b820191906000526020600020905b81548152906001019060200180831161374557829003601f168201915b5050505050815250508152602001906001019061369d565b5050505090506137886119ee565b60020182604051613799919061460c565b908152602001604051809103902060030160006137b69190613cd3565b60005b8151811015610758576137e88282815181106137d7576137d7614628565b602002602001015160000151611cc5565b6137f3600182614654565b90506137b9565b8051515160009061384d5760405162461bcd60e51b815260206004820152601d60248201527f457874656e73696f6e4d616e616765723a20656d707479206e616d652e0000006044820152606401610219565b8151516138629061385c6119ee565b906139fe565b6135945760405162461bcd60e51b815260206004820152602b60248201527f457874656e73696f6e4d616e616765723a20657874656e73696f6e20616c726560448201526a30b23c9032bc34b9ba399760a91b6064820152608401610219565b60008260000182815481106138d9576138d9614628565b9060005260206000200154905092915050565b6000613900826138fa6119ee565b90613a0a565b6136125760405162461bcd60e51b81526004016102199061479f565b6139246119ee565b60020181604051613935919061460c565b9081526040519081900360200190206000611cf58282613c99565b60008260010182604051613964919061460c565b9081526040519081900360200190205415159392505050565b606083156139ec5782516000036139e5576001600160a01b0385163b6139e55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610219565b50816139f6565b6139f68383613a16565b949350505050565b6000610dc68383613a40565b6000610dc68383613a9a565b815115613a265781518083602001fd5b8060405162461bcd60e51b81526004016102199190614557565b6000613a4c8383613950565b612ba057825460018101845560008481526020902001613a6c8382614a0c565b5082546040516001850190613a8290859061460c565b9081526040519081900360200190205550600161082a565b6000808360010183604051613aaf919061460c565b9081526020016040518091039020549050806000146134e4576000613ad560018361471f565b8554909150600090613ae99060019061471f565b9050818114613bf0576000866000018281548110613b0957613b09614628565b906000526020600020018054613b1e906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054613b4a906145d8565b8015613b975780601f10613b6c57610100808354040283529160200191613b97565b820191906000526020600020905b815481529060010190602001808311613b7a57829003601f168201915b5050505050905080876000018481548110613bb457613bb4614628565b906000526020600020019081613bca9190614a0c565b50838760010182604051613bde919061460c565b90815260405190819003602001902055505b8554869080613c0157613c016149ad565b600190038181906000526020600020016000613c1d9190613c99565b90558560010185604051613c31919061460c565b9081526020016040518091039020600090556001935050505061082a565b6040518060400160405280613c62613c6f565b8152602001606081525090565b6040518060600160405280606081526020016060815260200160006001600160a01b031681525090565b508054613ca5906145d8565b6000825580601f10613cb5575050565b601f016020900490600052602060002090810190610ff49190613cf4565b5080546000825560020290600052602060002090810190610ff49190613d0d565b5b80821115613d095760008155600101613cf5565b5090565b80821115613d0957805463ffffffff191681556000613d2f6001830182613c99565b50600201613d0d565b6020808252825182820181905260009190848201906040850190845b81811015613d795783516001600160a01b031683529284019291840191600101613d54565b50909695505050505050565b80356001600160a01b0381168114613d9c57600080fd5b919050565b60008060408385031215613db457600080fd5b613dbd83613d85565b946020939093013593505050565b600060208284031215613ddd57600080fd5b610dc682613d85565b600060208284031215613df857600080fd5b5035919050565b60008060408385031215613e1257600080fd5b82359150613e2260208401613d85565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715613e6357613e63613e2b565b60405290565b604051606081016001600160401b0381118282101715613e6357613e63613e2b565b604051601f8201601f191681016001600160401b0381118282101715613eb357613eb3613e2b565b604052919050565b600082601f830112613ecc57600080fd5b81356001600160401b03811115613ee557613ee5613e2b565b613ef8601f8201601f1916602001613e8b565b818152846020838601011115613f0d57600080fd5b816020850160208301376000918101602001919091529392505050565b80356001600160e01b031981168114613d9c57600080fd5b60008060408385031215613f5557600080fd5b82356001600160401b03811115613f6b57600080fd5b613f7785828601613ebb565b925050613e2260208401613f2a565b60005b83811015613fa1578181015183820152602001613f89565b50506000910152565b60008151808452613fc2816020860160208601613f86565b601f01601f19169290920160200192915050565b6000815160608452613feb6060850182613faa565b9050602083015184820360208601526140048282613faa565b6040948501516001600160a01b03169590940194909452509092915050565b63ffffffff60e01b815116825260006020820151604060208501526139f66040850182613faa565b60008151604084526140606040850182613fd6565b9050602080840151858303828701528281518085528385019150838160051b860101848401935060005b828110156140b857601f198783030184526140a6828651614023565b9486019493860193915060010161408a565b5098975050505050505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b8281101561411c57603f1988860301845261410a85835161404b565b945092850192908501906001016140ee565b5092979650505050505050565b60006040828403121561413b57600080fd5b614143613e41565b905061414e82613f2a565b815260208201356001600160401b0381111561416957600080fd5b61417584828501613ebb565b60208301525092915050565b6000806040838503121561419457600080fd5b82356001600160401b03808211156141ab57600080fd5b6141b786838701613ebb565b935060208501359150808211156141cd57600080fd5b506141da85828601614129565b9150509250929050565b6000806000604084860312156141f957600080fd5b61420284613d85565b925060208401356001600160401b038082111561421e57600080fd5b818601915086601f83011261423257600080fd5b81358181111561424157600080fd5b87602082850101111561425357600080fd5b6020830194508093505050509250925092565b6000806040838503121561427957600080fd5b50508035926020909101359150565b60006020828403121561429a57600080fd5b81356001600160401b038111156142b057600080fd5b6139f684828501613ebb565b6000602082840312156142ce57600080fd5b610dc682613f2a565b602081526000610dc66020830184613fd6565b600080602083850312156142fd57600080fd5b82356001600160401b038082111561431457600080fd5b818501915085601f83011261432857600080fd5b81358181111561433757600080fd5b8660208260051b850101111561434c57600080fd5b60209290920196919550909350505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b8281101561411c57603f198886030184526143a3858351613faa565b94509285019290850190600101614387565b600082601f8301126143c657600080fd5b813560206001600160401b03808311156143e2576143e2613e2b565b8260051b6143f1838201613e8b565b938452858101830193838101908886111561440b57600080fd5b84880192505b85831015614447578235848111156144295760008081fd5b6144378a87838c0101614129565b8352509184019190840190614411565b98975050505050505050565b60006020828403121561446557600080fd5b81356001600160401b038082111561447c57600080fd5b908301906040828603121561449057600080fd5b614498613e41565b8235828111156144a757600080fd5b8301606081880312156144b957600080fd5b6144c1613e69565b8135848111156144d057600080fd5b6144dc89828501613ebb565b8252506020820135848111156144f157600080fd5b6144fd89828501613ebb565b60208301525061450f60408301613d85565b604082015282525060208301358281111561452957600080fd5b614535878286016143b5565b60208301525095945050505050565b602081526000610dc6602083018461404b565b602081526000610dc66020830184613faa565b6020808252601f908201527f4163636f756e74466163746f72793a206e6f7420616e206163636f756e742e00604082015260600190565b6020808252601f908201527f457874656e73696f6e4d616e616765723a20756e617574686f72697a65642e00604082015260600190565b600181811c908216806145ec57607f821691505b60208210810361140d57634e487b7160e01b600052602260045260246000fd5b6000825161461e818460208701613f86565b9190910192915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561082a5761082a61463e565b6020808252602a908201527f4163636f756e74466163746f72793a206163636f756e7420616c7265616479206040820152691c9959da5cdd195c995960b21b606082015260800190565b6000808335601e198436030181126146c857600080fd5b8301803591506001600160401b038211156146e257600080fd5b6020019150368190038213156146f757600080fd5b9250929050565b8284823760609190911b6001600160601b0319169101908152601401919050565b8181038181111561082a5761082a61463e565b7402832b936b4b9b9b4b7b7399d1030b1b1b7bab73a1605d1b815260008351614762816015850160208801613f86565b7001034b99036b4b9b9b4b733903937b6329607d1b6015918401918201528351614793816026840160208801613f86565b01602601949350505050565b6020808252602b908201527f457874656e73696f6e4d616e616765723a20657874656e73696f6e20646f657360408201526a103737ba1032bc34b9ba1760a91b606082015260800190565b60006020808352600084546147fe816145d8565b8060208701526040600180841660008114614820576001811461483c5761486c565b60ff19851660408a0152604084151560051b8a0101955061486c565b89600052602060002060005b858110156148635781548b8201860152908301908801614848565b8a016040019650505b509398975050505050505050565b601f821115610758576000816000526020600020601f850160051c810160208610156148a35750805b601f850160051c820191505b8181101561331a578281556001016148af565b600019600383901b1c191660019190911b1790565b8181036148e2575050565b6148ec82546145d8565b6001600160401b0381111561490357614903613e2b565b6149178161491184546145d8565b8461487a565b6000601f82116001811461494557600083156149335750848201545b61493d84826148c2565b855550611cbe565b600085815260209020601f19841690600086815260209020845b8381101561497f578286015482556001958601959091019060200161495f565b508583101561499d5781850154600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052603160045260246000fd5b6040815260006149d66040830185614023565b8281036020840152610dc28185613fd6565b6001600160a01b03831681526040602082018190526000906139f690830184613faa565b81516001600160401b03811115614a2557614a25613e2b565b614a338161491184546145d8565b602080601f831160018114614a625760008415614a505750858301515b614a5a85826148c2565b86555061331a565b600085815260208120601f198616915b82811015614a9157888601518255948401946001909101908401614a72565b508582101561499d57939096015160001960f8600387901b161c19169092555050600190811b01905550565b604081526000614ad06040830185613faa565b8281036020840152610dc28185613faa565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b808202811582820484141761082a5761082a61463e565b600081614b4857614b4861463e565b50600019019056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220ea0bf6593fb849f1c8bca9503fc128d4ca8a5664256139b4a63c87879333ff4a64736f6c634300081700336101806040523480156200001257600080fd5b506040516200389138038062003891833981016040819052620000359162000250565b60408051808201825260078152661058d8dbdd5b9d60ca1b60208083019182528351808501855260018152603160f81b908201529151902060e08190527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66101008190524660a081815285517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818701819052818801959095526060810193909352608080840192909252308382018190528651808503909201825260c093840190965280519401939093209092529190526101205281816200011762000134565b6001600160a01b03908116610140521661016052506200028f9050565b7f322cf19c484104d3b1a9c2982ebae869ede3fa5f6c4703ca41b9a48c76ee03005460ff808216916101009004168015620001c55760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60ff828116101562000233577f322cf19c484104d3b1a9c2982ebae869ede3fa5f6c4703ca41b9a48c76ee0300805460ff191660ff90811790915560408051918252517f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989181900360200190a15b5050565b6001600160a01b03811681146200024d57600080fd5b50565b600080604083850312156200026457600080fd5b8251620002718162000237565b6020840151909250620002848162000237565b809150509250929050565b60805160a05160c05160e0516101005161012051610140516101605161356b62000326600039600061111a01526000818161033401528181610431015281816107eb015281816119660152818161199401528181611a1b01528181611a960152611ac60152600061232e0152600061237d01526000612358015260006122b1015260006122db01526000612305015261356b6000f3fe6080604052600436106100d95760003560e01c80631dd756c51461016257806324d7806c146101975780633a871cdd146101b75780634a00cc48146101e55780635892e236146102075780637dff5a79146102275780638b52d72314610247578063a9082d8414610269578063ac9650d8146102a8578063b0d691fe146102d5578063b76464d514610302578063c45a015514610322578063ce0b601314610356578063d087d28814610376578063d1f578941461038b578063d42f2f35146103ab578063e9523c97146103c0578063f15d424e146103e2575b366000036100e357005b60006100fa6000356001600160e01b03191661040f565b90506001600160a01b0381166101575760405162461bcd60e51b815260206004820181905260248201527f526f757465723a2066756e6374696f6e20646f6573206e6f742065786973742e60448201526064015b60405180910390fd5b610160816104aa565b005b34801561016e57600080fd5b5061018261017d3660046125ae565b6104ce565b60405190151581526020015b60405180910390f35b3480156101a357600080fd5b506101826101b23660046125fd565b610792565b3480156101c357600080fd5b506101d76101d236600461261a565b6107c1565b60405190815260200161018e565b3480156101f157600080fd5b506101fa6107e7565b60405161018e91906126b7565b34801561021357600080fd5b50610160610222366004612811565b610874565b34801561023357600080fd5b506101826102423660046125fd565b610c3a565b34801561025357600080fd5b5061025c610cf3565b60405161018e9190612933565b34801561027557600080fd5b50610289610284366004612811565b610f3a565b6040805192151583526001600160a01b0390911660208301520161018e565b3480156102b457600080fd5b506102c86102c3366004612997565b610f91565b60405161018e9190612a0b565b3480156102e157600080fd5b506102ea6110f6565b6040516001600160a01b03909116815260200161018e565b34801561030e57600080fd5b5061016061031d3660046125fd565b61113f565b34801561032e57600080fd5b506102ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561036257600080fd5b506102ea610371366004612a78565b61040f565b34801561038257600080fd5b506101d7611171565b34801561039757600080fd5b506101606103a6366004612a95565b6111ec565b3480156103b757600080fd5b5061025c6113a5565b3480156103cc57600080fd5b506103d5611516565b60405161018e9190612adc565b3480156103ee57600080fd5b506104026103fd3660046125fd565b611528565b60405161018e9190612aef565b60405163ce0b601360e01b81526001600160e01b0319821660048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063ce0b601390602401602060405180830381865afa158015610480573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a49190612b02565b92915050565b3660008037600080366000845af43d6000803e8080156104c9573d6000f35b3d6000fd5b60006104d8611600565b6001600160a01b0384166000908152600491909101602052604090205460ff1615610505575060016104a4565b600061050f611600565b6001600160a01b0385166000908152600591909101602090815260408083208151606081018352815481526001909101546001600160801b0380821694830194909452600160801b900490921690820152915061056a611600565b6006016000866001600160a01b03166001600160a01b0316815260200190815260200160002090504282602001516001600160801b031611806105ba575081604001516001600160801b03164210155b806105cb57506105c981611624565b155b156105db576000925050506104a4565b60006105f26105ed6060870187612b1f565b61162e565b905060006105ff83611624565b6001148015610620575060006106158482611668565b6001600160a01b0316145b90506324f16c0560e11b6001600160e01b03198316016106975760008061065261064d60608a018a612b1f565b611674565b91509150826106785761066585836116d9565b61067857600096505050505050506104a4565b855181111561069057600096505050505050506104a4565b5050610785565b635c0f12eb60e11b6001600160e01b0319831601610778576000806106c76106c260608a018a612b1f565b6116fb565b5091509150826107275760005b8251811015610725576107098382815181106106f2576106f2612b65565b6020026020010151876116d990919063ffffffff16565b61071d5760009750505050505050506104a4565b6001016106d4565b505b60005b82518110156107705781818151811061074557610745612b65565b6020026020010151876000015110156107685760009750505050505050506104a4565b60010161072a565b505050610785565b60009450505050506104a4565b5060019695505050505050565b600061079c611600565b6001600160a01b03909216600090815260049290920160205250604090205460ff1690565b60006107cb611748565b6107d584846117b1565b90506107e0826118f9565b9392505050565b60607f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634a00cc486040518163ffffffff1660e01b8152600401600060405180830381865afa158015610847573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261086f9190810190612d74565b905090565b600061088360208501856125fd565b90504261089660e0860160c08701612f10565b6001600160801b0316111580156108c557506108b9610100850160e08601612f10565b6001600160801b031642105b6108fb5760405162461bcd60e51b8152602060048201526007602482015266085c195c9a5bd960ca1b604482015260640161014e565b600080610909868686610f3a565b91509150816109435760405162461bcd60e51b815260040161014e906020808252600490820152632173696760e01b604082015260600190565b600161094d611600565b610100880135600090815260079190910160209081526040808320805460ff191694151594909417909355909161098991908901908901612f3c565b60ff1611156109bf5760006109a46040880160208901612f3c565b60ff1660011490506109b68482611952565b50505050505050565b6109c883610792565b156109fd5760405162461bcd60e51b815260206004820152600560248201526430b236b4b760d91b604482015260640161014e565b610a1283610a09611600565b60020190611a55565b50604051806060016040528087606001358152602001876080016020810190610a3b9190612f10565b6001600160801b03168152602001610a5960c0890160a08a01612f10565b6001600160801b03169052610a6c611600565b6001600160a01b03851660009081526005919091016020908152604080832084518155918401519301516001600160801b03908116600160801b02931692909217600190920191909155610ae2610ac1611600565b6001600160a01b038616600090815260069190910160205260409020611a6a565b805190915060005b81811015610b4c57610b39838281518110610b0757610b07612b65565b6020026020010151610b17611600565b6001600160a01b03891660009081526006919091016020526040902090611a77565b50610b45600182612f6d565b9050610aea565b50610b5a6040890189612f80565b9050905060005b81811015610bdb57610bc8610b7960408b018b612f80565b83818110610b8957610b89612b65565b9050602002016020810190610b9e91906125fd565b610ba6611600565b6001600160a01b03891660009081526006919091016020526040902090611a55565b50610bd4600182612f6d565b9050610b61565b50610be588611a8c565b846001600160a01b0316836001600160a01b03167ff21d10c26e35863a8df291aca54181ee8c4a3bc8e00246c3f7a5a14b69d826a78a604051610c28919061304f565b60405180910390a35050505050505050565b600080610c45611600565b6001600160a01b038416600090815260059190910160209081526040918290208251606081018452815481526001909101546001600160801b03808216938301849052600160801b90910416928101929092529091504210801590610cb6575080604001516001600160801b031642105b80156107e057506000610ceb610cca611600565b6001600160a01b038616600090815260069190910160205260409020611624565b119392505050565b60606000610d0a610d02611600565b600201611a6a565b80519091506000805b82811015610d9b57610d3d848281518110610d3057610d30612b65565b6020026020010151610c3a565b15610d545781610d4c8161313a565b925050610d89565b6000848281518110610d6857610d68612b65565b60200260200101906001600160a01b031690816001600160a01b0316815250505b610d94600182612f6d565b9050610d13565b50806001600160401b03811115610db457610db4612b7b565b604051908082528060200260200182016040528015610ded57816020015b610dda612526565b815260200190600190039081610dd25790505b5093506000805b83811015610f325760006001600160a01b0316858281518110610e1957610e19612b65565b60200260200101516001600160a01b031614610f20576000858281518110610e4357610e43612b65565b602002602001015190506000610e57611600565b6001600160a01b038316600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a081019094529183529092508101610ec1610ac1611600565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b0316815250888580610f009061313a565b965081518110610f1257610f12612b65565b602002602001018190525050505b610f2b600182612f6d565b9050610df4565b505050505090565b600080610f50610f4986611b4f565b8585611c93565b9050610f5a611600565b6101008601356000908152600791909101602052604090205460ff16158015610f875750610f8781610792565b9150935093915050565b6060816001600160401b03811115610fab57610fab612b7b565b604051908082528060200260200182016040528015610fde57816020015b6060815260200190600190039081610fc95790505b509050336000805b848110156110ed578115611065576110433087878481811061100a5761100a612b65565b905060200281019061101c9190612b1f565b8660405160200161102f93929190613153565b604051602081830303815290604052611ced565b84828151811061105557611055612b65565b60200260200101819052506110e5565b6110c73087878481811061107b5761107b612b65565b905060200281019061108d9190612b1f565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611ced92505050565b8482815181106110d9576110d9612b65565b60200260200101819052505b600101610fe6565b50505092915050565b600080611101611d12565b546001600160a01b03169050801561111857919050565b7f000000000000000000000000000000000000000000000000000000000000000091505090565b611147611d36565b80611150611d12565b80546001600160a01b0319166001600160a01b039290921691909117905550565b600061117b6110f6565b604051631aab3f0d60e11b8152306004820152600060248201526001600160a01b0391909116906335567e1a90604401602060405180830381865afa1580156111c8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086f9190613174565b60006111f6611d74565b5460ff1690506000611206611d74565b54610100900460ff1690508015808015611223575060018360ff16105b80611242575061123230611d98565b15801561124257508260ff166001145b6112a55760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161014e565b60016112af611d74565b805460ff191660ff9290921691909117905580156112e85760016112d1611d74565b80549115156101000261ff00199092169190911790555b6113288686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611da792505050565b611330611d12565b60010181905550611342866001611952565b801561139d576000611352611d74565b80549115156101000261ff0019909216919091179055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b606060006113b4610d02611600565b8051909150806001600160401b038111156113d1576113d1612b7b565b60405190808252806020026020018201604052801561140a57816020015b6113f7612526565b8152602001906001900390816113ef5790505b50925060005b8181101561151057600083828151811061142c5761142c612b65565b602002602001015190506000611440611600565b6001600160a01b038316600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a0810190945291835290925081016114aa610ac1611600565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b03168152508684815181106114ef576114ef612b65565b602002602001018190525050506001816115099190612f6d565b9050611410565b50505090565b606061086f611523611600565b611a6a565b611530612526565b600061153a611600565b6001600160a01b038416600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a0810190945291835290925081016115c56115a4611600565b6001600160a01b038716600090815260069190910160205260409020611a6a565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b0316815250915050919050565b7f3181e78fc1b109bc611fd2406150bf06e33faa75f71cba12c3e1fd670f2def0090565b60006104a4825490565b600060048210156116515760405162461bcd60e51b815260040161014e9061318d565b61165f6004600084866131ac565b6107e0916131d6565b60006107e08383611dda565b60008060448310156116985760405162461bcd60e51b815260040161014e9061318d565b6116a66024600485876131ac565b8101906116b391906125fd565b91506116c36044602485876131ac565b8101906116d09190613206565b90509250929050565b6001600160a01b038116600090815260018301602052604081205415156107e0565b6060808060648410156117205760405162461bcd60e51b815260040161014e9061318d565b61172d84600481886131ac565b81019061173a919061333c565b919790965090945092505050565b6117506110f6565b6001600160a01b0316336001600160a01b0316146117af5760405162461bcd60e51b815260206004820152601c60248201527b1858d8dbdd5b9d0e881b9bdd08199c9bdb48115b9d1c9e541bda5b9d60221b604482015260640161014e565b565b7b0ca2ba3432b932bab69029b4b3b732b21026b2b9b9b0b3b29d05199960211b6000908152601c829052603c8120600061182f6117f2610140870187612b1f565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508693925050611e049050565b905061183b81866104ce565b61184a576001925050506104a4565b6000611854611600565b6001600160a01b03929092166000908152600590920160209081526040808420815160608082018452825482526001909201546001600160801b0380821683870152600160801b8204908116928501929092528351928301845295825265ffffffffffff8087169483019490945292831691015260d09290921b6001600160d01b03191660a09290921b65ffffffffffff60a01b169190911795945050505050565b50565b80156118f657604051600090339060001990849084818181858888f193505050503d8060008114611946576040519150601f19603f3d011682016040523d82523d6000602084013e61194b565b606091505b5050505050565b61195c8282611e28565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163b15611a51578015611a19577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630b61e12b836119ca611d12565b600101546040518363ffffffff1660e01b81526004016119eb929190613421565b600060405180830381600087803b158015611a0557600080fd5b505af115801561139d573d6000803e3d6000fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639387a380836119ca611d12565b5050565b60006107e0836001600160a01b038416611ed7565b606060006107e083611f26565b60006107e0836001600160a01b038416611f82565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163b156118f6576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016630b61e12b611af860208401846125fd565b611b00611d12565b600101546040518363ffffffff1660e01b8152600401611b21929190613421565b600060405180830381600087803b158015611b3b57600080fd5b505af115801561194b573d6000803e3d6000fd5b60607f3fd4a1a1a267c84185e3b7eecd57c68783c0581d538b9d6e5f23e4670497c1e9611b7f60208401846125fd565b611b8f6040850160208601612f3c565b611b9c6040860186612f80565b604051602001611bad92919061343a565b60408051601f1981840301815291905280516020909101206060860135611bda60a0880160808901612f10565b611bea60c0890160a08a01612f10565b611bfa60e08a0160c08b01612f10565b611c0b6101008b0160e08c01612f10565b60408051602081019a909a526001600160a01b039098169789019790975260ff9095166060880152608087019390935260a08601919091526001600160801b0390811660c086015290811660e0850152908116610100848101919091529116610120830152830135610140820152610160016040516020818303038152906040529050919050565b6000611ce583838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505087516020890120611cdf92509050612075565b90611e04565b949350505050565b60606107e0838360405180606001604052806027815260200161350f602791396120a2565b7f036f52c1827dab135f7fd44ca0bddde297e2f659c710e0ec53e975f22b54830090565b611d3f33610792565b6117af5760405162461bcd60e51b815260206004820152600660248201526510b0b236b4b760d11b604482015260640161014e565b7f322cf19c484104d3b1a9c2982ebae869ede3fa5f6c4703ca41b9a48c76ee030090565b6001600160a01b03163b151590565b60008282604051602001611dbc92919061347c565b60405160208183030381529060405280519060200120905092915050565b6000826000018281548110611df157611df1612b65565b9060005260206000200154905092915050565b6000806000611e13858561211a565b91509150611e208161215f565b509392505050565b80611e31611600565b6001600160a01b038416600090815260049190910160205260409020805460ff19169115159190911790558015611e7a57611e7482611e6e611600565b90611a55565b50611e8e565b611e8c82611e86611600565b90611a77565b505b816001600160a01b03167f235bc17e7930760029e9f4d860a2a8089976de5b381cf8380fc11c1d88a1113382604051611ecb911515815260200190565b60405180910390a25050565b6000818152600183016020526040812054611f1e575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104a4565b5060006104a4565b606081600001805480602002602001604051908101604052809291908181526020018280548015611f7657602002820191906000526020600020905b815481526020019060010190808311611f62575b50505050509050919050565b6000818152600183016020526040812054801561206b576000611fa66001836134a0565b8554909150600090611fba906001906134a0565b905081811461201f576000866000018281548110611fda57611fda612b65565b9060005260206000200154905080876000018481548110611ffd57611ffd612b65565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612030576120306134b3565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506104a4565b60009150506104a4565b60006104a46120826122a4565b8360405161190160f01b8152600281019290925260228201526042902090565b6060600080856001600160a01b0316856040516120bf91906134c9565b600060405180830381855af49150503d80600081146120fa576040519150601f19603f3d011682016040523d82523d6000602084013e6120ff565b606091505b5091509150612110868383876123cb565b9695505050505050565b60008082516041036121505760208301516040840151606085015160001a61214487828585612442565b94509450505050612158565b506000905060025b9250929050565b6000816004811115612173576121736134e5565b0361217b5750565b600181600481111561218f5761218f6134e5565b036121d75760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b604482015260640161014e565b60028160048111156121eb576121eb6134e5565b036122385760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161014e565b600381600481111561224c5761224c6134e5565b036118f65760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161014e565b6000306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480156122fd57507f000000000000000000000000000000000000000000000000000000000000000046145b1561232757507f000000000000000000000000000000000000000000000000000000000000000090565b50604080517f00000000000000000000000000000000000000000000000000000000000000006020808301919091527f0000000000000000000000000000000000000000000000000000000000000000828401527f000000000000000000000000000000000000000000000000000000000000000060608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b60608315612438578251600003612431576123e585611d98565b6124315760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161014e565b5081611ce5565b611ce583836124fc565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b0383111561246f57506000905060036124f3565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156124c3573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166124ec576000600192509250506124f3565b9150600090505b94509492505050565b81511561250c5781518083602001fd5b8060405162461bcd60e51b815260040161014e91906134fb565b6040518060a0016040528060006001600160a01b03168152602001606081526020016000815260200160006001600160801b0316815260200160006001600160801b031681525090565b6001600160a01b03811681146118f657600080fd5b803561259081612570565b919050565b600061016082840312156125a857600080fd5b50919050565b600080604083850312156125c157600080fd5b82356125cc81612570565b915060208301356001600160401b038111156125e757600080fd5b6125f385828601612595565b9150509250929050565b60006020828403121561260f57600080fd5b81356107e081612570565b60008060006060848603121561262f57600080fd5b83356001600160401b0381111561264557600080fd5b61265186828701612595565b9660208601359650604090950135949350505050565b60005b8381101561268257818101518382015260200161266a565b50506000910152565b600081518084526126a3816020860160208601612667565b601f01601f19169290920160200192915050565b60006020808301818452808551808352604092508286019150828160051b8701018488016000805b848110156127c157603f19808b86030187528351805189875280516060808c8a015261270e60a08a018361268b565b91508c830151858a840301828b0152612727838261268b565b938d01516001600160a01b031660808b0152505050908a01518682038b88015280518083529192508a01908a830190600581901b84018c01865b828110156127aa57858203601f19018452845180516001600160e01b03191683528e01518e83018e90526127978e84018261268b565b958f0195948f0194925050600101612761565b50998c0199975050509389019350506001016126df565b50919998505050505050505050565b60008083601f8401126127e257600080fd5b5081356001600160401b038111156127f957600080fd5b60208301915083602082850101111561215857600080fd5b60008060006040848603121561282657600080fd5b83356001600160401b038082111561283d57600080fd5b90850190610120828803121561285257600080fd5b9093506020850135908082111561286857600080fd5b50612875868287016127d0565b9497909650939450505050565b60008151808452602080850194506020840160005b838110156128bc5781516001600160a01b031687529582019590820190600101612897565b509495945050505050565b6001600160801b03169052565b60018060a01b0381511682526000602082015160a060208501526128fb60a0850182612882565b604084810151908601526060808501516001600160801b03908116918701919091526080948501511693909401929092525090919050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b8281101561298a57603f198886030184526129788583516128d4565b9450928501929085019060010161295c565b5092979650505050505050565b600080602083850312156129aa57600080fd5b82356001600160401b03808211156129c157600080fd5b818501915085601f8301126129d557600080fd5b8135818111156129e457600080fd5b8660208260051b85010111156129f957600080fd5b60209290920196919550909350505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b8281101561298a57603f19888603018452612a5085835161268b565b94509285019290850190600101612a34565b6001600160e01b0319811681146118f657600080fd5b600060208284031215612a8a57600080fd5b81356107e081612a62565b600080600060408486031215612aaa57600080fd5b8335612ab581612570565b925060208401356001600160401b03811115612ad057600080fd5b612875868287016127d0565b6020815260006107e06020830184612882565b6020815260006107e060208301846128d4565b600060208284031215612b1457600080fd5b81516107e081612570565b6000808335601e19843603018112612b3657600080fd5b8301803591506001600160401b03821115612b5057600080fd5b60200191503681900382131561215857600080fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715612bb357612bb3612b7b565b60405290565b604051606081016001600160401b0381118282101715612bb357612bb3612b7b565b604051601f8201601f191681016001600160401b0381118282101715612c0357612c03612b7b565b604052919050565b60006001600160401b03821115612c2457612c24612b7b565b5060051b60200190565b60006001600160401b03821115612c4757612c47612b7b565b50601f01601f191660200190565b600082601f830112612c6657600080fd5b8151612c79612c7482612c2e565b612bdb565b818152846020838601011115612c8e57600080fd5b611ce5826020830160208701612667565b600082601f830112612cb057600080fd5b81516020612cc0612c7483612c0b565b82815260059290921b84018101918181019086841115612cdf57600080fd5b8286015b84811015612d695780516001600160401b0380821115612d035760008081fd5b908801906040828b03601f1901811315612d1d5760008081fd5b612d25612b91565b87840151612d3281612a62565b8152908301519082821115612d475760008081fd5b612d558c8984870101612c55565b818901528652505050918301918301612ce3565b509695505050505050565b600060208284031215612d8657600080fd5b81516001600160401b0380821115612d9d57600080fd5b818401915084601f830112612db157600080fd5b8151612dbf612c7482612c0b565b8082825260208201915060208360051b860101925087831115612de157600080fd5b602085015b83811015612eed57805185811115612dfd57600080fd5b8601601f196040828c0382011215612e1457600080fd5b612e1c612b91565b602083015188811115612e2e57600080fd5b83016060818e0384011215612e4257600080fd5b612e4a612bb9565b9250602081015189811115612e5e57600080fd5b612e6d8e602083850101612c55565b845250604081015189811115612e8257600080fd5b612e918e602083850101612c55565b60208501525060600151612ea481612570565b806040840152508181526040830151915087821115612ec257600080fd5b612ed18c602084860101612c9f565b6020820152808652505050602083019250602081019050612de6565b50979650505050505050565b80356001600160801b038116811461259057600080fd5b600060208284031215612f2257600080fd5b6107e082612ef9565b803560ff8116811461259057600080fd5b600060208284031215612f4e57600080fd5b6107e082612f2b565b634e487b7160e01b600052601160045260246000fd5b808201808211156104a4576104a4612f57565b6000808335601e19843603018112612f9757600080fd5b8301803591506001600160401b03821115612fb157600080fd5b6020019150600581901b360382131561215857600080fd5b6000808335601e19843603018112612fe057600080fd5b83016020810192503590506001600160401b03811115612fff57600080fd5b8060051b360382131561215857600080fd5b8183526000602080850194508260005b858110156128bc57813561303481612570565b6001600160a01b031687529582019590820190600101613021565b602081526130706020820161306384612585565b6001600160a01b03169052565b600061307e60208401612f2b565b60ff81166040840152506130956040840184612fc9565b6101208060608601526130ad61014086018385613011565b9250606086013560808601526130c560808701612ef9565b91506130d460a08601836128c7565b6130e060a08701612ef9565b91506130ef60c08601836128c7565b6130fb60c08701612ef9565b915061310a60e08601836128c7565b61311660e08701612ef9565b9150610100613127818701846128c7565b9590950135939094019290925250919050565b60006001820161314c5761314c612f57565b5060010190565b8284823760609190911b6001600160601b0319169101908152601401919050565b60006020828403121561318657600080fd5b5051919050565b602080825260059082015264214461746160d81b604082015260600190565b600080858511156131bc57600080fd5b838611156131c957600080fd5b5050820193919092039150565b6001600160e01b031981358181169160048510156131fe5780818660040360031b1b83161692505b505092915050565b60006020828403121561321857600080fd5b5035919050565b600082601f83011261323057600080fd5b81356020613240612c7483612c0b565b8083825260208201915060208460051b87010193508684111561326257600080fd5b602086015b84811015612d695780358352918301918301613267565b600082601f83011261328f57600080fd5b8135602061329f612c7483612c0b565b82815260059290921b840181019181810190868411156132be57600080fd5b8286015b84811015612d695780356001600160401b038111156132e15760008081fd5b8701603f810189136132f35760008081fd5b848101356040613305612c7483612c2e565b8281528b8284860101111561331a5760008081fd5b82828501898301376000928101880192909252508452509183019183016132c2565b60008060006060848603121561335157600080fd5b83356001600160401b038082111561336857600080fd5b818601915086601f83011261337c57600080fd5b8135602061338c612c7483612c0b565b82815260059290921b8401810191818101908a8411156133ab57600080fd5b948201945b838610156133d25785356133c381612570565b825294820194908201906133b0565b975050870135925050808211156133e857600080fd5b6133f48783880161321f565b9350604086013591508082111561340a57600080fd5b506134178682870161327e565b9150509250925092565b6001600160a01b03929092168252602082015260400190565b60008184825b8581101561347157813561345381612570565b6001600160a01b031683526020928301929190910190600101613440565b509095945050505050565b6001600160a01b0383168152604060208201819052600090611ce59083018461268b565b818103818111156104a4576104a4612f57565b634e487b7160e01b600052603160045260246000fd5b600082516134db818460208701612667565b9190910192915050565b634e487b7160e01b600052602160045260246000fd5b6020815260006107e0602083018461268b56fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122055c7ac679e117964ab4e3ff4448918e749659848bbe88b20fd0a9bd2116d360564736f6c63430008170033000000000000000000000000e00f80aab91e6f3526cfe90ce608dd0dd49d9ad10000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000cd68591e4f9fa55c4a9938a5574e22517047a05500000000000000000000000000000000000000000000000000000000000000104163636f756e74457874656e73696f6e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d4e5132646a543275346d793578704b50674a4d6e5145706f4e6a595a45387567704c6e647667454a4262335800000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004a0000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000005a0000000000000000000000000000000000000000000000000000000000000062000000000000000000000000000000000000000000000000000000000000006a0000000000000000000000000000000000000000000000000000000000000072000000000000000000000000000000000000000000000000000000000000007a0000000000000000000000000000000000000000000000000000000000000082000000000000000000000000000000000000000000000000000000000000008a000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000aa00000000000000000000000000000000000000000000000000000000000000b200000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000d604a58db19000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000c6164644465706f73697428290000000000000000000000000000000000000000e8a3d485000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000d636f6e7472616374555249282900000000000000000000000000000000000000b61d27f6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e6578656375746528616464726573732c75696e743235362c627974657329000047e1da2a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002965786563757465426174636828616464726573735b5d2c75696e743235365b5d2c62797465735b5d2900000000000000000000000000000000000000000000008b52d7230000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000015676574416c6c4163746976655369676e65727328290000000000000000000000e9523c97000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000e676574416c6c41646d696e732829000000000000000000000000000000000000d42f2f35000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000f676574416c6c5369676e65727328290000000000000000000000000000000000399b77da00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000176765744d65737361676548617368286279746573333229000000000000000000f15d424e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000206765745065726d697373696f6e73466f725369676e65722861646472657373297dff5a79000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001769734163746976655369676e657228616464726573732900000000000000000024d7806c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000010697341646d696e286164647265737329000000000000000000000000000000001626ba7e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001f697356616c69645369676e617475726528627974657333322c62797465732900bc197c8100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000416f6e455243313135354261746368526563656976656428616464726573732c616464726573732c75696e743235365b5d2c75696e743235365b5d2c62797465732900000000000000000000000000000000000000000000000000000000000000f23a6e6100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000386f6e45524331313535526563656976656428616464726573732c616464726573732c75696e743235362c75696e743235362c6279746573290000000000000000150b7a02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002f6f6e455243373231526563656976656428616464726573732c616464726573732c75696e743235362c6279746573290000000000000000000000000000000000938e3d7b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000016736574436f6e747261637455524928737472696e6729000000000000000000005892e23600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000687365745065726d697373696f6e73466f725369676e65722828616464726573732c75696e74382c616464726573735b5d2c75696e743235362c75696e743132382c75696e743132382c75696e743132382c75696e743132382c62797465733332292c62797465732900000000000000000000000000000000000000000000000001ffc9a70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000019737570706f727473496e74657266616365286279746573342900000000000000a9082d84000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000006e7665726966795369676e65725065726d697373696f6e526571756573742828616464726573732c75696e74382c616464726573735b5d2c75696e743235362c75696e743132382c75696e743132382c75696e743132382c75696e743132382c62797465733332292c6279746573290000000000000000000000000000000000004d44560d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002277697468647261774465706f736974546f28616464726573732c75696e7432353629000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106101a45760003560e01c80639387a380116100e85780639387a380146104ad578063938e3d7b146104cd578063a0dbaefd146104ed578063a217fddf1461051a578063a32fa5b31461052f578063a65d69d41461054f578063ac9650d814610583578063c0562f6d146105b0578063c22707ee146105d0578063c3c5a547146105fd578063ca15c8731461061d578063ce0b60131461063d578063d547741f1461065d578063d8fd8f441461067d578063e05688fe1461069d578063e68a7c3b146106bd578063e8a3d485146106dd578063ee7d2adf146106ff576101a4565b806308e93d0a1461022d5780630b61e12b146102585780630e6254fd1461027857806311464fbe14610298578063248a9ca3146102e45780632f2ff15d1461031257806336568abe14610332578063429eed8014610352578063463c4864146103725780634a00cc48146103a6578063512cf914146103c857806358451f97146103e857806383a03f8c146103fd5780638856a1131461041d5780638878ed331461043d5780639010d07c1461045d57806391d148541461047d575b366000036101ae57005b60006101c56000356001600160e01b03191661071f565b90506001600160a01b0381166102225760405162461bcd60e51b815260206004820181905260248201527f526f757465723a2066756e6374696f6e20646f6573206e6f742065786973742e60448201526064015b60405180910390fd5b61022b81610734565b005b34801561023957600080fd5b5061024261075d565b60405161024f9190613d38565b60405180910390f35b34801561026457600080fd5b5061022b610273366004613da1565b61076e565b34801561028457600080fd5b50610242610293366004613dcb565b610806565b3480156102a457600080fd5b506102cc7f0000000000000000000000002235dd3f8f8bfbe49603328bc68b416b5c320d6d81565b6040516001600160a01b03909116815260200161024f565b3480156102f057600080fd5b506103046102ff366004613de6565b610830565b60405190815260200161024f565b34801561031e57600080fd5b5061022b61032d366004613dff565b61084e565b34801561033e57600080fd5b5061022b61034d366004613dff565b6108f8565b34801561035e57600080fd5b5061022b61036d366004613f42565b610957565b34801561037e57600080fd5b506102cc7f0000000000000000000000006b877ebb33bd24a963ee4e4c044d75707b964cdb81565b3480156103b257600080fd5b506103bb610bce565b60405161024f91906140c5565b3480156103d457600080fd5b5061022b6103e3366004613f42565b610c9d565b3480156103f457600080fd5b50610304610ccb565b34801561040957600080fd5b5061022b610418366004613de6565b610cd7565b34801561042957600080fd5b5061022b610438366004614181565b610d25565b34801561044957600080fd5b506102cc6104583660046141e4565b610d53565b34801561046957600080fd5b506102cc610478366004614266565b610dcd565b34801561048957600080fd5b5061049d610498366004613dff565b610edb565b604051901515815260200161024f565b3480156104b957600080fd5b5061022b6104c8366004613da1565b610f0f565b3480156104d957600080fd5b5061022b6104e8366004614288565b610fa6565b3480156104f957600080fd5b5061050d6105083660046142bc565b610ff7565b60405161024f91906142d7565b34801561052657600080fd5b50610304600081565b34801561053b57600080fd5b5061049d61054a366004613dff565b61116d565b34801561055b57600080fd5b506102cc7f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278981565b34801561058f57600080fd5b506105a361059e3660046142ea565b6111d0565b60405161024f919061435e565b3480156105bc57600080fd5b5061022b6105cb366004614453565b61132c565b3480156105dc57600080fd5b506105f06105eb366004614288565b611359565b60405161024f9190614544565b34801561060957600080fd5b5061049d610618366004613dcb565b61136a565b34801561062957600080fd5b50610304610638366004613de6565b611376565b34801561064957600080fd5b506102cc6106583660046142bc565b61071f565b34801561066957600080fd5b5061022b610678366004613dff565b611413565b34801561068957600080fd5b506102cc6106983660046141e4565b61141e565b3480156106a957600080fd5b5061022b6106b8366004614453565b611569565b3480156106c957600080fd5b506102426106d8366004614266565b611596565b3480156106e957600080fd5b506106f26116c7565b60405161024f9190614557565b34801561070b57600080fd5b5061022b61071a366004614288565b61175f565b600061072a82610ff7565b6040015192915050565b3660008037600080366000845af43d6000803e808015610753573d6000f35b3d6000fd5b505050565b6060610769600061178c565b905090565b336107798183611799565b6107955760405162461bcd60e51b81526004016102199061456a565b6001600160a01b03831660009081526002602052604081206107b790836117dd565b9050801561080057836001600160a01b0316826001600160a01b03167f12146497b3b826918ec47f0cac7272a09ed06b30c16c030e99ec48ff5dd60b4760405160405180910390a35b50505050565b6001600160a01b038116600090815260026020526040902060609061082a9061178c565b92915050565b600061083a6117f2565b600092835260010160205250604090205490565b6108726108596117f2565b6000848152600191909101602052604090205433611816565b61087a6117f2565b6000838152602091825260408082206001600160a01b0385168352909252205460ff16156108ea5760405162461bcd60e51b815260206004820152601d60248201527f43616e206f6e6c79206772616e7420746f206e6f6e20686f6c646572730000006044820152606401610219565b6108f4828261189b565b5050565b336001600160a01b0382161461094d5760405162461bcd60e51b815260206004820152601a60248201527921b0b71037b7363c903932b737bab731b2903337b91039b2b63360311b6044820152606401610219565b6108f482826118af565b61095f6118c3565b61097b5760405162461bcd60e51b8152600401610219906145a1565b61098582826118ef565b6109f25760405162461bcd60e51b815260206004820152603860248201527f457874656e73696f6e4d616e616765723a2063616e6e6f742072656d6f766520604482015277333ab731ba34b7b710333937b69032bc3a32b739b4b7b71760411b6064820152608401610219565b60006109fc6119ee565b6001600160e01b031983166000908152600391909101602052604090819020815160608101909252805482908290610a33906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054610a5f906145d8565b8015610aac5780601f10610a8157610100808354040283529160200191610aac565b820191906000526020600020905b815481529060010190602001808311610a8f57829003601f168201915b50505050508152602001600182018054610ac5906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054610af1906145d8565b8015610b3e5780601f10610b1357610100808354040283529160200191610b3e565b820191906000526020600020905b815481529060010190602001808311610b2157829003601f168201915b5050509183525050600291909101546001600160a01b03166020909101529050610b6883836119f8565b610b7182611cc5565b816001600160e01b03191683604051610b8a919061460c565b60405180910390207fbb931a9651175c9c82f86afbf6ad37a9141aa8d1d42bf798739be245a12e4e8883604051610bc191906142d7565b60405180910390a3505050565b60606000610be2610bdd6119ee565b611d18565b8051909150806001600160401b03811115610bff57610bff613e2b565b604051908082528060200260200182016040528015610c3857816020015b610c25613c4f565b815260200190600190039081610c1d5790505b50925060005b81811015610c9757610c68838281518110610c5b57610c5b614628565b6020026020010151611d23565b848281518110610c7a57610c7a614628565b6020908102919091010152610c90600182614654565b9050610c3e565b50505090565b610ca56118c3565b610cc15760405162461bcd60e51b8152600401610219906145a1565b6108f48282610957565b60006107696000611fac565b33610ce28183611799565b610cfe5760405162461bcd60e51b81526004016102199061456a565b610d096000826117dd565b6108f45760405162461bcd60e51b815260040161021990614667565b610d2d6118c3565b610d495760405162461bcd60e51b8152600401610219906145a1565b6108f48282611fb6565b600080610d968585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061220592505050565b9050610dc27f0000000000000000000000002235dd3f8f8bfbe49603328bc68b416b5c320d6d82612238565b9150505b9392505050565b600080610dd8612298565b600085815260209190915260408120549150805b82811015610ed2576000610dfe612298565b60008881526020918252604080822085835260010190925220546001600160a01b031614610e7657848203610e6457610e35612298565b600087815260209182526040808220938252600190930190915220546001600160a01b0316925061082a915050565b610e6f600183614654565b9150610ec0565b610e81866000610edb565b8015610ead5750610e90612298565b600087815260209182526040808220828052600201909252205481145b15610ec057610ebd600183614654565b91505b610ecb600182614654565b9050610dec565b50505092915050565b6000610ee56117f2565b6000938452602090815260408085206001600160a01b039490941685529290525090205460ff1690565b33610f1a8183611799565b610f365760405162461bcd60e51b81526004016102199061456a565b6001600160a01b0383166000908152600260205260408120610f5890836122a2565b9050801561080057836001600160a01b0316826001600160a01b03167f98d1ebbe00ae92a5de96a0f49742a8afa89f42363592bc2e7cfaaed68b45e7a660405160405180910390a350505050565b610fae6122b7565b610feb5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606401610219565b610ff4816122c3565b50565b610fff613c6f565b6110076119ee565b6001600160e01b03198316600090815260039190910160205260409081902081516060810190925280548290829061103e906145d8565b80601f016020809104026020016040519081016040528092919081815260200182805461106a906145d8565b80156110b75780601f1061108c576101008083540402835291602001916110b7565b820191906000526020600020905b81548152906001019060200180831161109a57829003601f168201915b505050505081526020016001820180546110d0906145d8565b80601f01602080910402602001604051908101604052809291908181526020018280546110fc906145d8565b80156111495780601f1061111e57610100808354040283529160200191611149565b820191906000526020600020905b81548152906001019060200180831161112c57829003601f168201915b5050509183525050600291909101546001600160a01b031660209091015292915050565b60006111776117f2565b600084815260209182526040808220828052909252205460ff166111c75761119d6117f2565b6000848152602091825260408082206001600160a01b0386168352909252205460ff16905061082a565b50600192915050565b6060816001600160401b038111156111ea576111ea613e2b565b60405190808252806020026020018201604052801561121d57816020015b60608152602001906001900390816112085790505b509050336000805b84811015610ed25781156112a4576112823087878481811061124957611249614628565b905060200281019061125b91906146b1565b8660405160200161126e939291906146fe565b6040516020818303038152906040526123aa565b84828151811061129457611294614628565b6020026020010181905250611324565b611306308787848181106112ba576112ba614628565b90506020028101906112cc91906146b1565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506123aa92505050565b84828151811061131857611318614628565b60200260200101819052505b600101611225565b6113346118c3565b6113505760405162461bcd60e51b8152600401610219906145a1565b610ff4816123cf565b611361613c4f565b61082a82611d23565b600061082a8183612538565b600080611381612298565b6000848152602091909152604081205491505b818110156113ee5760006113a6612298565b60008681526020918252604080822085835260010190925220546001600160a01b0316146113dc576113d9600184614654565b92505b6113e7600182614654565b9050611394565b506113fa836000610edb565b1561140d5761140a600183614654565b91505b50919050565b61094d6108596117f2565b6000807f0000000000000000000000002235dd3f8f8bfbe49603328bc68b416b5c320d6d905060006114868686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061220592505050565b905060006114948383612238565b90506001600160a01b0381163b156114b0579250610dc6915050565b6114ba838361255a565b9050336001600160a01b037f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d27891614611513576114f76000826117dd565b6115135760405162461bcd60e51b815260040161021990614667565b61151f818888886125f1565b866001600160a01b0316816001600160a01b03167fac631f3001b55ea1509cf3d7e74898f85392a61a76e8149181ae1259622dabc860405160405180910390a39695505050505050565b6115716118c3565b61158d5760405162461bcd60e51b8152600401610219906145a1565b610ff481612659565b606081831080156115b057506115ac6000611fac565b8211155b6116085760405162461bcd60e51b815260206004820152602360248201527f426173654163636f756e74466163746f72793a20696e76616c696420696e646960448201526263657360e81b6064820152608401610219565b6000611614848461471f565b9050611620848461471f565b6001600160401b0381111561163757611637613e2b565b604051908082528060200260200182016040528015611660578160200160208202803683370190505b50915060005b818110156116bf5761168361167b8683614654565b600090612783565b83828151811061169557611695614628565b6001600160a01b03909216602092830291909101909101526116b8600182614654565b9050611666565b505092915050565b60606116d161278f565b80546116dc906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611708906145d8565b80156117555780601f1061172a57610100808354040283529160200191611755565b820191906000526020600020905b81548152906001019060200180831161173857829003601f168201915b5050505050905090565b6117676118c3565b6117835760405162461bcd60e51b8152600401610219906145a1565b610ff4816127b3565b60606000610dc683612afd565b6000806117c67f0000000000000000000000002235dd3f8f8bfbe49603328bc68b416b5c320d6d84612238565b6001600160a01b0385811691161491505092915050565b6000610dc6836001600160a01b038416612b59565b7f0a7b0f5c59907924802379ebe98cdc23e2ee7820f63d30126e10b3752010e50090565b61181e6117f2565b6000838152602091825260408082206001600160a01b0385168352909252205460ff166108f457611859816001600160a01b03166014612ba8565b611864836020612ba8565b604051602001611875929190614732565b60408051601f198184030181529082905262461bcd60e51b825261021991600401614557565b6118a58282612d43565b6108f48282612dac565b6118b98282612e6b565b6108f48282612ed4565b60006107697f55add213c41f3851b4506717b8af695a4256979dff496dcaae7789f6121331aa33610edb565b6000611903836118fd6119ee565b90612f63565b61191f5760405162461bcd60e51b81526004016102199061479f565b826040516020016119309190614557565b6040516020818303038152906040528051906020012061194e6119ee565b6001600160e01b0319841660009081526003919091016020908152604091829020915161197c9291016147ea565b60405160208183030381529060405280519060200120146111c75760405162461bcd60e51b815260206004820152602660248201527f457874656e73696f6e4d616e616765723a20696e636f727265637420657874656044820152653739b4b7b71760d11b6064820152608401610219565b6000610769612f6f565b6000611a026119ee565b60020183604051611a13919061460c565b9081526020016040518091039020600301805480602002602001604051908101604052809291908181526020016000905b82821015611b215760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b03191682526001810180549293919291840191611a90906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611abc906145d8565b8015611b095780601f10611ade57610100808354040283529160200191611b09565b820191906000526020600020905b815481529060010190602001808311611aec57829003601f168201915b50505050508152505081526020019060010190611a44565b5050825192935060009150505b81811015611cbe57836001600160e01b031916838281518110611b5357611b53614628565b6020026020010151600001516001600160e01b03191603611cac57611b766119ee565b60020185604051611b87919061460c565b908152604051908190036020019020600301611ba460018461471f565b81548110611bb457611bb4614628565b9060005260206000209060020201611bca6119ee565b60020186604051611bdb919061460c565b90815260200160405180910390206003018281548110611bfd57611bfd614628565b600091825260209091208254600290920201805463ffffffff191663ffffffff909216919091178155600180820190611c38908401826148d7565b50905050611c446119ee565b60020185604051611c55919061460c565b9081526020016040518091039020600301805480611c7557611c756149ad565b600082815260208120600260001990930192830201805463ffffffff1916815590611ca36001830182613c99565b50509055611cbe565b611cb7600182614654565b9050611b2e565b5050505050565b611ccd6119ee565b6001600160e01b0319821660009081526003919091016020526040812090611cf58282613c99565b611d03600183016000613c99565b5060020180546001600160a01b031916905550565b606061082a82612fcd565b611d2b613c4f565b611d336119ee565b60020182604051611d44919061460c565b9081526040805191829003602001822060a08301825280549091839190820190839082908290611d73906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611d9f906145d8565b8015611dec5780601f10611dc157610100808354040283529160200191611dec565b820191906000526020600020905b815481529060010190602001808311611dcf57829003601f168201915b50505050508152602001600182018054611e05906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611e31906145d8565b8015611e7e5780601f10611e5357610100808354040283529160200191611e7e565b820191906000526020600020905b815481529060010190602001808311611e6157829003601f168201915b5050509183525050600291909101546001600160a01b03166020918201529082526003830180546040805182850281018501909152818152938301939260009084015b82821015611f9e5760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b03191682526001810180549293919291840191611f0d906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611f39906145d8565b8015611f865780601f10611f5b57610100808354040283529160200191611f86565b820191906000526020600020905b815481529060010190602001808311611f6957829003601f168201915b50505050508152505081526020019060010190611ec1565b505050915250909392505050565b600061082a825490565b611fc082826130aa565b61202c5760405162461bcd60e51b815260206004820152603760248201527f457874656e73696f6e4d616e616765723a2063616e6e6f742053746f72653a20604482015276333ab731ba34b7b7103337b91032bc3a32b739b4b7b71760491b6064820152608401610219565b61203682826130d4565b60006120406119ee565b60020183604051612051919061460c565b9081526040805191829003602001822060608301909152805482908290612077906145d8565b80601f01602080910402602001604051908101604052809291908181526020018280546120a3906145d8565b80156120f05780601f106120c5576101008083540402835291602001916120f0565b820191906000526020600020905b8154815290600101906020018083116120d357829003601f168201915b50505050508152602001600182018054612109906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054612135906145d8565b80156121825780601f1061215757610100808354040283529160200191612182565b820191906000526020600020905b81548152906001019060200180831161216557829003601f168201915b5050509183525050600291909101546001600160a01b031660209091015282519091506121af9082613322565b81600001516001600160e01b031916836040516121cc919061460c565b60405180910390207f681115194e519bda23de4da5218f3bc38f5585eab7c6b7d5fa66caa4602f574d8484604051610bc19291906149c3565b6000828260405160200161221a9291906149e8565b60405160208183030381529060405280519060200120905092915050565b6040513060388201526f5af43d82803e903d91602b57fd5bf3ff602482015260148101839052733d602d80600a3d3981f3363d3d373d3d3d363d738152605881018290526037600c82012060788201526055604390910120600090610dc6565b6000610769613399565b6000610dc6836001600160a01b0384166133fb565b60006107698133610edb565b60006122cd61278f565b80546122d8906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054612304906145d8565b80156123515780601f1061232657610100808354040283529160200191612351565b820191906000526020600020905b81548152906001019060200180831161233457829003601f168201915b505050505090508161236161278f565b9061236c9082614a0c565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a16818360405161239e929190614abd565b60405180910390a15050565b6060610dc68383604051806060016040528060278152602001614b51602791396134ee565b6123d881613566565b6124385760405162461bcd60e51b815260206004820152602b60248201527f457874656e73696f6e4d616e616765723a2063616e6e6f74207265706c61636560448201526a1032bc3a32b739b4b7b71760a91b6064820152608401610219565b805180516124459161361a565b80515161245190613651565b60208101515160005b818110156124d2576124918360000151600001518460200151838151811061248457612484614628565b60200260200101516130d4565b6124c0836020015182815181106124aa576124aa614628565b6020026020010151600001518460000151613322565b6124cb600182614654565b905061245a565b508151604080820151915190516001600160a01b03909216916124f5919061460c565b60405180910390207f5f1ef2b136db521971a88818ce904a8e310082338afdc100212a3127066421588460405161252c9190614544565b60405180910390a35050565b6001600160a01b03811660009081526001830160205260408120541515610dc6565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b03811661082a5760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b6044820152606401610219565b60405163347d5e2560e21b81526001600160a01b0385169063d1f578949061262190869086908690600401614ae2565b600060405180830381600087803b15801561263b57600080fd5b505af115801561264f573d6000803e3d6000fd5b5050505050505050565b612662816137fa565b6126be5760405162461bcd60e51b815260206004820152602760248201527f457874656e73696f6e4d616e616765723a2063616e6e6f74206164642065787460448201526632b739b4b7b71760c91b6064820152608401610219565b805180516126cb9161361a565b60208101515160005b81811015612729576126fe8360000151600001518460200151838151811061248457612484614628565b612717836020015182815181106124aa576124aa614628565b612722600182614654565b90506126d4565b508151604080820151915190516001600160a01b039092169161274c919061460c565b60405180910390207fbb37a605de78ba6bc667aeaf438d0aae8247e6f48a8fad23730e4fbbb480abf38460405161252c9190614544565b6000610dc683836138c2565b7f4bc804ba64359c0e35e5ed5d90ee596ecaa49a3a930ddcb1470ea0dd625da90090565b6127bc816138ec565b61281b5760405162461bcd60e51b815260206004820152602a60248201527f457874656e73696f6e4d616e616765723a2063616e6e6f742072656d6f76652060448201526932bc3a32b739b4b7b71760b11b6064820152608401610219565b60006128256119ee565b60020182604051612836919061460c565b9081526040805191829003602001822060a08301825280549091839190820190839082908290612865906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054612891906145d8565b80156128de5780601f106128b3576101008083540402835291602001916128de565b820191906000526020600020905b8154815290600101906020018083116128c157829003601f168201915b505050505081526020016001820180546128f7906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054612923906145d8565b80156129705780601f1061294557610100808354040283529160200191612970565b820191906000526020600020905b81548152906001019060200180831161295357829003601f168201915b5050509183525050600291909101546001600160a01b03166020918201529082526003830180546040805182850281018501909152818152938301939260009084015b82821015612a905760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b031916825260018101805492939192918401916129ff906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054612a2b906145d8565b8015612a785780601f10612a4d57610100808354040283529160200191612a78565b820191906000526020600020905b815481529060010190602001808311612a5b57829003601f168201915b505050505081525050815260200190600101906129b3565b50505050815250509050612aa38261391c565b612aac82613651565b81604051612aba919061460c565b60405180910390207f3169a23cec9ad1a25ab59bbe00ecf8973dd840c745775ea8877041ef5ce65bcc82604051612af19190614544565b60405180910390a25050565b606081600001805480602002602001604051908101604052809291908181526020018280548015612b4d57602002820191906000526020600020905b815481526020019060010190808311612b39575b50505050509050919050565b6000818152600183016020526040812054612ba05750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561082a565b50600061082a565b60606000612bb7836002614b22565b612bc2906002614654565b6001600160401b03811115612bd957612bd9613e2b565b6040519080825280601f01601f191660200182016040528015612c03576020820181803683370190505b509050600360fc1b81600081518110612c1e57612c1e614628565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110612c4d57612c4d614628565b60200101906001600160f81b031916908160001a9053506000612c71846002614b22565b612c7c906001614654565b90505b6001811115612cf4576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110612cb057612cb0614628565b1a60f81b828281518110612cc657612cc6614628565b60200101906001600160f81b031916908160001a90535060049490941c93612ced81614b39565b9050612c7f565b508315610dc65760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610219565b6001612d4d6117f2565b6000848152602091825260408082206001600160a01b0386168084529352808220805460ff1916941515949094179093559151339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b6000612db6612298565b6000848152602091909152604090205490506001612dd2612298565b6000858152602091909152604081208054909190612df1908490614654565b90915550829050612e00612298565b6000858152602091825260408082208583526001019092522080546001600160a01b0319166001600160a01b039290921691909117905580612e40612298565b6000948552602090815260408086206001600160a01b03909516865260029094019052919092205550565b612e758282611816565b612e7d6117f2565b6000838152602091825260408082206001600160a01b0385168084529352808220805460ff191690555133929185917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000612ede612298565b6000848152602091825260408082206001600160a01b038616835260020190925220549050612f0b612298565b6000848152602091825260408082208483526001019092522080546001600160a01b0319169055612f3a612298565b6000938452602090815260408085206001600160a01b0390941685526002909301905250812055565b6000610dc68383613950565b600080612f9d60017f775b9fab5634a62bb2a682c067408edbed43efd726183d2e2af744334d47acb761471f565b604051602001612faf91815260200190565b60408051601f19818403018152919052805160209091012092915050565b606081600001805480602002602001604051908101604052809291908181526020016000905b8282101561309f578382906000526020600020018054613012906145d8565b80601f016020809104026020016040519081016040528092919081815260200182805461303e906145d8565b801561308b5780601f106130605761010080835404028352916020019161308b565b820191906000526020600020905b81548152906001019060200180831161306e57829003601f168201915b505050505081526020019060010190612ff3565b505050509050919050565b60006130b8836118fd6119ee565b6111c75760405162461bcd60e51b81526004016102199061479f565b80516000906001600160e01b03191661315e576040516020016131149060208082526009908201526872656365697665282960b81b604082015260600190565b60405160208183030381529060405280519060200120826020015160405160200161313f9190614557565b60405160208183030381529060405280519060200120141590506131a5565b602080830151604051613171920161460c565b604051602081830303815290604052805190602001206001600160e01b03191682600001516001600160e01b031916141590505b80156132115760405162461bcd60e51b815260206004820152603560248201527f457874656e73696f6e4d616e616765723a20666e2073656c6563746f7220616e604482015274321039b4b3b730ba3ab9329036b4b9b6b0ba31b41760591b6064820152608401610219565b600061321b6119ee565b83516001600160e01b031916600090815260039190910160205260409020600201546001600160a01b0316146132ab5760405162461bcd60e51b815260206004820152602f60248201527f457874656e73696f6e4d616e616765723a2066756e6374696f6e20696d706c2060448201526e30b63932b0b23c9032bc34b9ba399760891b6064820152608401610219565b6132b36119ee565b600201836040516132c4919061460c565b908152604051602091819003820190206003018054600180820183556000928352918390208551600290920201805463ffffffff191660e09290921c9190911781559184015184929182019061331a9082614a0c565b505050505050565b8061332b6119ee565b6001600160e01b03198416600090815260039190910160205260409020815181906133569082614a0c565b506020820151600182019061336b9082614a0c565b5060409190910151600290910180546001600160a01b0319166001600160a01b039092169190911790555050565b60008060ff196133ca60017f0c4ba382c0009cf238e4c1ca1a52f51c61e6248a70bdfb34e5ed49d5578a5c0c61471f565b6040516020016133dc91815260200190565b60408051601f1981840301815291905280516020909101201692915050565b600081815260018301602052604081205480156134e457600061341f60018361471f565b85549091506000906134339060019061471f565b905081811461349857600086600001828154811061345357613453614628565b906000526020600020015490508087600001848154811061347657613476614628565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806134a9576134a96149ad565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061082a565b600091505061082a565b6060600080856001600160a01b03168560405161350b919061460c565b600060405180830381855af49150503d8060008114613546576040519150601f19603f3d011682016040523d82523d6000602084013e61354b565b606091505b509150915061355c8683838761397d565b9695505050505050565b805151600090613578906118fd6119ee565b6135945760405162461bcd60e51b81526004016102199061479f565b8151604001516001600160a01b03166136125760405162461bcd60e51b815260206004820152603a60248201527f457874656e73696f6e4d616e616765723a20616464696e6720657874656e736960448201527937b7103bb4ba3437baba1034b6b83632b6b2b73a30ba34b7b71760311b6064820152608401610219565b506001919050565b806136236119ee565b60020183604051613634919061460c565b908152604051908190036020019020815181906133569082614a0c565b600061365b6119ee565b6002018260405161366c919061460c565b9081526020016040518091039020600301805480602002602001604051908101604052809291908181526020016000905b8282101561377a5760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b031916825260018101805492939192918401916136e9906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054613715906145d8565b80156137625780601f1061373757610100808354040283529160200191613762565b820191906000526020600020905b81548152906001019060200180831161374557829003601f168201915b5050505050815250508152602001906001019061369d565b5050505090506137886119ee565b60020182604051613799919061460c565b908152602001604051809103902060030160006137b69190613cd3565b60005b8151811015610758576137e88282815181106137d7576137d7614628565b602002602001015160000151611cc5565b6137f3600182614654565b90506137b9565b8051515160009061384d5760405162461bcd60e51b815260206004820152601d60248201527f457874656e73696f6e4d616e616765723a20656d707479206e616d652e0000006044820152606401610219565b8151516138629061385c6119ee565b906139fe565b6135945760405162461bcd60e51b815260206004820152602b60248201527f457874656e73696f6e4d616e616765723a20657874656e73696f6e20616c726560448201526a30b23c9032bc34b9ba399760a91b6064820152608401610219565b60008260000182815481106138d9576138d9614628565b9060005260206000200154905092915050565b6000613900826138fa6119ee565b90613a0a565b6136125760405162461bcd60e51b81526004016102199061479f565b6139246119ee565b60020181604051613935919061460c565b9081526040519081900360200190206000611cf58282613c99565b60008260010182604051613964919061460c565b9081526040519081900360200190205415159392505050565b606083156139ec5782516000036139e5576001600160a01b0385163b6139e55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610219565b50816139f6565b6139f68383613a16565b949350505050565b6000610dc68383613a40565b6000610dc68383613a9a565b815115613a265781518083602001fd5b8060405162461bcd60e51b81526004016102199190614557565b6000613a4c8383613950565b612ba057825460018101845560008481526020902001613a6c8382614a0c565b5082546040516001850190613a8290859061460c565b9081526040519081900360200190205550600161082a565b6000808360010183604051613aaf919061460c565b9081526020016040518091039020549050806000146134e4576000613ad560018361471f565b8554909150600090613ae99060019061471f565b9050818114613bf0576000866000018281548110613b0957613b09614628565b906000526020600020018054613b1e906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054613b4a906145d8565b8015613b975780601f10613b6c57610100808354040283529160200191613b97565b820191906000526020600020905b815481529060010190602001808311613b7a57829003601f168201915b5050505050905080876000018481548110613bb457613bb4614628565b906000526020600020019081613bca9190614a0c565b50838760010182604051613bde919061460c565b90815260405190819003602001902055505b8554869080613c0157613c016149ad565b600190038181906000526020600020016000613c1d9190613c99565b90558560010185604051613c31919061460c565b9081526020016040518091039020600090556001935050505061082a565b6040518060400160405280613c62613c6f565b8152602001606081525090565b6040518060600160405280606081526020016060815260200160006001600160a01b031681525090565b508054613ca5906145d8565b6000825580601f10613cb5575050565b601f016020900490600052602060002090810190610ff49190613cf4565b5080546000825560020290600052602060002090810190610ff49190613d0d565b5b80821115613d095760008155600101613cf5565b5090565b80821115613d0957805463ffffffff191681556000613d2f6001830182613c99565b50600201613d0d565b6020808252825182820181905260009190848201906040850190845b81811015613d795783516001600160a01b031683529284019291840191600101613d54565b50909695505050505050565b80356001600160a01b0381168114613d9c57600080fd5b919050565b60008060408385031215613db457600080fd5b613dbd83613d85565b946020939093013593505050565b600060208284031215613ddd57600080fd5b610dc682613d85565b600060208284031215613df857600080fd5b5035919050565b60008060408385031215613e1257600080fd5b82359150613e2260208401613d85565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715613e6357613e63613e2b565b60405290565b604051606081016001600160401b0381118282101715613e6357613e63613e2b565b604051601f8201601f191681016001600160401b0381118282101715613eb357613eb3613e2b565b604052919050565b600082601f830112613ecc57600080fd5b81356001600160401b03811115613ee557613ee5613e2b565b613ef8601f8201601f1916602001613e8b565b818152846020838601011115613f0d57600080fd5b816020850160208301376000918101602001919091529392505050565b80356001600160e01b031981168114613d9c57600080fd5b60008060408385031215613f5557600080fd5b82356001600160401b03811115613f6b57600080fd5b613f7785828601613ebb565b925050613e2260208401613f2a565b60005b83811015613fa1578181015183820152602001613f89565b50506000910152565b60008151808452613fc2816020860160208601613f86565b601f01601f19169290920160200192915050565b6000815160608452613feb6060850182613faa565b9050602083015184820360208601526140048282613faa565b6040948501516001600160a01b03169590940194909452509092915050565b63ffffffff60e01b815116825260006020820151604060208501526139f66040850182613faa565b60008151604084526140606040850182613fd6565b9050602080840151858303828701528281518085528385019150838160051b860101848401935060005b828110156140b857601f198783030184526140a6828651614023565b9486019493860193915060010161408a565b5098975050505050505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b8281101561411c57603f1988860301845261410a85835161404b565b945092850192908501906001016140ee565b5092979650505050505050565b60006040828403121561413b57600080fd5b614143613e41565b905061414e82613f2a565b815260208201356001600160401b0381111561416957600080fd5b61417584828501613ebb565b60208301525092915050565b6000806040838503121561419457600080fd5b82356001600160401b03808211156141ab57600080fd5b6141b786838701613ebb565b935060208501359150808211156141cd57600080fd5b506141da85828601614129565b9150509250929050565b6000806000604084860312156141f957600080fd5b61420284613d85565b925060208401356001600160401b038082111561421e57600080fd5b818601915086601f83011261423257600080fd5b81358181111561424157600080fd5b87602082850101111561425357600080fd5b6020830194508093505050509250925092565b6000806040838503121561427957600080fd5b50508035926020909101359150565b60006020828403121561429a57600080fd5b81356001600160401b038111156142b057600080fd5b6139f684828501613ebb565b6000602082840312156142ce57600080fd5b610dc682613f2a565b602081526000610dc66020830184613fd6565b600080602083850312156142fd57600080fd5b82356001600160401b038082111561431457600080fd5b818501915085601f83011261432857600080fd5b81358181111561433757600080fd5b8660208260051b850101111561434c57600080fd5b60209290920196919550909350505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b8281101561411c57603f198886030184526143a3858351613faa565b94509285019290850190600101614387565b600082601f8301126143c657600080fd5b813560206001600160401b03808311156143e2576143e2613e2b565b8260051b6143f1838201613e8b565b938452858101830193838101908886111561440b57600080fd5b84880192505b85831015614447578235848111156144295760008081fd5b6144378a87838c0101614129565b8352509184019190840190614411565b98975050505050505050565b60006020828403121561446557600080fd5b81356001600160401b038082111561447c57600080fd5b908301906040828603121561449057600080fd5b614498613e41565b8235828111156144a757600080fd5b8301606081880312156144b957600080fd5b6144c1613e69565b8135848111156144d057600080fd5b6144dc89828501613ebb565b8252506020820135848111156144f157600080fd5b6144fd89828501613ebb565b60208301525061450f60408301613d85565b604082015282525060208301358281111561452957600080fd5b614535878286016143b5565b60208301525095945050505050565b602081526000610dc6602083018461404b565b602081526000610dc66020830184613faa565b6020808252601f908201527f4163636f756e74466163746f72793a206e6f7420616e206163636f756e742e00604082015260600190565b6020808252601f908201527f457874656e73696f6e4d616e616765723a20756e617574686f72697a65642e00604082015260600190565b600181811c908216806145ec57607f821691505b60208210810361140d57634e487b7160e01b600052602260045260246000fd5b6000825161461e818460208701613f86565b9190910192915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561082a5761082a61463e565b6020808252602a908201527f4163636f756e74466163746f72793a206163636f756e7420616c7265616479206040820152691c9959da5cdd195c995960b21b606082015260800190565b6000808335601e198436030181126146c857600080fd5b8301803591506001600160401b038211156146e257600080fd5b6020019150368190038213156146f757600080fd5b9250929050565b8284823760609190911b6001600160601b0319169101908152601401919050565b8181038181111561082a5761082a61463e565b7402832b936b4b9b9b4b7b7399d1030b1b1b7bab73a1605d1b815260008351614762816015850160208801613f86565b7001034b99036b4b9b9b4b733903937b6329607d1b6015918401918201528351614793816026840160208801613f86565b01602601949350505050565b6020808252602b908201527f457874656e73696f6e4d616e616765723a20657874656e73696f6e20646f657360408201526a103737ba1032bc34b9ba1760a91b606082015260800190565b60006020808352600084546147fe816145d8565b8060208701526040600180841660008114614820576001811461483c5761486c565b60ff19851660408a0152604084151560051b8a0101955061486c565b89600052602060002060005b858110156148635781548b8201860152908301908801614848565b8a016040019650505b509398975050505050505050565b601f821115610758576000816000526020600020601f850160051c810160208610156148a35750805b601f850160051c820191505b8181101561331a578281556001016148af565b600019600383901b1c191660019190911b1790565b8181036148e2575050565b6148ec82546145d8565b6001600160401b0381111561490357614903613e2b565b6149178161491184546145d8565b8461487a565b6000601f82116001811461494557600083156149335750848201545b61493d84826148c2565b855550611cbe565b600085815260209020601f19841690600086815260209020845b8381101561497f578286015482556001958601959091019060200161495f565b508583101561499d5781850154600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052603160045260246000fd5b6040815260006149d66040830185614023565b8281036020840152610dc28185613fd6565b6001600160a01b03831681526040602082018190526000906139f690830184613faa565b81516001600160401b03811115614a2557614a25613e2b565b614a338161491184546145d8565b602080601f831160018114614a625760008415614a505750858301515b614a5a85826148c2565b86555061331a565b600085815260208120601f198616915b82811015614a9157888601518255948401946001909101908401614a72565b508582101561499d57939096015160001960f8600387901b161c19169092555050600190811b01905550565b604081526000614ad06040830185613faa565b8281036020840152610dc28185613faa565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b808202811582820484141761082a5761082a61463e565b600081614b4857614b4861463e565b50600019019056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220ea0bf6593fb849f1c8bca9503fc128d4ca8a5664256139b4a63c87879333ff4a64736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000e00f80aab91e6f3526cfe90ce608dd0dd49d9ad10000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000cd68591e4f9fa55c4a9938a5574e22517047a05500000000000000000000000000000000000000000000000000000000000000104163636f756e74457874656e73696f6e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d4e5132646a543275346d793578704b50674a4d6e5145706f4e6a595a45387567704c6e647667454a4262335800000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004a0000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000005a0000000000000000000000000000000000000000000000000000000000000062000000000000000000000000000000000000000000000000000000000000006a0000000000000000000000000000000000000000000000000000000000000072000000000000000000000000000000000000000000000000000000000000007a0000000000000000000000000000000000000000000000000000000000000082000000000000000000000000000000000000000000000000000000000000008a000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000aa00000000000000000000000000000000000000000000000000000000000000b200000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000d604a58db19000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000c6164644465706f73697428290000000000000000000000000000000000000000e8a3d485000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000d636f6e7472616374555249282900000000000000000000000000000000000000b61d27f6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e6578656375746528616464726573732c75696e743235362c627974657329000047e1da2a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002965786563757465426174636828616464726573735b5d2c75696e743235365b5d2c62797465735b5d2900000000000000000000000000000000000000000000008b52d7230000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000015676574416c6c4163746976655369676e65727328290000000000000000000000e9523c97000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000e676574416c6c41646d696e732829000000000000000000000000000000000000d42f2f35000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000f676574416c6c5369676e65727328290000000000000000000000000000000000399b77da00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000176765744d65737361676548617368286279746573333229000000000000000000f15d424e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000206765745065726d697373696f6e73466f725369676e65722861646472657373297dff5a79000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001769734163746976655369676e657228616464726573732900000000000000000024d7806c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000010697341646d696e286164647265737329000000000000000000000000000000001626ba7e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001f697356616c69645369676e617475726528627974657333322c62797465732900bc197c8100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000416f6e455243313135354261746368526563656976656428616464726573732c616464726573732c75696e743235365b5d2c75696e743235365b5d2c62797465732900000000000000000000000000000000000000000000000000000000000000f23a6e6100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000386f6e45524331313535526563656976656428616464726573732c616464726573732c75696e743235362c75696e743235362c6279746573290000000000000000150b7a02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002f6f6e455243373231526563656976656428616464726573732c616464726573732c75696e743235362c6279746573290000000000000000000000000000000000938e3d7b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000016736574436f6e747261637455524928737472696e6729000000000000000000005892e23600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000687365745065726d697373696f6e73466f725369676e65722828616464726573732c75696e74382c616464726573735b5d2c75696e743235362c75696e743132382c75696e743132382c75696e743132382c75696e743132382c62797465733332292c62797465732900000000000000000000000000000000000000000000000001ffc9a70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000019737570706f727473496e74657266616365286279746573342900000000000000a9082d84000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000006e7665726966795369676e65725065726d697373696f6e526571756573742828616464726573732c75696e74382c616464726573735b5d2c75696e743235362c75696e743132382c75696e743132382c75696e743132382c75696e743132382c62797465733332292c6279746573290000000000000000000000000000000000004d44560d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002277697468647261774465706f736974546f28616464726573732c75696e7432353629000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _defaultAdmin (address): 0xE00F80Aab91E6F3526CfE90cE608Dd0Dd49D9ad1
Arg [1] : _entrypoint (address): 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789
Arg [2] : _defaultExtensions (tuple[]): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
-----Encoded View---------------
128 Constructor Arguments found :
Arg [0] : 000000000000000000000000e00f80aab91e6f3526cfe90ce608dd0dd49d9ad1
Arg [1] : 0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d2789
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [8] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [9] : 000000000000000000000000cd68591e4f9fa55c4a9938a5574e22517047a055
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [11] : 4163636f756e74457874656e73696f6e00000000000000000000000000000000
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000035
Arg [13] : 697066733a2f2f516d4e5132646a543275346d793578704b50674a4d6e514570
Arg [14] : 6f4e6a595a45387567704c6e647667454a426233580000000000000000000000
Arg [15] : 0000000000000000000000000000000000000000000000000000000000000014
Arg [16] : 0000000000000000000000000000000000000000000000000000000000000280
Arg [17] : 0000000000000000000000000000000000000000000000000000000000000300
Arg [18] : 0000000000000000000000000000000000000000000000000000000000000380
Arg [19] : 0000000000000000000000000000000000000000000000000000000000000400
Arg [20] : 00000000000000000000000000000000000000000000000000000000000004a0
Arg [21] : 0000000000000000000000000000000000000000000000000000000000000520
Arg [22] : 00000000000000000000000000000000000000000000000000000000000005a0
Arg [23] : 0000000000000000000000000000000000000000000000000000000000000620
Arg [24] : 00000000000000000000000000000000000000000000000000000000000006a0
Arg [25] : 0000000000000000000000000000000000000000000000000000000000000720
Arg [26] : 00000000000000000000000000000000000000000000000000000000000007a0
Arg [27] : 0000000000000000000000000000000000000000000000000000000000000820
Arg [28] : 00000000000000000000000000000000000000000000000000000000000008a0
Arg [29] : 0000000000000000000000000000000000000000000000000000000000000960
Arg [30] : 0000000000000000000000000000000000000000000000000000000000000a00
Arg [31] : 0000000000000000000000000000000000000000000000000000000000000aa0
Arg [32] : 0000000000000000000000000000000000000000000000000000000000000b20
Arg [33] : 0000000000000000000000000000000000000000000000000000000000000c00
Arg [34] : 0000000000000000000000000000000000000000000000000000000000000c80
Arg [35] : 0000000000000000000000000000000000000000000000000000000000000d60
Arg [36] : 4a58db1900000000000000000000000000000000000000000000000000000000
Arg [37] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [38] : 000000000000000000000000000000000000000000000000000000000000000c
Arg [39] : 6164644465706f73697428290000000000000000000000000000000000000000
Arg [40] : e8a3d48500000000000000000000000000000000000000000000000000000000
Arg [41] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [42] : 000000000000000000000000000000000000000000000000000000000000000d
Arg [43] : 636f6e7472616374555249282900000000000000000000000000000000000000
Arg [44] : b61d27f600000000000000000000000000000000000000000000000000000000
Arg [45] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [46] : 000000000000000000000000000000000000000000000000000000000000001e
Arg [47] : 6578656375746528616464726573732c75696e743235362c6279746573290000
Arg [48] : 47e1da2a00000000000000000000000000000000000000000000000000000000
Arg [49] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [50] : 0000000000000000000000000000000000000000000000000000000000000029
Arg [51] : 65786563757465426174636828616464726573735b5d2c75696e743235365b5d
Arg [52] : 2c62797465735b5d290000000000000000000000000000000000000000000000
Arg [53] : 8b52d72300000000000000000000000000000000000000000000000000000000
Arg [54] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [55] : 0000000000000000000000000000000000000000000000000000000000000015
Arg [56] : 676574416c6c4163746976655369676e65727328290000000000000000000000
Arg [57] : e9523c9700000000000000000000000000000000000000000000000000000000
Arg [58] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [59] : 000000000000000000000000000000000000000000000000000000000000000e
Arg [60] : 676574416c6c41646d696e732829000000000000000000000000000000000000
Arg [61] : d42f2f3500000000000000000000000000000000000000000000000000000000
Arg [62] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [63] : 000000000000000000000000000000000000000000000000000000000000000f
Arg [64] : 676574416c6c5369676e65727328290000000000000000000000000000000000
Arg [65] : 399b77da00000000000000000000000000000000000000000000000000000000
Arg [66] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [67] : 0000000000000000000000000000000000000000000000000000000000000017
Arg [68] : 6765744d65737361676548617368286279746573333229000000000000000000
Arg [69] : f15d424e00000000000000000000000000000000000000000000000000000000
Arg [70] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [71] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [72] : 6765745065726d697373696f6e73466f725369676e6572286164647265737329
Arg [73] : 7dff5a7900000000000000000000000000000000000000000000000000000000
Arg [74] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [75] : 0000000000000000000000000000000000000000000000000000000000000017
Arg [76] : 69734163746976655369676e6572286164647265737329000000000000000000
Arg [77] : 24d7806c00000000000000000000000000000000000000000000000000000000
Arg [78] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [79] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [80] : 697341646d696e28616464726573732900000000000000000000000000000000
Arg [81] : 1626ba7e00000000000000000000000000000000000000000000000000000000
Arg [82] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [83] : 000000000000000000000000000000000000000000000000000000000000001f
Arg [84] : 697356616c69645369676e617475726528627974657333322c62797465732900
Arg [85] : bc197c8100000000000000000000000000000000000000000000000000000000
Arg [86] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [87] : 0000000000000000000000000000000000000000000000000000000000000041
Arg [88] : 6f6e455243313135354261746368526563656976656428616464726573732c61
Arg [89] : 6464726573732c75696e743235365b5d2c75696e743235365b5d2c6279746573
Arg [90] : 2900000000000000000000000000000000000000000000000000000000000000
Arg [91] : f23a6e6100000000000000000000000000000000000000000000000000000000
Arg [92] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [93] : 0000000000000000000000000000000000000000000000000000000000000038
Arg [94] : 6f6e45524331313535526563656976656428616464726573732c616464726573
Arg [95] : 732c75696e743235362c75696e743235362c6279746573290000000000000000
Arg [96] : 150b7a0200000000000000000000000000000000000000000000000000000000
Arg [97] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [98] : 000000000000000000000000000000000000000000000000000000000000002f
Arg [99] : 6f6e455243373231526563656976656428616464726573732c61646472657373
Arg [100] : 2c75696e743235362c6279746573290000000000000000000000000000000000
Arg [101] : 938e3d7b00000000000000000000000000000000000000000000000000000000
Arg [102] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [103] : 0000000000000000000000000000000000000000000000000000000000000016
Arg [104] : 736574436f6e747261637455524928737472696e672900000000000000000000
Arg [105] : 5892e23600000000000000000000000000000000000000000000000000000000
Arg [106] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [107] : 0000000000000000000000000000000000000000000000000000000000000068
Arg [108] : 7365745065726d697373696f6e73466f725369676e6572282861646472657373
Arg [109] : 2c75696e74382c616464726573735b5d2c75696e743235362c75696e74313238
Arg [110] : 2c75696e743132382c75696e743132382c75696e743132382c62797465733332
Arg [111] : 292c627974657329000000000000000000000000000000000000000000000000
Arg [112] : 01ffc9a700000000000000000000000000000000000000000000000000000000
Arg [113] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [114] : 0000000000000000000000000000000000000000000000000000000000000019
Arg [115] : 737570706f727473496e74657266616365286279746573342900000000000000
Arg [116] : a9082d8400000000000000000000000000000000000000000000000000000000
Arg [117] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [118] : 000000000000000000000000000000000000000000000000000000000000006e
Arg [119] : 7665726966795369676e65725065726d697373696f6e52657175657374282861
Arg [120] : 6464726573732c75696e74382c616464726573735b5d2c75696e743235362c75
Arg [121] : 696e743132382c75696e743132382c75696e743132382c75696e743132382c62
Arg [122] : 797465733332292c627974657329000000000000000000000000000000000000
Arg [123] : 4d44560d00000000000000000000000000000000000000000000000000000000
Arg [124] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [125] : 0000000000000000000000000000000000000000000000000000000000000022
Arg [126] : 77697468647261774465706f736974546f28616464726573732c75696e743235
Arg [127] : 3629000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 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.