Forkchoice Ethereum Mainnet

Address Contract Verified

Address 0x59888ea06a54bdC7d495c24513ed5b7A58ed7804
Balance 0 ETH
Nonce 1
Code Size 7389 bytes
Indexed Transactions 0 (1 on-chain, 0.8% indexed)
External Etherscan · Sourcify

Contract Bytecode

7389 bytes
0x608060405234801561001057600080fd5b50600436106100415760003560e01c80632418833f1461015d5780632b7ac3f314610178578063c4d66de8146101c3575b6004361161007b576040517f0f601ef500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061008a366004818461173b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509394506100cc92508491506101d89050565b6000546040517f1e5de2ab00000000000000000000000000000000000000000000000000000000815291925062010000900473ffffffffffffffffffffffffffffffffffffffff1690631e5de2ab906101299084906004016119bd565b60006040518083038186803b15801561014157600080fd5b505afa158015610155573d6000803e3d6000fd5b505050505050005b610165600481565b6040519081526020015b60405180910390f35b60005461019e9062010000900473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161016f565b6101d66101d1366004611b92565b6102ab565b005b6101e061159c565b600061021b6102168460408051808201825260008082526020918201528151808301909252825182529182019181019190915290565b610480565b50905061023b604051806040016040528060008152602001600081525090565b61024482610528565b9250905061025181610572565b835261025c82610528565b92509050610269816105f1565b602084015261027782610528565b925090506102848161067f565b604084015261029282610528565b50905061029e8161078e565b6060840152509092915050565b600054610100900460ff16158080156102cb5750600054600160ff909116105b806102e55750303b1580156102e5575060005460ff166001145b610376576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156103d457600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff851602179055801561047c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b60008061048c83610921565b6104f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f524c505265616465723a206974656d206973206e6f742061206c697374000000604482015260640161036d565b6104ff836020015161095a565b836020015161050e9190611bf7565b8351602085015191935061052191611bf7565b9050915091565b6040805180820190915260008082526020820152600080610548846109dc565b60408051808201909152818152602081018690529350905061056a8185611bf7565b915050915091565b6040805180820190915260008082526020820152600061059183610480565b5090506105b1604051806040016040528060008152602001600081525090565b6105ba82610528565b925090506105c781610a83565b83526105d282610528565b5090506105de81610c0d565b63ffffffff166020840152509092915050565b6105f96115e0565b600061060483610480565b509050610624604051806040016040528060008152602001600081525090565b61062d82610528565b9250905061063a81610c1e565b835261064582610528565b9250905061065281610c0d565b63ffffffff16602084015261066682610528565b5090506106728161078e565b6040840152509092915050565b610687611607565b600061069283610480565b5090506106b2604051806040016040528060008152602001600081525090565b6106bb82610528565b925090506106c881610c95565b83526106d382610528565b925090506106e081610e2a565b60208401526106ee82610528565b925090506106fb81610e2a565b604084015261070982610528565b9250905061071681610f20565b606084015261072482610528565b925090506107318161103c565b608084015261073f82610528565b9250905061074c81610c95565b60a084015261075a82610528565b9250905061076781610c95565b60c084015261077582610528565b509050610781816110b5565b60e0840152509092915050565b80516060906107f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f524c505265616465723a206974656d20686173206e6f20646174610000000000604482015260640161036d565b602082015182518151600090811a60808110600181146108a35760b88210600181146108985760c083106001811461086c5760f8841060018114610861577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0a85019550610866565b600195505b50610892565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a840194505b5061089d565b600193505b506108a8565b600092505b506108b590508183611c0f565b915060008267ffffffffffffffff8111156108d2576108d2611c26565b6040519080825280601f01601f1916602001820160405280156108fc576020820181803683370190505b509050602081016109176109108487611bf7565b8286611232565b5095945050505050565b805160009061093257506000919050565b6020820151805160001a9060c0821015610950575060009392505050565b5060019392505050565b8051600090811a60808110156109735750600092915050565b60b881108061098e575060c0811080159061098e575060f881105b1561099c5750600192915050565b60c08110156109d0576109b1600160b8611c55565b6109be9060ff1682611c0f565b6109c9906001611bf7565b9392505050565b6109b1600160f8611c55565b80516000908190811a60808110156109f75760019150610a7c565b60b8811015610a1d57610a0b608082611c0f565b610a16906001611bf7565b9150610a7c565b60c0811015610a495760b781036001850194508451816020036008021c60018201810193505050610a7c565b60f8811015610a5d57610a0b60c082611c0f565b60f781036001850194508451816020036008021c600182018101935050505b5092915050565b8051600090610aee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f524c505265616465723a206974656d20686173206e6f20646174610000000000604482015260640161036d565b602082015182518151600090811a906080821060018114610b995760b8831060018114610b8e5760c0841060018114610b625760f8851060018114610b57577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0a86019450610b5c565b600194505b50610b88565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a850193505b50610b93565b600192505b50610b9e565b600091505b509283019290910390506020811115610bed576308c379a06000526020600452601a6024527f524c505265616465723a2062797465733332206f766572666c6f77000000000060445260646000fd5b815192506020811015610c065782816020036008021c92505b5050919050565b6000610c18826112c1565b92915050565b610c2661166d565b6000610c3183610480565b509050610c51604051806040016040528060008152602001600081525090565b610c5a82610528565b92509050610c6781611459565b8352610c7282610528565b92509050610c7f8161078e565b6020840152610c8d82610528565b509050610672815b6060610ca082610921565b610d06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f524c505265616465723a206974656d206973206e6f742061206c697374000000604482015260640161036d565b6000610d15836020015161095a565b8360200151610d249190611bf7565b9050600083600001518460200151610d3c9190611bf7565b90506000825b82811015610d5f57610d53816109dc565b60019092019101610d42565b8167ffffffffffffffff811115610d7857610d78611c26565b604051908082528060200260200182016040528015610da1578160200160208202803683370190505b50945083905060005b82811015610e20576000610dbd836109dc565b90506000610dca8461095a565b84810151909150818303906020821015610de857602082900360031b1c5b808a8681518110610dfb57610dfb611c78565b63ffffffff909216602092830291909101909101525050509190910190600101610daa565b5050505050919050565b6060600080610e3884610480565b90925090506000825b82811015610e5e57610e52816109dc565b60019092019101610e41565b8167ffffffffffffffff811115610e7757610e77611c26565b604051908082528060200260200182016040528015610ebc57816020015b6040805180820190915260008082526020820152815260200190600190039081610e955790505b50945060005b82811015610e20576000610ed5866109dc565b6040805180820190915281815260208101889052909150610ef58161103c565b888481518110610f0757610f07611c78565b6020908102919091010152509490940193600101610ec2565b610f28611694565b6000610f3383610480565b509050610f53604051806040016040528060008152602001600081525090565b610f5c82610528565b925090506000610f6b82610480565b509050610f8b604051806040016040528060008152602001600081525090565b610f9482610528565b92509050610fa1816112c1565b855152610fad82610528565b509050610fb9816112c1565b85516020015250610fcb905082610528565b5090506000610fd982610480565b509050610ff9604051806040016040528060008152602001600081525090565b61100282610528565b9250905061100f816112c1565b60208601515261101e82610528565b50905061102a816112c1565b60208681015101525092949350505050565b6040805180820190915260008082526020820152600061105b83610480565b50905061107b604051806040016040528060008152602001600081525090565b61108482610528565b92509050611091816112c1565b835261109c82610528565b5090506110a8816112c1565b6020840152509092915050565b60606110c082610921565b611126576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f524c505265616465723a206974656d206973206e6f742061206c697374000000604482015260640161036d565b6000611135836020015161095a565b83602001516111449190611bf7565b905060008360000151846020015161115c9190611bf7565b90506000825b8281101561117f57611173816109dc565b60019092019101611162565b8167ffffffffffffffff81111561119857611198611c26565b6040519080825280602002602001820160405280156111cb57816020015b60608152602001906001900390816111b65790505b50945083905060005b82811015610e205760006111e7836109dc565b604080518082019091528181526020810185905290915061120781610c95565b88848151811061121957611219611c78565b60209081029190910101525091909101906001016111d4565b8061123c57505050565b5b6020811061127a5782518252602092830192909101907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00161123d565b80156112bc5782518251600160208490036008021b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161782525b505050565b8051600090158015906112d657508151602110155b61133c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f524c505265616465723a20696e76616c69642075696e74323536000000000000604482015260640161036d565b602082015182518151600090811a8160808210600181146113e75760b88310600181146113dc5760c08410600181146113b05760f88510600181146113a5577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0a860194506113aa565b600194505b506113d6565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a850193505b506113e1565b600192505b506113ec565b600091505b50938401939092039150602082111561143b576308c379a06000526020600452601b6024527f524c505265616465723a2075696e74323536206f766572666c6f77000000000060445260646000fd5b50815160208210156114515760086020839003021c5b949350505050565b6114616116b9565b600061146c83610480565b50905061148c604051806040016040528060008152602001600081525090565b61149582610528565b925090506114a281610c0d565b61ffff1683526114b182610528565b925090506114be8161078e565b60208401526114cc82610528565b925090506114d9816114f3565b60408401526114e782610528565b50905061029e81610a83565b6114fb6116e6565b600061150683610480565b509050611526604051806040016040528060008152602001600081525090565b61152f82610528565b9250905061153c8161103c565b835261154782610528565b9250905061155481610f20565b602084015261156282610528565b9250905061156f81610f20565b604084015261157d82610528565b50905061158981610c0d565b63ffffffff166060840152509092915050565b6040805160c0810190915260006080820181815260a08301919091528152602081016115c66115e0565b81526020016115d3611607565b8152602001606081525090565b60405180606001604052806115f361166d565b815260006020820152606060409091015290565b604051806101000160405280606081526020016060815260200160608152602001611630611694565b8152602001611652604051806040016040528060008152602001600081525090565b81526020016060815260200160608152602001606081525090565b60405180606001604052806116806116b9565b815260200160608152602001606081525090565b60405180604001604052806116a761171d565b81526020016116b461171d565b905290565b6040805160808101825260008152606060208201529081016116d96116e6565b8152600060209091015290565b6040805160c0810190915260006080820181815260a0830191909152815260208101611710611694565b81526020016116d9611694565b60405180604001604052806002906020820280368337509192915050565b6000808585111561174b57600080fd5b8386111561175857600080fd5b5050820193919092039150565b6000815180845260005b8181101561178b5760208185018101518683018201520161176f565b8181111561179d576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8060005b60028110156117f35781518452602093840193909101906001016117d4565b50505050565b6118048282516117d0565b60208101516112bc60408401826117d0565b600081518084526020808501945080840160005b8381101561184c57815163ffffffff168752958201959082019060010161182a565b509495945050505050565b600081518084526020808501945080840160005b8381101561184c5761188887835180518252602090810151910152565b604096909601959082019060010161186b565b600081518084526020808501808196508360051b8101915082860160005b858110156118e35782840389526118d1848351611816565b988501989350908401906001016118b9565b5091979650505050505050565b6000610180825181855261190682860182611816565b915050602083015184820360208601526119208282611857565b9150506040830151848203604086015261193a8282611857565b915050606083015161194f60608601826117f9565b506080830151805160e08601526020015161010085015260a083015184820361012086015261197e8282611816565b91505060c08301518482036101408601526119998282611816565b91505060e08301518482036101608601526119b4828261189b565b95945050505050565b600060208083528351805182850152818101519050604063ffffffff80831682870152838701519250606060a08188015283518160c08901528051826101208a015261ffff8151166101808a0152868101516101c0806101a08c0152611a276103408c0183611765565b915086830151611a44828d01825180518252602090810151910152565b898101519150611a586102008d01836117f9565b878101519150611a6c6102808d01836117f9565b8501519095166103008b0152908301516103208a0152818701518982037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee09081016101408c015290945090611ac18186611765565b928601518a84039092016101608b015250909250611adf8382611816565b9585015163ffffffff811660e08a0152959250611af99050565b8284015194507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4087830301610100880152611b348286611765565b94508288015193507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0925082878603016080880152611b7385856118f0565b94508088015193505050808584030160a0860152506119b48282611765565b600060208284031215611ba457600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146109c957600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611c0a57611c0a611bc8565b500190565b600082821015611c2157611c21611bc8565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060ff821660ff841680821015611c6f57611c6f611bc8565b90039392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea264697066735822122075d2b7165e0b15a21e6a02b722890210414488714ef1b78f0a35d137d074851064736f6c634300080c0033

