Forkchoice Ethereum Mainnet

Address Contract Partially Verified

Address 0x4CEA3E866e7c57fD75CB0CA3E9F5f1151D4Ead3F
Balance 0 ETH
Nonce 1
Code Size 2613 bytes
Indexed Transactions 0 (1 on-chain, 1.3% indexed)
External Etherscan · Sourcify

Contract Bytecode

2613 bytes
0x608060405234801561000f575f80fd5b50600436106100a6575f3560e01c80638da5cb5b1161006e5780638da5cb5b146101375780639551230614610147578063bd98b2b01461015a578063c7065b6a14610194578063cc780aa1146101ce578063f2fde38b146101e1575f80fd5b806322a262c9146100aa57806328aee03f146100bf5780632c09a848146100ef5780635027ad2e14610102578063715018a61461012f575b5f80fd5b6100bd6100b8366004610798565b6101f4565b005b6100d26100cd366004610814565b610269565b6040516001600160a01b0390911681526020015b60405180910390f35b6100bd6100fd366004610834565b610342565b610121610110366004610889565b5f9081526001602052604090205490565b6040519081526020016100e6565b6100bd6103b4565b5f546001600160a01b03166100d2565b6100bd6101553660046108bb565b6103c7565b61016d610168366004610814565b610578565b604080516001600160401b0390931683526001600160a01b039091166020830152016100e6565b61016d6101a2366004610889565b60026020525f90815260409020546001600160401b03811690600160401b90046001600160a01b031682565b6100bd6101dc366004610901565b6105bd565b6100bd6101ef36600461094f565b61062e565b5f6101ff8787610269565b604051637bf41d7760e11b81529091506001600160a01b0382169063f7e83aee90610234908890889088908890600401610997565b5f6040518083038186803b15801561024a575f80fd5b505afa15801561025c573d5f803e3d5ffd5b5050505050505050505050565b5f8281526002602090815260408083208151808301909252546001600160401b038116808352600160401b9091046001600160a01b03169282019290925290831015610337575f84815260016020526040902054805b8015610334575f86815260016020526040902080545f1983019081106102e7576102e76109c8565b5f918252602091829020604080518082019091529101546001600160401b038116808352600160401b9091046001600160a01b0316928201929092529350851015610334575f19016102bf565b50505b602001519392505050565b5f61034d8686610269565b604051636b40634160e01b81529091506001600160a01b03821690636b40634190610380908790879087906004016109dc565b5f6040518083038186803b158015610396575f80fd5b505afa1580156103a8573d5f803e3d5ffd5b50505050505050505050565b6103bc6106ac565b6103c55f610705565b565b6103cf6106ac565b5f838152600260209081526040918290208251808401909352546001600160401b03808216808552600160401b9092046001600160a01b031692840192909252908416101561043157604051632c3631c160e21b815260040160405180910390fd5b6001600160a01b0382166104585760405163a7f9319d60e01b815260040160405180910390fd5b80516001600160401b03808516911610156104e45760208101516001600160a01b0316156104d7575f848152600160208181526040832080549283018155835291829020835191018054928401516001600160a01b0316600160401b026001600160e01b03199093166001600160401b03909216919091179190911790555b6001600160401b03831681525b6001600160a01b0382811660208381018281525f88815260028352604090819020865181549351909616600160401b026001600160e01b03199093166001600160401b0396871617929092179091558051888152938716918401919091528201527f7a98750a395b9ee50a2644ffda039e31f1d5d06de45510275f972bb20b229b309060600160405180910390a150505050565b6001602052815f5260405f208181548110610591575f80fd5b5f918252602090912001546001600160401b0381169250600160401b90046001600160a01b0316905082565b5f6105c85f86610269565b604051636b40634160e01b81529091506001600160a01b03821690636b406341906105fb908790879087906004016109dc565b5f6040518083038186803b158015610611575f80fd5b505afa158015610623573d5f803e3d5ffd5b505050505050505050565b6106366106ac565b6001600160a01b0381166106a05760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b6106a981610705565b50565b5f546001600160a01b031633146103c55760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610697565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f8083601f840112610764575f80fd5b5081356001600160401b0381111561077a575f80fd5b602083019150836020828501011115610791575f80fd5b9250929050565b5f805f805f80608087890312156107ad575f80fd5b863595506020870135945060408701356001600160401b03808211156107d1575f80fd5b6107dd8a838b01610754565b909650945060608901359150808211156107f5575f80fd5b5061080289828a01610754565b979a9699509497509295939492505050565b5f8060408385031215610825575f80fd5b50508035926020909101359150565b5f805f805f60808688031215610848575f80fd5b853594506020860135935060408601356001600160401b0381111561086b575f80fd5b61087788828901610754565b96999598509660600135949350505050565b5f60208284031215610899575f80fd5b5035919050565b80356001600160a01b03811681146108b6575f80fd5b919050565b5f805f606084860312156108cd575f80fd5b8335925060208401356001600160401b03811681146108ea575f80fd5b91506108f8604085016108a0565b90509250925092565b5f805f8060608587031215610914575f80fd5b8435935060208501356001600160401b03811115610930575f80fd5b61093c87828801610754565b9598909750949560400135949350505050565b5f6020828403121561095f575f80fd5b610968826108a0565b9392505050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b604081525f6109aa60408301868861096f565b82810360208401526109bd81858761096f565b979650505050505050565b634e487b7160e01b5f52603260045260245ffd5b604081525f6109ef60408301858761096f565b905082602083015294935050505056fea26469706673582212203c5ffe1c0349d16ee19666d69ad4d28dfae1a7bb0906692725186070f9ceb2fd64736f6c63430008180033

