Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
20219938 | 185 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
L2OutputOracle
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import { ISemver } from "src/universal/ISemver.sol"; import { Types } from "src/libraries/Types.sol"; import { Constants } from "src/libraries/Constants.sol"; import { Verifier } from "src/L1/Verifier.sol"; /// @custom:proxied /// @title L2OutputOracle /// @notice The L2OutputOracle contains an array of L2 state outputs, where each output is a /// commitment to the state of the L2 chain. Other contracts like the OptimismPortal use /// these outputs to verify information about the state of L2. contract L2OutputOracle is Initializable, ISemver { modifier onlySystemOwner() { require(msg.sender == systemOwner, "L2OutputOracle: Caller is not the system owner"); _; } /// @notice The number of the first L2 block recorded in this contract. uint256 public startingBlockNumber; /// @notice The timestamp of the first L2 block recorded in this contract. uint256 public startingTimestamp; /// @notice Array of L2 output proposals. Types.OutputProposal[] internal l2Outputs; /// @notice The minimum time (in seconds) that must elapse before a withdrawal can be finalized. /// @custom:network-specific uint256 public finalizationPeriodSeconds; /// @notice The interval in L2 blocks at which checkpoints must be submitted. /// @custom:network-specific uint256 public submissionInterval; /// @notice The time between L2 blocks in seconds. Once set, this value MUST NOT be modified. /// @custom:network-specific uint256 public l2BlockTime; /// @notice The address of the challenger. Can be updated via upgrade. /// @custom:network-specific address public challenger; /// @notice The address of the System Owner. Can change the finalization period time address public systemOwner; /// @notice The address of the proposer. Can be updated via upgrade. /// @custom:network-specific address public proposer; /// @notice The address of the verifier Verifier public verifier; /// @notice Emitted when an output is proposed. /// @param outputRoot The output root. /// @param l2OutputIndex The index of the output in the l2Outputs array. /// @param l2BlockNumber The L2 block number of the output root. /// @param l1Timestamp The L1 timestamp when proposed. event OutputProposed( bytes32 indexed outputRoot, uint256 indexed l2OutputIndex, uint256 indexed l2BlockNumber, uint256 l1Timestamp ); /// @notice Emitted when outputs are deleted. /// @param prevNextOutputIndex Next L2 output index before the deletion. /// @param newNextOutputIndex Next L2 output index after the deletion. event OutputsDeleted(uint256 indexed prevNextOutputIndex, uint256 indexed newNextOutputIndex); /// @notice Semantic version. /// @custom:semver 1.4.0 string public constant version = "1.4.0"; /// @notice Constructs the L2OutputOracle contract. Initializes variables to the same values as /// in the getting-started config. constructor() { initialize({ _submissionInterval: 1, _l2BlockTime: 1, _startingBlockNumber: 0, _startingTimestamp: 0, _proposer: address(0), _challenger: address(0), _verifier: address(0), _finalizationPeriodSeconds: 0, _systemOwner: address(0) }); } /// @notice Initializer. /// @param _submissionInterval Interval in blocks at which checkpoints must be submitted. /// @param _l2BlockTime The time per L2 block, in seconds. /// @param _startingBlockNumber The number of the first L2 block. /// @param _startingTimestamp The timestamp of the first L2 block. /// @param _proposer The address of the proposer. /// @param _challenger The address of the challenger. /// @param _finalizationPeriodSeconds The minimum time (in seconds) that must elapse before a withdrawal /// can be finalized. function initialize( uint256 _submissionInterval, uint256 _l2BlockTime, uint256 _startingBlockNumber, uint256 _startingTimestamp, address _proposer, address _challenger, address _verifier, uint256 _finalizationPeriodSeconds, address _systemOwner ) public initializer { require(_submissionInterval > 0, "L2OutputOracle: submission interval must be greater than 0"); require(_l2BlockTime > 0, "L2OutputOracle: L2 block time must be greater than 0"); require( _startingTimestamp <= block.timestamp, "L2OutputOracle: starting L2 timestamp must be less than current time" ); submissionInterval = _submissionInterval; l2BlockTime = _l2BlockTime; startingBlockNumber = _startingBlockNumber; startingTimestamp = _startingTimestamp; proposer = _proposer; challenger = _challenger; verifier = Verifier(_verifier); systemOwner = _systemOwner; finalizationPeriodSeconds = _finalizationPeriodSeconds; } /// @notice Getter for the challenger address. /// Public getter is legacy and will be removed in the future. Use `challenger` instead. /// @return Address of the challenger. /// @custom:legacy function CHALLENGER() external view returns (address) { return challenger; } /// @notice Getter for the proposer address. /// Public getter is legacy and will be removed in the future. Use `proposer` instead. /// @return Address of the proposer. /// @custom:legacy function PROPOSER() external view returns (address) { return proposer; } /// @notice Getter for the submissionInterval. /// Public getter is legacy and will be removed in the future. Use `submissionInterval` instead. /// @return Submission interval. /// @custom:legacy function SUBMISSION_INTERVAL() external view returns (uint256) { return submissionInterval; } /// @notice Getter for the l2BlockTime. /// Public getter is legacy and will be removed in the future. Use `l2BlockTime` instead. /// @return L2 block time. /// @custom:legacy function L2_BLOCK_TIME() external view returns (uint256) { return l2BlockTime; } /// @notice Setter for the finalizationPeriodSeconds. function setFinalizationPeriodSeconds(uint256 newFinalizationPeriodLength) external onlySystemOwner { // We would never want a value that is larger than a week (like for an OR) and want // to avoid anyone being able to DoS the bridge therefore we set an upper bound for the period length require(newFinalizationPeriodLength <= 31536000, "L2OutputOracle: Finalization period too long"); finalizationPeriodSeconds = newFinalizationPeriodLength; } /// @notice Getter for the finalizationPeriodSeconds function FINALIZATION_PERIOD_SECONDS() external view returns (uint256) { return finalizationPeriodSeconds; } /// @notice Getter for the verifier address. function VERIFIER() external view returns (address) { return address(verifier); } /// @notice Deletes all output proposals after and including the proposal that corresponds to /// the given output index. Only the challenger address can delete outputs. /// @param _l2OutputIndex Index of the first L2 output to be deleted. /// All outputs after this output will also be deleted. // solhint-disable-next-line ordering function deleteL2Outputs(uint256 _l2OutputIndex) external { require(msg.sender == challenger, "L2OutputOracle: only the challenger address can delete outputs"); // Make sure we're not *increasing* the length of the array. require( _l2OutputIndex < l2Outputs.length, "L2OutputOracle: cannot delete outputs after the latest output index" ); // Do not allow deleting any outputs that have already been finalized. require( block.timestamp - l2Outputs[_l2OutputIndex].timestamp < finalizationPeriodSeconds, "L2OutputOracle: cannot delete outputs that have already been finalized" ); uint256 prevNextL2OutputIndex = nextOutputIndex(); // Use assembly to delete the array elements because Solidity doesn't allow it. assembly { sstore(l2Outputs.slot, _l2OutputIndex) } emit OutputsDeleted(prevNextL2OutputIndex, _l2OutputIndex); } /// @notice Accepts an outputRoot and the timestamp of the corresponding L2 block. /// The timestamp must be equal to the current value returned by `nextTimestamp()` in /// order to be accepted. This function may only be called by the Proposer. /// @param _outputRoot The L2 output of the checkpoint block. /// @param _l2BlockNumber The L2 block number that resulted in _outputRoot. /// @param _l1BlockHash A block hash which must be included in the current chain. /// @param _l1BlockNumber The block number with the specified block hash. function proposeL2Output( bytes32 _outputRoot, uint256 _l2BlockNumber, bytes32 _l1BlockHash, uint256 _l1BlockNumber, bytes calldata _proof ) external payable { require(msg.sender == proposer, "L2OutputOracle: only the proposer address can propose new outputs"); require( _l2BlockNumber >= nextBlockNumber(), "L2OutputOracle: block number must be at least the next expected block number" ); require( computeL2Timestamp(_l2BlockNumber) < block.timestamp, "L2OutputOracle: cannot propose L2 output in the future" ); require(_outputRoot != bytes32(0), "L2OutputOracle: L2 output proposal cannot be the zero hash"); if (_l1BlockHash != bytes32(0) && (_l1BlockNumber + 255) >= block.number) { // This check allows the proposer to propose an output based on a given L1 block, // without fear that it will be reorged out, provided that the block is in the most // recent 256 blocks. // // It will also revert if the blockheight provided is more than 256 blocks behind the // chain tip (as the hash will return as zero). This does open the door to a griefing // attack in which the proposer's submission is censored until the block is no longer // retrievable, if the proposer is experiencing this attack it can simply leave out the // blockhash value, and delay submission until it is confident that the L1 block is // finalized. require( blockhash(_l1BlockNumber) == _l1BlockHash, "L2OutputOracle: block hash does not match the hash at the expected height" ); } (bool success, ) = address(verifier).staticcall(_proof); require(success, "L2OutputOracle: Verifier rejected proof"); emit OutputProposed(_outputRoot, nextOutputIndex(), _l2BlockNumber, block.timestamp); l2Outputs.push( Types.OutputProposal({ outputRoot: _outputRoot, timestamp: uint128(block.timestamp), l2BlockNumber: uint128(_l2BlockNumber) }) ); } /// @notice Returns an output by index. Needed to return a struct instead of a tuple. /// @param _l2OutputIndex Index of the output to return. /// @return The output at the given index. function getL2Output(uint256 _l2OutputIndex) external view returns (Types.OutputProposal memory) { return l2Outputs[_l2OutputIndex]; } /// @notice Returns the index of the L2 output that checkpoints a given L2 block number. /// Uses a binary search to find the first output greater than or equal to the given /// block. /// @param _l2BlockNumber L2 block number to find a checkpoint for. /// @return Index of the first checkpoint that commits to the given L2 block number. function getL2OutputIndexAfter(uint256 _l2BlockNumber) public view returns (uint256) { // Make sure an output for this block number has actually been proposed. require( _l2BlockNumber <= latestBlockNumber(), "L2OutputOracle: cannot get output for a block that has not been proposed" ); // Make sure there's at least one output proposed. require(l2Outputs.length > 0, "L2OutputOracle: cannot get output as no outputs have been proposed yet"); // Find the output via binary search, guaranteed to exist. uint256 lo = 0; uint256 hi = l2Outputs.length; while (lo < hi) { uint256 mid = (lo + hi) / 2; if (l2Outputs[mid].l2BlockNumber < _l2BlockNumber) { lo = mid + 1; } else { hi = mid; } } return lo; } /// @notice Returns the L2 output proposal that checkpoints a given L2 block number. /// Uses a binary search to find the first output greater than or equal to the given /// block. /// @param _l2BlockNumber L2 block number to find a checkpoint for. /// @return First checkpoint that commits to the given L2 block number. function getL2OutputAfter(uint256 _l2BlockNumber) external view returns (Types.OutputProposal memory) { return l2Outputs[getL2OutputIndexAfter(_l2BlockNumber)]; } /// @notice Returns the number of outputs that have been proposed. /// Will revert if no outputs have been proposed yet. /// @return The number of outputs that have been proposed. function latestOutputIndex() external view returns (uint256) { return l2Outputs.length - 1; } /// @notice Returns the index of the next output to be proposed. /// @return The index of the next output to be proposed. function nextOutputIndex() public view returns (uint256) { return l2Outputs.length; } /// @notice Returns the block number of the latest submitted L2 output proposal. /// If no proposals been submitted yet then this function will return the starting /// block number. /// @return Latest submitted L2 block number. function latestBlockNumber() public view returns (uint256) { return l2Outputs.length == 0 ? startingBlockNumber : l2Outputs[l2Outputs.length - 1].l2BlockNumber; } /// @notice Computes the block number of the next L2 block that needs to be checkpointed. /// @return Next L2 block number. function nextBlockNumber() public view returns (uint256) { return latestBlockNumber() + submissionInterval; } /// @notice Returns the L2 timestamp corresponding to a given L2 block number. /// @param _l2BlockNumber The L2 block number of the target block. /// @return L2 timestamp of the given block. function computeL2Timestamp(uint256 _l2BlockNumber) public view returns (uint256) { return startingTimestamp + ((_l2BlockNumber - startingBlockNumber) * l2BlockTime); } }
// 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.0; /// @title ISemver /// @notice ISemver is a simple contract for ensuring that contracts are /// versioned using semantic versioning. interface ISemver { /// @notice Getter for the semantic version of the contract. This is not /// meant to be used onchain but instead meant to be used by offchain /// tooling. /// @return Semver contract version as a string. function version() external view returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title Types /// @notice Contains various types used throughout the Optimism contract system. library Types { /// @notice OutputProposal represents a commitment to the L2 state. The timestamp is the L1 /// timestamp that the output root is posted. This timestamp is used to verify that the /// finalization period has passed since the output root was submitted. /// @custom:field outputRoot Hash of the L2 output. /// @custom:field timestamp Timestamp of the L1 block that the output root was submitted in. /// @custom:field l2BlockNumber L2 block number that the output corresponds to. struct OutputProposal { bytes32 outputRoot; uint128 timestamp; uint128 l2BlockNumber; } /// @notice Struct representing the elements that are hashed together to generate an output root /// which itself represents a snapshot of the L2 state. /// @custom:field version Version of the output root. /// @custom:field stateRoot Root of the state trie at the block of this output. /// @custom:field messagePasserStorageRoot Root of the message passer storage trie. /// @custom:field latestBlockhash Hash of the block this output was generated from. struct OutputRootProof { bytes32 version; bytes32 stateRoot; bytes32 messagePasserStorageRoot; bytes32 latestBlockhash; } /// @notice Struct representing a deposit transaction (L1 => L2 transaction) created by an end /// user (as opposed to a system deposit transaction generated by the system). /// @custom:field from Address of the sender of the transaction. /// @custom:field to Address of the recipient of the transaction. /// @custom:field isCreation True if the transaction is a contract creation. /// @custom:field value Value to send to the recipient. /// @custom:field mint Amount of ETH to mint. /// @custom:field gasLimit Gas limit of the transaction. /// @custom:field data Data of the transaction. /// @custom:field l1BlockHash Hash of the block the transaction was submitted in. /// @custom:field logIndex Index of the log in the block the transaction was submitted in. struct UserDepositTransaction { address from; address to; bool isCreation; uint256 value; uint256 mint; uint64 gasLimit; bytes data; bytes32 l1BlockHash; uint256 logIndex; } /// @notice Struct representing a withdrawal transaction. /// @custom:field nonce Nonce of the withdrawal transaction /// @custom:field sender Address of the sender of the transaction. /// @custom:field target Address of the recipient of the transaction. /// @custom:field value Value to send to the recipient. /// @custom:field gasLimit Gas limit of the transaction. /// @custom:field data Data of the transaction. struct WithdrawalTransaction { uint256 nonce; address sender; address target; uint256 value; uint256 gasLimit; bytes data; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { ResourceMetering } from "src/L1/ResourceMetering.sol"; /// @title Constants /// @notice Constants is a library for storing constants. Simple! Don't put everything in here, just /// the stuff used in multiple contracts. Constants that only apply to a single contract /// should be defined in that contract instead. library Constants { /// @notice Special address to be used as the tx origin for gas estimation calls in the /// OptimismPortal and CrossDomainMessenger calls. You only need to use this address if /// the minimum gas limit specified by the user is not actually enough to execute the /// given message and you're attempting to estimate the actual necessary gas limit. We /// use address(1) because it's the ecrecover precompile and therefore guaranteed to /// never have any code on any EVM chain. address internal constant ESTIMATION_ADDRESS = address(1); /// @notice Value used for the L2 sender storage slot in both the OptimismPortal and the /// CrossDomainMessenger contracts before an actual sender is set. This value is /// non-zero to reduce the gas cost of message passing transactions. address internal constant DEFAULT_L2_SENDER = 0x000000000000000000000000000000000000dEaD; /// @notice The storage slot that holds the address of a proxy implementation. /// @dev `bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)` bytes32 internal constant PROXY_IMPLEMENTATION_ADDRESS = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /// @notice The storage slot that holds the address of the owner. /// @dev `bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)` bytes32 internal constant PROXY_OWNER_ADDRESS = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /// @notice Returns the default values for the ResourceConfig. These are the recommended values /// for a production network. function DEFAULT_RESOURCE_CONFIG() internal pure returns (ResourceMetering.ResourceConfig memory) { ResourceMetering.ResourceConfig memory config = ResourceMetering.ResourceConfig({ maxResourceLimit: 20_000_000, elasticityMultiplier: 10, baseFeeMaxChangeDenominator: 8, maxTransactionLimit: 8, minimumBaseFee: 1 gwei, systemTxMaxGas: 1_000_000, maximumBaseFee: type(uint128).max }); return config; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; contract Verifier { string public constant version = "aae8835184ea5f139fb319b901c7beb4331b4797"; fallback(bytes calldata _proof) external returns (bytes memory) { // Temporary dummy proof support if (_proof.length == 2 && bytes2(_proof) == 0xDEAD) { return bytes(""); } assembly ("memory-safe") { // Enforce that Solidity memory layout is respected let data := mload(0x40) if iszero(eq(data, 0x80)) { revert(0, 0) } let success := true let f_p := 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 let f_q := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 function validate_ec_point(x, y) -> valid { { let x_lt_p := lt(x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) let y_lt_p := lt(y, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) valid := and(x_lt_p, y_lt_p) } { let y_square := mulmod(y, y, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) let x_square := mulmod(x, x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) let x_cube := mulmod(x_square, x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) let x_cube_plus_3 := addmod(x_cube, 3, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) let is_affine := eq(x_cube_plus_3, y_square) valid := and(valid, is_affine) } } mstore(0x20, mod(calldataload(0x0), f_q)) mstore(0x40, mod(calldataload(0x20), f_q)) mstore(0x60, mod(calldataload(0x40), f_q)) mstore(0x80, mod(calldataload(0x60), f_q)) mstore(0xa0, mod(calldataload(0x80), f_q)) mstore(0xc0, mod(calldataload(0xa0), f_q)) mstore(0xe0, mod(calldataload(0xc0), f_q)) mstore(0x100, mod(calldataload(0xe0), f_q)) mstore(0x120, mod(calldataload(0x100), f_q)) mstore(0x140, mod(calldataload(0x120), f_q)) mstore(0x160, mod(calldataload(0x140), f_q)) mstore(0x180, mod(calldataload(0x160), f_q)) mstore(0x0, 1760506499957465787591370460202862525071930706260757520159104866001531100840) { let x := calldataload(0x180) mstore(0x1a0, x) let y := calldataload(0x1a0) mstore(0x1c0, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x1c0) mstore(0x1e0, x) let y := calldataload(0x1e0) mstore(0x200, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x200) mstore(0x220, x) let y := calldataload(0x220) mstore(0x240, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x240) mstore(0x260, x) let y := calldataload(0x260) mstore(0x280, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x280) mstore(0x2a0, x) let y := calldataload(0x2a0) mstore(0x2c0, y) success := and(validate_ec_point(x, y), success) } mstore(0x2e0, keccak256(0x0, 736)) { let hash := mload(0x2e0) mstore(0x300, mod(hash, f_q)) mstore(0x320, hash) } { let x := calldataload(0x2c0) mstore(0x340, x) let y := calldataload(0x2e0) mstore(0x360, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x300) mstore(0x380, x) let y := calldataload(0x320) mstore(0x3a0, y) success := and(validate_ec_point(x, y), success) } mstore(0x3c0, keccak256(0x320, 160)) { let hash := mload(0x3c0) mstore(0x3e0, mod(hash, f_q)) mstore(0x400, hash) } mstore8(1056, 1) mstore(0x420, keccak256(0x400, 33)) { let hash := mload(0x420) mstore(0x440, mod(hash, f_q)) mstore(0x460, hash) } { let x := calldataload(0x340) mstore(0x480, x) let y := calldataload(0x360) mstore(0x4a0, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x380) mstore(0x4c0, x) let y := calldataload(0x3a0) mstore(0x4e0, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x3c0) mstore(0x500, x) let y := calldataload(0x3e0) mstore(0x520, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x400) mstore(0x540, x) let y := calldataload(0x420) mstore(0x560, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x440) mstore(0x580, x) let y := calldataload(0x460) mstore(0x5a0, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x480) mstore(0x5c0, x) let y := calldataload(0x4a0) mstore(0x5e0, y) success := and(validate_ec_point(x, y), success) } mstore(0x600, keccak256(0x460, 416)) { let hash := mload(0x600) mstore(0x620, mod(hash, f_q)) mstore(0x640, hash) } { let x := calldataload(0x4c0) mstore(0x660, x) let y := calldataload(0x4e0) mstore(0x680, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x500) mstore(0x6a0, x) let y := calldataload(0x520) mstore(0x6c0, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x540) mstore(0x6e0, x) let y := calldataload(0x560) mstore(0x700, y) success := and(validate_ec_point(x, y), success) } mstore(0x720, keccak256(0x640, 224)) { let hash := mload(0x720) mstore(0x740, mod(hash, f_q)) mstore(0x760, hash) } mstore(0x780, mod(calldataload(0x580), f_q)) mstore(0x7a0, mod(calldataload(0x5a0), f_q)) mstore(0x7c0, mod(calldataload(0x5c0), f_q)) mstore(0x7e0, mod(calldataload(0x5e0), f_q)) mstore(0x800, mod(calldataload(0x600), f_q)) mstore(0x820, mod(calldataload(0x620), f_q)) mstore(0x840, mod(calldataload(0x640), f_q)) mstore(0x860, mod(calldataload(0x660), f_q)) mstore(0x880, mod(calldataload(0x680), f_q)) mstore(0x8a0, mod(calldataload(0x6a0), f_q)) mstore(0x8c0, mod(calldataload(0x6c0), f_q)) mstore(0x8e0, mod(calldataload(0x6e0), f_q)) mstore(0x900, mod(calldataload(0x700), f_q)) mstore(0x920, mod(calldataload(0x720), f_q)) mstore(0x940, mod(calldataload(0x740), f_q)) mstore(0x960, mod(calldataload(0x760), f_q)) mstore(0x980, mod(calldataload(0x780), f_q)) mstore(0x9a0, mod(calldataload(0x7a0), f_q)) mstore(0x9c0, mod(calldataload(0x7c0), f_q)) mstore(0x9e0, mod(calldataload(0x7e0), f_q)) mstore(0xa00, mod(calldataload(0x800), f_q)) mstore(0xa20, mod(calldataload(0x820), f_q)) mstore(0xa40, mod(calldataload(0x840), f_q)) mstore(0xa60, mod(calldataload(0x860), f_q)) mstore(0xa80, mod(calldataload(0x880), f_q)) mstore(0xaa0, mod(calldataload(0x8a0), f_q)) mstore(0xac0, mod(calldataload(0x8c0), f_q)) mstore(0xae0, mod(calldataload(0x8e0), f_q)) mstore(0xb00, mod(calldataload(0x900), f_q)) mstore(0xb20, mod(calldataload(0x920), f_q)) mstore(0xb40, mod(calldataload(0x940), f_q)) mstore(0xb60, mod(calldataload(0x960), f_q)) mstore(0xb80, mod(calldataload(0x980), f_q)) mstore(0xba0, mod(calldataload(0x9a0), f_q)) mstore(0xbc0, mod(calldataload(0x9c0), f_q)) mstore(0xbe0, mod(calldataload(0x9e0), f_q)) mstore(0xc00, mod(calldataload(0xa00), f_q)) mstore(0xc20, mod(calldataload(0xa20), f_q)) mstore(0xc40, mod(calldataload(0xa40), f_q)) mstore(0xc60, mod(calldataload(0xa60), f_q)) mstore(0xc80, mod(calldataload(0xa80), f_q)) mstore(0xca0, mod(calldataload(0xaa0), f_q)) mstore(0xcc0, mod(calldataload(0xac0), f_q)) mstore(0xce0, mod(calldataload(0xae0), f_q)) mstore(0xd00, mod(calldataload(0xb00), f_q)) mstore(0xd20, mod(calldataload(0xb20), f_q)) mstore(0xd40, mod(calldataload(0xb40), f_q)) mstore(0xd60, keccak256(0x760, 1536)) { let hash := mload(0xd60) mstore(0xd80, mod(hash, f_q)) mstore(0xda0, hash) } mstore8(3520, 1) mstore(0xdc0, keccak256(0xda0, 33)) { let hash := mload(0xdc0) mstore(0xde0, mod(hash, f_q)) mstore(0xe00, hash) } { let x := calldataload(0xb60) mstore(0xe20, x) let y := calldataload(0xb80) mstore(0xe40, y) success := and(validate_ec_point(x, y), success) } mstore(0xe60, keccak256(0xe00, 96)) { let hash := mload(0xe60) mstore(0xe80, mod(hash, f_q)) mstore(0xea0, hash) } { let x := calldataload(0xba0) mstore(0xec0, x) let y := calldataload(0xbc0) mstore(0xee0, y) success := and(validate_ec_point(x, y), success) } { let x := mload(0x20) x := add(x, shl(88, mload(0x40))) x := add(x, shl(176, mload(0x60))) mstore(3840, x) let y := mload(0x80) y := add(y, shl(88, mload(0xa0))) y := add(y, shl(176, mload(0xc0))) mstore(3872, y) success := and(validate_ec_point(x, y), success) } { let x := mload(0xe0) x := add(x, shl(88, mload(0x100))) x := add(x, shl(176, mload(0x120))) mstore(3904, x) let y := mload(0x140) y := add(y, shl(88, mload(0x160))) y := add(y, shl(176, mload(0x180))) mstore(3936, y) success := and(validate_ec_point(x, y), success) } mstore(0xf80, mulmod(mload(0x740), mload(0x740), f_q)) mstore(0xfa0, mulmod(mload(0xf80), mload(0xf80), f_q)) mstore(0xfc0, mulmod(mload(0xfa0), mload(0xfa0), f_q)) mstore(0xfe0, mulmod(mload(0xfc0), mload(0xfc0), f_q)) mstore(0x1000, mulmod(mload(0xfe0), mload(0xfe0), f_q)) mstore(0x1020, mulmod(mload(0x1000), mload(0x1000), f_q)) mstore(0x1040, mulmod(mload(0x1020), mload(0x1020), f_q)) mstore(0x1060, mulmod(mload(0x1040), mload(0x1040), f_q)) mstore(0x1080, mulmod(mload(0x1060), mload(0x1060), f_q)) mstore(0x10a0, mulmod(mload(0x1080), mload(0x1080), f_q)) mstore(0x10c0, mulmod(mload(0x10a0), mload(0x10a0), f_q)) mstore(0x10e0, mulmod(mload(0x10c0), mload(0x10c0), f_q)) mstore(0x1100, mulmod(mload(0x10e0), mload(0x10e0), f_q)) mstore(0x1120, mulmod(mload(0x1100), mload(0x1100), f_q)) mstore(0x1140, mulmod(mload(0x1120), mload(0x1120), f_q)) mstore(0x1160, mulmod(mload(0x1140), mload(0x1140), f_q)) mstore(0x1180, mulmod(mload(0x1160), mload(0x1160), f_q)) mstore(0x11a0, mulmod(mload(0x1180), mload(0x1180), f_q)) mstore(0x11c0, mulmod(mload(0x11a0), mload(0x11a0), f_q)) mstore(0x11e0, mulmod(mload(0x11c0), mload(0x11c0), f_q)) mstore(0x1200, mulmod(mload(0x11e0), mload(0x11e0), f_q)) mstore(0x1220, mulmod(mload(0x1200), mload(0x1200), f_q)) mstore(0x1240, mulmod(mload(0x1220), mload(0x1220), f_q)) mstore(0x1260, mulmod(mload(0x1240), mload(0x1240), f_q)) mstore(0x1280, addmod(mload(0x1260), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) mstore(0x12a0, mulmod(mload(0x1280), 21888241567198334088790460357988866238279339518792980768180410072331574733841, f_q)) mstore(0x12c0, mulmod(mload(0x12a0), 12929131318670223636853686797196826072950305380535537217467769528748593133487, f_q)) mstore(0x12e0, addmod(mload(0x740), 8959111553169051585392718948060449015598059019880497126230434657827215362130, f_q)) mstore(0x1300, mulmod(mload(0x12a0), 14655294445420895451632927078981340937842238432098198055057679026789553137428, f_q)) mstore(0x1320, addmod(mload(0x740), 7232948426418379770613478666275934150706125968317836288640525159786255358189, f_q)) mstore(0x1340, mulmod(mload(0x12a0), 12220484078924208264862893648548198807365556694478604924193442790112568454894, f_q)) mstore(0x1360, addmod(mload(0x740), 9667758792915066957383512096709076281182807705937429419504761396463240040723, f_q)) mstore(0x1380, mulmod(mload(0x12a0), 8734126352828345679573237859165904705806588461301144420590422589042130041188, f_q)) mstore(0x13a0, addmod(mload(0x740), 13154116519010929542673167886091370382741775939114889923107781597533678454429, f_q)) mstore(0x13c0, mulmod(mload(0x12a0), 7358966525675286471217089135633860168646304224547606326237275077574224349359, f_q)) mstore(0x13e0, addmod(mload(0x740), 14529276346163988751029316609623414919902060175868428017460929109001584146258, f_q)) mstore(0x1400, mulmod(mload(0x12a0), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q)) mstore(0x1420, addmod(mload(0x740), 12146688980418810893951125255607130521645347193942732958664170801695864621270, f_q)) mstore(0x1440, mulmod(mload(0x12a0), 17329448237240114492580865744088056414251735686965494637158808787419781175510, f_q)) mstore(0x1460, addmod(mload(0x740), 4558794634599160729665540001169218674296628713450539706539395399156027320107, f_q)) mstore(0x1480, mulmod(mload(0x12a0), 1, f_q)) mstore(0x14a0, addmod(mload(0x740), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) mstore(0x14c0, mulmod(mload(0x12a0), 11451405578697956743456240853980216273390554734748796433026540431386972584651, f_q)) mstore(0x14e0, addmod(mload(0x740), 10436837293141318478790164891277058815157809665667237910671663755188835910966, f_q)) mstore(0x1500, mulmod(mload(0x12a0), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q)) mstore(0x1520, addmod(mload(0x740), 13513867906530865119835332133273263211836799082674232843258448413103731898270, f_q)) mstore(0x1540, mulmod(mload(0x12a0), 21490807004895109926141140246143262403290679459142140821740925192625185504522, f_q)) mstore(0x1560, addmod(mload(0x740), 397435866944165296105265499114012685257684941273893521957278993950622991095, f_q)) mstore(0x1580, mulmod(mload(0x12a0), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q)) mstore(0x15a0, addmod(mload(0x740), 10676941854703594198666993839846402519342119846958189386823924046696287912227, f_q)) mstore(0x15c0, mulmod(mload(0x12a0), 18846108080730935585192484934247867403156699586319724728525857970312957475341, f_q)) mstore(0x15e0, addmod(mload(0x740), 3042134791108339637053920811009407685391664814096309615172346216262851020276, f_q)) mstore(0x1600, mulmod(mload(0x12a0), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q)) mstore(0x1620, addmod(mload(0x740), 18272764063556419981698118473909131571661591947471949595929891197711371770216, f_q)) mstore(0x1640, mulmod(mload(0x12a0), 21451937155080765789602997556105366785934335730087568134349216848800867145453, f_q)) mstore(0x1660, addmod(mload(0x740), 436305716758509432643408189151908302614028670328466209348987337774941350164, f_q)) mstore(0x1680, mulmod(mload(0x12a0), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) mstore(0x16a0, addmod(mload(0x740), 20461838439117790833741043996939313553025008529160428886800406442142042007110, f_q)) mstore(0x16c0, mulmod(mload(0x12a0), 13982290267294411190096162596630216412723378687553046594730793425118513274800, f_q)) mstore(0x16e0, addmod(mload(0x740), 7905952604544864032150243148627058675824985712862987748967410761457295220817, f_q)) mstore(0x1700, mulmod(mload(0x12a0), 216092043779272773661818549620449970334216366264741118684015851799902419467, f_q)) mstore(0x1720, addmod(mload(0x740), 21672150828060002448584587195636825118214148034151293225014188334775906076150, f_q)) mstore(0x1740, mulmod(mload(0x12a0), 9537783784440837896026284659246718978615447564543116209283382057778110278482, f_q)) mstore(0x1760, addmod(mload(0x740), 12350459087398437326220121086010556109932916835872918134414822128797698217135, f_q)) { let prod := mload(0x12e0) prod := mulmod(mload(0x1320), prod, f_q) mstore(0x1780, prod) prod := mulmod(mload(0x1360), prod, f_q) mstore(0x17a0, prod) prod := mulmod(mload(0x13a0), prod, f_q) mstore(0x17c0, prod) prod := mulmod(mload(0x13e0), prod, f_q) mstore(0x17e0, prod) prod := mulmod(mload(0x1420), prod, f_q) mstore(0x1800, prod) prod := mulmod(mload(0x1460), prod, f_q) mstore(0x1820, prod) prod := mulmod(mload(0x14a0), prod, f_q) mstore(0x1840, prod) prod := mulmod(mload(0x14e0), prod, f_q) mstore(0x1860, prod) prod := mulmod(mload(0x1520), prod, f_q) mstore(0x1880, prod) prod := mulmod(mload(0x1560), prod, f_q) mstore(0x18a0, prod) prod := mulmod(mload(0x15a0), prod, f_q) mstore(0x18c0, prod) prod := mulmod(mload(0x15e0), prod, f_q) mstore(0x18e0, prod) prod := mulmod(mload(0x1620), prod, f_q) mstore(0x1900, prod) prod := mulmod(mload(0x1660), prod, f_q) mstore(0x1920, prod) prod := mulmod(mload(0x16a0), prod, f_q) mstore(0x1940, prod) prod := mulmod(mload(0x16e0), prod, f_q) mstore(0x1960, prod) prod := mulmod(mload(0x1720), prod, f_q) mstore(0x1980, prod) prod := mulmod(mload(0x1760), prod, f_q) mstore(0x19a0, prod) prod := mulmod(mload(0x1280), prod, f_q) mstore(0x19c0, prod) } mstore(0x1a00, 32) mstore(0x1a20, 32) mstore(0x1a40, 32) mstore(0x1a60, mload(0x19c0)) mstore(0x1a80, 21888242871839275222246405745257275088548364400416034343698204186575808495615) mstore(0x1aa0, 21888242871839275222246405745257275088548364400416034343698204186575808495617) success := and(eq(staticcall(gas(), 0x5, 0x1a00, 0xc0, 0x19e0, 0x20), 1), success) { let inv := mload(0x19e0) let v v := mload(0x1280) mstore(4736, mulmod(mload(0x19a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1760) mstore(5984, mulmod(mload(0x1980), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1720) mstore(5920, mulmod(mload(0x1960), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x16e0) mstore(5856, mulmod(mload(0x1940), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x16a0) mstore(5792, mulmod(mload(0x1920), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1660) mstore(5728, mulmod(mload(0x1900), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1620) mstore(5664, mulmod(mload(0x18e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x15e0) mstore(5600, mulmod(mload(0x18c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x15a0) mstore(5536, mulmod(mload(0x18a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1560) mstore(5472, mulmod(mload(0x1880), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1520) mstore(5408, mulmod(mload(0x1860), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x14e0) mstore(5344, mulmod(mload(0x1840), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x14a0) mstore(5280, mulmod(mload(0x1820), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1460) mstore(5216, mulmod(mload(0x1800), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1420) mstore(5152, mulmod(mload(0x17e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x13e0) mstore(5088, mulmod(mload(0x17c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x13a0) mstore(5024, mulmod(mload(0x17a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1360) mstore(4960, mulmod(mload(0x1780), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1320) mstore(4896, mulmod(mload(0x12e0), inv, f_q)) inv := mulmod(v, inv, f_q) mstore(0x12e0, inv) } mstore(0x1ac0, mulmod(mload(0x12c0), mload(0x12e0), f_q)) mstore(0x1ae0, mulmod(mload(0x1300), mload(0x1320), f_q)) mstore(0x1b00, mulmod(mload(0x1340), mload(0x1360), f_q)) mstore(0x1b20, mulmod(mload(0x1380), mload(0x13a0), f_q)) mstore(0x1b40, mulmod(mload(0x13c0), mload(0x13e0), f_q)) mstore(0x1b60, mulmod(mload(0x1400), mload(0x1420), f_q)) mstore(0x1b80, mulmod(mload(0x1440), mload(0x1460), f_q)) mstore(0x1ba0, mulmod(mload(0x1480), mload(0x14a0), f_q)) mstore(0x1bc0, mulmod(mload(0x14c0), mload(0x14e0), f_q)) mstore(0x1be0, mulmod(mload(0x1500), mload(0x1520), f_q)) mstore(0x1c00, mulmod(mload(0x1540), mload(0x1560), f_q)) mstore(0x1c20, mulmod(mload(0x1580), mload(0x15a0), f_q)) mstore(0x1c40, mulmod(mload(0x15c0), mload(0x15e0), f_q)) mstore(0x1c60, mulmod(mload(0x1600), mload(0x1620), f_q)) mstore(0x1c80, mulmod(mload(0x1640), mload(0x1660), f_q)) mstore(0x1ca0, mulmod(mload(0x1680), mload(0x16a0), f_q)) mstore(0x1cc0, mulmod(mload(0x16c0), mload(0x16e0), f_q)) mstore(0x1ce0, mulmod(mload(0x1700), mload(0x1720), f_q)) mstore(0x1d00, mulmod(mload(0x1740), mload(0x1760), f_q)) { let result := mulmod(mload(0x1ba0), mload(0x20), f_q) result := addmod(mulmod(mload(0x1bc0), mload(0x40), f_q), result, f_q) result := addmod(mulmod(mload(0x1be0), mload(0x60), f_q), result, f_q) result := addmod(mulmod(mload(0x1c00), mload(0x80), f_q), result, f_q) result := addmod(mulmod(mload(0x1c20), mload(0xa0), f_q), result, f_q) result := addmod(mulmod(mload(0x1c40), mload(0xc0), f_q), result, f_q) result := addmod(mulmod(mload(0x1c60), mload(0xe0), f_q), result, f_q) result := addmod(mulmod(mload(0x1c80), mload(0x100), f_q), result, f_q) result := addmod(mulmod(mload(0x1ca0), mload(0x120), f_q), result, f_q) result := addmod(mulmod(mload(0x1cc0), mload(0x140), f_q), result, f_q) result := addmod(mulmod(mload(0x1ce0), mload(0x160), f_q), result, f_q) result := addmod(mulmod(mload(0x1d00), mload(0x180), f_q), result, f_q) mstore(7456, result) } mstore(0x1d40, mulmod(mload(0x7c0), mload(0x7a0), f_q)) mstore(0x1d60, addmod(mload(0x780), mload(0x1d40), f_q)) mstore(0x1d80, addmod(mload(0x1d60), sub(f_q, mload(0x7e0)), f_q)) mstore(0x1da0, mulmod(mload(0x1d80), mload(0x9e0), f_q)) mstore(0x1dc0, mulmod(mload(0x620), mload(0x1da0), f_q)) mstore(0x1de0, mulmod(mload(0x840), mload(0x820), f_q)) mstore(0x1e00, addmod(mload(0x800), mload(0x1de0), f_q)) mstore(0x1e20, addmod(mload(0x1e00), sub(f_q, mload(0x860)), f_q)) mstore(0x1e40, mulmod(mload(0x1e20), mload(0xa00), f_q)) mstore(0x1e60, addmod(mload(0x1dc0), mload(0x1e40), f_q)) mstore(0x1e80, mulmod(mload(0x620), mload(0x1e60), f_q)) mstore(0x1ea0, mulmod(mload(0x8c0), mload(0x8a0), f_q)) mstore(0x1ec0, addmod(mload(0x880), mload(0x1ea0), f_q)) mstore(0x1ee0, addmod(mload(0x1ec0), sub(f_q, mload(0x8e0)), f_q)) mstore(0x1f00, mulmod(mload(0x1ee0), mload(0xa20), f_q)) mstore(0x1f20, addmod(mload(0x1e80), mload(0x1f00), f_q)) mstore(0x1f40, mulmod(mload(0x620), mload(0x1f20), f_q)) mstore(0x1f60, mulmod(mload(0x940), mload(0x920), f_q)) mstore(0x1f80, addmod(mload(0x900), mload(0x1f60), f_q)) mstore(0x1fa0, addmod(mload(0x1f80), sub(f_q, mload(0x960)), f_q)) mstore(0x1fc0, mulmod(mload(0x1fa0), mload(0xa40), f_q)) mstore(0x1fe0, addmod(mload(0x1f40), mload(0x1fc0), f_q)) mstore(0x2000, mulmod(mload(0x620), mload(0x1fe0), f_q)) mstore(0x2020, addmod(1, sub(f_q, mload(0xb60)), f_q)) mstore(0x2040, mulmod(mload(0x2020), mload(0x1ba0), f_q)) mstore(0x2060, addmod(mload(0x2000), mload(0x2040), f_q)) mstore(0x2080, mulmod(mload(0x620), mload(0x2060), f_q)) mstore(0x20a0, mulmod(mload(0xc80), mload(0xc80), f_q)) mstore(0x20c0, addmod(mload(0x20a0), sub(f_q, mload(0xc80)), f_q)) mstore(0x20e0, mulmod(mload(0x20c0), mload(0x1ac0), f_q)) mstore(0x2100, addmod(mload(0x2080), mload(0x20e0), f_q)) mstore(0x2120, mulmod(mload(0x620), mload(0x2100), f_q)) mstore(0x2140, addmod(mload(0xbc0), sub(f_q, mload(0xba0)), f_q)) mstore(0x2160, mulmod(mload(0x2140), mload(0x1ba0), f_q)) mstore(0x2180, addmod(mload(0x2120), mload(0x2160), f_q)) mstore(0x21a0, mulmod(mload(0x620), mload(0x2180), f_q)) mstore(0x21c0, addmod(mload(0xc20), sub(f_q, mload(0xc00)), f_q)) mstore(0x21e0, mulmod(mload(0x21c0), mload(0x1ba0), f_q)) mstore(0x2200, addmod(mload(0x21a0), mload(0x21e0), f_q)) mstore(0x2220, mulmod(mload(0x620), mload(0x2200), f_q)) mstore(0x2240, addmod(mload(0xc80), sub(f_q, mload(0xc60)), f_q)) mstore(0x2260, mulmod(mload(0x2240), mload(0x1ba0), f_q)) mstore(0x2280, addmod(mload(0x2220), mload(0x2260), f_q)) mstore(0x22a0, mulmod(mload(0x620), mload(0x2280), f_q)) mstore(0x22c0, addmod(1, sub(f_q, mload(0x1ac0)), f_q)) mstore(0x22e0, addmod(mload(0x1ae0), mload(0x1b00), f_q)) mstore(0x2300, addmod(mload(0x22e0), mload(0x1b20), f_q)) mstore(0x2320, addmod(mload(0x2300), mload(0x1b40), f_q)) mstore(0x2340, addmod(mload(0x2320), mload(0x1b60), f_q)) mstore(0x2360, addmod(mload(0x2340), mload(0x1b80), f_q)) mstore(0x2380, addmod(mload(0x22c0), sub(f_q, mload(0x2360)), f_q)) mstore(0x23a0, mulmod(mload(0xa80), mload(0x3e0), f_q)) mstore(0x23c0, addmod(mload(0x9a0), mload(0x23a0), f_q)) mstore(0x23e0, addmod(mload(0x23c0), mload(0x440), f_q)) mstore(0x2400, mulmod(mload(0xaa0), mload(0x3e0), f_q)) mstore(0x2420, addmod(mload(0x780), mload(0x2400), f_q)) mstore(0x2440, addmod(mload(0x2420), mload(0x440), f_q)) mstore(0x2460, mulmod(mload(0x2440), mload(0x23e0), f_q)) mstore(0x2480, mulmod(mload(0x2460), mload(0xb80), f_q)) mstore(0x24a0, mulmod(1, mload(0x3e0), f_q)) mstore(0x24c0, mulmod(mload(0x740), mload(0x24a0), f_q)) mstore(0x24e0, addmod(mload(0x9a0), mload(0x24c0), f_q)) mstore(0x2500, addmod(mload(0x24e0), mload(0x440), f_q)) mstore(0x2520, mulmod(4131629893567559867359510883348571134090853742863529169391034518566172092834, mload(0x3e0), f_q)) mstore(0x2540, mulmod(mload(0x740), mload(0x2520), f_q)) mstore(0x2560, addmod(mload(0x780), mload(0x2540), f_q)) mstore(0x2580, addmod(mload(0x2560), mload(0x440), f_q)) mstore(0x25a0, mulmod(mload(0x2580), mload(0x2500), f_q)) mstore(0x25c0, mulmod(mload(0x25a0), mload(0xb60), f_q)) mstore(0x25e0, addmod(mload(0x2480), sub(f_q, mload(0x25c0)), f_q)) mstore(0x2600, mulmod(mload(0x25e0), mload(0x2380), f_q)) mstore(0x2620, addmod(mload(0x22a0), mload(0x2600), f_q)) mstore(0x2640, mulmod(mload(0x620), mload(0x2620), f_q)) mstore(0x2660, mulmod(mload(0xac0), mload(0x3e0), f_q)) mstore(0x2680, addmod(mload(0x800), mload(0x2660), f_q)) mstore(0x26a0, addmod(mload(0x2680), mload(0x440), f_q)) mstore(0x26c0, mulmod(mload(0xae0), mload(0x3e0), f_q)) mstore(0x26e0, addmod(mload(0x880), mload(0x26c0), f_q)) mstore(0x2700, addmod(mload(0x26e0), mload(0x440), f_q)) mstore(0x2720, mulmod(mload(0x2700), mload(0x26a0), f_q)) mstore(0x2740, mulmod(mload(0x2720), mload(0xbe0), f_q)) mstore(0x2760, mulmod(8910878055287538404433155982483128285667088683464058436815641868457422632747, mload(0x3e0), f_q)) mstore(0x2780, mulmod(mload(0x740), mload(0x2760), f_q)) mstore(0x27a0, addmod(mload(0x800), mload(0x2780), f_q)) mstore(0x27c0, addmod(mload(0x27a0), mload(0x440), f_q)) mstore(0x27e0, mulmod(11166246659983828508719468090013646171463329086121580628794302409516816350802, mload(0x3e0), f_q)) mstore(0x2800, mulmod(mload(0x740), mload(0x27e0), f_q)) mstore(0x2820, addmod(mload(0x880), mload(0x2800), f_q)) mstore(0x2840, addmod(mload(0x2820), mload(0x440), f_q)) mstore(0x2860, mulmod(mload(0x2840), mload(0x27c0), f_q)) mstore(0x2880, mulmod(mload(0x2860), mload(0xbc0), f_q)) mstore(0x28a0, addmod(mload(0x2740), sub(f_q, mload(0x2880)), f_q)) mstore(0x28c0, mulmod(mload(0x28a0), mload(0x2380), f_q)) mstore(0x28e0, addmod(mload(0x2640), mload(0x28c0), f_q)) mstore(0x2900, mulmod(mload(0x620), mload(0x28e0), f_q)) mstore(0x2920, mulmod(mload(0xb00), mload(0x3e0), f_q)) mstore(0x2940, addmod(mload(0x900), mload(0x2920), f_q)) mstore(0x2960, addmod(mload(0x2940), mload(0x440), f_q)) mstore(0x2980, mulmod(mload(0xb20), mload(0x3e0), f_q)) mstore(0x29a0, addmod(mload(0x980), mload(0x2980), f_q)) mstore(0x29c0, addmod(mload(0x29a0), mload(0x440), f_q)) mstore(0x29e0, mulmod(mload(0x29c0), mload(0x2960), f_q)) mstore(0x2a00, mulmod(mload(0x29e0), mload(0xc40), f_q)) mstore(0x2a20, mulmod(284840088355319032285349970403338060113257071685626700086398481893096618818, mload(0x3e0), f_q)) mstore(0x2a40, mulmod(mload(0x740), mload(0x2a20), f_q)) mstore(0x2a60, addmod(mload(0x900), mload(0x2a40), f_q)) mstore(0x2a80, addmod(mload(0x2a60), mload(0x440), f_q)) mstore(0x2aa0, mulmod(21134065618345176623193549882539580312263652408302468683943992798037078993309, mload(0x3e0), f_q)) mstore(0x2ac0, mulmod(mload(0x740), mload(0x2aa0), f_q)) mstore(0x2ae0, addmod(mload(0x980), mload(0x2ac0), f_q)) mstore(0x2b00, addmod(mload(0x2ae0), mload(0x440), f_q)) mstore(0x2b20, mulmod(mload(0x2b00), mload(0x2a80), f_q)) mstore(0x2b40, mulmod(mload(0x2b20), mload(0xc20), f_q)) mstore(0x2b60, addmod(mload(0x2a00), sub(f_q, mload(0x2b40)), f_q)) mstore(0x2b80, mulmod(mload(0x2b60), mload(0x2380), f_q)) mstore(0x2ba0, addmod(mload(0x2900), mload(0x2b80), f_q)) mstore(0x2bc0, mulmod(mload(0x620), mload(0x2ba0), f_q)) mstore(0x2be0, mulmod(mload(0xb40), mload(0x3e0), f_q)) mstore(0x2c00, addmod(mload(0x1d20), mload(0x2be0), f_q)) mstore(0x2c20, addmod(mload(0x2c00), mload(0x440), f_q)) mstore(0x2c40, mulmod(mload(0x2c20), mload(0xca0), f_q)) mstore(0x2c60, mulmod(5625741653535312224677218588085279924365897425605943700675464992185016992283, mload(0x3e0), f_q)) mstore(0x2c80, mulmod(mload(0x740), mload(0x2c60), f_q)) mstore(0x2ca0, addmod(mload(0x1d20), mload(0x2c80), f_q)) mstore(0x2cc0, addmod(mload(0x2ca0), mload(0x440), f_q)) mstore(0x2ce0, mulmod(mload(0x2cc0), mload(0xc80), f_q)) mstore(0x2d00, addmod(mload(0x2c40), sub(f_q, mload(0x2ce0)), f_q)) mstore(0x2d20, mulmod(mload(0x2d00), mload(0x2380), f_q)) mstore(0x2d40, addmod(mload(0x2bc0), mload(0x2d20), f_q)) mstore(0x2d60, mulmod(mload(0x620), mload(0x2d40), f_q)) mstore(0x2d80, addmod(1, sub(f_q, mload(0xcc0)), f_q)) mstore(0x2da0, mulmod(mload(0x2d80), mload(0x1ba0), f_q)) mstore(0x2dc0, addmod(mload(0x2d60), mload(0x2da0), f_q)) mstore(0x2de0, mulmod(mload(0x620), mload(0x2dc0), f_q)) mstore(0x2e00, mulmod(mload(0xcc0), mload(0xcc0), f_q)) mstore(0x2e20, addmod(mload(0x2e00), sub(f_q, mload(0xcc0)), f_q)) mstore(0x2e40, mulmod(mload(0x2e20), mload(0x1ac0), f_q)) mstore(0x2e60, addmod(mload(0x2de0), mload(0x2e40), f_q)) mstore(0x2e80, mulmod(mload(0x620), mload(0x2e60), f_q)) mstore(0x2ea0, addmod(mload(0xd00), mload(0x3e0), f_q)) mstore(0x2ec0, mulmod(mload(0x2ea0), mload(0xce0), f_q)) mstore(0x2ee0, addmod(mload(0xd40), mload(0x440), f_q)) mstore(0x2f00, mulmod(mload(0x2ee0), mload(0x2ec0), f_q)) mstore(0x2f20, addmod(mload(0x980), mload(0x3e0), f_q)) mstore(0x2f40, mulmod(mload(0x2f20), mload(0xcc0), f_q)) mstore(0x2f60, addmod(mload(0x9c0), mload(0x440), f_q)) mstore(0x2f80, mulmod(mload(0x2f60), mload(0x2f40), f_q)) mstore(0x2fa0, addmod(mload(0x2f00), sub(f_q, mload(0x2f80)), f_q)) mstore(0x2fc0, mulmod(mload(0x2fa0), mload(0x2380), f_q)) mstore(0x2fe0, addmod(mload(0x2e80), mload(0x2fc0), f_q)) mstore(0x3000, mulmod(mload(0x620), mload(0x2fe0), f_q)) mstore(0x3020, addmod(mload(0xd00), sub(f_q, mload(0xd40)), f_q)) mstore(0x3040, mulmod(mload(0x3020), mload(0x1ba0), f_q)) mstore(0x3060, addmod(mload(0x3000), mload(0x3040), f_q)) mstore(0x3080, mulmod(mload(0x620), mload(0x3060), f_q)) mstore(0x30a0, mulmod(mload(0x3020), mload(0x2380), f_q)) mstore(0x30c0, addmod(mload(0xd00), sub(f_q, mload(0xd20)), f_q)) mstore(0x30e0, mulmod(mload(0x30c0), mload(0x30a0), f_q)) mstore(0x3100, addmod(mload(0x3080), mload(0x30e0), f_q)) mstore(0x3120, mulmod(mload(0x1260), mload(0x1260), f_q)) mstore(0x3140, mulmod(mload(0x3120), mload(0x1260), f_q)) mstore(0x3160, mulmod(1, mload(0x1260), f_q)) mstore(0x3180, mulmod(1, mload(0x3120), f_q)) mstore(0x31a0, mulmod(mload(0x3100), mload(0x1280), f_q)) mstore(0x31c0, mulmod(mload(0xf80), mload(0x740), f_q)) mstore(0x31e0, mulmod(mload(0x740), 1, f_q)) mstore(0x3200, addmod(mload(0xe80), sub(f_q, mload(0x31e0)), f_q)) mstore(0x3220, mulmod(mload(0x740), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q)) mstore(0x3240, addmod(mload(0xe80), sub(f_q, mload(0x3220)), f_q)) mstore(0x3260, mulmod(mload(0x740), 11451405578697956743456240853980216273390554734748796433026540431386972584651, f_q)) mstore(0x3280, addmod(mload(0xe80), sub(f_q, mload(0x3260)), f_q)) mstore(0x32a0, mulmod(mload(0x740), 12929131318670223636853686797196826072950305380535537217467769528748593133487, f_q)) mstore(0x32c0, addmod(mload(0xe80), sub(f_q, mload(0x32a0)), f_q)) mstore(0x32e0, mulmod(mload(0x740), 17329448237240114492580865744088056414251735686965494637158808787419781175510, f_q)) mstore(0x3300, addmod(mload(0xe80), sub(f_q, mload(0x32e0)), f_q)) mstore(0x3320, mulmod(mload(0x740), 21490807004895109926141140246143262403290679459142140821740925192625185504522, f_q)) mstore(0x3340, addmod(mload(0xe80), sub(f_q, mload(0x3320)), f_q)) { let result := mulmod(mload(0xe80), 6616149745577394522356295102346368305374051634342887004165528916468992151333, f_q) result := addmod(mulmod(mload(0x740), 15272093126261880699890110642910906783174312766073147339532675270106816344284, f_q), result, f_q) mstore(13152, result) } { let result := mulmod(mload(0xe80), 530501691302793820034524283154921640443166880847115433758691660016816186416, f_q) result := addmod(mulmod(mload(0x740), 6735468303947967792722299167169712601265763928443086612877978228369959138708, f_q), result, f_q) mstore(13184, result) } { let result := mulmod(mload(0xe80), 6735468303947967792722299167169712601265763928443086612877978228369959138708, f_q) result := addmod(mulmod(mload(0x740), 21402573809525492531235934453699988060841876665026314791644170130242704768864, f_q), result, f_q) mstore(13216, result) } { let result := mulmod(mload(0xe80), 21558793644302942916864965630979640748886316167261336210841195936026980690666, f_q) result := addmod(mulmod(mload(0x740), 21647881284526053590463969745634050372655996593461286860577821962674562513632, f_q), result, f_q) mstore(13248, result) } mstore(0x33e0, mulmod(1, mload(0x3200), f_q)) mstore(0x3400, mulmod(mload(0x33e0), mload(0x3280), f_q)) mstore(0x3420, mulmod(mload(0x3400), mload(0x3240), f_q)) mstore(0x3440, mulmod(mload(0x3420), mload(0x3340), f_q)) { let result := mulmod(mload(0xe80), 1, f_q) result := addmod(mulmod(mload(0x740), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q), result, f_q) mstore(13408, result) } { let result := mulmod(mload(0xe80), 12163000419891990293569405173061573680049742717229898748261573253229795914908, f_q) result := addmod(mulmod(mload(0x740), 9725242451947284928677000572195701408498621683186135595436630933346012580709, f_q), result, f_q) mstore(13440, result) } { let result := mulmod(mload(0xe80), 17085049131699056766421998221476555826977441931846378573521510030619952504372, f_q) result := addmod(mulmod(mload(0x740), 6337000465755888211746305680664882431492568521396101891532798530745714905908, f_q), result, f_q) mstore(13472, result) } { let result := mulmod(mload(0xe80), 10262058425268217215884133263876699099081481632544093361167483234163265012860, f_q) result := addmod(mulmod(mload(0x740), 14297308348282218433797077139696728813764374573836158179437870281950912384055, f_q), result, f_q) mstore(13504, result) } mstore(0x34e0, mulmod(mload(0x3400), mload(0x32c0), f_q)) { let result := mulmod(mload(0xe80), 10436837293141318478790164891277058815157809665667237910671663755188835910967, f_q) result := addmod(mulmod(mload(0x740), 11451405578697956743456240853980216273390554734748796433026540431386972584650, f_q), result, f_q) mstore(13568, result) } { let result := mulmod(mload(0xe80), 11451405578697956743456240853980216273390554734748796433026540431386972584650, f_q) result := addmod(mulmod(mload(0x740), 3077030613389546641045167241996204396678989417006994932586784657914895987304, f_q), result, f_q) mstore(13600, result) } { let result := mulmod(mload(0xe80), 4558794634599160729665540001169218674296628713450539706539395399156027320108, f_q) result := addmod(mulmod(mload(0x740), 17329448237240114492580865744088056414251735686965494637158808787419781175509, f_q), result, f_q) mstore(13632, result) } { let result := mulmod(mload(0xe80), 17329448237240114492580865744088056414251735686965494637158808787419781175509, f_q) result := addmod(mulmod(mload(0x740), 7587894345819650164285585254437911847348718480492193252124775402539837301163, f_q), result, f_q) mstore(13664, result) } mstore(0x3580, mulmod(mload(0x33e0), mload(0x3300), f_q)) { let prod := mload(0x3360) prod := mulmod(mload(0x3380), prod, f_q) mstore(0x35a0, prod) prod := mulmod(mload(0x33a0), prod, f_q) mstore(0x35c0, prod) prod := mulmod(mload(0x33c0), prod, f_q) mstore(0x35e0, prod) prod := mulmod(mload(0x3460), prod, f_q) mstore(0x3600, prod) prod := mulmod(mload(0x33e0), prod, f_q) mstore(0x3620, prod) prod := mulmod(mload(0x3480), prod, f_q) mstore(0x3640, prod) prod := mulmod(mload(0x34a0), prod, f_q) mstore(0x3660, prod) prod := mulmod(mload(0x34c0), prod, f_q) mstore(0x3680, prod) prod := mulmod(mload(0x34e0), prod, f_q) mstore(0x36a0, prod) prod := mulmod(mload(0x3500), prod, f_q) mstore(0x36c0, prod) prod := mulmod(mload(0x3520), prod, f_q) mstore(0x36e0, prod) prod := mulmod(mload(0x3400), prod, f_q) mstore(0x3700, prod) prod := mulmod(mload(0x3540), prod, f_q) mstore(0x3720, prod) prod := mulmod(mload(0x3560), prod, f_q) mstore(0x3740, prod) prod := mulmod(mload(0x3580), prod, f_q) mstore(0x3760, prod) } mstore(0x37a0, 32) mstore(0x37c0, 32) mstore(0x37e0, 32) mstore(0x3800, mload(0x3760)) mstore(0x3820, 21888242871839275222246405745257275088548364400416034343698204186575808495615) mstore(0x3840, 21888242871839275222246405745257275088548364400416034343698204186575808495617) success := and(eq(staticcall(gas(), 0x5, 0x37a0, 0xc0, 0x3780, 0x20), 1), success) { let inv := mload(0x3780) let v v := mload(0x3580) mstore(13696, mulmod(mload(0x3740), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x3560) mstore(13664, mulmod(mload(0x3720), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x3540) mstore(13632, mulmod(mload(0x3700), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x3400) mstore(13312, mulmod(mload(0x36e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x3520) mstore(13600, mulmod(mload(0x36c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x3500) mstore(13568, mulmod(mload(0x36a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x34e0) mstore(13536, mulmod(mload(0x3680), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x34c0) mstore(13504, mulmod(mload(0x3660), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x34a0) mstore(13472, mulmod(mload(0x3640), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x3480) mstore(13440, mulmod(mload(0x3620), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x33e0) mstore(13280, mulmod(mload(0x3600), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x3460) mstore(13408, mulmod(mload(0x35e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x33c0) mstore(13248, mulmod(mload(0x35c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x33a0) mstore(13216, mulmod(mload(0x35a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x3380) mstore(13184, mulmod(mload(0x3360), inv, f_q)) inv := mulmod(v, inv, f_q) mstore(0x3360, inv) } { let result := mload(0x3360) result := addmod(mload(0x3380), result, f_q) result := addmod(mload(0x33a0), result, f_q) result := addmod(mload(0x33c0), result, f_q) mstore(14432, result) } mstore(0x3880, mulmod(mload(0x3440), mload(0x33e0), f_q)) { let result := mload(0x3460) mstore(14496, result) } mstore(0x38c0, mulmod(mload(0x3440), mload(0x34e0), f_q)) { let result := mload(0x3480) result := addmod(mload(0x34a0), result, f_q) result := addmod(mload(0x34c0), result, f_q) mstore(14560, result) } mstore(0x3900, mulmod(mload(0x3440), mload(0x3400), f_q)) { let result := mload(0x3500) result := addmod(mload(0x3520), result, f_q) mstore(14624, result) } mstore(0x3940, mulmod(mload(0x3440), mload(0x3580), f_q)) { let result := mload(0x3540) result := addmod(mload(0x3560), result, f_q) mstore(14688, result) } { let prod := mload(0x3860) prod := mulmod(mload(0x38a0), prod, f_q) mstore(0x3980, prod) prod := mulmod(mload(0x38e0), prod, f_q) mstore(0x39a0, prod) prod := mulmod(mload(0x3920), prod, f_q) mstore(0x39c0, prod) prod := mulmod(mload(0x3960), prod, f_q) mstore(0x39e0, prod) } mstore(0x3a20, 32) mstore(0x3a40, 32) mstore(0x3a60, 32) mstore(0x3a80, mload(0x39e0)) mstore(0x3aa0, 21888242871839275222246405745257275088548364400416034343698204186575808495615) mstore(0x3ac0, 21888242871839275222246405745257275088548364400416034343698204186575808495617) success := and(eq(staticcall(gas(), 0x5, 0x3a20, 0xc0, 0x3a00, 0x20), 1), success) { let inv := mload(0x3a00) let v v := mload(0x3960) mstore(14688, mulmod(mload(0x39c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x3920) mstore(14624, mulmod(mload(0x39a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x38e0) mstore(14560, mulmod(mload(0x3980), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x38a0) mstore(14496, mulmod(mload(0x3860), inv, f_q)) inv := mulmod(v, inv, f_q) mstore(0x3860, inv) } mstore(0x3ae0, mulmod(mload(0x3880), mload(0x38a0), f_q)) mstore(0x3b00, mulmod(mload(0x38c0), mload(0x38e0), f_q)) mstore(0x3b20, mulmod(mload(0x3900), mload(0x3920), f_q)) mstore(0x3b40, mulmod(mload(0x3940), mload(0x3960), f_q)) mstore(0x3b60, mulmod(mload(0xd80), mload(0xd80), f_q)) mstore(0x3b80, mulmod(mload(0x3b60), mload(0xd80), f_q)) mstore(0x3ba0, mulmod(mload(0x3b80), mload(0xd80), f_q)) mstore(0x3bc0, mulmod(mload(0x3ba0), mload(0xd80), f_q)) mstore(0x3be0, mulmod(mload(0x3bc0), mload(0xd80), f_q)) mstore(0x3c00, mulmod(mload(0x3be0), mload(0xd80), f_q)) mstore(0x3c20, mulmod(mload(0x3c00), mload(0xd80), f_q)) mstore(0x3c40, mulmod(mload(0x3c20), mload(0xd80), f_q)) mstore(0x3c60, mulmod(mload(0x3c40), mload(0xd80), f_q)) mstore(0x3c80, mulmod(mload(0x3c60), mload(0xd80), f_q)) mstore(0x3ca0, mulmod(mload(0x3c80), mload(0xd80), f_q)) mstore(0x3cc0, mulmod(mload(0x3ca0), mload(0xd80), f_q)) mstore(0x3ce0, mulmod(mload(0x3cc0), mload(0xd80), f_q)) mstore(0x3d00, mulmod(mload(0x3ce0), mload(0xd80), f_q)) mstore(0x3d20, mulmod(mload(0x3d00), mload(0xd80), f_q)) mstore(0x3d40, mulmod(mload(0x3d20), mload(0xd80), f_q)) mstore(0x3d60, mulmod(mload(0xde0), mload(0xde0), f_q)) mstore(0x3d80, mulmod(mload(0x3d60), mload(0xde0), f_q)) mstore(0x3da0, mulmod(mload(0x3d80), mload(0xde0), f_q)) mstore(0x3dc0, mulmod(mload(0x3da0), mload(0xde0), f_q)) { let result := mulmod(mload(0x780), mload(0x3360), f_q) result := addmod(mulmod(mload(0x7a0), mload(0x3380), f_q), result, f_q) result := addmod(mulmod(mload(0x7c0), mload(0x33a0), f_q), result, f_q) result := addmod(mulmod(mload(0x7e0), mload(0x33c0), f_q), result, f_q) mstore(15840, result) } mstore(0x3e00, mulmod(mload(0x3de0), mload(0x3860), f_q)) mstore(0x3e20, mulmod(sub(f_q, mload(0x3e00)), 1, f_q)) { let result := mulmod(mload(0x800), mload(0x3360), f_q) result := addmod(mulmod(mload(0x820), mload(0x3380), f_q), result, f_q) result := addmod(mulmod(mload(0x840), mload(0x33a0), f_q), result, f_q) result := addmod(mulmod(mload(0x860), mload(0x33c0), f_q), result, f_q) mstore(15936, result) } mstore(0x3e60, mulmod(mload(0x3e40), mload(0x3860), f_q)) mstore(0x3e80, mulmod(sub(f_q, mload(0x3e60)), mload(0xd80), f_q)) mstore(0x3ea0, mulmod(1, mload(0xd80), f_q)) mstore(0x3ec0, addmod(mload(0x3e20), mload(0x3e80), f_q)) { let result := mulmod(mload(0x880), mload(0x3360), f_q) result := addmod(mulmod(mload(0x8a0), mload(0x3380), f_q), result, f_q) result := addmod(mulmod(mload(0x8c0), mload(0x33a0), f_q), result, f_q) result := addmod(mulmod(mload(0x8e0), mload(0x33c0), f_q), result, f_q) mstore(16096, result) } mstore(0x3f00, mulmod(mload(0x3ee0), mload(0x3860), f_q)) mstore(0x3f20, mulmod(sub(f_q, mload(0x3f00)), mload(0x3b60), f_q)) mstore(0x3f40, mulmod(1, mload(0x3b60), f_q)) mstore(0x3f60, addmod(mload(0x3ec0), mload(0x3f20), f_q)) { let result := mulmod(mload(0x900), mload(0x3360), f_q) result := addmod(mulmod(mload(0x920), mload(0x3380), f_q), result, f_q) result := addmod(mulmod(mload(0x940), mload(0x33a0), f_q), result, f_q) result := addmod(mulmod(mload(0x960), mload(0x33c0), f_q), result, f_q) mstore(16256, result) } mstore(0x3fa0, mulmod(mload(0x3f80), mload(0x3860), f_q)) mstore(0x3fc0, mulmod(sub(f_q, mload(0x3fa0)), mload(0x3b80), f_q)) mstore(0x3fe0, mulmod(1, mload(0x3b80), f_q)) mstore(0x4000, addmod(mload(0x3f60), mload(0x3fc0), f_q)) mstore(0x4020, mulmod(mload(0x4000), 1, f_q)) mstore(0x4040, mulmod(mload(0x3ea0), 1, f_q)) mstore(0x4060, mulmod(mload(0x3f40), 1, f_q)) mstore(0x4080, mulmod(mload(0x3fe0), 1, f_q)) mstore(0x40a0, mulmod(1, mload(0x3880), f_q)) { let result := mulmod(mload(0x980), mload(0x3460), f_q) mstore(16576, result) } mstore(0x40e0, mulmod(mload(0x40c0), mload(0x3ae0), f_q)) mstore(0x4100, mulmod(sub(f_q, mload(0x40e0)), 1, f_q)) mstore(0x4120, mulmod(mload(0x40a0), 1, f_q)) { let result := mulmod(mload(0xd40), mload(0x3460), f_q) mstore(16704, result) } mstore(0x4160, mulmod(mload(0x4140), mload(0x3ae0), f_q)) mstore(0x4180, mulmod(sub(f_q, mload(0x4160)), mload(0xd80), f_q)) mstore(0x41a0, mulmod(mload(0x40a0), mload(0xd80), f_q)) mstore(0x41c0, addmod(mload(0x4100), mload(0x4180), f_q)) { let result := mulmod(mload(0x9a0), mload(0x3460), f_q) mstore(16864, result) } mstore(0x4200, mulmod(mload(0x41e0), mload(0x3ae0), f_q)) mstore(0x4220, mulmod(sub(f_q, mload(0x4200)), mload(0x3b60), f_q)) mstore(0x4240, mulmod(mload(0x40a0), mload(0x3b60), f_q)) mstore(0x4260, addmod(mload(0x41c0), mload(0x4220), f_q)) { let result := mulmod(mload(0x9c0), mload(0x3460), f_q) mstore(17024, result) } mstore(0x42a0, mulmod(mload(0x4280), mload(0x3ae0), f_q)) mstore(0x42c0, mulmod(sub(f_q, mload(0x42a0)), mload(0x3b80), f_q)) mstore(0x42e0, mulmod(mload(0x40a0), mload(0x3b80), f_q)) mstore(0x4300, addmod(mload(0x4260), mload(0x42c0), f_q)) { let result := mulmod(mload(0x9e0), mload(0x3460), f_q) mstore(17184, result) } mstore(0x4340, mulmod(mload(0x4320), mload(0x3ae0), f_q)) mstore(0x4360, mulmod(sub(f_q, mload(0x4340)), mload(0x3ba0), f_q)) mstore(0x4380, mulmod(mload(0x40a0), mload(0x3ba0), f_q)) mstore(0x43a0, addmod(mload(0x4300), mload(0x4360), f_q)) { let result := mulmod(mload(0xa00), mload(0x3460), f_q) mstore(17344, result) } mstore(0x43e0, mulmod(mload(0x43c0), mload(0x3ae0), f_q)) mstore(0x4400, mulmod(sub(f_q, mload(0x43e0)), mload(0x3bc0), f_q)) mstore(0x4420, mulmod(mload(0x40a0), mload(0x3bc0), f_q)) mstore(0x4440, addmod(mload(0x43a0), mload(0x4400), f_q)) { let result := mulmod(mload(0xa20), mload(0x3460), f_q) mstore(17504, result) } mstore(0x4480, mulmod(mload(0x4460), mload(0x3ae0), f_q)) mstore(0x44a0, mulmod(sub(f_q, mload(0x4480)), mload(0x3be0), f_q)) mstore(0x44c0, mulmod(mload(0x40a0), mload(0x3be0), f_q)) mstore(0x44e0, addmod(mload(0x4440), mload(0x44a0), f_q)) { let result := mulmod(mload(0xa40), mload(0x3460), f_q) mstore(17664, result) } mstore(0x4520, mulmod(mload(0x4500), mload(0x3ae0), f_q)) mstore(0x4540, mulmod(sub(f_q, mload(0x4520)), mload(0x3c00), f_q)) mstore(0x4560, mulmod(mload(0x40a0), mload(0x3c00), f_q)) mstore(0x4580, addmod(mload(0x44e0), mload(0x4540), f_q)) { let result := mulmod(mload(0xa80), mload(0x3460), f_q) mstore(17824, result) } mstore(0x45c0, mulmod(mload(0x45a0), mload(0x3ae0), f_q)) mstore(0x45e0, mulmod(sub(f_q, mload(0x45c0)), mload(0x3c20), f_q)) mstore(0x4600, mulmod(mload(0x40a0), mload(0x3c20), f_q)) mstore(0x4620, addmod(mload(0x4580), mload(0x45e0), f_q)) { let result := mulmod(mload(0xaa0), mload(0x3460), f_q) mstore(17984, result) } mstore(0x4660, mulmod(mload(0x4640), mload(0x3ae0), f_q)) mstore(0x4680, mulmod(sub(f_q, mload(0x4660)), mload(0x3c40), f_q)) mstore(0x46a0, mulmod(mload(0x40a0), mload(0x3c40), f_q)) mstore(0x46c0, addmod(mload(0x4620), mload(0x4680), f_q)) { let result := mulmod(mload(0xac0), mload(0x3460), f_q) mstore(18144, result) } mstore(0x4700, mulmod(mload(0x46e0), mload(0x3ae0), f_q)) mstore(0x4720, mulmod(sub(f_q, mload(0x4700)), mload(0x3c60), f_q)) mstore(0x4740, mulmod(mload(0x40a0), mload(0x3c60), f_q)) mstore(0x4760, addmod(mload(0x46c0), mload(0x4720), f_q)) { let result := mulmod(mload(0xae0), mload(0x3460), f_q) mstore(18304, result) } mstore(0x47a0, mulmod(mload(0x4780), mload(0x3ae0), f_q)) mstore(0x47c0, mulmod(sub(f_q, mload(0x47a0)), mload(0x3c80), f_q)) mstore(0x47e0, mulmod(mload(0x40a0), mload(0x3c80), f_q)) mstore(0x4800, addmod(mload(0x4760), mload(0x47c0), f_q)) { let result := mulmod(mload(0xb00), mload(0x3460), f_q) mstore(18464, result) } mstore(0x4840, mulmod(mload(0x4820), mload(0x3ae0), f_q)) mstore(0x4860, mulmod(sub(f_q, mload(0x4840)), mload(0x3ca0), f_q)) mstore(0x4880, mulmod(mload(0x40a0), mload(0x3ca0), f_q)) mstore(0x48a0, addmod(mload(0x4800), mload(0x4860), f_q)) { let result := mulmod(mload(0xb20), mload(0x3460), f_q) mstore(18624, result) } mstore(0x48e0, mulmod(mload(0x48c0), mload(0x3ae0), f_q)) mstore(0x4900, mulmod(sub(f_q, mload(0x48e0)), mload(0x3cc0), f_q)) mstore(0x4920, mulmod(mload(0x40a0), mload(0x3cc0), f_q)) mstore(0x4940, addmod(mload(0x48a0), mload(0x4900), f_q)) { let result := mulmod(mload(0xb40), mload(0x3460), f_q) mstore(18784, result) } mstore(0x4980, mulmod(mload(0x4960), mload(0x3ae0), f_q)) mstore(0x49a0, mulmod(sub(f_q, mload(0x4980)), mload(0x3ce0), f_q)) mstore(0x49c0, mulmod(mload(0x40a0), mload(0x3ce0), f_q)) mstore(0x49e0, addmod(mload(0x4940), mload(0x49a0), f_q)) mstore(0x4a00, mulmod(mload(0x3160), mload(0x3880), f_q)) mstore(0x4a20, mulmod(mload(0x3180), mload(0x3880), f_q)) { let result := mulmod(mload(0x31a0), mload(0x3460), f_q) mstore(19008, result) } mstore(0x4a60, mulmod(mload(0x4a40), mload(0x3ae0), f_q)) mstore(0x4a80, mulmod(sub(f_q, mload(0x4a60)), mload(0x3d00), f_q)) mstore(0x4aa0, mulmod(mload(0x40a0), mload(0x3d00), f_q)) mstore(0x4ac0, mulmod(mload(0x4a00), mload(0x3d00), f_q)) mstore(0x4ae0, mulmod(mload(0x4a20), mload(0x3d00), f_q)) mstore(0x4b00, addmod(mload(0x49e0), mload(0x4a80), f_q)) { let result := mulmod(mload(0xa60), mload(0x3460), f_q) mstore(19232, result) } mstore(0x4b40, mulmod(mload(0x4b20), mload(0x3ae0), f_q)) mstore(0x4b60, mulmod(sub(f_q, mload(0x4b40)), mload(0x3d20), f_q)) mstore(0x4b80, mulmod(mload(0x40a0), mload(0x3d20), f_q)) mstore(0x4ba0, addmod(mload(0x4b00), mload(0x4b60), f_q)) mstore(0x4bc0, mulmod(mload(0x4ba0), mload(0xde0), f_q)) mstore(0x4be0, mulmod(mload(0x4120), mload(0xde0), f_q)) mstore(0x4c00, mulmod(mload(0x41a0), mload(0xde0), f_q)) mstore(0x4c20, mulmod(mload(0x4240), mload(0xde0), f_q)) mstore(0x4c40, mulmod(mload(0x42e0), mload(0xde0), f_q)) mstore(0x4c60, mulmod(mload(0x4380), mload(0xde0), f_q)) mstore(0x4c80, mulmod(mload(0x4420), mload(0xde0), f_q)) mstore(0x4ca0, mulmod(mload(0x44c0), mload(0xde0), f_q)) mstore(0x4cc0, mulmod(mload(0x4560), mload(0xde0), f_q)) mstore(0x4ce0, mulmod(mload(0x4600), mload(0xde0), f_q)) mstore(0x4d00, mulmod(mload(0x46a0), mload(0xde0), f_q)) mstore(0x4d20, mulmod(mload(0x4740), mload(0xde0), f_q)) mstore(0x4d40, mulmod(mload(0x47e0), mload(0xde0), f_q)) mstore(0x4d60, mulmod(mload(0x4880), mload(0xde0), f_q)) mstore(0x4d80, mulmod(mload(0x4920), mload(0xde0), f_q)) mstore(0x4da0, mulmod(mload(0x49c0), mload(0xde0), f_q)) mstore(0x4dc0, mulmod(mload(0x4aa0), mload(0xde0), f_q)) mstore(0x4de0, mulmod(mload(0x4ac0), mload(0xde0), f_q)) mstore(0x4e00, mulmod(mload(0x4ae0), mload(0xde0), f_q)) mstore(0x4e20, mulmod(mload(0x4b80), mload(0xde0), f_q)) mstore(0x4e40, addmod(mload(0x4020), mload(0x4bc0), f_q)) mstore(0x4e60, mulmod(1, mload(0x38c0), f_q)) { let result := mulmod(mload(0xb60), mload(0x3480), f_q) result := addmod(mulmod(mload(0xb80), mload(0x34a0), f_q), result, f_q) result := addmod(mulmod(mload(0xba0), mload(0x34c0), f_q), result, f_q) mstore(20096, result) } mstore(0x4ea0, mulmod(mload(0x4e80), mload(0x3b00), f_q)) mstore(0x4ec0, mulmod(sub(f_q, mload(0x4ea0)), 1, f_q)) mstore(0x4ee0, mulmod(mload(0x4e60), 1, f_q)) { let result := mulmod(mload(0xbc0), mload(0x3480), f_q) result := addmod(mulmod(mload(0xbe0), mload(0x34a0), f_q), result, f_q) result := addmod(mulmod(mload(0xc00), mload(0x34c0), f_q), result, f_q) mstore(20224, result) } mstore(0x4f20, mulmod(mload(0x4f00), mload(0x3b00), f_q)) mstore(0x4f40, mulmod(sub(f_q, mload(0x4f20)), mload(0xd80), f_q)) mstore(0x4f60, mulmod(mload(0x4e60), mload(0xd80), f_q)) mstore(0x4f80, addmod(mload(0x4ec0), mload(0x4f40), f_q)) { let result := mulmod(mload(0xc20), mload(0x3480), f_q) result := addmod(mulmod(mload(0xc40), mload(0x34a0), f_q), result, f_q) result := addmod(mulmod(mload(0xc60), mload(0x34c0), f_q), result, f_q) mstore(20384, result) } mstore(0x4fc0, mulmod(mload(0x4fa0), mload(0x3b00), f_q)) mstore(0x4fe0, mulmod(sub(f_q, mload(0x4fc0)), mload(0x3b60), f_q)) mstore(0x5000, mulmod(mload(0x4e60), mload(0x3b60), f_q)) mstore(0x5020, addmod(mload(0x4f80), mload(0x4fe0), f_q)) mstore(0x5040, mulmod(mload(0x5020), mload(0x3d60), f_q)) mstore(0x5060, mulmod(mload(0x4ee0), mload(0x3d60), f_q)) mstore(0x5080, mulmod(mload(0x4f60), mload(0x3d60), f_q)) mstore(0x50a0, mulmod(mload(0x5000), mload(0x3d60), f_q)) mstore(0x50c0, addmod(mload(0x4e40), mload(0x5040), f_q)) mstore(0x50e0, mulmod(1, mload(0x3900), f_q)) { let result := mulmod(mload(0xc80), mload(0x3500), f_q) result := addmod(mulmod(mload(0xca0), mload(0x3520), f_q), result, f_q) mstore(20736, result) } mstore(0x5120, mulmod(mload(0x5100), mload(0x3b20), f_q)) mstore(0x5140, mulmod(sub(f_q, mload(0x5120)), 1, f_q)) mstore(0x5160, mulmod(mload(0x50e0), 1, f_q)) { let result := mulmod(mload(0xcc0), mload(0x3500), f_q) result := addmod(mulmod(mload(0xce0), mload(0x3520), f_q), result, f_q) mstore(20864, result) } mstore(0x51a0, mulmod(mload(0x5180), mload(0x3b20), f_q)) mstore(0x51c0, mulmod(sub(f_q, mload(0x51a0)), mload(0xd80), f_q)) mstore(0x51e0, mulmod(mload(0x50e0), mload(0xd80), f_q)) mstore(0x5200, addmod(mload(0x5140), mload(0x51c0), f_q)) mstore(0x5220, mulmod(mload(0x5200), mload(0x3d80), f_q)) mstore(0x5240, mulmod(mload(0x5160), mload(0x3d80), f_q)) mstore(0x5260, mulmod(mload(0x51e0), mload(0x3d80), f_q)) mstore(0x5280, addmod(mload(0x50c0), mload(0x5220), f_q)) mstore(0x52a0, mulmod(1, mload(0x3940), f_q)) { let result := mulmod(mload(0xd00), mload(0x3540), f_q) result := addmod(mulmod(mload(0xd20), mload(0x3560), f_q), result, f_q) mstore(21184, result) } mstore(0x52e0, mulmod(mload(0x52c0), mload(0x3b40), f_q)) mstore(0x5300, mulmod(sub(f_q, mload(0x52e0)), 1, f_q)) mstore(0x5320, mulmod(mload(0x52a0), 1, f_q)) mstore(0x5340, mulmod(mload(0x5300), mload(0x3da0), f_q)) mstore(0x5360, mulmod(mload(0x5320), mload(0x3da0), f_q)) mstore(0x5380, addmod(mload(0x5280), mload(0x5340), f_q)) mstore(0x53a0, mulmod(1, mload(0x3440), f_q)) mstore(0x53c0, mulmod(1, mload(0xe80), f_q)) mstore(0x53e0, 0x0000000000000000000000000000000000000000000000000000000000000001) mstore(0x5400, 0x0000000000000000000000000000000000000000000000000000000000000002) mstore(0x5420, mload(0x5380)) success := and(eq(staticcall(gas(), 0x7, 0x53e0, 0x60, 0x53e0, 0x40), 1), success) mstore(0x5440, mload(0x53e0)) mstore(0x5460, mload(0x5400)) mstore(0x5480, mload(0x1a0)) mstore(0x54a0, mload(0x1c0)) success := and(eq(staticcall(gas(), 0x6, 0x5440, 0x80, 0x5440, 0x40), 1), success) mstore(0x54c0, mload(0x1e0)) mstore(0x54e0, mload(0x200)) mstore(0x5500, mload(0x4040)) success := and(eq(staticcall(gas(), 0x7, 0x54c0, 0x60, 0x54c0, 0x40), 1), success) mstore(0x5520, mload(0x5440)) mstore(0x5540, mload(0x5460)) mstore(0x5560, mload(0x54c0)) mstore(0x5580, mload(0x54e0)) success := and(eq(staticcall(gas(), 0x6, 0x5520, 0x80, 0x5520, 0x40), 1), success) mstore(0x55a0, mload(0x220)) mstore(0x55c0, mload(0x240)) mstore(0x55e0, mload(0x4060)) success := and(eq(staticcall(gas(), 0x7, 0x55a0, 0x60, 0x55a0, 0x40), 1), success) mstore(0x5600, mload(0x5520)) mstore(0x5620, mload(0x5540)) mstore(0x5640, mload(0x55a0)) mstore(0x5660, mload(0x55c0)) success := and(eq(staticcall(gas(), 0x6, 0x5600, 0x80, 0x5600, 0x40), 1), success) mstore(0x5680, mload(0x260)) mstore(0x56a0, mload(0x280)) mstore(0x56c0, mload(0x4080)) success := and(eq(staticcall(gas(), 0x7, 0x5680, 0x60, 0x5680, 0x40), 1), success) mstore(0x56e0, mload(0x5600)) mstore(0x5700, mload(0x5620)) mstore(0x5720, mload(0x5680)) mstore(0x5740, mload(0x56a0)) success := and(eq(staticcall(gas(), 0x6, 0x56e0, 0x80, 0x56e0, 0x40), 1), success) mstore(0x5760, mload(0x2a0)) mstore(0x5780, mload(0x2c0)) mstore(0x57a0, mload(0x4be0)) success := and(eq(staticcall(gas(), 0x7, 0x5760, 0x60, 0x5760, 0x40), 1), success) mstore(0x57c0, mload(0x56e0)) mstore(0x57e0, mload(0x5700)) mstore(0x5800, mload(0x5760)) mstore(0x5820, mload(0x5780)) success := and(eq(staticcall(gas(), 0x6, 0x57c0, 0x80, 0x57c0, 0x40), 1), success) mstore(0x5840, mload(0x380)) mstore(0x5860, mload(0x3a0)) mstore(0x5880, mload(0x4c00)) success := and(eq(staticcall(gas(), 0x7, 0x5840, 0x60, 0x5840, 0x40), 1), success) mstore(0x58a0, mload(0x57c0)) mstore(0x58c0, mload(0x57e0)) mstore(0x58e0, mload(0x5840)) mstore(0x5900, mload(0x5860)) success := and(eq(staticcall(gas(), 0x6, 0x58a0, 0x80, 0x58a0, 0x40), 1), success) mstore(0x5920, 0x01df451a07ce807f7a567ed94106b14924f8f43c0f86427c3e28536219bf296c) mstore(0x5940, 0x1d86969cff248c331aad0ae9fc0799692b3b57749beb0a8e2c36e5549e6fd44c) mstore(0x5960, mload(0x4c20)) success := and(eq(staticcall(gas(), 0x7, 0x5920, 0x60, 0x5920, 0x40), 1), success) mstore(0x5980, mload(0x58a0)) mstore(0x59a0, mload(0x58c0)) mstore(0x59c0, mload(0x5920)) mstore(0x59e0, mload(0x5940)) success := and(eq(staticcall(gas(), 0x6, 0x5980, 0x80, 0x5980, 0x40), 1), success) mstore(0x5a00, 0x0d92789dcc98316be08be7bd04e12029ac4a5b25ffeca1a90a2fbb28ac1d26c6) mstore(0x5a20, 0x00b4ac8bc4b2459d0673d75f3258eff90be3a4608e15614aa0609f79a0e0cec0) mstore(0x5a40, mload(0x4c40)) success := and(eq(staticcall(gas(), 0x7, 0x5a00, 0x60, 0x5a00, 0x40), 1), success) mstore(0x5a60, mload(0x5980)) mstore(0x5a80, mload(0x59a0)) mstore(0x5aa0, mload(0x5a00)) mstore(0x5ac0, mload(0x5a20)) success := and(eq(staticcall(gas(), 0x6, 0x5a60, 0x80, 0x5a60, 0x40), 1), success) mstore(0x5ae0, 0x1c3bdc84f07d8329405d3169afc7aa869f95a0aa776e05360a9463d5337cb87c) mstore(0x5b00, 0x1dfebe35141fc80fee8523aa2894679a7d01494d8a140543eb498b6ad9c2fd76) mstore(0x5b20, mload(0x4c60)) success := and(eq(staticcall(gas(), 0x7, 0x5ae0, 0x60, 0x5ae0, 0x40), 1), success) mstore(0x5b40, mload(0x5a60)) mstore(0x5b60, mload(0x5a80)) mstore(0x5b80, mload(0x5ae0)) mstore(0x5ba0, mload(0x5b00)) success := and(eq(staticcall(gas(), 0x6, 0x5b40, 0x80, 0x5b40, 0x40), 1), success) mstore(0x5bc0, 0x1dce5b9f43f9db493f865a2785dd76beef5c4ce27d7ea0514780b587c3964d45) mstore(0x5be0, 0x0ad48d2ee9250f3e0accae64390dd78d61dfc4941b649184adb7349642d1168f) mstore(0x5c00, mload(0x4c80)) success := and(eq(staticcall(gas(), 0x7, 0x5bc0, 0x60, 0x5bc0, 0x40), 1), success) mstore(0x5c20, mload(0x5b40)) mstore(0x5c40, mload(0x5b60)) mstore(0x5c60, mload(0x5bc0)) mstore(0x5c80, mload(0x5be0)) success := and(eq(staticcall(gas(), 0x6, 0x5c20, 0x80, 0x5c20, 0x40), 1), success) mstore(0x5ca0, 0x2d8efc3bda1056d56c7770a96bb405bdf1ae38a951d45cda5d3914604012c02d) mstore(0x5cc0, 0x1bca96f3ba7b30444c664a8426b78f835398ec3984ea2a2f76034e14f8a00a56) mstore(0x5ce0, mload(0x4ca0)) success := and(eq(staticcall(gas(), 0x7, 0x5ca0, 0x60, 0x5ca0, 0x40), 1), success) mstore(0x5d00, mload(0x5c20)) mstore(0x5d20, mload(0x5c40)) mstore(0x5d40, mload(0x5ca0)) mstore(0x5d60, mload(0x5cc0)) success := and(eq(staticcall(gas(), 0x6, 0x5d00, 0x80, 0x5d00, 0x40), 1), success) mstore(0x5d80, 0x00745b3f0c095a655e86b173ebeb8724bdbf5da427e4ab72db18d91d2beaede5) mstore(0x5da0, 0x0ef7a76767e5a9666ef2cbe1f32c878ba908e52ca9dd1fe0a9aa86c389004f39) mstore(0x5dc0, mload(0x4cc0)) success := and(eq(staticcall(gas(), 0x7, 0x5d80, 0x60, 0x5d80, 0x40), 1), success) mstore(0x5de0, mload(0x5d00)) mstore(0x5e00, mload(0x5d20)) mstore(0x5e20, mload(0x5d80)) mstore(0x5e40, mload(0x5da0)) success := and(eq(staticcall(gas(), 0x6, 0x5de0, 0x80, 0x5de0, 0x40), 1), success) mstore(0x5e60, 0x19e12380adb6345979aa1575cd6770e51e3cb46b7d92e17a412a2b4d28138748) mstore(0x5e80, 0x18e46342b0b384573783b6dd8c1c5ca98b0d83781f31da2f6ea0b557b4f023c8) mstore(0x5ea0, mload(0x4ce0)) success := and(eq(staticcall(gas(), 0x7, 0x5e60, 0x60, 0x5e60, 0x40), 1), success) mstore(0x5ec0, mload(0x5de0)) mstore(0x5ee0, mload(0x5e00)) mstore(0x5f00, mload(0x5e60)) mstore(0x5f20, mload(0x5e80)) success := and(eq(staticcall(gas(), 0x6, 0x5ec0, 0x80, 0x5ec0, 0x40), 1), success) mstore(0x5f40, 0x1887e6a7d003b51a7816bd9461fa73852ebb6e59623b2993800589bce10f6c89) mstore(0x5f60, 0x08e3955f210cdb25ca9e2e0df0ca999f304191298eb5f351153fb4da50afc756) mstore(0x5f80, mload(0x4d00)) success := and(eq(staticcall(gas(), 0x7, 0x5f40, 0x60, 0x5f40, 0x40), 1), success) mstore(0x5fa0, mload(0x5ec0)) mstore(0x5fc0, mload(0x5ee0)) mstore(0x5fe0, mload(0x5f40)) mstore(0x6000, mload(0x5f60)) success := and(eq(staticcall(gas(), 0x6, 0x5fa0, 0x80, 0x5fa0, 0x40), 1), success) mstore(0x6020, 0x1b405475b6c28e3a2d3b8ac2d52e42639db1169d01542afd5ee7158caec43138) mstore(0x6040, 0x14ae2b28a8f2a737d1e0f55086fda2ab394341693dd21b82c24b617ea33f319a) mstore(0x6060, mload(0x4d20)) success := and(eq(staticcall(gas(), 0x7, 0x6020, 0x60, 0x6020, 0x40), 1), success) mstore(0x6080, mload(0x5fa0)) mstore(0x60a0, mload(0x5fc0)) mstore(0x60c0, mload(0x6020)) mstore(0x60e0, mload(0x6040)) success := and(eq(staticcall(gas(), 0x6, 0x6080, 0x80, 0x6080, 0x40), 1), success) mstore(0x6100, 0x139cf36792ab41ef2d77cc422b7960ba18074a558d00d0bb4f2fead1fd9e7911) mstore(0x6120, 0x254c2e57b321a69d42a5ed588477f10c6318d99b54ee58d25a56b1f390070b5b) mstore(0x6140, mload(0x4d40)) success := and(eq(staticcall(gas(), 0x7, 0x6100, 0x60, 0x6100, 0x40), 1), success) mstore(0x6160, mload(0x6080)) mstore(0x6180, mload(0x60a0)) mstore(0x61a0, mload(0x6100)) mstore(0x61c0, mload(0x6120)) success := and(eq(staticcall(gas(), 0x6, 0x6160, 0x80, 0x6160, 0x40), 1), success) mstore(0x61e0, 0x1adfeb5665214b4ae33c6533a871ffbf92cbb77a8858c6de24942fcd47ab686a) mstore(0x6200, 0x18f2e1aa7fce7888f36f0dd5fe547de9c93d0b4d285c39a349376fd754743c7d) mstore(0x6220, mload(0x4d60)) success := and(eq(staticcall(gas(), 0x7, 0x61e0, 0x60, 0x61e0, 0x40), 1), success) mstore(0x6240, mload(0x6160)) mstore(0x6260, mload(0x6180)) mstore(0x6280, mload(0x61e0)) mstore(0x62a0, mload(0x6200)) success := and(eq(staticcall(gas(), 0x6, 0x6240, 0x80, 0x6240, 0x40), 1), success) mstore(0x62c0, 0x1f1cd6a30c7cf28e3209499de1ff98654fd79b760b097f1cbc3c32d62a006aa7) mstore(0x62e0, 0x074c4f2cbe52889d47631af4b833a42d70062c6c8fc98e91f3c948093be1d730) mstore(0x6300, mload(0x4d80)) success := and(eq(staticcall(gas(), 0x7, 0x62c0, 0x60, 0x62c0, 0x40), 1), success) mstore(0x6320, mload(0x6240)) mstore(0x6340, mload(0x6260)) mstore(0x6360, mload(0x62c0)) mstore(0x6380, mload(0x62e0)) success := and(eq(staticcall(gas(), 0x6, 0x6320, 0x80, 0x6320, 0x40), 1), success) mstore(0x63a0, 0x2250197ac7ceeb40955285fb39c2c18390a03dcd0b1edf7751bc43a032419144) mstore(0x63c0, 0x2b8d9959f3f059dc080d5d6c3094ec77062ee4ff2bbe340dc4db5e64d9fc94ca) mstore(0x63e0, mload(0x4da0)) success := and(eq(staticcall(gas(), 0x7, 0x63a0, 0x60, 0x63a0, 0x40), 1), success) mstore(0x6400, mload(0x6320)) mstore(0x6420, mload(0x6340)) mstore(0x6440, mload(0x63a0)) mstore(0x6460, mload(0x63c0)) success := and(eq(staticcall(gas(), 0x6, 0x6400, 0x80, 0x6400, 0x40), 1), success) mstore(0x6480, mload(0x660)) mstore(0x64a0, mload(0x680)) mstore(0x64c0, mload(0x4dc0)) success := and(eq(staticcall(gas(), 0x7, 0x6480, 0x60, 0x6480, 0x40), 1), success) mstore(0x64e0, mload(0x6400)) mstore(0x6500, mload(0x6420)) mstore(0x6520, mload(0x6480)) mstore(0x6540, mload(0x64a0)) success := and(eq(staticcall(gas(), 0x6, 0x64e0, 0x80, 0x64e0, 0x40), 1), success) mstore(0x6560, mload(0x6a0)) mstore(0x6580, mload(0x6c0)) mstore(0x65a0, mload(0x4de0)) success := and(eq(staticcall(gas(), 0x7, 0x6560, 0x60, 0x6560, 0x40), 1), success) mstore(0x65c0, mload(0x64e0)) mstore(0x65e0, mload(0x6500)) mstore(0x6600, mload(0x6560)) mstore(0x6620, mload(0x6580)) success := and(eq(staticcall(gas(), 0x6, 0x65c0, 0x80, 0x65c0, 0x40), 1), success) mstore(0x6640, mload(0x6e0)) mstore(0x6660, mload(0x700)) mstore(0x6680, mload(0x4e00)) success := and(eq(staticcall(gas(), 0x7, 0x6640, 0x60, 0x6640, 0x40), 1), success) mstore(0x66a0, mload(0x65c0)) mstore(0x66c0, mload(0x65e0)) mstore(0x66e0, mload(0x6640)) mstore(0x6700, mload(0x6660)) success := and(eq(staticcall(gas(), 0x6, 0x66a0, 0x80, 0x66a0, 0x40), 1), success) mstore(0x6720, mload(0x5c0)) mstore(0x6740, mload(0x5e0)) mstore(0x6760, mload(0x4e20)) success := and(eq(staticcall(gas(), 0x7, 0x6720, 0x60, 0x6720, 0x40), 1), success) mstore(0x6780, mload(0x66a0)) mstore(0x67a0, mload(0x66c0)) mstore(0x67c0, mload(0x6720)) mstore(0x67e0, mload(0x6740)) success := and(eq(staticcall(gas(), 0x6, 0x6780, 0x80, 0x6780, 0x40), 1), success) mstore(0x6800, mload(0x480)) mstore(0x6820, mload(0x4a0)) mstore(0x6840, mload(0x5060)) success := and(eq(staticcall(gas(), 0x7, 0x6800, 0x60, 0x6800, 0x40), 1), success) mstore(0x6860, mload(0x6780)) mstore(0x6880, mload(0x67a0)) mstore(0x68a0, mload(0x6800)) mstore(0x68c0, mload(0x6820)) success := and(eq(staticcall(gas(), 0x6, 0x6860, 0x80, 0x6860, 0x40), 1), success) mstore(0x68e0, mload(0x4c0)) mstore(0x6900, mload(0x4e0)) mstore(0x6920, mload(0x5080)) success := and(eq(staticcall(gas(), 0x7, 0x68e0, 0x60, 0x68e0, 0x40), 1), success) mstore(0x6940, mload(0x6860)) mstore(0x6960, mload(0x6880)) mstore(0x6980, mload(0x68e0)) mstore(0x69a0, mload(0x6900)) success := and(eq(staticcall(gas(), 0x6, 0x6940, 0x80, 0x6940, 0x40), 1), success) mstore(0x69c0, mload(0x500)) mstore(0x69e0, mload(0x520)) mstore(0x6a00, mload(0x50a0)) success := and(eq(staticcall(gas(), 0x7, 0x69c0, 0x60, 0x69c0, 0x40), 1), success) mstore(0x6a20, mload(0x6940)) mstore(0x6a40, mload(0x6960)) mstore(0x6a60, mload(0x69c0)) mstore(0x6a80, mload(0x69e0)) success := and(eq(staticcall(gas(), 0x6, 0x6a20, 0x80, 0x6a20, 0x40), 1), success) mstore(0x6aa0, mload(0x540)) mstore(0x6ac0, mload(0x560)) mstore(0x6ae0, mload(0x5240)) success := and(eq(staticcall(gas(), 0x7, 0x6aa0, 0x60, 0x6aa0, 0x40), 1), success) mstore(0x6b00, mload(0x6a20)) mstore(0x6b20, mload(0x6a40)) mstore(0x6b40, mload(0x6aa0)) mstore(0x6b60, mload(0x6ac0)) success := and(eq(staticcall(gas(), 0x6, 0x6b00, 0x80, 0x6b00, 0x40), 1), success) mstore(0x6b80, mload(0x580)) mstore(0x6ba0, mload(0x5a0)) mstore(0x6bc0, mload(0x5260)) success := and(eq(staticcall(gas(), 0x7, 0x6b80, 0x60, 0x6b80, 0x40), 1), success) mstore(0x6be0, mload(0x6b00)) mstore(0x6c00, mload(0x6b20)) mstore(0x6c20, mload(0x6b80)) mstore(0x6c40, mload(0x6ba0)) success := and(eq(staticcall(gas(), 0x6, 0x6be0, 0x80, 0x6be0, 0x40), 1), success) mstore(0x6c60, mload(0x340)) mstore(0x6c80, mload(0x360)) mstore(0x6ca0, mload(0x5360)) success := and(eq(staticcall(gas(), 0x7, 0x6c60, 0x60, 0x6c60, 0x40), 1), success) mstore(0x6cc0, mload(0x6be0)) mstore(0x6ce0, mload(0x6c00)) mstore(0x6d00, mload(0x6c60)) mstore(0x6d20, mload(0x6c80)) success := and(eq(staticcall(gas(), 0x6, 0x6cc0, 0x80, 0x6cc0, 0x40), 1), success) mstore(0x6d40, mload(0xe20)) mstore(0x6d60, mload(0xe40)) mstore(0x6d80, sub(f_q, mload(0x53a0))) success := and(eq(staticcall(gas(), 0x7, 0x6d40, 0x60, 0x6d40, 0x40), 1), success) mstore(0x6da0, mload(0x6cc0)) mstore(0x6dc0, mload(0x6ce0)) mstore(0x6de0, mload(0x6d40)) mstore(0x6e00, mload(0x6d60)) success := and(eq(staticcall(gas(), 0x6, 0x6da0, 0x80, 0x6da0, 0x40), 1), success) mstore(0x6e20, mload(0xec0)) mstore(0x6e40, mload(0xee0)) mstore(0x6e60, mload(0x53c0)) success := and(eq(staticcall(gas(), 0x7, 0x6e20, 0x60, 0x6e20, 0x40), 1), success) mstore(0x6e80, mload(0x6da0)) mstore(0x6ea0, mload(0x6dc0)) mstore(0x6ec0, mload(0x6e20)) mstore(0x6ee0, mload(0x6e40)) success := and(eq(staticcall(gas(), 0x6, 0x6e80, 0x80, 0x6e80, 0x40), 1), success) mstore(0x6f00, mload(0x6e80)) mstore(0x6f20, mload(0x6ea0)) mstore(0x6f40, mload(0xec0)) mstore(0x6f60, mload(0xee0)) mstore(0x6f80, mload(0xf00)) mstore(0x6fa0, mload(0xf20)) mstore(0x6fc0, mload(0xf40)) mstore(0x6fe0, mload(0xf60)) mstore(0x7000, keccak256(0x6f00, 256)) mstore(28704, mod(mload(28672), f_q)) mstore(0x7040, mulmod(mload(0x7020), mload(0x7020), f_q)) mstore(0x7060, mulmod(1, mload(0x7020), f_q)) mstore(0x7080, mload(0x6f80)) mstore(0x70a0, mload(0x6fa0)) mstore(0x70c0, mload(0x7060)) success := and(eq(staticcall(gas(), 0x7, 0x7080, 0x60, 0x7080, 0x40), 1), success) mstore(0x70e0, mload(0x6f00)) mstore(0x7100, mload(0x6f20)) mstore(0x7120, mload(0x7080)) mstore(0x7140, mload(0x70a0)) success := and(eq(staticcall(gas(), 0x6, 0x70e0, 0x80, 0x70e0, 0x40), 1), success) mstore(0x7160, mload(0x6fc0)) mstore(0x7180, mload(0x6fe0)) mstore(0x71a0, mload(0x7060)) success := and(eq(staticcall(gas(), 0x7, 0x7160, 0x60, 0x7160, 0x40), 1), success) mstore(0x71c0, mload(0x6f40)) mstore(0x71e0, mload(0x6f60)) mstore(0x7200, mload(0x7160)) mstore(0x7220, mload(0x7180)) success := and(eq(staticcall(gas(), 0x6, 0x71c0, 0x80, 0x71c0, 0x40), 1), success) mstore(0x7240, mload(0x70e0)) mstore(0x7260, mload(0x7100)) mstore(0x7280, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) mstore(0x72a0, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) mstore(0x72c0, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) mstore(0x72e0, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa) mstore(0x7300, mload(0x71c0)) mstore(0x7320, mload(0x71e0)) mstore(0x7340, 0x18ceaa912f51ecae7abc622e73542dee891ef9d224dc542fbd5be49e432c1f8f) mstore(0x7360, 0x1d8e4ae1f1ba06d88197f0db4aa93b64f33b49325f49aa4b902f9a679d78f606) mstore(0x7380, 0x0e446ea664a3ae14af523a228fb59eb63a889b2251f499dc3e051ea1959934ce) mstore(0x73a0, 0x2574894e9882b307d5ca165742fd448889fa235f80644f92573ed6095c79a9bd) success := and(eq(staticcall(gas(), 0x8, 0x7240, 0x180, 0x7240, 0x20), 1), success) success := and(eq(mload(0x7240), 1), success) // Revert if anything fails if iszero(success) { revert(0, 0) } // Return empty bytes on success return(0, 0) } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; import { Burn } from "src/libraries/Burn.sol"; import { Arithmetic } from "src/libraries/Arithmetic.sol"; /// @custom:upgradeable /// @title ResourceMetering /// @notice ResourceMetering implements an EIP-1559 style resource metering system where pricing /// updates automatically based on current demand. abstract contract ResourceMetering is Initializable { /// @notice Error returned when too much gas resource is consumed. error OutOfGas(); /// @notice Represents the various parameters that control the way in which resources are /// metered. Corresponds to the EIP-1559 resource metering system. /// @custom:field prevBaseFee Base fee from the previous block(s). /// @custom:field prevBoughtGas Amount of gas bought so far in the current block. /// @custom:field prevBlockNum Last block number that the base fee was updated. /// @custom:field prevTxCount Number of transactions in the current block. struct ResourceParams { uint128 prevBaseFee; uint64 prevBoughtGas; uint64 prevBlockNum; uint16 prevTxCount; } /// @notice Represents the configuration for the EIP-1559 based curve for the deposit gas /// market. These values should be set with care as it is possible to set them in /// a way that breaks the deposit gas market. The target resource limit is defined as /// maxResourceLimit / elasticityMultiplier. This struct was designed to fit within a /// single word. There is additional space for additions in the future. /// @custom:field maxResourceLimit Represents the maximum amount of deposit gas that /// can be purchased per block. /// @custom:field elasticityMultiplier Determines the target resource limit along with /// the resource limit. /// @custom:field baseFeeMaxChangeDenominator Determines max change on fee per block. /// @custom:field maxTransactionLimit Determines max deposit transaction count per block. /// @custom:field minimumBaseFee The min deposit base fee, it is clamped to this /// value. /// @custom:field systemTxMaxGas The amount of gas supplied to the system /// transaction. This should be set to the same /// number that the op-node sets as the gas limit /// for the system transaction. /// @custom:field maximumBaseFee The max deposit base fee, it is clamped to this /// value. struct ResourceConfig { uint32 maxResourceLimit; uint8 elasticityMultiplier; uint8 baseFeeMaxChangeDenominator; uint16 maxTransactionLimit; uint32 minimumBaseFee; uint32 systemTxMaxGas; uint128 maximumBaseFee; } /// @notice EIP-1559 style gas parameters. ResourceParams public params; /// @notice Reserve extra slots (to a total of 50) in the storage layout for future upgrades. uint256[48] private __gap; event GasBurned(uint256 gasAmount, address indexed sender); /// @notice Meters access to a function based an amount of a requested resource. /// @param _amount Amount of the resource requested. modifier metered(uint64 _amount) { // Record initial gas amount so we can refund for it later. uint256 initialGas = gasleft(); // Run the underlying function. _; // Run the metering function. _metered(_amount, initialGas); } /// @notice An internal function that holds all of the logic for metering a resource. /// @param _amount Amount of the resource requested. /// @param _initialGas The amount of gas before any modifier execution. function _metered(uint64 _amount, uint256 _initialGas) internal { // Update block number and base fee if necessary. uint256 blockDiff = block.number - params.prevBlockNum; ResourceConfig memory config = _resourceConfig(); int256 targetResourceLimit = int256(uint256(config.maxResourceLimit)) / int256(uint256(config.elasticityMultiplier)); if (blockDiff > 0) { // Handle updating EIP-1559 style gas parameters. We use EIP-1559 to restrict the rate // at which deposits can be created and therefore limit the potential for deposits to // spam the L2 system. Fee scheme is very similar to EIP-1559 with minor changes. // If limit deposit limit is hit, increase the gas fee by max amount uint256 boughtGas = params.prevBoughtGas; if (params.prevTxCount == config.maxTransactionLimit) { boughtGas = Math.max(uint256(targetResourceLimit * 2), boughtGas); } int256 gasUsedDelta = int256(boughtGas) - targetResourceLimit; int256 baseFeeDelta = (int256(uint256(params.prevBaseFee)) * gasUsedDelta) / (targetResourceLimit * int256(uint256(config.baseFeeMaxChangeDenominator))); // Update base fee by adding the base fee delta and clamp the resulting value between // min and max. int256 newBaseFee = Arithmetic.clamp({ _value: int256(uint256(params.prevBaseFee)) + baseFeeDelta, _min: int256(uint256(config.minimumBaseFee)), _max: int256(uint256(config.maximumBaseFee)) }); // If we skipped more than one block, we also need to account for every empty block. // Empty block means there was no demand for deposits in that block, so we should // reflect this lack of demand in the fee. if (blockDiff > 1) { // Update the base fee by repeatedly applying the exponent 1-(1/change_denominator) // blockDiff - 1 times. Simulates multiple empty blocks. Clamp the resulting value // between min and max. newBaseFee = Arithmetic.clamp({ _value: Arithmetic.cdexp({ _coefficient: newBaseFee, _denominator: int256(uint256(config.baseFeeMaxChangeDenominator)), _exponent: int256(blockDiff - 1) }), _min: int256(uint256(config.minimumBaseFee)), _max: int256(uint256(config.maximumBaseFee)) }); } // Update new base fee, reset bought gas, and update block number. params.prevBaseFee = uint128(uint256(newBaseFee)); params.prevBoughtGas = 0; params.prevTxCount = 0; params.prevBlockNum = uint64(block.number); } params.prevTxCount += 1; // If limit is surpassed, require(params.prevTxCount <= config.maxTransactionLimit, "ResourceMetering: too many deposits in this block"); // Make sure we can actually buy the resource amount requested by the user. params.prevBoughtGas += _amount; if (int256(uint256(params.prevBoughtGas)) > int256(uint256(config.maxResourceLimit))) { revert OutOfGas(); } // Determine the amount of ETH to be paid. uint256 resourceCost = uint256(_amount) * uint256(params.prevBaseFee); // We currently charge for this ETH amount as an L1 gas burn, so we convert the ETH amount // into gas by dividing by the L1 base fee. We assume a minimum base fee of 1 gwei to avoid // division by zero for L1s that don't support 1559 or to avoid excessive gas burns during // periods of extremely low L1 demand. One-day average gas fee hasn't dipped below 1 gwei // during any 1 day period in the last 5 years, so should be fine. uint256 gasCost = resourceCost / Math.max(block.basefee, 1 gwei); // Give the user a refund based on the amount of gas they used to do all of the work up to // this point. Since we're at the end of the modifier, this should be pretty accurate. Acts // effectively like a dynamic stipend (with a minimum value). uint256 usedGas = _initialGas - gasleft(); if (gasCost > usedGas) { // We calculate gasToBurn based on the resourceCosts, but reserve some Gas for an event // that keeps track of the GasBurned. There we add the costs for the event because we // would be burning it otherwise uint256 gasToBurn = gasCost - usedGas; // Gas Costs For Event: // 375 Per LOG* operation. // 375 per indexed parameter // 8 Per byte in a LOG* operation's data. // 375 + 375 + 256 + 160 = 1166 (uint256 32 bytes, address 20bytes) uint256 estimatedEventGasCosts = 1200; // Ensure gasToBurn is greater than estimatedEventGasCosts to avoid underflow if (gasToBurn > estimatedEventGasCosts) { emit GasBurned(gasToBurn - estimatedEventGasCosts, tx.origin); // Subtract estimatedEventGasCosts because the event emission accounts for this already Burn.gas(gasToBurn - estimatedEventGasCosts); } else { // Handle case where gasToBurn is not enough to cover estimatedEventGasCosts // Emit event with what we have and burn zero gas emit GasBurned(estimatedEventGasCosts, tx.origin); Burn.gas(0); } } } /// @notice Virtual function that returns the resource config. /// Contracts that inherit this contract must implement this function. /// @return ResourceConfig function _resourceConfig() internal virtual returns (ResourceConfig memory); /// @notice Sets initial resource parameter values. /// This function must either be called by the initializer function of an upgradeable /// child contract. // solhint-disable-next-line func-name-mixedcase function __ResourceMetering_init() internal onlyInitializing { if (params.prevBlockNum == 0) { params = ResourceParams({ prevBaseFee: 1 gwei, prevBoughtGas: 0, prevBlockNum: uint64(block.number), prevTxCount: 0 }); } } }
// 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 // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an overflow flag. */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; /// @title Burn /// @notice Utilities for burning stuff. library Burn { /// @notice Burns a given amount of ETH. /// @param _amount Amount of ETH to burn. function eth(uint256 _amount) internal { new Burner{ value: _amount }(); } /// @notice Burns a given amount of gas. /// @param _amount Amount of gas to burn. function gas(uint256 _amount) internal view { uint256 i = 0; uint256 initialGas = gasleft(); while (initialGas - gasleft() < _amount) { ++i; } } } /// @title Burner /// @notice Burner self-destructs on creation and sends all ETH to itself, removing all ETH given to /// the contract from the circulating supply. Self-destructing is the only way to remove ETH /// from the circulating supply. contract Burner { constructor() payable { selfdestruct(payable(address(this))); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { SignedMath } from "@openzeppelin/contracts/utils/math/SignedMath.sol"; import { FixedPointMathLib } from "@rari-capital/solmate/src/utils/FixedPointMathLib.sol"; /// @title Arithmetic /// @notice Even more math than before. library Arithmetic { /// @notice Clamps a value between a minimum and maximum. /// @param _value The value to clamp. /// @param _min The minimum value. /// @param _max The maximum value. /// @return The clamped value. function clamp(int256 _value, int256 _min, int256 _max) internal pure returns (int256) { return SignedMath.min(SignedMath.max(_value, _min), _max); } /// @notice (c)oefficient (d)enominator (exp)onentiation function. /// Returns the result of: c * (1 - 1/d)^exp. /// @param _coefficient Coefficient of the function. /// @param _denominator Fractional denominator. /// @param _exponent Power function exponent. /// @return Result of c * (1 - 1/d)^exp. function cdexp(int256 _coefficient, int256 _denominator, int256 _exponent) internal pure returns (int256) { return (_coefficient * (FixedPointMathLib.powWad(1e18 - (1e18 / _denominator), _exponent * 1e18))) / 1e18; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.20; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol) library FixedPointMathLib { /*////////////////////////////////////////////////////////////// SIMPLIFIED FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s. function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down. } function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up. } function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down. } function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up. } function powWad(int256 x, int256 y) internal pure returns (int256) { // Equivalent to x to the power of y because x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y) return expWad((lnWad(x) * y) / int256(WAD)); // Using ln(x) means x must be greater than 0. } function expWad(int256 x) internal pure returns (int256 r) { unchecked { // When the result is < 0.5 we return zero. This happens when // x <= floor(log(0.5e18) * 1e18) ~ -42e18 if (x <= -42139678854452767551) return 0; // When the result is > (2**255 - 1) / 1e18 we can not represent it as an // int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135. if (x >= 135305999368893231589) revert("EXP_OVERFLOW"); // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96 // for more intermediate precision and a binary basis. This base conversion // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78. x = (x << 78) / 5**18; // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers // of two such that exp(x) = exp(x') * 2**k, where k is an integer. // Solving this gives k = round(x / log(2)) and x' = x - k * log(2). int256 k = ((x << 96) / 54916777467707473351141471128 + 2**95) >> 96; x = x - k * 54916777467707473351141471128; // k is in the range [-61, 195]. // Evaluate using a (6, 7)-term rational approximation. // p is made monic, we'll multiply by a scale factor later. int256 y = x + 1346386616545796478920950773328; y = ((y * x) >> 96) + 57155421227552351082224309758442; int256 p = y + x - 94201549194550492254356042504812; p = ((p * y) >> 96) + 28719021644029726153956944680412240; p = p * x + (4385272521454847904659076985693276 << 96); // We leave p in 2**192 basis so we don't need to scale it back up for the division. int256 q = x - 2855989394907223263936484059900; q = ((q * x) >> 96) + 50020603652535783019961831881945; q = ((q * x) >> 96) - 533845033583426703283633433725380; q = ((q * x) >> 96) + 3604857256930695427073651918091429; q = ((q * x) >> 96) - 14423608567350463180887372962807573; q = ((q * x) >> 96) + 26449188498355588339934803723976023; assembly { // Div in assembly because solidity adds a zero check despite the unchecked. // The q polynomial won't have zeros in the domain as all its roots are complex. // No scaling is necessary because p is already 2**96 too large. r := sdiv(p, q) } // r should be in the range (0.09, 0.25) * 2**96. // We now need to multiply r by: // * the scale factor s = ~6.031367120. // * the 2**k factor from the range reduction. // * the 1e18 / 2**96 factor for base conversion. // We do this all at once, with an intermediate result in 2**213 // basis, so the final right shift is always by a positive amount. r = int256((uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k)); } } function lnWad(int256 x) internal pure returns (int256 r) { unchecked { require(x > 0, "UNDEFINED"); // We want to convert x from 10**18 fixed point to 2**96 fixed point. // We do this by multiplying by 2**96 / 10**18. But since // ln(x * C) = ln(x) + ln(C), we can simply do nothing here // and add ln(2**96 / 10**18) at the end. // Reduce range of x to (1, 2) * 2**96 // ln(2^k * x) = k * ln(2) + ln(x) int256 k = int256(log2(uint256(x))) - 96; x <<= uint256(159 - k); x = int256(uint256(x) >> 159); // Evaluate using a (8, 8)-term rational approximation. // p is made monic, we will multiply by a scale factor later. int256 p = x + 3273285459638523848632254066296; p = ((p * x) >> 96) + 24828157081833163892658089445524; p = ((p * x) >> 96) + 43456485725739037958740375743393; p = ((p * x) >> 96) - 11111509109440967052023855526967; p = ((p * x) >> 96) - 45023709667254063763336534515857; p = ((p * x) >> 96) - 14706773417378608786704636184526; p = p * x - (795164235651350426258249787498 << 96); // We leave p in 2**192 basis so we don't need to scale it back up for the division. // q is monic by convention. int256 q = x + 5573035233440673466300451813936; q = ((q * x) >> 96) + 71694874799317883764090561454958; q = ((q * x) >> 96) + 283447036172924575727196451306956; q = ((q * x) >> 96) + 401686690394027663651624208769553; q = ((q * x) >> 96) + 204048457590392012362485061816622; q = ((q * x) >> 96) + 31853899698501571402653359427138; q = ((q * x) >> 96) + 909429971244387300277376558375; assembly { // Div in assembly because solidity adds a zero check despite the unchecked. // The q polynomial is known not to have zeros in the domain. // No scaling required because p is already 2**96 too large. r := sdiv(p, q) } // r is in the range (0, 0.125) * 2**96 // Finalization, we need to: // * multiply by the scale factor s = 5.549… // * add ln(2**96 / 10**18) // * add k * ln(2) // * multiply by 10**18 / 2**96 = 5**18 >> 78 // mul s * 5e18 * 2**96, base is now 5**18 * 2**192 r *= 1677202110996718588342820967067443963516166; // add ln(2) * k * 5e18 * 2**192 r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k; // add ln(2**96 / 10**18) * 5e18 * 2**192 r += 600920179829731861736702779321621459595472258049074101567377883020018308; // base conversion: mul 2**18 / 2**192 r >>= 174; } } /*////////////////////////////////////////////////////////////// LOW LEVEL FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ function mulDivDown( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { assembly { // Store x * y in z for now. z := mul(x, y) // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y)) if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) { revert(0, 0) } // Divide z by the denominator. z := div(z, denominator) } } function mulDivUp( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { assembly { // Store x * y in z for now. z := mul(x, y) // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y)) if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) { revert(0, 0) } // First, divide z - 1 by the denominator and add 1. // We allow z - 1 to underflow if z is 0, because we multiply the // end result by 0 if z is zero, ensuring we return 0 if z is zero. z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1)) } } function rpow( uint256 x, uint256 n, uint256 scalar ) internal pure returns (uint256 z) { assembly { switch x case 0 { switch n case 0 { // 0 ** 0 = 1 z := scalar } default { // 0 ** n = 0 z := 0 } } default { switch mod(n, 2) case 0 { // If n is even, store scalar in z for now. z := scalar } default { // If n is odd, store x in z for now. z := x } // Shifting right by 1 is like dividing by 2. let half := shr(1, scalar) for { // Shift n right by 1 before looping to halve it. n := shr(1, n) } n { // Shift n right by 1 each iteration to halve it. n := shr(1, n) } { // Revert immediately if x ** 2 would overflow. // Equivalent to iszero(eq(div(xx, x), x)) here. if shr(128, x) { revert(0, 0) } // Store x squared. let xx := mul(x, x) // Round to the nearest number. let xxRound := add(xx, half) // Revert if xx + half overflowed. if lt(xxRound, xx) { revert(0, 0) } // Set x to scaled xxRound. x := div(xxRound, scalar) // If n is even: if mod(n, 2) { // Compute z * x. let zx := mul(z, x) // If z * x overflowed: if iszero(eq(div(zx, x), z)) { // Revert if x is non-zero. if iszero(iszero(x)) { revert(0, 0) } } // Round to the nearest number. let zxRound := add(zx, half) // Revert if zx + half overflowed. if lt(zxRound, zx) { revert(0, 0) } // Return properly scaled zxRound. z := div(zxRound, scalar) } } } } } /*////////////////////////////////////////////////////////////// GENERAL NUMBER UTILITIES //////////////////////////////////////////////////////////////*/ function sqrt(uint256 x) internal pure returns (uint256 z) { assembly { let y := x // We start y at x, which will help us make our initial estimate. z := 181 // The "correct" value is 1, but this saves a multiplication later. // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. // We check y >= 2^(k + 8) but shift right by k bits // each branch to ensure that if x >= 256, then y >= 256. if iszero(lt(y, 0x10000000000000000000000000000000000)) { y := shr(128, y) z := shl(64, z) } if iszero(lt(y, 0x1000000000000000000)) { y := shr(64, y) z := shl(32, z) } if iszero(lt(y, 0x10000000000)) { y := shr(32, y) z := shl(16, z) } if iszero(lt(y, 0x1000000)) { y := shr(16, y) z := shl(8, z) } // Goal was to get z*z*y within a small factor of x. More iterations could // get y in a tighter range. Currently, we will have y in [256, 256*2^16). // We ensured y >= 256 so that the relative difference between y and y+1 is small. // That's not possible if x < 256 but we can just verify those cases exhaustively. // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256. // Correctness can be checked exhaustively for x < 256, so we assume y >= 256. // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps. // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256. // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18. // There is no overflow risk here since y < 2^136 after the first branch above. z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181. // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // If x+1 is a perfect square, the Babylonian method cycles between // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor. // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case. // If you don't care whether the floor or ceil square root is returned, you can remove this statement. z := sub(z, lt(div(x, z), z)) } } function log2(uint256 x) internal pure returns (uint256 r) { require(x > 0, "UNDEFINED"); assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) r := or(r, shl(2, lt(0xf, shr(r, x)))) r := or(r, shl(1, lt(0x3, shr(r, x)))) r := or(r, lt(0x1, shr(r, x))) } } }
{ "remappings": [ "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "@rari-capital/solmate/=lib/solmate/", "@cwia/=lib/clones-with-immutable-args/src/", "forge-std/=lib/forge-std/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "safe-contracts/=lib/safe-contracts/contracts/", "solady/=lib/solady/src/", "clones-with-immutable-args/=node_modules/clones-with-immutable-args/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "solmate/=lib/solmate/src/" ], "optimizer": { "enabled": true, "runs": 200, "details": { "yul": false } }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"outputRoot","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"l2OutputIndex","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"l2BlockNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"l1Timestamp","type":"uint256"}],"name":"OutputProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"prevNextOutputIndex","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newNextOutputIndex","type":"uint256"}],"name":"OutputsDeleted","type":"event"},{"inputs":[],"name":"CHALLENGER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZATION_PERIOD_SECONDS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"L2_BLOCK_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROPOSER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SUBMISSION_INTERVAL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERIFIER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"challenger","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_l2BlockNumber","type":"uint256"}],"name":"computeL2Timestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_l2OutputIndex","type":"uint256"}],"name":"deleteL2Outputs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"finalizationPeriodSeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_l2OutputIndex","type":"uint256"}],"name":"getL2Output","outputs":[{"components":[{"internalType":"bytes32","name":"outputRoot","type":"bytes32"},{"internalType":"uint128","name":"timestamp","type":"uint128"},{"internalType":"uint128","name":"l2BlockNumber","type":"uint128"}],"internalType":"struct Types.OutputProposal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_l2BlockNumber","type":"uint256"}],"name":"getL2OutputAfter","outputs":[{"components":[{"internalType":"bytes32","name":"outputRoot","type":"bytes32"},{"internalType":"uint128","name":"timestamp","type":"uint128"},{"internalType":"uint128","name":"l2BlockNumber","type":"uint128"}],"internalType":"struct Types.OutputProposal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_l2BlockNumber","type":"uint256"}],"name":"getL2OutputIndexAfter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_submissionInterval","type":"uint256"},{"internalType":"uint256","name":"_l2BlockTime","type":"uint256"},{"internalType":"uint256","name":"_startingBlockNumber","type":"uint256"},{"internalType":"uint256","name":"_startingTimestamp","type":"uint256"},{"internalType":"address","name":"_proposer","type":"address"},{"internalType":"address","name":"_challenger","type":"address"},{"internalType":"address","name":"_verifier","type":"address"},{"internalType":"uint256","name":"_finalizationPeriodSeconds","type":"uint256"},{"internalType":"address","name":"_systemOwner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"l2BlockTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestOutputIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextOutputIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_outputRoot","type":"bytes32"},{"internalType":"uint256","name":"_l2BlockNumber","type":"uint256"},{"internalType":"bytes32","name":"_l1BlockHash","type":"bytes32"},{"internalType":"uint256","name":"_l1BlockNumber","type":"uint256"},{"internalType":"bytes","name":"_proof","type":"bytes"}],"name":"proposeL2Output","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"proposer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFinalizationPeriodLength","type":"uint256"}],"name":"setFinalizationPeriodSeconds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startingBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startingTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"submissionInterval","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"systemOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"verifier","outputs":[{"internalType":"contract Verifier","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b506200002760018060008080808080806200002d565b620003a9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff1615906001600160401b0316600081158015620000785750825b90506000826001600160401b03166001148015620000955750303b155b905081158015620000a4575080155b15620000c35760405163f92ee8a960e01b815260040160405180910390fd5b84546001600160401b03191660011785558315620000f257845460ff60401b1916680100000000000000001785555b60008e116200011e5760405162461bcd60e51b8152600401620001159062000282565b60405180910390fd5b60008d11620001415760405162461bcd60e51b81526004016200011590620002f5565b428b1115620001645760405162461bcd60e51b8152600401620001159062000307565b60048e905560058d905560008c905560018b9055600880546001600160a01b03808d166001600160a01b031992831617909255600680548c8416908316179055600980548b84169083161790556007805492891692909116919091179055600387905583156200021557845460ff60401b191685556040517fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2906200020c9060019062000399565b60405180910390a15b5050505050505050505050505050565b603a81526000602082017f4c324f75747075744f7261636c653a207375626d697373696f6e20696e74657281527f76616c206d7573742062652067726561746572207468616e2030000000000000602082015291505b5060400190565b60208082528101620002948162000225565b92915050565b603481526000602082017f4c324f75747075744f7261636c653a204c3220626c6f636b2074696d65206d7581527f73742062652067726561746572207468616e2030000000000000000000000000602082015291506200027b565b6020808252810162000294816200029a565b602080825281016200029481604481527f4c324f75747075744f7261636c653a207374617274696e67204c322074696d6560208201527f7374616d70206d757374206265206c657373207468616e2063757272656e742060408201526374696d6560e01b606082015260800190565b60006001600160401b03821662000294565b620003938162000376565b82525050565b6020810162000294828462000388565b61179980620003b96000396000f3fe6080604052600436106101b65760003560e01c80637f006420116100ec578063bffa7f0f1161008a578063d1de856c11610064578063d1de856c1461049e578063dcec3348146104be578063e1a41bcf146104d3578063f4daa291146104e957600080fd5b8063bffa7f0f1461044a578063ce5db8d614610468578063cf8e5cf01461047e57600080fd5b806393991af3116100c657806393991af3146103d4578063a25ae557146103ea578063a8e4fb9014610417578063a9efd6b81461043757600080fd5b80637f0064201461037e578063887862721461039e57806389c44cbb146103b457600080fd5b8063534db0e21161015957806369f16eec1161013357806369f16eec146103205780636abcf563146103355780636b4d98dd1461034a57806370872aa51461036857600080fd5b8063534db0e2146102a257806354fd4d50146102c25780635ba701941461030057600080fd5b80632b7ac3f3116101955780632b7ac3f31461022b57806333779254146102585780634599c78814610278578063529933df1461028d57600080fd5b80622134cc146101bb57806308c84e70146101e25780631246144b14610209575b600080fd5b3480156101c757600080fd5b506005545b6040516101d99190610c98565b60405180910390f35b3480156101ee57600080fd5b506009546001600160a01b03165b6040516101d99190610cc0565b34801561021557600080fd5b50610229610224366004610cfd565b6104fe565b005b34801561023757600080fd5b5060095461024b906001600160a01b031681565b6040516101d99190610de3565b34801561026457600080fd5b506007546101fc906001600160a01b031681565b34801561028457600080fd5b506101cc6106de565b34801561029957600080fd5b506004546101cc565b3480156102ae57600080fd5b506006546101fc906001600160a01b031681565b3480156102ce57600080fd5b506102f3604051806040016040528060058152602001640312e342e360dc1b81525081565b6040516101d99190610e47565b34801561030c57600080fd5b5061022961031b366004610e5f565b61073b565b34801561032c57600080fd5b506101cc61078e565b34801561034157600080fd5b506002546101cc565b34801561035657600080fd5b506006546001600160a01b03166101fc565b34801561037457600080fd5b506101cc60005481565b34801561038a57600080fd5b506101cc610399366004610e5f565b6107a0565b3480156103aa57600080fd5b506101cc60015481565b3480156103c057600080fd5b506102296103cf366004610e5f565b610872565b3480156103e057600080fd5b506101cc60055481565b3480156103f657600080fd5b5061040a610405366004610e5f565b61095a565b6040516101d99190610ed4565b34801561042357600080fd5b506008546101fc906001600160a01b031681565b610229610445366004610f34565b6109d8565b34801561045657600080fd5b506008546001600160a01b03166101fc565b34801561047457600080fd5b506101cc60035481565b34801561048a57600080fd5b5061040a610499366004610e5f565b610c11565b3480156104aa57600080fd5b506101cc6104b9366004610e5f565b610c49565b3480156104ca57600080fd5b506101cc610c79565b3480156104df57600080fd5b506101cc60045481565b3480156104f557600080fd5b506003546101cc565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156105445750825b905060008267ffffffffffffffff1660011480156105615750303b155b90508115801561056f575080155b1561058d5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156105b757845460ff60401b1916600160401b1785555b60008e116105e05760405162461bcd60e51b81526004016105d790611027565b60405180910390fd5b60008d116106005760405162461bcd60e51b81526004016105d790611088565b428b11156106205760405162461bcd60e51b81526004016105d790611102565b60048e905560058d905560008c905560018b9055600880546001600160a01b03808d166001600160a01b031992831617909255600680548c8416908316179055600980548b84169083161790556007805492891692909116919091179055600387905583156106ce57845460ff60401b191685556040517fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2906106c59060019061112d565b60405180910390a15b5050505050505050505050505050565b6002546000901561073257600280546106f990600190611151565b8154811061070957610709611164565b6000918252602090912060029091020160010154600160801b90046001600160801b0316919050565b6000545b905090565b6007546001600160a01b031633146107655760405162461bcd60e51b81526004016105d7906111c5565b6301e133808111156107895760405162461bcd60e51b81526004016105d79061121e565b600355565b60025460009061073690600190611151565b60006107aa6106de565b8211156107c95760405162461bcd60e51b81526004016105d790611299565b6002546107e85760405162461bcd60e51b81526004016105d790611312565b6002546000905b8082101561086b57600060026108058385611322565b61080f919061134b565b9050846002828154811061082557610825611164565b6000918252602090912060029091020160010154600160801b90046001600160801b031610156108615761085a816001611322565b9250610865565b8091505b506107ef565b5092915050565b6006546001600160a01b0316331461089c5760405162461bcd60e51b81526004016105d7906113b9565b60025481106108bd5760405162461bcd60e51b81526004016105d79061142f565b600354600282815481106108d3576108d3611164565b60009182526020909120600160029092020101546108fa906001600160801b031642611151565b106109175760405162461bcd60e51b81526004016105d7906114a8565b600061092260025490565b90508160025581817f4ee37ac2c786ec85e87592d3c5c8a1dd66f8496dda3f125d9ea8ca5f657629b660405160405180910390a35050565b60408051606081018252600080825260208201819052918101919091526002828154811061098a5761098a611164565b600091825260209182902060408051606081018252600290930290910180548352600101546001600160801b0380821694840194909452600160801b90049092169181019190915292915050565b6008546001600160a01b03163314610a025760405162461bcd60e51b81526004016105d79061151c565b610a0a610c79565b851015610a295760405162461bcd60e51b81526004016105d79061159b565b42610a3386610c49565b10610a505760405162461bcd60e51b81526004016105d7906115fe565b85610a6d5760405162461bcd60e51b81526004016105d790611668565b8315801590610a86575043610a838460ff611322565b10155b15610aab5783834014610aab5760405162461bcd60e51b81526004016105d7906116e4565b6009546040516000916001600160a01b031690610acb9085908590611713565b600060405180830381855afa9150503d8060008114610b06576040519150601f19603f3d011682016040523d82523d6000602084013e610b0b565b606091505b5050905080610b2c5760405162461bcd60e51b81526004016105d790611764565b85610b3660025490565b887fa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e242604051610b669190610c98565b60405180910390a45050604080516060810182529586526001600160801b0342811660208801908152958116918701918252600280546001810182556000829052975197027f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace810197909755945190518516600160801b029416939093177f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5acf90940193909355505050565b60408051606081018252600080825260208201819052918101919091526002610c39836107a0565b8154811061098a5761098a611164565b600060055460005483610c5c9190611151565b610c669190611774565b600154610c739190611322565b92915050565b6000600454610c866106de565b6107369190611322565b805b82525050565b60208101610c738284610c90565b60006001600160a01b038216610c73565b610c9281610ca6565b60208101610c738284610cb7565b805b8114610cdb57600080fd5b50565b8035610c7381610cce565b610cd081610ca6565b8035610c7381610ce9565b60008060008060008060008060006101208a8c031215610d1f57610d1f600080fd5b6000610d2b8c8c610cde565b9950506020610d3c8c828d01610cde565b9850506040610d4d8c828d01610cde565b9750506060610d5e8c828d01610cde565b9650506080610d6f8c828d01610cf2565b95505060a0610d808c828d01610cf2565b94505060c0610d918c828d01610cf2565b93505060e0610da28c828d01610cde565b925050610100610db48c828d01610cf2565b9150509295985092959850929598565b6000610c7382610ca6565b6000610c7382610dc4565b610c9281610dcf565b60208101610c738284610dda565b60005b83811015610e0c578181015183820152602001610df4565b50506000910152565b6000610e1f825190565b808452602084019350610e36818560208601610df1565b601f01601f19169290920192915050565b60208082528101610e588184610e15565b9392505050565b600060208284031215610e7457610e74600080fd5b6000610e808484610cde565b949350505050565b6001600160801b038116610c92565b80516060830190610ea88482610c90565b506020820151610ebb6020850182610e88565b506040820151610ece6040850182610e88565b50505050565b60608101610c738284610e97565b60008083601f840112610ef757610ef7600080fd5b50813567ffffffffffffffff811115610f1257610f12600080fd5b602083019150836001820283011115610f2d57610f2d600080fd5b9250929050565b60008060008060008060a08789031215610f5057610f50600080fd5b6000610f5c8989610cde565b9650506020610f6d89828a01610cde565b9550506040610f7e89828a01610cde565b9450506060610f8f89828a01610cde565b935050608087013567ffffffffffffffff811115610faf57610faf600080fd5b610fbb89828a01610ee2565b92509250509295509295509295565b603a81526000602082017f4c324f75747075744f7261636c653a207375626d697373696f6e20696e74657281527f76616c206d7573742062652067726561746572207468616e2030000000000000602082015291505b5060400190565b60208082528101610c7381610fca565b603481526000602082017f4c324f75747075744f7261636c653a204c3220626c6f636b2074696d65206d75815273073742062652067726561746572207468616e20360641b60208201529150611020565b60208082528101610c7381611037565b604481526000602082017f4c324f75747075744f7261636c653a207374617274696e67204c322074696d6581527f7374616d70206d757374206265206c657373207468616e2063757272656e742060208201526374696d6560e01b604082015291505b5060600190565b60208082528101610c7381611098565b600067ffffffffffffffff8216610c73565b610c9281611112565b60208101610c738284611124565b634e487b7160e01b600052601160045260246000fd5b81810381811115610c7357610c7361113b565b634e487b7160e01b600052603260045260246000fd5b602e81526000602082017f4c324f75747075744f7261636c653a2043616c6c6572206973206e6f7420746881526d329039bcb9ba32b69037bbb732b960911b60208201529150611020565b60208082528101610c738161117a565b602c81526000602082017f4c324f75747075744f7261636c653a2046696e616c697a6174696f6e2070657281526b696f6420746f6f206c6f6e6760a01b60208201529150611020565b60208082528101610c73816111d5565b604881526000602082017f4c324f75747075744f7261636c653a2063616e6e6f7420676574206f7574707581527f7420666f72206120626c6f636b207468617420686173206e6f74206265656e206020820152671c1c9bdc1bdcd95960c21b604082015291506110fb565b60208082528101610c738161122e565b604681526000602082017f4c324f75747075744f7261636c653a2063616e6e6f7420676574206f7574707581527f74206173206e6f206f7574707574732068617665206265656e2070726f706f736020820152651959081e595d60d21b604082015291506110fb565b60208082528101610c73816112a9565b80820180821115610c7357610c7361113b565b634e487b7160e01b600052601260045260246000fd5b60008261135a5761135a611335565b500490565b603e81526000602082017f4c324f75747075744f7261636c653a206f6e6c7920746865206368616c6c656e81527f67657220616464726573732063616e2064656c657465206f757470757473000060208201529150611020565b60208082528101610c738161135f565b604381526000602082017f4c324f75747075744f7261636c653a2063616e6e6f742064656c657465206f7581527f747075747320616674657220746865206c6174657374206f757470757420696e6020820152620c8caf60eb1b604082015291506110fb565b60208082528101610c73816113c9565b604681526000602082017f4c324f75747075744f7261636c653a2063616e6e6f742064656c657465206f7581527f74707574732074686174206861766520616c7265616479206265656e2066696e602082015265185b1a5e995960d21b604082015291506110fb565b60208082528101610c738161143f565b604181526000602082017f4c324f75747075744f7261636c653a206f6e6c79207468652070726f706f736581527f7220616464726573732063616e2070726f706f7365206e6577206f75747075746020820152607360f81b604082015291506110fb565b60208082528101610c73816114b8565b604c81526000602082017f4c324f75747075744f7261636c653a20626c6f636b206e756d626572206d757381527f74206265206174206c6561737420746865206e6578742065787065637465642060208201526b313637b1b590373ab6b132b960a11b604082015291506110fb565b60208082528101610c738161152c565b603681526000602082017f4c324f75747075744f7261636c653a2063616e6e6f742070726f706f7365204c81527532206f757470757420696e207468652066757475726560501b60208201529150611020565b60208082528101610c73816115ab565b603a81526000602082017f4c324f75747075744f7261636c653a204c32206f75747075742070726f706f7381527f616c2063616e6e6f7420626520746865207a65726f206861736800000000000060208201529150611020565b60208082528101610c738161160e565b604981526000602082017f4c324f75747075744f7261636c653a20626c6f636b206861736820646f65732081527f6e6f74206d6174636820746865206861736820617420746865206578706563746020820152681959081a195a59da1d60ba1b604082015291506110fb565b60208082528101610c7381611678565b82818337506000910152565b600061170d8385846116f4565b50500190565b6000610e80828486611700565b602781526000602082017f4c324f75747075744f7261636c653a2056657269666965722072656a656374658152663210383937b7b360c91b60208201529150611020565b60208082528101610c7381611720565b81810280821583820485141761086b5761086b61113b56fea164736f6c6343000814000a
Deployed Bytecode
0x6080604052600436106101b65760003560e01c80637f006420116100ec578063bffa7f0f1161008a578063d1de856c11610064578063d1de856c1461049e578063dcec3348146104be578063e1a41bcf146104d3578063f4daa291146104e957600080fd5b8063bffa7f0f1461044a578063ce5db8d614610468578063cf8e5cf01461047e57600080fd5b806393991af3116100c657806393991af3146103d4578063a25ae557146103ea578063a8e4fb9014610417578063a9efd6b81461043757600080fd5b80637f0064201461037e578063887862721461039e57806389c44cbb146103b457600080fd5b8063534db0e21161015957806369f16eec1161013357806369f16eec146103205780636abcf563146103355780636b4d98dd1461034a57806370872aa51461036857600080fd5b8063534db0e2146102a257806354fd4d50146102c25780635ba701941461030057600080fd5b80632b7ac3f3116101955780632b7ac3f31461022b57806333779254146102585780634599c78814610278578063529933df1461028d57600080fd5b80622134cc146101bb57806308c84e70146101e25780631246144b14610209575b600080fd5b3480156101c757600080fd5b506005545b6040516101d99190610c98565b60405180910390f35b3480156101ee57600080fd5b506009546001600160a01b03165b6040516101d99190610cc0565b34801561021557600080fd5b50610229610224366004610cfd565b6104fe565b005b34801561023757600080fd5b5060095461024b906001600160a01b031681565b6040516101d99190610de3565b34801561026457600080fd5b506007546101fc906001600160a01b031681565b34801561028457600080fd5b506101cc6106de565b34801561029957600080fd5b506004546101cc565b3480156102ae57600080fd5b506006546101fc906001600160a01b031681565b3480156102ce57600080fd5b506102f3604051806040016040528060058152602001640312e342e360dc1b81525081565b6040516101d99190610e47565b34801561030c57600080fd5b5061022961031b366004610e5f565b61073b565b34801561032c57600080fd5b506101cc61078e565b34801561034157600080fd5b506002546101cc565b34801561035657600080fd5b506006546001600160a01b03166101fc565b34801561037457600080fd5b506101cc60005481565b34801561038a57600080fd5b506101cc610399366004610e5f565b6107a0565b3480156103aa57600080fd5b506101cc60015481565b3480156103c057600080fd5b506102296103cf366004610e5f565b610872565b3480156103e057600080fd5b506101cc60055481565b3480156103f657600080fd5b5061040a610405366004610e5f565b61095a565b6040516101d99190610ed4565b34801561042357600080fd5b506008546101fc906001600160a01b031681565b610229610445366004610f34565b6109d8565b34801561045657600080fd5b506008546001600160a01b03166101fc565b34801561047457600080fd5b506101cc60035481565b34801561048a57600080fd5b5061040a610499366004610e5f565b610c11565b3480156104aa57600080fd5b506101cc6104b9366004610e5f565b610c49565b3480156104ca57600080fd5b506101cc610c79565b3480156104df57600080fd5b506101cc60045481565b3480156104f557600080fd5b506003546101cc565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156105445750825b905060008267ffffffffffffffff1660011480156105615750303b155b90508115801561056f575080155b1561058d5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156105b757845460ff60401b1916600160401b1785555b60008e116105e05760405162461bcd60e51b81526004016105d790611027565b60405180910390fd5b60008d116106005760405162461bcd60e51b81526004016105d790611088565b428b11156106205760405162461bcd60e51b81526004016105d790611102565b60048e905560058d905560008c905560018b9055600880546001600160a01b03808d166001600160a01b031992831617909255600680548c8416908316179055600980548b84169083161790556007805492891692909116919091179055600387905583156106ce57845460ff60401b191685556040517fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2906106c59060019061112d565b60405180910390a15b5050505050505050505050505050565b6002546000901561073257600280546106f990600190611151565b8154811061070957610709611164565b6000918252602090912060029091020160010154600160801b90046001600160801b0316919050565b6000545b905090565b6007546001600160a01b031633146107655760405162461bcd60e51b81526004016105d7906111c5565b6301e133808111156107895760405162461bcd60e51b81526004016105d79061121e565b600355565b60025460009061073690600190611151565b60006107aa6106de565b8211156107c95760405162461bcd60e51b81526004016105d790611299565b6002546107e85760405162461bcd60e51b81526004016105d790611312565b6002546000905b8082101561086b57600060026108058385611322565b61080f919061134b565b9050846002828154811061082557610825611164565b6000918252602090912060029091020160010154600160801b90046001600160801b031610156108615761085a816001611322565b9250610865565b8091505b506107ef565b5092915050565b6006546001600160a01b0316331461089c5760405162461bcd60e51b81526004016105d7906113b9565b60025481106108bd5760405162461bcd60e51b81526004016105d79061142f565b600354600282815481106108d3576108d3611164565b60009182526020909120600160029092020101546108fa906001600160801b031642611151565b106109175760405162461bcd60e51b81526004016105d7906114a8565b600061092260025490565b90508160025581817f4ee37ac2c786ec85e87592d3c5c8a1dd66f8496dda3f125d9ea8ca5f657629b660405160405180910390a35050565b60408051606081018252600080825260208201819052918101919091526002828154811061098a5761098a611164565b600091825260209182902060408051606081018252600290930290910180548352600101546001600160801b0380821694840194909452600160801b90049092169181019190915292915050565b6008546001600160a01b03163314610a025760405162461bcd60e51b81526004016105d79061151c565b610a0a610c79565b851015610a295760405162461bcd60e51b81526004016105d79061159b565b42610a3386610c49565b10610a505760405162461bcd60e51b81526004016105d7906115fe565b85610a6d5760405162461bcd60e51b81526004016105d790611668565b8315801590610a86575043610a838460ff611322565b10155b15610aab5783834014610aab5760405162461bcd60e51b81526004016105d7906116e4565b6009546040516000916001600160a01b031690610acb9085908590611713565b600060405180830381855afa9150503d8060008114610b06576040519150601f19603f3d011682016040523d82523d6000602084013e610b0b565b606091505b5050905080610b2c5760405162461bcd60e51b81526004016105d790611764565b85610b3660025490565b887fa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e242604051610b669190610c98565b60405180910390a45050604080516060810182529586526001600160801b0342811660208801908152958116918701918252600280546001810182556000829052975197027f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace810197909755945190518516600160801b029416939093177f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5acf90940193909355505050565b60408051606081018252600080825260208201819052918101919091526002610c39836107a0565b8154811061098a5761098a611164565b600060055460005483610c5c9190611151565b610c669190611774565b600154610c739190611322565b92915050565b6000600454610c866106de565b6107369190611322565b805b82525050565b60208101610c738284610c90565b60006001600160a01b038216610c73565b610c9281610ca6565b60208101610c738284610cb7565b805b8114610cdb57600080fd5b50565b8035610c7381610cce565b610cd081610ca6565b8035610c7381610ce9565b60008060008060008060008060006101208a8c031215610d1f57610d1f600080fd5b6000610d2b8c8c610cde565b9950506020610d3c8c828d01610cde565b9850506040610d4d8c828d01610cde565b9750506060610d5e8c828d01610cde565b9650506080610d6f8c828d01610cf2565b95505060a0610d808c828d01610cf2565b94505060c0610d918c828d01610cf2565b93505060e0610da28c828d01610cde565b925050610100610db48c828d01610cf2565b9150509295985092959850929598565b6000610c7382610ca6565b6000610c7382610dc4565b610c9281610dcf565b60208101610c738284610dda565b60005b83811015610e0c578181015183820152602001610df4565b50506000910152565b6000610e1f825190565b808452602084019350610e36818560208601610df1565b601f01601f19169290920192915050565b60208082528101610e588184610e15565b9392505050565b600060208284031215610e7457610e74600080fd5b6000610e808484610cde565b949350505050565b6001600160801b038116610c92565b80516060830190610ea88482610c90565b506020820151610ebb6020850182610e88565b506040820151610ece6040850182610e88565b50505050565b60608101610c738284610e97565b60008083601f840112610ef757610ef7600080fd5b50813567ffffffffffffffff811115610f1257610f12600080fd5b602083019150836001820283011115610f2d57610f2d600080fd5b9250929050565b60008060008060008060a08789031215610f5057610f50600080fd5b6000610f5c8989610cde565b9650506020610f6d89828a01610cde565b9550506040610f7e89828a01610cde565b9450506060610f8f89828a01610cde565b935050608087013567ffffffffffffffff811115610faf57610faf600080fd5b610fbb89828a01610ee2565b92509250509295509295509295565b603a81526000602082017f4c324f75747075744f7261636c653a207375626d697373696f6e20696e74657281527f76616c206d7573742062652067726561746572207468616e2030000000000000602082015291505b5060400190565b60208082528101610c7381610fca565b603481526000602082017f4c324f75747075744f7261636c653a204c3220626c6f636b2074696d65206d75815273073742062652067726561746572207468616e20360641b60208201529150611020565b60208082528101610c7381611037565b604481526000602082017f4c324f75747075744f7261636c653a207374617274696e67204c322074696d6581527f7374616d70206d757374206265206c657373207468616e2063757272656e742060208201526374696d6560e01b604082015291505b5060600190565b60208082528101610c7381611098565b600067ffffffffffffffff8216610c73565b610c9281611112565b60208101610c738284611124565b634e487b7160e01b600052601160045260246000fd5b81810381811115610c7357610c7361113b565b634e487b7160e01b600052603260045260246000fd5b602e81526000602082017f4c324f75747075744f7261636c653a2043616c6c6572206973206e6f7420746881526d329039bcb9ba32b69037bbb732b960911b60208201529150611020565b60208082528101610c738161117a565b602c81526000602082017f4c324f75747075744f7261636c653a2046696e616c697a6174696f6e2070657281526b696f6420746f6f206c6f6e6760a01b60208201529150611020565b60208082528101610c73816111d5565b604881526000602082017f4c324f75747075744f7261636c653a2063616e6e6f7420676574206f7574707581527f7420666f72206120626c6f636b207468617420686173206e6f74206265656e206020820152671c1c9bdc1bdcd95960c21b604082015291506110fb565b60208082528101610c738161122e565b604681526000602082017f4c324f75747075744f7261636c653a2063616e6e6f7420676574206f7574707581527f74206173206e6f206f7574707574732068617665206265656e2070726f706f736020820152651959081e595d60d21b604082015291506110fb565b60208082528101610c73816112a9565b80820180821115610c7357610c7361113b565b634e487b7160e01b600052601260045260246000fd5b60008261135a5761135a611335565b500490565b603e81526000602082017f4c324f75747075744f7261636c653a206f6e6c7920746865206368616c6c656e81527f67657220616464726573732063616e2064656c657465206f757470757473000060208201529150611020565b60208082528101610c738161135f565b604381526000602082017f4c324f75747075744f7261636c653a2063616e6e6f742064656c657465206f7581527f747075747320616674657220746865206c6174657374206f757470757420696e6020820152620c8caf60eb1b604082015291506110fb565b60208082528101610c73816113c9565b604681526000602082017f4c324f75747075744f7261636c653a2063616e6e6f742064656c657465206f7581527f74707574732074686174206861766520616c7265616479206265656e2066696e602082015265185b1a5e995960d21b604082015291506110fb565b60208082528101610c738161143f565b604181526000602082017f4c324f75747075744f7261636c653a206f6e6c79207468652070726f706f736581527f7220616464726573732063616e2070726f706f7365206e6577206f75747075746020820152607360f81b604082015291506110fb565b60208082528101610c73816114b8565b604c81526000602082017f4c324f75747075744f7261636c653a20626c6f636b206e756d626572206d757381527f74206265206174206c6561737420746865206e6578742065787065637465642060208201526b313637b1b590373ab6b132b960a11b604082015291506110fb565b60208082528101610c738161152c565b603681526000602082017f4c324f75747075744f7261636c653a2063616e6e6f742070726f706f7365204c81527532206f757470757420696e207468652066757475726560501b60208201529150611020565b60208082528101610c73816115ab565b603a81526000602082017f4c324f75747075744f7261636c653a204c32206f75747075742070726f706f7381527f616c2063616e6e6f7420626520746865207a65726f206861736800000000000060208201529150611020565b60208082528101610c738161160e565b604981526000602082017f4c324f75747075744f7261636c653a20626c6f636b206861736820646f65732081527f6e6f74206d6174636820746865206861736820617420746865206578706563746020820152681959081a195a59da1d60ba1b604082015291506110fb565b60208082528101610c7381611678565b82818337506000910152565b600061170d8385846116f4565b50500190565b6000610e80828486611700565b602781526000602082017f4c324f75747075744f7261636c653a2056657269666965722072656a656374658152663210383937b7b360c91b60208201529150611020565b60208082528101610c7381611720565b81810280821583820485141761086b5761086b61113b56fea164736f6c6343000814000a
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.