Verified Source Code Full Match

Compiler: v0.8.12+commit.f00d7308 EVM: london Optimization: Yes (1000000 runs)
Initializable.sol 138 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (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. Equivalent to `reinitializer(1)`.
     */
    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.
     *
     * `initializer` is equivalent to `reinitializer(1)`, so 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.
     *
     * 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.
     */
    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.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized < type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }
}
AddressUpgradeable.sol 195 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.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 functionCall(target, data, "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");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(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) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason 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 {
            // 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);
            }
        }
    }
}
BN254.sol 350 lines
// SPDX-License-Identifier: MIT
// several functions are taken or adapted from https://github.com/HarryR/solcrypto/blob/master/contracts/altbn128.sol (MIT license):
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

// The remainder of the code in this library is written by LayrLabs Inc. and is also under an MIT license

pragma solidity ^0.8.12;

/**
 * @title Library for operations on the BN254 elliptic curve.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 * @notice Contains BN254 parameters, common operations (addition, scalar mul, pairing), and BLS signature functionality.
 */
library BN254 {
    // modulus for the underlying field F_p of the elliptic curve
    uint256 internal constant FP_MODULUS =
        21888242871839275222246405745257275088696311157297823662689037894645226208583;
    // modulus for the underlying field F_r of the elliptic curve
    uint256 internal constant FR_MODULUS =
        21888242871839275222246405745257275088548364400416034343698204186575808495617;

    struct G1Point {
        uint256 X;
        uint256 Y;
    }

    // Encoding of field elements is: X[1] * i + X[0]
    struct G2Point {
        uint256[2] X;
        uint256[2] Y;
    }

    function generatorG1() internal pure returns (G1Point memory) {
        return G1Point(1, 2);
    }

    // generator of group G2
    /// @dev Generator point in F_q2 is of the form: (x0 + ix1, y0 + iy1).
    uint256 internal constant G2x1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634;
    uint256 internal constant G2x0 = 10857046999023057135944570762232829481370756359578518086990519993285655852781;
    uint256 internal constant G2y1 = 4082367875863433681332203403145435568316851327593401208105741076214120093531;
    uint256 internal constant G2y0 = 8495653923123431417604973247489272438418190587263600148770280649306958101930;

    /// @notice returns the G2 generator
    /// @dev mind the ordering of the 1s and 0s!
    ///      this is because of the (unknown to us) convention used in the bn254 pairing precompile contract
    ///      "Elements a * i + b of F_p^2 are encoded as two elements of F_p, (a, b)."
    ///      https://github.com/ethereum/EIPs/blob/master/EIPS/eip-197.md#encoding
    function generatorG2() internal pure returns (G2Point memory) {
        return G2Point([G2x1, G2x0], [G2y1, G2y0]);
    }

    // negation of the generator of group G2
    /// @dev Generator point in F_q2 is of the form: (x0 + ix1, y0 + iy1).
    uint256 internal constant nG2x1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634;
    uint256 internal constant nG2x0 = 10857046999023057135944570762232829481370756359578518086990519993285655852781;
    uint256 internal constant nG2y1 = 17805874995975841540914202342111839520379459829704422454583296818431106115052;
    uint256 internal constant nG2y0 = 13392588948715843804641432497768002650278120570034223513918757245338268106653;

    function negGeneratorG2() internal pure returns (G2Point memory) {
        return G2Point([nG2x1, nG2x0], [nG2y1, nG2y0]);
    }

    bytes32 internal constant powersOfTauMerkleRoot =
        0x22c998e49752bbb1918ba87d6d59dd0e83620a311ba91dd4b2cc84990b31b56f;

    /**
     * @param p Some point in G1.
     * @return The negation of `p`, i.e. p.plus(p.negate()) should be zero.
     */
    function negate(G1Point memory p) internal pure returns (G1Point memory) {
        // The prime q in the base field F_q for G1
        if (p.X == 0 && p.Y == 0) {
            return G1Point(0, 0);
        } else {
            return G1Point(p.X, FP_MODULUS - (p.Y % FP_MODULUS));
        }
    }

    /**
     * @return r the sum of two points of G1
     */
    function plus(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
        uint256[4] memory input;
        input[0] = p1.X;
        input[1] = p1.Y;
        input[2] = p2.X;
        input[3] = p2.Y;
        bool success;

        // solium-disable-next-line security/no-inline-assembly
        assembly {
            success := staticcall(sub(gas(), 2000), 6, input, 0x80, r, 0x40)
            // Use "invalid" to make gas estimation work
            switch success
            case 0 {
                invalid()
            }
        }

        require(success, "ec-add-failed");
    }

    /**
     * @notice an optimized ecMul implementation that takes O(log_2(s)) ecAdds
     * @param p the point to multiply
     * @param s the scalar to multiply by
     * @dev this function is only safe to use if the scalar is 9 bits or less
     */ 
    function scalar_mul_tiny(BN254.G1Point memory p, uint16 s) internal view returns (BN254.G1Point memory) {
        require(s < 2**9, "scalar-too-large");

        // if s is 1 return p
        if(s == 1) {
            return p;
        }

        // the accumulated product to return
        BN254.G1Point memory acc = BN254.G1Point(0, 0);
        // the 2^n*p to add to the accumulated product in each iteration
        BN254.G1Point memory p2n = p;
        // value of most significant bit
        uint16 m = 1;
        // index of most significant bit
        uint8 i = 0;

        //loop until we reach the most significant bit
        while(s >= m){
            unchecked {
                // if the  current bit is 1, add the 2^n*p to the accumulated product
                if ((s >> i) & 1 == 1) {
                    acc = plus(acc, p2n);
                }
                // double the 2^n*p for the next iteration
                p2n = plus(p2n, p2n);

                // increment the index and double the value of the most significant bit
                m <<= 1;
                ++i;
            }
        }
        
        // return the accumulated product
        return acc;
    }

    /**
     * @return r the product of a point on G1 and a scalar, i.e.
     *         p == p.scalar_mul(1) and p.plus(p) == p.scalar_mul(2) for all
     *         points p.
     */
    function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
        uint256[3] memory input;
        input[0] = p.X;
        input[1] = p.Y;
        input[2] = s;
        bool success;
        // solium-disable-next-line security/no-inline-assembly
        assembly {
            success := staticcall(sub(gas(), 2000), 7, input, 0x60, r, 0x40)
            // Use "invalid" to make gas estimation work
            switch success
            case 0 {
                invalid()
            }
        }
        require(success, "ec-mul-failed");
    }

    /**
     *  @return The result of computing the pairing check
     *         e(p1[0], p2[0]) *  .... * e(p1[n], p2[n]) == 1
     *         For example,
     *         pairing([P1(), P1().negate()], [P2(), P2()]) should return true.
     */
    function pairing(
        G1Point memory a1,
        G2Point memory a2,
        G1Point memory b1,
        G2Point memory b2
    ) internal view returns (bool) {
        G1Point[2] memory p1 = [a1, b1];
        G2Point[2] memory p2 = [a2, b2];

        uint256[12] memory input;

        for (uint256 i = 0; i < 2; i++) {
            uint256 j = i * 6;
            input[j + 0] = p1[i].X;
            input[j + 1] = p1[i].Y;
            input[j + 2] = p2[i].X[0];
            input[j + 3] = p2[i].X[1];
            input[j + 4] = p2[i].Y[0];
            input[j + 5] = p2[i].Y[1];
        }

        uint256[1] memory out;
        bool success;

        // solium-disable-next-line security/no-inline-assembly
        assembly {
            success := staticcall(sub(gas(), 2000), 8, input, mul(12, 0x20), out, 0x20)
            // Use "invalid" to make gas estimation work
            switch success
            case 0 {
                invalid()
            }
        }

        require(success, "pairing-opcode-failed");

        return out[0] != 0;
    }

    /**
     * @notice This function is functionally the same as pairing(), however it specifies a gas limit
     *         the user can set, as a precompile may use the entire gas budget if it reverts.
     */
    function safePairing(
        G1Point memory a1,
        G2Point memory a2,
        G1Point memory b1,
        G2Point memory b2,
        uint256 pairingGas
    ) internal view returns (bool, bool) {
        G1Point[2] memory p1 = [a1, b1];
        G2Point[2] memory p2 = [a2, b2];

        uint256[12] memory input;

        for (uint256 i = 0; i < 2; i++) {
            uint256 j = i * 6;
            input[j + 0] = p1[i].X;
            input[j + 1] = p1[i].Y;
            input[j + 2] = p2[i].X[0];
            input[j + 3] = p2[i].X[1];
            input[j + 4] = p2[i].Y[0];
            input[j + 5] = p2[i].Y[1];
        }

        uint256[1] memory out;
        bool success;

        // solium-disable-next-line security/no-inline-assembly
        assembly {
            success := staticcall(pairingGas, 8, input, mul(12, 0x20), out, 0x20)
        }

        //Out is the output of the pairing precompile, either 0 or 1 based on whether the two pairings are equal.
        //Success is true if the precompile actually goes through (aka all inputs are valid)

        return (success, out[0] != 0);
    }

    /// @return hashedG1 the keccak256 hash of the G1 Point
    /// @dev used for BLS signatures
    function hashG1Point(BN254.G1Point memory pk) internal pure returns (bytes32 hashedG1) {
        assembly {
            mstore(0, mload(pk))
            mstore(0x20, mload(add(0x20, pk)))
            hashedG1 := keccak256(0, 0x40)
        }
    }

    /// @return the keccak256 hash of the G2 Point
    /// @dev used for BLS signatures
    function hashG2Point(
        BN254.G2Point memory pk
    ) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(pk.X[0], pk.X[1], pk.Y[0], pk.Y[1]));
    }

    /**
     * @notice adapted from https://github.com/HarryR/solcrypto/blob/master/contracts/altbn128.sol
     */
    function hashToG1(bytes32 _x) internal view returns (G1Point memory) {
        uint256 beta = 0;
        uint256 y = 0;

        uint256 x = uint256(_x) % FP_MODULUS;

        while (true) {
            (beta, y) = findYFromX(x);

            // y^2 == beta
            if( beta == mulmod(y, y, FP_MODULUS) ) {
                return G1Point(x, y);
            }

            x = addmod(x, 1, FP_MODULUS);
        }
        return G1Point(0, 0);
    }

    /**
     * Given X, find Y
     *
     *   where y = sqrt(x^3 + b)
     *
     * Returns: (x^3 + b), y
     */
    function findYFromX(uint256 x) internal view returns (uint256, uint256) {
        // beta = (x^3 + b) % p
        uint256 beta = addmod(mulmod(mulmod(x, x, FP_MODULUS), x, FP_MODULUS), 3, FP_MODULUS);

        // y^2 = x^3 + b
        // this acts like: y = sqrt(beta) = beta^((p+1) / 4)
        uint256 y = expMod(beta, 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52, FP_MODULUS);

        return (beta, y);
    }

    function expMod(uint256 _base, uint256 _exponent, uint256 _modulus) internal view returns (uint256 retval) {
        bool success;
        uint256[1] memory output;
        uint[6] memory input;
        input[0] = 0x20; // baseLen = new(big.Int).SetBytes(getData(input, 0, 32))
        input[1] = 0x20; // expLen  = new(big.Int).SetBytes(getData(input, 32, 32))
        input[2] = 0x20; // modLen  = new(big.Int).SetBytes(getData(input, 64, 32))
        input[3] = _base;
        input[4] = _exponent;
        input[5] = _modulus;
        assembly {
            success := staticcall(sub(gas(), 2000), 5, input, 0xc0, output, 0x20)
            // Use "invalid" to make gas estimation work
            switch success
            case 0 {
                invalid()
            }
        }
        require(success, "BN254.expMod: call failure");
        return output[0];
    }
}
EigenDATypesV1.sol 79 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import {BN254} from "lib/eigenlayer-middleware/src/libraries/BN254.sol";

