Overview
ETH Balance
0 ETH
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Transfer Ownersh... | 1466609 | 201 days ago | IN | 0 ETH | 0.00000003 |
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
1335126 | 204 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
OpWorldID
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 10000 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.15; import {WorldIDBridge} from "./abstract/WorldIDBridge.sol"; import {IOpWorldID} from "./interfaces/IOpWorldID.sol"; import {CrossDomainOwnable3} from "@eth-optimism/contracts-bedrock/contracts/L2/CrossDomainOwnable3.sol"; /// @title Optimism World ID Bridge /// @author Worldcoin /// @notice A contract that manages the root history of the Semaphore identity merkle tree on /// Optimism. /// @dev This contract is deployed on Optimism and is called by the L1 Proxy contract for each new /// root insertion. contract OpWorldID is WorldIDBridge, CrossDomainOwnable3, IOpWorldID { /////////////////////////////////////////////////////////////////////////////// /// CONSTRUCTION /// /////////////////////////////////////////////////////////////////////////////// /// @notice Initializes the contract the depth of the associated merkle tree. /// /// @param _treeDepth The depth of the WorldID Semaphore merkle tree. constructor(uint8 _treeDepth) WorldIDBridge(_treeDepth) {} /////////////////////////////////////////////////////////////////////////////// /// ROOT MIRRORING /// /////////////////////////////////////////////////////////////////////////////// /// @notice This function is called by the state bridge contract when it forwards a new root to /// the bridged WorldID. /// @dev This function can revert if Optimism's CrossDomainMessenger stops processing proofs /// or if OPLabs stops submitting them. Next iteration of Optimism's cross-domain messaging, will be /// fully permissionless for message-passing, so this will not be an issue. /// Sequencer needs to include changes to the CrossDomainMessenger contract on L1, /// not economically penalized if messages are not included, however the fraud prover (Cannon) /// can force the sequencer to include it. /// /// @param newRoot The value of the new root. /// /// @custom:reverts CannotOverwriteRoot If the root already exists in the root history. /// @custom:reverts string If the caller is not the owner. function receiveRoot(uint256 newRoot) external virtual onlyOwner { _receiveRoot(newRoot); } /////////////////////////////////////////////////////////////////////////////// /// DATA MANAGEMENT /// /////////////////////////////////////////////////////////////////////////////// /// @notice Sets the amount of time it takes for a root in the root history to expire. /// /// @param expiryTime The new amount of time it takes for a root to expire. /// /// @custom:reverts string If the caller is not the owner. function setRootHistoryExpiry(uint256 expiryTime) public virtual override onlyOwner { _setRootHistoryExpiry(expiryTime); } }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.15; import {IWorldID} from "../interfaces/IWorldID.sol"; import {SemaphoreTreeDepthValidator} from "../utils/SemaphoreTreeDepthValidator.sol"; import {SemaphoreVerifier} from "src/SemaphoreVerifier.sol"; /// @title Bridged World ID /// @author Worldcoin /// @notice A base contract for the WorldID state bridges that exist on other chains. The state /// bridges manage the root history of the identity merkle tree on chains other than /// mainnet. /// @dev This contract abstracts the common functionality, allowing for easier understanding and /// code reuse. /// @dev This contract is very explicitly not able to be instantiated. Do not un-mark it as /// `abstract`. abstract contract WorldIDBridge is IWorldID { /////////////////////////////////////////////////////////////////////////////// /// CONTRACT DATA /// /////////////////////////////////////////////////////////////////////////////// /// @notice The depth of the merkle tree used to store identities. uint8 internal immutable treeDepth; /// @notice The amount of time a root is considered as valid on the bridged chain. uint256 internal ROOT_HISTORY_EXPIRY = 1 weeks; /// @notice The value of the latest merkle tree root. uint256 internal _latestRoot; /// @notice The mapping between the value of the merkle tree root and the timestamp at which it /// entered the root history. mapping(uint256 => uint128) public rootHistory; /// @notice The time in the `rootHistory` mapping associated with a root that has never been /// seen before. uint128 internal constant NULL_ROOT_TIME = 0; /// @notice The verifier instance needed to operate within the semaphore protocol. SemaphoreVerifier internal semaphoreVerifier = new SemaphoreVerifier(); /////////////////////////////////////////////////////////////////////////////// /// ERRORS /// /////////////////////////////////////////////////////////////////////////////// /// @notice Emitted when the provided semaphore tree depth is unsupported. /// /// @param depth The tree depth that was passed. error UnsupportedTreeDepth(uint8 depth); /// @notice Emitted when attempting to validate a root that has expired. error ExpiredRoot(); /// @notice Emitted when attempting to validate a root that has yet to be added to the root /// history. error NonExistentRoot(); /// @notice Emitted when attempting to update the timestamp for a root that already has one. error CannotOverwriteRoot(); /// @notice Emitted if the latest root is requested but the bridge has not seen any roots yet. error NoRootsSeen(); /////////////////////////////////////////////////////////////////////////////// /// EVENTS /// /////////////////////////////////////////////////////////////////////////////// /// @notice Emitted when a new root is received by the contract. /// /// @param root The value of the root that was added. /// @param timestamp The timestamp of insertion for the given root. event RootAdded(uint256 root, uint128 timestamp); /// @notice Emitted when the expiry time for the root history is updated. /// /// @param newExpiry The new expiry time. event RootHistoryExpirySet(uint256 newExpiry); /////////////////////////////////////////////////////////////////////////////// /// CONSTRUCTION /// /////////////////////////////////////////////////////////////////////////////// /// @notice Constructs a new instance of the state bridge. /// /// @param _treeDepth The depth of the identities merkle tree. constructor(uint8 _treeDepth) { if (!SemaphoreTreeDepthValidator.validate(_treeDepth)) { revert UnsupportedTreeDepth(_treeDepth); } treeDepth = _treeDepth; } /////////////////////////////////////////////////////////////////////////////// /// ROOT MIRRORING /// /////////////////////////////////////////////////////////////////////////////// /// @notice This function is called by the state bridge contract when it forwards a new root to /// the bridged WorldID. /// @dev Intended to be called from a privilege-checked implementation of `receiveRoot` or an /// equivalent operation. /// /// @param newRoot The value of the new root. /// /// @custom:reverts CannotOverwriteRoot If the root already exists in the root history. function _receiveRoot(uint256 newRoot) internal { uint256 existingTimestamp = rootHistory[newRoot]; if (existingTimestamp != NULL_ROOT_TIME) { revert CannotOverwriteRoot(); } uint128 currTimestamp = uint128(block.timestamp); _latestRoot = newRoot; rootHistory[newRoot] = currTimestamp; emit RootAdded(newRoot, currTimestamp); } /// @notice Reverts if the provided root value is not valid. /// @dev A root is valid if it is either the latest root, or not the latest root but has not /// expired. /// /// @param root The root of the merkle tree to check for validity. /// /// @custom:reverts ExpiredRoot If the provided `root` has expired. /// @custom:reverts NonExistentRoot If the provided `root` does not exist in the history. function requireValidRoot(uint256 root) internal view { // The latest root is always valid. if (root == _latestRoot) { return; } // Otherwise, we need to check things via the timestamp. uint128 rootTimestamp = rootHistory[root]; // A root does not exist if it has no associated timestamp. if (rootTimestamp == 0) { revert NonExistentRoot(); } // A root is no longer valid if it has expired. if (block.timestamp - rootTimestamp > ROOT_HISTORY_EXPIRY) { revert ExpiredRoot(); } } /////////////////////////////////////////////////////////////////////////////// /// SEMAPHORE PROOFS /// /////////////////////////////////////////////////////////////////////////////// /// @notice A verifier for the semaphore protocol. /// @dev Note that a double-signaling check is not included here, and should be carried by the /// caller. /// /// @param root The root of the Merkle tree /// @param signalHash A keccak256 hash of the Semaphore signal /// @param nullifierHash The nullifier hash /// @param externalNullifierHash A keccak256 hash of the external nullifier /// @param proof The zero-knowledge proof /// /// @custom:reverts string If the zero-knowledge proof cannot be verified for the public inputs. function verifyProof( uint256 root, uint256 signalHash, uint256 nullifierHash, uint256 externalNullifierHash, uint256[8] calldata proof ) public view virtual { // Check the preconditions on the inputs. requireValidRoot(root); // With that done we can now verify the proof. semaphoreVerifier.verifyProof( proof, [root, nullifierHash, signalHash, externalNullifierHash] ); } /////////////////////////////////////////////////////////////////////////////// /// DATA MANAGEMENT /// /////////////////////////////////////////////////////////////////////////////// /// @notice Gets the value of the latest root. /// /// @custom:reverts NoRootsSeen If there is no latest root. function latestRoot() public view virtual returns (uint256) { if (_latestRoot == 0) { revert NoRootsSeen(); } return _latestRoot; } /// @notice Gets the amount of time it takes for a root in the root history to expire. function rootHistoryExpiry() public view virtual returns (uint256) { return ROOT_HISTORY_EXPIRY; } /// @notice Sets the amount of time it takes for a root in the root history to expire. /// @dev When implementing this function, ensure that it is guarded on `onlyOwner`. /// /// @param expiryTime The new amount of time it takes for a root to expire. function setRootHistoryExpiry(uint256 expiryTime) public virtual; /// @notice Sets the amount of time it takes for a root in the root history to expire. /// @dev Intended to be called from a privilege-checked implementation of `receiveRoot`. /// /// @param expiryTime The new amount of time it takes for a root to expire. function _setRootHistoryExpiry(uint256 expiryTime) internal virtual { ROOT_HISTORY_EXPIRY = expiryTime; emit RootHistoryExpirySet(expiryTime); } /// @notice Gets the Semaphore tree depth the contract was initialized with. function getTreeDepth() public view virtual returns (uint8) { return treeDepth; } }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.15; /// @title Interface for the OpWorldID contract /// @author Worldcoin /// @custom:usage abi.encodeCall(IOpWorldID.receiveRoot, (_newRoot, _supersedeTimestamp)); interface IOpWorldID { //////////////////////////////////////////////////////////////////////////////// /// ROOT MIRRORING /// /////////////////////////////////////////////////////////////////////////////// /// @notice This function is called by the state bridge contract when it forwards a new root to /// the bridged WorldID. /// @dev This function can revert if Optimism's CrossDomainMessenger stops processing proofs /// or if OPLabs stops submitting them. Next iteration of Optimism's cross-domain messaging, will be /// fully permissionless for message-passing, so this will not be an issue. /// Sequencer needs to include changes to the CrossDomainMessenger contract on L1, not economically penalized /// if messages are not included, however the fraud prover (Cannon) can force the sequencer to include it. /// /// @param newRoot The value of the new root. /// /// @custom:reverts CannotOverwriteRoot If the root already exists in the root history. /// @custom:reverts string If the caller is not the owner. function receiveRoot(uint256 newRoot) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { Predeploys } from "../libraries/Predeploys.sol"; import { L2CrossDomainMessenger } from "./L2CrossDomainMessenger.sol"; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; /** * @title CrossDomainOwnable3 * @notice This contract extends the OpenZeppelin `Ownable` contract for L2 contracts to be owned * by contracts on either L1 or L2. Note that this contract is meant to be used with systems * that use the CrossDomainMessenger system. It will not work if the OptimismPortal is * used directly. */ abstract contract CrossDomainOwnable3 is Ownable { /** * @notice If true, the contract uses the cross domain _checkOwner function override. If false * it uses the standard Ownable _checkOwner function. */ bool public isLocal = true; /** * @notice Emits when ownership of the contract is transferred. Includes the * isLocal field in addition to the standard `Ownable` OwnershipTransferred event. */ event OwnershipTransferred( address indexed previousOwner, address indexed newOwner, bool isLocal ); /** * @notice Allows for ownership to be transferred with specifying the locality. * @param _owner The new owner of the contract. * @param _isLocal Configures the locality of the ownership. */ function transferOwnership(address _owner, bool _isLocal) external onlyOwner { require(_owner != address(0), "CrossDomainOwnable3: new owner is the zero address"); address oldOwner = owner(); _transferOwnership(_owner); isLocal = _isLocal; emit OwnershipTransferred(oldOwner, _owner, _isLocal); } /** * @notice Overrides the implementation of the `onlyOwner` modifier to check that the unaliased * `xDomainMessageSender` is the owner of the contract. This value is set to the caller * of the L1CrossDomainMessenger. */ function _checkOwner() internal view override { if (isLocal) { require(owner() == msg.sender, "CrossDomainOwnable3: caller is not the owner"); } else { L2CrossDomainMessenger messenger = L2CrossDomainMessenger( Predeploys.L2_CROSS_DOMAIN_MESSENGER ); require( msg.sender == address(messenger), "CrossDomainOwnable3: caller is not the messenger" ); require( owner() == messenger.xDomainMessageSender(), "CrossDomainOwnable3: caller is not the owner" ); } } }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.15; /// @title WorldID Interface /// @author Worldcoin /// @notice The interface to the Semaphore Groth16 proof verification for WorldID. /// @custom:usage IWorldID(worldIDIdentityMangerAddress).verifyProof(root, signalHash, nullifierHash, externalNullifierHash, proof); interface IWorldID { /// @notice Verifies a WorldID zero knowledge proof. /// @dev Note that a double-signaling check is not included here, and should be carried by the /// caller. /// @dev It is highly recommended that the implementation is restricted to `view` if possible. /// /// @param root The of the Merkle tree /// @param signalHash A keccak256 hash of the Semaphore signal /// @param nullifierHash The nullifier hash /// @param externalNullifierHash A keccak256 hash of the external nullifier /// @param proof The zero-knowledge proof /// /// @custom:reverts string If the `proof` is invalid. function verifyProof( uint256 root, uint256 signalHash, uint256 nullifierHash, uint256 externalNullifierHash, uint256[8] calldata proof ) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.15; /// @title Semaphore tree depth validator /// @author Worldcoin library SemaphoreTreeDepthValidator { /// @notice Checks if the provided `treeDepth` is among supported depths. /// /// @param treeDepth The tree depth to validate. /// @return supportedDepth Returns `true` if `treeDepth` is between 16 and 32 function validate(uint8 treeDepth) internal pure returns (bool supportedDepth) { uint8 minDepth = 16; uint8 maxDepth = 32; return treeDepth >= minDepth && treeDepth <= maxDepth; } }
// SPDX-License-Identifier: MIT import {ISemaphoreVerifier} from "src/interfaces/ISemaphoreVerifier.sol"; pragma solidity ^0.8.0; /// @title Groth16 verifier template. /// @author Remco Bloemen /// @notice Supports verifying Groth16 proofs. Proofs can be in uncompressed /// (256 bytes) and compressed (128 bytes) format. A view function is provided /// to compress proofs. /// @notice See <https://2π.com/23/bn254-compression> for further explanation. contract SemaphoreVerifier is ISemaphoreVerifier { /// Some of the provided public input values are larger than the field modulus. /// @dev Public input elements are not automatically reduced, as this is can be /// a dangerous source of bugs. error PublicInputNotInField(); /// The proof is invalid. /// @dev This can mean that provided Groth16 proof points are not on their /// curves, that pairing equation fails, or that the proof is not for the /// provided public input. error ProofInvalid(); // Addresses of precompiles uint256 constant PRECOMPILE_MODEXP = 0x05; uint256 constant PRECOMPILE_ADD = 0x06; uint256 constant PRECOMPILE_MUL = 0x07; uint256 constant PRECOMPILE_VERIFY = 0x08; // Base field Fp order P and scalar field Fr order R. // For BN254 these are computed as follows: // t = 4965661367192848881 // P = 36⋅t⁴ + 36⋅t³ + 24⋅t² + 6⋅t + 1 // R = 36⋅t⁴ + 36⋅t³ + 18⋅t² + 6⋅t + 1 uint256 constant P = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47; uint256 constant R = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001; // Extension field Fp2 = Fp[i] / (i² + 1) // Note: This is the complex extension field of Fp with i² = -1. // Values in Fp2 are represented as a pair of Fp elements (a₀, a₁) as a₀ + a₁⋅i. // Note: The order of Fp2 elements is *opposite* that of the pairing contract, which // expects Fp2 elements in order (a₁, a₀). This is also the order in which // Fp2 elements are encoded in the public interface as this became convention. // Constants in Fp uint256 constant FRACTION_1_2_FP = 0x183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea4; uint256 constant FRACTION_27_82_FP = 0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5; uint256 constant FRACTION_3_82_FP = 0x2fcd3ac2a640a154eb23960892a85a68f031ca0c8344b23a577dcf1052b9e775; // Exponents for inversions and square roots mod P uint256 constant EXP_INVERSE_FP = 0x30644E72E131A029B85045B68181585D97816A916871CA8D3C208C16D87CFD45; // P - 2 uint256 constant EXP_SQRT_FP = 0xC19139CB84C680A6E14116DA060561765E05AA45A1C72A34F082305B61F3F52; // (P + 1) / 4; // Groth16 alpha point in G1 uint256 constant ALPHA_X = 20491192805390485299153009773594534940189261866228447918068658471970481763042; uint256 constant ALPHA_Y = 9383485363053290200918347156157836566562967994039712273449902621266178545958; // Groth16 beta point in G2 in powers of i uint256 constant BETA_NEG_X_0 = 6375614351688725206403948262868962793625744043794305715222011528459656738731; uint256 constant BETA_NEG_X_1 = 4252822878758300859123897981450591353533073413197771768651442665752259397132; uint256 constant BETA_NEG_Y_0 = 11383000245469012944693504663162918391286475477077232690815866754273895001727; uint256 constant BETA_NEG_Y_1 = 41207766310529818958173054109690360505148424997958324311878202295167071904; // Groth16 gamma point in G2 in powers of i uint256 constant GAMMA_NEG_X_0 = 10857046999023057135944570762232829481370756359578518086990519993285655852781; uint256 constant GAMMA_NEG_X_1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634; uint256 constant GAMMA_NEG_Y_0 = 13392588948715843804641432497768002650278120570034223513918757245338268106653; uint256 constant GAMMA_NEG_Y_1 = 17805874995975841540914202342111839520379459829704422454583296818431106115052; // Groth16 delta point in G2 in powers of i uint256 constant DELTA_NEG_X_0 = 15028154694713144242204861571552635520290993855826554325002991692907421516918; uint256 constant DELTA_NEG_X_1 = 10202326166286888893675634318107715186834588694714750762952081034135561546271; uint256 constant DELTA_NEG_Y_0 = 9121952986466441409625823112409402110610350380222160673756836983949377617226; uint256 constant DELTA_NEG_Y_1 = 3402203030459169245973828223647408421795734658790470725360311404592929738724; // Constant and public input points uint256 constant CONSTANT_X = 1452272927738590248356371174422184656932731110936062990115610832462181634644; uint256 constant CONSTANT_Y = 3608050114233210789542189629343107890943266759827387991788718454179833288695; uint256 constant PUB_0_X = 14798240452388909327945424685903532333765637883272751382037716636327236955001; uint256 constant PUB_0_Y = 10773894897711848209682368488916121016695006898681985691467605219098835500201; uint256 constant PUB_1_X = 17204267933132009093604099819536245144503489322639121825381131096467570698650; uint256 constant PUB_1_Y = 7704298975420304156332734115679983371345754866278811368869074990486717531131; uint256 constant PUB_2_X = 8060465662017324080560848316478407038163145149983639907596180500095598669247; uint256 constant PUB_2_Y = 20475082166427284188002500222093571716651248980245637602667562336751029856573; uint256 constant PUB_3_X = 7457566682692308112726332096733260585025339741083447785327706250123165087868; uint256 constant PUB_3_Y = 11904519443874922292602150685069370036383697877657723976244907400392778002614; /// Negation in Fp. /// @notice Returns a number x such that a + x = 0 in Fp. /// @notice The input does not need to be reduced. /// @param a the base /// @return x the result function negate(uint256 a) internal pure returns (uint256 x) { unchecked { x = (P - (a % P)) % P; // Modulo is cheaper than branching } } /// Exponentiation in Fp. /// @notice Returns a number x such that a ^ e = x in Fp. /// @notice The input does not need to be reduced. /// @param a the base /// @param e the exponent /// @return x the result function exp(uint256 a, uint256 e) internal view returns (uint256 x) { bool success; assembly ("memory-safe") { let f := mload(0x40) mstore(f, 0x20) mstore(add(f, 0x20), 0x20) mstore(add(f, 0x40), 0x20) mstore(add(f, 0x60), a) mstore(add(f, 0x80), e) mstore(add(f, 0xa0), P) success := staticcall(gas(), PRECOMPILE_MODEXP, f, 0xc0, f, 0x20) x := mload(f) } if (!success) { // Exponentiation failed. // Should not happen. revert ProofInvalid(); } } /// Invertsion in Fp. /// @notice Returns a number x such that a * x = 1 in Fp. /// @notice The input does not need to be reduced. /// @notice Reverts with ProofInvalid() if the inverse does not exist /// @param a the input /// @return x the solution function invert_Fp(uint256 a) internal view returns (uint256 x) { x = exp(a, EXP_INVERSE_FP); if (mulmod(a, x, P) != 1) { // Inverse does not exist. // Can only happen during G2 point decompression. revert ProofInvalid(); } } /// Square root in Fp. /// @notice Returns a number x such that x * x = a in Fp. /// @notice Will revert with InvalidProof() if the input is not a square /// or not reduced. /// @param a the square /// @return x the solution function sqrt_Fp(uint256 a) internal view returns (uint256 x) { x = exp(a, EXP_SQRT_FP); if (mulmod(x, x, P) != a) { // Square root does not exist or a is not reduced. // Happens when G1 point is not on curve. revert ProofInvalid(); } } /// Square test in Fp. /// @notice Returns wheter a number x exists such that x * x = a in Fp. /// @notice Will revert with InvalidProof() if the input is not a square /// or not reduced. /// @param a the square /// @return x the solution function isSquare_Fp(uint256 a) internal view returns (bool) { uint256 x = exp(a, EXP_SQRT_FP); return mulmod(x, x, P) == a; } /// Square root in Fp2. /// @notice Fp2 is the complex extension Fp[i]/(i^2 + 1). The input is /// a0 + a1 ⋅ i and the result is x0 + x1 ⋅ i. /// @notice Will revert with InvalidProof() if /// * the input is not a square, /// * the hint is incorrect, or /// * the input coefficents are not reduced. /// @param a0 The real part of the input. /// @param a1 The imaginary part of the input. /// @param hint A hint which of two possible signs to pick in the equation. /// @return x0 The real part of the square root. /// @return x1 The imaginary part of the square root. function sqrt_Fp2(uint256 a0, uint256 a1, bool hint) internal view returns (uint256 x0, uint256 x1) { // If this square root reverts there is no solution in Fp2. uint256 d = sqrt_Fp(addmod(mulmod(a0, a0, P), mulmod(a1, a1, P), P)); if (hint) { d = negate(d); } // If this square root reverts there is no solution in Fp2. x0 = sqrt_Fp(mulmod(addmod(a0, d, P), FRACTION_1_2_FP, P)); x1 = mulmod(a1, invert_Fp(mulmod(x0, 2, P)), P); // Check result to make sure we found a root. // Note: this also fails if a0 or a1 is not reduced. if ( a0 != addmod(mulmod(x0, x0, P), negate(mulmod(x1, x1, P)), P) || a1 != mulmod(2, mulmod(x0, x1, P), P) ) { revert ProofInvalid(); } } /// Compress a G1 point. /// @notice Reverts with InvalidProof if the coordinates are not reduced /// or if the point is not on the curve. /// @notice The point at infinity is encoded as (0,0) and compressed to 0. /// @param x The X coordinate in Fp. /// @param y The Y coordinate in Fp. /// @return c The compresed point (x with one signal bit). function compress_g1(uint256 x, uint256 y) internal view returns (uint256 c) { if (x >= P || y >= P) { // G1 point not in field. revert ProofInvalid(); } if (x == 0 && y == 0) { // Point at infinity return 0; } // Note: sqrt_Fp reverts if there is no solution, i.e. the x coordinate is invalid. uint256 y_pos = sqrt_Fp(addmod(mulmod(mulmod(x, x, P), x, P), 3, P)); if (y == y_pos) { return (x << 1) | 0; } else if (y == negate(y_pos)) { return (x << 1) | 1; } else { // G1 point not on curve. revert ProofInvalid(); } } /// Decompress a G1 point. /// @notice Reverts with InvalidProof if the input does not represent a valid point. /// @notice The point at infinity is encoded as (0,0) and compressed to 0. /// @param c The compresed point (x with one signal bit). /// @return x The X coordinate in Fp. /// @return y The Y coordinate in Fp. function decompress_g1(uint256 c) internal view returns (uint256 x, uint256 y) { // Note that X = 0 is not on the curve since 0³ + 3 = 3 is not a square. // so we can use it to represent the point at infinity. if (c == 0) { // Point at infinity as encoded in EIP196 and EIP197. return (0, 0); } bool negate_point = c & 1 == 1; x = c >> 1; if (x >= P) { // G1 x coordinate not in field. revert ProofInvalid(); } // Note: (x³ + 3) is irreducible in Fp, so it can not be zero and therefore // y can not be zero. // Note: sqrt_Fp reverts if there is no solution, i.e. the point is not on the curve. y = sqrt_Fp(addmod(mulmod(mulmod(x, x, P), x, P), 3, P)); if (negate_point) { y = negate(y); } } /// Compress a G2 point. /// @notice Reverts with InvalidProof if the coefficients are not reduced /// or if the point is not on the curve. /// @notice The G2 curve is defined over the complex extension Fp[i]/(i^2 + 1) /// with coordinates (x0 + x1 ⋅ i, y0 + y1 ⋅ i). /// @notice The point at infinity is encoded as (0,0,0,0) and compressed to (0,0). /// @param x0 The real part of the X coordinate. /// @param x1 The imaginary poart of the X coordinate. /// @param y0 The real part of the Y coordinate. /// @param y1 The imaginary part of the Y coordinate. /// @return c0 The first half of the compresed point (x0 with two signal bits). /// @return c1 The second half of the compressed point (x1 unmodified). function compress_g2(uint256 x0, uint256 x1, uint256 y0, uint256 y1) internal view returns (uint256 c0, uint256 c1) { if (x0 >= P || x1 >= P || y0 >= P || y1 >= P) { // G2 point not in field. revert ProofInvalid(); } if ((x0 | x1 | y0 | y1) == 0) { // Point at infinity return (0, 0); } // Compute y^2 // Note: shadowing variables and scoping to avoid stack-to-deep. uint256 y0_pos; uint256 y1_pos; { uint256 n3ab = mulmod(mulmod(x0, x1, P), P - 3, P); uint256 a_3 = mulmod(mulmod(x0, x0, P), x0, P); uint256 b_3 = mulmod(mulmod(x1, x1, P), x1, P); y0_pos = addmod(FRACTION_27_82_FP, addmod(a_3, mulmod(n3ab, x1, P), P), P); y1_pos = negate(addmod(FRACTION_3_82_FP, addmod(b_3, mulmod(n3ab, x0, P), P), P)); } // Determine hint bit // If this sqrt fails the x coordinate is not on the curve. bool hint; { uint256 d = sqrt_Fp(addmod(mulmod(y0_pos, y0_pos, P), mulmod(y1_pos, y1_pos, P), P)); hint = !isSquare_Fp(mulmod(addmod(y0_pos, d, P), FRACTION_1_2_FP, P)); } // Recover y (y0_pos, y1_pos) = sqrt_Fp2(y0_pos, y1_pos, hint); if (y0 == y0_pos && y1 == y1_pos) { c0 = (x0 << 2) | (hint ? 2 : 0) | 0; c1 = x1; } else if (y0 == negate(y0_pos) && y1 == negate(y1_pos)) { c0 = (x0 << 2) | (hint ? 2 : 0) | 1; c1 = x1; } else { // G1 point not on curve. revert ProofInvalid(); } } /// Decompress a G2 point. /// @notice Reverts with InvalidProof if the input does not represent a valid point. /// @notice The G2 curve is defined over the complex extension Fp[i]/(i^2 + 1) /// with coordinates (x0 + x1 ⋅ i, y0 + y1 ⋅ i). /// @notice The point at infinity is encoded as (0,0,0,0) and compressed to (0,0). /// @param c0 The first half of the compresed point (x0 with two signal bits). /// @param c1 The second half of the compressed point (x1 unmodified). /// @return x0 The real part of the X coordinate. /// @return x1 The imaginary poart of the X coordinate. /// @return y0 The real part of the Y coordinate. /// @return y1 The imaginary part of the Y coordinate. function decompress_g2(uint256 c0, uint256 c1) internal view returns (uint256 x0, uint256 x1, uint256 y0, uint256 y1) { // Note that X = (0, 0) is not on the curve since 0³ + 3/(9 + i) is not a square. // so we can use it to represent the point at infinity. if (c0 == 0 && c1 == 0) { // Point at infinity as encoded in EIP197. return (0, 0, 0, 0); } bool negate_point = c0 & 1 == 1; bool hint = c0 & 2 == 2; x0 = c0 >> 2; x1 = c1; if (x0 >= P || x1 >= P) { // G2 x0 or x1 coefficient not in field. revert ProofInvalid(); } uint256 n3ab = mulmod(mulmod(x0, x1, P), P - 3, P); uint256 a_3 = mulmod(mulmod(x0, x0, P), x0, P); uint256 b_3 = mulmod(mulmod(x1, x1, P), x1, P); y0 = addmod(FRACTION_27_82_FP, addmod(a_3, mulmod(n3ab, x1, P), P), P); y1 = negate(addmod(FRACTION_3_82_FP, addmod(b_3, mulmod(n3ab, x0, P), P), P)); // Note: sqrt_Fp2 reverts if there is no solution, i.e. the point is not on the curve. // Note: (X³ + 3/(9 + i)) is irreducible in Fp2, so y can not be zero. // But y0 or y1 may still independently be zero. (y0, y1) = sqrt_Fp2(y0, y1, hint); if (negate_point) { y0 = negate(y0); y1 = negate(y1); } } /// Compute the public input linear combination. /// @notice Reverts with PublicInputNotInField if the input is not in the field. /// @notice Computes the multi-scalar-multiplication of the public input /// elements and the verification key including the constant term. /// @param input The public inputs. These are elements of the scalar field Fr. /// @return x The X coordinate of the resulting G1 point. /// @return y The Y coordinate of the resulting G1 point. function publicInputMSM(uint256[4] calldata input) internal view returns (uint256 x, uint256 y) { // Note: The ECMUL precompile does not reject unreduced values, so we check this. // Note: Unrolling this loop does not cost much extra in code-size, the bulk of the // code-size is in the PUB_ constants. // ECMUL has input (x, y, scalar) and output (x', y'). // ECADD has input (x1, y1, x2, y2) and output (x', y'). // We call them such that ecmul output is already in the second point // argument to ECADD so we can have a tight loop. bool success = true; assembly ("memory-safe") { let f := mload(0x40) let g := add(f, 0x40) let s mstore(f, CONSTANT_X) mstore(add(f, 0x20), CONSTANT_Y) mstore(g, PUB_0_X) mstore(add(g, 0x20), PUB_0_Y) s := calldataload(input) mstore(add(g, 0x40), s) success := and(success, lt(s, R)) success := and(success, staticcall(gas(), PRECOMPILE_MUL, g, 0x60, g, 0x40)) success := and(success, staticcall(gas(), PRECOMPILE_ADD, f, 0x80, f, 0x40)) mstore(g, PUB_1_X) mstore(add(g, 0x20), PUB_1_Y) s := calldataload(add(input, 32)) mstore(add(g, 0x40), s) success := and(success, lt(s, R)) success := and(success, staticcall(gas(), PRECOMPILE_MUL, g, 0x60, g, 0x40)) success := and(success, staticcall(gas(), PRECOMPILE_ADD, f, 0x80, f, 0x40)) mstore(g, PUB_2_X) mstore(add(g, 0x20), PUB_2_Y) s := calldataload(add(input, 64)) mstore(add(g, 0x40), s) success := and(success, lt(s, R)) success := and(success, staticcall(gas(), PRECOMPILE_MUL, g, 0x60, g, 0x40)) success := and(success, staticcall(gas(), PRECOMPILE_ADD, f, 0x80, f, 0x40)) mstore(g, PUB_3_X) mstore(add(g, 0x20), PUB_3_Y) s := calldataload(add(input, 96)) mstore(add(g, 0x40), s) success := and(success, lt(s, R)) success := and(success, staticcall(gas(), PRECOMPILE_MUL, g, 0x60, g, 0x40)) success := and(success, staticcall(gas(), PRECOMPILE_ADD, f, 0x80, f, 0x40)) x := mload(f) y := mload(add(f, 0x20)) } if (!success) { // Either Public input not in field, or verification key invalid. // We assume the contract is correctly generated, so the verification key is valid. revert PublicInputNotInField(); } } /// Compress a proof. /// @notice Will revert with InvalidProof if the curve points are invalid, /// but does not verify the proof itself. /// @param proof The uncompressed Groth16 proof. Elements are in the same order as for /// verifyProof. I.e. Groth16 points (A, B, C) encoded as in EIP-197. /// @return compressed The compressed proof. Elements are in the same order as for /// verifyCompressedProof. I.e. points (A, B, C) in compressed format. function compressProof(uint256[8] calldata proof) public view returns (uint256[4] memory compressed) { compressed[0] = compress_g1(proof[0], proof[1]); (compressed[2], compressed[1]) = compress_g2(proof[3], proof[2], proof[5], proof[4]); compressed[3] = compress_g1(proof[6], proof[7]); } /// Verify a Groth16 proof with compressed points. /// @notice Reverts with InvalidProof if the proof is invalid or /// with PublicInputNotInField the public input is not reduced. /// @notice There is no return value. If the function does not revert, the /// proof was succesfully verified. /// @param compressedProof the points (A, B, C) in compressed format /// matching the output of compressProof. /// @param input the public input field elements in the scalar field Fr. /// Elements must be reduced. function verifyCompressedProof(uint256[4] calldata compressedProof, uint256[4] calldata input) public view { (uint256 Ax, uint256 Ay) = decompress_g1(compressedProof[0]); (uint256 Bx0, uint256 Bx1, uint256 By0, uint256 By1) = decompress_g2(compressedProof[2], compressedProof[1]); (uint256 Cx, uint256 Cy) = decompress_g1(compressedProof[3]); (uint256 Lx, uint256 Ly) = publicInputMSM(input); // Verify the pairing // Note: The precompile expects the F2 coefficients in big-endian order. // Note: The pairing precompile rejects unreduced values, so we won't check that here. uint256[24] memory pairings; // e(A, B) pairings[0] = Ax; pairings[1] = Ay; pairings[2] = Bx1; pairings[3] = Bx0; pairings[4] = By1; pairings[5] = By0; // e(C, -δ) pairings[6] = Cx; pairings[7] = Cy; pairings[8] = DELTA_NEG_X_1; pairings[9] = DELTA_NEG_X_0; pairings[10] = DELTA_NEG_Y_1; pairings[11] = DELTA_NEG_Y_0; // e(α, -β) pairings[12] = ALPHA_X; pairings[13] = ALPHA_Y; pairings[14] = BETA_NEG_X_1; pairings[15] = BETA_NEG_X_0; pairings[16] = BETA_NEG_Y_1; pairings[17] = BETA_NEG_Y_0; // e(L_pub, -γ) pairings[18] = Lx; pairings[19] = Ly; pairings[20] = GAMMA_NEG_X_1; pairings[21] = GAMMA_NEG_X_0; pairings[22] = GAMMA_NEG_Y_1; pairings[23] = GAMMA_NEG_Y_0; // Check pairing equation. bool success; uint256[1] memory output; assembly ("memory-safe") { success := staticcall(gas(), PRECOMPILE_VERIFY, pairings, 0x300, output, 0x20) } if (!success || output[0] != 1) { // Either proof or verification key invalid. // We assume the contract is correctly generated, so the verification key is valid. revert ProofInvalid(); } } /// Verify an uncompressed Groth16 proof. /// @notice Reverts with InvalidProof if the proof is invalid or /// with PublicInputNotInField the public input is not reduced. /// @notice There is no return value. If the function does not revert, the /// proof was succesfully verified. /// @param proof the points (A, B, C) in EIP-197 format matching the output /// of compressProof. /// @param input the public input field elements in the scalar field Fr. /// Elements must be reduced. function verifyProof(uint256[8] calldata proof, uint256[4] calldata input) public view { (uint256 x, uint256 y) = publicInputMSM(input); // Note: The precompile expects the F2 coefficients in big-endian order. // Note: The pairing precompile rejects unreduced values, so we won't check that here. bool success; assembly ("memory-safe") { let f := mload(0x40) // Free memory pointer. // Copy points (A, B, C) to memory. They are already in correct encoding. // This is pairing e(A, B) and G1 of e(C, -δ). calldatacopy(f, proof, 0x100) // Complete e(C, -δ) and write e(α, -β), e(L_pub, -γ) to memory. // OPT: This could be better done using a single codecopy, but // Solidity (unlike standalone Yul) doesn't provide a way to // to do this. mstore(add(f, 0x100), DELTA_NEG_X_1) mstore(add(f, 0x120), DELTA_NEG_X_0) mstore(add(f, 0x140), DELTA_NEG_Y_1) mstore(add(f, 0x160), DELTA_NEG_Y_0) mstore(add(f, 0x180), ALPHA_X) mstore(add(f, 0x1a0), ALPHA_Y) mstore(add(f, 0x1c0), BETA_NEG_X_1) mstore(add(f, 0x1e0), BETA_NEG_X_0) mstore(add(f, 0x200), BETA_NEG_Y_1) mstore(add(f, 0x220), BETA_NEG_Y_0) mstore(add(f, 0x240), x) mstore(add(f, 0x260), y) mstore(add(f, 0x280), GAMMA_NEG_X_1) mstore(add(f, 0x2a0), GAMMA_NEG_X_0) mstore(add(f, 0x2c0), GAMMA_NEG_Y_1) mstore(add(f, 0x2e0), GAMMA_NEG_Y_0) // Check pairing equation. success := staticcall(gas(), PRECOMPILE_VERIFY, f, 0x300, f, 0x20) // Also check returned value (both are either 1 or 0). success := and(success, mload(f)) } if (!success) { // Either proof or verification key invalid. // We assume the contract is correctly generated, so the verification key is valid. revert ProofInvalid(); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title Predeploys * @notice Contains constant addresses for contracts that are pre-deployed to the L2 system. */ library Predeploys { /** * @notice Address of the L2ToL1MessagePasser predeploy. */ address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000016; /** * @notice Address of the L2CrossDomainMessenger predeploy. */ address internal constant L2_CROSS_DOMAIN_MESSENGER = 0x4200000000000000000000000000000000000007; /** * @notice Address of the L2StandardBridge predeploy. */ address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010; /** * @notice Address of the L2ERC721Bridge predeploy. */ address internal constant L2_ERC721_BRIDGE = 0x4200000000000000000000000000000000000014; /** * @notice Address of the SequencerFeeWallet predeploy. */ address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011; /** * @notice Address of the OptimismMintableERC20Factory predeploy. */ address internal constant OPTIMISM_MINTABLE_ERC20_FACTORY = 0x4200000000000000000000000000000000000012; /** * @notice Address of the OptimismMintableERC721Factory predeploy. */ address internal constant OPTIMISM_MINTABLE_ERC721_FACTORY = 0x4200000000000000000000000000000000000017; /** * @notice Address of the L1Block predeploy. */ address internal constant L1_BLOCK_ATTRIBUTES = 0x4200000000000000000000000000000000000015; /** * @notice Address of the GasPriceOracle predeploy. Includes fee information * and helpers for computing the L1 portion of the transaction fee. */ address internal constant GAS_PRICE_ORACLE = 0x420000000000000000000000000000000000000F; /** * @custom:legacy * @notice Address of the L1MessageSender predeploy. Deprecated. Use L2CrossDomainMessenger * or access tx.origin (or msg.sender) in a L1 to L2 transaction instead. */ address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001; /** * @custom:legacy * @notice Address of the DeployerWhitelist predeploy. No longer active. */ address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002; /** * @custom:legacy * @notice Address of the LegacyERC20ETH predeploy. Deprecated. Balances are migrated to the * state trie as of the Bedrock upgrade. Contract has been locked and write functions * can no longer be accessed. */ address internal constant LEGACY_ERC20_ETH = 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000; /** * @custom:legacy * @notice Address of the L1BlockNumber predeploy. Deprecated. Use the L1Block predeploy * instead, which exposes more information about the L1 state. */ address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013; /** * @custom:legacy * @notice Address of the LegacyMessagePasser predeploy. Deprecate. Use the updated * L2ToL1MessagePasser contract instead. */ address internal constant LEGACY_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000; /** * @notice Address of the ProxyAdmin predeploy. */ address internal constant PROXY_ADMIN = 0x4200000000000000000000000000000000000018; /** * @notice Address of the BaseFeeVault predeploy. */ address internal constant BASE_FEE_VAULT = 0x4200000000000000000000000000000000000019; /** * @notice Address of the L1FeeVault predeploy. */ address internal constant L1_FEE_VAULT = 0x420000000000000000000000000000000000001A; /** * @notice Address of the GovernanceToken predeploy. */ address internal constant GOVERNANCE_TOKEN = 0x4200000000000000000000000000000000000042; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.15; import { AddressAliasHelper } from "../vendor/AddressAliasHelper.sol"; import { Predeploys } from "../libraries/Predeploys.sol"; import { CrossDomainMessenger } from "../universal/CrossDomainMessenger.sol"; import { Semver } from "../universal/Semver.sol"; import { L2ToL1MessagePasser } from "./L2ToL1MessagePasser.sol"; /** * @custom:proxied * @custom:predeploy 0x4200000000000000000000000000000000000007 * @title L2CrossDomainMessenger * @notice The L2CrossDomainMessenger is a high-level interface for message passing between L1 and * L2 on the L2 side. Users are generally encouraged to use this contract instead of lower * level message passing contracts. */ contract L2CrossDomainMessenger is CrossDomainMessenger, Semver { /** * @custom:semver 1.1.0 * * @param _l1CrossDomainMessenger Address of the L1CrossDomainMessenger contract. */ constructor(address _l1CrossDomainMessenger) Semver(1, 1, 0) CrossDomainMessenger(_l1CrossDomainMessenger) { initialize(); } /** * @notice Initializer. */ function initialize() public initializer { __CrossDomainMessenger_init(); } /** * @custom:legacy * @notice Legacy getter for the remote messenger. Use otherMessenger going forward. * * @return Address of the L1CrossDomainMessenger contract. */ function l1CrossDomainMessenger() public view returns (address) { return OTHER_MESSENGER; } /** * @inheritdoc CrossDomainMessenger */ function _sendMessage( address _to, uint64 _gasLimit, uint256 _value, bytes memory _data ) internal override { L2ToL1MessagePasser(payable(Predeploys.L2_TO_L1_MESSAGE_PASSER)).initiateWithdrawal{ value: _value }(_to, _gasLimit, _data); } /** * @inheritdoc CrossDomainMessenger */ function _isOtherMessenger() internal view override returns (bool) { return AddressAliasHelper.undoL1ToL2Alias(msg.sender) == OTHER_MESSENGER; } /** * @inheritdoc CrossDomainMessenger */ function _isUnsafeTarget(address _target) internal view override returns (bool) { return _target == address(this) || _target == address(Predeploys.L2_TO_L1_MESSAGE_PASSER); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.15; /// @title Tree Verifier Interface /// @author Worldcoin /// @notice An interface representing a merkle tree verifier. interface ISemaphoreVerifier { /// @notice Verify an uncompressed Groth16 proof. /// @notice Reverts with InvalidProof if the proof is invalid or /// with PublicInputNotInField the public input is not reduced. /// @notice There is no return value. If the function does not revert, the /// proof was succesfully verified. /// @param proof the points (A, B, C) in EIP-197 format matching the output /// of compressProof. /// @param input the public input field elements in the scalar field Fr. /// Elements must be reduced. function verifyProof(uint256[8] calldata proof, uint256[4] calldata input) external view; }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2019-2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.8.0; library AddressAliasHelper { uint160 constant offset = uint160(0x1111000000000000000000000000000000001111); /// @notice Utility function that converts the address in the L1 that submitted a tx to /// the inbox to the msg.sender viewed in the L2 /// @param l1Address the address in the L1 that triggered the tx to L2 /// @return l2Address L2 address as viewed in msg.sender function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) { unchecked { l2Address = address(uint160(l1Address) + offset); } } /// @notice Utility function that converts the msg.sender viewed in the L2 to the /// address in the L1 that submitted a tx to the inbox /// @param l2Address L2 address as viewed in msg.sender /// @return l1Address the address in the L1 that triggered the tx to L2 function undoL1ToL2Alias(address l2Address) internal pure returns (address l1Address) { unchecked { l1Address = address(uint160(l2Address) - offset); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.15; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { SafeCall } from "../libraries/SafeCall.sol"; import { Hashing } from "../libraries/Hashing.sol"; import { Encoding } from "../libraries/Encoding.sol"; import { Constants } from "../libraries/Constants.sol"; /** * @custom:legacy * @title CrossDomainMessengerLegacySpacer0 * @notice Contract only exists to add a spacer to the CrossDomainMessenger where the * libAddressManager variable used to exist. Must be the first contract in the inheritance * tree of the CrossDomainMessenger. */ contract CrossDomainMessengerLegacySpacer0 { /** * @custom:legacy * @custom:spacer libAddressManager * @notice Spacer for backwards compatibility. */ address private spacer_0_0_20; } /** * @custom:legacy * @title CrossDomainMessengerLegacySpacer1 * @notice Contract only exists to add a spacer to the CrossDomainMessenger where the * PausableUpgradable and OwnableUpgradeable variables used to exist. Must be * the third contract in the inheritance tree of the CrossDomainMessenger. */ contract CrossDomainMessengerLegacySpacer1 { /** * @custom:legacy * @custom:spacer __gap * @notice Spacer for backwards compatibility. Comes from OpenZeppelin * ContextUpgradable via OwnableUpgradeable. * */ uint256[50] private spacer_1_0_1600; /** * @custom:legacy * @custom:spacer _owner * @notice Spacer for backwards compatibility. * Come from OpenZeppelin OwnableUpgradeable. */ address private spacer_51_0_20; /** * @custom:legacy * @custom:spacer __gap * @notice Spacer for backwards compatibility. Comes from OpenZeppelin * ContextUpgradable via PausableUpgradable. */ uint256[49] private spacer_52_0_1568; /** * @custom:legacy * @custom:spacer _paused * @notice Spacer for backwards compatibility. Comes from OpenZeppelin * PausableUpgradable. */ bool private spacer_101_0_1; /** * @custom:legacy * @custom:spacer __gap * @notice Spacer for backwards compatibility. Comes from OpenZeppelin * PausableUpgradable. */ uint256[49] private spacer_102_0_1568; /** * @custom:legacy * @custom:spacer ReentrancyGuardUpgradeable's `_status` field. * @notice Spacer for backwards compatibility */ uint256 private spacer_151_0_32; /** * @custom:spacer ReentrancyGuardUpgradeable * @notice Spacer for backwards compatibility */ uint256[49] private __gap_reentrancy_guard; /** * @custom:legacy * @custom:spacer blockedMessages * @notice Spacer for backwards compatibility. */ mapping(bytes32 => bool) private spacer_201_0_32; /** * @custom:legacy * @custom:spacer relayedMessages * @notice Spacer for backwards compatibility. */ mapping(bytes32 => bool) private spacer_202_0_32; } /** * @custom:upgradeable * @title CrossDomainMessenger * @notice CrossDomainMessenger is a base contract that provides the core logic for the L1 and L2 * cross-chain messenger contracts. It's designed to be a universal interface that only * needs to be extended slightly to provide low-level message passing functionality on each * chain it's deployed on. Currently only designed for message passing between two paired * chains and does not support one-to-many interactions. * * Any changes to this contract MUST result in a semver bump for contracts that inherit it. */ abstract contract CrossDomainMessenger is CrossDomainMessengerLegacySpacer0, Initializable, CrossDomainMessengerLegacySpacer1 { /** * @notice Current message version identifier. */ uint16 public constant MESSAGE_VERSION = 1; /** * @notice Constant overhead added to the base gas for a message. */ uint64 public constant MIN_GAS_CONSTANT_OVERHEAD = 200_000; /** * @notice Numerator for dynamic overhead added to the base gas for a message. */ uint64 public constant MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR = 1016; /** * @notice Denominator for dynamic overhead added to the base gas for a message. */ uint64 public constant MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR = 1000; /** * @notice Extra gas added to base gas for each byte of calldata in a message. */ uint64 public constant MIN_GAS_CALLDATA_OVERHEAD = 16; /** * @notice Address of the paired CrossDomainMessenger contract on the other chain. */ address public immutable OTHER_MESSENGER; /** * @notice Mapping of message hashes to boolean receipt values. Note that a message will only * be present in this mapping if it has successfully been relayed on this chain, and * can therefore not be relayed again. */ mapping(bytes32 => bool) public successfulMessages; /** * @notice Address of the sender of the currently executing message on the other chain. If the * value of this variable is the default value (0x00000000...dead) then no message is * currently being executed. Use the xDomainMessageSender getter which will throw an * error if this is the case. */ address internal xDomainMsgSender; /** * @notice Nonce for the next message to be sent, without the message version applied. Use the * messageNonce getter which will insert the message version into the nonce to give you * the actual nonce to be used for the message. */ uint240 internal msgNonce; /** * @notice Mapping of message hashes to a boolean if and only if the message has failed to be * executed at least once. A message will not be present in this mapping if it * successfully executed on the first attempt. */ mapping(bytes32 => bool) public failedMessages; /** * @notice A mapping of hashes to reentrancy locks. */ mapping(bytes32 => bool) internal reentrancyLocks; /** * @notice Reserve extra slots in the storage layout for future upgrades. * A gap size of 41 was chosen here, so that the first slot used in a child contract * would be a multiple of 50. */ uint256[41] private __gap; /** * @notice Emitted whenever a message is sent to the other chain. * * @param target Address of the recipient of the message. * @param sender Address of the sender of the message. * @param message Message to trigger the recipient address with. * @param messageNonce Unique nonce attached to the message. * @param gasLimit Minimum gas limit that the message can be executed with. */ event SentMessage( address indexed target, address sender, bytes message, uint256 messageNonce, uint256 gasLimit ); /** * @notice Additional event data to emit, required as of Bedrock. Cannot be merged with the * SentMessage event without breaking the ABI of this contract, this is good enough. * * @param sender Address of the sender of the message. * @param value ETH value sent along with the message to the recipient. */ event SentMessageExtension1(address indexed sender, uint256 value); /** * @notice Emitted whenever a message is successfully relayed on this chain. * * @param msgHash Hash of the message that was relayed. */ event RelayedMessage(bytes32 indexed msgHash); /** * @notice Emitted whenever a message fails to be relayed on this chain. * * @param msgHash Hash of the message that failed to be relayed. */ event FailedRelayedMessage(bytes32 indexed msgHash); /** * @param _otherMessenger Address of the messenger on the paired chain. */ constructor(address _otherMessenger) { OTHER_MESSENGER = _otherMessenger; } /** * @notice Sends a message to some target address on the other chain. Note that if the call * always reverts, then the message will be unrelayable, and any ETH sent will be * permanently locked. The same will occur if the target on the other chain is * considered unsafe (see the _isUnsafeTarget() function). * * @param _target Target contract or wallet address. * @param _message Message to trigger the target address with. * @param _minGasLimit Minimum gas limit that the message can be executed with. */ function sendMessage( address _target, bytes calldata _message, uint32 _minGasLimit ) external payable { // Triggers a message to the other messenger. Note that the amount of gas provided to the // message is the amount of gas requested by the user PLUS the base gas value. We want to // guarantee the property that the call to the target contract will always have at least // the minimum gas limit specified by the user. _sendMessage( OTHER_MESSENGER, baseGas(_message, _minGasLimit), msg.value, abi.encodeWithSelector( this.relayMessage.selector, messageNonce(), msg.sender, _target, msg.value, _minGasLimit, _message ) ); emit SentMessage(_target, msg.sender, _message, messageNonce(), _minGasLimit); emit SentMessageExtension1(msg.sender, msg.value); unchecked { ++msgNonce; } } /** * @notice Relays a message that was sent by the other CrossDomainMessenger contract. Can only * be executed via cross-chain call from the other messenger OR if the message was * already received once and is currently being replayed. * * @param _nonce Nonce of the message being relayed. * @param _sender Address of the user who sent the message. * @param _target Address that the message is targeted at. * @param _value ETH value to send with the message. * @param _minGasLimit Minimum amount of gas that the message can be executed with. * @param _message Message to send to the target. */ function relayMessage( uint256 _nonce, address _sender, address _target, uint256 _value, uint256 _minGasLimit, bytes calldata _message ) external payable { (, uint16 version) = Encoding.decodeVersionedNonce(_nonce); require( version < 2, "CrossDomainMessenger: only version 0 or 1 messages are supported at this time" ); // If the message is version 0, then it's a migrated legacy withdrawal. We therefore need // to check that the legacy version of the message has not already been relayed. if (version == 0) { bytes32 oldHash = Hashing.hashCrossDomainMessageV0(_target, _sender, _message, _nonce); require( successfulMessages[oldHash] == false, "CrossDomainMessenger: legacy withdrawal already relayed" ); } // We use the v1 message hash as the unique identifier for the message because it commits // to the value and minimum gas limit of the message. bytes32 versionedHash = Hashing.hashCrossDomainMessageV1( _nonce, _sender, _target, _value, _minGasLimit, _message ); // Check if the reentrancy lock for the `versionedHash` is already set. if (reentrancyLocks[versionedHash]) { revert("ReentrancyGuard: reentrant call"); } // Trigger the reentrancy lock for `versionedHash` reentrancyLocks[versionedHash] = true; if (_isOtherMessenger()) { // These properties should always hold when the message is first submitted (as // opposed to being replayed). assert(msg.value == _value); assert(!failedMessages[versionedHash]); } else { require( msg.value == 0, "CrossDomainMessenger: value must be zero unless message is from a system address" ); require( failedMessages[versionedHash], "CrossDomainMessenger: message cannot be replayed" ); } require( _isUnsafeTarget(_target) == false, "CrossDomainMessenger: cannot send message to blocked system address" ); require( successfulMessages[versionedHash] == false, "CrossDomainMessenger: message has already been relayed" ); xDomainMsgSender = _sender; bool success = SafeCall.callWithMinGas(_target, _minGasLimit, _value, _message); xDomainMsgSender = Constants.DEFAULT_L2_SENDER; if (success) { successfulMessages[versionedHash] = true; emit RelayedMessage(versionedHash); } else { failedMessages[versionedHash] = true; emit FailedRelayedMessage(versionedHash); // Revert in this case if the transaction was triggered by the estimation address. This // should only be possible during gas estimation or we have bigger problems. Reverting // here will make the behavior of gas estimation change such that the gas limit // computed will be the amount required to relay the message, even if that amount is // greater than the minimum gas limit specified by the user. if (tx.origin == Constants.ESTIMATION_ADDRESS) { revert("CrossDomainMessenger: failed to relay message"); } } // Clear the reentrancy lock for `versionedHash` reentrancyLocks[versionedHash] = false; } /** * @notice Retrieves the address of the contract or wallet that initiated the currently * executing message on the other chain. Will throw an error if there is no message * currently being executed. Allows the recipient of a call to see who triggered it. * * @return Address of the sender of the currently executing message on the other chain. */ function xDomainMessageSender() external view returns (address) { require( xDomainMsgSender != Constants.DEFAULT_L2_SENDER, "CrossDomainMessenger: xDomainMessageSender is not set" ); return xDomainMsgSender; } /** * @notice Retrieves the next message nonce. Message version will be added to the upper two * bytes of the message nonce. Message version allows us to treat messages as having * different structures. * * @return Nonce of the next message to be sent, with added message version. */ function messageNonce() public view returns (uint256) { return Encoding.encodeVersionedNonce(msgNonce, MESSAGE_VERSION); } /** * @notice Computes the amount of gas required to guarantee that a given message will be * received on the other chain without running out of gas. Guaranteeing that a message * will not run out of gas is important because this ensures that a message can always * be replayed on the other chain if it fails to execute completely. * * @param _message Message to compute the amount of required gas for. * @param _minGasLimit Minimum desired gas limit when message goes to target. * * @return Amount of gas required to guarantee message receipt. */ function baseGas(bytes calldata _message, uint32 _minGasLimit) public pure returns (uint64) { // We peform the following math on uint64s to avoid overflow errors. Multiplying the // by MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR would otherwise limit the _minGasLimit to // type(uint32).max / MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR ~= 4.2m. return // Dynamic overhead ((uint64(_minGasLimit) * MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR) / MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR) + // Calldata overhead (uint64(_message.length) * MIN_GAS_CALLDATA_OVERHEAD) + // Constant overhead MIN_GAS_CONSTANT_OVERHEAD; } /** * @notice Intializer. */ // solhint-disable-next-line func-name-mixedcase function __CrossDomainMessenger_init() internal onlyInitializing { xDomainMsgSender = Constants.DEFAULT_L2_SENDER; } /** * @notice Sends a low-level message to the other messenger. Needs to be implemented by child * contracts because the logic for this depends on the network where the messenger is * being deployed. * * @param _to Recipient of the message on the other chain. * @param _gasLimit Minimum gas limit the message can be executed with. * @param _value Amount of ETH to send with the message. * @param _data Message data. */ function _sendMessage( address _to, uint64 _gasLimit, uint256 _value, bytes memory _data ) internal virtual; /** * @notice Checks whether the message is coming from the other messenger. Implemented by child * contracts because the logic for this depends on the network where the messenger is * being deployed. * * @return Whether the message is coming from the other messenger. */ function _isOtherMessenger() internal view virtual returns (bool); /** * @notice Checks whether a given call target is a system address that could cause the * messenger to peform an unsafe action. This is NOT a mechanism for blocking user * addresses. This is ONLY used to prevent the execution of messages to specific * system addresses that could cause security issues, e.g., having the * CrossDomainMessenger send messages to itself. * * @param _target Address of the contract to check. * * @return Whether or not the address is an unsafe system address. */ function _isUnsafeTarget(address _target) internal view virtual returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; /** * @title Semver * @notice Semver is a simple contract for managing contract versions. */ contract Semver { /** * @notice Contract version number (major). */ uint256 private immutable MAJOR_VERSION; /** * @notice Contract version number (minor). */ uint256 private immutable MINOR_VERSION; /** * @notice Contract version number (patch). */ uint256 private immutable PATCH_VERSION; /** * @param _major Version number (major). * @param _minor Version number (minor). * @param _patch Version number (patch). */ constructor( uint256 _major, uint256 _minor, uint256 _patch ) { MAJOR_VERSION = _major; MINOR_VERSION = _minor; PATCH_VERSION = _patch; } /** * @notice Returns the full semver contract version. * * @return Semver contract version as a string. */ function version() public view returns (string memory) { return string( abi.encodePacked( Strings.toString(MAJOR_VERSION), ".", Strings.toString(MINOR_VERSION), ".", Strings.toString(PATCH_VERSION) ) ); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.15; import { Types } from "../libraries/Types.sol"; import { Hashing } from "../libraries/Hashing.sol"; import { Encoding } from "../libraries/Encoding.sol"; import { Burn } from "../libraries/Burn.sol"; import { Semver } from "../universal/Semver.sol"; /** * @custom:proxied * @custom:predeploy 0x4200000000000000000000000000000000000016 * @title L2ToL1MessagePasser * @notice The L2ToL1MessagePasser is a dedicated contract where messages that are being sent from * L2 to L1 can be stored. The storage root of this contract is pulled up to the top level * of the L2 output to reduce the cost of proving the existence of sent messages. */ contract L2ToL1MessagePasser is Semver { /** * @notice The L1 gas limit set when eth is withdrawn using the receive() function. */ uint256 internal constant RECEIVE_DEFAULT_GAS_LIMIT = 100_000; /** * @notice Current message version identifier. */ uint16 public constant MESSAGE_VERSION = 1; /** * @notice Includes the message hashes for all withdrawals */ mapping(bytes32 => bool) public sentMessages; /** * @notice A unique value hashed with each withdrawal. */ uint240 internal msgNonce; /** * @notice Emitted any time a withdrawal is initiated. * * @param nonce Unique value corresponding to each withdrawal. * @param sender The L2 account address which initiated the withdrawal. * @param target The L1 account address the call will be send to. * @param value The ETH value submitted for withdrawal, to be forwarded to the target. * @param gasLimit The minimum amount of gas that must be provided when withdrawing. * @param data The data to be forwarded to the target on L1. * @param withdrawalHash The hash of the withdrawal. */ event MessagePassed( uint256 indexed nonce, address indexed sender, address indexed target, uint256 value, uint256 gasLimit, bytes data, bytes32 withdrawalHash ); /** * @notice Emitted when the balance of this contract is burned. * * @param amount Amount of ETh that was burned. */ event WithdrawerBalanceBurnt(uint256 indexed amount); /** * @custom:semver 1.0.0 */ constructor() Semver(1, 0, 0) {} /** * @notice Allows users to withdraw ETH by sending directly to this contract. */ receive() external payable { initiateWithdrawal(msg.sender, RECEIVE_DEFAULT_GAS_LIMIT, bytes("")); } /** * @notice Removes all ETH held by this contract from the state. Used to prevent the amount of * ETH on L2 inflating when ETH is withdrawn. Currently only way to do this is to * create a contract and self-destruct it to itself. Anyone can call this function. Not * incentivized since this function is very cheap. */ function burn() external { uint256 balance = address(this).balance; Burn.eth(balance); emit WithdrawerBalanceBurnt(balance); } /** * @notice Sends a message from L2 to L1. * * @param _target Address to call on L1 execution. * @param _gasLimit Minimum gas limit for executing the message on L1. * @param _data Data to forward to L1 target. */ function initiateWithdrawal( address _target, uint256 _gasLimit, bytes memory _data ) public payable { bytes32 withdrawalHash = Hashing.hashWithdrawal( Types.WithdrawalTransaction({ nonce: messageNonce(), sender: msg.sender, target: _target, value: msg.value, gasLimit: _gasLimit, data: _data }) ); sentMessages[withdrawalHash] = true; emit MessagePassed( messageNonce(), msg.sender, _target, msg.value, _gasLimit, _data, withdrawalHash ); unchecked { ++msgNonce; } } /** * @notice Retrieves the next message nonce. Message version will be added to the upper two * bytes of the message nonce. Message version allows us to treat messages as having * different structures. * * @return Nonce of the next message to be sent, with added message version. */ function messageNonce() public view returns (uint256) { return Encoding.encodeVersionedNonce(msgNonce, MESSAGE_VERSION); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @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] * ``` * 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 Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _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 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _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() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.15; /** * @title SafeCall * @notice Perform low level safe calls */ library SafeCall { /** * @notice Perform a low level call without copying any returndata * * @param _target Address to call * @param _gas Amount of gas to pass to the call * @param _value Amount of value to pass to the call * @param _calldata Calldata to pass to the call */ function call( address _target, uint256 _gas, uint256 _value, bytes memory _calldata ) internal returns (bool) { bool _success; assembly { _success := call( _gas, // gas _target, // recipient _value, // ether value add(_calldata, 32), // inloc mload(_calldata), // inlen 0, // outloc 0 // outlen ) } return _success; } /** * @notice Perform a low level call without copying any returndata. This function * will revert if the call cannot be performed with the specified minimum * gas. * * @param _target Address to call * @param _minGas The minimum amount of gas that may be passed to the call * @param _value Amount of value to pass to the call * @param _calldata Calldata to pass to the call */ function callWithMinGas( address _target, uint256 _minGas, uint256 _value, bytes memory _calldata ) internal returns (bool) { bool _success; assembly { // Assertion: gasleft() >= ((_minGas + 200) * 64) / 63 // // Because EIP-150 ensures that, a maximum of 63/64ths of the remaining gas in the call // frame may be passed to a subcontext, we need to ensure that the gas will not be // truncated to hold this function's invariant: "If a call is performed by // `callWithMinGas`, it must receive at least the specified minimum gas limit." In // addition, exactly 51 gas is consumed between the below `GAS` opcode and the `CALL` // opcode, so it is factored in with some extra room for error. if lt(gas(), div(mul(64, add(_minGas, 200)), 63)) { // Store the "Error(string)" selector in scratch space. mstore(0, 0x08c379a0) // Store the pointer to the string length in scratch space. mstore(32, 32) // Store the string. // // SAFETY: // - We pad the beginning of the string with two zero bytes as well as the // length (24) to ensure that we override the free memory pointer at offset // 0x40. This is necessary because the free memory pointer is likely to // be greater than 1 byte when this function is called, but it is incredibly // unlikely that it will be greater than 3 bytes. As for the data within // 0x60, it is ensured that it is 0 due to 0x60 being the zero offset. // - It's fine to clobber the free memory pointer, we're reverting. mstore(88, 0x0000185361666543616c6c3a204e6f7420656e6f75676820676173) // Revert with 'Error("SafeCall: Not enough gas")' revert(28, 100) } // The call will be supplied at least (((_minGas + 200) * 64) / 63) - 49 gas due to the // above assertion. This ensures that, in all circumstances, the call will // receive at least the minimum amount of gas specified. // We can prove this property by solving the inequalities: // ((((_minGas + 200) * 64) / 63) - 49) >= _minGas // ((((_minGas + 200) * 64) / 63) - 51) * (63 / 64) >= _minGas // Both inequalities hold true for all possible values of `_minGas`. _success := call( gas(), // gas _target, // recipient _value, // ether value add(_calldata, 32), // inloc mload(_calldata), // inlen 0x00, // outloc 0x00 // outlen ) } return _success; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { Types } from "./Types.sol"; import { Encoding } from "./Encoding.sol"; /** * @title Hashing * @notice Hashing handles Optimism's various different hashing schemes. */ library Hashing { /** * @notice Computes the hash of the RLP encoded L2 transaction that would be generated when a * given deposit is sent to the L2 system. Useful for searching for a deposit in the L2 * system. * * @param _tx User deposit transaction to hash. * * @return Hash of the RLP encoded L2 deposit transaction. */ function hashDepositTransaction(Types.UserDepositTransaction memory _tx) internal pure returns (bytes32) { return keccak256(Encoding.encodeDepositTransaction(_tx)); } /** * @notice Computes the deposit transaction's "source hash", a value that guarantees the hash * of the L2 transaction that corresponds to a deposit is unique and is * deterministically generated from L1 transaction data. * * @param _l1BlockHash Hash of the L1 block where the deposit was included. * @param _logIndex The index of the log that created the deposit transaction. * * @return Hash of the deposit transaction's "source hash". */ function hashDepositSource(bytes32 _l1BlockHash, uint256 _logIndex) internal pure returns (bytes32) { bytes32 depositId = keccak256(abi.encode(_l1BlockHash, _logIndex)); return keccak256(abi.encode(bytes32(0), depositId)); } /** * @notice Hashes the cross domain message based on the version that is encoded into the * message nonce. * * @param _nonce Message nonce with version encoded into the first two bytes. * @param _sender Address of the sender of the message. * @param _target Address of the target of the message. * @param _value ETH value to send to the target. * @param _gasLimit Gas limit to use for the message. * @param _data Data to send with the message. * * @return Hashed cross domain message. */ function hashCrossDomainMessage( uint256 _nonce, address _sender, address _target, uint256 _value, uint256 _gasLimit, bytes memory _data ) internal pure returns (bytes32) { (, uint16 version) = Encoding.decodeVersionedNonce(_nonce); if (version == 0) { return hashCrossDomainMessageV0(_target, _sender, _data, _nonce); } else if (version == 1) { return hashCrossDomainMessageV1(_nonce, _sender, _target, _value, _gasLimit, _data); } else { revert("Hashing: unknown cross domain message version"); } } /** * @notice Hashes a cross domain message based on the V0 (legacy) encoding. * * @param _target Address of the target of the message. * @param _sender Address of the sender of the message. * @param _data Data to send with the message. * @param _nonce Message nonce. * * @return Hashed cross domain message. */ function hashCrossDomainMessageV0( address _target, address _sender, bytes memory _data, uint256 _nonce ) internal pure returns (bytes32) { return keccak256(Encoding.encodeCrossDomainMessageV0(_target, _sender, _data, _nonce)); } /** * @notice Hashes a cross domain message based on the V1 (current) encoding. * * @param _nonce Message nonce. * @param _sender Address of the sender of the message. * @param _target Address of the target of the message. * @param _value ETH value to send to the target. * @param _gasLimit Gas limit to use for the message. * @param _data Data to send with the message. * * @return Hashed cross domain message. */ function hashCrossDomainMessageV1( uint256 _nonce, address _sender, address _target, uint256 _value, uint256 _gasLimit, bytes memory _data ) internal pure returns (bytes32) { return keccak256( Encoding.encodeCrossDomainMessageV1( _nonce, _sender, _target, _value, _gasLimit, _data ) ); } /** * @notice Derives the withdrawal hash according to the encoding in the L2 Withdrawer contract * * @param _tx Withdrawal transaction to hash. * * @return Hashed withdrawal transaction. */ function hashWithdrawal(Types.WithdrawalTransaction memory _tx) internal pure returns (bytes32) { return keccak256( abi.encode(_tx.nonce, _tx.sender, _tx.target, _tx.value, _tx.gasLimit, _tx.data) ); } /** * @notice Hashes the various elements of an output root proof into an output root hash which * can be used to check if the proof is valid. * * @param _outputRootProof Output root proof which should hash to an output root. * * @return Hashed output root proof. */ function hashOutputRootProof(Types.OutputRootProof memory _outputRootProof) internal pure returns (bytes32) { return keccak256( abi.encode( _outputRootProof.version, _outputRootProof.stateRoot, _outputRootProof.messagePasserStorageRoot, _outputRootProof.latestBlockhash ) ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { Types } from "./Types.sol"; import { Hashing } from "./Hashing.sol"; import { RLPWriter } from "./rlp/RLPWriter.sol"; /** * @title Encoding * @notice Encoding handles Optimism's various different encoding schemes. */ library Encoding { /** * @notice RLP encodes the L2 transaction that would be generated when a given deposit is sent * to the L2 system. Useful for searching for a deposit in the L2 system. The * transaction is prefixed with 0x7e to identify its EIP-2718 type. * * @param _tx User deposit transaction to encode. * * @return RLP encoded L2 deposit transaction. */ function encodeDepositTransaction(Types.UserDepositTransaction memory _tx) internal pure returns (bytes memory) { bytes32 source = Hashing.hashDepositSource(_tx.l1BlockHash, _tx.logIndex); bytes[] memory raw = new bytes[](8); raw[0] = RLPWriter.writeBytes(abi.encodePacked(source)); raw[1] = RLPWriter.writeAddress(_tx.from); raw[2] = _tx.isCreation ? RLPWriter.writeBytes("") : RLPWriter.writeAddress(_tx.to); raw[3] = RLPWriter.writeUint(_tx.mint); raw[4] = RLPWriter.writeUint(_tx.value); raw[5] = RLPWriter.writeUint(uint256(_tx.gasLimit)); raw[6] = RLPWriter.writeBool(false); raw[7] = RLPWriter.writeBytes(_tx.data); return abi.encodePacked(uint8(0x7e), RLPWriter.writeList(raw)); } /** * @notice Encodes the cross domain message based on the version that is encoded into the * message nonce. * * @param _nonce Message nonce with version encoded into the first two bytes. * @param _sender Address of the sender of the message. * @param _target Address of the target of the message. * @param _value ETH value to send to the target. * @param _gasLimit Gas limit to use for the message. * @param _data Data to send with the message. * * @return Encoded cross domain message. */ function encodeCrossDomainMessage( uint256 _nonce, address _sender, address _target, uint256 _value, uint256 _gasLimit, bytes memory _data ) internal pure returns (bytes memory) { (, uint16 version) = decodeVersionedNonce(_nonce); if (version == 0) { return encodeCrossDomainMessageV0(_target, _sender, _data, _nonce); } else if (version == 1) { return encodeCrossDomainMessageV1(_nonce, _sender, _target, _value, _gasLimit, _data); } else { revert("Encoding: unknown cross domain message version"); } } /** * @notice Encodes a cross domain message based on the V0 (legacy) encoding. * * @param _target Address of the target of the message. * @param _sender Address of the sender of the message. * @param _data Data to send with the message. * @param _nonce Message nonce. * * @return Encoded cross domain message. */ function encodeCrossDomainMessageV0( address _target, address _sender, bytes memory _data, uint256 _nonce ) internal pure returns (bytes memory) { return abi.encodeWithSignature( "relayMessage(address,address,bytes,uint256)", _target, _sender, _data, _nonce ); } /** * @notice Encodes a cross domain message based on the V1 (current) encoding. * * @param _nonce Message nonce. * @param _sender Address of the sender of the message. * @param _target Address of the target of the message. * @param _value ETH value to send to the target. * @param _gasLimit Gas limit to use for the message. * @param _data Data to send with the message. * * @return Encoded cross domain message. */ function encodeCrossDomainMessageV1( uint256 _nonce, address _sender, address _target, uint256 _value, uint256 _gasLimit, bytes memory _data ) internal pure returns (bytes memory) { return abi.encodeWithSignature( "relayMessage(uint256,address,address,uint256,uint256,bytes)", _nonce, _sender, _target, _value, _gasLimit, _data ); } /** * @notice Adds a version number into the first two bytes of a message nonce. * * @param _nonce Message nonce to encode into. * @param _version Version number to encode into the message nonce. * * @return Message nonce with version encoded into the first two bytes. */ function encodeVersionedNonce(uint240 _nonce, uint16 _version) internal pure returns (uint256) { uint256 nonce; assembly { nonce := or(shl(240, _version), _nonce) } return nonce; } /** * @notice Pulls the version out of a version-encoded nonce. * * @param _nonce Message nonce with version encoded into the first two bytes. * * @return Nonce without encoded version. * @return Version of the message. */ function decodeVersionedNonce(uint256 _nonce) internal pure returns (uint240, uint16) { uint240 nonce; uint16 version; assembly { nonce := and(_nonce, 0x0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) version := shr(240, _nonce) } return (nonce, version); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { ResourceMetering } from "../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 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, minimumBaseFee: 1 gwei, systemTxMaxGas: 1_000_000, maximumBaseFee: type(uint128).max }); return config; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// 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.15; /** * @title Burn * @notice Utilities for burning stuff. */ library Burn { /** * Burns a given amount of ETH. * * @param _amount Amount of ETH to burn. */ function eth(uint256 _amount) internal { new Burner{ value: _amount }(); } /** * 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 // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @custom:attribution https://github.com/bakaoh/solidity-rlp-encode * @title RLPWriter * @author RLPWriter is a library for encoding Solidity types to RLP bytes. Adapted from Bakaoh's * RLPEncode library (https://github.com/bakaoh/solidity-rlp-encode) with minor * modifications to improve legibility. */ library RLPWriter { /** * @notice RLP encodes a byte string. * * @param _in The byte string to encode. * * @return The RLP encoded string in bytes. */ function writeBytes(bytes memory _in) internal pure returns (bytes memory) { bytes memory encoded; if (_in.length == 1 && uint8(_in[0]) < 128) { encoded = _in; } else { encoded = abi.encodePacked(_writeLength(_in.length, 128), _in); } return encoded; } /** * @notice RLP encodes a list of RLP encoded byte byte strings. * * @param _in The list of RLP encoded byte strings. * * @return The RLP encoded list of items in bytes. */ function writeList(bytes[] memory _in) internal pure returns (bytes memory) { bytes memory list = _flatten(_in); return abi.encodePacked(_writeLength(list.length, 192), list); } /** * @notice RLP encodes a string. * * @param _in The string to encode. * * @return The RLP encoded string in bytes. */ function writeString(string memory _in) internal pure returns (bytes memory) { return writeBytes(bytes(_in)); } /** * @notice RLP encodes an address. * * @param _in The address to encode. * * @return The RLP encoded address in bytes. */ function writeAddress(address _in) internal pure returns (bytes memory) { return writeBytes(abi.encodePacked(_in)); } /** * @notice RLP encodes a uint. * * @param _in The uint256 to encode. * * @return The RLP encoded uint256 in bytes. */ function writeUint(uint256 _in) internal pure returns (bytes memory) { return writeBytes(_toBinary(_in)); } /** * @notice RLP encodes a bool. * * @param _in The bool to encode. * * @return The RLP encoded bool in bytes. */ function writeBool(bool _in) internal pure returns (bytes memory) { bytes memory encoded = new bytes(1); encoded[0] = (_in ? bytes1(0x01) : bytes1(0x80)); return encoded; } /** * @notice Encode the first byte and then the `len` in binary form if `length` is more than 55. * * @param _len The length of the string or the payload. * @param _offset 128 if item is string, 192 if item is list. * * @return RLP encoded bytes. */ function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory) { bytes memory encoded; if (_len < 56) { encoded = new bytes(1); encoded[0] = bytes1(uint8(_len) + uint8(_offset)); } else { uint256 lenLen; uint256 i = 1; while (_len / i != 0) { lenLen++; i *= 256; } encoded = new bytes(lenLen + 1); encoded[0] = bytes1(uint8(lenLen) + uint8(_offset) + 55); for (i = 1; i <= lenLen; i++) { encoded[i] = bytes1(uint8((_len / (256**(lenLen - i))) % 256)); } } return encoded; } /** * @notice Encode integer in big endian binary form with no leading zeroes. * * @param _x The integer to encode. * * @return RLP encoded bytes. */ function _toBinary(uint256 _x) private pure returns (bytes memory) { bytes memory b = abi.encodePacked(_x); uint256 i = 0; for (; i < 32; i++) { if (b[i] != 0) { break; } } bytes memory res = new bytes(32 - i); for (uint256 j = 0; j < res.length; j++) { res[j] = b[i++]; } return res; } /** * @custom:attribution https://github.com/Arachnid/solidity-stringutils * @notice Copies a piece of memory to another location. * * @param _dest Destination location. * @param _src Source location. * @param _len Length of memory to copy. */ function _memcpy( uint256 _dest, uint256 _src, uint256 _len ) private pure { uint256 dest = _dest; uint256 src = _src; uint256 len = _len; for (; len >= 32; len -= 32) { assembly { mstore(dest, mload(src)) } dest += 32; src += 32; } uint256 mask; unchecked { mask = 256**(32 - len) - 1; } assembly { let srcpart := and(mload(src), not(mask)) let destpart := and(mload(dest), mask) mstore(dest, or(destpart, srcpart)) } } /** * @custom:attribution https://github.com/sammayo/solidity-rlp-encoder * @notice Flattens a list of byte strings into one byte string. * * @param _list List of byte strings to flatten. * * @return The flattened byte string. */ function _flatten(bytes[] memory _list) private pure returns (bytes memory) { if (_list.length == 0) { return new bytes(0); } uint256 len; uint256 i = 0; for (; i < _list.length; i++) { len += _list[i].length; } bytes memory flattened = new bytes(len); uint256 flattenedPtr; assembly { flattenedPtr := add(flattened, 0x20) } for (i = 0; i < _list.length; i++) { bytes memory item = _list[i]; uint256 listPtr; assembly { listPtr := add(item, 0x20) } _memcpy(flattenedPtr, listPtr, item.length); flattenedPtr += _list[i].length; } return flattened; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.15; import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; import { Burn } from "../libraries/Burn.sol"; import { Arithmetic } from "../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 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. */ struct ResourceParams { uint128 prevBaseFee; uint64 prevBoughtGas; uint64 prevBlockNum; } /** * @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 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; 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; /** * @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. int256 gasUsedDelta = int256(uint256(params.prevBoughtGas)) - 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.prevBlockNum = uint64(block.number); } // Make sure we can actually buy the resource amount requested by the user. params.prevBoughtGas += _amount; require( int256(uint256(params.prevBoughtGas)) <= int256(uint256(config.maxResourceLimit)), "ResourceMetering: cannot buy more gas than available gas limit" ); // 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) { Burn.gas(gasCost - usedGas); } } /** * @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 { params = ResourceParams({ prevBaseFee: 1 gwei, prevBoughtGas: 0, prevBlockNum: uint64(block.number) }); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/Address.sol"; /** * @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] * ``` * 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 Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _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 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _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() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Internal function that returns the initialized version. Returns `_initialized` */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Internal function that returns the initialized version. Returns `_initializing` */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.15; 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 v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: 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))) } } function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) { assembly { // z will equal 0 if y is 0, unlike in Solidity where it will revert. z := mod(x, y) } } function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 z) { assembly { // z will equal 0 if y is 0, unlike in Solidity where it will revert. z := div(x, y) } } /// @dev Will return 0 instead of reverting if y is zero. function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) { assembly { // Add 1 to x * y if x % y > 0. z := add(gt(mod(x, y), 0), div(x, y)) } } }
{ "remappings": [ "@prb/test/=lib/prb-test/src/", "forge-std/=lib/forge-std/src/", "src/=src/", "solmate/=lib/solmate/", "@rari-capital/solmate/=lib/solmate/", "@eth-optimism/contracts/=node_modules/@eth-optimism/contracts/", "@eth-optimism/contracts-bedrock/=node_modules/@eth-optimism/contracts-bedrock/", "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/", "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "fx-portal/contracts/=lib/contracts/contracts/", "ds-test/=lib/forge-std/lib/ds-test/src/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "prb-test/=lib/prb-test/src/", "semaphore-v3/=lib/semaphore-v3/" ], "optimizer": { "enabled": true, "runs": 10000, "details": { "peephole": true, "inliner": true, "deduplicate": true, "cse": true, "yul": true } }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"uint8","name":"_treeDepth","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CannotOverwriteRoot","type":"error"},{"inputs":[],"name":"ExpiredRoot","type":"error"},{"inputs":[],"name":"NoRootsSeen","type":"error"},{"inputs":[],"name":"NonExistentRoot","type":"error"},{"inputs":[{"internalType":"uint8","name":"depth","type":"uint8"}],"name":"UnsupportedTreeDepth","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"},{"indexed":false,"internalType":"bool","name":"isLocal","type":"bool"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"root","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"timestamp","type":"uint128"}],"name":"RootAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newExpiry","type":"uint256"}],"name":"RootHistoryExpirySet","type":"event"},{"inputs":[],"name":"getTreeDepth","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isLocal","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestRoot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newRoot","type":"uint256"}],"name":"receiveRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rootHistory","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rootHistoryExpiry","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"expiryTime","type":"uint256"}],"name":"setRootHistoryExpiry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"bool","name":"_isLocal","type":"bool"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"root","type":"uint256"},{"internalType":"uint256","name":"signalHash","type":"uint256"},{"internalType":"uint256","name":"nullifierHash","type":"uint256"},{"internalType":"uint256","name":"externalNullifierHash","type":"uint256"},{"internalType":"uint256[8]","name":"proof","type":"uint256[8]"}],"name":"verifyProof","outputs":[],"stateMutability":"view","type":"function"}]
Contract Creation Code
60a060405262093a806000556040516100179061015e565b604051809103906000f080158015610033573d6000803e3d6000fd5b50600380546001600160a01b03929092166001600160a01b03199092169190911790556004805460ff60a01b1916600160a01b17905534801561007557600080fd5b5060405162002926380380620029268339810160408190526100969161016c565b806100aa816100e560201b6105aa1760201c565b6100d057604051630220cee360e61b815260ff8216600482015260240160405180910390fd5b60ff166080526100df3361010c565b50610196565b60006010602060ff8416821180159061010457508060ff168460ff1611155b949350505050565b600480546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b611ade8062000e4883390190565b60006020828403121561017e57600080fd5b815160ff8116811461018f57600080fd5b9392505050565b608051610c96620001b2600039600061015f0152610c966000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c8063b242e53411610081578063f1c621ee1161005b578063f1c621ee146101c9578063f2fde38b1461021c578063fbde929b1461022f57600080fd5b8063b242e5341461019b578063c70aa727146101ae578063d7b0fef1146101c157600080fd5b80638da5cb5b116100b25780638da5cb5b146101305780638e5cdd5014610158578063b0d690791461018957600080fd5b80630ee04629146100d9578063354ca12014610113578063715018a614610128575b600080fd5b6004546100fe9074010000000000000000000000000000000000000000900460ff1681565b60405190151581526020015b60405180910390f35b610126610121366004610afe565b610242565b005b6101266102f9565b60045460405173ffffffffffffffffffffffffffffffffffffffff909116815260200161010a565b60405160ff7f000000000000000000000000000000000000000000000000000000000000000016815260200161010a565b6000545b60405190815260200161010a565b6101266101a9366004610b73565b61030d565b6101266101bc366004610bb1565b61048c565b61018d6104a0565b6101fb6101d7366004610bb1565b6002602052600090815260409020546fffffffffffffffffffffffffffffffff1681565b6040516fffffffffffffffffffffffffffffffff909116815260200161010a565b61012661022a366004610bca565b6104e5565b61012661023d366004610bb1565b610599565b61024b856105d1565b60035460408051608081018252878152602081018690528082018790526060810185905290517f2357251100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909216916323572511916102c291859190600401610bee565b60006040518083038186803b1580156102da57600080fd5b505afa1580156102ee573d6000803e3d6000fd5b505050505050505050565b610301610693565b61030b6000610964565b565b610315610693565b73ffffffffffffffffffffffffffffffffffffffff82166103bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f43726f7373446f6d61696e4f776e61626c65333a206e6577206f776e6572206960448201527f7320746865207a65726f2061646472657373000000000000000000000000000060648201526084015b60405180910390fd5b60006103de60045473ffffffffffffffffffffffffffffffffffffffff1690565b90506103e983610964565b6004805483151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff90911617905560405173ffffffffffffffffffffffffffffffffffffffff80851691908316907f7fdc2a4b6eb39ec3363d710d188620bd1e97b3c434161f187b4d0dc0544faa589061047f90861515815260200190565b60405180910390a3505050565b610494610693565b61049d816109db565b50565b60006001546000036104de576040517f5b8dabb700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060015490565b6104ed610693565b73ffffffffffffffffffffffffffffffffffffffff8116610590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016103b4565b61049d81610964565b6105a1610693565b61049d81610a16565b60006010602060ff841682118015906105c957508060ff168460ff1611155b949350505050565b60015481036105dd5750565b6000818152600260205260408120546fffffffffffffffffffffffffffffffff1690819003610638576040517fddae3b7100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000546106576fffffffffffffffffffffffffffffffff831642610c2e565b111561068f576040517f3ae7359e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b60045474010000000000000000000000000000000000000000900460ff161561077957336106d660045473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff161461030b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f43726f7373446f6d61696e4f776e61626c65333a2063616c6c6572206973206e60448201527f6f7420746865206f776e6572000000000000000000000000000000000000000060648201526084016103b4565b73420000000000000000000000000000000000000733811461081d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f43726f7373446f6d61696e4f776e61626c65333a2063616c6c6572206973206e60448201527f6f7420746865206d657373656e6765720000000000000000000000000000000060648201526084016103b4565b8073ffffffffffffffffffffffffffffffffffffffff16636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610868573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061088c9190610c6c565b73ffffffffffffffffffffffffffffffffffffffff166108c160045473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff161461049d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f43726f7373446f6d61696e4f776e61626c65333a2063616c6c6572206973206e60448201527f6f7420746865206f776e6572000000000000000000000000000000000000000060648201526084016103b4565b6004805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60008190556040518181527f147b815b6a3a8dd5d49310410e089f6b5e9f3782e944772edc938c8bb48ef1219060200160405180910390a150565b6000818152600260205260409020546fffffffffffffffffffffffffffffffff168015610a6f576040517f6650c4d100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600182905560008281526002602090815260409182902080547fffffffffffffffffffffffffffffffff0000000000000000000000000000000016426fffffffffffffffffffffffffffffffff8116918217909255835186815292830152917fe97c89cbb137505b36f55ebfc9732fd6c4c73ff43d49db239fc25f6e7a534145910160405180910390a1505050565b6000806000806000610180808789031215610b1857600080fd5b86359550602087013594506040870135935060608701359250878188011115610b4057600080fd5b506080860190509295509295909350565b73ffffffffffffffffffffffffffffffffffffffff8116811461049d57600080fd5b60008060408385031215610b8657600080fd5b8235610b9181610b51565b915060208301358015158114610ba657600080fd5b809150509250929050565b600060208284031215610bc357600080fd5b5035919050565b600060208284031215610bdc57600080fd5b8135610be781610b51565b9392505050565b610180810161010080858437600090830181815284915b6004811015610c24578251825260209283019290910190600101610c05565b5050509392505050565b600082821015610c67577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500390565b600060208284031215610c7e57600080fd5b8151610be781610b5156fea164736f6c634300080f000a608060405234801561001057600080fd5b50611abe806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063235725111461004657806344f636921461005b578063f2457c8d14610084575b600080fd5b61005961005436600461198b565b610097565b005b61006e6100693660046119c2565b61032f565b60405161007b91906119e6565b60405180910390f35b610059610092366004611a17565b61038c565b6000806100a3836106c2565b9150915060006040516101008682377f168e4fddac50a40d5bcff39c7fa9207cd368444c0c01a86690a6645b52f3aa1f6101008201527f2139a256456825daa623957c4f2ea1a0d26f135769e450759142a7159b0a44766101208201527f07859424108de88bfbe5c80a19c0e80ba35fda4383d3fd125305dd04b4c08fe46101408201527f142ad7a93ca0c554a9f0303059e5a24e85400004a730598bd423b0090f4b3d4a6101608201527f2d4d9aa7e302d9df41749d5507949d05dbea33fbb16c643b22f599a2be6df2e26101808201527f14bedd503c37ceb061d8ec60209fe345ce89830a19230301f076caff004d19266101a08201527f0967032fcbf776d1afc985f88877f182d38480a653f2decaa9794cbc3bf3060c6101c08201527f0e187847ad4c798374d0d6732bf501847dd68bc0e071241e0213bc7fc13db7ab6101e08201527e1752a100a72fdf1e5a5d6ea841cc20ec838bccfcf7bd559e79f1c9c759b6a06102008201527f192a8cc13cd9f762871f21e43451c6ca9eeab2cb2987c4e366a185c25dac2e7f61022082015283610240820152826102608201527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c26102808201527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed6102a08201527f275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec6102c08201527f1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d6102e08201526020816103008360085afa905116905080610328576040517f7fcdd1f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b61033761190d565b61034a82358360015b60200201356109c8565b81526103686060830135604084013560a08501356080860135610b67565b6020830152604082015261038260c0830135836007610340565b6060820152919050565b60008061039f84825b6020020135611041565b909250905060008080806103bb604089013560208a0135611165565b929650909450925090506000806103d38a6003610395565b915091506000806103e38b6106c2565b915091506103ef61192b565b8a8152602081018a905260408101889052606081018990526080810186905260a0810187905260c0810185905260e081018490527f168e4fddac50a40d5bcff39c7fa9207cd368444c0c01a86690a6645b52f3aa1f6101008201527f2139a256456825daa623957c4f2ea1a0d26f135769e450759142a7159b0a44766101208201527f07859424108de88bfbe5c80a19c0e80ba35fda4383d3fd125305dd04b4c08fe46101408201527f142ad7a93ca0c554a9f0303059e5a24e85400004a730598bd423b0090f4b3d4a6101608201527f2d4d9aa7e302d9df41749d5507949d05dbea33fbb16c643b22f599a2be6df2e26101808201527f14bedd503c37ceb061d8ec60209fe345ce89830a19230301f076caff004d19266101a08201527f0967032fcbf776d1afc985f88877f182d38480a653f2decaa9794cbc3bf3060c6101c08201527f0e187847ad4c798374d0d6732bf501847dd68bc0e071241e0213bc7fc13db7ab6101e08201527e1752a100a72fdf1e5a5d6ea841cc20ec838bccfcf7bd559e79f1c9c759b6a06102008201527f192a8cc13cd9f762871f21e43451c6ca9eeab2cb2987c4e366a185c25dac2e7f610220820152610240810183905261026081018290527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c26102808201527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed6102a08201527f275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec6102c08201527f1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d6102e0820152600061065e61194a565b6020816103008560085afa915081158061067a57508051600114155b156106b1576040517f7fcdd1f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050505050565b6000806000600190506040516040810160007f0335f514c2acb9b255aae85514122267cd7d16e374c6231a2c34417d3449125483527f07fa1580c1cc3ed4f6d660c6f60f86afedd8a12fb90b2e8ed4f7e310c88b97f760208401527f20b781dd0db3b7980a4b3814128c86e597e1442d0fc9eb7f932a5229494d6b7982527f17d1cef436eb2f665670c7b34854e62c227043a7b111a539c0295518bbab3ca96020830152863590508060408301527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181108416935060408260608460075afa8416935060408360808560065afa841693507f260945445b4205f874ab7e203a18240e51c9d3c896ea300d40132b1c2f50299a82527f11087a8b76b0f957e1c482c909302916795f811a06866059e403689c01c903fb6020830152602087013590508060408301527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181108416935060408260608460075afa8416935060408360808560065afa841693507f11d20fd81c0e5cf48ba1469ccb8ac99dcdc7cf746a6e70762a939d63dcc52dbf82527f2d447c5f134eff527d7bcaace88b3842c42b800d8dc049e0a6e72f5efc14293d6020830152604087013590508060408301527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181108416935060408260608460075afa8416935060408360808560065afa841693507f107cd54a1606a6a873bed4c1b76af48975e66dcf6c127b4c799ad4fdd230b87c82527f1a51b81f6c07725ebcc56ebb1c482b99340eaa9bcb86cc09aed6f58a28e530b66020830152606087013590508060408301527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018110841693505060408160608360075afa831692505060408160808360065afa815160209092015191945090925016806109c2576040517fa54f8e2700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50915091565b60007f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4783101580610a1957507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478210155b15610a50576040517f7fcdd1f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82158015610a5c575081155b15610a6957506000610b61565b6000610ade7f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47877f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47898a0909086114b0565b9050808303610af3575050600182901b610b61565b7f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478082068103068303610b2d575050600182811b17610b61565b6040517f7fcdd1f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b92915050565b6000807f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4786101580610bb957507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478510155b80610be457507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478410155b80610c0f57507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478310155b15610c46576040517f7fcdd1f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82848688171717600003610c5f57506000905080611038565b600080807f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610caf60037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47611a73565b7f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478a8c0909905060007f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478a7f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478c8d0909905060007f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478a7f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478c8d090990507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47807f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478c860984087f2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5089450610e707f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47807f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478e870984087f2fcd3ac2a640a154eb23960892a85a68f031ca0c8344b23a577dcf1052b9e775087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd479081900681030690565b9350505050600080610ef77f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4780610ea957610ea9611a44565b7f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478586097f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47878809086114b0565b9050610f687f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd477f183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea47f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478488080961153f565b15915050610f7783838361159b565b90935091508683148015610f8a57508186145b15610fb45780610f9b576000610f9e565b60025b60ff1660028a901b176000179450879350611034565b7f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478084068103068714801561100e57507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4780830681030686145b15610b2d578061101f576000611022565b60025b60ff1660028a901b1760011794508793505b5050505b94509492505050565b6000808260000361105757506000928392509050565b600183811c9250808416147f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4783106110bb576040517f7fcdd1f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61112e7f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47867f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4788890909086114b0565b915080156109c2577f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47808306810306915050915091565b600080808085158015611176575084155b1561118c575060009250829150819050806114a7565b600286811c945085935060018088161490808816147f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47861015806111f057507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478510155b15611227576040517f7fcdd1f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4761127560037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47611a73565b7f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47888a0909905060007f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47887f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478a8b0909905060007f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47887f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478a8b090990507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47807f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478a860984087f2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e50896506114367f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47807f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478c870984087f2fcd3ac2a640a154eb23960892a85a68f031ca0c8344b23a577dcf1052b9e775087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd479081900681030690565b955061144387878661159b565b909750955084156114a1577f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4780880681030696507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4780870681030695505b50505050505b92959194509250565b60006114dc827f0c19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f526117f2565b9050817f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478283091461153a576040517f7fcdd1f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919050565b60008061156c837f0c19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f526117f2565b9050827f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309149392505050565b600080806115f17f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47808788097f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47898a09086114b0565b90508315611622577f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47908190068103065b6116917f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd477f183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea47f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848a08096114b0565b92507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476116e17f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760028609611882565b860991507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476117587f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478485097f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd479081900681030690565b7f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4785860908861415806117b257507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47808385096002098514155b156117e9576040517f7fcdd1f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50935093915050565b60008060405160208152602080820152602060408201528460608201528360808201527f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760a082015260208160c08360055afa90519250905080610b5f576040517f7fcdd1f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006118ae827f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd456117f2565b90507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4781830960011461153a576040517f7fcdd1f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180608001604052806004906020820280368337509192915050565b6040518061030001604052806018906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b806101008101831015610b6157600080fd5b8060808101831015610b6157600080fd5b600080610180838503121561199f57600080fd5b6119a98484611968565b91506119b984610100850161197a565b90509250929050565b600061010082840312156119d557600080fd5b6119df8383611968565b9392505050565b60808101818360005b6004811015611a0e5781518352602092830192909101906001016119ef565b50505092915050565b6000806101008385031215611a2b57600080fd5b611a35848461197a565b91506119b9846080850161197a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082821015611aac577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b50039056fea164736f6c634300080f000a000000000000000000000000000000000000000000000000000000000000001e
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100d45760003560e01c8063b242e53411610081578063f1c621ee1161005b578063f1c621ee146101c9578063f2fde38b1461021c578063fbde929b1461022f57600080fd5b8063b242e5341461019b578063c70aa727146101ae578063d7b0fef1146101c157600080fd5b80638da5cb5b116100b25780638da5cb5b146101305780638e5cdd5014610158578063b0d690791461018957600080fd5b80630ee04629146100d9578063354ca12014610113578063715018a614610128575b600080fd5b6004546100fe9074010000000000000000000000000000000000000000900460ff1681565b60405190151581526020015b60405180910390f35b610126610121366004610afe565b610242565b005b6101266102f9565b60045460405173ffffffffffffffffffffffffffffffffffffffff909116815260200161010a565b60405160ff7f000000000000000000000000000000000000000000000000000000000000001e16815260200161010a565b6000545b60405190815260200161010a565b6101266101a9366004610b73565b61030d565b6101266101bc366004610bb1565b61048c565b61018d6104a0565b6101fb6101d7366004610bb1565b6002602052600090815260409020546fffffffffffffffffffffffffffffffff1681565b6040516fffffffffffffffffffffffffffffffff909116815260200161010a565b61012661022a366004610bca565b6104e5565b61012661023d366004610bb1565b610599565b61024b856105d1565b60035460408051608081018252878152602081018690528082018790526060810185905290517f2357251100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909216916323572511916102c291859190600401610bee565b60006040518083038186803b1580156102da57600080fd5b505afa1580156102ee573d6000803e3d6000fd5b505050505050505050565b610301610693565b61030b6000610964565b565b610315610693565b73ffffffffffffffffffffffffffffffffffffffff82166103bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f43726f7373446f6d61696e4f776e61626c65333a206e6577206f776e6572206960448201527f7320746865207a65726f2061646472657373000000000000000000000000000060648201526084015b60405180910390fd5b60006103de60045473ffffffffffffffffffffffffffffffffffffffff1690565b90506103e983610964565b6004805483151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff90911617905560405173ffffffffffffffffffffffffffffffffffffffff80851691908316907f7fdc2a4b6eb39ec3363d710d188620bd1e97b3c434161f187b4d0dc0544faa589061047f90861515815260200190565b60405180910390a3505050565b610494610693565b61049d816109db565b50565b60006001546000036104de576040517f5b8dabb700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060015490565b6104ed610693565b73ffffffffffffffffffffffffffffffffffffffff8116610590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016103b4565b61049d81610964565b6105a1610693565b61049d81610a16565b60006010602060ff841682118015906105c957508060ff168460ff1611155b949350505050565b60015481036105dd5750565b6000818152600260205260408120546fffffffffffffffffffffffffffffffff1690819003610638576040517fddae3b7100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000546106576fffffffffffffffffffffffffffffffff831642610c2e565b111561068f576040517f3ae7359e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b60045474010000000000000000000000000000000000000000900460ff161561077957336106d660045473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff161461030b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f43726f7373446f6d61696e4f776e61626c65333a2063616c6c6572206973206e60448201527f6f7420746865206f776e6572000000000000000000000000000000000000000060648201526084016103b4565b73420000000000000000000000000000000000000733811461081d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f43726f7373446f6d61696e4f776e61626c65333a2063616c6c6572206973206e60448201527f6f7420746865206d657373656e6765720000000000000000000000000000000060648201526084016103b4565b8073ffffffffffffffffffffffffffffffffffffffff16636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610868573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061088c9190610c6c565b73ffffffffffffffffffffffffffffffffffffffff166108c160045473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff161461049d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f43726f7373446f6d61696e4f776e61626c65333a2063616c6c6572206973206e60448201527f6f7420746865206f776e6572000000000000000000000000000000000000000060648201526084016103b4565b6004805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60008190556040518181527f147b815b6a3a8dd5d49310410e089f6b5e9f3782e944772edc938c8bb48ef1219060200160405180910390a150565b6000818152600260205260409020546fffffffffffffffffffffffffffffffff168015610a6f576040517f6650c4d100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600182905560008281526002602090815260409182902080547fffffffffffffffffffffffffffffffff0000000000000000000000000000000016426fffffffffffffffffffffffffffffffff8116918217909255835186815292830152917fe97c89cbb137505b36f55ebfc9732fd6c4c73ff43d49db239fc25f6e7a534145910160405180910390a1505050565b6000806000806000610180808789031215610b1857600080fd5b86359550602087013594506040870135935060608701359250878188011115610b4057600080fd5b506080860190509295509295909350565b73ffffffffffffffffffffffffffffffffffffffff8116811461049d57600080fd5b60008060408385031215610b8657600080fd5b8235610b9181610b51565b915060208301358015158114610ba657600080fd5b809150509250929050565b600060208284031215610bc357600080fd5b5035919050565b600060208284031215610bdc57600080fd5b8135610be781610b51565b9392505050565b610180810161010080858437600090830181815284915b6004811015610c24578251825260209283019290910190600101610c05565b5050509392505050565b600082821015610c67577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500390565b600060208284031215610c7e57600080fd5b8151610be781610b5156fea164736f6c634300080f000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000000000000000000000000000001e
-----Decoded View---------------
Arg [0] : _treeDepth (uint8): 30
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000000000000000000000000000000000000000001e
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.