Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 239 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Import Last | 19423338 | 126 days ago | IN | 0 ETH | 0.02214802 | ||||
Import Last | 19415103 | 127 days ago | IN | 0 ETH | 0.03085128 | ||||
Import Last | 19406905 | 128 days ago | IN | 0 ETH | 0.03151236 | ||||
Import Last | 19398714 | 129 days ago | IN | 0 ETH | 0.03596836 | ||||
Import Last | 19390522 | 130 days ago | IN | 0 ETH | 0.02739764 | ||||
Import Last | 19382330 | 132 days ago | IN | 0 ETH | 0.02424878 | ||||
Import Last | 19374137 | 133 days ago | IN | 0 ETH | 0.03353946 | ||||
Import Last | 19365946 | 134 days ago | IN | 0 ETH | 0.04039123 | ||||
Import Last | 19357754 | 135 days ago | IN | 0 ETH | 0.0285381 | ||||
Import Last | 19349562 | 136 days ago | IN | 0 ETH | 0.02644296 | ||||
Import Last | 19341371 | 137 days ago | IN | 0 ETH | 0.02924834 | ||||
Import Last | 19333178 | 138 days ago | IN | 0 ETH | 0.04149181 | ||||
Import Last | 19324986 | 140 days ago | IN | 0 ETH | 0.02542557 | ||||
Import Last | 19316795 | 141 days ago | IN | 0 ETH | 0.01897427 | ||||
Import Last | 19308602 | 142 days ago | IN | 0 ETH | 0.01293404 | ||||
Import Last | 19300410 | 143 days ago | IN | 0 ETH | 0.01141962 | ||||
Import Last | 19292217 | 144 days ago | IN | 0 ETH | 0.01545279 | ||||
Import Last | 19284025 | 145 days ago | IN | 0 ETH | 0.02826385 | ||||
Import Last | 19275834 | 147 days ago | IN | 0 ETH | 0.01785554 | ||||
Import Last | 19267641 | 148 days ago | IN | 0 ETH | 0.01940391 | ||||
Import Last | 19259450 | 149 days ago | IN | 0 ETH | 0.01032928 | ||||
Import Last | 19251258 | 150 days ago | IN | 0 ETH | 0.008328 | ||||
Import Last | 19243064 | 151 days ago | IN | 0 ETH | 0.01583142 | ||||
Import Last | 19234874 | 152 days ago | IN | 0 ETH | 0.01714889 | ||||
Import Last | 19226682 | 153 days ago | IN | 0 ETH | 0.03114532 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
BlockHistory
Compiler Version
v0.8.13+commit.abaa5c0e
Contract Source Code (Solidity Standard Json-Input format)
/// SPDX-License-Identifier: UNLICENSED /// (c) Theori, Inc. 2022 /// All rights reserved pragma solidity >=0.8.0; import "@openzeppelin/contracts/access/AccessControl.sol"; import "./lib/CoreTypes.sol"; import "./lib/MerkleTree.sol"; import "./lib/AuxMerkleTree.sol"; import "./interfaces/IBlockHistory.sol"; import "./interfaces/IRecursiveVerifier.sol"; import { RecursiveProof, SignedRecursiveProof, getProofSigner, readHashWords } from "./lib/Proofs.sol"; /** * @title BlockHistory * @author Theori, Inc. * @notice BlockHistory allows trustless and cheap verification of any * historical block hash. Historical blocks are divided into chunks of * fixed size, and each chunk's merkle root is stored on-chain. The * merkle roots are validated on chain using aggregated SNARK proofs, * enabling both trustlessness and scalability. * * @dev Each SNARK proof validates some contiguous block headers and has * public inputs (parentHash, lastHash, merkleRoot). Here the merkleRoot * is the merkleRoot of all block hashes contained in the proof, which may * commit to many merkle roots which to commit on chain. If the last block * is recent enough (<= 256 blocks old), the lastHash can be confirmed in * the EVM, verifying that all blocks of the proof belong to this chain. * Due to this, the historical blocks' merkle roots are imported in reverse * order. */ contract BlockHistory is AccessControl, IBlockHistory { bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE"); bytes32 public constant QUERY_ROLE = keccak256("QUERY_ROLE"); // depth of the merkle trees whose roots we store in storage uint256 private constant MERKLE_TREE_DEPTH = 13; uint256 private constant BLOCKS_PER_CHUNK = 1 << MERKLE_TREE_DEPTH; /// @dev address of the reliquary, immutable address public immutable reliquary; /// @dev the expected signer of the SNARK proofs - if 0, then no signatures address public signer; /// @dev maps numBlocks => SNARK verifier (with VK embedded), only assigned /// to in the constructor mapping(uint256 => IRecursiveVerifier) public verifiers; /// @dev parent hash of oldest block in current merkle trees /// (0 once backlog fully imported) bytes32 public parentHash; /// @dev the earliest merkle root that has been imported uint256 public earliestRoot; /// @dev hash of most recent block in merkle trees bytes32 public lastHash; /// @dev merkle roots of block chunks between parentHash and lastHash mapping(uint256 => bytes32) private merkleRoots; /// @dev ZK-Friendly merkle roots, used by auxiliary SNARKs mapping(uint256 => bytes32) private auxiliaryRoots; /// @dev whether auth checks should run on aux root queries bool private needsAuth; event ImportMerkleRoot(uint256 indexed index, bytes32 merkleRoot, bytes32 auxiliaryRoot); event NewSigner(address newSigner); enum ProofType { Merkle, SNARK } /// @dev A SNARK + Merkle proof used to prove validity of a block struct MerkleSNARKProof { uint256 numBlocks; uint256 endBlock; SignedRecursiveProof snark; bytes32[] merkleProof; } struct ProofInputs { bytes32 parent; bytes32 last; bytes32 merkleRoot; bytes32 auxiliaryRoot; } constructor( uint256[] memory sizes, IRecursiveVerifier[] memory _verifiers, address _reliquary ) AccessControl() { _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); _setupRole(ADMIN_ROLE, msg.sender); _setupRole(QUERY_ROLE, msg.sender); reliquary = _reliquary; signer = msg.sender; require(sizes.length == _verifiers.length); for (uint256 i = 0; i < sizes.length; i++) { require(address(verifiers[sizes[i]]) == address(0)); verifiers[sizes[i]] = _verifiers[i]; } } /** * @notice Checks if a SNARK is valid and signed as expected. * Signatures checks are disabled if stored signer == address(0) * Properties proven by the SNARK: * - (parent ... last) form a valid block chain of length numBlocks * - root is the merkle root of all contained blocks * * @param proof the aggregated proof * @param numBlocks the number of blocks contained in the proof * @return the validity */ function validSNARK(SignedRecursiveProof calldata proof, uint256 numBlocks) internal view returns (bool) { address expected = signer; if (expected != address(0) && getProofSigner(proof) != expected) { return false; } IRecursiveVerifier verifier = verifiers[numBlocks]; require(address(verifier) != address(0), "invalid numBlocks"); return verifier.verify(proof.inner); } /** * @notice Asserts that the provided SNARK proof is valid and contains * the provied merkle roots. * * @param proof the aggregated proof * @param roots the block merkle roots * @param aux the auxiliary merkle roots * @return inputs the proof inputs */ function assertValidSNARKWithRoots( SignedRecursiveProof calldata proof, bytes32[] calldata roots, bytes32[] calldata aux ) internal view returns (ProofInputs memory inputs) { require(roots.length & (roots.length - 1) == 0, "roots length must be a power of 2"); require(roots.length == aux.length, "roots arrays must be same length"); // extract the inputs from the proof inputs = parseProofInputs(proof); // ensure the merkle roots are valid require(inputs.merkleRoot == MerkleTree.computeRoot(roots), "invalid block roots"); // ensure the auxiliary merkle roots are valid require(inputs.auxiliaryRoot == AuxMerkleTree.computeRoot(aux), "invalid aux roots"); // assert the SNARK proof is valid require(validSNARK(proof, BLOCKS_PER_CHUNK * roots.length), "invalid SNARK"); } /** * @notice Checks if the given block number/hash connects to the current * block using a SNARK. * * @param num the block number to check * @param hash the block hash to check * @param encodedProof the encoded MerkleSNARKProof * @return the validity */ function validBlockHashWithSNARK( bytes32 hash, uint256 num, bytes calldata encodedProof ) internal view returns (bool) { MerkleSNARKProof calldata proof = parseMerkleSNARKProof(encodedProof); ProofInputs memory inputs = parseProofInputs(proof.snark); // check that the proof ends with a current block if (!validCurrentBlock(inputs.last, proof.endBlock)) { return false; } if (!validSNARK(proof.snark, proof.numBlocks)) { return false; } // compute the first block number in the proof uint256 startBlock = proof.endBlock + 1 - proof.numBlocks; // check if the target block is the parent of the proven blocks if (num == startBlock - 1 && hash == inputs.parent) { // merkle proof not needed in this case return true; } // check if the target block is in the proven merkle root uint256 index = num - startBlock; return MerkleTree.validProof(inputs.merkleRoot, index, hash, proof.merkleProof); } /** * @notice Checks if the given block number + hash exists in a commited * merkle tree. * * @param num the block number to check * @param hash the block hash to check * @param encodedProof the encoded merkle proof * @return the validity */ function validBlockHashWithMerkle( bytes32 hash, uint256 num, bytes calldata encodedProof ) internal view returns (bool) { bytes32 merkleRoot = merkleRoots[num / BLOCKS_PER_CHUNK]; if (merkleRoot == 0) { return false; } bytes32[] calldata proofHashes = parseMerkleProof(encodedProof); if (proofHashes.length != MERKLE_TREE_DEPTH) { return false; } return MerkleTree.validProof(merkleRoot, num % BLOCKS_PER_CHUNK, hash, proofHashes); } /** * @notice Checks if the block is a current block (defined as being * accessible in the EVM, i.e. <= 256 blocks old) and that the hash * is correct. * * @param hash the alleged block hash * @param num the block number * @return the validity */ function validCurrentBlock(bytes32 hash, uint256 num) internal view returns (bool) { // the block hash must be accessible in the EVM and match return (block.number - num <= 256) && (blockhash(num) == hash); } /** * @notice Stores the merkle roots starting at the index * * @param index the index for the first merkle root * @param roots the merkle roots of the block hashes * @param aux the auxiliary merkle roots of the block hashes */ function storeMerkleRoots( uint256 index, bytes32[] calldata roots, bytes32[] calldata aux ) internal { for (uint256 i = 0; i < roots.length; i++) { uint256 idx = index + i; merkleRoots[idx] = roots[i]; auxiliaryRoots[idx] = aux[i]; emit ImportMerkleRoot(idx, roots[i], aux[i]); } } /** * @notice Imports new chunks of blocks before the current parentHash * * @param proof the aggregated proof for these chunks * @param roots the merkle roots for the block hashes * @param aux the auxiliary roots for the block hashes */ function importParent( SignedRecursiveProof calldata proof, bytes32[] calldata roots, bytes32[] calldata aux ) external { require(parentHash != 0 && earliestRoot != 0, "import not started or already completed"); ProofInputs memory inputs = assertValidSNARKWithRoots(proof, roots, aux); // assert the last hash in the proof is our current parent hash require(parentHash == inputs.last, "proof doesn't connect with parentHash"); // store the merkle roots uint256 index = earliestRoot - roots.length; storeMerkleRoots(index, roots, aux); // store the new parentHash and earliestRoot parentHash = inputs.parent; earliestRoot = index; } /** * @notice Imports new chunks of blocks after the current lastHash * * @param endBlock the last block number in the chunks * @param proof the aggregated proof for these chunks * @param roots the merkle roots for the block hashes * @param connectProof an optional SNARK proof connecting the proof to * a current block */ function importLast( uint256 endBlock, SignedRecursiveProof calldata proof, bytes32[] calldata roots, bytes32[] calldata aux, bytes calldata connectProof ) external { require((endBlock + 1) % BLOCKS_PER_CHUNK == 0, "endBlock must end at a chunk boundary"); ProofInputs memory inputs = assertValidSNARKWithRoots(proof, roots, aux); if (!validCurrentBlock(inputs.last, endBlock)) { // if the proof doesn't connect our lastHash with a current block, // then the connectProof must fill the gap require( validBlockHashWithSNARK(inputs.last, endBlock, connectProof), "connectProof invalid" ); } uint256 index = (endBlock + 1) / BLOCKS_PER_CHUNK - roots.length; if (lastHash == 0) { // if we're importing for the first time, set parentHash and earliestRoot require(parentHash == 0); parentHash = inputs.parent; earliestRoot = index; } else { require(inputs.parent == lastHash, "proof doesn't connect with lastHash"); } // store the new lastHash lastHash = inputs.last; // store the merkle roots storeMerkleRoots(index, roots, aux); } /** * @notice Checks if a block hash is valid. A proof is required unless the * block is current (accesible in the EVM). If the target block has * no commited merkle root, the proof must contain a SNARK proof. * * @param hash the hash to check * @param num the block number for the alleged hash * @param proof the merkle witness or SNARK proof (if needed) * @return the validity */ function _validBlockHash( bytes32 hash, uint256 num, bytes calldata proof ) internal view returns (bool) { if (validCurrentBlock(hash, num)) { return true; } ProofType typ; (typ, proof) = parseProofType(proof); if (typ == ProofType.Merkle) { return validBlockHashWithMerkle(hash, num, proof); } else if (typ == ProofType.SNARK) { return validBlockHashWithSNARK(hash, num, proof); } else { revert("invalid proof type"); } } /** * @notice Checks if a block hash is correct. A proof is required unless the * block is current (accesible in the EVM). If the target block has * no commited merkle root, the proof must contain a SNARK proof. * Reverts if block hash or proof is invalid. * * @param hash the hash to check * @param num the block number for the alleged hash * @param proof the merkle witness or SNARK proof (if needed) */ function validBlockHash( bytes32 hash, uint256 num, bytes calldata proof ) external view returns (bool) { require(msg.sender == reliquary || hasRole(QUERY_ROLE, msg.sender)); require(num < block.number); return _validBlockHash(hash, num, proof); } /** * @notice Queries an auxRoot * * @dev only authorized addresses can call this * @param idx the index of the root to query */ function auxRoots(uint256 idx) external view returns (bytes32 root) { if (needsAuth) { _checkRole(QUERY_ROLE); } root = auxiliaryRoots[idx]; } /** * @notice sets the needsAuth flag which controls auxRoot query auth checks * * @dev only the owner can call this * @param _needsAuth the new value */ function setNeedsAuth(bool _needsAuth) external onlyRole(ADMIN_ROLE) { needsAuth = _needsAuth; } /** * @notice Parses a proof type and proof from the encoded proof * * @param proof the encoded proof * @return typ the proof type (SNARK or Merkle) * @return proof the remaining encoded proof */ function parseProofType(bytes calldata encodedProof) internal pure returns (ProofType typ, bytes calldata proof) { require(encodedProof.length > 0, "cannot parse proof type"); typ = ProofType(uint8(encodedProof[0])); proof = encodedProof[1:]; } /** * @notice Parses a MerkleSNARKProof from calldata bytes * * @param proof the encoded proof * @return result a MerkleSNARKProof */ function parseMerkleSNARKProof(bytes calldata proof) internal pure returns (MerkleSNARKProof calldata result) { // solidity doesn't support getting calldata outputs from abi.decode // but we can decode it; calldata structs are just offsets assembly { result := proof.offset } } /** * @notice Parses a merkle inclusion proof from the bytes * * @param proof the encoded merkle inclusion proof * @return result the array of proof hashes */ function parseMerkleProof(bytes calldata proof) internal pure returns (bytes32[] calldata result) { require(proof.length % 32 == 0); require(proof.length >= 32); // solidity doesn't support getting calldata outputs from abi.decode // but we can decode it; calldata arrays are just (offset,length) assembly { result.offset := add(proof.offset, 0x20) result.length := calldataload(proof.offset) } } /** * @notice Parses the proof inputs for block history snark proofs * * @param proof the snark proof * @return result the parsed proof inputs */ function parseProofInputs(SignedRecursiveProof calldata proof) internal pure returns (ProofInputs memory result) { uint256[] calldata inputs = proof.inner.inputs; require(inputs.length == 13); result = ProofInputs( readHashWords(inputs[0:4]), readHashWords(inputs[4:8]), readHashWords(inputs[8:12]), bytes32(inputs[12]) ); } /** * @notice sets the expected signer of the SNARK proofs, only callable by * the contract owner * * @param _signer the new signer; if 0, disables signature checks */ function setSigner(address _signer) external onlyRole(ADMIN_ROLE) { require(signer != _signer); signer = _signer; emit NewSigner(_signer); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControl.sol"; import "../utils/Context.sol"; import "../utils/Strings.sol"; import "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", Strings.toHexString(account), " is missing role ", Strings.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { return _roles[role].adminRole; } /** * @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. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @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 revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * May emit a {RoleGranted} event. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @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: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) { // 32 is the length in bytes of hash, // enforced by the type signature above /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") mstore(0x1c, hash) message := keccak256(0x00, 0x3c) } } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, "\x19\x01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) data := keccak256(ptr, 0x42) } } /** * @dev Returns an Ethereum Signed Data with intended validator, created from a * `validator` and `data` according to the version 0 of EIP-191. * * See {recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x00", validator, data)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
/// SPDX-License-Identifier: UNLICENSED /// (c) Theori, Inc. 2022 /// All rights reserved pragma solidity >=0.8.0; /** * @title Block history provider * @author Theori, Inc. * @notice IBlockHistory provides a way to verify a blockhash */ interface IBlockHistory { /** * @notice Determine if the given hash corresponds to the given block * @param hash the hash if the block in question * @param num the number of the block in question * @param proof any witness data required to prove the block hash is * correct (such as a Merkle or SNARK proof) * @return boolean indicating if the block hash can be verified correct */ function validBlockHash( bytes32 hash, uint256 num, bytes calldata proof ) external view returns (bool); }
/// SPDX-License-Identifier: UNLICENSED /// (c) Theori, Inc. 2022 /// All rights reserved pragma solidity >=0.8.0; import {RecursiveProof} from "../lib/Proofs.sol"; /** * @title Verifier of zk-SNARK proofs * @author Theori, Inc. * @notice Provider of validity checking of zk-SNARKs */ interface IRecursiveVerifier { /** * @notice Checks the validity of SNARK data * @param proof the proof to verify * @return the validity of the proof */ function verify(RecursiveProof calldata proof) external view returns (bool); }
/// SPDX-License-Identifier: UNLICENSED /// (c) Theori, Inc. 2022 /// All rights reserved pragma solidity >=0.8.0; /** * @title AnemoiJive * @author Theori, Inc. * @notice Implementation of the Anemoi hash function and Jive mode of operation */ library AnemoiJive { uint256 constant beta = 5; uint256 constant alpha_inv = 17510594297471420177797124596205820070838691520332827474958563349260646796493; uint256 constant q = 21888242871839275222246405745257275088548364400416034343698204186575808495617; uint256 constant delta = 8755297148735710088898562298102910035419345760166413737479281674630323398247; function CD(uint256 round) internal pure returns (uint256, uint256) { if (round == 0) return ( 37, 8755297148735710088898562298102910035419345760166413737479281674630323398284 ); if (round == 1) return ( 13352247125433170118601974521234241686699252132838635793584252509352796067497, 5240474505904316858775051800099222288270827863409873986701694203345984265770 ); if (round == 2) return ( 8959866518978803666083663798535154543742217570455117599799616562379347639707, 9012679925958717565787111885188464538194947839997341443807348023221726055342 ); if (round == 3) return ( 3222831896788299315979047232033900743869692917288857580060845801753443388885, 21855834035835287540286238525800162342051591799629360593177152465113152235615 ); if (round == 4) return ( 11437915391085696126542499325791687418764799800375359697173212755436799377493, 11227229470941648605622822052481187204980748641142847464327016901091886692935 ); if (round == 5) return ( 14725846076402186085242174266911981167870784841637418717042290211288365715997, 8277823808153992786803029269162651355418392229624501612473854822154276610437 ); if (round == 6) return ( 3625896738440557179745980526949999799504652863693655156640745358188128872126, 20904607884889140694334069064199005451741168419308859136555043894134683701950 ); if (round == 7) return ( 463291105983501380924034618222275689104775247665779333141206049632645736639, 1902748146936068574869616392736208205391158973416079524055965306829204527070 ); if (round == 8) return ( 17443852951621246980363565040958781632244400021738903729528591709655537559937, 14452570815461138929654743535323908350592751448372202277464697056225242868484 ); if (round == 9) return ( 10761214205488034344706216213805155745482379858424137060372633423069634639664, 10548134661912479705005015677785100436776982856523954428067830720054853946467 ); if (round == 10) return ( 1555059412520168878870894914371762771431462665764010129192912372490340449901, 17068729307795998980462158858164249718900656779672000551618940554342475266265 ); if (round == 11) return ( 7985258549919592662769781896447490440621354347569971700598437766156081995625, 16199718037005378969178070485166950928725365516399196926532630556982133691321 ); if (round == 12) return ( 9570976950823929161626934660575939683401710897903342799921775980893943353035, 19148564379197615165212957504107910110246052442686857059768087896511716255278 ); if (round == 13) return ( 17962366505931708682321542383646032762931774796150042922562707170594807376009, 5497141763311860520411283868772341077137612389285480008601414949457218086902 ); if (round == 14) return ( 12386136552538719544323156650508108618627836659179619225468319506857645902649, 18379046272821041930426853913114663808750865563081998867954732461233335541378 ); if (round == 15) return ( 21184636178578575123799189548464293431630680704815247777768147599366857217074, 7696001730141875853127759241422464241772355903155684178131833937483164915734 ); if (round == 16) return ( 3021529450787050964585040537124323203563336821758666690160233275817988779052, 963844642109550260189938374814031216012862679737123536423540607519656220143 ); if (round == 17) return ( 7005374570978576078843482270548485551486006385990713926354381743200520456088, 12412434690468911461310698766576920805270445399824272791985598210955534611003 ); if (round == 18) return ( 3870834761329466217812893622834770840278912371521351591476987639109753753261, 6971318955459107915662273112161635903624047034354567202210253298398705502050 ); revert(); } function expmod( uint256 base, uint256 e, uint256 m ) internal view returns (uint256 o) { assembly { // define pointer let p := mload(0x40) // store data assembly-favouring ways mstore(p, 0x20) // Length of Base mstore(add(p, 0x20), 0x20) // Length of Exponent mstore(add(p, 0x40), 0x20) // Length of Modulus mstore(add(p, 0x60), base) // Base mstore(add(p, 0x80), e) // Exponent mstore(add(p, 0xa0), m) // Modulus if iszero(staticcall(sub(gas(), 2000), 0x05, p, 0xc0, p, 0x20)) { revert(0, 0) } // data o := mload(p) } } function sbox(uint256 x, uint256 y) internal view returns (uint256, uint256) { x = addmod(x, q - mulmod(beta, mulmod(y, y, q), q), q); y = addmod(y, q - expmod(x, alpha_inv, q), q); x = addmod(addmod(x, mulmod(beta, mulmod(y, y, q), q), q), delta, q); return (x, y); } function ll(uint256 x, uint256 y) internal pure returns (uint256 r0, uint256 r1) { r0 = addmod(x, mulmod(5, y, q), q); r1 = addmod(y, mulmod(5, r0, q), q); } function compress(uint256 x, uint256 y) internal view returns (uint256) { uint256 sum = addmod(x, y, q); uint256 c; uint256 d; for (uint256 r = 0; r < 19; r++) { (c, d) = CD(r); x = addmod(x, c, q); y = addmod(y, d, q); (x, y) = ll(x, y); (x, y) = sbox(x, y); } (x, y) = ll(x, y); return addmod(addmod(x, y, q), sum, q); } }
/// SPDX-License-Identifier: UNLICENSED /// (c) Theori, Inc. 2022 /// All rights reserved pragma solidity >=0.8.0; import "./AnemoiJive.sol"; /** * @title Auxiliary Merkle Tree * @author Theori, Inc. * @notice Gas optimized arithmetic-friendly merkle tree code. * @dev uses Anemoi / Jive 2-to-1 */ library AuxMerkleTree { /** * @notice computes a jive merkle root of the provided hashes, in place * @param temp the mutable array of hashes * @return root the merkle root hash */ function computeRoot(bytes32[] memory temp) internal view returns (bytes32 root) { uint256 count = temp.length; while (count > 1) { unchecked { for (uint256 i = 0; i < count / 2; i++) { uint256 x; uint256 y; assembly { let ptr := add(temp, add(0x20, mul(0x40, i))) x := mload(ptr) ptr := add(ptr, 0x20) y := mload(ptr) } x = AnemoiJive.compress(x, y); assembly { mstore(add(temp, add(0x20, mul(0x20, i))), x) } } count >>= 1; } } return temp[0]; } }
/// SPDX-License-Identifier: UNLICENSED /// (c) Theori, Inc. 2022 /// All rights reserved pragma solidity >=0.8.13; // custom bytes calldata pointer storing (length | offset) in one word, // also allows calldata pointers to be stored in memory type BytesCalldata is uint256; using BytesCalldataOps for BytesCalldata global; // can't introduce global using .. for non UDTs // each consumer should add the following line: using BytesCalldataOps for bytes; /** * @author Theori, Inc * @title BytesCalldataOps * @notice Common operations for bytes calldata, implemented for both the builtin * type and our BytesCalldata type. These operations are heavily optimized * and omit safety checks, so this library should only be used when memory * safety is not a security issue. */ library BytesCalldataOps { function length(BytesCalldata bc) internal pure returns (uint256 result) { assembly { result := shr(128, shl(128, bc)) } } function offset(BytesCalldata bc) internal pure returns (uint256 result) { assembly { result := shr(128, bc) } } function convert(BytesCalldata bc) internal pure returns (bytes calldata value) { assembly { value.offset := shr(128, bc) value.length := shr(128, shl(128, bc)) } } function convert(bytes calldata inp) internal pure returns (BytesCalldata bc) { assembly { bc := or(shl(128, inp.offset), inp.length) } } function slice( BytesCalldata bc, uint256 start, uint256 len ) internal pure returns (BytesCalldata result) { assembly { result := shl(128, add(shr(128, bc), start)) // add to the offset and clear the length result := or(result, len) // set the new length } } function slice( bytes calldata value, uint256 start, uint256 len ) internal pure returns (bytes calldata result) { assembly { result.offset := add(value.offset, start) result.length := len } } function prefix(BytesCalldata bc, uint256 len) internal pure returns (BytesCalldata result) { assembly { result := shl(128, shr(128, bc)) // clear out the length result := or(result, len) // set it to the new length } } function prefix(bytes calldata value, uint256 len) internal pure returns (bytes calldata result) { assembly { result.offset := value.offset result.length := len } } function suffix(BytesCalldata bc, uint256 start) internal pure returns (BytesCalldata result) { assembly { result := add(bc, shl(128, start)) // add to the offset result := sub(result, start) // subtract from the length } } function suffix(bytes calldata value, uint256 start) internal pure returns (bytes calldata result) { assembly { result.offset := add(value.offset, start) result.length := sub(value.length, start) } } function split(BytesCalldata bc, uint256 start) internal pure returns (BytesCalldata, BytesCalldata) { return (prefix(bc, start), suffix(bc, start)); } function split(bytes calldata value, uint256 start) internal pure returns (bytes calldata, bytes calldata) { return (prefix(value, start), suffix(value, start)); } }
/// SPDX-License-Identifier: UNLICENSED /// (c) Theori, Inc. 2022 /// All rights reserved pragma solidity >=0.8.0; import "./BytesCalldata.sol"; import "./RLP.sol"; /** * @title CoreTypes * @author Theori, Inc. * @notice Data types and parsing functions for core types, including block headers * and account data. */ library CoreTypes { using BytesCalldataOps for bytes; struct BlockHeaderData { bytes32 ParentHash; address Coinbase; bytes32 Root; bytes32 TxHash; bytes32 ReceiptHash; uint256 Number; uint256 GasLimit; uint256 GasUsed; uint256 Time; bytes32 MixHash; uint256 BaseFee; bytes32 WithdrawalsHash; } struct AccountData { uint256 Nonce; uint256 Balance; bytes32 StorageRoot; bytes32 CodeHash; } struct LogData { address Address; bytes32[] Topics; bytes Data; } struct WithdrawalData { uint256 Index; uint256 ValidatorIndex; address Address; uint256 AmountInGwei; } function parseHash(bytes calldata buf) internal pure returns (bytes32 result, uint256 offset) { uint256 value; (value, offset) = RLP.parseUint(buf); result = bytes32(value); } function parseAddress(bytes calldata buf) internal pure returns (address result, uint256 offset) { uint256 value; (value, offset) = RLP.parseUint(buf); result = address(uint160(value)); } function parseBlockHeader(bytes calldata header) internal pure returns (BlockHeaderData memory data) { (uint256 listSize, uint256 offset) = RLP.parseList(header); header = header.slice(offset, listSize); (data.ParentHash, offset) = parseHash(header); // ParentHash header = header.suffix(offset); header = RLP.skip(header); // UncleHash (data.Coinbase, offset) = parseAddress(header); // Coinbase header = header.suffix(offset); (data.Root, offset) = parseHash(header); // Root header = header.suffix(offset); (data.TxHash, offset) = parseHash(header); // TxHash header = header.suffix(offset); (data.ReceiptHash, offset) = parseHash(header); // ReceiptHash header = header.suffix(offset); header = RLP.skip(header); // Bloom header = RLP.skip(header); // Difficulty (data.Number, offset) = RLP.parseUint(header); // Number header = header.suffix(offset); (data.GasLimit, offset) = RLP.parseUint(header); // GasLimit header = header.suffix(offset); (data.GasUsed, offset) = RLP.parseUint(header); // GasUsed header = header.suffix(offset); (data.Time, offset) = RLP.parseUint(header); // Time header = header.suffix(offset); header = RLP.skip(header); // Extra (data.MixHash, offset) = parseHash(header); // MixHash header = header.suffix(offset); header = RLP.skip(header); // Nonce if (header.length > 0) { (data.BaseFee, offset) = RLP.parseUint(header); // BaseFee header = header.suffix(offset); } if (header.length > 0) { (data.WithdrawalsHash, offset) = parseHash(header); // WithdrawalsHash } } function getBlockHeaderHashAndSize(bytes calldata header) internal pure returns (bytes32 blockHash, uint256 headerSize) { (uint256 listSize, uint256 offset) = RLP.parseList(header); unchecked { headerSize = offset + listSize; } blockHash = keccak256(header.prefix(headerSize)); } function parseAccount(bytes calldata account) internal pure returns (AccountData memory data) { (, uint256 offset) = RLP.parseList(account); account = account.suffix(offset); (data.Nonce, offset) = RLP.parseUint(account); // Nonce account = account.suffix(offset); (data.Balance, offset) = RLP.parseUint(account); // Balance account = account.suffix(offset); (data.StorageRoot, offset) = parseHash(account); // StorageRoot account = account.suffix(offset); (data.CodeHash, offset) = parseHash(account); // CodeHash account = account.suffix(offset); } function parseLog(bytes calldata log) internal pure returns (LogData memory data) { (, uint256 offset) = RLP.parseList(log); log = log.suffix(offset); uint256 tmp; (tmp, offset) = RLP.parseUint(log); // Address data.Address = address(uint160(tmp)); log = log.suffix(offset); (tmp, offset) = RLP.parseList(log); // Topics bytes calldata topics = log.slice(offset, tmp); log = log.suffix(offset + tmp); require(topics.length % 33 == 0); data.Topics = new bytes32[](tmp / 33); uint256 i = 0; while (topics.length > 0) { (data.Topics[i], offset) = parseHash(topics); topics = topics.suffix(offset); unchecked { i++; } } (data.Data, ) = RLP.splitBytes(log); } function extractLog(bytes calldata receiptValue, uint256 logIdx) internal pure returns (LogData memory) { // support EIP-2718: Currently all transaction types have the same // receipt RLP format, so we can just skip the receipt type byte if (receiptValue[0] < 0x80) { receiptValue = receiptValue.suffix(1); } (, uint256 offset) = RLP.parseList(receiptValue); receiptValue = receiptValue.suffix(offset); // pre EIP-658, receipts stored an intermediate state root in this field // post EIP-658, the field is a tx status (0 for failure, 1 for success) uint256 statusOrIntermediateRoot; (statusOrIntermediateRoot, offset) = RLP.parseUint(receiptValue); require(statusOrIntermediateRoot != 0, "tx did not succeed"); receiptValue = receiptValue.suffix(offset); receiptValue = RLP.skip(receiptValue); // GasUsed receiptValue = RLP.skip(receiptValue); // LogsBloom uint256 length; (length, offset) = RLP.parseList(receiptValue); // Logs receiptValue = receiptValue.slice(offset, length); // skip the earlier logs for (uint256 i = 0; i < logIdx; i++) { require(receiptValue.length > 0, "log index does not exist"); receiptValue = RLP.skip(receiptValue); } return parseLog(receiptValue); } function parseWithdrawal(bytes calldata withdrawal) internal pure returns (WithdrawalData memory data) { (, uint256 offset) = RLP.parseList(withdrawal); withdrawal = withdrawal.suffix(offset); (data.Index, offset) = RLP.parseUint(withdrawal); // Index withdrawal = withdrawal.suffix(offset); (data.ValidatorIndex, offset) = RLP.parseUint(withdrawal); // ValidatorIndex withdrawal = withdrawal.suffix(offset); (data.Address, offset) = parseAddress(withdrawal); // Address withdrawal = withdrawal.suffix(offset); (data.AmountInGwei, offset) = RLP.parseUint(withdrawal); // Amount } }
/// SPDX-License-Identifier: UNLICENSED /// (c) Theori, Inc. 2022 /// All rights reserved pragma solidity >=0.8.0; /** * @title Merkle Tree * @author Theori, Inc. * @notice Gas optimized SHA256 Merkle tree code. */ library MerkleTree { /** * @notice computes a SHA256 merkle root of the provided hashes, in place * @param temp the mutable array of hashes * @return the merkle root hash */ function computeRoot(bytes32[] memory temp) internal view returns (bytes32) { uint256 count = temp.length; assembly { // repeat until we arrive at one root hash for { } gt(count, 1) { } { let dataElementLocation := add(temp, 0x20) let hashElementLocation := add(temp, 0x20) for { let i := 0 } lt(i, count) { i := add(i, 2) } { if iszero( staticcall(gas(), 0x2, hashElementLocation, 0x40, dataElementLocation, 0x20) ) { revert(0, 0) } dataElementLocation := add(dataElementLocation, 0x20) hashElementLocation := add(hashElementLocation, 0x40) } count := shr(1, count) } } return temp[0]; } /** * @notice check if a hash is in the merkle tree for rootHash * @param rootHash the merkle root * @param index the index of the node to check * @param hash the hash to check * @param proofHashes the proof, i.e. the sequence of siblings from the * node to root */ function validProof( bytes32 rootHash, uint256 index, bytes32 hash, bytes32[] memory proofHashes ) internal view returns (bool result) { assembly { let constructedHash := hash let length := mload(proofHashes) let start := add(proofHashes, 0x20) let end := add(start, mul(length, 0x20)) for { let ptr := start } lt(ptr, end) { ptr := add(ptr, 0x20) } { let proofHash := mload(ptr) // use scratch space (0x0 - 0x40) for hash input switch and(index, 1) case 0 { mstore(0x0, constructedHash) mstore(0x20, proofHash) } case 1 { mstore(0x0, proofHash) mstore(0x20, constructedHash) } // compute sha256 if iszero(staticcall(gas(), 0x2, 0x0, 0x40, 0x0, 0x20)) { revert(0, 0) } constructedHash := mload(0x0) index := shr(1, index) } result := eq(constructedHash, rootHash) } } }
/// SPDX-License-Identifier: UNLICENSED /// (c) Theori, Inc. 2022 /// All rights reserved /* * @author Theori, Inc. */ pragma solidity >=0.8.0; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; uint256 constant BASE_PROOF_SIZE = 34; uint256 constant SUBPROOF_LIMBS_SIZE = 16; struct RecursiveProof { uint256[BASE_PROOF_SIZE] base; uint256[SUBPROOF_LIMBS_SIZE] subproofLimbs; uint256[] inputs; } struct SignedRecursiveProof { RecursiveProof inner; bytes signature; } /** * @notice recover the signer of the proof * @param proof the SignedRecursiveProof * @return the address of the signer */ function getProofSigner(SignedRecursiveProof calldata proof) pure returns (address) { bytes32 msgHash = keccak256( abi.encodePacked("\x19Ethereum Signed Message:\n", "32", hashProof(proof.inner)) ); return ECDSA.recover(msgHash, proof.signature); } /** * @notice hash the contents of a RecursiveProof * @param proof the RecursiveProof * @return result a 32-byte digest of the proof */ function hashProof(RecursiveProof calldata proof) pure returns (bytes32 result) { uint256[] calldata inputs = proof.inputs; assembly { let ptr := mload(0x40) let contigLen := mul(0x20, add(BASE_PROOF_SIZE, SUBPROOF_LIMBS_SIZE)) let inputsLen := mul(0x20, inputs.length) calldatacopy(ptr, proof, contigLen) calldatacopy(add(ptr, contigLen), inputs.offset, inputsLen) result := keccak256(ptr, add(contigLen, inputsLen)) } } /** * @notice reverse the byte order of a uint256 * @param input the input value * @return v the byte-order reversed value */ function byteReverse(uint256 input) pure returns (uint256 v) { v = input; uint256 MASK08 = 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00; uint256 MASK16 = 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000; uint256 MASK32 = 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000; uint256 MASK64 = 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000; // swap bytes v = ((v & MASK08) >> 8) | ((v & (~MASK08)) << 8); // swap 2-byte long pairs v = ((v & MASK16) >> 16) | ((v & (~MASK16)) << 16); // swap 4-byte long pairs v = ((v & MASK32) >> 32) | ((v & (~MASK32)) << 32); // swap 8-byte long pairs v = ((v & MASK64) >> 64) | ((v & (~MASK64)) << 64); // swap 16-byte long pairs v = (v >> 128) | (v << 128); } /** * @notice reads a 32-byte hash from its little-endian word-encoded form * @param words the hash words * @return the hash */ function readHashWords(uint256[] calldata words) pure returns (bytes32) { uint256 mask = 0xffffffffffffffff; uint256 result = (words[0] & mask); result |= (words[1] & mask) << 0x40; result |= (words[2] & mask) << 0x80; result |= (words[3] & mask) << 0xc0; return bytes32(byteReverse(result)); }
/// SPDX-License-Identifier: UNLICENSED /// (c) Theori, Inc. 2022 /// All rights reserved pragma solidity >=0.8.0; /** * @title RLP * @author Theori, Inc. * @notice Gas optimized RLP parsing code. Note that some parsing logic is * duplicated because helper functions are oddly expensive. */ library RLP { function parseUint(bytes calldata buf) internal pure returns (uint256 result, uint256 size) { assembly { // check that we have at least one byte of input if iszero(buf.length) { revert(0, 0) } let first32 := calldataload(buf.offset) let kind := shr(248, first32) // ensure it's a not a long string or list (> 0xB7) // also ensure it's not a short string longer than 32 bytes (> 0xA0) if gt(kind, 0xA0) { revert(0, 0) } switch lt(kind, 0x80) case true { // small single byte result := kind size := 1 } case false { // short string size := sub(kind, 0x80) // ensure it's not reading out of bounds if lt(buf.length, size) { revert(0, 0) } switch eq(size, 32) case true { // if it's exactly 32 bytes, read it from calldata result := calldataload(add(buf.offset, 1)) } case false { // if it's < 32 bytes, we've already read it from calldata result := shr(shl(3, sub(32, size)), shl(8, first32)) } size := add(size, 1) } } } function nextSize(bytes calldata buf) internal pure returns (uint256 size) { assembly { if iszero(buf.length) { revert(0, 0) } let first32 := calldataload(buf.offset) let kind := shr(248, first32) switch lt(kind, 0x80) case true { // small single byte size := 1 } case false { switch lt(kind, 0xB8) case true { // short string size := add(1, sub(kind, 0x80)) } case false { switch lt(kind, 0xC0) case true { // long string let lengthSize := sub(kind, 0xB7) // ensure that we don't overflow if gt(lengthSize, 31) { revert(0, 0) } // ensure that we don't read out of bounds if lt(buf.length, lengthSize) { revert(0, 0) } size := shr(mul(8, sub(32, lengthSize)), shl(8, first32)) size := add(size, add(1, lengthSize)) } case false { switch lt(kind, 0xF8) case true { // short list size := add(1, sub(kind, 0xC0)) } case false { let lengthSize := sub(kind, 0xF7) // ensure that we don't overflow if gt(lengthSize, 31) { revert(0, 0) } // ensure that we don't read out of bounds if lt(buf.length, lengthSize) { revert(0, 0) } size := shr(mul(8, sub(32, lengthSize)), shl(8, first32)) size := add(size, add(1, lengthSize)) } } } } } } function skip(bytes calldata buf) internal pure returns (bytes calldata) { uint256 size = RLP.nextSize(buf); assembly { buf.offset := add(buf.offset, size) buf.length := sub(buf.length, size) } return buf; } function parseList(bytes calldata buf) internal pure returns (uint256 listSize, uint256 offset) { assembly { // check that we have at least one byte of input if iszero(buf.length) { revert(0, 0) } let first32 := calldataload(buf.offset) let kind := shr(248, first32) // ensure it's a list if lt(kind, 0xC0) { revert(0, 0) } switch lt(kind, 0xF8) case true { // short list listSize := sub(kind, 0xC0) offset := 1 } case false { // long list let lengthSize := sub(kind, 0xF7) // ensure that we don't overflow if gt(lengthSize, 31) { revert(0, 0) } // ensure that we don't read out of bounds if lt(buf.length, lengthSize) { revert(0, 0) } listSize := shr(mul(8, sub(32, lengthSize)), shl(8, first32)) offset := add(lengthSize, 1) } } } function splitBytes(bytes calldata buf) internal pure returns (bytes calldata result, bytes calldata rest) { uint256 offset; uint256 size; assembly { // check that we have at least one byte of input if iszero(buf.length) { revert(0, 0) } let first32 := calldataload(buf.offset) let kind := shr(248, first32) // ensure it's a not list if gt(kind, 0xBF) { revert(0, 0) } switch lt(kind, 0x80) case true { // small single byte offset := 0 size := 1 } case false { switch lt(kind, 0xB8) case true { // short string offset := 1 size := sub(kind, 0x80) } case false { // long string let lengthSize := sub(kind, 0xB7) // ensure that we don't overflow if gt(lengthSize, 31) { revert(0, 0) } // ensure we don't read out of bounds if lt(buf.length, lengthSize) { revert(0, 0) } size := shr(mul(8, sub(32, lengthSize)), shl(8, first32)) offset := add(lengthSize, 1) } } result.offset := add(buf.offset, offset) result.length := size let end := add(offset, size) rest.offset := add(buf.offset, end) rest.length := sub(buf.length, end) } } function encodeUint(uint256 value) internal pure returns (bytes memory) { // allocate our result bytes bytes memory result = new bytes(33); if (value == 0) { // store length = 1, value = 0x80 assembly { mstore(add(result, 1), 0x180) } return result; } if (value < 128) { // store length = 1, value = value assembly { mstore(add(result, 1), or(0x100, value)) } return result; } if (value > 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) { // length 33, prefix 0xa0 followed by value assembly { mstore(add(result, 1), 0x21a0) mstore(add(result, 33), value) } return result; } if (value > 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) { // length 32, prefix 0x9f followed by value assembly { mstore(add(result, 1), 0x209f) mstore(add(result, 33), shl(8, value)) } return result; } assembly { let length := 1 for { let min := 0x100 } lt(sub(min, 1), value) { min := shl(8, min) } { length := add(length, 1) } let bytesLength := add(length, 1) // bytes length field let hi := shl(mul(bytesLength, 8), bytesLength) // rlp encoding of value let lo := or(shl(mul(length, 8), add(length, 0x80)), value) mstore(add(result, bytesLength), or(hi, lo)) } return result; } }
{ "evmVersion": "london", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 1000 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"uint256[]","name":"sizes","type":"uint256[]"},{"internalType":"contract IRecursiveVerifier[]","name":"_verifiers","type":"address[]"},{"internalType":"address","name":"_reliquary","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"auxiliaryRoot","type":"bytes32"}],"name":"ImportMerkleRoot","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newSigner","type":"address"}],"name":"NewSigner","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"},{"inputs":[],"name":"ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QUERY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"idx","type":"uint256"}],"name":"auxRoots","outputs":[{"internalType":"bytes32","name":"root","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"earliestRoot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"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":"uint256","name":"endBlock","type":"uint256"},{"components":[{"components":[{"internalType":"uint256[34]","name":"base","type":"uint256[34]"},{"internalType":"uint256[16]","name":"subproofLimbs","type":"uint256[16]"},{"internalType":"uint256[]","name":"inputs","type":"uint256[]"}],"internalType":"struct RecursiveProof","name":"inner","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct SignedRecursiveProof","name":"proof","type":"tuple"},{"internalType":"bytes32[]","name":"roots","type":"bytes32[]"},{"internalType":"bytes32[]","name":"aux","type":"bytes32[]"},{"internalType":"bytes","name":"connectProof","type":"bytes"}],"name":"importLast","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint256[34]","name":"base","type":"uint256[34]"},{"internalType":"uint256[16]","name":"subproofLimbs","type":"uint256[16]"},{"internalType":"uint256[]","name":"inputs","type":"uint256[]"}],"internalType":"struct RecursiveProof","name":"inner","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct SignedRecursiveProof","name":"proof","type":"tuple"},{"internalType":"bytes32[]","name":"roots","type":"bytes32[]"},{"internalType":"bytes32[]","name":"aux","type":"bytes32[]"}],"name":"importParent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"parentHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reliquary","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","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":"bool","name":"_needsAuth","type":"bool"}],"name":"setNeedsAuth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"uint256","name":"num","type":"uint256"},{"internalType":"bytes","name":"proof","type":"bytes"}],"name":"validBlockHash","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"verifiers","outputs":[{"internalType":"contract IRecursiveVerifier","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60a06040523480156200001157600080fd5b50604051620031eb380380620031eb83398101604081905262000034916200037f565b62000041600033620001b7565b6200006d7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177533620001b7565b620000997f49fbb2dfcd7338090911494f07df6bed9cd3c3f3d06c747324f545174e6e30c533620001b7565b6001600160a01b038116608052600180546001600160a01b031916331790558151835114620000c757600080fd5b60005b8351811015620001ad5760006001600160a01b031660026000868481518110620000f857620000f862000458565b6020908102919091018101518252810191909152604001600020546001600160a01b0316146200012757600080fd5b8281815181106200013c576200013c62000458565b6020026020010151600260008684815181106200015d576200015d62000458565b6020026020010151815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055508080620001a4906200046e565b915050620000ca565b5050505062000496565b620001c38282620001c7565b5050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16620001c3576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620002233390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715620002a857620002a862000267565b604052919050565b60006001600160401b03821115620002cc57620002cc62000267565b5060051b60200190565b6001600160a01b0381168114620002ec57600080fd5b50565b600082601f8301126200030157600080fd5b815160206200031a6200031483620002b0565b6200027d565b82815260059290921b840181019181810190868411156200033a57600080fd5b8286015b84811015620003625780516200035481620002d6565b83529183019183016200033e565b509695505050505050565b80516200037a81620002d6565b919050565b6000806000606084860312156200039557600080fd5b83516001600160401b0380821115620003ad57600080fd5b818601915086601f830112620003c257600080fd5b81516020620003d56200031483620002b0565b82815260059290921b8401810191818101908a841115620003f557600080fd5b948201945b838610156200041557855182529482019490820190620003fa565b918901519197509093505050808211156200042f57600080fd5b506200043e86828701620002ef565b9250506200044f604085016200036d565b90509250925092565b634e487b7160e01b600052603260045260246000fd5b6000600182016200048f57634e487b7160e01b600052601160045260246000fd5b5060010190565b608051612d32620004b96000396000818161034a01526109560152612d326000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c80636c19e783116100d8578063ac1eff681161008c578063ea5c100611610066578063ea5c10061461036c578063f50ef57d1461037f578063fd9a40b61461039257600080fd5b8063ac1eff6814610309578063d547741f14610332578063e754de631461034557600080fd5b806383383897116100bd57806383383897146102c157806391d14854146102ca578063a217fddf1461030157600080fd5b80636c19e7831461028757806375b238fc1461029a57600080fd5b80633fa218061161012f57806351a9f1e61161011457806351a9f1e6146102445780635ea2759f1461024d57806367a1ce711461026057600080fd5b80633fa2180614610228578063425516d21461023157600080fd5b8063248a9ca311610160578063248a9ca3146101cf5780632f2ff15d1461020057806336568abe1461021557600080fd5b806301ffc9a71461017c578063238ac933146101a4575b600080fd5b61018f61018a3660046125b1565b6103a5565b60405190151581526020015b60405180910390f35b6001546101b7906001600160a01b031681565b6040516001600160a01b03909116815260200161019b565b6101f26101dd3660046125f3565b60009081526020819052604090206001015490565b60405190815260200161019b565b61021361020e366004612628565b61043e565b005b610213610223366004612628565b610468565b6101f260055481565b61021361023f3660046126f3565b6104f9565b6101f260035481565b61021361025b3660046127bb565b6106ea565b6101f27f49fbb2dfcd7338090911494f07df6bed9cd3c3f3d06c747324f545174e6e30c581565b610213610295366004612850565b610829565b6101f27fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177581565b6101f260045481565b61018f6102d8366004612628565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6101f2600081565b6101b76103173660046125f3565b6002602052600090815260409020546001600160a01b031681565b610213610340366004612628565b6108da565b6101b77f000000000000000000000000000000000000000000000000000000000000000081565b6101f261037a3660046125f3565b6108ff565b61018f61038d36600461286b565b610949565b6102136103a03660046128cc565b6109dc565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061043857507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60008281526020819052604090206001015461045981610a1a565b6104638383610a27565b505050565b6001600160a01b03811633146104eb5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b6104f58282610ac5565b5050565b6120006105078960016128ff565b610511919061292d565b156105845760405162461bcd60e51b815260206004820152602560248201527f656e64426c6f636b206d75737420656e642061742061206368756e6b20626f7560448201527f6e6461727900000000000000000000000000000000000000000000000000000060648201526084016104e2565b60006105938888888888610b44565b90506105a381602001518a610dc8565b610603576105b781602001518a8585610dec565b6106035760405162461bcd60e51b815260206004820152601460248201527f636f6e6e65637450726f6f6620696e76616c696400000000000000000000000060448201526064016104e2565b6000866120006106148c60016128ff565b61061e9190612941565b6106289190612955565b600554909150600003610651576003541561064257600080fd5b815160035560048190556106c9565b6005548251146106c95760405162461bcd60e51b815260206004820152602360248201527f70726f6f6620646f65736e277420636f6e6e6563742077697468206c6173744860448201527f617368000000000000000000000000000000000000000000000000000000000060648201526084016104e2565b60208201516005556106de8189898989610f02565b50505050505050505050565b600354158015906106fc575060045415155b61076e5760405162461bcd60e51b815260206004820152602760248201527f696d706f7274206e6f742073746172746564206f7220616c726561647920636f60448201527f6d706c657465640000000000000000000000000000000000000000000000000060648201526084016104e2565b600061077d8686868686610b44565b90508060200151600354146107fa5760405162461bcd60e51b815260206004820152602560248201527f70726f6f6620646f65736e277420636f6e6e656374207769746820706172656e60448201527f744861736800000000000000000000000000000000000000000000000000000060648201526084016104e2565b60045460009061080b908690612955565b905061081a8187878787610f02565b90516003556004555050505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561085381610a1a565b6001546001600160a01b0380841691160361086d57600080fd5b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0384169081179091556040519081527fffafe5c39be83f4bcf20d7e1a150f6e21c1858ea0948315ba84b6b1c386d45bb9060200160405180910390a15050565b6000828152602081905260409020600101546108f581610a1a565b6104638383610ac5565b60085460009060ff1615610936576109367f49fbb2dfcd7338090911494f07df6bed9cd3c3f3d06c747324f545174e6e30c5610a1a565b5060009081526007602052604090205490565b6000336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806109b057503360009081527f8d07f6acc18f6c06a34101d6d4494dd029b316058993396e828b51be0fdd5090602052604090205460ff165b6109b957600080fd5b4384106109c557600080fd5b6109d185858585611009565b90505b949350505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610a0681610a1a565b506008805460ff1916911515919091179055565b610a2481336110cf565b50565b6000828152602081815260408083206001600160a01b038516845290915290205460ff166104f5576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055610a813390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16156104f5576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b604080516080810182526000808252602082018190529181018290526060810191909152610b73600185612955565b841615610be85760405162461bcd60e51b815260206004820152602160248201527f726f6f7473206c656e677468206d757374206265206120706f776572206f662060448201527f320000000000000000000000000000000000000000000000000000000000000060648201526084016104e2565b838214610c375760405162461bcd60e51b815260206004820181905260248201527f726f6f747320617272617973206d7573742062652073616d65206c656e67746860448201526064016104e2565b610c4086611142565b9050610c7e85858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061120e92505050565b816040015114610cd05760405162461bcd60e51b815260206004820152601360248201527f696e76616c696420626c6f636b20726f6f74730000000000000000000000000060448201526064016104e2565b610d0c83838080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061128492505050565b816060015114610d5e5760405162461bcd60e51b815260206004820152601160248201527f696e76616c69642061757820726f6f747300000000000000000000000000000060448201526064016104e2565b610d7386610d6e8661200061296c565b6112d6565b610dbf5760405162461bcd60e51b815260206004820152600d60248201527f696e76616c696420534e41524b0000000000000000000000000000000000000060448201526064016104e2565b95945050505050565b6000610100610dd78343612955565b11158015610de55750828240145b9392505050565b60008281610e05610e00604084018461298b565b611142565b9050610e1981602001518360200135610dc8565b610e28576000925050506109d4565b610e3f610e38604084018461298b565b83356112d6565b610e4e576000925050506109d4565b60008235610e61602085013560016128ff565b610e6b9190612955565b9050610e78600182612955565b87148015610e865750815188145b15610e9757600193505050506109d4565b6000610ea38289612955565b6040840151909150610ef590828b610ebe60608901896129ab565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506113f892505050565b9998505050505050505050565b60005b83811015611001576000610f1982886128ff565b9050858583818110610f2d57610f2d6129f5565b905060200201356006600083815260200190815260200160002081905550838383818110610f5d57610f5d6129f5565b905060200201356007600083815260200190815260200160002081905550807f49901d0580efb62ec337e62803189da8862b97999943a30de0b95446ae61daee878785818110610faf57610faf6129f5565b90506020020135868686818110610fc857610fc86129f5565b90506020020135604051610fe6929190918252602082015260400190565b60405180910390a25080610ff981612a0b565b915050610f05565b505050505050565b60006110158585610dc8565b15611022575060016109d4565b600061102e848461147b565b90955093509050600081600181111561104957611049612a24565b036110625761105a86868686611514565b9150506109d4565b600181600181111561107657611076612a24565b036110875761105a86868686610dec565b60405162461bcd60e51b815260206004820152601260248201527f696e76616c69642070726f6f662074797065000000000000000000000000000060448201526064016104e2565b6000828152602081815260408083206001600160a01b038516845290915290205460ff166104f557611100816115c7565b61110b8360206115d9565b60405160200161111c929190612a6a565b60408051601f198184030181529082905262461bcd60e51b82526104e291600401612aeb565b6040805160808101825260008082526020820181905291810182905260608101919091523660006111738480612b1e565b611182906106408101906129ab565b9092509050600d811461119457600080fd5b6040805160808101909152806111b66111b1600460008688612b35565b6117ba565b81526020016111cc6111b1600860048688612b35565b81526020016111e26111b1600c60088688612b35565b81526020018383600c8181106111fa576111fa6129f5565b602002919091013590915250949350505050565b80516000905b600181111561126157602083018060005b838110156112565760208360408460025afa61124057600080fd5b6020929092019160409190910190600201611225565b50505060011c611214565b82600081518110611274576112746129f5565b6020026020010151915050919050565b80516000905b60018111156112615760005b600282048110156112cd576040808202850160208101519101516112ba828261198f565b6020808502880101525050600101611296565b5060011c61128a565b6001546000906001600160a01b0316801580159061130e5750806001600160a01b031661130285611a58565b6001600160a01b031614155b1561131d576000915050610438565b6000838152600260205260409020546001600160a01b0316806113825760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964206e756d426c6f636b7300000000000000000000000000000060448201526064016104e2565b6001600160a01b038116632efb216b61139b8780612b1e565b6040518263ffffffff1660e01b81526004016113b79190612b63565b602060405180830381865afa1580156113d4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dbf9190612c21565b6000828251602084016020820281019150805b8281101561146d57805160018916801561142c576001811461143957611442565b8560005281602052611442565b81600052856020525b5050602060006040600060025afa61145957600080fd5b60005160019890981c97935060200161140b565b505050909414949350505050565b60003681836114cc5760405162461bcd60e51b815260206004820152601760248201527f63616e6e6f742070617273652070726f6f66207479706500000000000000000060448201526064016104e2565b848460008181106114df576114df6129f5565b919091013560f81c905060018111156114fa576114fa612a24565b92506115098460018188612c3e565b915091509250925092565b60008060068161152661200088612941565b8152602001908152602001600020549050806000801b0361154b5760009150506109d4565b3660006115588686611b2d565b9092509050600d811461157157600093505050506109d4565b6115bb836115816120008a61292d565b8a8585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506113f892505050565b98975050505050505050565b60606104386001600160a01b03831660145b606060006115e883600261296c565b6115f39060026128ff565b67ffffffffffffffff81111561160b5761160b612c68565b6040519080825280601f01601f191660200182016040528015611635576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061166c5761166c6129f5565b60200101906001600160f81b031916908160001a9053507f7800000000000000000000000000000000000000000000000000000000000000816001815181106116b7576116b76129f5565b60200101906001600160f81b031916908160001a90535060006116db84600261296c565b6116e69060016128ff565b90505b600181111561176b577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110611727576117276129f5565b1a60f81b82828151811061173d5761173d6129f5565b60200101906001600160f81b031916908160001a90535060049490941c9361176481612c7e565b90506116e9565b508315610de55760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016104e2565b600067ffffffffffffffff8181858583816117d7576117d76129f5565b90506020020135169050604082868660018181106117f7576117f76129f5565b9050602002013516901b811790506080828686600281811061181b5761181b6129f5565b9050602002013516901b8117905060c0828686600381811061183f5761183f6129f5565b9050602002013516901b81179050610dbf817bffffffff000000000000000000000000ffffffff00000000000000007eff000000ff000000ff000000ff000000ff000000ff000000ff000000ff0000600883811c9182167fff000000ff000000ff000000ff000000ff000000ff000000ff000000ff0000009490911b93841617601090811c7cff000000ff000000ff000000ff000000ff000000ff000000ff000000ff9092167dff000000ff000000ff000000ff000000ff000000ff000000ff000000ff009094169390931790921b91909117602081811c9283167fffffffff000000000000000000000000ffffffff0000000000000000000000009290911b91821617604090811c73ffffffff000000000000000000000000ffffffff90931677ffffffff000000000000000000000000ffffffff0000000090921691909117901b17608081811c91901b1790565b600080600080516020612cdd833981519152838508905060008060005b6013811015611a1b576119be81611b60565b9093509150600080516020612cdd8339815191528388089650600080516020612cdd83398151915282870895506119f5878761215a565b9097509550611a048787612194565b909750955080611a1381612a0b565b9150506119ac565b50611a26868661215a565b9096509450600080516020612cdd83398151915283600080516020612cdd833981519152878908089695505050505050565b600080611a6d611a688480612b1e565b6122a4565b6040517f19457468657265756d205369676e6564204d6573736167653a0a00000000000060208201527f3332000000000000000000000000000000000000000000000000000000000000603a820152603c810191909152605c01604051602081830303815290604052805190602001209050610de581848060200190611af39190612c95565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506122da92505050565b366000611b3b60208461292d565b15611b4557600080fd5b6020831015611b5357600080fd5b5050506020810191903590565b60008082600003611b9657506025927f135b52945a13d9aa49b9b57c33cd568ba9ae5ce9ca4a2d06e7f3fbd4c666668c92509050565b82600103611be857507f1d851aa3a1ad5cfa398a47d33b9c614f0879e1c79891ea5a21ff8ece689f96a9927f0b9600e2b2bdd62adf15f55c26da154bd4ca3e19ff98c7fc971568d5215b9e2a92509050565b82600203611c3a57507f13cf1ad003eda20a5223e28f2b7aaa5d12d6128ac67cd2dd53ecd2b2695ebd9b927f13ecfefe27ca58493b421659e9cf5c056f879e613101b95cd0d80c9460ad8bae92509050565b82600303611c8c57507f07200ee6f1261ae24b5d9887e7b2955e0e511df646085706304134927f554dd5927f3051f6b4575b550151f0a4d11b0bde4c49579bbfa93cfd88cd1c08fa0ad8285f92509050565b82600403611cde57507f1949a1753252aa42804dc3212af703bba8f85b2fb9ed269c87537a8729a9c055927f18d262fe1684723d7a37ad0a2b8cce9b28b3a38c63d8d73d868745950bf4fa4792509050565b82600503611d3057507f208e8894681bab57e9469e78383500b5b80787320bf51735e884e0e57760d21d927f124d150dd5ca235c52ff9be5db1309e00c4476d05105e0909423822db70ea18592509050565b82600603611d8257507f08042f50d6fde723aa9b666fbaaeb8167846c47f5ae31f113fee0d0d8c59a6be927f2e3796b9718260f8a9d4787313e2a4d9619f1550f7b6368c17d40a7ee75792be92509050565b82600703611dd457507f010636a632dfd37321d8db96bf4edb26218ffdbed735817b1251aafbb326e8bf927f0434ead34c59b1208b4536cfa7b378a6d85d6f7dc613ec33cd23f0cdf2fa97de92509050565b82600803611e2657507f2690def299310b1e5ffd20b0f76b16c4d3a93900dcaccaffcbbba0ab1f5c2981927f1ff3dd7d9e9a28afb5fe76bd90d446e6cc7c62e437054d826bd2bdf308736b0492509050565b82600903611e7857507f17caa1a332d82688b206471cbd9c861a0a0c71c421ec35cb382d33f055ec3730927f1752085ba9964afe3cbde284d496afaee92dab06f8b99a0287aa3b6c0608cc6392509050565b82600a03611eca57507f037021e76044464089e5f4964d1d172947c91f5adc2f36ad36dadd6dd134be6d927f25bc8ef554367127acb079907da14304f1a0d4ebd8b4b70c2cf08c56f4f878d992509050565b82600b03611f1c57507f11a77f05482b4d24e84fcc06d71704c2e5f9288acca092848bcd318fb80c9f69927f23d0b729d2976dc00d2a7275bfaaeaafdac884006d133c4e94896de7014893b992509050565b82600c03611f6e57507f1528fb21bda777a250b3d6d0c053f1202aca44fc52ec14b519b056cbba1fcecb927f2a55b40fb8b6c0c267b18521e5024a1a6b9f430f852735e2197bb88a09b7e62e92509050565b82600d03611fc057507f27b656d33f3dc3b879ac63999d0bed50518bece8ead6a6b1b7b5486962e06889927f0c2745a06592c06ae9b1b32c591f9760fb9303ce4298f0529c9d0e8f8bfda7f692509050565b82600e0361201257507f1b624e0ad6dcf65d0887d5fe0ff8a493e37e80fcfb8e667a2c64da2741b90b39927f28a22beaca06bdb5d74634cfaeedbfe8f43b2f876b25fdf562b8a9b6f93d9e8292509050565b82600f0361206457507f2ed6144422f782b0c04afff934c27256cfd3ac13541db0b61bcf022b6538d432927f1103c859880bfb49b748d6d50647be3825042365676efbd3b964cdecd059981692509050565b826010036120b657507f06ae20043bc1c0491bf2d8968b9ef5611b1b261eb5db7038949c3a548da8ec2c927f02218448bf89f18f4a64f94b904879ca580e3d088e1ebc0655b15f107c3f95ef92509050565b8260110361210857507f0f7ce6c8772669ffe3124a4b13156a3af7be5c1c094c48141beca658ae794798927f1b713066fd2aa6c06be1c510616e13a75b1053f8e703c607ce30e1b55187323b92509050565b8260120361017757507f088ed0990cd88d6f919086db6f56e4a991d8d44b3a5aebac604f59a07777cead927f0f69a06f7adc84762053d61221652e79bc0a88c6434b560d10bc6a09164c476292509050565b600080600080516020612cdd833981519152808460050985089150600080516020612cdd8339815191528083600509840890509250929050565b600080600080516020612cdd83398151915280600080516020612cdd8339815191528586096005096121d490600080516020612cdd833981519152612955565b85089350600080516020612cdd833981519152612220857f26b6a528b427b35493736af8679aad17535cb9d394945a0dcfe7f7a98ccccccd600080516020612cdd8339815191526122fe565b61223890600080516020612cdd833981519152612955565b84089250600080516020612cdd8339815191527f135b52945a13d9aa49b9b57c33cd568ba9ae5ce9ca4a2d06e7f3fbd4c6666667600080516020612cdd83398151915280600080516020612cdd83398151915287880960050987080893508383915091505b9250929050565b600036816122b66106408501856129ab565b60405191935091506106406020830281878437808583850137019020949350505050565b60008060006122e98585612346565b915091506122f681612388565b509392505050565b600060405160208152602080820152602060408201528460608201528360808201528260a082015260208160c08360056107d05a03fa61233d57600080fd5b51949350505050565b600080825160410361237c5760208301516040840151606085015160001a612370878285856124ed565b9450945050505061229d565b5060009050600261229d565b600081600481111561239c5761239c612a24565b036123a45750565b60018160048111156123b8576123b8612a24565b036124055760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016104e2565b600281600481111561241957612419612a24565b036124665760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016104e2565b600381600481111561247a5761247a612a24565b03610a245760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f756500000000000000000000000000000000000000000000000000000000000060648201526084016104e2565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561252457506000905060036125a8565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015612578573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166125a1576000600192509250506125a8565b9150600090505b94509492505050565b6000602082840312156125c357600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610de557600080fd5b60006020828403121561260557600080fd5b5035919050565b80356001600160a01b038116811461262357600080fd5b919050565b6000806040838503121561263b57600080fd5b8235915061264b6020840161260c565b90509250929050565b60006040828403121561266657600080fd5b50919050565b60008083601f84011261267e57600080fd5b50813567ffffffffffffffff81111561269657600080fd5b6020830191508360208260051b850101111561229d57600080fd5b60008083601f8401126126c357600080fd5b50813567ffffffffffffffff8111156126db57600080fd5b60208301915083602082850101111561229d57600080fd5b60008060008060008060008060a0898b03121561270f57600080fd5b88359750602089013567ffffffffffffffff8082111561272e57600080fd5b61273a8c838d01612654565b985060408b013591508082111561275057600080fd5b61275c8c838d0161266c565b909850965060608b013591508082111561277557600080fd5b6127818c838d0161266c565b909650945060808b013591508082111561279a57600080fd5b506127a78b828c016126b1565b999c989b5096995094979396929594505050565b6000806000806000606086880312156127d357600080fd5b853567ffffffffffffffff808211156127eb57600080fd5b6127f789838a01612654565b9650602088013591508082111561280d57600080fd5b61281989838a0161266c565b9096509450604088013591508082111561283257600080fd5b5061283f8882890161266c565b969995985093965092949392505050565b60006020828403121561286257600080fd5b610de58261260c565b6000806000806060858703121561288157600080fd5b8435935060208501359250604085013567ffffffffffffffff8111156128a657600080fd5b6128b2878288016126b1565b95989497509550505050565b8015158114610a2457600080fd5b6000602082840312156128de57600080fd5b8135610de5816128be565b634e487b7160e01b600052601160045260246000fd5b60008219821115612912576129126128e9565b500190565b634e487b7160e01b600052601260045260246000fd5b60008261293c5761293c612917565b500690565b60008261295057612950612917565b500490565b600082821015612967576129676128e9565b500390565b6000816000190483118215151615612986576129866128e9565b500290565b60008235603e198336030181126129a157600080fd5b9190910192915050565b6000808335601e198436030181126129c257600080fd5b83018035915067ffffffffffffffff8211156129dd57600080fd5b6020019150600581901b360382131561229d57600080fd5b634e487b7160e01b600052603260045260246000fd5b600060018201612a1d57612a1d6128e9565b5060010190565b634e487b7160e01b600052602160045260246000fd5b60005b83811015612a55578181015183820152602001612a3d565b83811115612a64576000848401525b50505050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351612aa2816017850160208801612a3a565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351612adf816028840160208801612a3a565b01602801949350505050565b6020815260008251806020840152612b0a816040850160208701612a3a565b601f01601f19169190910160400192915050565b6000823561065e198336030181126129a157600080fd5b60008085851115612b4557600080fd5b83861115612b5257600080fd5b5050600583901b0193919092039150565b6020815260006104408084602085013761020081850161046085013750610660610640840135601e19853603018112612b9b57600080fd5b8401803567ffffffffffffffff811115612bb457600080fd5b8060051b803603871315612bc757600080fd5b8384870152816106808701526106a093507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821115612c0557600080fd5b8060208401858801376000950190920193845250919392505050565b600060208284031215612c3357600080fd5b8151610de5816128be565b60008085851115612c4e57600080fd5b83861115612c5b57600080fd5b5050820193919092039150565b634e487b7160e01b600052604160045260246000fd5b600081612c8d57612c8d6128e9565b506000190190565b6000808335601e19843603018112612cac57600080fd5b83018035915067ffffffffffffffff821115612cc757600080fd5b60200191503681900382131561229d57600080fdfe30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a264697066735822122023ea0263ab984210c155189232ce9b290064e8d52b614fcd898b409b34c5d0bc64736f6c634300080d0033000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001800000000000000000000000005e4de6bb8c6824f29c44bd3473d44da120387d08000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000099dfc2aec28741c9b94c7f001a73f8198f15b5cb000000000000000000000000f90a774c3a9f7e913b2a7ce18e9e055e68720a16000000000000000000000000ea0818567477312001af788310190afa25f47084000000000000000000000000eb30405c22fa38c7fa51245e52a22ccbf4864d4c000000000000000000000000e70aa7bfd3efb5061d45e1ea65a0c1537c0b36d000000000000000000000000028d8c05ab477410e039dc4ea2503b25f99b6f20300000000000000000000000058576fca4eb2993a9b49af7f5ec2b3e86450914000000000000000000000000069bf5a3e122b8965dc4568f796bdbdd6bfaf9220
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101775760003560e01c80636c19e783116100d8578063ac1eff681161008c578063ea5c100611610066578063ea5c10061461036c578063f50ef57d1461037f578063fd9a40b61461039257600080fd5b8063ac1eff6814610309578063d547741f14610332578063e754de631461034557600080fd5b806383383897116100bd57806383383897146102c157806391d14854146102ca578063a217fddf1461030157600080fd5b80636c19e7831461028757806375b238fc1461029a57600080fd5b80633fa218061161012f57806351a9f1e61161011457806351a9f1e6146102445780635ea2759f1461024d57806367a1ce711461026057600080fd5b80633fa2180614610228578063425516d21461023157600080fd5b8063248a9ca311610160578063248a9ca3146101cf5780632f2ff15d1461020057806336568abe1461021557600080fd5b806301ffc9a71461017c578063238ac933146101a4575b600080fd5b61018f61018a3660046125b1565b6103a5565b60405190151581526020015b60405180910390f35b6001546101b7906001600160a01b031681565b6040516001600160a01b03909116815260200161019b565b6101f26101dd3660046125f3565b60009081526020819052604090206001015490565b60405190815260200161019b565b61021361020e366004612628565b61043e565b005b610213610223366004612628565b610468565b6101f260055481565b61021361023f3660046126f3565b6104f9565b6101f260035481565b61021361025b3660046127bb565b6106ea565b6101f27f49fbb2dfcd7338090911494f07df6bed9cd3c3f3d06c747324f545174e6e30c581565b610213610295366004612850565b610829565b6101f27fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177581565b6101f260045481565b61018f6102d8366004612628565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6101f2600081565b6101b76103173660046125f3565b6002602052600090815260409020546001600160a01b031681565b610213610340366004612628565b6108da565b6101b77f0000000000000000000000005e4de6bb8c6824f29c44bd3473d44da120387d0881565b6101f261037a3660046125f3565b6108ff565b61018f61038d36600461286b565b610949565b6102136103a03660046128cc565b6109dc565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061043857507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60008281526020819052604090206001015461045981610a1a565b6104638383610a27565b505050565b6001600160a01b03811633146104eb5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b6104f58282610ac5565b5050565b6120006105078960016128ff565b610511919061292d565b156105845760405162461bcd60e51b815260206004820152602560248201527f656e64426c6f636b206d75737420656e642061742061206368756e6b20626f7560448201527f6e6461727900000000000000000000000000000000000000000000000000000060648201526084016104e2565b60006105938888888888610b44565b90506105a381602001518a610dc8565b610603576105b781602001518a8585610dec565b6106035760405162461bcd60e51b815260206004820152601460248201527f636f6e6e65637450726f6f6620696e76616c696400000000000000000000000060448201526064016104e2565b6000866120006106148c60016128ff565b61061e9190612941565b6106289190612955565b600554909150600003610651576003541561064257600080fd5b815160035560048190556106c9565b6005548251146106c95760405162461bcd60e51b815260206004820152602360248201527f70726f6f6620646f65736e277420636f6e6e6563742077697468206c6173744860448201527f617368000000000000000000000000000000000000000000000000000000000060648201526084016104e2565b60208201516005556106de8189898989610f02565b50505050505050505050565b600354158015906106fc575060045415155b61076e5760405162461bcd60e51b815260206004820152602760248201527f696d706f7274206e6f742073746172746564206f7220616c726561647920636f60448201527f6d706c657465640000000000000000000000000000000000000000000000000060648201526084016104e2565b600061077d8686868686610b44565b90508060200151600354146107fa5760405162461bcd60e51b815260206004820152602560248201527f70726f6f6620646f65736e277420636f6e6e656374207769746820706172656e60448201527f744861736800000000000000000000000000000000000000000000000000000060648201526084016104e2565b60045460009061080b908690612955565b905061081a8187878787610f02565b90516003556004555050505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561085381610a1a565b6001546001600160a01b0380841691160361086d57600080fd5b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0384169081179091556040519081527fffafe5c39be83f4bcf20d7e1a150f6e21c1858ea0948315ba84b6b1c386d45bb9060200160405180910390a15050565b6000828152602081905260409020600101546108f581610a1a565b6104638383610ac5565b60085460009060ff1615610936576109367f49fbb2dfcd7338090911494f07df6bed9cd3c3f3d06c747324f545174e6e30c5610a1a565b5060009081526007602052604090205490565b6000336001600160a01b037f0000000000000000000000005e4de6bb8c6824f29c44bd3473d44da120387d081614806109b057503360009081527f8d07f6acc18f6c06a34101d6d4494dd029b316058993396e828b51be0fdd5090602052604090205460ff165b6109b957600080fd5b4384106109c557600080fd5b6109d185858585611009565b90505b949350505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610a0681610a1a565b506008805460ff1916911515919091179055565b610a2481336110cf565b50565b6000828152602081815260408083206001600160a01b038516845290915290205460ff166104f5576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055610a813390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16156104f5576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b604080516080810182526000808252602082018190529181018290526060810191909152610b73600185612955565b841615610be85760405162461bcd60e51b815260206004820152602160248201527f726f6f7473206c656e677468206d757374206265206120706f776572206f662060448201527f320000000000000000000000000000000000000000000000000000000000000060648201526084016104e2565b838214610c375760405162461bcd60e51b815260206004820181905260248201527f726f6f747320617272617973206d7573742062652073616d65206c656e67746860448201526064016104e2565b610c4086611142565b9050610c7e85858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061120e92505050565b816040015114610cd05760405162461bcd60e51b815260206004820152601360248201527f696e76616c696420626c6f636b20726f6f74730000000000000000000000000060448201526064016104e2565b610d0c83838080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061128492505050565b816060015114610d5e5760405162461bcd60e51b815260206004820152601160248201527f696e76616c69642061757820726f6f747300000000000000000000000000000060448201526064016104e2565b610d7386610d6e8661200061296c565b6112d6565b610dbf5760405162461bcd60e51b815260206004820152600d60248201527f696e76616c696420534e41524b0000000000000000000000000000000000000060448201526064016104e2565b95945050505050565b6000610100610dd78343612955565b11158015610de55750828240145b9392505050565b60008281610e05610e00604084018461298b565b611142565b9050610e1981602001518360200135610dc8565b610e28576000925050506109d4565b610e3f610e38604084018461298b565b83356112d6565b610e4e576000925050506109d4565b60008235610e61602085013560016128ff565b610e6b9190612955565b9050610e78600182612955565b87148015610e865750815188145b15610e9757600193505050506109d4565b6000610ea38289612955565b6040840151909150610ef590828b610ebe60608901896129ab565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506113f892505050565b9998505050505050505050565b60005b83811015611001576000610f1982886128ff565b9050858583818110610f2d57610f2d6129f5565b905060200201356006600083815260200190815260200160002081905550838383818110610f5d57610f5d6129f5565b905060200201356007600083815260200190815260200160002081905550807f49901d0580efb62ec337e62803189da8862b97999943a30de0b95446ae61daee878785818110610faf57610faf6129f5565b90506020020135868686818110610fc857610fc86129f5565b90506020020135604051610fe6929190918252602082015260400190565b60405180910390a25080610ff981612a0b565b915050610f05565b505050505050565b60006110158585610dc8565b15611022575060016109d4565b600061102e848461147b565b90955093509050600081600181111561104957611049612a24565b036110625761105a86868686611514565b9150506109d4565b600181600181111561107657611076612a24565b036110875761105a86868686610dec565b60405162461bcd60e51b815260206004820152601260248201527f696e76616c69642070726f6f662074797065000000000000000000000000000060448201526064016104e2565b6000828152602081815260408083206001600160a01b038516845290915290205460ff166104f557611100816115c7565b61110b8360206115d9565b60405160200161111c929190612a6a565b60408051601f198184030181529082905262461bcd60e51b82526104e291600401612aeb565b6040805160808101825260008082526020820181905291810182905260608101919091523660006111738480612b1e565b611182906106408101906129ab565b9092509050600d811461119457600080fd5b6040805160808101909152806111b66111b1600460008688612b35565b6117ba565b81526020016111cc6111b1600860048688612b35565b81526020016111e26111b1600c60088688612b35565b81526020018383600c8181106111fa576111fa6129f5565b602002919091013590915250949350505050565b80516000905b600181111561126157602083018060005b838110156112565760208360408460025afa61124057600080fd5b6020929092019160409190910190600201611225565b50505060011c611214565b82600081518110611274576112746129f5565b6020026020010151915050919050565b80516000905b60018111156112615760005b600282048110156112cd576040808202850160208101519101516112ba828261198f565b6020808502880101525050600101611296565b5060011c61128a565b6001546000906001600160a01b0316801580159061130e5750806001600160a01b031661130285611a58565b6001600160a01b031614155b1561131d576000915050610438565b6000838152600260205260409020546001600160a01b0316806113825760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964206e756d426c6f636b7300000000000000000000000000000060448201526064016104e2565b6001600160a01b038116632efb216b61139b8780612b1e565b6040518263ffffffff1660e01b81526004016113b79190612b63565b602060405180830381865afa1580156113d4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dbf9190612c21565b6000828251602084016020820281019150805b8281101561146d57805160018916801561142c576001811461143957611442565b8560005281602052611442565b81600052856020525b5050602060006040600060025afa61145957600080fd5b60005160019890981c97935060200161140b565b505050909414949350505050565b60003681836114cc5760405162461bcd60e51b815260206004820152601760248201527f63616e6e6f742070617273652070726f6f66207479706500000000000000000060448201526064016104e2565b848460008181106114df576114df6129f5565b919091013560f81c905060018111156114fa576114fa612a24565b92506115098460018188612c3e565b915091509250925092565b60008060068161152661200088612941565b8152602001908152602001600020549050806000801b0361154b5760009150506109d4565b3660006115588686611b2d565b9092509050600d811461157157600093505050506109d4565b6115bb836115816120008a61292d565b8a8585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506113f892505050565b98975050505050505050565b60606104386001600160a01b03831660145b606060006115e883600261296c565b6115f39060026128ff565b67ffffffffffffffff81111561160b5761160b612c68565b6040519080825280601f01601f191660200182016040528015611635576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061166c5761166c6129f5565b60200101906001600160f81b031916908160001a9053507f7800000000000000000000000000000000000000000000000000000000000000816001815181106116b7576116b76129f5565b60200101906001600160f81b031916908160001a90535060006116db84600261296c565b6116e69060016128ff565b90505b600181111561176b577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110611727576117276129f5565b1a60f81b82828151811061173d5761173d6129f5565b60200101906001600160f81b031916908160001a90535060049490941c9361176481612c7e565b90506116e9565b508315610de55760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016104e2565b600067ffffffffffffffff8181858583816117d7576117d76129f5565b90506020020135169050604082868660018181106117f7576117f76129f5565b9050602002013516901b811790506080828686600281811061181b5761181b6129f5565b9050602002013516901b8117905060c0828686600381811061183f5761183f6129f5565b9050602002013516901b81179050610dbf817bffffffff000000000000000000000000ffffffff00000000000000007eff000000ff000000ff000000ff000000ff000000ff000000ff000000ff0000600883811c9182167fff000000ff000000ff000000ff000000ff000000ff000000ff000000ff0000009490911b93841617601090811c7cff000000ff000000ff000000ff000000ff000000ff000000ff000000ff9092167dff000000ff000000ff000000ff000000ff000000ff000000ff000000ff009094169390931790921b91909117602081811c9283167fffffffff000000000000000000000000ffffffff0000000000000000000000009290911b91821617604090811c73ffffffff000000000000000000000000ffffffff90931677ffffffff000000000000000000000000ffffffff0000000090921691909117901b17608081811c91901b1790565b600080600080516020612cdd833981519152838508905060008060005b6013811015611a1b576119be81611b60565b9093509150600080516020612cdd8339815191528388089650600080516020612cdd83398151915282870895506119f5878761215a565b9097509550611a048787612194565b909750955080611a1381612a0b565b9150506119ac565b50611a26868661215a565b9096509450600080516020612cdd83398151915283600080516020612cdd833981519152878908089695505050505050565b600080611a6d611a688480612b1e565b6122a4565b6040517f19457468657265756d205369676e6564204d6573736167653a0a00000000000060208201527f3332000000000000000000000000000000000000000000000000000000000000603a820152603c810191909152605c01604051602081830303815290604052805190602001209050610de581848060200190611af39190612c95565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506122da92505050565b366000611b3b60208461292d565b15611b4557600080fd5b6020831015611b5357600080fd5b5050506020810191903590565b60008082600003611b9657506025927f135b52945a13d9aa49b9b57c33cd568ba9ae5ce9ca4a2d06e7f3fbd4c666668c92509050565b82600103611be857507f1d851aa3a1ad5cfa398a47d33b9c614f0879e1c79891ea5a21ff8ece689f96a9927f0b9600e2b2bdd62adf15f55c26da154bd4ca3e19ff98c7fc971568d5215b9e2a92509050565b82600203611c3a57507f13cf1ad003eda20a5223e28f2b7aaa5d12d6128ac67cd2dd53ecd2b2695ebd9b927f13ecfefe27ca58493b421659e9cf5c056f879e613101b95cd0d80c9460ad8bae92509050565b82600303611c8c57507f07200ee6f1261ae24b5d9887e7b2955e0e511df646085706304134927f554dd5927f3051f6b4575b550151f0a4d11b0bde4c49579bbfa93cfd88cd1c08fa0ad8285f92509050565b82600403611cde57507f1949a1753252aa42804dc3212af703bba8f85b2fb9ed269c87537a8729a9c055927f18d262fe1684723d7a37ad0a2b8cce9b28b3a38c63d8d73d868745950bf4fa4792509050565b82600503611d3057507f208e8894681bab57e9469e78383500b5b80787320bf51735e884e0e57760d21d927f124d150dd5ca235c52ff9be5db1309e00c4476d05105e0909423822db70ea18592509050565b82600603611d8257507f08042f50d6fde723aa9b666fbaaeb8167846c47f5ae31f113fee0d0d8c59a6be927f2e3796b9718260f8a9d4787313e2a4d9619f1550f7b6368c17d40a7ee75792be92509050565b82600703611dd457507f010636a632dfd37321d8db96bf4edb26218ffdbed735817b1251aafbb326e8bf927f0434ead34c59b1208b4536cfa7b378a6d85d6f7dc613ec33cd23f0cdf2fa97de92509050565b82600803611e2657507f2690def299310b1e5ffd20b0f76b16c4d3a93900dcaccaffcbbba0ab1f5c2981927f1ff3dd7d9e9a28afb5fe76bd90d446e6cc7c62e437054d826bd2bdf308736b0492509050565b82600903611e7857507f17caa1a332d82688b206471cbd9c861a0a0c71c421ec35cb382d33f055ec3730927f1752085ba9964afe3cbde284d496afaee92dab06f8b99a0287aa3b6c0608cc6392509050565b82600a03611eca57507f037021e76044464089e5f4964d1d172947c91f5adc2f36ad36dadd6dd134be6d927f25bc8ef554367127acb079907da14304f1a0d4ebd8b4b70c2cf08c56f4f878d992509050565b82600b03611f1c57507f11a77f05482b4d24e84fcc06d71704c2e5f9288acca092848bcd318fb80c9f69927f23d0b729d2976dc00d2a7275bfaaeaafdac884006d133c4e94896de7014893b992509050565b82600c03611f6e57507f1528fb21bda777a250b3d6d0c053f1202aca44fc52ec14b519b056cbba1fcecb927f2a55b40fb8b6c0c267b18521e5024a1a6b9f430f852735e2197bb88a09b7e62e92509050565b82600d03611fc057507f27b656d33f3dc3b879ac63999d0bed50518bece8ead6a6b1b7b5486962e06889927f0c2745a06592c06ae9b1b32c591f9760fb9303ce4298f0529c9d0e8f8bfda7f692509050565b82600e0361201257507f1b624e0ad6dcf65d0887d5fe0ff8a493e37e80fcfb8e667a2c64da2741b90b39927f28a22beaca06bdb5d74634cfaeedbfe8f43b2f876b25fdf562b8a9b6f93d9e8292509050565b82600f0361206457507f2ed6144422f782b0c04afff934c27256cfd3ac13541db0b61bcf022b6538d432927f1103c859880bfb49b748d6d50647be3825042365676efbd3b964cdecd059981692509050565b826010036120b657507f06ae20043bc1c0491bf2d8968b9ef5611b1b261eb5db7038949c3a548da8ec2c927f02218448bf89f18f4a64f94b904879ca580e3d088e1ebc0655b15f107c3f95ef92509050565b8260110361210857507f0f7ce6c8772669ffe3124a4b13156a3af7be5c1c094c48141beca658ae794798927f1b713066fd2aa6c06be1c510616e13a75b1053f8e703c607ce30e1b55187323b92509050565b8260120361017757507f088ed0990cd88d6f919086db6f56e4a991d8d44b3a5aebac604f59a07777cead927f0f69a06f7adc84762053d61221652e79bc0a88c6434b560d10bc6a09164c476292509050565b600080600080516020612cdd833981519152808460050985089150600080516020612cdd8339815191528083600509840890509250929050565b600080600080516020612cdd83398151915280600080516020612cdd8339815191528586096005096121d490600080516020612cdd833981519152612955565b85089350600080516020612cdd833981519152612220857f26b6a528b427b35493736af8679aad17535cb9d394945a0dcfe7f7a98ccccccd600080516020612cdd8339815191526122fe565b61223890600080516020612cdd833981519152612955565b84089250600080516020612cdd8339815191527f135b52945a13d9aa49b9b57c33cd568ba9ae5ce9ca4a2d06e7f3fbd4c6666667600080516020612cdd83398151915280600080516020612cdd83398151915287880960050987080893508383915091505b9250929050565b600036816122b66106408501856129ab565b60405191935091506106406020830281878437808583850137019020949350505050565b60008060006122e98585612346565b915091506122f681612388565b509392505050565b600060405160208152602080820152602060408201528460608201528360808201528260a082015260208160c08360056107d05a03fa61233d57600080fd5b51949350505050565b600080825160410361237c5760208301516040840151606085015160001a612370878285856124ed565b9450945050505061229d565b5060009050600261229d565b600081600481111561239c5761239c612a24565b036123a45750565b60018160048111156123b8576123b8612a24565b036124055760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016104e2565b600281600481111561241957612419612a24565b036124665760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016104e2565b600381600481111561247a5761247a612a24565b03610a245760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f756500000000000000000000000000000000000000000000000000000000000060648201526084016104e2565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561252457506000905060036125a8565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015612578573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166125a1576000600192509250506125a8565b9150600090505b94509492505050565b6000602082840312156125c357600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610de557600080fd5b60006020828403121561260557600080fd5b5035919050565b80356001600160a01b038116811461262357600080fd5b919050565b6000806040838503121561263b57600080fd5b8235915061264b6020840161260c565b90509250929050565b60006040828403121561266657600080fd5b50919050565b60008083601f84011261267e57600080fd5b50813567ffffffffffffffff81111561269657600080fd5b6020830191508360208260051b850101111561229d57600080fd5b60008083601f8401126126c357600080fd5b50813567ffffffffffffffff8111156126db57600080fd5b60208301915083602082850101111561229d57600080fd5b60008060008060008060008060a0898b03121561270f57600080fd5b88359750602089013567ffffffffffffffff8082111561272e57600080fd5b61273a8c838d01612654565b985060408b013591508082111561275057600080fd5b61275c8c838d0161266c565b909850965060608b013591508082111561277557600080fd5b6127818c838d0161266c565b909650945060808b013591508082111561279a57600080fd5b506127a78b828c016126b1565b999c989b5096995094979396929594505050565b6000806000806000606086880312156127d357600080fd5b853567ffffffffffffffff808211156127eb57600080fd5b6127f789838a01612654565b9650602088013591508082111561280d57600080fd5b61281989838a0161266c565b9096509450604088013591508082111561283257600080fd5b5061283f8882890161266c565b969995985093965092949392505050565b60006020828403121561286257600080fd5b610de58261260c565b6000806000806060858703121561288157600080fd5b8435935060208501359250604085013567ffffffffffffffff8111156128a657600080fd5b6128b2878288016126b1565b95989497509550505050565b8015158114610a2457600080fd5b6000602082840312156128de57600080fd5b8135610de5816128be565b634e487b7160e01b600052601160045260246000fd5b60008219821115612912576129126128e9565b500190565b634e487b7160e01b600052601260045260246000fd5b60008261293c5761293c612917565b500690565b60008261295057612950612917565b500490565b600082821015612967576129676128e9565b500390565b6000816000190483118215151615612986576129866128e9565b500290565b60008235603e198336030181126129a157600080fd5b9190910192915050565b6000808335601e198436030181126129c257600080fd5b83018035915067ffffffffffffffff8211156129dd57600080fd5b6020019150600581901b360382131561229d57600080fd5b634e487b7160e01b600052603260045260246000fd5b600060018201612a1d57612a1d6128e9565b5060010190565b634e487b7160e01b600052602160045260246000fd5b60005b83811015612a55578181015183820152602001612a3d565b83811115612a64576000848401525b50505050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351612aa2816017850160208801612a3a565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351612adf816028840160208801612a3a565b01602801949350505050565b6020815260008251806020840152612b0a816040850160208701612a3a565b601f01601f19169190910160400192915050565b6000823561065e198336030181126129a157600080fd5b60008085851115612b4557600080fd5b83861115612b5257600080fd5b5050600583901b0193919092039150565b6020815260006104408084602085013761020081850161046085013750610660610640840135601e19853603018112612b9b57600080fd5b8401803567ffffffffffffffff811115612bb457600080fd5b8060051b803603871315612bc757600080fd5b8384870152816106808701526106a093507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821115612c0557600080fd5b8060208401858801376000950190920193845250919392505050565b600060208284031215612c3357600080fd5b8151610de5816128be565b60008085851115612c4e57600080fd5b83861115612c5b57600080fd5b5050820193919092039150565b634e487b7160e01b600052604160045260246000fd5b600081612c8d57612c8d6128e9565b506000190190565b6000808335601e19843603018112612cac57600080fd5b83018035915067ffffffffffffffff821115612cc757600080fd5b60200191503681900382131561229d57600080fdfe30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a264697066735822122023ea0263ab984210c155189232ce9b290064e8d52b614fcd898b409b34c5d0bc64736f6c634300080d0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001800000000000000000000000005e4de6bb8c6824f29c44bd3473d44da120387d08000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000099dfc2aec28741c9b94c7f001a73f8198f15b5cb000000000000000000000000f90a774c3a9f7e913b2a7ce18e9e055e68720a16000000000000000000000000ea0818567477312001af788310190afa25f47084000000000000000000000000eb30405c22fa38c7fa51245e52a22ccbf4864d4c000000000000000000000000e70aa7bfd3efb5061d45e1ea65a0c1537c0b36d000000000000000000000000028d8c05ab477410e039dc4ea2503b25f99b6f20300000000000000000000000058576fca4eb2993a9b49af7f5ec2b3e86450914000000000000000000000000069bf5a3e122b8965dc4568f796bdbdd6bfaf9220
-----Decoded View---------------
Arg [0] : sizes (uint256[]): 8192,16384,32768,65536,131072,262144,524288,1048576
Arg [1] : _verifiers (address[]): 0x99DfC2aEc28741C9b94C7F001a73f8198F15B5cb,0xf90A774c3A9f7e913b2A7ce18e9e055E68720A16,0xeA0818567477312001Af788310190aFA25f47084,0xeb30405c22fA38c7fa51245e52a22ccBf4864d4c,0xe70AA7BfD3EFB5061D45E1ea65a0C1537c0B36d0,0x28D8C05aB477410E039dC4ea2503B25F99b6F203,0x58576fca4EB2993A9B49aF7f5eC2b3e864509140,0x69Bf5A3e122B8965DC4568F796bdbdD6BfAf9220
Arg [2] : _reliquary (address): 0x5E4DE6Bb8c6824f29c44Bd3473d44da120387d08
-----Encoded View---------------
21 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000180
Arg [2] : 0000000000000000000000005e4de6bb8c6824f29c44bd3473d44da120387d08
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [4] : 0000000000000000000000000000000000000000000000000000000000002000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000004000
Arg [6] : 0000000000000000000000000000000000000000000000000000000000008000
Arg [7] : 0000000000000000000000000000000000000000000000000000000000010000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000020000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000040000
Arg [10] : 0000000000000000000000000000000000000000000000000000000000080000
Arg [11] : 0000000000000000000000000000000000000000000000000000000000100000
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [13] : 00000000000000000000000099dfc2aec28741c9b94c7f001a73f8198f15b5cb
Arg [14] : 000000000000000000000000f90a774c3a9f7e913b2a7ce18e9e055e68720a16
Arg [15] : 000000000000000000000000ea0818567477312001af788310190afa25f47084
Arg [16] : 000000000000000000000000eb30405c22fa38c7fa51245e52a22ccbf4864d4c
Arg [17] : 000000000000000000000000e70aa7bfd3efb5061d45e1ea65a0c1537c0b36d0
Arg [18] : 00000000000000000000000028d8c05ab477410e039dc4ea2503b25f99b6f203
Arg [19] : 00000000000000000000000058576fca4eb2993a9b49af7f5ec2b3e864509140
Arg [20] : 00000000000000000000000069bf5a3e122b8965dc4568f796bdbdd6bfaf9220
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ 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.