library EigenDATypesV1 {
    struct VersionedBlobParams {
        uint32 maxNumOperators;
        uint32 numChunks;
        uint8 codingRate;
    }

    struct SecurityThresholds {
        uint8 confirmationThreshold;
        uint8 adversaryThreshold;
    }

    struct QuorumBlobParam {
        uint8 quorumNumber;
        uint8 adversaryThresholdPercentage;
        uint8 confirmationThresholdPercentage;
        uint32 chunkLength;
    }

    struct BlobHeader {
        BN254.G1Point commitment;
        uint32 dataLength;
        QuorumBlobParam[] quorumBlobParams;
    }

    struct ReducedBatchHeader {
        bytes32 blobHeadersRoot;
        uint32 referenceBlockNumber;
    }

    struct BatchHeader {
        bytes32 blobHeadersRoot;
        bytes quorumNumbers;
        bytes signedStakeForQuorums;
        uint32 referenceBlockNumber;
    }

    struct BatchMetadata {
        BatchHeader batchHeader;
        bytes32 signatoryRecordHash;
        uint32 confirmationBlockNumber;
    }

    struct BlobVerificationProof {
        uint32 batchId;
        uint32 blobIndex;
        BatchMetadata batchMetadata;
        bytes inclusionProof;
        bytes quorumIndices;
    }

    struct NonSignerStakesAndSignature {
        uint32[] nonSignerQuorumBitmapIndices;
        BN254.G1Point[] nonSignerPubkeys;
        BN254.G1Point[] quorumApks;
        BN254.G2Point apkG2;
        BN254.G1Point sigma;
        uint32[] quorumApkIndices;
        uint32[] totalStakeIndices;
        uint32[][] nonSignerStakeIndices;
    }

    struct QuorumStakeTotals {
        uint96[] signedStakeForQuorum;
        uint96[] totalStakeForQuorum;
    }

    struct CheckSignaturesIndices {
        uint32[] nonSignerQuorumBitmapIndices;
        uint32[] quorumApkIndices;
        uint32[] totalStakeIndices;
        uint32[][] nonSignerStakeIndices;
    }
}
EigenDATypesV2.sol 59 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import {BN254} from "lib/eigenlayer-middleware/src/libraries/BN254.sol";

