Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60806040 | 20708959 | 13 days ago | IN | 0 ETH | 0.00529579 |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
LPNRegistryV1
Compiler Version
v0.8.25+commit.b61c2a91
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import {OwnableWhitelist} from "../utils/OwnableWhitelist.sol"; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import {RegistrationManager} from "./RegistrationManager.sol"; import {QueryManager} from "./QueryManager.sol"; /// @title LPNRegistryV1 /// @notice A registry contract for managing LPN (Lagrange Proving Network) registrations and requests. contract LPNRegistryV1 is QueryManager, RegistrationManager, OwnableWhitelist, Initializable { function initialize(address owner) external initializer { OwnableWhitelist._initialize(owner); } /// @dev Only owner can register tables currently function registerTable( bytes32 hash, address contractAddr, uint96 chainId, uint256 genesisBlock, string calldata name, string calldata schema ) external onlyOwner { // TODO: Implement payment model _registerTable(hash, contractAddr, chainId, genesisBlock, name, schema); } /// @notice The owner withdraws all fees accumulated function withdrawFees() external onlyOwner returns (bool) { return _withdrawFees(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import {Ownable} from "solady/auth/Ownable.sol"; /// @notice Error thrown when an unauthorized caller attempts to perform an action. error NotAuthorized(); /// @title OwnableWhitelist /// @notice A contract for managing whitelisted addresses. abstract contract OwnableWhitelist is Ownable { event Whitelisted(address addr, bool value); event BatchWhitelisted(address[] addrs, bool value); /// @notice Mapping to track whitelisted addresses. mapping(address => bool) public whitelist; /// @notice Modifier to restrict access to whitelisted addresses only. modifier onlyWhitelist(address someAddress) { if (!whitelist[someAddress]) { revert NotAuthorized(); } _; } function _initialize(address owner) internal { _initializeOwner(owner); } function toggleWhitelist(address client) external onlyOwner { bool newState = !whitelist[client]; whitelist[client] = newState; emit Whitelisted(client, newState); } /// @notice add a batch of addresses to the whitelist. /// @param addrs an array of addresses to add. function addToWhitelist(address[] calldata addrs) external onlyOwner { for (uint256 i; i < addrs.length; i++) { whitelist[addrs[i]] = true; } emit BatchWhitelisted(addrs, true); } /// @notice Remove a batch of addresses from the whitelist. /// @param addrs an array of addresses to remove. function removeFromWhitelist(address[] calldata addrs) external onlyOwner { for (uint256 i; i < addrs.length; i++) { delete whitelist[addrs[i]]; } emit BatchWhitelisted(addrs, false); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly { $.slot := INITIALIZABLE_STORAGE } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import {isEthereum, isOPStack, isMantle, isCDK} from "../utils/Constants.sol"; import {IRegistrationManager} from "./interfaces/IRegistrationManager.sol"; /// @notice Error thrown when attempting to register a table more than once. error TableAlreadyRegistered(); /// @notice Error thrown when attempting to register a query more than once. error QueryAlreadyRegistered(); /// @title RegistrationManager /// @notice TODO contract RegistrationManager is IRegistrationManager { /// @notice Mapping to track registered tables mapping(bytes32 hash => bool registered) public tables; /// @notice Mapping to track registered queries mapping(bytes32 hash => bool registered) public queries; /// @dev Reserves storage slots for future upgrades uint256[48] private __gap; function _registerTable( bytes32 hash, address contractAddr, uint96 chainId, uint256 genesisBlock, string calldata name, // TODO: Should we save name? string calldata schema ) internal { if (tables[hash]) { revert TableAlreadyRegistered(); } tables[hash] = true; // TODO: Do we need this? emit NewTableRegistration( hash, contractAddr, chainId, genesisBlock, name, schema ); } function registerQuery(bytes32 hash, bytes32 tableHash, string calldata sql) external { if (queries[hash]) { revert QueryAlreadyRegistered(); } queries[hash] = true; // TODO: Do we need this? emit NewQueryRegistration(hash, tableHash, sql); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { Groth16VerifierExtensions, QueryInput, QueryOutput } from "./Groth16VerifierExtensions.sol"; import {ILPNClientV1} from "./interfaces/ILPNClientV1.sol"; import {isCDK} from "../utils/Constants.sol"; import {L1BlockHash, L1BlockNumber} from "../utils/L1Block.sol"; import {isEthereum, isOPStack, isMantle, isCDK} from "../utils/Constants.sol"; import {IQueryManager} from "./interfaces/IQueryManager.sol"; /// @notice Error thrown when attempting to query a block number that is after the current block. /// @dev endBlock > block.number error QueryAfterCurrentBlock(); /// @notice Error thrown when attempting to query a range that exceeds the maximum allowed range. /// @dev endBlock - startBlock > MAX_QUERY_RANGE error QueryGreaterThanMaxRange(); /// @notice Error thrown when attempting to query an invalid range. /// @dev startBlock > endBlock error QueryInvalidRange(); /// @notice Error thrown when gas fee is not paid. error InsufficientGasFee(); /// @title QueryManager /// @notice TODO contract QueryManager is IQueryManager { /// @notice The maximum number of blocks a query can be computed over uint256 public constant MAX_QUERY_RANGE = 50_000; /// @notice A constant gas fee paid for each request to reimburse the relayer when it delivers the response uint256 public constant ETH_GAS_FEE = 0.005 ether; uint256 public constant OP_GAS_FEE = 0.00045 ether; uint256 public constant CDK_GAS_FEE = 0.00045 ether; /// @dev Mantle uses a custom gas token uint256 public constant MANTLE_GAS_FEE = 1.5 ether; /// @notice A counter that assigns unique ids for client requests. // TODO: Need to ensure this does not conflict with V0 uint256 public requestId; struct QueryRequest { address client; QueryInput input; } /// @notice Mapping to track requests and their associated clients. mapping(uint256 requestId => QueryRequest query) public requests; /// @dev Reserves storage slots for future upgrades uint256[48] private __gap; modifier requireGasFee() { if (msg.value < gasFee()) { revert InsufficientGasFee(); } _; } /// @notice Validates the query range for a storage contract. /// @param startBlock The starting block number of the query range. /// @param endBlock The ending block number of the query range. /// @dev Reverts with appropriate errors if the query range is invalid: /// - QueryAfterCurrentBlock: If the ending block is after the current block number. /// - QueryInvalidRange: If the starting block is greater than the ending block. /// - QueryGreaterThanMaxRange: If the range (ending block - starting block) exceeds the maximum allowed range. modifier validateQueryRange(uint256 startBlock, uint256 endBlock) { if (!isCDK() && endBlock > L1BlockNumber()) { revert QueryAfterCurrentBlock(); } if (startBlock > endBlock) { revert QueryInvalidRange(); } if (endBlock - startBlock + 1 > MAX_QUERY_RANGE) { revert QueryGreaterThanMaxRange(); } _; } function request( bytes32 queryHash, bytes32[] calldata placeholders, uint256 startBlock, uint256 endBlock ) external payable requireGasFee validateQueryRange(startBlock, endBlock) returns (uint256) { unchecked { requestId++; } uint256 proofBlock = 0; bytes32 blockHash = 0; // TODO: Maybe store proofBlock for L1 queries as well if (!isEthereum()) { proofBlock = L1BlockNumber(); blockHash = L1BlockHash(); } requests[requestId] = QueryRequest({ input: QueryInput({ // TODO: limit: 0, // TODO: offset: 0, minBlockNumber: uint64(startBlock), maxBlockNumber: uint64(endBlock), blockHash: blockHash, computationalHash: queryHash, userPlaceholders: placeholders }), client: msg.sender }); // TODO: Limit and offset separate from placeholders ? emit NewRequest( requestId, queryHash, msg.sender, placeholders, startBlock, endBlock, msg.value, proofBlock ); return requestId; } function respond( uint256 requestId_, bytes32[] calldata data, uint256 blockNumber ) external { QueryRequest memory query = requests[requestId_]; delete requests[requestId_]; if (isEthereum()) { query.input.blockHash = blockhash(blockNumber); } QueryOutput memory result = Groth16VerifierExtensions.processQuery(data, query.input); ILPNClientV1(query.client).lpnCallback(requestId_, result); emit NewResponse(requestId_, query.client, result); } function gasFee() public view returns (uint256) { if (isEthereum()) { return ETH_GAS_FEE; } if (isMantle()) { return MANTLE_GAS_FEE; } if (isOPStack()) { return OP_GAS_FEE; } if (isCDK()) { return CDK_GAS_FEE; } revert("Chain not supported"); } /// @notice The relayer withdraws all fees accumulated function _withdrawFees() internal returns (bool) { (bool sent,) = msg.sender.call{value: address(this).balance}(""); return sent; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple single owner authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// /// @dev Note: /// This implementation does NOT auto-initialize the owner to `msg.sender`. /// You MUST call the `_initializeOwner` in the constructor / initializer. /// /// While the ownable portion follows /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, /// the nomenclature for the 2-step ownership handover may be unique to this codebase. abstract contract Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The caller is not authorized to call the function. error Unauthorized(); /// @dev The `newOwner` cannot be the zero address. error NewOwnerIsZeroAddress(); /// @dev The `pendingOwner` does not have a valid handover request. error NoHandoverRequest(); /// @dev Cannot double-initialize. error AlreadyInitialized(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership is transferred from `oldOwner` to `newOwner`. /// This event is intentionally kept the same as OpenZeppelin's Ownable to be /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), /// despite it not being as lightweight as a single argument event. event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); /// @dev An ownership handover to `pendingOwner` has been requested. event OwnershipHandoverRequested(address indexed pendingOwner); /// @dev The ownership handover to `pendingOwner` has been canceled. event OwnershipHandoverCanceled(address indexed pendingOwner); /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The owner slot is given by: /// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`. /// It is intentionally chosen to be a high value /// to avoid collision with lower slots. /// The choice of manual storage layout is to enable compatibility /// with both regular and upgradeable contracts. bytes32 internal constant _OWNER_SLOT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927; /// The ownership handover slot of `newOwner` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) /// let handoverSlot := keccak256(0x00, 0x20) /// ``` /// It stores the expiry timestamp of the two-step ownership handover. uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Override to return true to make `_initializeOwner` prevent double-initialization. function _guardInitializeOwner() internal pure virtual returns (bool guard) {} /// @dev Initializes the owner directly without authorization guard. /// This function must be called upon initialization, /// regardless of whether the contract is upgradeable or not. /// This is to enable generalization to both regular and upgradeable contracts, /// and to save gas in case the initial owner is not the caller. /// For performance reasons, this function will not check if there /// is an existing owner. function _initializeOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT if sload(ownerSlot) { mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`. revert(0x1c, 0x04) } // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } else { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(_OWNER_SLOT, newOwner) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } } /// @dev Sets the owner directly without authorization guard. function _setOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) } } else { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, newOwner) } } } /// @dev Throws if the sender is not the owner. function _checkOwner() internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner, revert. if iszero(eq(caller(), sload(_OWNER_SLOT))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. /// Override to return a different value if needed. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _ownershipHandoverValidFor() internal view virtual returns (uint64) { return 48 * 3600; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to transfer the ownership to `newOwner`. function transferOwnership(address newOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { if iszero(shl(96, newOwner)) { mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. revert(0x1c, 0x04) } } _setOwner(newOwner); } /// @dev Allows the owner to renounce their ownership. function renounceOwnership() public payable virtual onlyOwner { _setOwner(address(0)); } /// @dev Request a two-step ownership handover to the caller. /// The request will automatically expire in 48 hours (172800 seconds) by default. function requestOwnershipHandover() public payable virtual { unchecked { uint256 expires = block.timestamp + _ownershipHandoverValidFor(); /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to `expires`. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), expires) // Emit the {OwnershipHandoverRequested} event. log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) } } } /// @dev Cancels the two-step ownership handover to the caller, if any. function cancelOwnershipHandover() public payable virtual { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), 0) // Emit the {OwnershipHandoverCanceled} event. log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) } } /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. /// Reverts if there is no existing ownership handover requested by `pendingOwner`. function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) let handoverSlot := keccak256(0x0c, 0x20) // If the handover does not exist, or has expired. if gt(timestamp(), sload(handoverSlot)) { mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. revert(0x1c, 0x04) } // Set the handover slot to 0. sstore(handoverSlot, 0) } _setOwner(pendingOwner); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of the contract. function owner() public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { result := sload(_OWNER_SLOT) } } /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. function ownershipHandoverExpiresAt(address pendingOwner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Compute the handover slot. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) // Load the handover slot. result := sload(keccak256(0x0c, 0x20)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() virtual { _checkOwner(); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import {IOptimismL1Block} from "../interfaces/IOptimismL1Block.sol"; uint256 constant LOCAL = 1337; uint256 constant ANVIL = 31337; uint256 constant ETH_MAINNET = 1; uint256 constant ETH_SEPOLIA = 11155111; uint256 constant ETH_HOLESKY = 17000; uint256 constant BASE_MAINNET = 8453; uint256 constant BASE_SEPOLIA = 84532; uint256 constant FRAXTAL_MAINNET = 252; uint256 constant FRAXTAL_HOLESKY = 2522; uint256 constant MANTLE_SEPOLIA = 5003; uint256 constant MANTLE_MAINNET = 5000; uint256 constant POLYGON_ZKEVM_MAINNET = 1101; address constant OP_STACK_L1_BLOCK_PREDEPLOY_ADDR = 0x4200000000000000000000000000000000000015; address constant L1_BASE_BRIDGE = 0x3154Cf16ccdb4C6d922629664174b904d80F2C35; address constant L1_FRAXTAL_BRIDGE = 0x34C0bD5877A5Ee7099D0f5688D65F4bB9158BDE2; address constant L1_FRAXTAL_HOLESKY_BRIDGE = 0x0BaafC217162f64930909aD9f2B27125121d6332; address constant L1_MANTLE_BRIDGE = 0xb4133552BA49dFb60DA6eb5cA0102d0f94ce071f; address constant L1_MANTLE_SEPOLIA_BRIDGE = 0xf26e9932106E6477a4Ae15dA0eDDCdB985065a1a; address constant PUDGEY_PENGUINS = 0xBd3531dA5CF5857e7CfAA92426877b022e612cf8; uint256 constant PUDGEY_PENGUINS_MAPPING_SLOT = 2; uint256 constant PUDGEY_PENGUINS_LENGTH_SLOT = 8; uint256 constant LAGRANGE_LOONS_MAPPING_SLOT = 2; uint256 constant LAGRANGE_LOONS_LENGTH_SLOT = 8; uint256 constant TEST_ERC20_MAPPING_SLOT = 4; function isEthereum() view returns (bool) { return block.chainid == ETH_MAINNET || block.chainid == ETH_SEPOLIA || block.chainid == ETH_HOLESKY; } function isOPStack() view returns (bool) { uint32 size; assembly { size := extcodesize(OP_STACK_L1_BLOCK_PREDEPLOY_ADDR) } return (size > 0); } function isCDK() view returns (bool) { return block.chainid == POLYGON_ZKEVM_MAINNET; } function isMantle() view returns (bool) { return block.chainid == MANTLE_MAINNET || block.chainid == MANTLE_MAINNET; } function isLocal() view returns (bool) { return block.chainid == LOCAL || block.chainid == ANVIL; } function isTestnet() view returns (bool) { uint256[5] memory testnets = [ ETH_SEPOLIA, ETH_HOLESKY, BASE_SEPOLIA, FRAXTAL_HOLESKY, MANTLE_SEPOLIA ]; return chainMatches(testnets); } function isMainnet() view returns (bool) { uint256[5] memory mainnets = [ ETH_MAINNET, BASE_MAINNET, FRAXTAL_MAINNET, MANTLE_MAINNET, POLYGON_ZKEVM_MAINNET ]; return chainMatches(mainnets); } function chainMatches(uint256[4] memory chains) view returns (bool) { for (uint256 i = 0; i < chains.length; i++) { if (chains[i] == block.chainid) return true; } return false; } function chainMatches(uint256[5] memory chains) view returns (bool) { for (uint256 i = 0; i < chains.length; i++) { if (chains[i] == block.chainid) return true; } return false; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /// @title IRegistrationManager /// @notice interface IRegistrationManager { event NewTableRegistration( bytes32 indexed hash, address indexed contractAddr, uint256 chainId, uint256 genesisBlock, string name, string schema ); event NewQueryRegistration( bytes32 indexed hash, bytes32 indexed tableHash, string sql ); function registerQuery(bytes32 hash, bytes32 tableHash, string calldata sql) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./Groth16Verifier.sol"; import {isCDK} from "../utils/Constants.sol"; // The query input struct passed into the processQuery function struct QueryInput { // Query limit parameter uint32 limit; // Query offset parameter uint32 offset; // Minimum block number uint64 minBlockNumber; // Maximum block number uint64 maxBlockNumber; // Block hash bytes32 blockHash; // Computational hash bytes32 computationalHash; // User placeholder values bytes32[] userPlaceholders; } // The query output struct returned from the processQuery function struct QueryOutput { // Total number of the all matching rows uint256 totalMatchedRows; // Returned rows of the current cursor bytes[] rows; } library Groth16VerifierExtensions { // Top 3 bits mask. uint256 constant TOP_THREE_BIT_MASK = ~(uint256(7) << 253); // Generic constants for the supported queries // TODO: These constants are possible to be changed depending on user queries exploration. // Once we know which queries users are mostly doing, we'll be able to modify these constants. // Maximum number of the results uint32 constant MAX_NUM_OUTPUTS = 3; // Maximum number of the items per result uint32 constant MAX_NUM_ITEMS_PER_OUTPUT = 5; // Maximum number of the placeholders uint32 constant MAX_NUM_PLACEHOLDERS = 10; // The start uint256 offset of the public inputs in calldata. // groth16_proof_number (8) + groth16_input_number (3) uint32 constant PI_OFFSET = 11; // These values are aligned and each is an uint256. // Block hash uint256 position in the public inputs uint32 constant BLOCK_HASH_POS = 0; // Flattened computational hash uint256 position uint32 constant COMPUTATIONAL_HASH_POS = BLOCK_HASH_POS + 1; // Placeholder values uint256 position uint32 constant PLACEHOLDER_VALUES_POS = COMPUTATIONAL_HASH_POS + 1; // Result values uint256 position uint32 constant RESULT_VALUES_POS = PLACEHOLDER_VALUES_POS + MAX_NUM_PLACEHOLDERS; // The remaining items of public inputs are saved in one uint256. // The uint256 offset of the last uint256 of public inputs in calldata. uint32 constant PI_REM_OFFSET = PI_OFFSET + RESULT_VALUES_POS + MAX_NUM_OUTPUTS * MAX_NUM_ITEMS_PER_OUTPUT; // Placeholder number uint32 position in the last uint256 uint32 constant REM_NUM_PLACEHOLDERS_POS = 0; // Result number uint32 position uint32 constant REM_NUM_RESULTS_POS = 1; // Entry count (current result number) uint32 position uint32 constant REM_ENTRY_COUNT_POS = 2; // Overflow flag uint32 position uint32 constant REM_OVERFLOW_POS = 3; // Query limit uint32 position uint32 constant REM_QUERY_LIMIT_POS = 4; // Query offset uint32 position uint32 constant REM_QUERY_OFFSET_POS = 5; // The total byte length of public inputs uint32 constant PI_LEN = 32 * (PI_REM_OFFSET - PI_OFFSET) + (REM_QUERY_OFFSET_POS + 1) * 4; // A computation overflow error during the query process error QueryComputationOverflow(); // The processQuery function does the followings: // 1. Parse the Groth16 proofs (8 uint256) and inputs (3 uint256) from the `data` // argument, and call `verifyProof` function for Groth16 verification. // 2. Calculate sha256 on the public inputs, and set the top 3 bits of this hash to 0. // Then ensure this hash value equals to the last Groth16 input (groth16_inputs[2]). // 3. Parse the items from public inputs, and check as expected for query. // 4. Parse and return the query output from public inputs. function processQuery(bytes32[] calldata data, QueryInput memory query) internal view returns (QueryOutput memory) { // 1. Groth16 verification uint256[3] memory groth16Inputs = verifyGroth16Proof(data); // 2. Ensure the sha256 of public inputs equals to the last Groth16 input. verifyPublicInputs(data, groth16Inputs); // 3. Ensure the items of public inputs equal as expected for query. verifyQuery(data, query); // 4. Parse and return the query output. return parseOutput(data); } // Parse the Groth16 proofs and inputs, do verification, and returns the Groth16 inputs. function verifyGroth16Proof(bytes32[] calldata data) internal view returns (uint256[3] memory) { uint256[8] memory proofs; uint256[3] memory inputs; for (uint32 i = 0; i < 8; ++i) { proofs[i] = uint256(data[i]); } for (uint32 i = 0; i < 3; ++i) { inputs[i] = uint256(data[i + 8]); } // Ensure the sha256 hash equals to the last Groth16 input. require( inputs[0] == uint256(Groth16Verifier.CIRCUIT_DIGEST), "The first Groth16 input must be equal to the circuit digest" ); // Verify the Groth16 proof. Groth16Verifier.verifyProof(proofs, inputs); return inputs; } // Compute sha256 on the public inputs, and ensure it equals to the last Groth16 input. function verifyPublicInputs( bytes32[] calldata data, uint256[3] memory groth16Inputs ) internal pure { // Parse the public inputs from calldata. bytes memory pi = parsePublicInputs(data); // Calculate sha256. uint256 hash = uint256(sha256(pi)); // Set the top 3 bits of the hash value to 0. hash = hash & TOP_THREE_BIT_MASK; // Require the sha256 equals to the last Groth16 input. require( hash == groth16Inputs[2], "The sha256 hash of public inputs must be equal to the last of the Groth16 inputs" ); } // Parse the public inputs from calldata. function parsePublicInputs(bytes32[] calldata data) internal pure returns (bytes memory) { bytes memory pi = new bytes(PI_LEN); // The calldata is encoded as Bytes32. uint256 b32Len = PI_LEN / 32; for (uint256 i = 0; i < b32Len; ++i) { bytes32 b = data[PI_OFFSET + i]; for (uint32 j = 0; j < 32; ++j) { pi[i * 32 + j] = bytes1(b[j]); } } bytes32 rem = data[PI_OFFSET + b32Len]; for (uint32 i = 0; i < PI_LEN % 32; ++i) { pi[b32Len * 32 + i] = rem[i]; } return pi; } // Verify the public inputs with the expected query. function verifyQuery(bytes32[] calldata data, QueryInput memory query) internal view { // Retrieve the last Uint256 of public inputs. bytes32 rem = data[PI_REM_OFFSET]; // Check the block hash and computational hash. bytes32 blockHash = convertToBlockHash(data[PI_OFFSET + BLOCK_HASH_POS]); require( isCDK() || blockHash == query.blockHash, "Block hash must equal as expected." ); bytes32 computationalHash = data[PI_OFFSET + COMPUTATIONAL_HASH_POS]; require( computationalHash == query.computationalHash, "Computational hash must equal as expected." ); uint32 numPlaceholders = uint32(bytes4(rem << (REM_NUM_PLACEHOLDERS_POS * 32))); require( numPlaceholders <= MAX_NUM_PLACEHOLDERS, "Placeholder number cannot overflow." ); require( // The first two placeholders are minimum and maximum block numbers. numPlaceholders == query.userPlaceholders.length + 2, "Placeholder number cannot overflow and must equal as expected." ); // Check the minimum and maximum block numbers. require( uint256(data[PI_OFFSET + PLACEHOLDER_VALUES_POS]) == query.minBlockNumber, "The first placeholder must be the expected minimum block number." ); require( uint256(data[PI_OFFSET + PLACEHOLDER_VALUES_POS + 1]) == query.maxBlockNumber, "The second placeholder must be the expected maximum block number." ); // Check the user placeholders. for (uint256 i = 0; i < numPlaceholders - 2; ++i) { require( data[PI_OFFSET + PLACEHOLDER_VALUES_POS + 2 + i] == query.userPlaceholders[i], "The user placeholder must equal as expected." ); } // Check the query limit and offset. // uint32 limit = uint32(bytes4(rem << (REM_QUERY_LIMIT_POS * 32))); // require(limit == query.limit, "Query limit must equal as expected."); // uint32 offset = uint32(bytes4(rem << (REM_QUERY_OFFSET_POS * 32))); // require(offset == query.offset, "Query offset must equal as expected."); // Throw an error if overflow. uint32 overflow = uint32(bytes4(rem << (REM_OVERFLOW_POS * 32))); if (overflow != 0) { revert QueryComputationOverflow(); } } // Parse the query output from the public inputs. function parseOutput(bytes32[] calldata data) internal pure returns (QueryOutput memory) { bytes32 rem = data[PI_REM_OFFSET]; // Retrieve total number of the matched rows. uint32 totalMatchedRows = uint32(bytes4(rem << (REM_ENTRY_COUNT_POS * 32))); // Retrieve the current result number. uint32 numResults = uint32(bytes4(rem << (REM_NUM_RESULTS_POS * 32))); require(numResults <= MAX_NUM_OUTPUTS, "Result number cannot overflow."); uint32 offset = PI_OFFSET + RESULT_VALUES_POS; bytes[] memory rows = new bytes[](numResults); for (uint32 i = 0; i < numResults; ++i) { uint256[] memory columns = new uint256[](MAX_NUM_ITEMS_PER_OUTPUT); for (uint32 j = 0; j < MAX_NUM_ITEMS_PER_OUTPUT; ++j) { columns[j] = uint256(data[offset + i * MAX_NUM_ITEMS_PER_OUTPUT + j]); } rows[i] = abi.encodePacked(columns); } QueryOutput memory output = QueryOutput({totalMatchedRows: totalMatchedRows, rows: rows}); return output; } // Reverse the bytes of each Uint32 in block hash. // Since we pack to little-endian for each Uint32 in block hash. function convertToBlockHash(bytes32 original) internal pure returns (bytes32) { bytes32 result; for (uint256 i = 0; i < 8; ++i) { for (uint256 j = 0; j < 4; ++j) { result |= bytes32(original[i * 4 + j]) >> (8 * (i * 4 + 3 - j)); } } return result; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {QueryOutput} from "../Groth16VerifierExtensions.sol"; /** * @title ILPNClientV1 * @notice Interface for the LPNClientV1 contract. */ interface ILPNClientV1 { /// @notice Callback function called by the LPNRegistry contract. /// @param requestId The ID of the request. /// @param result The result of the request. function lpnCallback(uint256 requestId, QueryOutput memory result) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import {IOptimismL1Block} from "../interfaces/IOptimismL1Block.sol"; import { OP_STACK_L1_BLOCK_PREDEPLOY_ADDR, isEthereum, isOPStack } from "./Constants.sol"; /// @notice The latest L1 blockhash. function L1BlockHash() view returns (bytes32) { if (isEthereum()) { return blockhash(block.number); } if (isOPStack()) { return IOptimismL1Block(OP_STACK_L1_BLOCK_PREDEPLOY_ADDR).hash(); } return bytes32(0); } /// @notice The latest L1 block number. function L1BlockNumber() view returns (uint256) { if (isEthereum()) { return block.number; } if (isOPStack()) { return uint256(IOptimismL1Block(OP_STACK_L1_BLOCK_PREDEPLOY_ADDR).number()); } return 0; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {QueryOutput} from "../Groth16VerifierExtensions.sol"; /// @title IQueryManager /// @notice interface IQueryManager { /// @notice Event emitted when a new request is made. /// @param requestId The ID of the request. /// @param queryHash The identifier of the SQL query associated with the request. /// @param client The address of the client who made this request. /// @param placeholders Values for the numbered placeholders in the query. /// @param startBlock The starting block for the computation. /// @param endBlock The ending block for the computation. /// @param proofBlock The requested block for the proof to be computed against. /// Currently required for OP Stack chains event NewRequest( uint256 indexed requestId, bytes32 indexed queryHash, address indexed client, bytes32[] placeholders, uint256 startBlock, uint256 endBlock, uint256 gasFee, uint256 proofBlock ); /// @notice Event emitted when a response is received. /// @param requestId The ID of the request. /// @param client The address of the client who made the matching request. /// @param result The computed results for the request. event NewResponse( uint256 indexed requestId, address indexed client, QueryOutput result ); /// @notice Submits a new request to the registry. /// @param queryHash The identifier of the SQL query associated with the request. /// @param placeholders Values for the numbered placeholders in the query. /// @param startBlock The starting block for the computation. /// @param endBlock The ending block for the computation. /// @return The ID of the newly created request. function request( bytes32 queryHash, bytes32[] calldata placeholders, uint256 startBlock, uint256 endBlock ) external payable returns (uint256); /// @notice Submits a response to a specific request. /// @param requestId_ The ID of the request to respond to. /// @param data The proof, inputs, and public inputs to verify. /// - groth16_proof.proofs: 8 * U256 = 256 bytes /// - groth16_proof.inputs: 3 * U256 = 96 bytes /// - plonky2_proof.public_inputs: the little-endian bytes of public inputs exported by user /// @param blockNumber The block number of the block hash corresponding to the proof. function respond( uint256 requestId_, bytes32[] calldata data, uint256 blockNumber ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /// @custom:proxied /// @custom:predeploy 0x4200000000000000000000000000000000000015 /// @title IOptimismL1Block /// @notice from https://github.com/ethereum-optimism/optimism/blob/0d221da603418fe99e96bba944d2af64feee94eb/packages/contracts-bedrock/src/L2/L1Block.sol /// The L1Block predeploy gives users access to information about the last known L1 block. interface IOptimismL1Block { /// @notice The latest L1 blockhash. function hash() external view returns (bytes32); /// @notice The latest L1 block number known by the L2 system. function number() external view returns (uint64); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title Groth16 verifier template. /// @author Remco Bloemen /// @notice Supports verifying Groth16 proofs. Proofs can be in uncompressed /// (256 bytes) and compressed (128 bytes) format. A view function is provided /// to compress proofs. /// @notice See <https://2π.com/23/bn254-compression> for further explanation. library Groth16Verifier { /// Some of the provided public input values are larger than the field modulus. /// @dev Public input elements are not automatically reduced, as this is can be /// a dangerous source of bugs. error PublicInputNotInField(); /// The proof is invalid. /// @dev This can mean that provided Groth16 proof points are not on their /// curves, that pairing equation fails, or that the proof is not for the /// provided public input. error ProofInvalid(); // Addresses of precompiles uint256 constant PRECOMPILE_MODEXP = 0x05; uint256 constant PRECOMPILE_ADD = 0x06; uint256 constant PRECOMPILE_MUL = 0x07; uint256 constant PRECOMPILE_VERIFY = 0x08; // Base field Fp order P and scalar field Fr order R. // For BN254 these are computed as follows: // t = 4965661367192848881 // P = 36⋅t⁴ + 36⋅t³ + 24⋅t² + 6⋅t + 1 // R = 36⋅t⁴ + 36⋅t³ + 18⋅t² + 6⋅t + 1 uint256 constant P = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47; uint256 constant R = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001; // Extension field Fp2 = Fp[i] / (i² + 1) // Note: This is the complex extension field of Fp with i² = -1. // Values in Fp2 are represented as a pair of Fp elements (a₀, a₁) as a₀ + a₁⋅i. // Note: The order of Fp2 elements is *opposite* that of the pairing contract, which // expects Fp2 elements in order (a₁, a₀). This is also the order in which // Fp2 elements are encoded in the public interface as this became convention. // Constants in Fp uint256 constant FRACTION_1_2_FP = 0x183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea4; uint256 constant FRACTION_27_82_FP = 0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5; uint256 constant FRACTION_3_82_FP = 0x2fcd3ac2a640a154eb23960892a85a68f031ca0c8344b23a577dcf1052b9e775; // Exponents for inversions and square roots mod P uint256 constant EXP_INVERSE_FP = 0x30644E72E131A029B85045B68181585D97816A916871CA8D3C208C16D87CFD45; // P - 2 uint256 constant EXP_SQRT_FP = 0xC19139CB84C680A6E14116DA060561765E05AA45A1C72A34F082305B61F3F52; // (P + 1) / 4; // Groth16 alpha point in G1 uint256 constant ALPHA_X = 2875744645601179976363844474093959170321451803468610749057361104388358291569; uint256 constant ALPHA_Y = 9030985415484203529157134388375178884197023634925284841817030493863215311578; // Groth16 beta point in G2 in powers of i uint256 constant BETA_NEG_X_0 = 4168542318372003188156028087884714088142844126831279036928527463314104009625; uint256 constant BETA_NEG_X_1 = 5384258495492721486098880640446239757401296141806067034806601160302198090976; uint256 constant BETA_NEG_Y_0 = 1561207354601639018543331975916306910309853318626727545899124391823831330521; uint256 constant BETA_NEG_Y_1 = 20383936205862041072654599425036456432253475457020266865126981895931969642957; // Groth16 gamma point in G2 in powers of i uint256 constant GAMMA_NEG_X_0 = 13554115733070795354020222745368660317579173163554475930738337944072472283563; uint256 constant GAMMA_NEG_X_1 = 10693921363568381157961078842123743771766278612605336854092820597802382701424; uint256 constant GAMMA_NEG_Y_0 = 2281918776349629127804164206207247630789796515702357424568453929478875220785; uint256 constant GAMMA_NEG_Y_1 = 5177137659153390376817448136516111829235629037725638242867426284681774382012; // Groth16 delta point in G2 in powers of i uint256 constant DELTA_NEG_X_0 = 242531771162725810330185935192292698113063884016085472046645295503301133275; uint256 constant DELTA_NEG_X_1 = 16291580441059584414836602944126194811398774433528842992651872049031028482753; uint256 constant DELTA_NEG_Y_0 = 1417816254065265703615823536099938140877122992281837643943740324053939897364; uint256 constant DELTA_NEG_Y_1 = 14030578855720338723602878644561073910674875557052687059892517557596226896548; // Constant and public input points uint256 constant CONSTANT_X = 5202978798150463655908570029891721340884651522916353899726471113111423929342; uint256 constant CONSTANT_Y = 14982591606621159141329318953795543458568319795981297660099879207303254040809; uint256 constant PUB_0_X = 14296192090556038838045209301731774710680090775075355984322587980761493543904; uint256 constant PUB_0_Y = 19601706790272468704913839562858335792111985806205849666707512679510610253899; uint256 constant PUB_1_X = 6556458653007261924416086804438178193077444885416364865223485598120055942696; uint256 constant PUB_1_Y = 286212824975773989378954189604165017341082476242589668187439098069840023246; uint256 constant PUB_2_X = 13430983197622959976950587585456204167851174705647144133972047650438831094215; uint256 constant PUB_2_Y = 7842741937998900944887201062754035088483914707422731211588620224038761132415; /// Negation in Fp. /// @notice Returns a number x such that a + x = 0 in Fp. /// @notice The input does not need to be reduced. /// @param a the base /// @return x the result function negate(uint256 a) internal pure returns (uint256 x) { unchecked { x = (P - (a % P)) % P; // Modulo is cheaper than branching } } /// Exponentiation in Fp. /// @notice Returns a number x such that a ^ e = x in Fp. /// @notice The input does not need to be reduced. /// @param a the base /// @param e the exponent /// @return x the result function exp(uint256 a, uint256 e) internal view returns (uint256 x) { bool success; assembly ("memory-safe") { let f := mload(0x40) mstore(f, 0x20) mstore(add(f, 0x20), 0x20) mstore(add(f, 0x40), 0x20) mstore(add(f, 0x60), a) mstore(add(f, 0x80), e) mstore(add(f, 0xa0), P) success := staticcall(gas(), PRECOMPILE_MODEXP, f, 0xc0, f, 0x20) x := mload(f) } if (!success) { // Exponentiation failed. // Should not happen. revert ProofInvalid(); } } /// Invertsion in Fp. /// @notice Returns a number x such that a * x = 1 in Fp. /// @notice The input does not need to be reduced. /// @notice Reverts with ProofInvalid() if the inverse does not exist /// @param a the input /// @return x the solution function invert_Fp(uint256 a) internal view returns (uint256 x) { x = exp(a, EXP_INVERSE_FP); if (mulmod(a, x, P) != 1) { // Inverse does not exist. // Can only happen during G2 point decompression. revert ProofInvalid(); } } /// Square root in Fp. /// @notice Returns a number x such that x * x = a in Fp. /// @notice Will revert with InvalidProof() if the input is not a square /// or not reduced. /// @param a the square /// @return x the solution function sqrt_Fp(uint256 a) internal view returns (uint256 x) { x = exp(a, EXP_SQRT_FP); if (mulmod(x, x, P) != a) { // Square root does not exist or a is not reduced. // Happens when G1 point is not on curve. revert ProofInvalid(); } } /// Square test in Fp. /// @notice Returns wheter a number x exists such that x * x = a in Fp. /// @notice Will revert with InvalidProof() if the input is not a square /// or not reduced. /// @param a the square /// @return x the solution function isSquare_Fp(uint256 a) internal view returns (bool) { uint256 x = exp(a, EXP_SQRT_FP); return mulmod(x, x, P) == a; } /// Square root in Fp2. /// @notice Fp2 is the complex extension Fp[i]/(i^2 + 1). The input is /// a0 + a1 ⋅ i and the result is x0 + x1 ⋅ i. /// @notice Will revert with InvalidProof() if /// * the input is not a square, /// * the hint is incorrect, or /// * the input coefficents are not reduced. /// @param a0 The real part of the input. /// @param a1 The imaginary part of the input. /// @param hint A hint which of two possible signs to pick in the equation. /// @return x0 The real part of the square root. /// @return x1 The imaginary part of the square root. function sqrt_Fp2(uint256 a0, uint256 a1, bool hint) internal view returns (uint256 x0, uint256 x1) { // If this square root reverts there is no solution in Fp2. uint256 d = sqrt_Fp(addmod(mulmod(a0, a0, P), mulmod(a1, a1, P), P)); if (hint) { d = negate(d); } // If this square root reverts there is no solution in Fp2. x0 = sqrt_Fp(mulmod(addmod(a0, d, P), FRACTION_1_2_FP, P)); x1 = mulmod(a1, invert_Fp(mulmod(x0, 2, P)), P); // Check result to make sure we found a root. // Note: this also fails if a0 or a1 is not reduced. if ( a0 != addmod(mulmod(x0, x0, P), negate(mulmod(x1, x1, P)), P) || a1 != mulmod(2, mulmod(x0, x1, P), P) ) { revert ProofInvalid(); } } /// Compress a G1 point. /// @notice Reverts with InvalidProof if the coordinates are not reduced /// or if the point is not on the curve. /// @notice The point at infinity is encoded as (0,0) and compressed to 0. /// @param x The X coordinate in Fp. /// @param y The Y coordinate in Fp. /// @return c The compresed point (x with one signal bit). function compress_g1(uint256 x, uint256 y) internal view returns (uint256 c) { if (x >= P || y >= P) { // G1 point not in field. revert ProofInvalid(); } if (x == 0 && y == 0) { // Point at infinity return 0; } // Note: sqrt_Fp reverts if there is no solution, i.e. the x coordinate is invalid. uint256 y_pos = sqrt_Fp(addmod(mulmod(mulmod(x, x, P), x, P), 3, P)); if (y == y_pos) { return (x << 1) | 0; } else if (y == negate(y_pos)) { return (x << 1) | 1; } else { // G1 point not on curve. revert ProofInvalid(); } } /// Decompress a G1 point. /// @notice Reverts with InvalidProof if the input does not represent a valid point. /// @notice The point at infinity is encoded as (0,0) and compressed to 0. /// @param c The compresed point (x with one signal bit). /// @return x The X coordinate in Fp. /// @return y The Y coordinate in Fp. function decompress_g1(uint256 c) internal view returns (uint256 x, uint256 y) { // Note that X = 0 is not on the curve since 0³ + 3 = 3 is not a square. // so we can use it to represent the point at infinity. if (c == 0) { // Point at infinity as encoded in EIP196 and EIP197. return (0, 0); } bool negate_point = c & 1 == 1; x = c >> 1; if (x >= P) { // G1 x coordinate not in field. revert ProofInvalid(); } // Note: (x³ + 3) is irreducible in Fp, so it can not be zero and therefore // y can not be zero. // Note: sqrt_Fp reverts if there is no solution, i.e. the point is not on the curve. y = sqrt_Fp(addmod(mulmod(mulmod(x, x, P), x, P), 3, P)); if (negate_point) { y = negate(y); } } /// Compress a G2 point. /// @notice Reverts with InvalidProof if the coefficients are not reduced /// or if the point is not on the curve. /// @notice The G2 curve is defined over the complex extension Fp[i]/(i^2 + 1) /// with coordinates (x0 + x1 ⋅ i, y0 + y1 ⋅ i). /// @notice The point at infinity is encoded as (0,0,0,0) and compressed to (0,0). /// @param x0 The real part of the X coordinate. /// @param x1 The imaginary poart of the X coordinate. /// @param y0 The real part of the Y coordinate. /// @param y1 The imaginary part of the Y coordinate. /// @return c0 The first half of the compresed point (x0 with two signal bits). /// @return c1 The second half of the compressed point (x1 unmodified). function compress_g2(uint256 x0, uint256 x1, uint256 y0, uint256 y1) internal view returns (uint256 c0, uint256 c1) { if (x0 >= P || x1 >= P || y0 >= P || y1 >= P) { // G2 point not in field. revert ProofInvalid(); } if ((x0 | x1 | y0 | y1) == 0) { // Point at infinity return (0, 0); } // Compute y^2 // Note: shadowing variables and scoping to avoid stack-to-deep. uint256 y0_pos; uint256 y1_pos; { uint256 n3ab = mulmod(mulmod(x0, x1, P), P - 3, P); uint256 a_3 = mulmod(mulmod(x0, x0, P), x0, P); uint256 b_3 = mulmod(mulmod(x1, x1, P), x1, P); y0_pos = addmod( FRACTION_27_82_FP, addmod(a_3, mulmod(n3ab, x1, P), P), P ); y1_pos = negate( addmod(FRACTION_3_82_FP, addmod(b_3, mulmod(n3ab, x0, P), P), P) ); } // Determine hint bit // If this sqrt fails the x coordinate is not on the curve. bool hint; { uint256 d = sqrt_Fp( addmod(mulmod(y0_pos, y0_pos, P), mulmod(y1_pos, y1_pos, P), P) ); hint = !isSquare_Fp(mulmod(addmod(y0_pos, d, P), FRACTION_1_2_FP, P)); } // Recover y (y0_pos, y1_pos) = sqrt_Fp2(y0_pos, y1_pos, hint); if (y0 == y0_pos && y1 == y1_pos) { c0 = (x0 << 2) | (hint ? 2 : 0) | 0; c1 = x1; } else if (y0 == negate(y0_pos) && y1 == negate(y1_pos)) { c0 = (x0 << 2) | (hint ? 2 : 0) | 1; c1 = x1; } else { // G1 point not on curve. revert ProofInvalid(); } } /// Decompress a G2 point. /// @notice Reverts with InvalidProof if the input does not represent a valid point. /// @notice The G2 curve is defined over the complex extension Fp[i]/(i^2 + 1) /// with coordinates (x0 + x1 ⋅ i, y0 + y1 ⋅ i). /// @notice The point at infinity is encoded as (0,0,0,0) and compressed to (0,0). /// @param c0 The first half of the compresed point (x0 with two signal bits). /// @param c1 The second half of the compressed point (x1 unmodified). /// @return x0 The real part of the X coordinate. /// @return x1 The imaginary poart of the X coordinate. /// @return y0 The real part of the Y coordinate. /// @return y1 The imaginary part of the Y coordinate. function decompress_g2(uint256 c0, uint256 c1) internal view returns (uint256 x0, uint256 x1, uint256 y0, uint256 y1) { // Note that X = (0, 0) is not on the curve since 0³ + 3/(9 + i) is not a square. // so we can use it to represent the point at infinity. if (c0 == 0 && c1 == 0) { // Point at infinity as encoded in EIP197. return (0, 0, 0, 0); } bool negate_point = c0 & 1 == 1; bool hint = c0 & 2 == 2; x0 = c0 >> 2; x1 = c1; if (x0 >= P || x1 >= P) { // G2 x0 or x1 coefficient not in field. revert ProofInvalid(); } uint256 n3ab = mulmod(mulmod(x0, x1, P), P - 3, P); uint256 a_3 = mulmod(mulmod(x0, x0, P), x0, P); uint256 b_3 = mulmod(mulmod(x1, x1, P), x1, P); y0 = addmod(FRACTION_27_82_FP, addmod(a_3, mulmod(n3ab, x1, P), P), P); y1 = negate( addmod(FRACTION_3_82_FP, addmod(b_3, mulmod(n3ab, x0, P), P), P) ); // Note: sqrt_Fp2 reverts if there is no solution, i.e. the point is not on the curve. // Note: (X³ + 3/(9 + i)) is irreducible in Fp2, so y can not be zero. // But y0 or y1 may still independently be zero. (y0, y1) = sqrt_Fp2(y0, y1, hint); if (negate_point) { y0 = negate(y0); y1 = negate(y1); } } /// Compute the public input linear combination. /// @notice Reverts with PublicInputNotInField if the input is not in the field. /// @notice Computes the multi-scalar-multiplication of the public input /// elements and the verification key including the constant term. /// @param input The public inputs. These are elements of the scalar field Fr. /// @return x The X coordinate of the resulting G1 point. /// @return y The Y coordinate of the resulting G1 point. function publicInputMSM(uint256[3] memory input) internal view returns (uint256 x, uint256 y) { // Note: The ECMUL precompile does not reject unreduced values, so we check this. // Note: Unrolling this loop does not cost much extra in code-size, the bulk of the // code-size is in the PUB_ constants. // ECMUL has input (x, y, scalar) and output (x', y'). // ECADD has input (x1, y1, x2, y2) and output (x', y'). // We call them such that ecmul output is already in the second point // argument to ECADD so we can have a tight loop. bool success = true; assembly ("memory-safe") { let f := mload(0x40) let g := add(f, 0x40) let s mstore(f, CONSTANT_X) mstore(add(f, 0x20), CONSTANT_Y) mstore(g, PUB_0_X) mstore(add(g, 0x20), PUB_0_Y) s := mload(input) mstore(add(g, 0x40), s) success := and(success, lt(s, R)) success := and(success, staticcall(gas(), PRECOMPILE_MUL, g, 0x60, g, 0x40)) success := and(success, staticcall(gas(), PRECOMPILE_ADD, f, 0x80, f, 0x40)) mstore(g, PUB_1_X) mstore(add(g, 0x20), PUB_1_Y) s := mload(add(input, 32)) mstore(add(g, 0x40), s) success := and(success, lt(s, R)) success := and(success, staticcall(gas(), PRECOMPILE_MUL, g, 0x60, g, 0x40)) success := and(success, staticcall(gas(), PRECOMPILE_ADD, f, 0x80, f, 0x40)) mstore(g, PUB_2_X) mstore(add(g, 0x20), PUB_2_Y) s := mload(add(input, 64)) mstore(add(g, 0x40), s) success := and(success, lt(s, R)) success := and(success, staticcall(gas(), PRECOMPILE_MUL, g, 0x60, g, 0x40)) success := and(success, staticcall(gas(), PRECOMPILE_ADD, f, 0x80, f, 0x40)) x := mload(f) y := mload(add(f, 0x20)) } if (!success) { // Either Public input not in field, or verification key invalid. // We assume the contract is correctly generated, so the verification key is valid. revert PublicInputNotInField(); } } /// Compress a proof. /// @notice Will revert with InvalidProof if the curve points are invalid, /// but does not verify the proof itself. /// @param proof The uncompressed Groth16 proof. Elements are in the same order as for /// verifyProof. I.e. Groth16 points (A, B, C) encoded as in EIP-197. /// @return compressed The compressed proof. Elements are in the same order as for /// verifyCompressedProof. I.e. points (A, B, C) in compressed format. function compressProof(uint256[8] memory proof) internal view returns (uint256[4] memory compressed) { compressed[0] = compress_g1(proof[0], proof[1]); (compressed[2], compressed[1]) = compress_g2(proof[3], proof[2], proof[5], proof[4]); compressed[3] = compress_g1(proof[6], proof[7]); } /// Verify a Groth16 proof with compressed points. /// @notice Reverts with InvalidProof if the proof is invalid or /// with PublicInputNotInField the public input is not reduced. /// @notice There is no return value. If the function does not revert, the /// proof was successfully verified. /// @param compressedProof the points (A, B, C) in compressed format /// matching the output of compressProof. /// @param input the public input field elements in the scalar field Fr. /// Elements must be reduced. function verifyCompressedProof( uint256[4] calldata compressedProof, uint256[3] memory input ) internal view { (uint256 Ax, uint256 Ay) = decompress_g1(compressedProof[0]); (uint256 Bx0, uint256 Bx1, uint256 By0, uint256 By1) = decompress_g2(compressedProof[2], compressedProof[1]); (uint256 Cx, uint256 Cy) = decompress_g1(compressedProof[3]); (uint256 Lx, uint256 Ly) = publicInputMSM(input); // Verify the pairing // Note: The precompile expects the F2 coefficients in big-endian order. // Note: The pairing precompile rejects unreduced values, so we won't check that here. uint256[24] memory pairings; // e(A, B) pairings[0] = Ax; pairings[1] = Ay; pairings[2] = Bx1; pairings[3] = Bx0; pairings[4] = By1; pairings[5] = By0; // e(C, -δ) pairings[6] = Cx; pairings[7] = Cy; pairings[8] = DELTA_NEG_X_1; pairings[9] = DELTA_NEG_X_0; pairings[10] = DELTA_NEG_Y_1; pairings[11] = DELTA_NEG_Y_0; // e(α, -β) pairings[12] = ALPHA_X; pairings[13] = ALPHA_Y; pairings[14] = BETA_NEG_X_1; pairings[15] = BETA_NEG_X_0; pairings[16] = BETA_NEG_Y_1; pairings[17] = BETA_NEG_Y_0; // e(L_pub, -γ) pairings[18] = Lx; pairings[19] = Ly; pairings[20] = GAMMA_NEG_X_1; pairings[21] = GAMMA_NEG_X_0; pairings[22] = GAMMA_NEG_Y_1; pairings[23] = GAMMA_NEG_Y_0; // Check pairing equation. bool success; uint256[1] memory output; assembly ("memory-safe") { success := staticcall(gas(), PRECOMPILE_VERIFY, pairings, 0x300, output, 0x20) } if (!success || output[0] != 1) { // Either proof or verification key invalid. // We assume the contract is correctly generated, so the verification key is valid. revert ProofInvalid(); } } /// Verify an uncompressed Groth16 proof. /// @notice Reverts with InvalidProof if the proof is invalid or /// with PublicInputNotInField the public input is not reduced. /// @notice There is no return value. If the function does not revert, the /// proof was successfully verified. /// @param proof the points (A, B, C) in EIP-197 format matching the output /// of compressProof. /// @param input the public input field elements in the scalar field Fr. /// Elements must be reduced. function verifyProof(uint256[8] memory proof, uint256[3] memory input) internal view { (uint256 x, uint256 y) = publicInputMSM(input); // Note: The precompile expects the F2 coefficients in big-endian order. // Note: The pairing precompile rejects unreduced values, so we won't check that here. bool success; assembly ("memory-safe") { let f := mload(0x40) // Free memory pointer. // Copy points (A, B, C) to memory. They are already in correct encoding. // This is pairing e(A, B) and G1 of e(C, -δ). mstore(f, mload(add(proof, 0x00))) mstore(add(f, 0x20), mload(add(proof, 0x20))) mstore(add(f, 0x40), mload(add(proof, 0x40))) mstore(add(f, 0x60), mload(add(proof, 0x60))) mstore(add(f, 0x80), mload(add(proof, 0x80))) mstore(add(f, 0xa0), mload(add(proof, 0xa0))) mstore(add(f, 0xc0), mload(add(proof, 0xc0))) mstore(add(f, 0xe0), mload(add(proof, 0xe0))) // Complete e(C, -δ) and write e(α, -β), e(L_pub, -γ) to memory. // OPT: This could be better done using a single codecopy, but // Solidity (unlike standalone Yul) doesn't provide a way to // to do this. mstore(add(f, 0x100), DELTA_NEG_X_1) mstore(add(f, 0x120), DELTA_NEG_X_0) mstore(add(f, 0x140), DELTA_NEG_Y_1) mstore(add(f, 0x160), DELTA_NEG_Y_0) mstore(add(f, 0x180), ALPHA_X) mstore(add(f, 0x1a0), ALPHA_Y) mstore(add(f, 0x1c0), BETA_NEG_X_1) mstore(add(f, 0x1e0), BETA_NEG_X_0) mstore(add(f, 0x200), BETA_NEG_Y_1) mstore(add(f, 0x220), BETA_NEG_Y_0) mstore(add(f, 0x240), x) mstore(add(f, 0x260), y) mstore(add(f, 0x280), GAMMA_NEG_X_1) mstore(add(f, 0x2a0), GAMMA_NEG_X_0) mstore(add(f, 0x2c0), GAMMA_NEG_Y_1) mstore(add(f, 0x2e0), GAMMA_NEG_Y_0) // Check pairing equation. success := staticcall(gas(), PRECOMPILE_VERIFY, f, 0x300, f, 0x20) // Also check returned value (both are either 1 or 0). success := and(success, mload(f)) } if (!success) { // Either proof or verification key invalid. // We assume the contract is correctly generated, so the verification key is valid. revert ProofInvalid(); } } bytes32 constant CIRCUIT_DIGEST = 0x2f220073107d5d15dd938ce95b310688567a9c1610677513ef91fd0836afc496; }
{ "remappings": [ "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "solady/=lib/solady/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "cancun", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"InsufficientGasFee","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"ProofInvalid","type":"error"},{"inputs":[],"name":"PublicInputNotInField","type":"error"},{"inputs":[],"name":"QueryAfterCurrentBlock","type":"error"},{"inputs":[],"name":"QueryAlreadyRegistered","type":"error"},{"inputs":[],"name":"QueryComputationOverflow","type":"error"},{"inputs":[],"name":"QueryGreaterThanMaxRange","type":"error"},{"inputs":[],"name":"QueryInvalidRange","type":"error"},{"inputs":[],"name":"TableAlreadyRegistered","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"addrs","type":"address[]"},{"indexed":false,"internalType":"bool","name":"value","type":"bool"}],"name":"BatchWhitelisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"hash","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"tableHash","type":"bytes32"},{"indexed":false,"internalType":"string","name":"sql","type":"string"}],"name":"NewQueryRegistration","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"queryHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"client","type":"address"},{"indexed":false,"internalType":"bytes32[]","name":"placeholders","type":"bytes32[]"},{"indexed":false,"internalType":"uint256","name":"startBlock","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endBlock","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"proofBlock","type":"uint256"}],"name":"NewRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"client","type":"address"},{"components":[{"internalType":"uint256","name":"totalMatchedRows","type":"uint256"},{"internalType":"bytes[]","name":"rows","type":"bytes[]"}],"indexed":false,"internalType":"struct QueryOutput","name":"result","type":"tuple"}],"name":"NewResponse","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"hash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"contractAddr","type":"address"},{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"genesisBlock","type":"uint256"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"schema","type":"string"}],"name":"NewTableRegistration","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"bool","name":"value","type":"bool"}],"name":"Whitelisted","type":"event"},{"inputs":[],"name":"CDK_GAS_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ETH_GAS_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANTLE_GAS_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_QUERY_RANGE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OP_GAS_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"addrs","type":"address[]"}],"name":"addToWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"gasFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"queries","outputs":[{"internalType":"bool","name":"registered","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"bytes32","name":"tableHash","type":"bytes32"},{"internalType":"string","name":"sql","type":"string"}],"name":"registerQuery","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"address","name":"contractAddr","type":"address"},{"internalType":"uint96","name":"chainId","type":"uint96"},{"internalType":"uint256","name":"genesisBlock","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"schema","type":"string"}],"name":"registerTable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"addrs","type":"address[]"}],"name":"removeFromWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"queryHash","type":"bytes32"},{"internalType":"bytes32[]","name":"placeholders","type":"bytes32[]"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"name":"request","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"requests","outputs":[{"internalType":"address","name":"client","type":"address"},{"components":[{"internalType":"uint32","name":"limit","type":"uint32"},{"internalType":"uint32","name":"offset","type":"uint32"},{"internalType":"uint64","name":"minBlockNumber","type":"uint64"},{"internalType":"uint64","name":"maxBlockNumber","type":"uint64"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"internalType":"bytes32","name":"computationalHash","type":"bytes32"},{"internalType":"bytes32[]","name":"userPlaceholders","type":"bytes32[]"}],"internalType":"struct QueryInput","name":"input","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId_","type":"uint256"},{"internalType":"bytes32[]","name":"data","type":"bytes32[]"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"respond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"tables","outputs":[{"internalType":"bool","name":"registered","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"client","type":"address"}],"name":"toggleWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawFees","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6080604052348015600e575f80fd5b50612e298061001c5f395ff3fe608060405260043610610194575f3560e01c80637f649783116100e7578063c81de78c11610087578063d3098b9a11610062578063d3098b9a14610415578063f04e283e14610443578063f2fde38b14610456578063fee81cf414610469575f80fd5b8063c81de78c146103e0578063c9179506146103fb578063cf72dddd146103fb575f80fd5b80639468441c116100c25780639468441c146103665780639b19251a146103805780639bc24290146103ae578063c4d66de8146103c1575f80fd5b80637f649783146102ef57806381d12c581461030e5780638da5cb5b1461033b575f80fd5b8063476343ee1161015257806355c2c6711161012d57806355c2c67114610295578063658612e9146102b4578063715018a6146102c85780637b20c8dc146102d0575f80fd5b8063476343ee1461025a578063548db1741461026e57806354d1f13d1461028d575f80fd5b80626d6cae1461019857806308506853146101bf57806312def999146101d457806321dfb600146101f5578063256929621461023357806339393ac91461023b575b5f80fd5b3480156101a3575f80fd5b506101ac5f5481565b6040519081526020015b60405180910390f35b3480156101ca575f80fd5b506101ac61c35081565b3480156101df575f80fd5b506101f36101ee366004612736565b61049a565b005b348015610200575f80fd5b5061022361020f3660046127e4565b60336020525f908152604090205460ff1681565b60405190151581526020016101b6565b6101f36104bc565b348015610246575f80fd5b506101f36102553660046127fb565b610508565b348015610265575f80fd5b50610223610579565b348015610279575f80fd5b506101f361028836600461285b565b61058f565b6101f3610627565b3480156102a0575f80fd5b506101f36102af366004612899565b610660565b3480156102bf575f80fd5b506101ac6106eb565b6101f3610797565b3480156102db575f80fd5b506101f36102ea3660046128e7565b6107aa565b3480156102fa575f80fd5b506101f361030936600461285b565b6109b2565b348015610319575f80fd5b5061032d6103283660046127e4565b610a54565b6040516101b692919061296f565b348015610346575f80fd5b50638b78c6d819546040516001600160a01b0390911681526020016101b6565b348015610371575f80fd5b506101ac6611c37937e0800081565b34801561038b575f80fd5b5061022361039a3660046127fb565b60646020525f908152604090205460ff1681565b6101ac6103bc3660046129fa565b610b2a565b3480156103cc575f80fd5b506101f36103db3660046127fb565b610dfd565b3480156103eb575f80fd5b506101ac6714d1120d7b16000081565b348015610406575f80fd5b506101ac66019945ca26200081565b348015610420575f80fd5b5061022361042f3660046127e4565b60326020525f908152604090205460ff1681565b6101f36104513660046127fb565b610f09565b6101f36104643660046127fb565b610f46565b348015610474575f80fd5b506101ac6104833660046127fb565b63389a75e1600c9081525f91909152602090205490565b6104a2610f6c565b6104b28888888888888888610f86565b5050505050505050565b5f6202a3006001600160401b03164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a250565b610510610f6c565b6001600160a01b0381165f81815260646020908152604091829020805460ff81161560ff1990911681179091558251938452908301819052917fa54714518c5d275fdcd3d2a461e4858e4e8cb04fb93cd0bca9d6d34115f2644091015b60405180910390a15050565b5f610582610f6c565b61058a611026565b905090565b610597610f6c565b5f5b818110156105f35760645f8484848181106105b6576105b6612a52565b90506020020160208101906105cb91906127fb565b6001600160a01b0316815260208101919091526040015f20805460ff19169055600101610599565b507fe481b9d265afbda7824b6945408c17197396b0621a7e5418ac204f8c5abe644582825f60405161056d93929190612a66565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2565b5f8481526033602052604090205460ff161561068f576040516319ed6f1960e11b815260040160405180910390fd5b5f8481526033602052604090819020805460ff1916600117905551839085907fc7f97dc1b8d74ceebb3210d4fa3c174bc04a0723402ea2b5800c07dbc645e2c0906106dd9086908690612ae4565b60405180910390a350505050565b5f6106f4611075565b1561070557506611c37937e0800090565b61070d611096565b1561071f57506714d1120d7b16000090565b6015602160991b013b63ffffffff161561073f575066019945ca26200090565b61044d4603610754575066019945ca26200090565b60405162461bcd60e51b815260206004820152601360248201527210da185a5b881b9bdd081cdd5c1c1bdc9d1959606a1b60448201526064015b60405180910390fd5b61079f610f6c565b6107a85f6110ab565b565b5f8481526001602081815260408084208151808301835281546001600160a01b03168152825160e081018452948201805463ffffffff8082168852640100000000820416878701526001600160401b03600160401b8204811688870152600160801b90910416606087015260028301546080870152600383015460a08701526004830180548551818802810188019096528086529296939587810195929360c0860193929183018282801561087c57602002820191905f5260205f20905b815481526020019060010190808311610868575b505050919092525050509052505f868152600160208190526040822080546001600160a01b031916815590810180546001600160c01b0319168155600282018390556003820183905592935091816108d76004850182612622565b505050506108e3611075565b156108f657602081015182406080909101525b5f610906858584602001516110e8565b8251604051635e5ff5c560e01b81529192506001600160a01b031690635e5ff5c5906109389089908590600401612b84565b5f604051808303815f87803b15801561094f575f80fd5b505af1158015610961573d5f803e3d5ffd5b50505050815f01516001600160a01b0316867f380bea3763a1f2305283f679e3da2563d01a42cfe16d5744b7bd4c9d60ed61bf836040516109a29190612b9c565b60405180910390a3505050505050565b6109ba610f6c565b5f5b81811015610a1f57600160645f8585858181106109db576109db612a52565b90506020020160208101906109f091906127fb565b6001600160a01b0316815260208101919091526040015f20805460ff19169115159190911790556001016109bc565b507fe481b9d265afbda7824b6945408c17197396b0621a7e5418ac204f8c5abe64458282600160405161056d93929190612a66565b600160208181525f9283526040928390208054845160e081018652938201805463ffffffff8082168752640100000000820416868601526001600160401b03600160401b8204811687890152600160801b90910416606086015260028301546080860152600383015460a08601526004830180548751818702810187019098528088526001600160a01b0390931696939594919360c08601939092830182828015610b1c57602002820191905f5260205f20905b815481526020019060010190808311610b08575b505050505081525050905082565b5f610b336106eb565b341015610b535760405163e6b6589360e01b815260040160405180910390fd5b828261044d4614158015610b6d5750610b6a611132565b81115b15610b8b57604051636d53123b60e01b815260040160405180910390fd5b80821115610bac57604051635d6fbc4960e11b815260040160405180910390fd5b61c350610bb98383612bc2565b610bc4906001612bd5565b1115610be3576040516383d304cf60e01b815260040160405180910390fd5b5f8054600101815580610bf4611075565b610c0d57610c00611132565b9150610c0a6111d3565b90505b6040518060400160405280336001600160a01b031681526020016040518060e001604052805f63ffffffff1681526020015f63ffffffff1681526020018a6001600160401b03168152602001896001600160401b031681526020018481526020018d81526020018c8c808060200260200160405190810160405280939291908181526020018383602002808284375f920182905250939094525050919092528054815260016020818152604092839020855181546001600160a01b0319166001600160a01b0390911617815585820151805193820180548285015196830151606084015163ffffffff97881667ffffffffffffffff199093169290921764010000000097909816969096029690961777ffffffffffffffffffffffffffffffff00000000000000001916600160401b6001600160401b039687160267ffffffffffffffff60801b191617600160801b95909616949094029490941783556080840151600282015560a0840151600382015560c08401518051919550610d9992600487019291019061263d565b505050905050336001600160a01b03168a5f547f5f80fe6d2eee22c9cc67535c0777535ddfbc865871b6f0369a4644936102e0a38c8c8c8c348a604051610de596959493929190612be8565b60405180910390a450505f5498975050505050505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b03165f81158015610e415750825b90505f826001600160401b03166001148015610e5c5750303b155b905081158015610e6a575080155b15610e885760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610eb257845460ff60401b1916600160401b1785555b610ebb86611262565b8315610f0157845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b610f11610f6c565b63389a75e1600c52805f526020600c208054421115610f3757636f5e88185f526004601cfd5b5f9055610f43816110ab565b50565b610f4e610f6c565b8060601b610f6357637448fbae5f526004601cfd5b610f43816110ab565b638b78c6d8195433146107a8576382b429005f526004601cfd5b5f8881526032602052604090205460ff1615610fb55760405163e5b70def60e01b815260040160405180910390fd5b5f8881526032602052604090819020805460ff19166001179055516001600160a01b0388169089907f77a60dab33c0274a972cadc956c819927458e5ed5b76a69c45c37ba6ed39f72690611014908a908a908a908a908a908a90612c39565b60405180910390a35050505050505050565b6040515f908190339047908381818185875af1925050503d805f8114611067576040519150601f19603f3d011682016040523d82523d5f602084013e61106c565b606091505b50909392505050565b5f6001461480611087575062aa36a746145b8061058a575050466142681490565b5f61138846148061058a575050466113881490565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355565b604080518082019091525f8152606060208201525f611107858561126b565b90506111148585836113e7565b61111f8585856114ea565b6111298585611a5c565b95945050505050565b5f61113b611075565b1561114557504390565b6015602160991b013b63ffffffff16156111ce576015602160991b016001600160a01b0316638381f58a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561119c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111c09190612c86565b6001600160401b0316905090565b505f90565b5f6111dc611075565b156111e75750434090565b6015602160991b013b63ffffffff16156111ce576015602160991b016001600160a01b03166309bd5a606040518163ffffffff1660e01b8152600401602060405180830381865afa15801561123e573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061058a9190612cac565b610f4381611d09565b611273612686565b61127b6126a4565b611283612686565b5f5b60088163ffffffff1610156112da5785858263ffffffff168181106112ac576112ac612a52565b905060200201355f1c838263ffffffff16600881106112cd576112cd612a52565b6020020152600101611285565b505f5b60038163ffffffff16101561133c5785856112f9836008612cc3565b63ffffffff1681811061130e5761130e612a52565b905060200201355f1c828263ffffffff166003811061132f5761132f612a52565b60200201526001016112dd565b5080517f2f220073107d5d15dd938ce95b310688567a9c1610677513ef91fd0836afc496146113d35760405162461bcd60e51b815260206004820152603b60248201527f5468652066697273742047726f7468313620696e707574206d7573742062652060448201527f657175616c20746f207468652063697263756974206469676573740000000000606482015260840161078e565b6113dd8282611d44565b9150505b92915050565b5f6113f28484612000565b90505f6002826040516114059190612ce0565b602060405180830381855afa158015611420573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906114439190612cac565b6001600160fd1b03169050826002602002015181146114e35760405162461bcd60e51b815260206004820152605060248201527f546865207368613235362068617368206f66207075626c696320696e7075747360448201527f206d75737420626520657175616c20746f20746865206c617374206f6620746860648201526f652047726f7468313620696e7075747360801b608482015260a40161078e565b5050505050565b5f83836114f960056003612cf6565b600a6115065f6001612cc3565b611511906001612cc3565b61151b9190612cc3565b61152690600b612cc3565b6115309190612cc3565b63ffffffff1681811061154557611545612a52565b9050602002013590505f61158285855f600b6115619190612cc3565b63ffffffff1681811061157657611576612a52565b9050602002013561233f565b905061044d4614806115975750826080015181145b6115ee5760405162461bcd60e51b815260206004820152602260248201527f426c6f636b2068617368206d75737420657175616c2061732065787065637465604482015261321760f11b606482015260840161078e565b5f85856115fc836001612cc3565b61160790600b612cc3565b63ffffffff1681811061161c5761161c612a52565b9050602002013590508360a00151811461168b5760405162461bcd60e51b815260206004820152602a60248201527f436f6d7075746174696f6e616c2068617368206d75737420657175616c2061736044820152691032bc3832b1ba32b21760b11b606482015260840161078e565b5f611697816020612cf6565b63ffffffff1684901b60e01c9050600a8111156117025760405162461bcd60e51b815260206004820152602360248201527f506c616365686f6c646572206e756d6265722063616e6e6f74206f766572666c60448201526237bb9760e91b606482015260840161078e565b60c085015151611713906002612bd5565b8163ffffffff161461178d5760405162461bcd60e51b815260206004820152603e60248201527f506c616365686f6c646572206e756d6265722063616e6e6f74206f766572666c60448201527f6f7720616e64206d75737420657175616c2061732065787065637465642e0000606482015260840161078e565b60408501516001600160401b031687876117a85f6001612cc3565b6117b3906001612cc3565b6117be90600b612cc3565b63ffffffff168181106117d3576117d3612a52565b905060200201355f1c14611851576040805162461bcd60e51b81526020600482015260248101919091527f54686520666972737420706c616365686f6c646572206d75737420626520746860448201527f65206578706563746564206d696e696d756d20626c6f636b206e756d6265722e606482015260840161078e565b60608501516001600160401b0316878761186c5f6001612cc3565b611877906001612cc3565b61188290600b612cc3565b61188d906001612cc3565b63ffffffff168181106118a2576118a2612a52565b905060200201355f1c146119285760405162461bcd60e51b815260206004820152604160248201527f546865207365636f6e6420706c616365686f6c646572206d757374206265207460448201527f6865206578706563746564206d6178696d756d20626c6f636b206e756d6265726064820152601760f91b608482015260a40161078e565b5f5b611935600283612d1e565b63ffffffff16811015611a21578560c00151818151811061195857611958612a52565b60200260200101518888835f60016119709190612cc3565b61197b906001612cc3565b61198690600b612cc3565b611991906002612cc3565b63ffffffff166119a19190612bd5565b8181106119b0576119b0612a52565b9050602002013514611a195760405162461bcd60e51b815260206004820152602c60248201527f546865207573657220706c616365686f6c646572206d75737420657175616c2060448201526b30b99032bc3832b1ba32b21760a11b606482015260840161078e565b60010161192a565b505f611a2f60036020612cf6565b63ffffffff1685901b60e01c905080156104b25760405163a729eb9d60e01b815260040160405180910390fd5b604080518082019091525f8152606060208201525f8383611a7f60056003612cf6565b600a611a8c5f6001612cc3565b611a97906001612cc3565b611aa19190612cc3565b611aac90600b612cc3565b611ab69190612cc3565b63ffffffff16818110611acb57611acb612a52565b9050602002013590505f60026020611ae39190612cf6565b63ffffffff1682901b60e01c90505f611afe60016020612cf6565b63ffffffff1683901b60e01c90506003811115611b5d5760405162461bcd60e51b815260206004820152601e60248201527f526573756c74206e756d6265722063616e6e6f74206f766572666c6f772e0000604482015260640161078e565b5f600a611b6b826001612cc3565b611b76906001612cc3565b611b809190612cc3565b611b8b90600b612cc3565b90505f8263ffffffff166001600160401b03811115611bac57611bac612d3b565b604051908082528060200260200182016040528015611bdf57816020015b6060815260200190600190039081611bca5790505b5090505f5b8363ffffffff168163ffffffff161015611ce35760408051600580825260c082019092525f916020820160a0803683370190505090505f5b600563ffffffff82161015611c96578a8a82611c39600587612cf6565b611c439089612cc3565b611c4d9190612cc3565b63ffffffff16818110611c6257611c62612a52565b905060200201355f1c828263ffffffff1681518110611c8357611c83612a52565b6020908102919091010152600101611c1c565b5080604051602001611ca89190612d4f565b604051602081830303815290604052838363ffffffff1681518110611ccf57611ccf612a52565b602090810291909101015250600101611be4565b506040805180820190915263ffffffff9094168452602084015250909250505092915050565b6001600160a01b0316638b78c6d819819055805f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b5f80611d4f836123d7565b915091505f6040515f86015181526020860151602082015260408601516040820152606086015160608201526080860151608082015260a086015160a082015260c086015160c082015260e086015160e08201527f2404b52fc3939b209c8db73c059d84e40dca65a3ac5a9d4840a62496d27922c16101008201527e8944a35f93247fd959f6a69bdccd23521cce4c67b2896d41f8e811e163c3db6101208201527f1f0506b5e4b7ac559f5daf81081d646558798fcdb12dea10b84d19874038c2a46101408201527f0322749fb3842040f9be42bae127fe87497c7e07351b841135c336a7cfffc4146101608201527f065b9d2145cfdfbfe2ea727830a9f7f6fbd4e923e8cb0228f05e867a4c5240716101808201527f13f75b4a7fb2eee944703c2b9ad7646f6b386ccbe8559b29246b616cc28b2ada6101a08201527f0be761df48a24519ac090bf58d00982f4f8e9487fa9927fa05874a1d82ad6ce06101c08201527f09374fb4112affecfcdb368f562b74d7bd32932ed4591977c100e1fc153843996101e08201527f2d10e62780024b9e01e2cd9b64ebdea97a805f70dc72befc3555dc5d1f4ba1cd6102008201527f03739caf38cc5da9ae740d0f22bb3b19edbd164394ba901fb1fa67393639eed961022082015283610240820152826102608201527f17a48b84f79770e34efa0cc6f7e5b12ccf96e467edf33db5d5d76e0fec2cb3706102808201527f1df75b8e713e12cc1413510fe246b9dbb064640039f88b73ee960963c430c9ab6102a08201527f0b7227f47b9d85a2e5e304c45980b771f251320ed88c9125a514f276b7463bbc6102c08201527f050b852f9b263260ed7f7a438b9c16a029d85d7fc976b654dc1b73d5514f8b316102e08201526020816103008360085afa9051169050806114e357604051631ff3747d60e21b815260040160405180910390fd5b60605f61200f60056001612cc3565b61201a906004612cf6565b600b61202860056003612cf6565b600a6120355f6001612cc3565b612040906001612cc3565b61204a9190612cc3565b61205590600b612cc3565b61205f9190612cc3565b6120699190612d1e565b612074906020612cf6565b61207e9190612cc3565b63ffffffff166001600160401b0381111561209b5761209b612d3b565b6040519080825280601f01601f1916602001820160405280156120c5576020820181803683370190505b5090505f60206120d760056001612cc3565b6120e2906004612cf6565b600b6120f060056003612cf6565b600a6120fd5f6001612cc3565b612108906001612cc3565b6121129190612cc3565b61211d90600b612cc3565b6121279190612cc3565b6121319190612d1e565b61213c906020612cf6565b6121469190612cc3565b6121509190612d98565b63ffffffff1690505f5b8181101561220a575f868661217084600b612bd5565b81811061217f5761217f612a52565b9050602002013590505f5b60208163ffffffff16101561220057818163ffffffff16602081106121b1576121b1612a52565b1a60f81b8563ffffffff83166121c8866020612dba565b6121d29190612bd5565b815181106121e2576121e2612a52565b60200101906001600160f81b03191690815f1a90535060010161218a565b505060010161215a565b505f858561221984600b612bd5565b81811061222857612228612a52565b9050602002013590505f5b602061224160056001612cc3565b61224c906004612cf6565b600b61225a60056003612cf6565b600a6122675f6001612cc3565b612272906001612cc3565b61227c9190612cc3565b61228790600b612cc3565b6122919190612cc3565b61229b9190612d1e565b6122a6906020612cf6565b6122b09190612cc3565b6122ba9190612dd1565b63ffffffff168163ffffffff16101561233457818163ffffffff16602081106122e5576122e5612a52565b1a60f81b8463ffffffff83166122fc866020612dba565b6123069190612bd5565b8151811061231657612316612a52565b60200101906001600160f81b03191690815f1a905350600101612233565b509195945050505050565b5f805f5b60088110156123d0575f5b60048110156123c75780612363836004612dba565b61236e906003612bd5565b6123789190612bc2565b612383906008612dba565b8582612390856004612dba565b61239a9190612bd5565b602081106123aa576123aa612a52565b1a60f81b6001600160f81b031916901c929092179160010161234e565b50600101612343565b5092915050565b5f805f60019050604051604081015f7f0b80c8199996f1ac070d2ad2c866b4ac191c2533307106e1b133532819ebcbfe83527f211fd8a967b92e385bce925354a7dc8f9ad6105f7d474bfff934d57d938ee0e960208401527f1f9b5ba456453070086619a2e0271f25389c841003c51797b57c4e75655e1be082527f2b562c41e78d557fc844695d6b443c1a0af45c6e980ddbdaca11e8011ff7984b6020830152865190508060408301527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181108416935060408260608460075afa8416935060408360808560065afa841693507f0e7ed2f79fe74b4b6361980f2327d835473509d9e87d45998257fc5010442e2882527ea1fd9fb54343d961f6cd54cd4219ab9aae13df8f0c88b3056336cc26ebcece6020830152602087015190508060408301527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181108416935060408260608460075afa8416935060408360808560065afa7f1db1aac6dd30bcfb711d394cf6f744abaeb40f3d7b7b2210422995edb8bb39c783527f1156d5aa58c7b1f500b6e1cbbd1ed1ff9839e4652b835e14746242f90a13f17f60208401526040888101518185018190527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000011191909516169390508160608160075afa831692505060408160808360065afa8151602090920151919450909250168061261c5760405163a54f8e2760e01b815260040160405180910390fd5b50915091565b5080545f8255905f5260205f2090810190610f4391906126c3565b828054828255905f5260205f20908101928215612676579160200282015b8281111561267657825182559160200191906001019061265b565b506126829291506126c3565b5090565b60405180606001604052806003906020820280368337509192915050565b6040518061010001604052806008906020820280368337509192915050565b5b80821115612682575f81556001016126c4565b80356001600160a01b03811681146126ed575f80fd5b919050565b5f8083601f840112612702575f80fd5b5081356001600160401b03811115612718575f80fd5b60208301915083602082850101111561272f575f80fd5b9250929050565b5f805f805f805f8060c0898b03121561274d575f80fd5b8835975061275d60208a016126d7565b965060408901356bffffffffffffffffffffffff8116811461277d575f80fd5b95506060890135945060808901356001600160401b038082111561279f575f80fd5b6127ab8c838d016126f2565b909650945060a08b01359150808211156127c3575f80fd5b506127d08b828c016126f2565b999c989b5096995094979396929594505050565b5f602082840312156127f4575f80fd5b5035919050565b5f6020828403121561280b575f80fd5b612814826126d7565b9392505050565b5f8083601f84011261282b575f80fd5b5081356001600160401b03811115612841575f80fd5b6020830191508360208260051b850101111561272f575f80fd5b5f806020838503121561286c575f80fd5b82356001600160401b03811115612881575f80fd5b61288d8582860161281b565b90969095509350505050565b5f805f80606085870312156128ac575f80fd5b843593506020850135925060408501356001600160401b038111156128cf575f80fd5b6128db878288016126f2565b95989497509550505050565b5f805f80606085870312156128fa575f80fd5b8435935060208501356001600160401b03811115612916575f80fd5b6129228782880161281b565b9598909750949560400135949350505050565b5f815180845260208085019450602084015f5b8381101561296457815187529582019590820190600101612948565b509495945050505050565b60018060a01b0383168152604060208201525f63ffffffff808451166040840152806020850151166060840152506001600160401b03604084015116608083015260608301516129ca60a08401826001600160401b03169052565b50608083015160c083015260a083015160e083015260c083015160e0610100840152611129610120840182612935565b5f805f805f60808688031215612a0e575f80fd5b8535945060208601356001600160401b03811115612a2a575f80fd5b612a368882890161281b565b9699909850959660408101359660609091013595509350505050565b634e487b7160e01b5f52603260045260245ffd5b604080825281018390525f8460608301825b86811015612aa6576001600160a01b03612a91846126d7565b16825260209283019290910190600101612a78565b5080925050508215156020830152949350505050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b602081525f612af7602083018486612abc565b949350505050565b5f604083018251845260208084015160408287015282815180855260608801915060608160051b890101945083830192505f5b81811015612b7757888603605f190183528351805180885280878301888a015e5f888201880152601f01601f1916909601850195509284019291840191600101612b32565b5093979650505050505050565b828152604060208201525f612af76040830184612aff565b602081525f6128146020830184612aff565b634e487b7160e01b5f52601160045260245ffd5b818103818111156113e1576113e1612bae565b808201808211156113e1576113e1612bae565b60a080825281018690525f6001600160fb1b03871115612c06575f80fd5b8660051b808960c08501376020830196909652506040810193909352606083019190915260808201520160c00192915050565b6bffffffffffffffffffffffff87168152856020820152608060408201525f612c66608083018688612abc565b8281036060840152612c79818587612abc565b9998505050505050505050565b5f60208284031215612c96575f80fd5b81516001600160401b0381168114612814575f80fd5b5f60208284031215612cbc575f80fd5b5051919050565b63ffffffff8181168382160190808211156123d0576123d0612bae565b5f82518060208501845e5f920191825250919050565b63ffffffff818116838216028082169190828114612d1657612d16612bae565b505092915050565b63ffffffff8281168282160390808211156123d0576123d0612bae565b634e487b7160e01b5f52604160045260245ffd5b81515f9082906020808601845b83811015612d7857815185529382019390820190600101612d5c565b50929695505050505050565b634e487b7160e01b5f52601260045260245ffd5b5f63ffffffff80841680612dae57612dae612d84565b92169190910492915050565b80820281158282048414176113e1576113e1612bae565b5f63ffffffff80841680612de757612de7612d84565b9216919091069291505056fea26469706673582212208db0e68b087bd131d23070a73ef53b9a0ac5bea69d42096878ed461ccc09a87564736f6c63430008190033
Deployed Bytecode
0x608060405260043610610194575f3560e01c80637f649783116100e7578063c81de78c11610087578063d3098b9a11610062578063d3098b9a14610415578063f04e283e14610443578063f2fde38b14610456578063fee81cf414610469575f80fd5b8063c81de78c146103e0578063c9179506146103fb578063cf72dddd146103fb575f80fd5b80639468441c116100c25780639468441c146103665780639b19251a146103805780639bc24290146103ae578063c4d66de8146103c1575f80fd5b80637f649783146102ef57806381d12c581461030e5780638da5cb5b1461033b575f80fd5b8063476343ee1161015257806355c2c6711161012d57806355c2c67114610295578063658612e9146102b4578063715018a6146102c85780637b20c8dc146102d0575f80fd5b8063476343ee1461025a578063548db1741461026e57806354d1f13d1461028d575f80fd5b80626d6cae1461019857806308506853146101bf57806312def999146101d457806321dfb600146101f5578063256929621461023357806339393ac91461023b575b5f80fd5b3480156101a3575f80fd5b506101ac5f5481565b6040519081526020015b60405180910390f35b3480156101ca575f80fd5b506101ac61c35081565b3480156101df575f80fd5b506101f36101ee366004612736565b61049a565b005b348015610200575f80fd5b5061022361020f3660046127e4565b60336020525f908152604090205460ff1681565b60405190151581526020016101b6565b6101f36104bc565b348015610246575f80fd5b506101f36102553660046127fb565b610508565b348015610265575f80fd5b50610223610579565b348015610279575f80fd5b506101f361028836600461285b565b61058f565b6101f3610627565b3480156102a0575f80fd5b506101f36102af366004612899565b610660565b3480156102bf575f80fd5b506101ac6106eb565b6101f3610797565b3480156102db575f80fd5b506101f36102ea3660046128e7565b6107aa565b3480156102fa575f80fd5b506101f361030936600461285b565b6109b2565b348015610319575f80fd5b5061032d6103283660046127e4565b610a54565b6040516101b692919061296f565b348015610346575f80fd5b50638b78c6d819546040516001600160a01b0390911681526020016101b6565b348015610371575f80fd5b506101ac6611c37937e0800081565b34801561038b575f80fd5b5061022361039a3660046127fb565b60646020525f908152604090205460ff1681565b6101ac6103bc3660046129fa565b610b2a565b3480156103cc575f80fd5b506101f36103db3660046127fb565b610dfd565b3480156103eb575f80fd5b506101ac6714d1120d7b16000081565b348015610406575f80fd5b506101ac66019945ca26200081565b348015610420575f80fd5b5061022361042f3660046127e4565b60326020525f908152604090205460ff1681565b6101f36104513660046127fb565b610f09565b6101f36104643660046127fb565b610f46565b348015610474575f80fd5b506101ac6104833660046127fb565b63389a75e1600c9081525f91909152602090205490565b6104a2610f6c565b6104b28888888888888888610f86565b5050505050505050565b5f6202a3006001600160401b03164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a250565b610510610f6c565b6001600160a01b0381165f81815260646020908152604091829020805460ff81161560ff1990911681179091558251938452908301819052917fa54714518c5d275fdcd3d2a461e4858e4e8cb04fb93cd0bca9d6d34115f2644091015b60405180910390a15050565b5f610582610f6c565b61058a611026565b905090565b610597610f6c565b5f5b818110156105f35760645f8484848181106105b6576105b6612a52565b90506020020160208101906105cb91906127fb565b6001600160a01b0316815260208101919091526040015f20805460ff19169055600101610599565b507fe481b9d265afbda7824b6945408c17197396b0621a7e5418ac204f8c5abe644582825f60405161056d93929190612a66565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2565b5f8481526033602052604090205460ff161561068f576040516319ed6f1960e11b815260040160405180910390fd5b5f8481526033602052604090819020805460ff1916600117905551839085907fc7f97dc1b8d74ceebb3210d4fa3c174bc04a0723402ea2b5800c07dbc645e2c0906106dd9086908690612ae4565b60405180910390a350505050565b5f6106f4611075565b1561070557506611c37937e0800090565b61070d611096565b1561071f57506714d1120d7b16000090565b6015602160991b013b63ffffffff161561073f575066019945ca26200090565b61044d4603610754575066019945ca26200090565b60405162461bcd60e51b815260206004820152601360248201527210da185a5b881b9bdd081cdd5c1c1bdc9d1959606a1b60448201526064015b60405180910390fd5b61079f610f6c565b6107a85f6110ab565b565b5f8481526001602081815260408084208151808301835281546001600160a01b03168152825160e081018452948201805463ffffffff8082168852640100000000820416878701526001600160401b03600160401b8204811688870152600160801b90910416606087015260028301546080870152600383015460a08701526004830180548551818802810188019096528086529296939587810195929360c0860193929183018282801561087c57602002820191905f5260205f20905b815481526020019060010190808311610868575b505050919092525050509052505f868152600160208190526040822080546001600160a01b031916815590810180546001600160c01b0319168155600282018390556003820183905592935091816108d76004850182612622565b505050506108e3611075565b156108f657602081015182406080909101525b5f610906858584602001516110e8565b8251604051635e5ff5c560e01b81529192506001600160a01b031690635e5ff5c5906109389089908590600401612b84565b5f604051808303815f87803b15801561094f575f80fd5b505af1158015610961573d5f803e3d5ffd5b50505050815f01516001600160a01b0316867f380bea3763a1f2305283f679e3da2563d01a42cfe16d5744b7bd4c9d60ed61bf836040516109a29190612b9c565b60405180910390a3505050505050565b6109ba610f6c565b5f5b81811015610a1f57600160645f8585858181106109db576109db612a52565b90506020020160208101906109f091906127fb565b6001600160a01b0316815260208101919091526040015f20805460ff19169115159190911790556001016109bc565b507fe481b9d265afbda7824b6945408c17197396b0621a7e5418ac204f8c5abe64458282600160405161056d93929190612a66565b600160208181525f9283526040928390208054845160e081018652938201805463ffffffff8082168752640100000000820416868601526001600160401b03600160401b8204811687890152600160801b90910416606086015260028301546080860152600383015460a08601526004830180548751818702810187019098528088526001600160a01b0390931696939594919360c08601939092830182828015610b1c57602002820191905f5260205f20905b815481526020019060010190808311610b08575b505050505081525050905082565b5f610b336106eb565b341015610b535760405163e6b6589360e01b815260040160405180910390fd5b828261044d4614158015610b6d5750610b6a611132565b81115b15610b8b57604051636d53123b60e01b815260040160405180910390fd5b80821115610bac57604051635d6fbc4960e11b815260040160405180910390fd5b61c350610bb98383612bc2565b610bc4906001612bd5565b1115610be3576040516383d304cf60e01b815260040160405180910390fd5b5f8054600101815580610bf4611075565b610c0d57610c00611132565b9150610c0a6111d3565b90505b6040518060400160405280336001600160a01b031681526020016040518060e001604052805f63ffffffff1681526020015f63ffffffff1681526020018a6001600160401b03168152602001896001600160401b031681526020018481526020018d81526020018c8c808060200260200160405190810160405280939291908181526020018383602002808284375f920182905250939094525050919092528054815260016020818152604092839020855181546001600160a01b0319166001600160a01b0390911617815585820151805193820180548285015196830151606084015163ffffffff97881667ffffffffffffffff199093169290921764010000000097909816969096029690961777ffffffffffffffffffffffffffffffff00000000000000001916600160401b6001600160401b039687160267ffffffffffffffff60801b191617600160801b95909616949094029490941783556080840151600282015560a0840151600382015560c08401518051919550610d9992600487019291019061263d565b505050905050336001600160a01b03168a5f547f5f80fe6d2eee22c9cc67535c0777535ddfbc865871b6f0369a4644936102e0a38c8c8c8c348a604051610de596959493929190612be8565b60405180910390a450505f5498975050505050505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b03165f81158015610e415750825b90505f826001600160401b03166001148015610e5c5750303b155b905081158015610e6a575080155b15610e885760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610eb257845460ff60401b1916600160401b1785555b610ebb86611262565b8315610f0157845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b610f11610f6c565b63389a75e1600c52805f526020600c208054421115610f3757636f5e88185f526004601cfd5b5f9055610f43816110ab565b50565b610f4e610f6c565b8060601b610f6357637448fbae5f526004601cfd5b610f43816110ab565b638b78c6d8195433146107a8576382b429005f526004601cfd5b5f8881526032602052604090205460ff1615610fb55760405163e5b70def60e01b815260040160405180910390fd5b5f8881526032602052604090819020805460ff19166001179055516001600160a01b0388169089907f77a60dab33c0274a972cadc956c819927458e5ed5b76a69c45c37ba6ed39f72690611014908a908a908a908a908a908a90612c39565b60405180910390a35050505050505050565b6040515f908190339047908381818185875af1925050503d805f8114611067576040519150601f19603f3d011682016040523d82523d5f602084013e61106c565b606091505b50909392505050565b5f6001461480611087575062aa36a746145b8061058a575050466142681490565b5f61138846148061058a575050466113881490565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355565b604080518082019091525f8152606060208201525f611107858561126b565b90506111148585836113e7565b61111f8585856114ea565b6111298585611a5c565b95945050505050565b5f61113b611075565b1561114557504390565b6015602160991b013b63ffffffff16156111ce576015602160991b016001600160a01b0316638381f58a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561119c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111c09190612c86565b6001600160401b0316905090565b505f90565b5f6111dc611075565b156111e75750434090565b6015602160991b013b63ffffffff16156111ce576015602160991b016001600160a01b03166309bd5a606040518163ffffffff1660e01b8152600401602060405180830381865afa15801561123e573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061058a9190612cac565b610f4381611d09565b611273612686565b61127b6126a4565b611283612686565b5f5b60088163ffffffff1610156112da5785858263ffffffff168181106112ac576112ac612a52565b905060200201355f1c838263ffffffff16600881106112cd576112cd612a52565b6020020152600101611285565b505f5b60038163ffffffff16101561133c5785856112f9836008612cc3565b63ffffffff1681811061130e5761130e612a52565b905060200201355f1c828263ffffffff166003811061132f5761132f612a52565b60200201526001016112dd565b5080517f2f220073107d5d15dd938ce95b310688567a9c1610677513ef91fd0836afc496146113d35760405162461bcd60e51b815260206004820152603b60248201527f5468652066697273742047726f7468313620696e707574206d7573742062652060448201527f657175616c20746f207468652063697263756974206469676573740000000000606482015260840161078e565b6113dd8282611d44565b9150505b92915050565b5f6113f28484612000565b90505f6002826040516114059190612ce0565b602060405180830381855afa158015611420573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906114439190612cac565b6001600160fd1b03169050826002602002015181146114e35760405162461bcd60e51b815260206004820152605060248201527f546865207368613235362068617368206f66207075626c696320696e7075747360448201527f206d75737420626520657175616c20746f20746865206c617374206f6620746860648201526f652047726f7468313620696e7075747360801b608482015260a40161078e565b5050505050565b5f83836114f960056003612cf6565b600a6115065f6001612cc3565b611511906001612cc3565b61151b9190612cc3565b61152690600b612cc3565b6115309190612cc3565b63ffffffff1681811061154557611545612a52565b9050602002013590505f61158285855f600b6115619190612cc3565b63ffffffff1681811061157657611576612a52565b9050602002013561233f565b905061044d4614806115975750826080015181145b6115ee5760405162461bcd60e51b815260206004820152602260248201527f426c6f636b2068617368206d75737420657175616c2061732065787065637465604482015261321760f11b606482015260840161078e565b5f85856115fc836001612cc3565b61160790600b612cc3565b63ffffffff1681811061161c5761161c612a52565b9050602002013590508360a00151811461168b5760405162461bcd60e51b815260206004820152602a60248201527f436f6d7075746174696f6e616c2068617368206d75737420657175616c2061736044820152691032bc3832b1ba32b21760b11b606482015260840161078e565b5f611697816020612cf6565b63ffffffff1684901b60e01c9050600a8111156117025760405162461bcd60e51b815260206004820152602360248201527f506c616365686f6c646572206e756d6265722063616e6e6f74206f766572666c60448201526237bb9760e91b606482015260840161078e565b60c085015151611713906002612bd5565b8163ffffffff161461178d5760405162461bcd60e51b815260206004820152603e60248201527f506c616365686f6c646572206e756d6265722063616e6e6f74206f766572666c60448201527f6f7720616e64206d75737420657175616c2061732065787065637465642e0000606482015260840161078e565b60408501516001600160401b031687876117a85f6001612cc3565b6117b3906001612cc3565b6117be90600b612cc3565b63ffffffff168181106117d3576117d3612a52565b905060200201355f1c14611851576040805162461bcd60e51b81526020600482015260248101919091527f54686520666972737420706c616365686f6c646572206d75737420626520746860448201527f65206578706563746564206d696e696d756d20626c6f636b206e756d6265722e606482015260840161078e565b60608501516001600160401b0316878761186c5f6001612cc3565b611877906001612cc3565b61188290600b612cc3565b61188d906001612cc3565b63ffffffff168181106118a2576118a2612a52565b905060200201355f1c146119285760405162461bcd60e51b815260206004820152604160248201527f546865207365636f6e6420706c616365686f6c646572206d757374206265207460448201527f6865206578706563746564206d6178696d756d20626c6f636b206e756d6265726064820152601760f91b608482015260a40161078e565b5f5b611935600283612d1e565b63ffffffff16811015611a21578560c00151818151811061195857611958612a52565b60200260200101518888835f60016119709190612cc3565b61197b906001612cc3565b61198690600b612cc3565b611991906002612cc3565b63ffffffff166119a19190612bd5565b8181106119b0576119b0612a52565b9050602002013514611a195760405162461bcd60e51b815260206004820152602c60248201527f546865207573657220706c616365686f6c646572206d75737420657175616c2060448201526b30b99032bc3832b1ba32b21760a11b606482015260840161078e565b60010161192a565b505f611a2f60036020612cf6565b63ffffffff1685901b60e01c905080156104b25760405163a729eb9d60e01b815260040160405180910390fd5b604080518082019091525f8152606060208201525f8383611a7f60056003612cf6565b600a611a8c5f6001612cc3565b611a97906001612cc3565b611aa19190612cc3565b611aac90600b612cc3565b611ab69190612cc3565b63ffffffff16818110611acb57611acb612a52565b9050602002013590505f60026020611ae39190612cf6565b63ffffffff1682901b60e01c90505f611afe60016020612cf6565b63ffffffff1683901b60e01c90506003811115611b5d5760405162461bcd60e51b815260206004820152601e60248201527f526573756c74206e756d6265722063616e6e6f74206f766572666c6f772e0000604482015260640161078e565b5f600a611b6b826001612cc3565b611b76906001612cc3565b611b809190612cc3565b611b8b90600b612cc3565b90505f8263ffffffff166001600160401b03811115611bac57611bac612d3b565b604051908082528060200260200182016040528015611bdf57816020015b6060815260200190600190039081611bca5790505b5090505f5b8363ffffffff168163ffffffff161015611ce35760408051600580825260c082019092525f916020820160a0803683370190505090505f5b600563ffffffff82161015611c96578a8a82611c39600587612cf6565b611c439089612cc3565b611c4d9190612cc3565b63ffffffff16818110611c6257611c62612a52565b905060200201355f1c828263ffffffff1681518110611c8357611c83612a52565b6020908102919091010152600101611c1c565b5080604051602001611ca89190612d4f565b604051602081830303815290604052838363ffffffff1681518110611ccf57611ccf612a52565b602090810291909101015250600101611be4565b506040805180820190915263ffffffff9094168452602084015250909250505092915050565b6001600160a01b0316638b78c6d819819055805f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b5f80611d4f836123d7565b915091505f6040515f86015181526020860151602082015260408601516040820152606086015160608201526080860151608082015260a086015160a082015260c086015160c082015260e086015160e08201527f2404b52fc3939b209c8db73c059d84e40dca65a3ac5a9d4840a62496d27922c16101008201527e8944a35f93247fd959f6a69bdccd23521cce4c67b2896d41f8e811e163c3db6101208201527f1f0506b5e4b7ac559f5daf81081d646558798fcdb12dea10b84d19874038c2a46101408201527f0322749fb3842040f9be42bae127fe87497c7e07351b841135c336a7cfffc4146101608201527f065b9d2145cfdfbfe2ea727830a9f7f6fbd4e923e8cb0228f05e867a4c5240716101808201527f13f75b4a7fb2eee944703c2b9ad7646f6b386ccbe8559b29246b616cc28b2ada6101a08201527f0be761df48a24519ac090bf58d00982f4f8e9487fa9927fa05874a1d82ad6ce06101c08201527f09374fb4112affecfcdb368f562b74d7bd32932ed4591977c100e1fc153843996101e08201527f2d10e62780024b9e01e2cd9b64ebdea97a805f70dc72befc3555dc5d1f4ba1cd6102008201527f03739caf38cc5da9ae740d0f22bb3b19edbd164394ba901fb1fa67393639eed961022082015283610240820152826102608201527f17a48b84f79770e34efa0cc6f7e5b12ccf96e467edf33db5d5d76e0fec2cb3706102808201527f1df75b8e713e12cc1413510fe246b9dbb064640039f88b73ee960963c430c9ab6102a08201527f0b7227f47b9d85a2e5e304c45980b771f251320ed88c9125a514f276b7463bbc6102c08201527f050b852f9b263260ed7f7a438b9c16a029d85d7fc976b654dc1b73d5514f8b316102e08201526020816103008360085afa9051169050806114e357604051631ff3747d60e21b815260040160405180910390fd5b60605f61200f60056001612cc3565b61201a906004612cf6565b600b61202860056003612cf6565b600a6120355f6001612cc3565b612040906001612cc3565b61204a9190612cc3565b61205590600b612cc3565b61205f9190612cc3565b6120699190612d1e565b612074906020612cf6565b61207e9190612cc3565b63ffffffff166001600160401b0381111561209b5761209b612d3b565b6040519080825280601f01601f1916602001820160405280156120c5576020820181803683370190505b5090505f60206120d760056001612cc3565b6120e2906004612cf6565b600b6120f060056003612cf6565b600a6120fd5f6001612cc3565b612108906001612cc3565b6121129190612cc3565b61211d90600b612cc3565b6121279190612cc3565b6121319190612d1e565b61213c906020612cf6565b6121469190612cc3565b6121509190612d98565b63ffffffff1690505f5b8181101561220a575f868661217084600b612bd5565b81811061217f5761217f612a52565b9050602002013590505f5b60208163ffffffff16101561220057818163ffffffff16602081106121b1576121b1612a52565b1a60f81b8563ffffffff83166121c8866020612dba565b6121d29190612bd5565b815181106121e2576121e2612a52565b60200101906001600160f81b03191690815f1a90535060010161218a565b505060010161215a565b505f858561221984600b612bd5565b81811061222857612228612a52565b9050602002013590505f5b602061224160056001612cc3565b61224c906004612cf6565b600b61225a60056003612cf6565b600a6122675f6001612cc3565b612272906001612cc3565b61227c9190612cc3565b61228790600b612cc3565b6122919190612cc3565b61229b9190612d1e565b6122a6906020612cf6565b6122b09190612cc3565b6122ba9190612dd1565b63ffffffff168163ffffffff16101561233457818163ffffffff16602081106122e5576122e5612a52565b1a60f81b8463ffffffff83166122fc866020612dba565b6123069190612bd5565b8151811061231657612316612a52565b60200101906001600160f81b03191690815f1a905350600101612233565b509195945050505050565b5f805f5b60088110156123d0575f5b60048110156123c75780612363836004612dba565b61236e906003612bd5565b6123789190612bc2565b612383906008612dba565b8582612390856004612dba565b61239a9190612bd5565b602081106123aa576123aa612a52565b1a60f81b6001600160f81b031916901c929092179160010161234e565b50600101612343565b5092915050565b5f805f60019050604051604081015f7f0b80c8199996f1ac070d2ad2c866b4ac191c2533307106e1b133532819ebcbfe83527f211fd8a967b92e385bce925354a7dc8f9ad6105f7d474bfff934d57d938ee0e960208401527f1f9b5ba456453070086619a2e0271f25389c841003c51797b57c4e75655e1be082527f2b562c41e78d557fc844695d6b443c1a0af45c6e980ddbdaca11e8011ff7984b6020830152865190508060408301527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181108416935060408260608460075afa8416935060408360808560065afa841693507f0e7ed2f79fe74b4b6361980f2327d835473509d9e87d45998257fc5010442e2882527ea1fd9fb54343d961f6cd54cd4219ab9aae13df8f0c88b3056336cc26ebcece6020830152602087015190508060408301527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181108416935060408260608460075afa8416935060408360808560065afa7f1db1aac6dd30bcfb711d394cf6f744abaeb40f3d7b7b2210422995edb8bb39c783527f1156d5aa58c7b1f500b6e1cbbd1ed1ff9839e4652b835e14746242f90a13f17f60208401526040888101518185018190527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000011191909516169390508160608160075afa831692505060408160808360065afa8151602090920151919450909250168061261c5760405163a54f8e2760e01b815260040160405180910390fd5b50915091565b5080545f8255905f5260205f2090810190610f4391906126c3565b828054828255905f5260205f20908101928215612676579160200282015b8281111561267657825182559160200191906001019061265b565b506126829291506126c3565b5090565b60405180606001604052806003906020820280368337509192915050565b6040518061010001604052806008906020820280368337509192915050565b5b80821115612682575f81556001016126c4565b80356001600160a01b03811681146126ed575f80fd5b919050565b5f8083601f840112612702575f80fd5b5081356001600160401b03811115612718575f80fd5b60208301915083602082850101111561272f575f80fd5b9250929050565b5f805f805f805f8060c0898b03121561274d575f80fd5b8835975061275d60208a016126d7565b965060408901356bffffffffffffffffffffffff8116811461277d575f80fd5b95506060890135945060808901356001600160401b038082111561279f575f80fd5b6127ab8c838d016126f2565b909650945060a08b01359150808211156127c3575f80fd5b506127d08b828c016126f2565b999c989b5096995094979396929594505050565b5f602082840312156127f4575f80fd5b5035919050565b5f6020828403121561280b575f80fd5b612814826126d7565b9392505050565b5f8083601f84011261282b575f80fd5b5081356001600160401b03811115612841575f80fd5b6020830191508360208260051b850101111561272f575f80fd5b5f806020838503121561286c575f80fd5b82356001600160401b03811115612881575f80fd5b61288d8582860161281b565b90969095509350505050565b5f805f80606085870312156128ac575f80fd5b843593506020850135925060408501356001600160401b038111156128cf575f80fd5b6128db878288016126f2565b95989497509550505050565b5f805f80606085870312156128fa575f80fd5b8435935060208501356001600160401b03811115612916575f80fd5b6129228782880161281b565b9598909750949560400135949350505050565b5f815180845260208085019450602084015f5b8381101561296457815187529582019590820190600101612948565b509495945050505050565b60018060a01b0383168152604060208201525f63ffffffff808451166040840152806020850151166060840152506001600160401b03604084015116608083015260608301516129ca60a08401826001600160401b03169052565b50608083015160c083015260a083015160e083015260c083015160e0610100840152611129610120840182612935565b5f805f805f60808688031215612a0e575f80fd5b8535945060208601356001600160401b03811115612a2a575f80fd5b612a368882890161281b565b9699909850959660408101359660609091013595509350505050565b634e487b7160e01b5f52603260045260245ffd5b604080825281018390525f8460608301825b86811015612aa6576001600160a01b03612a91846126d7565b16825260209283019290910190600101612a78565b5080925050508215156020830152949350505050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b602081525f612af7602083018486612abc565b949350505050565b5f604083018251845260208084015160408287015282815180855260608801915060608160051b890101945083830192505f5b81811015612b7757888603605f190183528351805180885280878301888a015e5f888201880152601f01601f1916909601850195509284019291840191600101612b32565b5093979650505050505050565b828152604060208201525f612af76040830184612aff565b602081525f6128146020830184612aff565b634e487b7160e01b5f52601160045260245ffd5b818103818111156113e1576113e1612bae565b808201808211156113e1576113e1612bae565b60a080825281018690525f6001600160fb1b03871115612c06575f80fd5b8660051b808960c08501376020830196909652506040810193909352606083019190915260808201520160c00192915050565b6bffffffffffffffffffffffff87168152856020820152608060408201525f612c66608083018688612abc565b8281036060840152612c79818587612abc565b9998505050505050505050565b5f60208284031215612c96575f80fd5b81516001600160401b0381168114612814575f80fd5b5f60208284031215612cbc575f80fd5b5051919050565b63ffffffff8181168382160190808211156123d0576123d0612bae565b5f82518060208501845e5f920191825250919050565b63ffffffff818116838216028082169190828114612d1657612d16612bae565b505092915050565b63ffffffff8281168282160390808211156123d0576123d0612bae565b634e487b7160e01b5f52604160045260245ffd5b81515f9082906020808601845b83811015612d7857815185529382019390820190600101612d5c565b50929695505050505050565b634e487b7160e01b5f52601260045260245ffd5b5f63ffffffff80841680612dae57612dae612d84565b92169190910492915050565b80820281158282048414176113e1576113e1612bae565b5f63ffffffff80841680612de757612de7612d84565b9216919091069291505056fea26469706673582212208db0e68b087bd131d23070a73ef53b9a0ac5bea69d42096878ed461ccc09a87564736f6c63430008190033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 27 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ 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.