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 | 20667677 | 69 days ago | IN | 0 ETH | 0.0030129 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
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 = 14; // 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 = 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."); // TODO: Each result value is an Uint256 and need to confirm this encoding code. // And it encodes the whole row with dummy values, since we don't know the real // number of items per result here. uint32 offset = PI_OFFSET + RESULT_VALUES_POS; bytes[] memory rows = new bytes[](numResults); for (uint256 i = 0; i < numResults; ++i) { rows[i] = abi.encode( data[ offset + i * MAX_NUM_ITEMS_PER_OUTPUT: offset + (i + 1) * MAX_NUM_ITEMS_PER_OUTPUT ] ); } QueryOutput memory output = QueryOutput({totalMatchedRows: totalMatchedRows, rows: rows}); return output; } }
// 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 = 17907337084192034765119714908911515289906764691979827894695344987889478541781; uint256 constant ALPHA_Y = 12081345641630512954554054616291084687120235460903563256531721577550101103355; // Groth16 beta point in G2 in powers of i uint256 constant BETA_NEG_X_0 = 1321340443706860886436957793321584755563222541101768411890716174570741920888; uint256 constant BETA_NEG_X_1 = 920363870669119483034097620638982273796249632396243853650793408827776494946; uint256 constant BETA_NEG_Y_0 = 4195793325450645855813358536487033233301305964202899721144542528515217913046; uint256 constant BETA_NEG_Y_1 = 4536471338710790329574260299407145985054983030628740264745065379798505540277; // Groth16 gamma point in G2 in powers of i uint256 constant GAMMA_NEG_X_0 = 12571758756220634190514175557306433519556272056257098779840280778464430061066; uint256 constant GAMMA_NEG_X_1 = 14273535764379946710540177133638120129655732233944995562618230898164782072255; uint256 constant GAMMA_NEG_Y_0 = 11103029107274626994884738710525502032304625660495260793626815437650071921453; uint256 constant GAMMA_NEG_Y_1 = 21429319373771741409083380502870292961538602348974432497032400475283747952572; // Groth16 delta point in G2 in powers of i uint256 constant DELTA_NEG_X_0 = 12919809559089348596199526724652277781891068305322193275707327055616857379966; uint256 constant DELTA_NEG_X_1 = 5511422485602468108861855528593943865334080850416272727097143838293216639215; uint256 constant DELTA_NEG_Y_0 = 8970731587382751322010109173871096578249484627287472271602859842894560360684; uint256 constant DELTA_NEG_Y_1 = 7509029918022231803529436917154276080065723840110322075236055027947365873148; // Constant and public input points uint256 constant CONSTANT_X = 12050350580237785728456149127021902371527603008304628288955799130439009294661; uint256 constant CONSTANT_Y = 8971262406129550343747641016671753435023288156830139050058550579971406166994; uint256 constant PUB_0_X = 15432206935594661954711361759382054827491859145187546845262342689137822766451; uint256 constant PUB_0_Y = 6225727369118324581048921232767732114392225356569519817159401999523544733879; uint256 constant PUB_1_X = 11568293976853107246955142917121588330248018158931691036422993254958632295940; uint256 constant PUB_1_Y = 9714678980441493265192687167866917501505220659712154610563614762542916480933; uint256 constant PUB_2_X = 21033449728405906145571511337915392892876480995206328441395146396091883633727; uint256 constant PUB_2_Y = 8630849778917286526883999490781889401640014431687430806620475130538470507687; /// 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 = 0x1ef3e0e4525d9634361ccfbbaab5825505dadaae75dfc5278ba0ab9824dabfc0; }
{ "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
6080604052348015600e575f80fd5b50612d5e8061001c5f395ff3fe608060405260043610610194575f3560e01c80637f649783116100e7578063c81de78c11610087578063d3098b9a11610062578063d3098b9a14610415578063f04e283e14610443578063f2fde38b14610456578063fee81cf414610469575f80fd5b8063c81de78c146103e0578063c9179506146103fb578063cf72dddd146103fb575f80fd5b80639468441c116100c25780639468441c146103665780639b19251a146103805780639bc24290146103ae578063c4d66de8146103c1575f80fd5b80637f649783146102ef57806381d12c581461030e5780638da5cb5b1461033b575f80fd5b8063476343ee1161015257806355c2c6711161012d57806355c2c67114610295578063658612e9146102b4578063715018a6146102c85780637b20c8dc146102d0575f80fd5b8063476343ee1461025a578063548db1741461026e57806354d1f13d1461028d575f80fd5b80626d6cae1461019857806308506853146101bf57806312def999146101d457806321dfb600146101f5578063256929621461023357806339393ac91461023b575b5f80fd5b3480156101a3575f80fd5b506101ac5f5481565b6040519081526020015b60405180910390f35b3480156101ca575f80fd5b506101ac61c35081565b3480156101df575f80fd5b506101f36101ee366004612644565b61049a565b005b348015610200575f80fd5b5061022361020f3660046126f2565b60336020525f908152604090205460ff1681565b60405190151581526020016101b6565b6101f36104bc565b348015610246575f80fd5b506101f3610255366004612709565b610508565b348015610265575f80fd5b50610223610579565b348015610279575f80fd5b506101f3610288366004612769565b61058f565b6101f3610627565b3480156102a0575f80fd5b506101f36102af3660046127a7565b610660565b3480156102bf575f80fd5b506101ac6106eb565b6101f3610797565b3480156102db575f80fd5b506101f36102ea3660046127f5565b6107aa565b3480156102fa575f80fd5b506101f3610309366004612769565b6109b2565b348015610319575f80fd5b5061032d6103283660046126f2565b610a54565b6040516101b692919061287d565b348015610346575f80fd5b50638b78c6d819546040516001600160a01b0390911681526020016101b6565b348015610371575f80fd5b506101ac6611c37937e0800081565b34801561038b575f80fd5b5061022361039a366004612709565b60646020525f908152604090205460ff1681565b6101ac6103bc366004612908565b610b2a565b3480156103cc575f80fd5b506101f36103db366004612709565b610dfd565b3480156103eb575f80fd5b506101ac6714d1120d7b16000081565b348015610406575f80fd5b506101ac66019945ca26200081565b348015610420575f80fd5b5061022361042f3660046126f2565b60326020525f908152604090205460ff1681565b6101f3610451366004612709565b610f09565b6101f3610464366004612709565b610f46565b348015610474575f80fd5b506101ac610483366004612709565b63389a75e1600c9081525f91909152602090205490565b6104a2610f6c565b6104b28888888888888888610f86565b5050505050505050565b5f6202a3006001600160401b03164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a250565b610510610f6c565b6001600160a01b0381165f81815260646020908152604091829020805460ff81161560ff1990911681179091558251938452908301819052917fa54714518c5d275fdcd3d2a461e4858e4e8cb04fb93cd0bca9d6d34115f2644091015b60405180910390a15050565b5f610582610f6c565b61058a611026565b905090565b610597610f6c565b5f5b818110156105f35760645f8484848181106105b6576105b6612960565b90506020020160208101906105cb9190612709565b6001600160a01b0316815260208101919091526040015f20805460ff19169055600101610599565b507fe481b9d265afbda7824b6945408c17197396b0621a7e5418ac204f8c5abe644582825f60405161056d93929190612974565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2565b5f8481526033602052604090205460ff161561068f576040516319ed6f1960e11b815260040160405180910390fd5b5f8481526033602052604090819020805460ff1916600117905551839085907fc7f97dc1b8d74ceebb3210d4fa3c174bc04a0723402ea2b5800c07dbc645e2c0906106dd90869086906129f2565b60405180910390a350505050565b5f6106f4611075565b1561070557506611c37937e0800090565b61070d611096565b1561071f57506714d1120d7b16000090565b6015602160991b013b63ffffffff161561073f575066019945ca26200090565b61044d4603610754575066019945ca26200090565b60405162461bcd60e51b815260206004820152601360248201527210da185a5b881b9bdd081cdd5c1c1bdc9d1959606a1b60448201526064015b60405180910390fd5b61079f610f6c565b6107a85f6110ab565b565b5f8481526001602081815260408084208151808301835281546001600160a01b03168152825160e081018452948201805463ffffffff8082168852640100000000820416878701526001600160401b03600160401b8204811688870152600160801b90910416606087015260028301546080870152600383015460a08701526004830180548551818802810188019096528086529296939587810195929360c0860193929183018282801561087c57602002820191905f5260205f20905b815481526020019060010190808311610868575b505050919092525050509052505f868152600160208190526040822080546001600160a01b031916815590810180546001600160c01b0319168155600282018390556003820183905592935091816108d76004850182612530565b505050506108e3611075565b156108f657602081015182406080909101525b5f610906858584602001516110e8565b8251604051635e5ff5c560e01b81529192506001600160a01b031690635e5ff5c5906109389089908590600401612a92565b5f604051808303815f87803b15801561094f575f80fd5b505af1158015610961573d5f803e3d5ffd5b50505050815f01516001600160a01b0316867f380bea3763a1f2305283f679e3da2563d01a42cfe16d5744b7bd4c9d60ed61bf836040516109a29190612aaa565b60405180910390a3505050505050565b6109ba610f6c565b5f5b81811015610a1f57600160645f8585858181106109db576109db612960565b90506020020160208101906109f09190612709565b6001600160a01b0316815260208101919091526040015f20805460ff19169115159190911790556001016109bc565b507fe481b9d265afbda7824b6945408c17197396b0621a7e5418ac204f8c5abe64458282600160405161056d93929190612974565b600160208181525f9283526040928390208054845160e081018652938201805463ffffffff8082168752640100000000820416868601526001600160401b03600160401b8204811687890152600160801b90910416606086015260028301546080860152600383015460a08601526004830180548751818702810187019098528088526001600160a01b0390931696939594919360c08601939092830182828015610b1c57602002820191905f5260205f20905b815481526020019060010190808311610b08575b505050505081525050905082565b5f610b336106eb565b341015610b535760405163e6b6589360e01b815260040160405180910390fd5b828261044d4614158015610b6d5750610b6a611132565b81115b15610b8b57604051636d53123b60e01b815260040160405180910390fd5b80821115610bac57604051635d6fbc4960e11b815260040160405180910390fd5b61c350610bb98383612ad0565b610bc4906001612ae3565b1115610be3576040516383d304cf60e01b815260040160405180910390fd5b5f8054600101815580610bf4611075565b610c0d57610c00611132565b9150610c0a6111d3565b90505b6040518060400160405280336001600160a01b031681526020016040518060e001604052805f63ffffffff1681526020015f63ffffffff1681526020018a6001600160401b03168152602001896001600160401b031681526020018481526020018d81526020018c8c808060200260200160405190810160405280939291908181526020018383602002808284375f920182905250939094525050919092528054815260016020818152604092839020855181546001600160a01b0319166001600160a01b0390911617815585820151805193820180548285015196830151606084015163ffffffff97881667ffffffffffffffff199093169290921764010000000097909816969096029690961777ffffffffffffffffffffffffffffffff00000000000000001916600160401b6001600160401b039687160267ffffffffffffffff60801b191617600160801b95909616949094029490941783556080840151600282015560a0840151600382015560c08401518051919550610d9992600487019291019061254b565b505050905050336001600160a01b03168a5f547f5f80fe6d2eee22c9cc67535c0777535ddfbc865871b6f0369a4644936102e0a38c8c8c8c348a604051610de596959493929190612b26565b60405180910390a450505f5498975050505050505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b03165f81158015610e415750825b90505f826001600160401b03166001148015610e5c5750303b155b905081158015610e6a575080155b15610e885760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610eb257845460ff60401b1916600160401b1785555b610ebb86611262565b8315610f0157845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b610f11610f6c565b63389a75e1600c52805f526020600c208054421115610f3757636f5e88185f526004601cfd5b5f9055610f43816110ab565b50565b610f4e610f6c565b8060601b610f6357637448fbae5f526004601cfd5b610f43816110ab565b638b78c6d8195433146107a8576382b429005f526004601cfd5b5f8881526032602052604090205460ff1615610fb55760405163e5b70def60e01b815260040160405180910390fd5b5f8881526032602052604090819020805460ff19166001179055516001600160a01b0388169089907f77a60dab33c0274a972cadc956c819927458e5ed5b76a69c45c37ba6ed39f72690611014908a908a908a908a908a908a90612b5e565b60405180910390a35050505050505050565b6040515f908190339047908381818185875af1925050503d805f8114611067576040519150601f19603f3d011682016040523d82523d5f602084013e61106c565b606091505b50909392505050565b5f6001461480611087575062aa36a746145b8061058a575050466142681490565b5f61138846148061058a575050466113881490565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355565b604080518082019091525f8152606060208201525f611107858561126b565b90506111148585836113e7565b61111f8585856114ea565b6111298585611a5a565b95945050505050565b5f61113b611075565b1561114557504390565b6015602160991b013b63ffffffff16156111ce576015602160991b016001600160a01b0316638381f58a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561119c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111c09190612bab565b6001600160401b0316905090565b505f90565b5f6111dc611075565b156111e75750434090565b6015602160991b013b63ffffffff16156111ce576015602160991b016001600160a01b03166309bd5a606040518163ffffffff1660e01b8152600401602060405180830381865afa15801561123e573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061058a9190612bd1565b610f4381611cad565b611273612594565b61127b6125b2565b611283612594565b5f5b60088163ffffffff1610156112da5785858263ffffffff168181106112ac576112ac612960565b905060200201355f1c838263ffffffff16600881106112cd576112cd612960565b6020020152600101611285565b505f5b60038163ffffffff16101561133c5785856112f9836008612be8565b63ffffffff1681811061130e5761130e612960565b905060200201355f1c828263ffffffff166003811061132f5761132f612960565b60200201526001016112dd565b5080517f1ef3e0e4525d9634361ccfbbaab5825505dadaae75dfc5278ba0ab9824dabfc0146113d35760405162461bcd60e51b815260206004820152603b60248201527f5468652066697273742047726f7468313620696e707574206d7573742062652060448201527f657175616c20746f207468652063697263756974206469676573740000000000606482015260840161078e565b6113dd8282611ce8565b9150505b92915050565b5f6113f28484611fa5565b90505f6002826040516114059190612c0c565b602060405180830381855afa158015611420573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906114439190612bd1565b6001600160fd1b03169050826002602002015181146114e35760405162461bcd60e51b815260206004820152605060248201527f546865207368613235362068617368206f66207075626c696320696e7075747360448201527f206d75737420626520657175616c20746f20746865206c617374206f6620746860648201526f652047726f7468313620696e7075747360801b608482015260a40161078e565b5050505050565b5f83836114f960056003612c22565b600e6115065f6001612be8565b611511906001612be8565b61151b9190612be8565b61152690600b612be8565b6115309190612be8565b63ffffffff1681811061154557611545612960565b9050602002013590505f84845f600b61155e9190612be8565b63ffffffff1681811061157357611573612960565b9050602002013590506115874661044d1490565b806115955750826080015181145b6115ec5760405162461bcd60e51b815260206004820152602260248201527f426c6f636b2068617368206d75737420657175616c2061732065787065637465604482015261321760f11b606482015260840161078e565b5f85856115fa836001612be8565b61160590600b612be8565b63ffffffff1681811061161a5761161a612960565b9050602002013590508360a0015181146116895760405162461bcd60e51b815260206004820152602a60248201527f436f6d7075746174696f6e616c2068617368206d75737420657175616c2061736044820152691032bc3832b1ba32b21760b11b606482015260840161078e565b5f611695816020612c22565b63ffffffff1684901b60e01c9050600e8111156117005760405162461bcd60e51b815260206004820152602360248201527f506c616365686f6c646572206e756d6265722063616e6e6f74206f766572666c60448201526237bb9760e91b606482015260840161078e565b60c085015151611711906002612ae3565b8163ffffffff161461178b5760405162461bcd60e51b815260206004820152603e60248201527f506c616365686f6c646572206e756d6265722063616e6e6f74206f766572666c60448201527f6f7720616e64206d75737420657175616c2061732065787065637465642e0000606482015260840161078e565b60408501516001600160401b031687876117a65f6001612be8565b6117b1906001612be8565b6117bc90600b612be8565b63ffffffff168181106117d1576117d1612960565b905060200201355f1c1461184f576040805162461bcd60e51b81526020600482015260248101919091527f54686520666972737420706c616365686f6c646572206d75737420626520746860448201527f65206578706563746564206d696e696d756d20626c6f636b206e756d6265722e606482015260840161078e565b60608501516001600160401b0316878761186a5f6001612be8565b611875906001612be8565b61188090600b612be8565b61188b906001612be8565b63ffffffff168181106118a0576118a0612960565b905060200201355f1c146119265760405162461bcd60e51b815260206004820152604160248201527f546865207365636f6e6420706c616365686f6c646572206d757374206265207460448201527f6865206578706563746564206d6178696d756d20626c6f636b206e756d6265726064820152601760f91b608482015260a40161078e565b5f5b611933600283612c4a565b63ffffffff16811015611a1f578560c00151818151811061195657611956612960565b60200260200101518888835f600161196e9190612be8565b611979906001612be8565b61198490600b612be8565b61198f906002612be8565b63ffffffff1661199f9190612ae3565b8181106119ae576119ae612960565b9050602002013514611a175760405162461bcd60e51b815260206004820152602c60248201527f546865207573657220706c616365686f6c646572206d75737420657175616c2060448201526b30b99032bc3832b1ba32b21760a11b606482015260840161078e565b600101611928565b505f611a2d60036020612c22565b63ffffffff1685901b60e01c905080156104b25760405163a729eb9d60e01b815260040160405180910390fd5b604080518082019091525f8152606060208201525f8383611a7d60056003612c22565b600e611a8a5f6001612be8565b611a95906001612be8565b611a9f9190612be8565b611aaa90600b612be8565b611ab49190612be8565b63ffffffff16818110611ac957611ac9612960565b9050602002013590505f60026020611ae19190612c22565b63ffffffff1682901b60e01c90505f611afc60016020612c22565b63ffffffff1683901b60e01c90506003811115611b5b5760405162461bcd60e51b815260206004820152601e60248201527f526573756c74206e756d6265722063616e6e6f74206f766572666c6f772e0000604482015260640161078e565b5f600e611b69826001612be8565b611b74906001612be8565b611b7e9190612be8565b611b8990600b612be8565b90505f8263ffffffff166001600160401b03811115611baa57611baa612c67565b604051908082528060200260200182016040528015611bdd57816020015b6060815260200190600190039081611bc85790505b5090505f5b8363ffffffff16811015611c87578888611bfd600584612c7b565b611c0d9063ffffffff8716612ae3565b906005611c1b856001612ae3565b611c259190612c7b565b611c359063ffffffff8816612ae3565b92611c4293929190612c92565b604051602001611c53929190612cbd565b604051602081830303815290604052828281518110611c7457611c74612960565b6020908102919091010152600101611be2565b506040805180820190915263ffffffff9094168452602084015250909250505092915050565b6001600160a01b0316638b78c6d819819055805f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b5f80611cf3836122e4565b915091505f6040515f86015181526020860151602082015260408601516040820152606086015160608201526080860151608082015260a086015160a082015260c086015160c082015260e086015160e08201527f0c2f5ac5d38ac6bc5ffcc6d0443959df057e1b248b2179d185238ae4998ab8ef6101008201527f1c905a62d2a5dfbcf97c7134a26053e0225f7c3dbbeed02cf53050bfa8a0947e6101208201527f1099f5d793846a7f876ab3ada153ce75145db25319db01334448f437228635fc6101408201527f13d5410fcd052f4dbcfeab3213d2abda0036b2adceaf3b2315ebaf189171f8ec6101608201527f279731908d1a2a3cba0f3bdb5f96692b6ea1ac4826ff30a7422b6e38526a21d56101808201527f1ab5cc9fa00adbfdd948d63c641ca9772b0f1b82ed4bed83bebfc500af1842fb6101a08201527f0208e8514cb036a5a0c06c74fe594ebd71d3efd7657b6b1e3a45a0a48f4eed626101c08201527f02ebda29026e498463705b9f25bbefea6278dd729e7976a7a6af4d8a6ac574786101e08201527f0a078d41eb6d0b701853ba078cc0d26c04c95b72f9fb6c3720a1787c4c6ccab56102008201527f0946bc201905fd784086058caf5489559f443bee8b4eb332f23f5a0401f574d661022082015283610240820152826102608201527f1f8e88f27e31f5c6d77f8bbf1727178390b35df1509fd39963804629a8c801bf6102808201527f1bcb5d01090abf1d5f2a0da22e30d77db2259b3699f0840152937b5ad3eef60a6102a08201527f2f6090a0432c2a0e8affb6d97e10aef434ce8c7d19887a528b35008d963ed7bc6102c08201527f188c177e8f44e7b4d3b38029e7162e4b3998e8215c72e3309814b6e9f92c232d6102e08201526020816103008360085afa9051169050806114e357604051631ff3747d60e21b815260040160405180910390fd5b60605f611fb460056001612be8565b611fbf906004612c22565b600b611fcd60056003612c22565b600e611fda5f6001612be8565b611fe5906001612be8565b611fef9190612be8565b611ffa90600b612be8565b6120049190612be8565b61200e9190612c4a565b612019906020612c22565b6120239190612be8565b63ffffffff166001600160401b0381111561204057612040612c67565b6040519080825280601f01601f19166020018201604052801561206a576020820181803683370190505b5090505f602061207c60056001612be8565b612087906004612c22565b600b61209560056003612c22565b600e6120a25f6001612be8565b6120ad906001612be8565b6120b79190612be8565b6120c290600b612be8565b6120cc9190612be8565b6120d69190612c4a565b6120e1906020612c22565b6120eb9190612be8565b6120f59190612ce4565b63ffffffff1690505f5b818110156121af575f868661211584600b612ae3565b81811061212457612124612960565b9050602002013590505f5b60208163ffffffff1610156121a557818163ffffffff166020811061215657612156612960565b1a60f81b8563ffffffff831661216d866020612c7b565b6121779190612ae3565b8151811061218757612187612960565b60200101906001600160f81b03191690815f1a90535060010161212f565b50506001016120ff565b505f85856121be84600b612ae3565b8181106121cd576121cd612960565b9050602002013590505f5b60206121e660056001612be8565b6121f1906004612c22565b600b6121ff60056003612c22565b600e61220c5f6001612be8565b612217906001612be8565b6122219190612be8565b61222c90600b612be8565b6122369190612be8565b6122409190612c4a565b61224b906020612c22565b6122559190612be8565b61225f9190612d06565b63ffffffff168163ffffffff1610156122d957818163ffffffff166020811061228a5761228a612960565b1a60f81b8463ffffffff83166122a1866020612c7b565b6122ab9190612ae3565b815181106122bb576122bb612960565b60200101906001600160f81b03191690815f1a9053506001016121d8565b509195945050505050565b5f805f60019050604051604081015f7f1aa441b8e6cdc56f63ee195b4583f410a0f4ace2aee367532ca44844d465d94583527f13d58df8f66425d86bb391d54bb55fa9c0fe63e9fafafe6ca3601d582303fbd260208401527f221e51d0d785f9584d94c40aec1ad869d729a0980dd83f57d67d62acc8c7957382527f0dc3a30680180e89d0710191d17fca3f2976b4d44d0fb6826744feac537e98b76020830152865190508060408301527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181108416935060408260608460075afa8416935060408360808560065afa841693507f19936c1fb812df1ee42ed160cb8edc80f17e0cf083e7a2115bc904c95d045e0482527f157a503e431747341c40111cd07246ef27d3d3d00c87e26572dd93df03ecafa56020830152602087015190508060408301527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181108416935060408260608460075afa8416935060408360808560065afa7f2e8082bb071c7f8f8b22e411ca17cfd99d1f3699cdf5ef73ad9d35f7ce26bc3f83527f1314e34adb2f6120fef9c5a6a67056a06f52b0609a26316edbb685ce2f6984a760208401526040888101518185018190527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000011191909516169390508160608160075afa831692505060408160808360065afa8151602090920151919450909250168061252a5760405163a54f8e2760e01b815260040160405180910390fd5b50915091565b5080545f8255905f5260205f2090810190610f4391906125d1565b828054828255905f5260205f20908101928215612584579160200282015b82811115612584578251825591602001919060010190612569565b506125909291506125d1565b5090565b60405180606001604052806003906020820280368337509192915050565b6040518061010001604052806008906020820280368337509192915050565b5b80821115612590575f81556001016125d2565b80356001600160a01b03811681146125fb575f80fd5b919050565b5f8083601f840112612610575f80fd5b5081356001600160401b03811115612626575f80fd5b60208301915083602082850101111561263d575f80fd5b9250929050565b5f805f805f805f8060c0898b03121561265b575f80fd5b8835975061266b60208a016125e5565b965060408901356bffffffffffffffffffffffff8116811461268b575f80fd5b95506060890135945060808901356001600160401b03808211156126ad575f80fd5b6126b98c838d01612600565b909650945060a08b01359150808211156126d1575f80fd5b506126de8b828c01612600565b999c989b5096995094979396929594505050565b5f60208284031215612702575f80fd5b5035919050565b5f60208284031215612719575f80fd5b612722826125e5565b9392505050565b5f8083601f840112612739575f80fd5b5081356001600160401b0381111561274f575f80fd5b6020830191508360208260051b850101111561263d575f80fd5b5f806020838503121561277a575f80fd5b82356001600160401b0381111561278f575f80fd5b61279b85828601612729565b90969095509350505050565b5f805f80606085870312156127ba575f80fd5b843593506020850135925060408501356001600160401b038111156127dd575f80fd5b6127e987828801612600565b95989497509550505050565b5f805f8060608587031215612808575f80fd5b8435935060208501356001600160401b03811115612824575f80fd5b61283087828801612729565b9598909750949560400135949350505050565b5f815180845260208085019450602084015f5b8381101561287257815187529582019590820190600101612856565b509495945050505050565b60018060a01b0383168152604060208201525f63ffffffff808451166040840152806020850151166060840152506001600160401b03604084015116608083015260608301516128d860a08401826001600160401b03169052565b50608083015160c083015260a083015160e083015260c083015160e0610100840152611129610120840182612843565b5f805f805f6080868803121561291c575f80fd5b8535945060208601356001600160401b03811115612938575f80fd5b61294488828901612729565b9699909850959660408101359660609091013595509350505050565b634e487b7160e01b5f52603260045260245ffd5b604080825281018390525f8460608301825b868110156129b4576001600160a01b0361299f846125e5565b16825260209283019290910190600101612986565b5080925050508215156020830152949350505050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b602081525f612a056020830184866129ca565b949350505050565b5f604083018251845260208084015160408287015282815180855260608801915060608160051b890101945083830192505f5b81811015612a8557888603605f190183528351805180885280878301888a015e5f888201880152601f01601f1916909601850195509284019291840191600101612a40565b5093979650505050505050565b828152604060208201525f612a056040830184612a0d565b602081525f6127226020830184612a0d565b634e487b7160e01b5f52601160045260245ffd5b818103818111156113e1576113e1612abc565b808201808211156113e1576113e1612abc565b8183525f6001600160fb1b03831115612b0d575f80fd5b8260051b80836020870137939093016020019392505050565b60a081525f612b3960a08301888a612af6565b9050856020830152846040830152836060830152826080830152979650505050505050565b6bffffffffffffffffffffffff87168152856020820152608060408201525f612b8b6080830186886129ca565b8281036060840152612b9e8185876129ca565b9998505050505050505050565b5f60208284031215612bbb575f80fd5b81516001600160401b0381168114612722575f80fd5b5f60208284031215612be1575f80fd5b5051919050565b63ffffffff818116838216019080821115612c0557612c05612abc565b5092915050565b5f82518060208501845e5f920191825250919050565b63ffffffff818116838216028082169190828114612c4257612c42612abc565b505092915050565b63ffffffff828116828216039080821115612c0557612c05612abc565b634e487b7160e01b5f52604160045260245ffd5b80820281158282048414176113e1576113e1612abc565b5f8085851115612ca0575f80fd5b83861115612cac575f80fd5b5050600583901b0193919092039150565b602081525f612a05602083018486612af6565b634e487b7160e01b5f52601260045260245ffd5b5f63ffffffff80841680612cfa57612cfa612cd0565b92169190910492915050565b5f63ffffffff80841680612d1c57612d1c612cd0565b9216919091069291505056fea26469706673582212209c8c3ea02e94c3470a01fa01109bfe82bfc9daf8d8c82550503116f36279e4af64736f6c63430008190033
Deployed Bytecode
0x608060405260043610610194575f3560e01c80637f649783116100e7578063c81de78c11610087578063d3098b9a11610062578063d3098b9a14610415578063f04e283e14610443578063f2fde38b14610456578063fee81cf414610469575f80fd5b8063c81de78c146103e0578063c9179506146103fb578063cf72dddd146103fb575f80fd5b80639468441c116100c25780639468441c146103665780639b19251a146103805780639bc24290146103ae578063c4d66de8146103c1575f80fd5b80637f649783146102ef57806381d12c581461030e5780638da5cb5b1461033b575f80fd5b8063476343ee1161015257806355c2c6711161012d57806355c2c67114610295578063658612e9146102b4578063715018a6146102c85780637b20c8dc146102d0575f80fd5b8063476343ee1461025a578063548db1741461026e57806354d1f13d1461028d575f80fd5b80626d6cae1461019857806308506853146101bf57806312def999146101d457806321dfb600146101f5578063256929621461023357806339393ac91461023b575b5f80fd5b3480156101a3575f80fd5b506101ac5f5481565b6040519081526020015b60405180910390f35b3480156101ca575f80fd5b506101ac61c35081565b3480156101df575f80fd5b506101f36101ee366004612644565b61049a565b005b348015610200575f80fd5b5061022361020f3660046126f2565b60336020525f908152604090205460ff1681565b60405190151581526020016101b6565b6101f36104bc565b348015610246575f80fd5b506101f3610255366004612709565b610508565b348015610265575f80fd5b50610223610579565b348015610279575f80fd5b506101f3610288366004612769565b61058f565b6101f3610627565b3480156102a0575f80fd5b506101f36102af3660046127a7565b610660565b3480156102bf575f80fd5b506101ac6106eb565b6101f3610797565b3480156102db575f80fd5b506101f36102ea3660046127f5565b6107aa565b3480156102fa575f80fd5b506101f3610309366004612769565b6109b2565b348015610319575f80fd5b5061032d6103283660046126f2565b610a54565b6040516101b692919061287d565b348015610346575f80fd5b50638b78c6d819546040516001600160a01b0390911681526020016101b6565b348015610371575f80fd5b506101ac6611c37937e0800081565b34801561038b575f80fd5b5061022361039a366004612709565b60646020525f908152604090205460ff1681565b6101ac6103bc366004612908565b610b2a565b3480156103cc575f80fd5b506101f36103db366004612709565b610dfd565b3480156103eb575f80fd5b506101ac6714d1120d7b16000081565b348015610406575f80fd5b506101ac66019945ca26200081565b348015610420575f80fd5b5061022361042f3660046126f2565b60326020525f908152604090205460ff1681565b6101f3610451366004612709565b610f09565b6101f3610464366004612709565b610f46565b348015610474575f80fd5b506101ac610483366004612709565b63389a75e1600c9081525f91909152602090205490565b6104a2610f6c565b6104b28888888888888888610f86565b5050505050505050565b5f6202a3006001600160401b03164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a250565b610510610f6c565b6001600160a01b0381165f81815260646020908152604091829020805460ff81161560ff1990911681179091558251938452908301819052917fa54714518c5d275fdcd3d2a461e4858e4e8cb04fb93cd0bca9d6d34115f2644091015b60405180910390a15050565b5f610582610f6c565b61058a611026565b905090565b610597610f6c565b5f5b818110156105f35760645f8484848181106105b6576105b6612960565b90506020020160208101906105cb9190612709565b6001600160a01b0316815260208101919091526040015f20805460ff19169055600101610599565b507fe481b9d265afbda7824b6945408c17197396b0621a7e5418ac204f8c5abe644582825f60405161056d93929190612974565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2565b5f8481526033602052604090205460ff161561068f576040516319ed6f1960e11b815260040160405180910390fd5b5f8481526033602052604090819020805460ff1916600117905551839085907fc7f97dc1b8d74ceebb3210d4fa3c174bc04a0723402ea2b5800c07dbc645e2c0906106dd90869086906129f2565b60405180910390a350505050565b5f6106f4611075565b1561070557506611c37937e0800090565b61070d611096565b1561071f57506714d1120d7b16000090565b6015602160991b013b63ffffffff161561073f575066019945ca26200090565b61044d4603610754575066019945ca26200090565b60405162461bcd60e51b815260206004820152601360248201527210da185a5b881b9bdd081cdd5c1c1bdc9d1959606a1b60448201526064015b60405180910390fd5b61079f610f6c565b6107a85f6110ab565b565b5f8481526001602081815260408084208151808301835281546001600160a01b03168152825160e081018452948201805463ffffffff8082168852640100000000820416878701526001600160401b03600160401b8204811688870152600160801b90910416606087015260028301546080870152600383015460a08701526004830180548551818802810188019096528086529296939587810195929360c0860193929183018282801561087c57602002820191905f5260205f20905b815481526020019060010190808311610868575b505050919092525050509052505f868152600160208190526040822080546001600160a01b031916815590810180546001600160c01b0319168155600282018390556003820183905592935091816108d76004850182612530565b505050506108e3611075565b156108f657602081015182406080909101525b5f610906858584602001516110e8565b8251604051635e5ff5c560e01b81529192506001600160a01b031690635e5ff5c5906109389089908590600401612a92565b5f604051808303815f87803b15801561094f575f80fd5b505af1158015610961573d5f803e3d5ffd5b50505050815f01516001600160a01b0316867f380bea3763a1f2305283f679e3da2563d01a42cfe16d5744b7bd4c9d60ed61bf836040516109a29190612aaa565b60405180910390a3505050505050565b6109ba610f6c565b5f5b81811015610a1f57600160645f8585858181106109db576109db612960565b90506020020160208101906109f09190612709565b6001600160a01b0316815260208101919091526040015f20805460ff19169115159190911790556001016109bc565b507fe481b9d265afbda7824b6945408c17197396b0621a7e5418ac204f8c5abe64458282600160405161056d93929190612974565b600160208181525f9283526040928390208054845160e081018652938201805463ffffffff8082168752640100000000820416868601526001600160401b03600160401b8204811687890152600160801b90910416606086015260028301546080860152600383015460a08601526004830180548751818702810187019098528088526001600160a01b0390931696939594919360c08601939092830182828015610b1c57602002820191905f5260205f20905b815481526020019060010190808311610b08575b505050505081525050905082565b5f610b336106eb565b341015610b535760405163e6b6589360e01b815260040160405180910390fd5b828261044d4614158015610b6d5750610b6a611132565b81115b15610b8b57604051636d53123b60e01b815260040160405180910390fd5b80821115610bac57604051635d6fbc4960e11b815260040160405180910390fd5b61c350610bb98383612ad0565b610bc4906001612ae3565b1115610be3576040516383d304cf60e01b815260040160405180910390fd5b5f8054600101815580610bf4611075565b610c0d57610c00611132565b9150610c0a6111d3565b90505b6040518060400160405280336001600160a01b031681526020016040518060e001604052805f63ffffffff1681526020015f63ffffffff1681526020018a6001600160401b03168152602001896001600160401b031681526020018481526020018d81526020018c8c808060200260200160405190810160405280939291908181526020018383602002808284375f920182905250939094525050919092528054815260016020818152604092839020855181546001600160a01b0319166001600160a01b0390911617815585820151805193820180548285015196830151606084015163ffffffff97881667ffffffffffffffff199093169290921764010000000097909816969096029690961777ffffffffffffffffffffffffffffffff00000000000000001916600160401b6001600160401b039687160267ffffffffffffffff60801b191617600160801b95909616949094029490941783556080840151600282015560a0840151600382015560c08401518051919550610d9992600487019291019061254b565b505050905050336001600160a01b03168a5f547f5f80fe6d2eee22c9cc67535c0777535ddfbc865871b6f0369a4644936102e0a38c8c8c8c348a604051610de596959493929190612b26565b60405180910390a450505f5498975050505050505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b03165f81158015610e415750825b90505f826001600160401b03166001148015610e5c5750303b155b905081158015610e6a575080155b15610e885760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610eb257845460ff60401b1916600160401b1785555b610ebb86611262565b8315610f0157845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b610f11610f6c565b63389a75e1600c52805f526020600c208054421115610f3757636f5e88185f526004601cfd5b5f9055610f43816110ab565b50565b610f4e610f6c565b8060601b610f6357637448fbae5f526004601cfd5b610f43816110ab565b638b78c6d8195433146107a8576382b429005f526004601cfd5b5f8881526032602052604090205460ff1615610fb55760405163e5b70def60e01b815260040160405180910390fd5b5f8881526032602052604090819020805460ff19166001179055516001600160a01b0388169089907f77a60dab33c0274a972cadc956c819927458e5ed5b76a69c45c37ba6ed39f72690611014908a908a908a908a908a908a90612b5e565b60405180910390a35050505050505050565b6040515f908190339047908381818185875af1925050503d805f8114611067576040519150601f19603f3d011682016040523d82523d5f602084013e61106c565b606091505b50909392505050565b5f6001461480611087575062aa36a746145b8061058a575050466142681490565b5f61138846148061058a575050466113881490565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355565b604080518082019091525f8152606060208201525f611107858561126b565b90506111148585836113e7565b61111f8585856114ea565b6111298585611a5a565b95945050505050565b5f61113b611075565b1561114557504390565b6015602160991b013b63ffffffff16156111ce576015602160991b016001600160a01b0316638381f58a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561119c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111c09190612bab565b6001600160401b0316905090565b505f90565b5f6111dc611075565b156111e75750434090565b6015602160991b013b63ffffffff16156111ce576015602160991b016001600160a01b03166309bd5a606040518163ffffffff1660e01b8152600401602060405180830381865afa15801561123e573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061058a9190612bd1565b610f4381611cad565b611273612594565b61127b6125b2565b611283612594565b5f5b60088163ffffffff1610156112da5785858263ffffffff168181106112ac576112ac612960565b905060200201355f1c838263ffffffff16600881106112cd576112cd612960565b6020020152600101611285565b505f5b60038163ffffffff16101561133c5785856112f9836008612be8565b63ffffffff1681811061130e5761130e612960565b905060200201355f1c828263ffffffff166003811061132f5761132f612960565b60200201526001016112dd565b5080517f1ef3e0e4525d9634361ccfbbaab5825505dadaae75dfc5278ba0ab9824dabfc0146113d35760405162461bcd60e51b815260206004820152603b60248201527f5468652066697273742047726f7468313620696e707574206d7573742062652060448201527f657175616c20746f207468652063697263756974206469676573740000000000606482015260840161078e565b6113dd8282611ce8565b9150505b92915050565b5f6113f28484611fa5565b90505f6002826040516114059190612c0c565b602060405180830381855afa158015611420573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906114439190612bd1565b6001600160fd1b03169050826002602002015181146114e35760405162461bcd60e51b815260206004820152605060248201527f546865207368613235362068617368206f66207075626c696320696e7075747360448201527f206d75737420626520657175616c20746f20746865206c617374206f6620746860648201526f652047726f7468313620696e7075747360801b608482015260a40161078e565b5050505050565b5f83836114f960056003612c22565b600e6115065f6001612be8565b611511906001612be8565b61151b9190612be8565b61152690600b612be8565b6115309190612be8565b63ffffffff1681811061154557611545612960565b9050602002013590505f84845f600b61155e9190612be8565b63ffffffff1681811061157357611573612960565b9050602002013590506115874661044d1490565b806115955750826080015181145b6115ec5760405162461bcd60e51b815260206004820152602260248201527f426c6f636b2068617368206d75737420657175616c2061732065787065637465604482015261321760f11b606482015260840161078e565b5f85856115fa836001612be8565b61160590600b612be8565b63ffffffff1681811061161a5761161a612960565b9050602002013590508360a0015181146116895760405162461bcd60e51b815260206004820152602a60248201527f436f6d7075746174696f6e616c2068617368206d75737420657175616c2061736044820152691032bc3832b1ba32b21760b11b606482015260840161078e565b5f611695816020612c22565b63ffffffff1684901b60e01c9050600e8111156117005760405162461bcd60e51b815260206004820152602360248201527f506c616365686f6c646572206e756d6265722063616e6e6f74206f766572666c60448201526237bb9760e91b606482015260840161078e565b60c085015151611711906002612ae3565b8163ffffffff161461178b5760405162461bcd60e51b815260206004820152603e60248201527f506c616365686f6c646572206e756d6265722063616e6e6f74206f766572666c60448201527f6f7720616e64206d75737420657175616c2061732065787065637465642e0000606482015260840161078e565b60408501516001600160401b031687876117a65f6001612be8565b6117b1906001612be8565b6117bc90600b612be8565b63ffffffff168181106117d1576117d1612960565b905060200201355f1c1461184f576040805162461bcd60e51b81526020600482015260248101919091527f54686520666972737420706c616365686f6c646572206d75737420626520746860448201527f65206578706563746564206d696e696d756d20626c6f636b206e756d6265722e606482015260840161078e565b60608501516001600160401b0316878761186a5f6001612be8565b611875906001612be8565b61188090600b612be8565b61188b906001612be8565b63ffffffff168181106118a0576118a0612960565b905060200201355f1c146119265760405162461bcd60e51b815260206004820152604160248201527f546865207365636f6e6420706c616365686f6c646572206d757374206265207460448201527f6865206578706563746564206d6178696d756d20626c6f636b206e756d6265726064820152601760f91b608482015260a40161078e565b5f5b611933600283612c4a565b63ffffffff16811015611a1f578560c00151818151811061195657611956612960565b60200260200101518888835f600161196e9190612be8565b611979906001612be8565b61198490600b612be8565b61198f906002612be8565b63ffffffff1661199f9190612ae3565b8181106119ae576119ae612960565b9050602002013514611a175760405162461bcd60e51b815260206004820152602c60248201527f546865207573657220706c616365686f6c646572206d75737420657175616c2060448201526b30b99032bc3832b1ba32b21760a11b606482015260840161078e565b600101611928565b505f611a2d60036020612c22565b63ffffffff1685901b60e01c905080156104b25760405163a729eb9d60e01b815260040160405180910390fd5b604080518082019091525f8152606060208201525f8383611a7d60056003612c22565b600e611a8a5f6001612be8565b611a95906001612be8565b611a9f9190612be8565b611aaa90600b612be8565b611ab49190612be8565b63ffffffff16818110611ac957611ac9612960565b9050602002013590505f60026020611ae19190612c22565b63ffffffff1682901b60e01c90505f611afc60016020612c22565b63ffffffff1683901b60e01c90506003811115611b5b5760405162461bcd60e51b815260206004820152601e60248201527f526573756c74206e756d6265722063616e6e6f74206f766572666c6f772e0000604482015260640161078e565b5f600e611b69826001612be8565b611b74906001612be8565b611b7e9190612be8565b611b8990600b612be8565b90505f8263ffffffff166001600160401b03811115611baa57611baa612c67565b604051908082528060200260200182016040528015611bdd57816020015b6060815260200190600190039081611bc85790505b5090505f5b8363ffffffff16811015611c87578888611bfd600584612c7b565b611c0d9063ffffffff8716612ae3565b906005611c1b856001612ae3565b611c259190612c7b565b611c359063ffffffff8816612ae3565b92611c4293929190612c92565b604051602001611c53929190612cbd565b604051602081830303815290604052828281518110611c7457611c74612960565b6020908102919091010152600101611be2565b506040805180820190915263ffffffff9094168452602084015250909250505092915050565b6001600160a01b0316638b78c6d819819055805f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b5f80611cf3836122e4565b915091505f6040515f86015181526020860151602082015260408601516040820152606086015160608201526080860151608082015260a086015160a082015260c086015160c082015260e086015160e08201527f0c2f5ac5d38ac6bc5ffcc6d0443959df057e1b248b2179d185238ae4998ab8ef6101008201527f1c905a62d2a5dfbcf97c7134a26053e0225f7c3dbbeed02cf53050bfa8a0947e6101208201527f1099f5d793846a7f876ab3ada153ce75145db25319db01334448f437228635fc6101408201527f13d5410fcd052f4dbcfeab3213d2abda0036b2adceaf3b2315ebaf189171f8ec6101608201527f279731908d1a2a3cba0f3bdb5f96692b6ea1ac4826ff30a7422b6e38526a21d56101808201527f1ab5cc9fa00adbfdd948d63c641ca9772b0f1b82ed4bed83bebfc500af1842fb6101a08201527f0208e8514cb036a5a0c06c74fe594ebd71d3efd7657b6b1e3a45a0a48f4eed626101c08201527f02ebda29026e498463705b9f25bbefea6278dd729e7976a7a6af4d8a6ac574786101e08201527f0a078d41eb6d0b701853ba078cc0d26c04c95b72f9fb6c3720a1787c4c6ccab56102008201527f0946bc201905fd784086058caf5489559f443bee8b4eb332f23f5a0401f574d661022082015283610240820152826102608201527f1f8e88f27e31f5c6d77f8bbf1727178390b35df1509fd39963804629a8c801bf6102808201527f1bcb5d01090abf1d5f2a0da22e30d77db2259b3699f0840152937b5ad3eef60a6102a08201527f2f6090a0432c2a0e8affb6d97e10aef434ce8c7d19887a528b35008d963ed7bc6102c08201527f188c177e8f44e7b4d3b38029e7162e4b3998e8215c72e3309814b6e9f92c232d6102e08201526020816103008360085afa9051169050806114e357604051631ff3747d60e21b815260040160405180910390fd5b60605f611fb460056001612be8565b611fbf906004612c22565b600b611fcd60056003612c22565b600e611fda5f6001612be8565b611fe5906001612be8565b611fef9190612be8565b611ffa90600b612be8565b6120049190612be8565b61200e9190612c4a565b612019906020612c22565b6120239190612be8565b63ffffffff166001600160401b0381111561204057612040612c67565b6040519080825280601f01601f19166020018201604052801561206a576020820181803683370190505b5090505f602061207c60056001612be8565b612087906004612c22565b600b61209560056003612c22565b600e6120a25f6001612be8565b6120ad906001612be8565b6120b79190612be8565b6120c290600b612be8565b6120cc9190612be8565b6120d69190612c4a565b6120e1906020612c22565b6120eb9190612be8565b6120f59190612ce4565b63ffffffff1690505f5b818110156121af575f868661211584600b612ae3565b81811061212457612124612960565b9050602002013590505f5b60208163ffffffff1610156121a557818163ffffffff166020811061215657612156612960565b1a60f81b8563ffffffff831661216d866020612c7b565b6121779190612ae3565b8151811061218757612187612960565b60200101906001600160f81b03191690815f1a90535060010161212f565b50506001016120ff565b505f85856121be84600b612ae3565b8181106121cd576121cd612960565b9050602002013590505f5b60206121e660056001612be8565b6121f1906004612c22565b600b6121ff60056003612c22565b600e61220c5f6001612be8565b612217906001612be8565b6122219190612be8565b61222c90600b612be8565b6122369190612be8565b6122409190612c4a565b61224b906020612c22565b6122559190612be8565b61225f9190612d06565b63ffffffff168163ffffffff1610156122d957818163ffffffff166020811061228a5761228a612960565b1a60f81b8463ffffffff83166122a1866020612c7b565b6122ab9190612ae3565b815181106122bb576122bb612960565b60200101906001600160f81b03191690815f1a9053506001016121d8565b509195945050505050565b5f805f60019050604051604081015f7f1aa441b8e6cdc56f63ee195b4583f410a0f4ace2aee367532ca44844d465d94583527f13d58df8f66425d86bb391d54bb55fa9c0fe63e9fafafe6ca3601d582303fbd260208401527f221e51d0d785f9584d94c40aec1ad869d729a0980dd83f57d67d62acc8c7957382527f0dc3a30680180e89d0710191d17fca3f2976b4d44d0fb6826744feac537e98b76020830152865190508060408301527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181108416935060408260608460075afa8416935060408360808560065afa841693507f19936c1fb812df1ee42ed160cb8edc80f17e0cf083e7a2115bc904c95d045e0482527f157a503e431747341c40111cd07246ef27d3d3d00c87e26572dd93df03ecafa56020830152602087015190508060408301527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181108416935060408260608460075afa8416935060408360808560065afa7f2e8082bb071c7f8f8b22e411ca17cfd99d1f3699cdf5ef73ad9d35f7ce26bc3f83527f1314e34adb2f6120fef9c5a6a67056a06f52b0609a26316edbb685ce2f6984a760208401526040888101518185018190527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000011191909516169390508160608160075afa831692505060408160808360065afa8151602090920151919450909250168061252a5760405163a54f8e2760e01b815260040160405180910390fd5b50915091565b5080545f8255905f5260205f2090810190610f4391906125d1565b828054828255905f5260205f20908101928215612584579160200282015b82811115612584578251825591602001919060010190612569565b506125909291506125d1565b5090565b60405180606001604052806003906020820280368337509192915050565b6040518061010001604052806008906020820280368337509192915050565b5b80821115612590575f81556001016125d2565b80356001600160a01b03811681146125fb575f80fd5b919050565b5f8083601f840112612610575f80fd5b5081356001600160401b03811115612626575f80fd5b60208301915083602082850101111561263d575f80fd5b9250929050565b5f805f805f805f8060c0898b03121561265b575f80fd5b8835975061266b60208a016125e5565b965060408901356bffffffffffffffffffffffff8116811461268b575f80fd5b95506060890135945060808901356001600160401b03808211156126ad575f80fd5b6126b98c838d01612600565b909650945060a08b01359150808211156126d1575f80fd5b506126de8b828c01612600565b999c989b5096995094979396929594505050565b5f60208284031215612702575f80fd5b5035919050565b5f60208284031215612719575f80fd5b612722826125e5565b9392505050565b5f8083601f840112612739575f80fd5b5081356001600160401b0381111561274f575f80fd5b6020830191508360208260051b850101111561263d575f80fd5b5f806020838503121561277a575f80fd5b82356001600160401b0381111561278f575f80fd5b61279b85828601612729565b90969095509350505050565b5f805f80606085870312156127ba575f80fd5b843593506020850135925060408501356001600160401b038111156127dd575f80fd5b6127e987828801612600565b95989497509550505050565b5f805f8060608587031215612808575f80fd5b8435935060208501356001600160401b03811115612824575f80fd5b61283087828801612729565b9598909750949560400135949350505050565b5f815180845260208085019450602084015f5b8381101561287257815187529582019590820190600101612856565b509495945050505050565b60018060a01b0383168152604060208201525f63ffffffff808451166040840152806020850151166060840152506001600160401b03604084015116608083015260608301516128d860a08401826001600160401b03169052565b50608083015160c083015260a083015160e083015260c083015160e0610100840152611129610120840182612843565b5f805f805f6080868803121561291c575f80fd5b8535945060208601356001600160401b03811115612938575f80fd5b61294488828901612729565b9699909850959660408101359660609091013595509350505050565b634e487b7160e01b5f52603260045260245ffd5b604080825281018390525f8460608301825b868110156129b4576001600160a01b0361299f846125e5565b16825260209283019290910190600101612986565b5080925050508215156020830152949350505050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b602081525f612a056020830184866129ca565b949350505050565b5f604083018251845260208084015160408287015282815180855260608801915060608160051b890101945083830192505f5b81811015612a8557888603605f190183528351805180885280878301888a015e5f888201880152601f01601f1916909601850195509284019291840191600101612a40565b5093979650505050505050565b828152604060208201525f612a056040830184612a0d565b602081525f6127226020830184612a0d565b634e487b7160e01b5f52601160045260245ffd5b818103818111156113e1576113e1612abc565b808201808211156113e1576113e1612abc565b8183525f6001600160fb1b03831115612b0d575f80fd5b8260051b80836020870137939093016020019392505050565b60a081525f612b3960a08301888a612af6565b9050856020830152846040830152836060830152826080830152979650505050505050565b6bffffffffffffffffffffffff87168152856020820152608060408201525f612b8b6080830186886129ca565b8281036060840152612b9e8185876129ca565b9998505050505050505050565b5f60208284031215612bbb575f80fd5b81516001600160401b0381168114612722575f80fd5b5f60208284031215612be1575f80fd5b5051919050565b63ffffffff818116838216019080821115612c0557612c05612abc565b5092915050565b5f82518060208501845e5f920191825250919050565b63ffffffff818116838216028082169190828114612c4257612c42612abc565b505092915050565b63ffffffff828116828216039080821115612c0557612c05612abc565b634e487b7160e01b5f52604160045260245ffd5b80820281158282048414176113e1576113e1612abc565b5f8085851115612ca0575f80fd5b83861115612cac575f80fd5b5050600583901b0193919092039150565b602081525f612a05602083018486612af6565b634e487b7160e01b5f52601260045260245ffd5b5f63ffffffff80841680612cfa57612cfa612cd0565b92169190910492915050565b5f63ffffffff80841680612d1c57612d1c612cd0565b9216919091069291505056fea26469706673582212209c8c3ea02e94c3470a01fa01109bfe82bfc9daf8d8c82550503116f36279e4af64736f6c63430008190033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 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.