library EigenDATypesV2 {
    struct RelayInfo {
        address relayAddress;
        string relayURL;
    }

    struct DisperserInfo {
        address disperserAddress;
    }

    struct BlobInclusionInfo {
        BlobCertificate blobCertificate;
        uint32 blobIndex;
        bytes inclusionProof;
    }

    struct BlobCertificate {
        BlobHeaderV2 blobHeader;
        bytes signature;
        uint32[] relayKeys;
    }

    struct BlobHeaderV2 {
        uint16 version;
        bytes quorumNumbers;
        BlobCommitment commitment;
        bytes32 paymentHeaderHash;
    }

    struct BlobCommitment {
        BN254.G1Point commitment;
        BN254.G2Point lengthCommitment;
        BN254.G2Point lengthProof;
        uint32 length;
    }

    struct SignedBatch {
        BatchHeaderV2 batchHeader;
        Attestation attestation;
    }

    struct BatchHeaderV2 {
        bytes32 batchRoot;
        uint32 referenceBlockNumber;
    }

    struct Attestation {
        BN254.G1Point[] nonSignerPubkeys;
        BN254.G1Point[] quorumApks;
        BN254.G1Point sigma;
        BN254.G2Point apkG2;
        uint32[] quorumNumbers;
    }
}
BunnyInbox.sol 350 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
import {IEigenDACertVerifierBase} from "src/integrations/cert/interfaces/IEigenDACertVerifierBase.sol";
import {EigenDACertTypes as CT} from "src/integrations/cert/EigenDACertTypes.sol";
import {EigenDATypesV1 as DATypesV1} from "src/core/libraries/v1/EigenDATypesV1.sol";
import {EigenDATypesV2 as DATypesV2} from "src/core/libraries/v2/EigenDATypesV2.sol";
import {BN254} from "lib/eigenlayer-middleware/src/libraries/BN254.sol";
import {RLPReader} from "src/integrations/cert/libraries/RLPReader.sol";