Verified Source Code Partial Match

Compiler: v0.8.24+commit.e11b9ed9 EVM: cancun Optimization: Yes (200 runs)
Context.sol 24 lines
// 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;
    }
}
IZkEvmVerifier.sol 17 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.24;

interface IZkEvmVerifierV1 {
    /// @notice Verify aggregate zk proof.
    /// @param aggrProof The aggregated proof.
    /// @param publicInputHash The public input hash.
    function verify(bytes calldata aggrProof, bytes32 publicInputHash) external view;
}

interface IZkEvmVerifierV2 {
    /// @notice Verify bundle zk proof.
    /// @param bundleProof The bundle recursion proof.
    /// @param publicInput The public input.
    function verify(bytes calldata bundleProof, bytes calldata publicInput) external view;
}
Ownable.sol 83 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling 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);
    }
}
IRollupVerifier.sol 41 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.24;

/// @title IRollupVerifier
/// @notice The interface for rollup verifier.
interface IRollupVerifier {
    /// @notice Verify aggregate zk proof.
    /// @param batchIndex The batch index to verify.
    /// @param aggrProof The aggregated proof.
    /// @param publicInputHash The public input hash.
    function verifyAggregateProof(
        uint256 batchIndex,
        bytes calldata aggrProof,
        bytes32 publicInputHash
    ) external view;

    /// @notice Verify aggregate zk proof.
    /// @param version The version of verifier to use.
    /// @param batchIndex The batch index to verify.
    /// @param aggrProof The aggregated proof.
    /// @param publicInputHash The public input hash.
    function verifyAggregateProof(
        uint256 version,
        uint256 batchIndex,
        bytes calldata aggrProof,
        bytes32 publicInputHash
    ) external view;

    /// @notice Verify bundle zk proof.
    /// @param version The version of verifier to use.
    /// @param batchIndex The batch index used to select verifier.
    /// @param bundleProof The aggregated proof.
    /// @param publicInput The public input.
    function verifyBundleProof(
        uint256 version,
        uint256 batchIndex,
        bytes calldata bundleProof,
        bytes calldata publicInput
    ) external view;
}
MultipleVersionRollupVerifier.sol 177 lines
// SPDX-License-Identifier: MIT

pragma solidity =0.8.24;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

import {IRollupVerifier} from "../../libraries/verifier/IRollupVerifier.sol";
import {IZkEvmVerifierV1, IZkEvmVerifierV2} from "../../libraries/verifier/IZkEvmVerifier.sol";