/// @title BunnyInbox
/// @notice Implementation contract for RLP DA cert decoding, deployed behind a TransparentUpgradeableProxy
/// @dev Uses storage variable instead of immutable for verifier to support proxy pattern.
///      Accepts raw DA cert calldata via fallback() in format: 4-byte prefix + RLP-encoded EigenDACertV3
///      Prefix format: [0x01 op_version][0x01 generic_mode][0x00 da_layer][0x02 cert_version]
contract BunnyInbox is Initializable {
    using RLPReader for bytes;
    using RLPReader for RLPReader.RLPItem;

    /// @notice The underlying cert verifier that will validate the decoded certificate
    IEigenDACertVerifierBase public verifier;

    /// @notice Length of the prefix to strip from raw calldata
    uint256 public constant PREFIX_LENGTH = 4;

    error InvalidRawCertLength();
    error RLPDecodingFailed();

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    /// @notice Initializes the contract with the verifier address
    /// @param _verifier Address of the EigenDACertVerifier contract
    function initialize(IEigenDACertVerifierBase _verifier) external initializer {
        verifier = _verifier;
    }

    /// @notice Fallback function that verifies raw DA certificate from msg.data
    /// @dev Processes msg.data directly: 4-byte prefix + RLP-encoded EigenDACertV3
    ///      Reverts if the certificate is invalid
    fallback() external {
        if (msg.data.length <= PREFIX_LENGTH) {
            revert InvalidRawCertLength();
        }

        // Strip the 4-byte prefix
        bytes memory rlpCert = msg.data[PREFIX_LENGTH:];

        // Decode the RLP data into EigenDACertV3 struct
        CT.EigenDACertV3 memory cert = _rlpDecodeCert(rlpCert);

        // Call the verifier with struct directly (reverts on invalid cert)
        verifier.checkDACertReverts(cert);
    }

    /// @notice Decodes RLP-encoded data into an EigenDACertV3 struct
    /// @param rlpData RLP-encoded certificate data
    /// @return cert The decoded EigenDACertV3 struct
    function _rlpDecodeCert(bytes memory rlpData) internal pure returns (CT.EigenDACertV3 memory cert) {
        // Top-level is a list of 4 items:
        // [batchHeader, blobInclusionInfo, nonSignerStakesAndSignature, signedQuorumNumbers]
        (uint256 currPtr, ) = _listHead(rlpData.toRlpItem());

        RLPReader.RLPItem memory item;
        (item, currPtr) = _nextItem(currPtr);
        cert.batchHeader = _decodeBatchHeaderV2(item);
        (item, currPtr) = _nextItem(currPtr);
        cert.blobInclusionInfo = _decodeBlobInclusionInfo(item);
        (item, currPtr) = _nextItem(currPtr);
        cert.nonSignerStakesAndSignature = _decodeNonSignerStakesAndSignature(item);
        (item, ) = _nextItem(currPtr);
        cert.signedQuorumNumbers = item.toBytes();
    }

    /// @notice Decodes BatchHeaderV2 from RLP
    function _decodeBatchHeaderV2(RLPReader.RLPItem memory item)
        internal
        pure
        returns (DATypesV2.BatchHeaderV2 memory header)
    {
        (uint256 currPtr, ) = _listHead(item);

        RLPReader.RLPItem memory field;
        (field, currPtr) = _nextItem(currPtr);
        header.batchRoot = field.toBytes32();
        (field, ) = _nextItem(currPtr);
        header.referenceBlockNumber = field.toUint32();
    }

    /// @notice Decodes BlobInclusionInfo from RLP
    function _decodeBlobInclusionInfo(RLPReader.RLPItem memory item)
        internal
        pure
        returns (DATypesV2.BlobInclusionInfo memory info)
    {
        (uint256 currPtr, ) = _listHead(item);

        RLPReader.RLPItem memory field;
        (field, currPtr) = _nextItem(currPtr);
        info.blobCertificate = _decodeBlobCertificate(field);
        (field, currPtr) = _nextItem(currPtr);
        info.blobIndex = field.toUint32();
        (field, ) = _nextItem(currPtr);
        info.inclusionProof = field.toBytes();
    }

    /// @notice Decodes BlobCertificate from RLP
    function _decodeBlobCertificate(RLPReader.RLPItem memory item)
        internal
        pure
        returns (DATypesV2.BlobCertificate memory cert)
    {
        (uint256 currPtr, ) = _listHead(item);

        RLPReader.RLPItem memory field;
        (field, currPtr) = _nextItem(currPtr);
        cert.blobHeader = _decodeBlobHeaderV2(field);
        (field, currPtr) = _nextItem(currPtr);
        cert.signature = field.toBytes();
        (field, ) = _nextItem(currPtr);
        cert.relayKeys = _decodeUint32Array(field);
    }

    /// @notice Decodes BlobHeaderV2 from RLP
    function _decodeBlobHeaderV2(RLPReader.RLPItem memory item)
        internal
        pure
        returns (DATypesV2.BlobHeaderV2 memory header)
    {
        (uint256 currPtr, ) = _listHead(item);

        RLPReader.RLPItem memory field;
        (field, currPtr) = _nextItem(currPtr);
        header.version = field.toUint16();
        (field, currPtr) = _nextItem(currPtr);
        header.quorumNumbers = field.toBytes();
        (field, currPtr) = _nextItem(currPtr);
        header.commitment = _decodeBlobCommitment(field);
        (field, ) = _nextItem(currPtr);
        header.paymentHeaderHash = field.toBytes32();
    }

    /// @notice Decodes BlobCommitment from RLP
    function _decodeBlobCommitment(RLPReader.RLPItem memory item)
        internal
        pure
        returns (DATypesV2.BlobCommitment memory commitment)
    {
        (uint256 currPtr, ) = _listHead(item);

        RLPReader.RLPItem memory field;
        (field, currPtr) = _nextItem(currPtr);
        commitment.commitment = _decodeG1Point(field);

        (field, currPtr) = _nextItem(currPtr);
        commitment.lengthCommitment = _decodeG2Point(field);

        (field, currPtr) = _nextItem(currPtr);
        commitment.lengthProof = _decodeG2Point(field);

        (field, ) = _nextItem(currPtr);
        commitment.length = field.toUint32();
    }

    /// @notice Decodes NonSignerStakesAndSignature from RLP
    function _decodeNonSignerStakesAndSignature(RLPReader.RLPItem memory item)
        internal
        pure
        returns (DATypesV1.NonSignerStakesAndSignature memory sig)
    {
        (uint256 currPtr, ) = _listHead(item);

        RLPReader.RLPItem memory field;
        (field, currPtr) = _nextItem(currPtr);
        sig.nonSignerQuorumBitmapIndices = _decodeUint32Array(field);
        (field, currPtr) = _nextItem(currPtr);
        sig.nonSignerPubkeys = _decodeG1PointArray(field);
        (field, currPtr) = _nextItem(currPtr);
        sig.quorumApks = _decodeG1PointArray(field);
        (field, currPtr) = _nextItem(currPtr);
        sig.apkG2 = _decodeG2Point(field);
        (field, currPtr) = _nextItem(currPtr);
        sig.sigma = _decodeG1Point(field);
        (field, currPtr) = _nextItem(currPtr);
        sig.quorumApkIndices = _decodeUint32Array(field);
        (field, currPtr) = _nextItem(currPtr);
        sig.totalStakeIndices = _decodeUint32Array(field);
        (field, ) = _nextItem(currPtr);
        sig.nonSignerStakeIndices = _decodeUint32ArrayArray(field);
    }

    /// @notice Decodes a G1Point from RLP (2-element list: X, Y)
    function _decodeG1Point(RLPReader.RLPItem memory item) internal pure returns (BN254.G1Point memory point) {
        (uint256 currPtr, ) = _listHead(item);
        RLPReader.RLPItem memory field;
        (field, currPtr) = _nextItem(currPtr);
        point.X = field.toUint256();
        (field, ) = _nextItem(currPtr);
        point.Y = field.toUint256();
    }

    /// @notice Decodes a G2Point from RLP (2-element list: X[2], Y[2])
    function _decodeG2Point(RLPReader.RLPItem memory item) internal pure returns (BN254.G2Point memory point) {
        (uint256 currPtr, ) = _listHead(item);

        RLPReader.RLPItem memory field;
        (field, currPtr) = _nextItem(currPtr);
        // X is a 2-element list
        {
            (uint256 xPtr, ) = _listHead(field);
            RLPReader.RLPItem memory xField;
            (xField, xPtr) = _nextItem(xPtr);
            point.X[0] = xField.toUint256();
            (xField, ) = _nextItem(xPtr);
            point.X[1] = xField.toUint256();
        }
        (field, ) = _nextItem(currPtr);
        // Y is a 2-element list
        {
            (uint256 yPtr, ) = _listHead(field);
            RLPReader.RLPItem memory yField;
            (yField, yPtr) = _nextItem(yPtr);
            point.Y[0] = yField.toUint256();
            (yField, ) = _nextItem(yPtr);
            point.Y[1] = yField.toUint256();
        }
    }

    /// @notice Decodes an array of G1Points from RLP
    function _decodeG1PointArray(RLPReader.RLPItem memory item)
        internal
        pure
        returns (BN254.G1Point[] memory points)
    {
        (uint256 currPtr, uint256 endPtr) = _listHead(item);

        // Count items
        uint256 count = 0;
        uint256 scanPtr = currPtr;
        unchecked {
            while (scanPtr < endPtr) {
                scanPtr = scanPtr + RLPReader._itemLength(scanPtr);
                ++count;
            }
        }

        points = new BN254.G1Point[](count);
        unchecked {
            for (uint256 i = 0; i < count; ++i) {
                uint256 itemLen = RLPReader._itemLength(currPtr);
                RLPReader.RLPItem memory pointItem = RLPReader.RLPItem(itemLen, currPtr);
                points[i] = _decodeG1Point(pointItem);
                currPtr = currPtr + itemLen;
            }
        }
    }

    function _listHead(RLPReader.RLPItem memory item) private pure returns (uint256 currPtr, uint256 endPtr) {
        require(item.isList(), "RLPReader: item is not a list");
        currPtr = item.memPtr + RLPReader._payloadOffset(item.memPtr);
        endPtr = item.memPtr + item.len;
    }

    function _nextItem(uint256 currPtr)
        private
        pure
        returns (RLPReader.RLPItem memory item, uint256 nextPtr)
    {
        uint256 itemLen = RLPReader._itemLength(currPtr);
        item = RLPReader.RLPItem(itemLen, currPtr);
        nextPtr = currPtr + itemLen;
    }

    /// @notice Decodes an array of uint32 from RLP
    function _decodeUint32Array(RLPReader.RLPItem memory item) internal pure returns (uint32[] memory arr) {
        require(item.isList(), "RLPReader: item is not a list");

        uint256 memPtr = item.memPtr + RLPReader._payloadOffset(item.memPtr);
        uint256 endPtr = item.memPtr + item.len;

        // Count items
        uint256 count = 0;
        uint256 currPtr = memPtr;
        unchecked {
            while (currPtr < endPtr) {
                currPtr = currPtr + RLPReader._itemLength(currPtr);
                ++count;
            }
        }

        // Allocate final array (no intermediate RLPItem[])
        arr = new uint32[](count);

        // Decode directly to uint32[]
        currPtr = memPtr;
        unchecked {
            for (uint256 i = 0; i < count; ++i) {
                uint256 itemLen = RLPReader._itemLength(currPtr);
                uint256 offset = RLPReader._payloadOffset(currPtr);
                uint256 dataLen = itemLen - offset;

                uint256 value;
                assembly {
                    value := mload(add(currPtr, offset))
                    if lt(dataLen, 32) {
                        value := shr(shl(3, sub(32, dataLen)), value)
                    }
                }
                arr[i] = uint32(value);
                currPtr = currPtr + itemLen;
            }
        }
    }

    /// @notice Decodes a 2D array of uint32 from RLP
    function _decodeUint32ArrayArray(RLPReader.RLPItem memory item) internal pure returns (uint32[][] memory arr) {
        require(item.isList(), "RLPReader: item is not a list");

        uint256 memPtr = item.memPtr + RLPReader._payloadOffset(item.memPtr);
        uint256 endPtr = item.memPtr + item.len;

        // Count outer array items
        uint256 count = 0;
        uint256 currPtr = memPtr;
        unchecked {
            while (currPtr < endPtr) {
                currPtr = currPtr + RLPReader._itemLength(currPtr);
                ++count;
            }
        }

        // Allocate outer array
        arr = new uint32[][](count);

        // Decode each inner array directly
        currPtr = memPtr;
        unchecked {
            for (uint256 i = 0; i < count; ++i) {
                uint256 itemLen = RLPReader._itemLength(currPtr);
                // Create RLPItem for the inner array and decode it
                RLPReader.RLPItem memory innerItem = RLPReader.RLPItem(itemLen, currPtr);
                arr[i] = _decodeUint32Array(innerItem);
                currPtr = currPtr + itemLen;
            }
        }
    }
}
EigenDACertTypes.sol 17 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import {EigenDATypesV1 as DATypesV1} from "src/core/libraries/v1/EigenDATypesV1.sol";
import {EigenDATypesV2 as DATypesV2} from "src/core/libraries/v2/EigenDATypesV2.sol";

/// @title EigenDACertTypes
/// @notice This library defines the types for each EigenDA certificate version.
/// @dev It is required that RBN be located in positions 32:64 (padded) in the ABI encoded certificate.
library EigenDACertTypes {
    struct EigenDACertV3 {
        DATypesV2.BatchHeaderV2 batchHeader;
        DATypesV2.BlobInclusionInfo blobInclusionInfo;
        DATypesV1.NonSignerStakesAndSignature nonSignerStakesAndSignature;
        bytes signedQuorumNumbers;
    }
}
IEigenDACertVerifierBase.sol 19 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import {EigenDACertTypes as CT} from "src/integrations/cert/EigenDACertTypes.sol";

interface IEigenDACertVerifierBase {
    /// @notice Check a DA cert's validity
    /// @param abiEncodedCert The ABI encoded certificate. Any cert verifier should decode this ABI encoding based on the certificate version.
    /// @return status An enum value. Success is always mapped to 1, and other values are errors specific to each CertVerifier.
    /// @dev This function should never revert on invalid certs, and should instead return an error status code.
    /// This is because cert invalidity needs to be proven to the rollup's derivation pipeline that the cert can be discarded.
    /// We use Risc0's Steel library for this purpose, which doesn't support reverts: https://github.com/risc0/risc0-ethereum/issues/438
    function checkDACert(bytes calldata abiEncodedCert) external view returns (uint8 status);