/// @title MultipleVersionRollupVerifier
/// @notice Verifies aggregate zk proofs using the appropriate verifier.
contract MultipleVersionRollupVerifier is IRollupVerifier, Ownable {
    /**********
     * Events *
     **********/

    /// @notice Emitted when the address of verifier is updated.
    /// @param version The version of the verifier.
    /// @param startBatchIndex The start batch index when the verifier will be used.
    /// @param verifier The address of new verifier.
    event UpdateVerifier(uint256 version, uint256 startBatchIndex, address verifier);

    /**********
     * Errors *
     **********/

    /// @dev Thrown when the given address is `address(0)`.
    error ErrorZeroAddress();

    /// @dev Thrown when the given start batch index is smaller than `latestVerifier.startBatchIndex`.
    error ErrorStartBatchIndexTooSmall();

    /***********
     * Structs *
     ***********/

    struct Verifier {
        // The start batch index for the verifier.
        uint64 startBatchIndex;
        // The address of zkevm verifier.
        address verifier;
    }

    /*************
     * Variables *
     *************/

    /// @notice Mapping from verifier version to the list of legacy zkevm verifiers.
    /// The verifiers are sorted by batchIndex in increasing order.
    mapping(uint256 => Verifier[]) public legacyVerifiers;

    /// @notice Mapping from verifier version to the latest used zkevm verifier.
    mapping(uint256 => Verifier) public latestVerifier;

    /***************
     * Constructor *
     ***************/

    constructor(uint256[] memory _versions, address[] memory _verifiers) {
        for (uint256 i = 0; i < _versions.length; i++) {
            if (_verifiers[i] == address(0)) revert ErrorZeroAddress();
            latestVerifier[_versions[i]].verifier = _verifiers[i];

            emit UpdateVerifier(_versions[i], 0, _verifiers[i]);
        }
    }

    /*************************
     * Public View Functions *
     *************************/

    /// @notice Return the number of legacy verifiers.
    /// @param _version The version of legacy verifiers.
    /// @return The number of legacy verifiers.
    function legacyVerifiersLength(uint256 _version) external view returns (uint256) {
        return legacyVerifiers[_version].length;
    }

    /// @notice Compute the verifier should be used for specific batch.
    /// @param _version The version of verifier to query.
    /// @param _batchIndex The batch index to query.
    /// @return The address of verifier.
    function getVerifier(uint256 _version, uint256 _batchIndex) public view returns (address) {
        // Normally, we will use the latest verifier.
        Verifier memory _verifier = latestVerifier[_version];

        if (_verifier.startBatchIndex > _batchIndex) {
            uint256 _length = legacyVerifiers[_version].length;
            // In most case, only last few verifier will be used by `ScrollChain`.
            // So, we use linear search instead of binary search.
            unchecked {
                for (uint256 i = _length; i > 0; --i) {
                    _verifier = legacyVerifiers[_version][i - 1];
                    if (_verifier.startBatchIndex <= _batchIndex) break;
                }
            }
        }

        return _verifier.verifier;
    }

    /*****************************
     * Public Mutating Functions *
     *****************************/

    /// @inheritdoc IRollupVerifier
    function verifyAggregateProof(
        uint256 _batchIndex,
        bytes calldata _aggrProof,
        bytes32 _publicInputHash
    ) external view override {
        address _verifier = getVerifier(0, _batchIndex);

        IZkEvmVerifierV1(_verifier).verify(_aggrProof, _publicInputHash);
    }

    /// @inheritdoc IRollupVerifier
    function verifyAggregateProof(
        uint256 _version,
        uint256 _batchIndex,
        bytes calldata _aggrProof,
        bytes32 _publicInputHash
    ) external view override {
        address _verifier = getVerifier(_version, _batchIndex);

        IZkEvmVerifierV1(_verifier).verify(_aggrProof, _publicInputHash);
    }

    /// @inheritdoc IRollupVerifier
    function verifyBundleProof(
        uint256 _version,
        uint256 _batchIndex,
        bytes calldata _bundleProof,
        bytes calldata _publicInput
    ) external view override {
        address _verifier = getVerifier(_version, _batchIndex);

        IZkEvmVerifierV2(_verifier).verify(_bundleProof, _publicInput);
    }

    /************************
     * Restricted Functions *
     ************************/

    /// @notice Update the address of zkevm verifier.
    /// @param _version The version of the verifier.
    /// @param _startBatchIndex The start batch index when the verifier will be used.
    /// @param _verifier The address of new verifier.
    function updateVerifier(
        uint256 _version,
        uint64 _startBatchIndex,
        address _verifier
    ) external onlyOwner {
        // We are using version to decide the verifier to use and also this function is
        // controlled by 7 days TimeLock. It is hard to predict `lastFinalizedBatchIndex` after 7 days.
        // So we decide to remove this check to make verifier updating more easier.
        // if (_startBatchIndex <= IScrollChain(scrollChain).lastFinalizedBatchIndex())
        //    revert ErrorStartBatchIndexFinalized();

        Verifier memory _latestVerifier = latestVerifier[_version];
        if (_startBatchIndex < _latestVerifier.startBatchIndex) revert ErrorStartBatchIndexTooSmall();
        if (_verifier == address(0)) revert ErrorZeroAddress();

        if (_latestVerifier.startBatchIndex < _startBatchIndex) {
            // don't push when it is the first update of the version.
            if (_latestVerifier.verifier != address(0)) {
                legacyVerifiers[_version].push(_latestVerifier);
            }
            _latestVerifier.startBatchIndex = _startBatchIndex;
        }
        _latestVerifier.verifier = _verifier;

        latestVerifier[_version] = _latestVerifier;

        emit UpdateVerifier(_version, _startBatchIndex, _verifier);
    }
}

Read Contract

getVerifier 0x28aee03f → address
latestVerifier 0xc7065b6a → uint64, address
legacyVerifiers 0xbd98b2b0 → uint64, address
legacyVerifiersLength 0x5027ad2e → uint256
owner 0x8da5cb5b → address
verifyAggregateProof 0x2c09a848
verifyAggregateProof 0xcc780aa1
verifyBundleProof 0x22a262c9

Write Contract 3 functions

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

renounceOwnership 0x715018a6
No parameters
transferOwnership 0xf2fde38b
address newOwner
updateVerifier 0x95512306
uint256 _version
uint64 _startBatchIndex
address _verifier

Recent Transactions

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