    /// @notice Check a DA cert's validity, reverting on failure
    /// @param daCert The EigenDA certificate
    /// @dev This function will revert if the certificate is invalid.
    function checkDACertReverts(CT.EigenDACertV3 calldata daCert) external view;
}
RLPReader.sol 341 lines
// SPDX-License-Identifier: Apache-2.0

/*
 * @author Hamdi Allam [email protected]
 * Please reach out with any questions or concerns
 * https://github.com/hamdiallam/Solidity-RLP
 */
pragma solidity ^0.8.9;

library RLPReader {
    uint8 constant STRING_SHORT_START = 0x80;
    uint8 constant STRING_LONG_START = 0xb8;
    uint8 constant LIST_SHORT_START = 0xc0;
    uint8 constant LIST_LONG_START = 0xf8;
    uint8 constant WORD_SIZE = 32;

    struct RLPItem {
        uint256 len;
        uint256 memPtr;
    }

    /*
     * @param item RLP encoded bytes
     */
    function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) {
        uint256 memPtr;
        assembly {
            memPtr := add(item, 0x20)
        }

        return RLPItem(item.length, memPtr);
    }

    /*
     * @param the RLP item containing the encoded list.
     */
    function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) {
        require(isList(item), "RLPReader: item is not a list");

        uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr);
        uint256 endPtr = item.memPtr + item.len;

        // Single-pass list decoding: count items and cache their positions/lengths
        uint256 itemCount = 0;
        uint256 currPtr = memPtr;

        // First, count items (unavoidable to allocate array)
        unchecked {
            while (currPtr < endPtr) {
                currPtr = currPtr + _itemLength(currPtr);
                ++itemCount;
            }
        }

        // Allocate result array
        RLPItem[] memory result = new RLPItem[](itemCount);

        // Second pass: populate array (but we already have the structure)
        currPtr = memPtr;
        unchecked {
            for (uint256 i = 0; i < itemCount; ++i) {
                uint256 itemLen = _itemLength(currPtr);
                result[i] = RLPItem(itemLen, currPtr);
                currPtr = currPtr + itemLen;
            }
        }

        return result;
    }

    // @return indicator whether encoded payload is a list. negate this function call for isData.
    function isList(RLPItem memory item) internal pure returns (bool) {
        if (item.len == 0) return false;

        uint8 byte0;
        uint256 memPtr = item.memPtr;
        assembly {
            byte0 := byte(0, mload(memPtr))
        }

        if (byte0 < LIST_SHORT_START) return false;
        return true;
    }

    // @return number of payload items inside an encoded list.
    function numItems(RLPItem memory item) private pure returns (uint256) {
        if (item.len == 0) return 0;

        uint256 count = 0;
        uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr);
        uint256 endPtr = item.memPtr + item.len;
        while (currPtr < endPtr) {
            currPtr = currPtr + _itemLength(currPtr); // skip over an item
            count++;
        }

        return count;
    }

    // @return entire rlp item byte length
    function _itemLength(uint256 memPtr) internal pure returns (uint256) {
        uint256 itemLen;
        uint256 byte0;
        assembly {
            byte0 := byte(0, mload(memPtr))
        }

        if (byte0 < STRING_SHORT_START) {
            itemLen = 1;
        } else if (byte0 < STRING_LONG_START) {
            itemLen = byte0 - STRING_SHORT_START + 1;
        } else if (byte0 < LIST_SHORT_START) {
            assembly {
                let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is
                memPtr := add(memPtr, 1) // skip over the first byte

                /* 32 byte word size */
                // Use bit shift instead of exp: shr(bits, x) = x >> bits = x / 2^bits
                let dataLen := shr(mul(8, sub(32, byteLen)), mload(memPtr))
                itemLen := add(dataLen, add(byteLen, 1))
            }
        } else if (byte0 < LIST_LONG_START) {
            itemLen = byte0 - LIST_SHORT_START + 1;
        } else {
            assembly {
                let byteLen := sub(byte0, 0xf7)
                memPtr := add(memPtr, 1)

                // Use bit shift instead of exp: shr(bits, x) = x >> bits = x / 2^bits
                let dataLen := shr(mul(8, sub(32, byteLen)), mload(memPtr))
                itemLen := add(dataLen, add(byteLen, 1))
            }
        }

        return itemLen;
    }

    // @return number of bytes until the data
    function _payloadOffset(uint256 memPtr) internal pure returns (uint256) {
        uint256 byte0;
        assembly {
            byte0 := byte(0, mload(memPtr))
        }

        if (byte0 < STRING_SHORT_START) {
            return 0;
        } else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) {
            return 1;
        } else if (byte0 < LIST_SHORT_START) {
            // being explicit
            return byte0 - (STRING_LONG_START - 1) + 1;
        } else {
            return byte0 - (LIST_LONG_START - 1) + 1;
        }
    }

    /*
     * @param src Pointer to source
     * @param dest Pointer to destination
     * @param len Amount of memory to copy from the source
     */
    function copy(uint256 src, uint256 dest, uint256 len) private pure {
        if (len == 0) return;

        // copy as many word sizes as possible
        unchecked {
            for (; len >= WORD_SIZE; len -= WORD_SIZE) {
                assembly {
                    mstore(dest, mload(src))
                }

                src += WORD_SIZE;
                dest += WORD_SIZE;
            }
        }

        if (len > 0) {
            // left over bytes. Mask is used to remove unwanted bytes from the word
            // Use bit shift instead of exp: 256 ** x = 2 ** (8 * x) = 1 << (8 * x)
            uint256 mask;
            assembly {
                mask := sub(shl(mul(8, sub(WORD_SIZE, len)), 1), 1)
                let srcpart := and(mload(src), not(mask)) // zero out src
                let destpart := and(mload(dest), mask) // retrieve the bytes
                mstore(dest, or(destpart, srcpart))
            }
        }
    }

    /*
     * Additional helper functions for EigenDA cert decoding
     */

    /// @notice Convert RLPItem to bytes
    function toBytes(RLPItem memory item) internal pure returns (bytes memory) {
        require(item.len > 0, "RLPReader: item has no data");

        uint256 memPtr = item.memPtr;
        uint256 len = item.len;
        uint256 offset;

        assembly {
            let byte0 := byte(0, mload(memPtr))

            // Inline _payloadOffset calculation
            switch lt(byte0, 0x80)
            case 1 { offset := 0 }
            default {
                switch lt(byte0, 0xb8)
                case 1 { offset := 1 }
                default {
                    switch lt(byte0, 0xc0)
                    case 1 { offset := add(sub(byte0, 0xb7), 1) }
                    default {
                        switch lt(byte0, 0xf8)
                        case 1 { offset := 1 }
                        default { offset := add(sub(byte0, 0xf7), 1) }
                    }
                }
            }
        }

        len = len - offset;
        bytes memory result = new bytes(len);

        uint256 destPtr;
        assembly {
            destPtr := add(result, 0x20)
        }
        copy(memPtr + offset, destPtr, len);
        return result;
    }

    /// @notice Convert RLPItem to bytes32
    function toBytes32(RLPItem memory item) internal pure returns (bytes32 result) {
        require(item.len > 0, "RLPReader: item has no data");

        uint256 memPtr = item.memPtr;
        uint256 len = item.len;

        assembly {
            let byte0 := byte(0, mload(memPtr))
            let offset := 0

            // Inline _payloadOffset calculation
            switch lt(byte0, 0x80)
            case 1 { offset := 0 }
            default {
                switch lt(byte0, 0xb8)
                case 1 { offset := 1 }
                default {
                    switch lt(byte0, 0xc0)
                    case 1 { offset := add(sub(byte0, 0xb7), 1) }
                    default {
                        switch lt(byte0, 0xf8)
                        case 1 { offset := 1 }
                        default { offset := add(sub(byte0, 0xf7), 1) }
                    }
                }
            }

            memPtr := add(memPtr, offset)
            len := sub(len, offset)

            // Validate length
            if gt(len, 32) {
                mstore(0x00, 0x08c379a0) // Error selector for "Error(string)"
                mstore(0x04, 0x20)
                mstore(0x24, 26) // Length of error message
                mstore(0x44, "RLPReader: bytes32 overflow")
                revert(0x00, 0x64)
            }

            result := mload(memPtr)
            // Right-align if less than 32 bytes
            if lt(len, 32) {
                result := shr(mul(8, sub(32, len)), result)
            }
        }
    }

    /// @notice Convert RLPItem to uint256
    function toUint256(RLPItem memory item) internal pure returns (uint256) {
        require(item.len > 0 && item.len <= 33, "RLPReader: invalid uint256");

        uint256 memPtr = item.memPtr;
        uint256 len = item.len;
        uint256 result;

        assembly {
            let byte0 := byte(0, mload(memPtr))
            let offset := 0

            // Inline _payloadOffset calculation
            switch lt(byte0, 0x80)
            case 1 { offset := 0 }
            default {
                switch lt(byte0, 0xb8)
                case 1 { offset := 1 }
                default {
                    switch lt(byte0, 0xc0)
                    case 1 { offset := add(sub(byte0, 0xb7), 1) }
                    default {
                        switch lt(byte0, 0xf8)
                        case 1 { offset := 1 }
                        default { offset := add(sub(byte0, 0xf7), 1) }
                    }
                }
            }

            memPtr := add(memPtr, offset)
            len := sub(len, offset)

            // Validate length
            if gt(len, 32) {
                mstore(0x00, 0x08c379a0) // Error selector for "Error(string)"
                mstore(0x04, 0x20)
                mstore(0x24, 27) // Length of error message
                mstore(0x44, "RLPReader: uint256 overflow")
                revert(0x00, 0x64)
            }

            result := mload(memPtr)
            // Right-align the value using bit shift
            if lt(len, 32) {
                result := shr(mul(8, sub(32, len)), result)
            }
        }
        return result;
    }

    /// @notice Convert RLPItem to uint32
    function toUint32(RLPItem memory item) internal pure returns (uint32) {
        return uint32(toUint256(item));
    }

    /// @notice Convert RLPItem to uint16
    function toUint16(RLPItem memory item) internal pure returns (uint16) {
        return uint16(toUint256(item));
    }
}

Read Contract

PREFIX_LENGTH 0x2418833f → uint256
verifier 0x2b7ac3f3 → address

Write Contract 1 functions

These functions modify contract state and require a wallet transaction to execute.

initialize 0xc4d66de8
address _verifier

Recent Transactions

This address has 1 on-chain transactions, but only 0.8% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →