Sepolia Testnet

Contract

0xB6D545eEe2d9B3653DaBCf1D0ea23A80FCd51B4C

Overview

ETH Balance

0 ETH

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Allocate Aggrega...58624362024-05-08 17:44:0065 days ago1715190240IN
0xB6D545eE...0FCd51B4C
0 ETH0.0035463153.5437883
Verify Aggregate...58604862024-05-08 10:01:1265 days ago1715162472IN
0xB6D545eE...0FCd51B4C
0 ETH0.0999765154.39194172
Verify Aggregate...58602272024-05-08 8:59:1266 days ago1715158752IN
0xB6D545eE...0FCd51B4C
0 ETH0.07008637105.72165059
Verify Aggregate...58597202024-05-08 6:56:4866 days ago1715151408IN
0xB6D545eE...0FCd51B4C
0 ETH0.0508012778.95446111
Verify Aggregate...58594772024-05-08 5:58:1266 days ago1715147892IN
0xB6D545eE...0FCd51B4C
0 ETH0.0316239347.7918878
Verify Aggregate...58564342024-05-07 17:59:0066 days ago1715104740IN
0xB6D545eE...0FCd51B4C
0 ETH0.13307306206.92083696
Verify Aggregate...58551732024-05-07 12:56:1266 days ago1715086572IN
0xB6D545eE...0FCd51B4C
0 ETH0.0346240253.1656599
Verify Aggregate...58549322024-05-07 11:57:2466 days ago1715083044IN
0xB6D545eE...0FCd51B4C
0 ETH0.0269133731.53845544
Verify Aggregate...58471342024-05-06 7:37:1268 days ago1714981032IN
0xB6D545eE...0FCd51B4C
0 ETH0.08289713101.2992559
Verify Aggregate...58458902024-05-06 3:16:0068 days ago1714965360IN
0xB6D545eE...0FCd51B4C
0 ETH0.008117779.6624457
Verify Aggregate...58425292024-05-05 15:17:3668 days ago1714922256IN
0xB6D545eE...0FCd51B4C
0 ETH0.10609409129.64755799
Verify Aggregate...58387812024-05-05 1:44:1269 days ago1714873452IN
0xB6D545eE...0FCd51B4C
0 ETH0.003813234.53883105
Verify Aggregate...58351422024-05-04 12:49:0069 days ago1714826940IN
0xB6D545eE...0FCd51B4C
0 ETH0.00679478.30316333
Verify Aggregate...58295742024-05-03 17:14:0070 days ago1714756440IN
0xB6D545eE...0FCd51B4C
0 ETH0.0378337945.02967536
Verify Aggregate...58269072024-05-03 7:45:3671 days ago1714722336IN
0xB6D545eE...0FCd51B4C
0 ETH0.0171950321.01458125
Verify Aggregate...58239322024-05-02 21:05:0071 days ago1714683900IN
0xB6D545eE...0FCd51B4C
0 ETH0.002927893.48536668
Verify Aggregate...58224072024-05-02 15:45:3671 days ago1714664736IN
0xB6D545eE...0FCd51B4C
0 ETH0.0426675352.13996109
Verify Aggregate...58203842024-05-02 8:17:2472 days ago1714637844IN
0xB6D545eE...0FCd51B4C
0 ETH0.001704292.02852851
Verify Aggregate...58174552024-05-01 21:23:2472 days ago1714598604IN
0xB6D545eE...0FCd51B4C
0 ETH0.001777142.17148792
Verify Aggregate...58161002024-05-01 16:22:3672 days ago1714580556IN
0xB6D545eE...0FCd51B4C
0 ETH0.001145441.36332337
Verify Aggregate...58151602024-05-01 12:46:3672 days ago1714567596IN
0xB6D545eE...0FCd51B4C
0 ETH0.001201311.46806162
Verify Aggregate...58140482024-05-01 8:26:3673 days ago1714551996IN
0xB6D545eE...0FCd51B4C
0 ETH0.000210730.25083657
Verify Aggregate...58133822024-05-01 5:53:3673 days ago1714542816IN
0xB6D545eE...0FCd51B4C
0 ETH0.000818691.00039377
Verify Aggregate...58109922024-04-30 20:56:4873 days ago1714510608IN
0xB6D545eE...0FCd51B4C
0 ETH0.000840491.00033468
Verify Aggregate...58102912024-04-30 18:24:1273 days ago1714501452IN
0xB6D545eE...0FCd51B4C
0 ETH0.001107341.35314479
View all transactions

Advanced mode:
Parent Transaction Hash Block From To
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SaturnVerifier

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 100 runs

Other Settings:
default evmVersion, None license

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 10 : SaturnVerifier.sol
// SPDX-License-Identifier: UNLICENSED
/*
    Saturn is Nebra's first generation proof aggregation engine
                                         _.oo.
                 _.u[[/;:,.         .odMMMMMM'
              .o888UU[[[/;:-.  .o@P^    MMM^
             oN88888UU[[[/;::-.        dP^
            dNMMNN888UU[[[/;:--.   .o@P^
           ,MMMMMMN888UU[[/;::-. o@^
           NNMMMNN888UU[[[/~.o@P^
           888888888UU[[[/o@^-..
          oI8888UU[[[/o@P^:--..
       .@^  YUU[[[/o@^;::---..
     oMP     ^/o@P^;:::---..
  .dMMM    .o@^ ^;::---...
 dMMMMMMM@^`       `^^^^
YMMMUP^
 ^^
*/

pragma solidity ^0.8.17;

import "./SaturnProofReceiver.sol";
import "./ISaturnFeeModel.sol";
import "./ISaturnVerifier.sol";
import "./IGroth16Verifier.sol";
import "./Uint16VectorLib.sol";

// Commented but left for debugging
// import "hardhat/console.sol";

/// The proof that a given sequence of proofIds belong to an existing
/// submission.  This is intended to be sent to the SaturnVerifier alongside
/// aggregated proofs.  The contract can compute the vector of proofIds to
/// prove membership of, and the location that they start within the merkle
/// tree.  The contract also knows the Merkle tree depth.  Hence, this
/// structure only contains the `submissionId` (or the Merkle root of the
/// `proofIds`), and the proof of membership (at the given location) of the
/// proofIds.
struct SubmissionProof {
    /// The submissionId
    bytes32 submissionId;
    /// The number of proofIds and the starting location is determined based
    /// on contract state and parameters.  This is a proof that these entries
    /// are in the merkle tree.
    bytes32[] proof;
}

/// Implementation of ISaturnAggregatedProofVerifier.  Accepts aggregated
/// proofs that verify application proofs, where the application proofs have
/// been submitted to an instance of SaturnProofReceiver contract.
contract SaturnVerifier is ISaturnVerifier {
    // owner of contract, responsible for registering vks, etc. Should be a
    // multisig for security.
    address public owner;

    // off-chain worker address
    address public worker;

    // The proof receiver contract
    SaturnProofReceiver public proofReceiver;

    // Saturn Fee Model
    ISaturnFeeModel public feeModel;

    // The outer contract verifier
    address public outerVerifier;

    // Single Groth16 Proof Verifier
    IGroth16Verifier public groth16Verifier;

    /// The submissionIdx of the next submission expected.  Subsequent proofs
    /// to be verified must be from this, or a later submission.
    uint64 public override nextSubmissionIdxToVerify;

    /// The height at which the last verified proof was submitted.  This
    /// intended so that off-chain aggregators can quickly detect from
    /// which height they should start reading proofs.
    uint64 public lastVerifiedSubmissionHeight;

    /// The number of proofs verified for each submission, indexed by
    /// `submissionIdx`.  Since there are 16 entries per 256-bit word, we
    /// should expect to only write to a small number of different slots per
    /// aggregated proof, since indexes are strictly increasing with generally
    /// few gaps.
    ///
    /// Note, the proofs in a submission are considered to appear in order in
    /// the leaves of a Merkle tree (possibly padded on the right with 0s),
    /// and aggregators cannot skip individual proofs within a submission.
    /// Hence, the number stored here completely determines which proofs in
    /// the submission are verified and which are not yet.
    Uint16VectorLib.Uint16Vector private numVerifiedInSubmission;

    constructor(
        address _owner,
        address _worker,
        SaturnProofReceiver _proofReceiver,
        address _outerVerifier,
        address _groth16Verifier
    ) {
        owner = _owner;
        worker = _worker;
        proofReceiver = _proofReceiver;
        outerVerifier = _outerVerifier;
        groth16Verifier = IGroth16Verifier(_groth16Verifier);
        nextSubmissionIdxToVerify = 1;
        lastVerifiedSubmissionHeight = (uint64)(block.number);
    }

    // Note this must be exposed by a function instead of property, otherwise
    // return types do not match.
    function proofReceiverContract()
        external
        view
        override
        returns (ISaturnProofReceiver)
    {
        return proofReceiver;
    }

    /// Verify an aggregated proof.
    function verifyAggregatedProof(
        bytes calldata proof,
        bytes32[] calldata proofIds,
        SubmissionProof[] calldata submissionProofs
    ) external onlyWorker {
        // console.log("verifyAggregatedProof");

        // Expected to fit in a uint16 to match the proof counts.
        require(proofIds.length < (1 << 16), "too many proofIds");

        // Proofs must appear in the order they were submitted, and (for
        // multi-proof submission) in the order they appear within submission,
        // which enables the following algorithm to mark aggregated proofs as
        // verified:
        //
        // For each proof in the batch, namely each `proofId` in `proofIds`,
        // determine the submission (in particular submissionIdx) it belongs
        // to.
        //
        //  - For single-proof submissions, the `proofId` will also be a
        //    `submissionId`, and set
        //    `numVerifiedInSubmission[submissionIdx] = 1`
        //
        //  - For multi-proof submissions, pull a `SubmissionProof` from the
        //    `submissionProofs` list and use it to verify that `proofId` (and
        //    some number of subsequent proofIds) belong to the submission.
        //    Increment `numVerifiedInSubmission[submissionIdx]` accordingly.
        //
        // The caller is responsible for ensuring that `submissionProofs` is
        // compatible with the algorithm described above.

        // Track the proof indices to ensure proofs are verified in order.
        uint64 nextSubmissionIdx = nextSubmissionIdxToVerify;
        uint64 verifiedSubmissionHeight = lastVerifiedSubmissionHeight;

        uint16 submissionProofIdx = 0; // idx into submissionProofs
        uint16 numProofIds = uint16(proofIds.length);
        uint16 proofIdIdx = 0; // idx into proofIds
        while (proofIdIdx < numProofIds) {
            // console.log(" proofIdIdx: %s", proofIdIdx);

            // TODO: Break this segment into functions ... somehow.

            bytes32 proofId = proofIds[proofIdIdx];

            // Attempt to use the proofId as the submissionId.  If this
            // succeeds (namely, if we find a submission with this Id), then
            // the proof was submitted alone, hence and we do not need a
            // SubmissionProof.

            (uint64 submissionIdx, uint64 submissionBlockNumber) = proofReceiver
                .getSubmissionIdxAndHeight(proofId);
            if (submissionIdx != 0) {
                require(
                    submissionIdx >= nextSubmissionIdxToVerify,
                    "out of order"
                );

                // Single-proof case - mark as verified
                require(
                    Uint16VectorLib.getUint16(
                        numVerifiedInSubmission,
                        submissionIdx
                    ) == 0,
                    "proof already verified"
                );
                Uint16VectorLib.setUint16(
                    numVerifiedInSubmission,
                    submissionIdx,
                    1
                );

                // Emit the event
                emit ProofVerified(proofId);

                proofIdIdx++;
                nextSubmissionIdx = submissionIdx + 1;
                verifiedSubmissionHeight = submissionBlockNumber;
            } else {
                // This is a multi-entry submission.  Use the next
                // SubmissionVerification entry.
                require(
                    submissionProofIdx < submissionProofs.length,
                    "missing submission proof"
                );
                SubmissionProof
                    calldata submissionVerification = submissionProofs[
                        submissionProofIdx++
                    ];

                // Read properties of the original submission from
                // SaturnProofReceiver.  Read numVerifiedInSubmission from
                // this contract.
                bytes32 submissionId = submissionVerification.submissionId;
                uint16 numProofsInSubmission;
                uint8 submissionDepth;
                (
                    submissionIdx,
                    submissionBlockNumber,
                    numProofsInSubmission,
                    submissionDepth
                ) = proofReceiver.getSubmissionIdxHeightNumProofsDepth(
                    submissionId
                );

                // Submissions must be verified in the order submitted.
                require(submissionIdx >= nextSubmissionIdx, "out of order");

                // Further, proofs within a submission must appear in order.
                // We can therefore use:
                //
                // - the number of proofs already verified in this submission
                // - the number of proofs left in this aggregated proof
                //
                // to determine exactly which interval of proofs in the
                // submission we expect to see at this point.

                uint16 verified = Uint16VectorLib.getUint16(
                    numVerifiedInSubmission,
                    submissionIdx
                );

                // console.log(
                //     " numProofsInSubmission: %s, verified: %s",
                //     numProofsInSubmission, verified);

                // Compute the number of proofs expected from this submission.
                uint16 unverified = numProofsInSubmission - verified;
                uint16 remainingInAggProof = numProofIds - proofIdIdx;
                uint16 proofsThisSubmission = (unverified < remainingInAggProof)
                    ? (unverified)
                    : (remainingInAggProof);
                // console.log(
                //     " unverified: %s, remainingInAggProof: %s, "
                //     "proofsThisSubmission: %s",
                //     unverified,
                //     remainingInAggProof,
                //     proofsThisSubmission);

                require(
                    proofsThisSubmission > 0,
                    "assert(no submission proofs)"
                );
                require(
                    verified + proofsThisSubmission <= numProofsInSubmission,
                    "assert(submission proofs)"
                );

                doHandleMultiProofSubmission(
                    submissionId,
                    proofIds,
                    submissionVerification.proof,
                    proofIdIdx,
                    proofsThisSubmission,
                    verified,
                    submissionDepth
                );

                // Update state
                proofIdIdx += proofsThisSubmission;
                uint16 newVerified = verified + proofsThisSubmission;
                Uint16VectorLib.setUint16(
                    numVerifiedInSubmission,
                    submissionIdx,
                    newVerified
                );
                // console.log(
                //   " set numVerifiedInSubmission to %s",
                //   verified + proofsThisSubmission);

                if (newVerified == numProofsInSubmission) {
                    nextSubmissionIdx = submissionIdx + 1;
                } else {
                    nextSubmissionIdx = submissionIdx;
                }
                verifiedSubmissionHeight = submissionBlockNumber;
            }
        }

        nextSubmissionIdxToVerify = nextSubmissionIdx;
        lastVerifiedSubmissionHeight = verifiedSubmissionHeight;

        // Verify the aggregated proof
        verifyProofForIDs(proofIds, proof);
    }

    function doHandleMultiProofSubmission(
        bytes32 submissionId,
        bytes32[] calldata proofIds,
        bytes32[] calldata proof,
        uint16 proofIdx,
        uint16 proofsThisSubmission,
        uint16 location,
        uint8 depth
    ) private {
        // Copy the proofIds into memory (we must read them from
        // calldata anyway), and emit events.  Keep proofIdStartIdx
        // and incrememnt proofIdx ready for the next loop.
        bytes32[] memory interval = new bytes32[](proofsThisSubmission);
        for (uint16 i = 0; i < proofsThisSubmission; ++i) {
            bytes32 proofId = proofIds[proofIdx++];
            emit ProofVerified(proofId);
            interval[i] = proofId;
        }

        // Do the Merkle check for the interval of proofIds.

        // Note: location in merkle tree is the number of submission
        // proofs already verified.
        require(
            location + proofsThisSubmission <= 1 << depth,
            "too many proofs"
        );
        bytes32 computedSubmissionId = Merkle.computeMerkleIntervalRoot(
            depth,
            location,
            interval,
            proof
        );
        require(
            computedSubmissionId == submissionId,
            "merkle interval proof is invalid"
        );
    }

    // See ISaturnVerifier.sol
    function isVerified(
        uint256 circuitId,
        uint256[] calldata publicInputs
    ) external view override returns (bool) {
        bytes32 proofId = SaturnLib.computeProofId(circuitId, publicInputs);
        uint64 submissionIdx = proofReceiver.getSubmissionIdx(proofId);

        // This is a single proof submission.  There should only be 1 or 0
        // proofs verified.
        uint16 verified = Uint16VectorLib.getUint16(
            numVerifiedInSubmission,
            submissionIdx
        );
        require(verified < 2, "invalid num verified");

        return (verified == 1);
    }

    function isVerified(
        uint256 circuitId,
        uint256[] calldata publicInputs,
        ProofReference calldata proofReference
    ) external view override returns (bool) {
        (uint64 submissionIdx, uint16 numProofs, uint8 depth) = proofReceiver
            .getSubmissionIdxNumProofsDepth(proofReference.submissionId);
        require(submissionIdx > 0, "no such submission");

        // Strictly speaking, `verified` below should never be more than
        // numProofs, so this check is superfluous.  Kept as a sanity check
        // for now.
        require(proofReference.location < numProofs, "location out of range");

        // Out of `numProofs` in total in the submission, `verified` have been
        // marked as verified, therefore `proofReference.location` should be
        // strictly less than `verified`.
        uint16 verified = Uint16VectorLib.getUint16(
            numVerifiedInSubmission,
            submissionIdx
        );
        if (proofReference.location >= verified) {
            return false;
        }

        // Check the Merkle proof, showing that proofId indeed belongs to the
        // given submission.
        bytes32 proofId = SaturnLib.computeProofId(circuitId, publicInputs);
        return
            Merkle.verifyMerkleProof(
                proofReference.submissionId,
                proofId,
                depth,
                proofReference.location,
                proofReference.merkleProof
            );
    }

    function challenge(
        uint256 circuitId,
        Proof calldata proof,
        uint256[] calldata publicInputs
    ) external returns (bool challengeSuccessful) {
        // Compute the proofId and look up the submitted information.
        bytes32 submissionId = SaturnLib.computeProofId(
            circuitId,
            publicInputs
        );
        SaturnProofReceiver.Submission memory submission = proofReceiver
            .getSubmission(submissionId);

        // TODO: for now, we only support challenges on single-proof
        // submissions.
        require(submission.numProofs == 1, "multi-proof (challenge)");

        // Check that the submitted proofHash matches the proof in this
        // challenge.
        require(
            submission.proofDigestRoot == SaturnLib.computeProofDigest(proof),
            "Proof digest does not match"
        );

        // Confirm that the proof has indeed been skipped, i.e.
        // - the latest proof to be verified is greater than proofIdx, and
        // - the proof has not been verified
        uint64 submissionIdx = submission.submissionIdx;
        require(
            nextSubmissionIdxToVerify - 1 > submissionIdx,
            "Proof not skipped"
        );
        require(
            Uint16VectorLib.getUint16(numVerifiedInSubmission, submissionIdx) ==
                0,
            "Proof verified"
        );

        // Check that the challenge proof is valid for the corresponding VK
        // and public inputs.
        VK memory vk = proofReceiver.getVK(circuitId);
        require(
            groth16Verifier.verifyProof(proof, publicInputs, vk),
            "Challenge not successful"
        );

        // Mark the proof as verified
        Uint16VectorLib.setUint16(numVerifiedInSubmission, submissionIdx, 1);

        // TODO: mark the proof as being challenged by this address, with a
        // timeout.
        //
        // TODO: challenge must be applied to entries in order.

        // TODO: reward msg.sender and/or punish the aggregator who skipped
        // the proof.

        return true;
    }

    function setWorker(address _worker) public onlyOwner {
        worker = _worker;
    }

    function setFeeModel(address _feeModel) external onlyOwner {
        feeModel = ISaturnFeeModel(_feeModel);
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "onlyOwner");
        _;
    }

    modifier onlyWorker() {
        require(msg.sender == worker, "onlyWorker");
        _;
    }

    /// MUST NOT make any state changes!
    ///
    /// This function is public in order that it can be tested and clients
    /// (aggregators) can check their calldata against the verifier.  However,
    /// since it calls outerVerifier, we cannot make it a view function.  If
    /// future changes modify this function to perform state changes,
    /// malicious aggregators could send transactions calling this function
    /// directly.
    ///
    /// TODO: make this function view or internal.
    function verifyProofForIDs(
        bytes32[] calldata proofIDs,
        bytes calldata proof
    ) public {
        // Check that the call data contains the expected final digest at the
        // correct location.
        bytes32 finalDigest = SaturnLib.computeFinalDigest(proofIDs);
        (uint256 expectL, uint256 expectH) = SaturnLib.digestAsFieldElements(
            finalDigest
        );
        uint256 proofL;
        uint256 proofH;
        assembly {
            proofL := calldataload(add(proof.offset, /* 12 * 0x20 */ 0x180))
            proofH := calldataload(add(proof.offset, /* 13 * 0x20 */ 0x1a0))
        }
        require(proofL == expectL, "final digest (l) does not match");
        require(proofH == expectH, "final digest (h) does not match");

        // Call the verifier to check the proof
        (bool success, ) = outerVerifier.call(proof);
        require(success, "invalid proof");
    }

    /// Allocates the aggregator fee to be claimed once
    /// `lastSubmittedProofIdx` in `proofReceiver` is verified.
    function allocateAggregatorFee() external {
        uint64 lastSubmittedProofIdx = proofReceiver.nextSubmissionIdx() - 1;
        feeModel.allocateAggregatorFee(worker, lastSubmittedProofIdx);
    }

    /// Claims the aggregator fee from the `feeModel`.
    function claimAggregatorFee() external {
        feeModel.claimAggregatorFee(worker, nextSubmissionIdxToVerify - 1);
    }

    // For testing
    function getNumVerifiedForSubmissionIdx(
        uint64 submissionIdx
    ) public view returns (uint16) {
        return
            Uint16VectorLib.getUint16(numVerifiedInSubmission, submissionIdx);
    }
}

File 2 of 10 : IGroth16Verifier.sol
// SPDX-License-Identifier: UNLICENSED
/*
    Saturn is Nebra's first generation proof aggregation engine
                                         _.oo.
                 _.u[[/;:,.         .odMMMMMM'
              .o888UU[[[/;:-.  .o@P^    MMM^
             oN88888UU[[[/;::-.        dP^
            dNMMNN888UU[[[/;:--.   .o@P^
           ,MMMMMMN888UU[[/;::-. o@^
           NNMMMNN888UU[[[/~.o@P^
           888888888UU[[[/o@^-..
          oI8888UU[[[/o@P^:--..
       .@^  YUU[[[/o@^;::---..
     oMP     ^/o@P^;:::---..
  .dMMM    .o@^ ^;::---...
 dMMMMMMM@^`       `^^^^
YMMMUP^
 ^^
*/

pragma solidity ^0.8.17;

import "./SaturnLib.sol";

/// Interface to a universal Groth16 verifier contract.
interface IGroth16Verifier {
    /// Note that the Fq2 elements of VK are passed in "natural", not "EVM",
    /// order.
    function verifyProof(
        Proof calldata proofBytes,
        uint256[] calldata publicInputs,
        VK calldata vk
    ) external view returns (bool success);
}

File 3 of 10 : ISaturnFeeModel.sol
// SPDX-License-Identifier: UNLICENSED
/*
    Saturn is Nebra's first generation proof aggregation engine
                                         _.oo.
                 _.u[[/;:,.         .odMMMMMM'
              .o888UU[[[/;:-.  .o@P^    MMM^
             oN88888UU[[[/;::-.        dP^
            dNMMNN888UU[[[/;:--.   .o@P^
           ,MMMMMMN888UU[[/;::-. o@^
           NNMMMNN888UU[[[/~.o@P^
           888888888UU[[[/o@^-..
          oI8888UU[[[/o@P^:--..
       .@^  YUU[[[/o@^;::---..
     oMP     ^/o@P^;:::---..
  .dMMM    .o@^ ^;::---...
 dMMMMMMM@^`       `^^^^
YMMMUP^
 ^^
*/
pragma solidity ^0.8.17;

interface ISaturnFeeModel {
    /// Returns the estimated fee to aggregate `numProofs`.
    function estimateFee(
        uint16 numProofs
    ) external view returns (uint256 feeWei);

    /// `SaturnProofReceiver` calls this function after receiving a proof
    /// submission. This contract takes ownership of the fee, making
    /// it available to the aggregator once `submissionIdx` has been
    /// verified (or skipped).
    /// If the payment is insufficient the transaction is rejected.
    function onProofSubmitted(
        address submitter,
        uint64 submissionIdx,
        uint16 numProofs
    ) external payable returns (uint256 refundWei);

    /// Aggregators call this function (via `SaturnVerifier`) to initiate a
    /// withdrawal of fees for submissions up to the given index. The aggregator
    /// can then claim these fees once the submissions have been verified
    /// or skipped. This 2-step withdrawal enables gas
    /// optimizations in some implementations.
    function allocateAggregatorFee(
        address aggregator,
        uint64 lastSubmittedProofIdx
    ) external;

    /// Aggregators call this (via `SaturnVerifier`) to claim all fees
    /// that have been previously been allocated with
    /// `allocateAggregatorFee`.  The `lastSubmittedProofIdx` passed to
    /// `allocateAggregatorFee` must have been verified or this method will
    /// reject the tx.
    function claimAggregatorFee(
        address aggregator,
        uint128 lastVerifiedProofIdx
    ) external;

    /// Returns the total amount owed to `aggregator` in Wei. This function
    /// doesn't guarantee that the amount can be claimed right away, only that
    /// it has been allocated and will be claimable in the future.
    function feeAllocated(
        address aggregator
    ) external view returns (uint256 feeDue);
}

File 4 of 10 : ISaturnProofReceiver.sol
// SPDX-License-Identifier: UNLICENSED
/*
    Saturn is Nebra's first generation proof aggregation engine
                                         _.oo.
                 _.u[[/;:,.         .odMMMMMM'
              .o888UU[[[/;:-.  .o@P^    MMM^
             oN88888UU[[[/;::-.        dP^
            dNMMNN888UU[[[/;:--.   .o@P^
           ,MMMMMMN888UU[[/;::-. o@^
           NNMMMNN888UU[[[/~.o@P^
           888888888UU[[[/o@^-..
          oI8888UU[[[/o@P^:--..
       .@^  YUU[[[/o@^;::---..
     oMP     ^/o@P^;:::---..
  .dMMM    .o@^ ^;::---...
 dMMMMMMM@^`       `^^^^
YMMMUP^
 ^^
*/
pragma solidity ^0.8.17;

/// A Groth16 proof (with Fq2 elements reversed, to be compatible with the EVM
/// precompiled contracts).
struct Proof {
    uint256[2] pA;
    uint256[2][2] pB;
    uint256[2] pC;
}

/// A Groth16 verification key.  This is primarily used by off-chain
/// aggregators, and therefore Fq2 elements use the "natural" ordering, not
/// the EVM-precompiled-contract-compatible ordering.  The generic
/// IGroth16Verifier contract is expected to fix the ordering internally.
struct VK {
    uint256[2] alpha;
    uint256[2][2] beta;
    uint256[2][2] gamma;
    uint256[2][2] delta;
    uint256[2][] s;
}

// Contract receiving proofs to be aggregated.
interface ISaturnProofReceiver {
    /// Emitted when an application VK is registered.
    event VKRegistered(uint256 indexed circuitId, VK vk);

    /// Emitted when an application proof is submitted to the receiver
    /// contract.
    event ProofSubmitted(
        uint256 indexed circuitId,
        bytes32 indexed proofId,
        uint64 submissionIdx,
        uint64 proofIdx,
        Proof proof,
        uint256[] publicInputs
    );

    /// Returns the maximum number of proofs that can be submitted at once.  0
    /// indicates that the contract itself does not impose a limit.
    function maxNumProofsPerSubmission() external view returns (uint256);

    /// Register a circuit.  A circuit must be registered before proofs for it
    /// can be submitted.
    function registerVK(VK calldata vk) external returns (uint256 circuitId);

    /// Submit a proof that publicInputs is valid for the circuit `circuitId`.
    function submit(
        uint256[] calldata circuitIds,
        Proof[] calldata proofs,
        uint256[][] calldata publicInputs
    ) external payable returns (bytes32 submissionId);

    /// Estimate the fee required to submit `numProofs`.
    function estimateFee(uint16 numProofs) external view returns (uint256);
}

File 5 of 10 : ISaturnVerifier.sol
// SPDX-License-Identifier: UNLICENSED
/*
    Saturn is Nebra's first generation proof aggregation engine
                                         _.oo.
                 _.u[[/;:,.         .odMMMMMM'
              .o888UU[[[/;:-.  .o@P^    MMM^
             oN88888UU[[[/;::-.        dP^
            dNMMNN888UU[[[/;:--.   .o@P^
           ,MMMMMMN888UU[[/;::-. o@^
           NNMMMNN888UU[[[/~.o@P^
           888888888UU[[[/o@^-..
          oI8888UU[[[/o@P^:--..
       .@^  YUU[[[/o@^;::---..
     oMP     ^/o@P^;:::---..
  .dMMM    .o@^ ^;::---...
 dMMMMMMM@^`       `^^^^
YMMMUP^
 ^^
*/
pragma solidity ^0.8.17;

import "./ISaturnProofReceiver.sol";

/// Reference to a single proof in a Submission.  Used by clients to show that
/// a given proof appears in a submission which has been verified as part of
/// an aggregated proof.  Not required for single-proof submissions, since in
/// this case `submissionId == proofId`, and the `merkleProof` and `location`
/// are trivial.
struct ProofReference {
    bytes32 submissionId;
    bytes32[] merkleProof;
    /// Index into the proofs in the submission.  The sequence of proofs
    /// within the submission starts at this index.
    uint16 location;
}

// Contract which verified aggregated proofs.
interface ISaturnVerifier {
    /// Emitted when an application proof is verified as part of an aggregated
    /// proof.  After this event is emitted, `isVerified` will return true for
    /// the given proof.
    event ProofVerified(bytes32 indexed proofId);

    function proofReceiverContract()
        external
        view
        returns (ISaturnProofReceiver);

    function nextSubmissionIdxToVerify() external view returns (uint64);

    // Checks if Saturn has verified a proof that publicInputs is valid for
    // the circuit `circuitId`.
    function isVerified(
        uint256 circuitId,
        uint256[] calldata publicInputs
    ) external view returns (bool);

    // Checks if Saturn has verified a proof that publicInputs is valid for
    // the circuit `circuitId`, where the proof belongs to a multi-proof
    // submission.
    function isVerified(
        uint256 circuitId,
        uint256[] calldata publicInputs,
        ProofReference calldata proofReference
    ) external view returns (bool);

    /// Make a censorship claim that `proof` for `circuitId` with public
    /// inputs `publicInputs` has been skipped by the aggregator.  If the
    /// claim is upheld by the contract (according to the protocol rules - see
    /// the protocol spec), the aggregator will be punished and the claimant
    /// rewarded.
    function challenge(
        uint256 circuitId,
        Proof calldata proof,
        uint256[] calldata publicInputs
    ) external returns (bool challengeSuccessful);
}

File 6 of 10 : Merkle.sol
// SPDX-License-Identifier: UNLICENSED
/*
    Saturn is Nebra's first generation proof aggregation engine
                                         _.oo.
                 _.u[[/;:,.         .odMMMMMM'
              .o888UU[[[/;:-.  .o@P^    MMM^
             oN88888UU[[[/;::-.        dP^
            dNMMNN888UU[[[/;:--.   .o@P^
           ,MMMMMMN888UU[[/;::-. o@^
           NNMMMNN888UU[[[/~.o@P^
           888888888UU[[[/o@^-..
          oI8888UU[[[/o@P^:--..
       .@^  YUU[[[/o@^;::---..
     oMP     ^/o@P^;:::---..
  .dMMM    .o@^ ^;::---...
 dMMMMMMM@^`       `^^^^
YMMMUP^
 ^^
*/

pragma solidity ^0.8.17;

// Commented but left for debugging purposes
// import "hardhat/console.sol";

/// Merkle tree functions for Saturn.
library Merkle {
    function hash(
        bytes32 left,
        bytes32 right
    ) internal pure returns (bytes32 digest) {
        bytes32[2] memory preimage;
        preimage[0] = left;
        preimage[1] = right;
        assembly {
            digest := keccak256(preimage, 0x40)
        }
    }

    /// Given a sequence of contiguous leaf digests, and a proof for the
    /// sequence, compute the Merkle root.
    ///
    /// The "proof" here is similar to a Merkle proof for a single element, in
    /// that it provides the nodes required to complete the Merkle root
    /// calculation.  In this case, it is the elements that "complete" the
    /// pairs at each level of the tree, in the order that they are required.
    function computeMerkleIntervalRoot(
        uint8 depth,
        uint16 offset,
        bytes32[] memory interval,
        bytes32[] calldata intervalProof
    ) internal pure returns (bytes32) {
        // console.log("computeMerkleIntervalRoot:");
        // console.log("  depth: ", depth);
        // console.log("  offset: ", offset);
        // console.log("  interval.length: ", interval.length);
        // console.log("  intervalProof.length: ", intervalProof.length);

        // Implementation follows the function of the same name in the
        // Typescript code, except for some Solidity-specific lines.

        uint32 proofIdx = 0;
        for (uint8 d = depth; d > 0; --d) {
            uint16 intervalLength = (uint16)(interval.length);

            // console.log("  d: %s, intervalLength: %s", d, intervalLength);

            // We must determine the length of the next row up-front.  Compute
            // the length of the current row + extra values from the proof.
            uint16 availableEntries = intervalLength +
                (offset & 1) +
                ((offset + intervalLength) & 1);

            // console.log("  availableEntries: ", availableEntries);

            uint16 newRowLength = availableEntries >> 1;
            bytes32[] memory newRow = new bytes32[](newRowLength);
            uint16 newOffset = offset >> 1;

            // console.log(
            //   "  newRowLen: %s, newOffset", newRowLength, newOffset);

            uint16 entryIdx = 0;
            uint16 remainingEntries = intervalLength;

            // console.log(
            //     "  proofIdx: %s, entryIdx: %s, remainingEntries",
            //     proofIdx,
            //     entryIdx,
            //     remainingEntries);

            // Start at the left of the row.  If the starting idx is odd, the
            // element we have is on the RIGHT of the tuple, and we need to
            // pull the left element from the proof.

            uint16 newRowIdx = 0;
            if ((offset & 1) == 1) {
                require(
                    proofIdx < intervalProof.length,
                    "intervalProof too short (1)"
                );
                newRow[newRowIdx++] = hash(
                    intervalProof[proofIdx++],
                    interval[entryIdx++]
                );
                --remainingEntries;

                // console.log(
                //     "  (absorb left) proofIdx: %s, entryIdx: %s, "
                //     "remainingEntries: %s",
                //     proofIdx,
                //     entryIdx,
                //     remainingEntries);
            }

            // We must now be at an even offset within the row.  Iterate
            // through pairs of entries, computing their hash into the next
            // row, until we have 0 or 1 remaining.

            while (remainingEntries > 1) {
                newRow[newRowIdx++] = hash(
                    interval[entryIdx++],
                    interval[entryIdx++]
                );
                remainingEntries -= 2;

                // console.log(
                //     "  (entry) proofIdx: %s, entryIdx: %s, "
                //     "remainingEntries: %s",
                //     proofIdx,
                //     entryIdx,
                //     remainingEntries);
            }

            // If there is a remaining entry, we must pull an element from the
            // proof in order to use it on the right.

            if (remainingEntries == 1) {
                require(
                    proofIdx < intervalProof.length,
                    "intervalProof too short (2)"
                );
                newRow[newRowIdx++] = hash(
                    interval[entryIdx++],
                    intervalProof[proofIdx++]
                );

                // console.log(
                //     "  (absorb right) proofIdx: %s, entryIdx: %s, "
                //     "remainingEntries: %s",
                //     proofIdx,
                //     entryIdx,
                //     remainingEntries);
            }

            interval = newRow;
            offset = newOffset;
        }

        return interval[0];
    }

    // Note: this could be implemented in terms of computeMerkleIntervalRoot,
    // with a small gas-overhead.  Since this is used for clients to verify
    // individual proofs we use this implementation specialized for single
    // leaves.
    function computeMerkleRoot(
        bytes32[] memory leaves
    ) internal pure returns (bytes32) {
        uint16 numEntries = uint16(leaves.length);
        require(
            ((numEntries - 1) & numEntries) == 0,
            "NPOT leaves (computeMerkleRoot)"
        );

        while (numEntries > 1) {
            uint16 nextNumEntries = numEntries >> 1;
            bytes32[] memory nextLayer = new bytes32[](nextNumEntries);
            uint16 j = 0;
            for (uint16 i = 0; i < numEntries; i += 2) {
                // TODO: Can do this much more optimally by invoking keccak256
                // directly on the array, avoiding copying.
                nextLayer[j++] = hash(leaves[i], leaves[i + 1]);
            }

            numEntries = nextNumEntries;
            leaves = nextLayer;
        }

        return leaves[0];
    }

    function verifyMerkleProof(
        bytes32 root,
        bytes32 value,
        uint8 depth,
        uint16 location,
        bytes32[] calldata proof
    ) internal pure returns (bool) {
        require(proof.length == depth, "invalid proof length");
        bytes32 next;
        uint8 proofIdx = 0;
        while (depth > 0) {
            if (location & 1 == 0) {
                next = hash(value, proof[proofIdx++]);
            } else {
                next = hash(proof[proofIdx++], value);
            }

            location = location >> 1;
            value = next;
            --depth;
        }

        return value == root;
    }

    function merkleDepth(uint16 numEntries) internal pure returns (uint8) {
        uint8 depth = 0;
        uint16 capacity = 1;
        while (capacity < numEntries) {
            ++depth;
            capacity <<= 1;
        }
        return depth;
    }
}

File 7 of 10 : Poseidon.sol
/// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;

// Based on:
//   solhint-disable-next-line
//   https://github.com/vimwitch/poseidon-solidity/blob/e57becdabb65d99fdc586fe1e1e09e7108202d53/contracts/Poseidon.sol

library Poseidon {
    uint256 private constant F =
        // solhint-disable-next-line
        21888242871839275222246405745257275088548364400416034343698204186575808495617;
    uint256 private constant ROUNDS_F = 8;
    uint256 private constant ROUNDS_P = 57;
    uint256 private constant T = 3;

    uint256 private constant M00 =
        0x109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b;
    uint256 private constant M01 =
        0x2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771;
    uint256 private constant M02 =
        0x143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7;
    uint256 private constant M10 =
        0x16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e0;
    uint256 private constant M11 =
        0x2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe23;
    uint256 private constant M12 =
        0x176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee2911;
    uint256 private constant M20 =
        0x2b90bba00fca0589f617e7dcbfe82e0df706ab640ceb247b791a93b74e36736d;
    uint256 private constant M21 =
        0x101071f0032379b697315876690f053d148d4e109f5fb065c8aacc55a0f89bfa;
    uint256 private constant M22 =
        0x19a3fc0a56702bf417ba7fee3802593fa644470307043f7773279cd71d25d5e0;

    /// Run the poseidon hash on the incoming data, assumed to be a list of Fr
    /// elements (for BN254).  Uses a state size of 3, rate of 2.  Pre and post
    /// padding matches the implementation in the halo2::primitives::poseidon
    /// package.
    function hash(uint256[] memory data) public pure returns (uint256) {
        // State is an array of 3 elements, initialized to: [ 1<< 64, 0, 0 ]
        //
        // A `1` is appended to the incoming data, which is processed 2 elements
        // at a time as follows:
        //
        //   - 2 input entries are written to the last 2 state elements
        //   - the update function is called to update the state
        //
        // Squeezed data is read starting at element 1.

        uint256[195] memory c = constants();

        uint256 state0 = 0x10000000000000000;
        uint256 state1 = 0;
        uint256 state2 = 0;

        // For full chunks (of 2 elements), read into state1 and state 2, and
        // permute.

        uint256 i = 0;
        // round(data.length, 2)
        uint256 chunkLimit = data.length & ~uint256(1);
        while (i < chunkLimit) {
            state1 += data[i++];
            state2 += data[i++];
            (state0, state1, state2) = permute(c, state0, state1, state2);
        }

        // Final update uses any remaining data (if the length was odd), and the
        // terminating `1`.

        if (data.length & 1 == 1) {
            state1 += data[i];
            state2 += 1;
        } else {
            state1 += 1;
        }
        (state0, state1, state2) = permute(c, state0, state1, state2);

        // Squeeze a single element, from state1

        return state1;
    }

    function constants() public pure returns (uint256[195] memory) {
        // solhint-disable
        // prettier-ignore
        uint[195] memory C = [0x0ee9a592ba9a9518d05986d656f40c2114c4993c11bb29938d21d47304cd8e6e, 0x00f1445235f2148c5986587169fc1bcd887b08d4d00868df5696fff40956e864, 0x08dff3487e8ac99e1f29a058d0fa80b930c728730b7ab36ce879f3890ecf73f5, 0x2f27be690fdaee46c3ce28f7532b13c856c35342c84bda6e20966310fadc01d0, 0x2b2ae1acf68b7b8d2416bebf3d4f6234b763fe04b8043ee48b8327bebca16cf2, 0x0319d062072bef7ecca5eac06f97d4d55952c175ab6b03eae64b44c7dbf11cfa, 0x28813dcaebaeaa828a376df87af4a63bc8b7bf27ad49c6298ef7b387bf28526d, 0x2727673b2ccbc903f181bf38e1c1d40d2033865200c352bc150928adddf9cb78, 0x234ec45ca27727c2e74abd2b2a1494cd6efbd43e340587d6b8fb9e31e65cc632, 0x15b52534031ae18f7f862cb2cf7cf760ab10a8150a337b1ccd99ff6e8797d428, 0x0dc8fad6d9e4b35f5ed9a3d186b79ce38e0e8a8d1b58b132d701d4eecf68d1f6, 0x1bcd95ffc211fbca600f705fad3fb567ea4eb378f62e1fec97805518a47e4d9c, 0x10520b0ab721cadfe9eff81b016fc34dc76da36c2578937817cb978d069de559, 0x1f6d48149b8e7f7d9b257d8ed5fbbaf42932498075fed0ace88a9eb81f5627f6, 0x1d9655f652309014d29e00ef35a2089bfff8dc1c816f0dc9ca34bdb5460c8705, 0x04df5a56ff95bcafb051f7b1cd43a99ba731ff67e47032058fe3d4185697cc7d, 0x0672d995f8fff640151b3d290cedaf148690a10a8c8424a7f6ec282b6e4be828, 0x099952b414884454b21200d7ffafdd5f0c9a9dcc06f2708e9fc1d8209b5c75b9, 0x052cba2255dfd00c7c483143ba8d469448e43586a9b4cd9183fd0e843a6b9fa6, 0x0b8badee690adb8eb0bd74712b7999af82de55707251ad7716077cb93c464ddc, 0x119b1590f13307af5a1ee651020c07c749c15d60683a8050b963d0a8e4b2bdd1, 0x03150b7cd6d5d17b2529d36be0f67b832c4acfc884ef4ee5ce15be0bfb4a8d09, 0x2cc6182c5e14546e3cf1951f173912355374efb83d80898abe69cb317c9ea565, 0x005032551e6378c450cfe129a404b3764218cadedac14e2b92d2cd73111bf0f9, 0x233237e3289baa34bb147e972ebcb9516469c399fcc069fb88f9da2cc28276b5, 0x05c8f4f4ebd4a6e3c980d31674bfbe6323037f21b34ae5a4e80c2d4c24d60280, 0x0a7b1db13042d396ba05d818a319f25252bcf35ef3aeed91ee1f09b2590fc65b, 0x2a73b71f9b210cf5b14296572c9d32dbf156e2b086ff47dc5df542365a404ec0, 0x1ac9b0417abcc9a1935107e9ffc91dc3ec18f2c4dbe7f22976a760bb5c50c460, 0x12c0339ae08374823fabb076707ef479269f3e4d6cb104349015ee046dc93fc0, 0x0b7475b102a165ad7f5b18db4e1e704f52900aa3253baac68246682e56e9a28e, 0x037c2849e191ca3edb1c5e49f6e8b8917c843e379366f2ea32ab3aa88d7f8448, 0x05a6811f8556f014e92674661e217e9bd5206c5c93a07dc145fdb176a716346f, 0x29a795e7d98028946e947b75d54e9f044076e87a7b2883b47b675ef5f38bd66e, 0x20439a0c84b322eb45a3857afc18f5826e8c7382c8a1585c507be199981fd22f, 0x2e0ba8d94d9ecf4a94ec2050c7371ff1bb50f27799a84b6d4a2a6f2a0982c887, 0x143fd115ce08fb27ca38eb7cce822b4517822cd2109048d2e6d0ddcca17d71c8, 0x0c64cbecb1c734b857968dbbdcf813cdf8611659323dbcbfc84323623be9caf1, 0x028a305847c683f646fca925c163ff5ae74f348d62c2b670f1426cef9403da53, 0x2e4ef510ff0b6fda5fa940ab4c4380f26a6bcb64d89427b824d6755b5db9e30c, 0x0081c95bc43384e663d79270c956ce3b8925b4f6d033b078b96384f50579400e, 0x2ed5f0c91cbd9749187e2fade687e05ee2491b349c039a0bba8a9f4023a0bb38, 0x30509991f88da3504bbf374ed5aae2f03448a22c76234c8c990f01f33a735206, 0x1c3f20fd55409a53221b7c4d49a356b9f0a1119fb2067b41a7529094424ec6ad, 0x10b4e7f3ab5df003049514459b6e18eec46bb2213e8e131e170887b47ddcb96c, 0x2a1982979c3ff7f43ddd543d891c2abddd80f804c077d775039aa3502e43adef, 0x1c74ee64f15e1db6feddbead56d6d55dba431ebc396c9af95cad0f1315bd5c91, 0x07533ec850ba7f98eab9303cace01b4b9e4f2e8b82708cfa9c2fe45a0ae146a0, 0x21576b438e500449a151e4eeaf17b154285c68f42d42c1808a11abf3764c0750, 0x2f17c0559b8fe79608ad5ca193d62f10bce8384c815f0906743d6930836d4a9e, 0x2d477e3862d07708a79e8aae946170bc9775a4201318474ae665b0b1b7e2730e, 0x162f5243967064c390e095577984f291afba2266c38f5abcd89be0f5b2747eab, 0x2b4cb233ede9ba48264ecd2c8ae50d1ad7a8596a87f29f8a7777a70092393311, 0x2c8fbcb2dd8573dc1dbaf8f4622854776db2eece6d85c4cf4254e7c35e03b07a, 0x1d6f347725e4816af2ff453f0cd56b199e1b61e9f601e9ade5e88db870949da9, 0x204b0c397f4ebe71ebc2d8b3df5b913df9e6ac02b68d31324cd49af5c4565529, 0x0c4cb9dc3c4fd8174f1149b3c63c3c2f9ecb827cd7dc25534ff8fb75bc79c502, 0x174ad61a1448c899a25416474f4930301e5c49475279e0639a616ddc45bc7b54, 0x1a96177bcf4d8d89f759df4ec2f3cde2eaaa28c177cc0fa13a9816d49a38d2ef, 0x066d04b24331d71cd0ef8054bc60c4ff05202c126a233c1a8242ace360b8a30a, 0x2a4c4fc6ec0b0cf52195782871c6dd3b381cc65f72e02ad527037a62aa1bd804, 0x13ab2d136ccf37d447e9f2e14a7cedc95e727f8446f6d9d7e55afc01219fd649, 0x1121552fca26061619d24d843dc82769c1b04fcec26f55194c2e3e869acc6a9a, 0x00ef653322b13d6c889bc81715c37d77a6cd267d595c4a8909a5546c7c97cff1, 0x0e25483e45a665208b261d8ba74051e6400c776d652595d9845aca35d8a397d3, 0x29f536dcb9dd7682245264659e15d88e395ac3d4dde92d8c46448db979eeba89, 0x2a56ef9f2c53febadfda33575dbdbd885a124e2780bbea170e456baace0fa5be, 0x1c8361c78eb5cf5decfb7a2d17b5c409f2ae2999a46762e8ee416240a8cb9af1, 0x151aff5f38b20a0fc0473089aaf0206b83e8e68a764507bfd3d0ab4be74319c5, 0x04c6187e41ed881dc1b239c88f7f9d43a9f52fc8c8b6cdd1e76e47615b51f100, 0x13b37bd80f4d27fb10d84331f6fb6d534b81c61ed15776449e801b7ddc9c2967, 0x01a5c536273c2d9df578bfbd32c17b7a2ce3664c2a52032c9321ceb1c4e8a8e4, 0x2ab3561834ca73835ad05f5d7acb950b4a9a2c666b9726da832239065b7c3b02, 0x1d4d8ec291e720db200fe6d686c0d613acaf6af4e95d3bf69f7ed516a597b646, 0x041294d2cc484d228f5784fe7919fd2bb925351240a04b711514c9c80b65af1d, 0x154ac98e01708c611c4fa715991f004898f57939d126e392042971dd90e81fc6, 0x0b339d8acca7d4f83eedd84093aef51050b3684c88f8b0b04524563bc6ea4da4, 0x0955e49e6610c94254a4f84cfbab344598f0e71eaff4a7dd81ed95b50839c82e, 0x06746a6156eba54426b9e22206f15abca9a6f41e6f535c6f3525401ea0654626, 0x0f18f5a0ecd1423c496f3820c549c27838e5790e2bd0a196ac917c7ff32077fb, 0x04f6eeca1751f7308ac59eff5beb261e4bb563583ede7bc92a738223d6f76e13, 0x2b56973364c4c4f5c1a3ec4da3cdce038811eb116fb3e45bc1768d26fc0b3758, 0x123769dd49d5b054dcd76b89804b1bcb8e1392b385716a5d83feb65d437f29ef, 0x2147b424fc48c80a88ee52b91169aacea989f6446471150994257b2fb01c63e9, 0x0fdc1f58548b85701a6c5505ea332a29647e6f34ad4243c2ea54ad897cebe54d, 0x12373a8251fea004df68abcf0f7786d4bceff28c5dbbe0c3944f685cc0a0b1f2, 0x21e4f4ea5f35f85bad7ea52ff742c9e8a642756b6af44203dd8a1f35c1a90035, 0x16243916d69d2ca3dfb4722224d4c462b57366492f45e90d8a81934f1bc3b147, 0x1efbe46dd7a578b4f66f9adbc88b4378abc21566e1a0453ca13a4159cac04ac2, 0x07ea5e8537cf5dd08886020e23a7f387d468d5525be66f853b672cc96a88969a, 0x05a8c4f9968b8aa3b7b478a30f9a5b63650f19a75e7ce11ca9fe16c0b76c00bc, 0x20f057712cc21654fbfe59bd345e8dac3f7818c701b9c7882d9d57b72a32e83f, 0x04a12ededa9dfd689672f8c67fee31636dcd8e88d01d49019bd90b33eb33db69, 0x27e88d8c15f37dcee44f1e5425a51decbd136ce5091a6767e49ec9544ccd101a, 0x2feed17b84285ed9b8a5c8c5e95a41f66e096619a7703223176c41ee433de4d1, 0x1ed7cc76edf45c7c404241420f729cf394e5942911312a0d6972b8bd53aff2b8, 0x15742e99b9bfa323157ff8c586f5660eac6783476144cdcadf2874be45466b1a, 0x1aac285387f65e82c895fc6887ddf40577107454c6ec0317284f033f27d0c785, 0x25851c3c845d4790f9ddadbdb6057357832e2e7a49775f71ec75a96554d67c77, 0x15a5821565cc2ec2ce78457db197edf353b7ebba2c5523370ddccc3d9f146a67, 0x2411d57a4813b9980efa7e31a1db5966dcf64f36044277502f15485f28c71727, 0x002e6f8d6520cd4713e335b8c0b6d2e647e9a98e12f4cd2558828b5ef6cb4c9b, 0x2ff7bc8f4380cde997da00b616b0fcd1af8f0e91e2fe1ed7398834609e0315d2, 0x00b9831b948525595ee02724471bcd182e9521f6b7bb68f1e93be4febb0d3cbe, 0x0a2f53768b8ebf6a86913b0e57c04e011ca408648a4743a87d77adbf0c9c3512, 0x00248156142fd0373a479f91ff239e960f599ff7e94be69b7f2a290305e1198d, 0x171d5620b87bfb1328cf8c02ab3f0c9a397196aa6a542c2350eb512a2b2bcda9, 0x170a4f55536f7dc970087c7c10d6fad760c952172dd54dd99d1045e4ec34a808, 0x29aba33f799fe66c2ef3134aea04336ecc37e38c1cd211ba482eca17e2dbfae1, 0x1e9bc179a4fdd758fdd1bb1945088d47e70d114a03f6a0e8b5ba650369e64973, 0x1dd269799b660fad58f7f4892dfb0b5afeaad869a9c4b44f9c9e1c43bdaf8f09, 0x22cdbc8b70117ad1401181d02e15459e7ccd426fe869c7c95d1dd2cb0f24af38, 0x0ef042e454771c533a9f57a55c503fcefd3150f52ed94a7cd5ba93b9c7dacefd, 0x11609e06ad6c8fe2f287f3036037e8851318e8b08a0359a03b304ffca62e8284, 0x1166d9e554616dba9e753eea427c17b7fecd58c076dfe42708b08f5b783aa9af, 0x2de52989431a859593413026354413db177fbf4cd2ac0b56f855a888357ee466, 0x3006eb4ffc7a85819a6da492f3a8ac1df51aee5b17b8e89d74bf01cf5f71e9ad, 0x2af41fbb61ba8a80fdcf6fff9e3f6f422993fe8f0a4639f962344c8225145086, 0x119e684de476155fe5a6b41a8ebc85db8718ab27889e85e781b214bace4827c3, 0x1835b786e2e8925e188bea59ae363537b51248c23828f047cff784b97b3fd800, 0x28201a34c594dfa34d794996c6433a20d152bac2a7905c926c40e285ab32eeb6, 0x083efd7a27d1751094e80fefaf78b000864c82eb571187724a761f88c22cc4e7, 0x0b6f88a3577199526158e61ceea27be811c16df7774dd8519e079564f61fd13b, 0x0ec868e6d15e51d9644f66e1d6471a94589511ca00d29e1014390e6ee4254f5b, 0x2af33e3f866771271ac0c9b3ed2e1142ecd3e74b939cd40d00d937ab84c98591, 0x0b520211f904b5e7d09b5d961c6ace7734568c547dd6858b364ce5e47951f178, 0x0b2d722d0919a1aad8db58f10062a92ea0c56ac4270e822cca228620188a1d40, 0x1f790d4d7f8cf094d980ceb37c2453e957b54a9991ca38bbe0061d1ed6e562d4, 0x0171eb95dfbf7d1eaea97cd385f780150885c16235a2a6a8da92ceb01e504233, 0x0c2d0e3b5fd57549329bf6885da66b9b790b40defd2c8650762305381b168873, 0x1162fb28689c27154e5a8228b4e72b377cbcafa589e283c35d3803054407a18d, 0x2f1459b65dee441b64ad386a91e8310f282c5a92a89e19921623ef8249711bc0, 0x1e6ff3216b688c3d996d74367d5cd4c1bc489d46754eb712c243f70d1b53cfbb, 0x01ca8be73832b8d0681487d27d157802d741a6f36cdc2a0576881f9326478875, 0x1f7735706ffe9fc586f976d5bdf223dc680286080b10cea00b9b5de315f9650e, 0x2522b60f4ea3307640a0c2dce041fba921ac10a3d5f096ef4745ca838285f019, 0x23f0bee001b1029d5255075ddc957f833418cad4f52b6c3f8ce16c235572575b, 0x2bc1ae8b8ddbb81fcaac2d44555ed5685d142633e9df905f66d9401093082d59, 0x0f9406b8296564a37304507b8dba3ed162371273a07b1fc98011fcd6ad72205f, 0x2360a8eb0cc7defa67b72998de90714e17e75b174a52ee4acb126c8cd995f0a8, 0x15871a5cddead976804c803cbaef255eb4815a5e96df8b006dcbbc2767f88948, 0x193a56766998ee9e0a8652dd2f3b1da0362f4f54f72379544f957ccdeefb420f, 0x2a394a43934f86982f9be56ff4fab1703b2e63c8ad334834e4309805e777ae0f, 0x1859954cfeb8695f3e8b635dcb345192892cd11223443ba7b4166e8876c0d142, 0x04e1181763050e58013444dbcb99f1902b11bc25d90bbdca408d3819f4fed32b, 0x0fdb253dee83869d40c335ea64de8c5bb10eb82db08b5e8b1f5e5552bfd05f23, 0x058cbe8a9a5027bdaa4efb623adead6275f08686f1c08984a9d7c5bae9b4f1c0, 0x1382edce9971e186497eadb1aeb1f52b23b4b83bef023ab0d15228b4cceca59a, 0x03464990f045c6ee0819ca51fd11b0be7f61b8eb99f14b77e1e6634601d9e8b5, 0x23f7bfc8720dc296fff33b41f98ff83c6fcab4605db2eb5aaa5bc137aeb70a58, 0x0a59a158e3eec2117e6e94e7f0e9decf18c3ffd5e1531a9219636158bbaf62f2, 0x06ec54c80381c052b58bf23b312ffd3ce2c4eba065420af8f4c23ed0075fd07b, 0x118872dc832e0eb5476b56648e867ec8b09340f7a7bcb1b4962f0ff9ed1f9d01, 0x13d69fa127d834165ad5c7cba7ad59ed52e0b0f0e42d7fea95e1906b520921b1, 0x169a177f63ea681270b1c6877a73d21bde143942fb71dc55fd8a49f19f10c77b, 0x04ef51591c6ead97ef42f287adce40d93abeb032b922f66ffb7e9a5a7450544d, 0x256e175a1dc079390ecd7ca703fb2e3b19ec61805d4f03ced5f45ee6dd0f69ec, 0x30102d28636abd5fe5f2af412ff6004f75cc360d3205dd2da002813d3e2ceeb2, 0x10998e42dfcd3bbf1c0714bc73eb1bf40443a3fa99bef4a31fd31be182fcc792, 0x193edd8e9fcf3d7625fa7d24b598a1d89f3362eaf4d582efecad76f879e36860, 0x18168afd34f2d915d0368ce80b7b3347d1c7a561ce611425f2664d7aa51f0b5d, 0x29383c01ebd3b6ab0c017656ebe658b6a328ec77bc33626e29e2e95b33ea6111, 0x10646d2f2603de39a1f4ae5e7771a64a702db6e86fb76ab600bf573f9010c711, 0x0beb5e07d1b27145f575f1395a55bf132f90c25b40da7b3864d0242dcb1117fb, 0x16d685252078c133dc0d3ecad62b5c8830f95bb2e54b59abdffbf018d96fa336, 0x0a6abd1d833938f33c74154e0404b4b40a555bbbec21ddfafd672dd62047f01a, 0x1a679f5d36eb7b5c8ea12a4c2dedc8feb12dffeec450317270a6f19b34cf1860, 0x0980fb233bd456c23974d50e0ebfde4726a423eada4e8f6ffbc7592e3f1b93d6, 0x161b42232e61b84cbf1810af93a38fc0cece3d5628c9282003ebacb5c312c72b, 0x0ada10a90c7f0520950f7d47a60d5e6a493f09787f1564e5d09203db47de1a0b, 0x1a730d372310ba82320345a29ac4238ed3f07a8a2b4e121bb50ddb9af407f451, 0x2c8120f268ef054f817064c369dda7ea908377feaba5c4dffbda10ef58e8c556, 0x1c7c8824f758753fa57c00789c684217b930e95313bcb73e6e7b8649a4968f70, 0x2cd9ed31f5f8691c8e39e4077a74faa0f400ad8b491eb3f7b47b27fa3fd1cf77, 0x23ff4f9d46813457cf60d92f57618399a5e022ac321ca550854ae23918a22eea, 0x09945a5d147a4f66ceece6405dddd9d0af5a2c5103529407dff1ea58f180426d, 0x188d9c528025d4c2b67660c6b771b90f7c7da6eaa29d3f268a6dd223ec6fc630, 0x3050e37996596b7f81f68311431d8734dba7d926d3633595e0c0d8ddf4f0f47f, 0x15af1169396830a91600ca8102c35c426ceae5461e3f95d89d829518d30afd78, 0x1da6d09885432ea9a06d9f37f873d985dae933e351466b2904284da3320d8acc, 0x2796ea90d269af29f5f8acf33921124e4e4fad3dbe658945e546ee411ddaa9cb, 0x202d7dd1da0f6b4b0325c8b3307742f01e15612ec8e9304a7cb0319e01d32d60, 0x096d6790d05bb759156a952ba263d672a2d7f9c788f4c831a29dace4c0f8be5f, 0x054efa1f65b0fce283808965275d877b438da23ce5b13e1963798cb1447d25a4, 0x1b162f83d917e93edb3308c29802deb9d8aa690113b2e14864ccf6e18e4165f1, 0x21e5241e12564dd6fd9f1cdd2a0de39eedfefc1466cc568ec5ceb745a0506edc, 0x1cfb5662e8cf5ac9226a80ee17b36abecb73ab5f87e161927b4349e10e4bdf08, 0x0f21177e302a771bbae6d8d1ecb373b62c99af346220ac0129c53f666eb24100, 0x1671522374606992affb0dd7f71b12bec4236aede6290546bcef7e1f515c2320, 0x0fa3ec5b9488259c2eb4cf24501bfad9be2ec9e42c5cc8ccd419d2a692cad870, 0x193c0e04e0bd298357cb266c1506080ed36edce85c648cc085e8c57b1ab54bba, 0x102adf8ef74735a27e9128306dcbc3c99f6f7291cd406578ce14ea2adaba68f8, 0x0fe0af7858e49859e2a54d6f1ad945b1316aa24bfbdd23ae40a6d0cb70c3eab1, 0x216f6717bbc7dedb08536a2220843f4e2da5f1daa9ebdefde8a5ea7344798d22, 0x1da55cc900f0d21f4a3e694391918a1b3c23b2ac773c6b3ef88e2e4228325161];
        // solhint-enable
        return C;
    }

    function permute(
        uint256[195] memory c,
        uint256 state0,
        uint256 state1,
        uint256 state2
    ) public pure returns (uint256, uint256, uint256) {
        uint256 swap0 = state0;
        uint256 swap1 = state1;
        uint256 swap2 = state2;
        for (uint8 r = 0; r < ROUNDS_F + ROUNDS_P; r++) {
            state0 = addmod(swap0, c[r * T + 0], F);
            state1 = addmod(swap1, c[r * T + 1], F);
            state2 = addmod(swap2, c[r * T + 2], F);

            state0 = pow5mod(state0);
            if (r < ROUNDS_F / 2 || r >= ROUNDS_F / 2 + ROUNDS_P) {
                state1 = pow5mod(state1);
                state2 = pow5mod(state2);
            }

            swap0 = addmod(
                addmod(
                    addmod(0, mulmod(state0, M00, F), F),
                    mulmod(state1, M10, F),
                    F
                ),
                mulmod(state2, M20, F),
                F
            );
            swap1 = addmod(
                addmod(
                    addmod(0, mulmod(state0, M01, F), F),
                    mulmod(state1, M11, F),
                    F
                ),
                mulmod(state2, M21, F),
                F
            );
            swap2 = addmod(
                addmod(
                    addmod(0, mulmod(state0, M02, F), F),
                    mulmod(state1, M12, F),
                    F
                ),
                mulmod(state2, M22, F),
                F
            );
        }

        return (swap0, swap1, swap2);
    }

    function pow5mod(uint256 i) public pure returns (uint256) {
        uint256 a = mulmod(i, i, F);
        uint256 c = mulmod(a, a, F);
        return mulmod(i, c, F);
    }
}

File 8 of 10 : SaturnLib.sol
// SPDX-License-Identifier: UNLICENSED
/*
    Saturn is Nebra's first generation proof aggregation engine
                                         _.oo.
                 _.u[[/;:,.         .odMMMMMM'
              .o888UU[[[/;:-.  .o@P^    MMM^
             oN88888UU[[[/;::-.        dP^
            dNMMNN888UU[[[/;:--.   .o@P^
           ,MMMMMMN888UU[[/;::-. o@^
           NNMMMNN888UU[[[/~.o@P^
           888888888UU[[[/o@^-..
          oI8888UU[[[/o@P^:--..
       .@^  YUU[[[/o@^;::---..
     oMP     ^/o@P^;:::---..
  .dMMM    .o@^ ^;::---...
 dMMMMMMM@^`       `^^^^
YMMMUP^
 ^^
*/

pragma solidity ^0.8.17;

import "./Poseidon.sol";
import "./ISaturnProofReceiver.sol";

/// Library of Saturn utility functions.
library SaturnLib {
    // These must be consistent with the BatchVerify circuit configuration.
    uint8 internal constant NUM_LIMBS = 3;
    uint8 internal constant LIMB_BITS = 88;
    uint256 internal constant LIMB_MASK = (uint256(1) << LIMB_BITS) - 1;

    /// Compute the proofId for a proof given the vk_hash and the public
    /// inputs.
    function computeProofId(
        uint256 circuitId,
        uint256[] calldata publicInputs
    ) internal pure returns (bytes32) {
        uint256 numPIs = publicInputs.length;

        // Lay out the pre-image as a memory array of words:
        //   [ <len>,    0     , 0, 0, ... ]
        // and write the circuitId at the start:
        //   [ <len>, circuitId, 0, 0, ... ]

        uint256[] memory preimage = new uint256[](numPIs + 1);
        preimage[0] = circuitId;

        // Fill in the remaining values from the public inputs in calldata
        //   [ <len>, circuitId, PI_0, ... ]
        // and call keccak on the underlying memory (as bytes).

        bytes32 digest;
        assembly {
            let pi_bytes := mul(publicInputs.length, 0x20)
            calldatacopy(add(preimage, 0x40), publicInputs.offset, pi_bytes)
            digest := keccak256(add(preimage, 0x20), add(pi_bytes, 0x20))
        }

        return digest;
    }

    /// Compute the digest of a specific Groth16 proof.  Used to commit to
    /// proof data which may later be submitted by a claimant.
    function computeProofDigest(
        Proof calldata proof
    ) internal pure returns (bytes32) {
        return keccak256(abi.encode(proof));
    }

    /// Compute the circuitId for a Groth16 verification key.
    function computeCircuitId(VK calldata vk) internal pure returns (uint256) {
        // Compute output length
        uint256 numPiElements = vk.s.length;
        uint256 outputLenFq = 10 + numPiElements * 2;
        uint256 outputLenFr = outputLenFq * NUM_LIMBS;

        // TODO: try "streaming" this rather than writing everything to a huge
        // buffer.

        uint256[] memory preimage = new uint256[](outputLenFr);
        uint256 i = 0;
        decomposeFqToBuffer(vk.alpha[0], preimage, i);
        i += NUM_LIMBS;
        decomposeFqToBuffer(vk.alpha[1], preimage, i);
        i += NUM_LIMBS;
        decomposeFqToBuffer(vk.beta[0][0], preimage, i);
        i += NUM_LIMBS;
        decomposeFqToBuffer(vk.beta[0][1], preimage, i);
        i += NUM_LIMBS;
        decomposeFqToBuffer(vk.beta[1][0], preimage, i);
        i += NUM_LIMBS;
        decomposeFqToBuffer(vk.beta[1][1], preimage, i);
        i += NUM_LIMBS;
        decomposeFqToBuffer(vk.delta[0][0], preimage, i);
        i += NUM_LIMBS;
        decomposeFqToBuffer(vk.delta[0][1], preimage, i);
        i += NUM_LIMBS;
        decomposeFqToBuffer(vk.delta[1][0], preimage, i);
        i += NUM_LIMBS;
        decomposeFqToBuffer(vk.delta[1][1], preimage, i);
        i += NUM_LIMBS;
        for (uint256 pi = 0; pi < numPiElements; ++pi) {
            decomposeFqToBuffer(vk.s[pi][0], preimage, i);
            i += NUM_LIMBS;
            decomposeFqToBuffer(vk.s[pi][1], preimage, i);
            i += NUM_LIMBS;
        }
        assert(outputLenFr == i);

        return Poseidon.hash(preimage);
    }

    function computeFinalDigest(
        bytes32[] calldata proofIDs
    ) internal pure returns (bytes32 finalDigest) {
        bytes32[] memory pids = new bytes32[](proofIDs.length);
        assembly {
            let pid_bytes := mul(proofIDs.length, 0x20)
            calldatacopy(add(pids, 0x20), proofIDs.offset, pid_bytes)
            finalDigest := keccak256(add(pids, 0x20), pid_bytes)
        }
    }

    /// Split the given field element into "limbs".  Note, this does not check
    /// the well-formedness of the incoming element.
    function decomposeFq(
        uint256 fq
    ) internal pure returns (uint256, uint256, uint256) {
        assert(NUM_LIMBS == 3);
        uint256 x0 = fq & LIMB_MASK;
        fq = fq >> LIMB_BITS;
        uint256 x1 = fq & LIMB_MASK;
        return (x0, x1, fq >> LIMB_BITS);
    }

    function decomposeFqToBuffer(
        uint256 fq,
        uint256[] memory output,
        uint256 offset
    ) internal pure {
        (uint256 x0, uint256 x1, uint256 x2) = decomposeFq(fq);
        output[offset] = x0;
        output[offset + 1] = x1;
        output[offset + 2] = x2;
    }

    // Decompose a 32-byte digest into (lower, higher) order 128 bit values,
    // representable as field elements.
    function digestAsFieldElements(
        bytes32 digest
    ) internal pure returns (uint256, uint256) {
        uint256 digestUint = uint256(digest);
        return (digestUint & ((1 << 128) - 1), digestUint >> 128);
    }
}

File 9 of 10 : SaturnProofReceiver.sol
// SPDX-License-Identifier: UNLICENSED
/*
    Saturn is Nebra's first generation proof aggregation engine
                                         _.oo.
                 _.u[[/;:,.         .odMMMMMM'
              .o888UU[[[/;:-.  .o@P^    MMM^
             oN88888UU[[[/;::-.        dP^
            dNMMNN888UU[[[/;:--.   .o@P^
           ,MMMMMMN888UU[[/;::-. o@^
           NNMMMNN888UU[[[/~.o@P^
           888888888UU[[[/o@^-..
          oI8888UU[[[/o@P^:--..
       .@^  YUU[[[/o@^;::---..
     oMP     ^/o@P^;:::---..
  .dMMM    .o@^ ^;::---...
 dMMMMMMM@^`       `^^^^
YMMMUP^
 ^^
*/

pragma solidity ^0.8.17;

import "./ISaturnFeeModel.sol";
import "./ISaturnProofReceiver.sol";
import "./SaturnLib.sol";
import "./Merkle.sol";

/// Implementation of ISaturnProofReceiver.  Accepts VK registrations and
/// tracks proofs against each registered VK.
contract SaturnProofReceiver is ISaturnProofReceiver {
    uint16 public constant MAX_SUBMISSION_MERKLE_DEPTH = 5;
    uint16 public constant MAX_NUM_PROOFS_PER_SUBMISSION =
        uint16(1) << MAX_SUBMISSION_MERKLE_DEPTH;

    // Per-circuit data
    struct CircuitData {
        /// Verification key of the circuit
        VK verificationKey;
    }

    struct Submission {
        /// Merkle root of the proof data digests as seen by the contract
        bytes32 proofDigestRoot;
        /// Index of this submission
        uint64 submissionIdx;
        /// Block number at which the submission was made
        uint64 submissionBlockNumber;
        /// The number of proofs in this submission
        uint16 numProofs;
        uint8 merkleDepth;

        /// TODO: space for a claimant address here.
    }

    /// All circuitIds known to the contract.
    uint256[] public _circuitIds;

    /// Data for each registered circuit, indexed by the circuitId.
    mapping(uint256 => CircuitData) public _circuitData;

    /// The full set of submissions, indexed by the submissionId.
    mapping(bytes32 => Submission) public _submissions;

    /// The next submission index
    uint64 public _nextSubmissionIdx;

    /// The next proof index.  (Proof index is not strictly required, but
    /// since it doesn't occupy any extra storage slots, we track this.  It
    /// can be useful for auditing off-chain DBs).
    uint64 public _nextProofIdx;

    // owner of contract, responsible for registering vks, etc. Should be a
    // multisig for security.
    address public _owner;

    /// Fee model contract. `submitProof` calls will forward the fees here.
    ISaturnFeeModel public _feeModel;

    modifier onlyOwner() {
        require(msg.sender == _owner, "onlyOwner");
        _;
    }

    constructor(address owner) {
        _owner = owner;
        _nextSubmissionIdx = 1;
        _nextProofIdx = 1;
    }

    function maxNumProofsPerSubmission()
        external
        pure
        override
        returns (uint256)
    {
        return MAX_SUBMISSION_MERKLE_DEPTH;
    }

    function registerVK(
        VK calldata vk
    ) external override returns (uint256 circuitId) {
        // Record the new circuitId.
        circuitId = SaturnLib.computeCircuitId(vk);
        _circuitIds.push(circuitId);

        // Record the CircuitData struct
        CircuitData storage cData = _circuitData[circuitId];
        require(0 == cData.verificationKey.alpha[0], "VK already registered");
        cData.verificationKey = vk;

        /// Emit the VKRegistered event
        emit VKRegistered(circuitId, vk);
    }

    // See ISaturn.sol
    function submit(
        uint256[] calldata circuitIds,
        Proof[] calldata proofs,
        uint256[][] calldata publicInputs
    ) public payable override returns (bytes32 submissionId) {
        uint16 numProofs = uint16(circuitIds.length);
        require(proofs.length == numProofs, "incompatible num proofs");
        require(
            publicInputs.length == numProofs,
            "incompatible num public inputs"
        );
        require(numProofs <= MAX_NUM_PROOFS_PER_SUBMISSION, "too many proofs");

        uint8 depth = Merkle.merkleDepth(numProofs);
        uint16 fullSize = uint16(1) << depth;

        bytes32[] memory proofIds = new bytes32[](fullSize);
        bytes32[] memory proofDigests = new bytes32[](fullSize);
        uint64 submissionIdx = _nextSubmissionIdx++;
        uint64 proofIdx = _nextProofIdx;

        // Iterate through all proofs.  Emit events, compute the proofIds and
        // proofHashes.
        for (uint16 i = 0; i < numProofs; ++i) {
            handleSubmittedProof(
                i,
                proofIdx,
                submissionIdx,
                circuitIds,
                proofs,
                publicInputs,
                proofIds,
                proofDigests
            );
            proofIdx++;
        }

        // _nextSubmissionIdx = submissionIdx + 1;
        _nextProofIdx = proofIdx;

        // Record the final submission
        submissionId = Merkle.computeMerkleRoot(proofIds);
        bytes32 proofDigestRoot = Merkle.computeMerkleRoot(proofDigests);

        // Ensure there is no existing submission
        require(
            _submissions[submissionId].submissionIdx == 0,
            "submission exists (submit)"
        );

        // Forward the fee to the fee model
        _feeModel.onProofSubmitted{value: msg.value}(
            msg.sender,
            submissionIdx,
            numProofs
        );

        _submissions[submissionId] = Submission(
            proofDigestRoot,
            submissionIdx,
            uint64(block.number),
            numProofs,
            depth
        );
    }

    /// Return the list of circuit Ids that have been registered.
    function getCircuitIds() public view returns (uint256[] memory) {
        return _circuitIds;
    }

    /// Return the VK for a specific circuit Id.
    function getVK(uint256 circuitId) public view returns (VK memory) {
        CircuitData storage cData = _circuitData[circuitId];
        require(cData.verificationKey.alpha[0] != 0, "VK not registered");
        return cData.verificationKey;
    }

    function nextSubmissionIdx() public view returns (uint64) {
        return _nextSubmissionIdx;
    }

    function getSubmissionIdx(
        bytes32 submissionId
    ) public view returns (uint64 submissionIdx) {
        Submission storage submission = _submissions[submissionId];
        require(
            0 != submission.submissionIdx,
            "No submission (getSubmissionIdx)"
        );
        submissionIdx = submission.submissionIdx;
    }

    function getSubmissionIdxAndHeight(
        bytes32 submissionId
    ) public view returns (uint64 submissionIdx, uint64 submissionBlockNumber) {
        Submission storage submission = _submissions[submissionId];
        // require(
        //     0 != submission.submissionIdx,
        //     "No proof(getSubmissionIdxAndHeight)");
        submissionIdx = submission.submissionIdx;
        submissionBlockNumber = submission.submissionBlockNumber;
    }

    function getSubmissionIdxAndNumProofs(
        bytes32 submissionId
    ) public view returns (uint64 submissionIdx, uint16 numProofs) {
        Submission storage submission = _submissions[submissionId];
        submissionIdx = submission.submissionIdx;
        numProofs = submission.numProofs;
    }

    function getSubmissionIdxNumProofsDepth(
        bytes32 submissionId
    )
        public
        view
        returns (uint64 submissionIdx, uint16 numProofs, uint8 depth)
    {
        Submission storage submission = _submissions[submissionId];
        submissionIdx = submission.submissionIdx;
        numProofs = submission.numProofs;
        depth = submission.merkleDepth;
    }

    function getSubmissionIdxHeightNumProofsDepth(
        bytes32 submissionId
    )
        public
        view
        returns (
            uint64 submissionIdx,
            uint64 height,
            uint16 numProofs,
            uint8 depth
        )
    {
        Submission storage submission = _submissions[submissionId];
        submissionIdx = submission.submissionIdx;
        height = submission.submissionBlockNumber;
        numProofs = submission.numProofs;
        depth = submission.merkleDepth;
    }

    function getSubmission(
        bytes32 submissionId
    ) public view returns (Submission memory submission) {
        submission = _submissions[submissionId];
        require(
            0 != submission.submissionIdx,
            "No such proof(getSubmissionData)"
        );
    }

    function computeProofId(
        uint256 circuitId,
        uint256[] calldata publicInputs
    ) public pure returns (bytes32) {
        return SaturnLib.computeProofId(circuitId, publicInputs);
    }

    function computeCircuitId(VK calldata vk) public pure returns (uint256) {
        return SaturnLib.computeCircuitId(vk);
    }

    function computeFinalDigest(
        bytes32[] calldata proofIDs
    ) public pure returns (bytes32 finalDigest) {
        return SaturnLib.computeFinalDigest(proofIDs);
    }

    function digestAsFieldElements(
        bytes32 digest
    ) public pure returns (uint256, uint256) {
        return SaturnLib.digestAsFieldElements(digest);
    }

    function setFeeModel(address feeModel) external onlyOwner {
        _feeModel = ISaturnFeeModel(feeModel);
    }

    function estimateFee(
        uint16 numProofs
    ) external view override returns (uint256) {
        return _feeModel.estimateFee(numProofs);
    }

    // Exposed for testing
    function decomposeFq(
        uint256 fq
    ) public pure returns (uint256, uint256, uint256) {
        return SaturnLib.decomposeFq(fq);
    }

    // Sub-section of the code in `submit`.  This function exists only to
    // avoid a "stack too deep" error in the compiler.
    function handleSubmittedProof(
        uint16 i,
        uint64 proofIdx,
        uint64 submissionIdx,
        uint256[] calldata circuitIds,
        Proof[] calldata proofs,
        uint256[][] calldata publicInputs,
        bytes32[] memory proofIds,
        bytes32[] memory proofDigests
    ) internal {
        uint256 circuitId = circuitIds[i];
        CircuitData storage cData = _circuitData[circuitId];
        require(
            cData.verificationKey.alpha[0] != 0,
            "VK has not been registered"
        );

        bytes32 proofDigest = SaturnLib.computeProofDigest(proofs[i]);
        proofDigests[i] = proofDigest;

        bytes32 proofId = SaturnLib.computeProofId(circuitId, publicInputs[i]);
        proofIds[i] = proofId;

        emit ProofSubmitted(
            circuitId,
            proofId,
            submissionIdx,
            proofIdx,
            proofs[i],
            publicInputs[i]
        );
    }
}

File 10 of 10 : Uint16VectorLib.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity ^0.8.17;

library Uint16VectorLib {
    /// Mask of low-order 16 bits of a word.  Used to extract packed uint16.
    uint256 internal constant UINT16_MASK = 0xffff;

    /// A vector of uint16's implemented as an array of 256-bit words.
    struct Uint16Vector {
        uint256[] entries;
    }

    function getUint16(
        Uint16Vector storage vector,
        uint64 idx
    ) internal view returns (uint16 out) {
        /// Word idx is 'idx / 16' = 'idx >> 4'
        uint64 wordIdx = idx >> 4;
        if (wordIdx < vector.entries.length) {
            // The uint16 index within the word is idx % 16, so the shift is
            // that * 16.
            uint64 shift = (idx & 0xf) << 4;
            uint256 word = vector.entries[wordIdx];
            out = uint16((word >> shift) & UINT16_MASK);
        } else {
            out = 0;
        }
    }

    function setUint16(
        Uint16Vector storage vector,
        uint64 idx,
        uint16 value
    ) internal {
        // wordIdx = idx / 16
        uint128 wordIdx = idx >> 4;
        // shift = (idx % 16) * 16
        uint128 shift = (idx & 0xf) << 4;
        // Mask to remove any existing value
        uint256 mask = ~(UINT16_MASK << shift); /* ~(0xffff << shift) */
        // New value, shifted up to replace the existing one.
        uint256 shiftedValue = uint256(value) << shift;

        uint256 len = vector.entries.length;
        if (wordIdx < len) {
            uint256 word = (vector.entries[wordIdx] & mask) | shiftedValue;
            vector.entries[wordIdx] = word;
        } else {
            // We do not want to extend the array by pushing 0s, since we don't
            // know many will need to be pushed, but this requires updating the
            // array data.  The following is equivalent to:
            //
            //   bitVector.entries.length = wordIdx + 1;   // <-- illegal
            //   bitVector.entries[wordIdx] = bitMask;
            //
            assembly {
                // The slot at `bitVector.slot` holds the length of `entries`.
                // Avoid extending with repeated `push` instructions and simply
                // write the new length and new word.  Any intermediate slots
                // will already be 0.
                sstore(vector.slot, add(wordIdx, 1))

                // The array data starts at slot: bv = keccak256(bitVector.slot)
                // hence we write bitMask at slot: bv + wordIdx.
                mstore(0, vector.slot)
                let bv := keccak256(0, 0x20)
                sstore(add(bv, wordIdx), shiftedValue)
            }

            // Uncomment to enable checks that the above has done the right
            // thing.

            require(vector.entries.length == wordIdx + 1, "vector length");
            require(vector.entries[wordIdx] == shiftedValue, "vector entry");
        }
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 100
  },
  "viaIR": true,
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  }
}

Contract ABI

[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_worker","type":"address"},{"internalType":"contract SaturnProofReceiver","name":"_proofReceiver","type":"address"},{"internalType":"address","name":"_outerVerifier","type":"address"},{"internalType":"address","name":"_groth16Verifier","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"proofId","type":"bytes32"}],"name":"ProofVerified","type":"event"},{"inputs":[],"name":"allocateAggregatorFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"circuitId","type":"uint256"},{"components":[{"internalType":"uint256[2]","name":"pA","type":"uint256[2]"},{"internalType":"uint256[2][2]","name":"pB","type":"uint256[2][2]"},{"internalType":"uint256[2]","name":"pC","type":"uint256[2]"}],"internalType":"struct Proof","name":"proof","type":"tuple"},{"internalType":"uint256[]","name":"publicInputs","type":"uint256[]"}],"name":"challenge","outputs":[{"internalType":"bool","name":"challengeSuccessful","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimAggregatorFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeModel","outputs":[{"internalType":"contract ISaturnFeeModel","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"submissionIdx","type":"uint64"}],"name":"getNumVerifiedForSubmissionIdx","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"groth16Verifier","outputs":[{"internalType":"contract IGroth16Verifier","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"circuitId","type":"uint256"},{"internalType":"uint256[]","name":"publicInputs","type":"uint256[]"}],"name":"isVerified","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"circuitId","type":"uint256"},{"internalType":"uint256[]","name":"publicInputs","type":"uint256[]"},{"components":[{"internalType":"bytes32","name":"submissionId","type":"bytes32"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"},{"internalType":"uint16","name":"location","type":"uint16"}],"internalType":"struct ProofReference","name":"proofReference","type":"tuple"}],"name":"isVerified","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastVerifiedSubmissionHeight","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextSubmissionIdxToVerify","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"outerVerifier","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proofReceiver","outputs":[{"internalType":"contract SaturnProofReceiver","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proofReceiverContract","outputs":[{"internalType":"contract ISaturnProofReceiver","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_feeModel","type":"address"}],"name":"setFeeModel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_worker","type":"address"}],"name":"setWorker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"proof","type":"bytes"},{"internalType":"bytes32[]","name":"proofIds","type":"bytes32[]"},{"components":[{"internalType":"bytes32","name":"submissionId","type":"bytes32"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"internalType":"struct SubmissionProof[]","name":"submissionProofs","type":"tuple[]"}],"name":"verifyAggregatedProof","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proofIDs","type":"bytes32[]"},{"internalType":"bytes","name":"proof","type":"bytes"}],"name":"verifyProofForIDs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"worker","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60803462000102576001600160401b0390601f6200258d38819003918201601f191683019184831184841017620001075780849260a09460405283398101031262000102576200004f816200011d565b906200005e602082016200011d565b91604082015160018060a01b039283821680920362000102578391826200009660806200008e606086016200011d565b94016200011d565b968160018060a01b031996168660005416176000551684600154161760015583600254161760025516906004541617600455600160a01b911663ffffffff60e01b600554161717600555431660018060401b0319600654161760065560405161245a9081620001338239f35b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b0382168203620001025756fe60806040526004361015610013575b600080fd5b60003560e01c80630fdb8dca1461018657806319c813be1461017d5780631e00b6b6146101745780631e035f371461016b5780634d547ada146101625780634deda90014610159578063650b3ca1146101505780636a872ed9146101475780638da5cb5b1461013e57806397ee1144146101355780639fabac471461011a578063a5a9504e1461012c578063ad9b484d14610123578063addef8ae1461011a578063c26f6d4414610111578063c68ed32b14610108578063d6ae6a90146100ff578063d6af8da4146100f65763d87366ad146100ee57600080fd5b61000e610bf7565b5061000e610bcc565b5061000e610ba2565b5061000e610b1e565b5061000e610adf565b5061000e6105db565b5061000e610666565b5061000e610627565b5061000e6105b1565b5061000e610587565b5061000e610520565b5061000e6104c8565b5061000e6103c9565b5061000e61036f565b5061000e610347565b5061000e610313565b5061000e6102d8565b5061000e61019a565b600091031261000e57565b503461000e576000806003193601126102d5576002546101fd906004906020906101d4906001600160a01b03165b6001600160a01b031690565b60405163fb8bb1f760e01b815292839182905afa9081156102c8575b839161029a575b50611b9b565b6003548290610214906001600160a01b03166101c8565b6001546001600160a01b03169290803b1561029657604051630f58b8a760e01b81526001600160a01b0390941660048501526001600160401b0390911660248401528290818381604481015b03925af18015610289575b610273575080f35b8061028061028692610ed6565b8061018f565b80f35b610291610f75565b61026b565b8280fd5b6102bb915060203d81116102c1575b6102b38183610f2c565b810190611701565b386101f7565b503d6102a9565b6102d0610f75565b6101f0565b80fd5b503461000e57600036600319011261000e576005546040516001600160a01b039091168152602090f35b6001600160401b0381160361000e57565b503461000e57602036600319011261000e57602061033b60043561033681610302565b6121dd565b61ffff60405191168152f35b503461000e57600036600319011261000e5760206001600160401b0360065416604051908152f35b503461000e57600036600319011261000e576001546040516001600160a01b039091168152602090f35b9181601f8401121561000e578235916001600160401b03831161000e576020808501948460051b01011161000e57565b503461000e57604036600319011261000e576024356001600160401b03811161000e5761ffff61045761043d602061041361040a6001963690600401610399565b90600435611759565b858060a01b0360025416604051808095819463d3b3a1a960e01b8352600483019190602083019252565b03915afa90811561048e575b600091610470575b506121dd565b1661046460028210611716565b60405191148152602090f35b610488915060203d81116102c1576102b38183610f2c565b38610451565b610496610f75565b610449565b9181601f8401121561000e578235916001600160401b03831161000e576020838186019501011161000e57565b503461000e57604036600319011261000e576001600160401b0360043581811161000e576104fa903690600401610399565b9060243592831161000e5761051661051e93369060040161049b565b9290916120f4565b005b503461000e5760031960603682011261000e576001600160401b0360243581811161000e57610553903690600401610399565b9260443592831161000e57606090833603011261000e5760209261057d9260040191600435611885565b6040519015158152f35b503461000e57600036600319011261000e576000546040516001600160a01b039091168152602090f35b503461000e57600036600319011261000e576003546040516001600160a01b039091168152602090f35b503461000e57600036600319011261000e576002546040516001600160a01b039091168152602090f35b602090600319011261000e576004356001600160a01b038116810361000e5790565b503461000e5761063636610605565b6000546001600160a01b0391906106509083163314611fd9565b1660018060a01b03196003541617600355600080f35b503461000e57606036600319011261000e576004356001600160401b03811161000e5761069790369060040161049b565b6024356001600160401b03811161000e576106b6903690600401610399565b6044939193356001600160401b03811161000e576106d8903690600401610399565b60018054909692906001600160a01b03163303610aad57956106fe620100008510610e4a565b600554819060a01c6001600160401b0316926107226006546001600160401b031690565b9860009182945b610787575b505050505061051e9561076661078292600554906001600160401b0360a01b9060a01b16906001600160401b0360a01b191617600555565b6001600160401b03166001600160401b03196006541617600655565b6120f4565b90929491939961ffff85169061ffff8916821015610aa357506107ab908888610ea1565b600254903594906107c4906001600160a01b03166101c8565b604080516305160b7760e11b815260048101889052919691948d9180876024818c5afa988915610a96575b600097889a610a61575b506001600160401b0388169384156108ab5750505050916108969161084761089c946108406108346005546001600160401b039060a01c1690565b6001600160401b031690565b111561108b565b61086361085d610856886121dd565b61ffff1690565b156111ef565b61086c86612386565b7f543093db8d78fd8619586d3a0be12a5736836393feede0888f262888c81ce4c3600080a2610fe0565b926111d7565b93945b9290839a94959a610729565b6108de939a5061ffff929698506108d5919550608094506108cf8884831610610f82565b9f610fe0565b9e168588611000565b925163cccb79e560e01b81528335600482015291829060249082905afa918215610a54575b8989600094859986958792610a05575b50906109366001600160401b038a959493166001600160401b038916101561108b565b61093f876121dd565b809561094b82896110e4565b6109598761ffff88166110e4565b61ffff811661ffff8316106000146109f957509a8b9586925b61098161ffff851615156110f8565b61098b8486611144565b9a61ffff1661ffff819c1611156109a19061115a565b6109ae60208201826111a2565b92909135976109bc98611309565b6109c591611144565b946109cf91611144565b6109d981846122c0565b61ffff16036109f3576109eb906111d7565b935b9461089f565b936109ed565b90509a8b958692610972565b6109369b506001600160401b039750610a3c919650899493925060803d608011610a4d575b610a348183610f2c565b81019061104a565b919c92985096939450919290610913565b503d610a2a565b610a5c610f75565b610903565b90995081610a859298503d8911610a8f575b610a7d8183610f2c565b810190610f4d565b96909698386107f9565b503d610a73565b610a9e610f75565b6107ef565b9a5082955061072e565b60405162461bcd60e51b815260206004820152600a60248201526937b7363cabb7b935b2b960b11b6044820152606490fd5b503461000e57610aee36610605565b6000546001600160a01b039190610b089083163314611fd9565b1660018060a01b03196001541617600155600080f35b503461000e576000806003193601126102d5576003546001546005546001600160a01b039182169284921690610b5f9060a01c6001600160401b0316611b9b565b90803b1561029657604051635611757360e01b81526001600160a01b0390941660048501526001600160401b039091166024840152829081838160448101610260565b503461000e57600036600319011261000e576004546040516001600160a01b039091168152602090f35b503461000e57600036600319011261000e5760206001600160401b0360055460a01c16604051908152f35b503461000e5761014036600319011261000e5760043561010036602319011261000e57610124356001600160401b039182821161000e57610c3f610c83923690600401610399565b91610c4b838383611759565b60025460a090610c63906001600160a01b03166101c8565b9160405180978192631d5b74e960e21b8352600483019190602083019252565b0381845afa948515610e3d575b600095610e0d575b5061ffff94856060820151610cae9061ffff1690565b16600114610cbb90611b09565b8051610cc5611f95565b14610ccf90611b4f565b602001516001600160401b03169460055496808860a01c16610cf090611b9b565b610cff91888116911611611bb4565b610d08866121dd565b1615610d1390611bf4565b60405163405ef34760e01b81526004810192909252816024815a93600094fa610d9695610d9194610d6e946020948415610e00575b600094610ddd575b50604051633fb5881960e01b81529586948593849360048501611e69565b03916001600160a01b03165afa908115610dd0575b600091610da2575b50611f4e565b612386565b60405160018152602090f35b610dc3915060203d8111610dc9575b610dbb8183610f2c565b810190611dbc565b38610d8b565b503d610db1565b610dd8610f75565b610d83565b610df991943d8091833e610df18183610f2c565b810190611cc8565b9238610d50565b610e08610f75565b610d48565b610e2f91955060a03d8111610e36575b610e278183610f2c565b810190611a83565b9338610c98565b503d610e1d565b610e45610f75565b610c90565b15610e5157565b60405162461bcd60e51b8152602060048201526011602482015270746f6f206d616e792070726f6f6649647360781b6044820152606490fd5b50634e487b7160e01b600052603260045260246000fd5b9190811015610eb2575b60051b0190565b610eba610e8a565b610eab565b50634e487b7160e01b600052604160045260246000fd5b6001600160401b038111610ee957604052565b610ef1610ebf565b604052565b60a081019081106001600160401b03821117610ee957604052565b604081019081106001600160401b03821117610ee957604052565b90601f801991011681019081106001600160401b03821117610ee957604052565b919082604091031261000e5760208251610f6681610302565b920151610f7281610302565b90565b506040513d6000823e3d90fd5b15610f8957565b60405162461bcd60e51b815260206004820152601860248201527736b4b9b9b4b7339039bab136b4b9b9b4b7b710383937b7b360411b6044820152606490fd5b50634e487b7160e01b600052601160045260246000fd5b60019061ffff809116908114610ff4570190565b610ffc610fc9565b0190565b9190811015611023575b60051b81013590603e198136030182121561000e570190565b61102b610e8a565b61100a565b61ffff81160361000e57565b519060ff8216820361000e57565b919082608091031261000e57815161106181610302565b91602081015161107081610302565b91610f726060604084015161108481611030565b930161103c565b1561109257565b60405162461bcd60e51b815260206004820152600c60248201526b37baba1037b31037b93232b960a11b6044820152606490fd5b61ffff90811660011901919082116110da57565b6110e2610fc9565b565b61ffff91821690821603919082116110da57565b156110ff57565b60405162461bcd60e51b815260206004820152601c60248201527f617373657274286e6f207375626d697373696f6e2070726f6f667329000000006044820152606490fd5b91909161ffff808094169116019182116110da57565b1561116157565b60405162461bcd60e51b8152602060048201526019602482015278617373657274287375626d697373696f6e2070726f6f66732960381b6044820152606490fd5b903590601e198136030182121561000e57018035906001600160401b03821161000e57602001918160051b3603831361000e57565b9060016001600160401b03809316019182116110da57565b156111f657565b60405162461bcd60e51b81526020600482015260166024820152751c1c9bdbd988185b1c9958591e481d995c9a599a595960521b6044820152606490fd5b6020906001600160401b03811161124c5760051b0190565b610eba610ebf565b9061125e82611234565b61126b6040519182610f2c565b828152809261127c601f1991611234565b0190602036910137565b602090805115611294570190565b610ffc610e8a565b60209181518110156112b1575b60051b010190565b6112b9610e8a565b6112a9565b156112c557565b606460405162461bcd60e51b815260206004820152602060248201527f6d65726b6c6520696e74657276616c2070726f6f6620697320696e76616c69646044820152fd5b91959790989396929661131f61ffff8a16611254565b9760005b61ffff8b1661ffff821610156113905761138b906113508d8b61ffff6113488d610fe0565b9c1691610ea1565b35807f543093db8d78fd8619586d3a0be12a5736836393feede0888f262888c81ce4c3600080a261138561ffff83168d61129c565b52610fe0565b611323565b50949950945094509490956113a59087611144565b61ffff600160ff87161b9116116113c9576110e2956113c3946114dd565b146112be565b60405162461bcd60e51b815260206004820152600f60248201526e746f6f206d616e792070726f6f667360881b6044820152606490fd5b60ff168015611411575b6000190190565b611419610fc9565b61140a565b1561142557565b60405162461bcd60e51b815260206004820152601b60248201527f696e74657276616c50726f6f6620746f6f2073686f72742028312900000000006044820152606490fd5b60019063ffffffff809116908114610ff4570190565b61ffff168015611411576000190190565b1561149857565b60405162461bcd60e51b815260206004820152601b60248201527f696e74657276616c50726f6f6620746f6f2073686f72742028322900000000006044820152606490fd5b9193906000905b60ff84166114fe5750505050506114fa90611286565b5190565b855161ffff16956001968783169061154361153e6108566115346115228686611144565b8d61152d878b611144565b1690611144565b60011c617fff1690565b611254565b926000908a838184961461168a575b50889392918b828a935b611600575b9161158d9997959391617fff9997959361ffff80961614611593575b50505050505050971c1693611400565b926114e4565b6115f3956115e1946115d26115ca6115da958963ffffffff946115b987878c1610611491565b6115c281610fe0565b50169061129c565b51959e61146a565b9d1691610ea1565b35906116e3565b926115eb81610fe0565b50168361129c565b523886818088818d61157d565b9550509192905061ffff89898d87848616111561167d57505050908161166961165761163a61166f9561163289610fe0565b98168761129c565b51611650846116488a610fe0565b99168861129c565b51906116e3565b9161166189610fe0565b98168961129c565b526110c6565b92889392918b828a9361155c565b9196909395949250611561565b9450925090506116b763ffffffff6116a589828a161061141e565b6116ae8861146a565b9716888b610ea1565b35906116dc6116ca849361165084611286565b9484956116d688611286565b52611480565b9238611552565b6040918251916116f283610f11565b83368437825260208201522090565b9081602091031261000e5751610f7281610302565b1561171d57565b60405162461bcd60e51b81526020600482015260146024820152731a5b9d985b1a59081b9d5b481d995c9a599a595960621b6044820152606490fd5b9160409060209260018201918281116117bf575b61178e61177984611234565b9361178686519586610f2c565b808552611234565b8386019690601f19013688378351156117b2575b865260051b928392013701902090565b6117ba610e8a565b6117a2565b6117c7610fc9565b61176d565b9081606091031261000e5780516117e281610302565b91610f726040602084015161108481611030565b156117fd57565b60405162461bcd60e51b815260206004820152601260248201527137379039bab1b41039bab136b4b9b9b4b7b760711b6044820152606490fd5b35610f7281611030565b1561184857565b60405162461bcd60e51b81526020600482015260156024820152746c6f636174696f6e206f7574206f662072616e676560581b6044820152606490fd5b6002549093919291906118a0906001600160a01b03166101c8565b92813592606060405180966332bde3f160e21b825281806118c989600483019190602083019252565b03915afa91821561199e575b60009586908794611967575b506118f66001600160401b03881615156117f6565b611919604086019761033661190a8a611837565b61ffff80809616911610611841565b908061192489611837565b92169116101561195b576119426119539261194892610f7299611759565b95611837565b9260208101906111a2565b9490936119bd565b50505050505050600090565b9196505061198d91925060603d8111611997575b6119858183610f2c565b8101906117cc565b92919590386118e1565b503d61197b565b6119a6610f75565b6118d5565b60ff6001911660ff8114610ff4570190565b949192909360ff928385168103611a47576000925b8486166119e3575050505050501490565b617fff611a2291600198959697989586821615600014611a2a57611a17906115da8a611a0e8b6119ab565b9a168789610ea1565b955b1c169396611400565b9493926119d2565b611a4190611a3b8a611a0e8b6119ab565b356116e3565b95611a19565b60405162461bcd60e51b81526020600482015260146024820152730d2dcecc2d8d2c840e0e4dedecc40d8cadccee8d60631b6044820152606490fd5b908160a091031261000e57611af460806040519260a084018481106001600160401b03821117611afc575b604052805184526020810151611ac381610302565b60208501526040810151611ad681610302565b60408501526060810151611ae981611030565b60608501520161103c565b608082015290565b611b04610ebf565b611aae565b15611b1057565b60405162461bcd60e51b81526020600482015260176024820152766d756c74692d70726f6f6620286368616c6c656e67652960481b6044820152606490fd5b15611b5657565b60405162461bcd60e51b815260206004820152601b60248201527f50726f6f662064696765737420646f6573206e6f74206d6174636800000000006044820152606490fd5b6001600160401b0390811660001901919082116110da57565b15611bbb57565b60405162461bcd60e51b8152602060048201526011602482015270141c9bdbd9881b9bdd081cdada5c1c1959607a1b6044820152606490fd5b15611bfb57565b60405162461bcd60e51b815260206004820152600e60248201526d141c9bdbd9881d995c9a599a595960921b6044820152606490fd5b9080601f8301121561000e5760405191611c4a83610f11565b82906040810192831161000e57905b828210611c665750505090565b8151815260209182019101611c59565b81601f8201121561000e57604090815192611c9084610f11565b8390608083019281841161000e57915b838310611caf57505050505090565b60208591611cbd8486611c31565b815201920191611ca0565b90602091828183031261000e5780516001600160401b039182821161000e5701926101e08484031261000e57604091825194611d0386610ef6565b611d0d8582611c31565b8652611d1b85858301611c76565b83870152611d2c8560c08301611c76565b84870152611d3e856101408301611c76565b60608701526101c081015191821161000e57019083601f8301121561000e578151611d6881611234565b94611d7585519687610f2c565b818652828087019260061b8501019381851161000e578301915b848310611da457505050505050608082015290565b838691611db18486611c31565b815201920191611d8f565b9081602091031261000e5751801515810361000e5790565b604090816024823760646000838381015b60028310611dfa575050505060c060e4910137565b908082818660019537019301910190918490611de5565b6000915b60028310611e2257505050565b600190825181526020809101920192019190611e15565b906000905b60028210611e4b57505050565b6020604082611e5d6001948751611e11565b01930191019091611e3e565b929091611e7584611dd4565b610140610100850181905284018190526001600160fb1b03811161000e5760059291921b8061016092838601378301926101208282860301910152611ec261034084019184018351611e11565b6020611ed6818401516101a0860190611e39565b806103606080604095611ef1878201516102208a0190611e39565b611f0460608201516102a08a0190611e39565b0151956101e06103208201528651809552019401926000905b838210611f2c57505050505090565b9091929394838282611f416001948a51611e11565b0196019493920190611f1d565b15611f5557565b60405162461bcd60e51b815260206004820152601860248201527710da185b1b195b99d9481b9bdd081cdd58d8d95cdcd99d5b60421b6044820152606490fd5b6040516020810190611fa682611dd4565b610100815261012081018181106001600160401b03821117611fcc575b60405251902090565b611fd4610ebf565b611fc3565b15611fe057565b60405162461bcd60e51b815260206004820152600960248201526837b7363ca7bbb732b960b91b6044820152606490fd5b1561201857565b60405162461bcd60e51b815260206004820152601f60248201527f66696e616c206469676573742028682920646f6573206e6f74206d61746368006044820152606490fd5b908092918237016000815290565b3d156120b3573d906001600160401b0382116120a6575b6040519161209a601f8201601f191660200184610f2c565b82523d6000602084013e565b6120ae610ebf565b612082565b606090565b156120bf57565b60405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606490fd5b60209193929361210381611254565b9060051b92839101918237206001600160801b0381166101808401350361216f576110e29260009261213f849360801c6101a084013514612011565b60045483906001600160a01b03169261215d6040518094819361205d565b03925af161216961206b565b506120b8565b60405162461bcd60e51b815260206004820152601f60248201527f66696e616c2064696765737420286c2920646f6573206e6f74206d61746368006044820152606490fd5b6007548110156121d0575b600760005260206000200190600090565b6121d8610e8a565b6121bf565b670fffffffffffffff8160041c16906007548210806000146122295761ffff9260f0911561221c575b6007600052602060002001549160041b161c1690565b612224610e8a565b612206565b505050600090565b6001600160801b03908116600101919082116110da57565b1561225057565b60405162461bcd60e51b815260206004820152600d60248201526c0eccac6e8dee440d8cadccee8d609b1b6044820152606490fd5b1561228c57565b60405162461bcd60e51b815260206004820152600c60248201526b766563746f7220656e74727960a01b6044820152606490fd5b9060f0670fffffffffffffff8360041c169260041b1661ffff809216811b91600754841060001461233357916123189161231085946123016110e2976121b4565b9190931b1992549060031b1c90565b1617916121b4565b90919082549060031b600019811b9283911b16911916179055565b50506123806123768360016110e29501600755600760005283816020600020015561237160075460018060801b0361236a84612231565b1614612249565b6121b4565b90549060031b1c90565b14612285565b60f0670fffffffffffffff8260041c169160041b166001811b9060075483106000146123c45782916123189161231061ffff6123016110e2976121b4565b5060018201600790815560008190527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6888301829055546110e29261241791612371906001600160801b0361236a84612231565b90549060031b1c1461228556fea2646970667358221220ae158f9e02614b03dd1b5d39e989e393ad644b36b04f9c6678bcab473076201a64736f6c634300081100330000000000000000000000000d3523576b3d656678fd173e496a7b2be5e966830000000000000000000000007ee56e7332b4471c71e5d6a733e858e930aad585000000000000000000000000b85eb64229a46ee784ee504bc583e0820551fa7c000000000000000000000000af0e17dc4de072b9b6a356c51418e017804c560d000000000000000000000000af0e17dc4de072b9b6a356c51418e017804c560d

Deployed Bytecode

0x60806040526004361015610013575b600080fd5b60003560e01c80630fdb8dca1461018657806319c813be1461017d5780631e00b6b6146101745780631e035f371461016b5780634d547ada146101625780634deda90014610159578063650b3ca1146101505780636a872ed9146101475780638da5cb5b1461013e57806397ee1144146101355780639fabac471461011a578063a5a9504e1461012c578063ad9b484d14610123578063addef8ae1461011a578063c26f6d4414610111578063c68ed32b14610108578063d6ae6a90146100ff578063d6af8da4146100f65763d87366ad146100ee57600080fd5b61000e610bf7565b5061000e610bcc565b5061000e610ba2565b5061000e610b1e565b5061000e610adf565b5061000e6105db565b5061000e610666565b5061000e610627565b5061000e6105b1565b5061000e610587565b5061000e610520565b5061000e6104c8565b5061000e6103c9565b5061000e61036f565b5061000e610347565b5061000e610313565b5061000e6102d8565b5061000e61019a565b600091031261000e57565b503461000e576000806003193601126102d5576002546101fd906004906020906101d4906001600160a01b03165b6001600160a01b031690565b60405163fb8bb1f760e01b815292839182905afa9081156102c8575b839161029a575b50611b9b565b6003548290610214906001600160a01b03166101c8565b6001546001600160a01b03169290803b1561029657604051630f58b8a760e01b81526001600160a01b0390941660048501526001600160401b0390911660248401528290818381604481015b03925af18015610289575b610273575080f35b8061028061028692610ed6565b8061018f565b80f35b610291610f75565b61026b565b8280fd5b6102bb915060203d81116102c1575b6102b38183610f2c565b810190611701565b386101f7565b503d6102a9565b6102d0610f75565b6101f0565b80fd5b503461000e57600036600319011261000e576005546040516001600160a01b039091168152602090f35b6001600160401b0381160361000e57565b503461000e57602036600319011261000e57602061033b60043561033681610302565b6121dd565b61ffff60405191168152f35b503461000e57600036600319011261000e5760206001600160401b0360065416604051908152f35b503461000e57600036600319011261000e576001546040516001600160a01b039091168152602090f35b9181601f8401121561000e578235916001600160401b03831161000e576020808501948460051b01011161000e57565b503461000e57604036600319011261000e576024356001600160401b03811161000e5761ffff61045761043d602061041361040a6001963690600401610399565b90600435611759565b858060a01b0360025416604051808095819463d3b3a1a960e01b8352600483019190602083019252565b03915afa90811561048e575b600091610470575b506121dd565b1661046460028210611716565b60405191148152602090f35b610488915060203d81116102c1576102b38183610f2c565b38610451565b610496610f75565b610449565b9181601f8401121561000e578235916001600160401b03831161000e576020838186019501011161000e57565b503461000e57604036600319011261000e576001600160401b0360043581811161000e576104fa903690600401610399565b9060243592831161000e5761051661051e93369060040161049b565b9290916120f4565b005b503461000e5760031960603682011261000e576001600160401b0360243581811161000e57610553903690600401610399565b9260443592831161000e57606090833603011261000e5760209261057d9260040191600435611885565b6040519015158152f35b503461000e57600036600319011261000e576000546040516001600160a01b039091168152602090f35b503461000e57600036600319011261000e576003546040516001600160a01b039091168152602090f35b503461000e57600036600319011261000e576002546040516001600160a01b039091168152602090f35b602090600319011261000e576004356001600160a01b038116810361000e5790565b503461000e5761063636610605565b6000546001600160a01b0391906106509083163314611fd9565b1660018060a01b03196003541617600355600080f35b503461000e57606036600319011261000e576004356001600160401b03811161000e5761069790369060040161049b565b6024356001600160401b03811161000e576106b6903690600401610399565b6044939193356001600160401b03811161000e576106d8903690600401610399565b60018054909692906001600160a01b03163303610aad57956106fe620100008510610e4a565b600554819060a01c6001600160401b0316926107226006546001600160401b031690565b9860009182945b610787575b505050505061051e9561076661078292600554906001600160401b0360a01b9060a01b16906001600160401b0360a01b191617600555565b6001600160401b03166001600160401b03196006541617600655565b6120f4565b90929491939961ffff85169061ffff8916821015610aa357506107ab908888610ea1565b600254903594906107c4906001600160a01b03166101c8565b604080516305160b7760e11b815260048101889052919691948d9180876024818c5afa988915610a96575b600097889a610a61575b506001600160401b0388169384156108ab5750505050916108969161084761089c946108406108346005546001600160401b039060a01c1690565b6001600160401b031690565b111561108b565b61086361085d610856886121dd565b61ffff1690565b156111ef565b61086c86612386565b7f543093db8d78fd8619586d3a0be12a5736836393feede0888f262888c81ce4c3600080a2610fe0565b926111d7565b93945b9290839a94959a610729565b6108de939a5061ffff929698506108d5919550608094506108cf8884831610610f82565b9f610fe0565b9e168588611000565b925163cccb79e560e01b81528335600482015291829060249082905afa918215610a54575b8989600094859986958792610a05575b50906109366001600160401b038a959493166001600160401b038916101561108b565b61093f876121dd565b809561094b82896110e4565b6109598761ffff88166110e4565b61ffff811661ffff8316106000146109f957509a8b9586925b61098161ffff851615156110f8565b61098b8486611144565b9a61ffff1661ffff819c1611156109a19061115a565b6109ae60208201826111a2565b92909135976109bc98611309565b6109c591611144565b946109cf91611144565b6109d981846122c0565b61ffff16036109f3576109eb906111d7565b935b9461089f565b936109ed565b90509a8b958692610972565b6109369b506001600160401b039750610a3c919650899493925060803d608011610a4d575b610a348183610f2c565b81019061104a565b919c92985096939450919290610913565b503d610a2a565b610a5c610f75565b610903565b90995081610a859298503d8911610a8f575b610a7d8183610f2c565b810190610f4d565b96909698386107f9565b503d610a73565b610a9e610f75565b6107ef565b9a5082955061072e565b60405162461bcd60e51b815260206004820152600a60248201526937b7363cabb7b935b2b960b11b6044820152606490fd5b503461000e57610aee36610605565b6000546001600160a01b039190610b089083163314611fd9565b1660018060a01b03196001541617600155600080f35b503461000e576000806003193601126102d5576003546001546005546001600160a01b039182169284921690610b5f9060a01c6001600160401b0316611b9b565b90803b1561029657604051635611757360e01b81526001600160a01b0390941660048501526001600160401b039091166024840152829081838160448101610260565b503461000e57600036600319011261000e576004546040516001600160a01b039091168152602090f35b503461000e57600036600319011261000e5760206001600160401b0360055460a01c16604051908152f35b503461000e5761014036600319011261000e5760043561010036602319011261000e57610124356001600160401b039182821161000e57610c3f610c83923690600401610399565b91610c4b838383611759565b60025460a090610c63906001600160a01b03166101c8565b9160405180978192631d5b74e960e21b8352600483019190602083019252565b0381845afa948515610e3d575b600095610e0d575b5061ffff94856060820151610cae9061ffff1690565b16600114610cbb90611b09565b8051610cc5611f95565b14610ccf90611b4f565b602001516001600160401b03169460055496808860a01c16610cf090611b9b565b610cff91888116911611611bb4565b610d08866121dd565b1615610d1390611bf4565b60405163405ef34760e01b81526004810192909252816024815a93600094fa610d9695610d9194610d6e946020948415610e00575b600094610ddd575b50604051633fb5881960e01b81529586948593849360048501611e69565b03916001600160a01b03165afa908115610dd0575b600091610da2575b50611f4e565b612386565b60405160018152602090f35b610dc3915060203d8111610dc9575b610dbb8183610f2c565b810190611dbc565b38610d8b565b503d610db1565b610dd8610f75565b610d83565b610df991943d8091833e610df18183610f2c565b810190611cc8565b9238610d50565b610e08610f75565b610d48565b610e2f91955060a03d8111610e36575b610e278183610f2c565b810190611a83565b9338610c98565b503d610e1d565b610e45610f75565b610c90565b15610e5157565b60405162461bcd60e51b8152602060048201526011602482015270746f6f206d616e792070726f6f6649647360781b6044820152606490fd5b50634e487b7160e01b600052603260045260246000fd5b9190811015610eb2575b60051b0190565b610eba610e8a565b610eab565b50634e487b7160e01b600052604160045260246000fd5b6001600160401b038111610ee957604052565b610ef1610ebf565b604052565b60a081019081106001600160401b03821117610ee957604052565b604081019081106001600160401b03821117610ee957604052565b90601f801991011681019081106001600160401b03821117610ee957604052565b919082604091031261000e5760208251610f6681610302565b920151610f7281610302565b90565b506040513d6000823e3d90fd5b15610f8957565b60405162461bcd60e51b815260206004820152601860248201527736b4b9b9b4b7339039bab136b4b9b9b4b7b710383937b7b360411b6044820152606490fd5b50634e487b7160e01b600052601160045260246000fd5b60019061ffff809116908114610ff4570190565b610ffc610fc9565b0190565b9190811015611023575b60051b81013590603e198136030182121561000e570190565b61102b610e8a565b61100a565b61ffff81160361000e57565b519060ff8216820361000e57565b919082608091031261000e57815161106181610302565b91602081015161107081610302565b91610f726060604084015161108481611030565b930161103c565b1561109257565b60405162461bcd60e51b815260206004820152600c60248201526b37baba1037b31037b93232b960a11b6044820152606490fd5b61ffff90811660011901919082116110da57565b6110e2610fc9565b565b61ffff91821690821603919082116110da57565b156110ff57565b60405162461bcd60e51b815260206004820152601c60248201527f617373657274286e6f207375626d697373696f6e2070726f6f667329000000006044820152606490fd5b91909161ffff808094169116019182116110da57565b1561116157565b60405162461bcd60e51b8152602060048201526019602482015278617373657274287375626d697373696f6e2070726f6f66732960381b6044820152606490fd5b903590601e198136030182121561000e57018035906001600160401b03821161000e57602001918160051b3603831361000e57565b9060016001600160401b03809316019182116110da57565b156111f657565b60405162461bcd60e51b81526020600482015260166024820152751c1c9bdbd988185b1c9958591e481d995c9a599a595960521b6044820152606490fd5b6020906001600160401b03811161124c5760051b0190565b610eba610ebf565b9061125e82611234565b61126b6040519182610f2c565b828152809261127c601f1991611234565b0190602036910137565b602090805115611294570190565b610ffc610e8a565b60209181518110156112b1575b60051b010190565b6112b9610e8a565b6112a9565b156112c557565b606460405162461bcd60e51b815260206004820152602060248201527f6d65726b6c6520696e74657276616c2070726f6f6620697320696e76616c69646044820152fd5b91959790989396929661131f61ffff8a16611254565b9760005b61ffff8b1661ffff821610156113905761138b906113508d8b61ffff6113488d610fe0565b9c1691610ea1565b35807f543093db8d78fd8619586d3a0be12a5736836393feede0888f262888c81ce4c3600080a261138561ffff83168d61129c565b52610fe0565b611323565b50949950945094509490956113a59087611144565b61ffff600160ff87161b9116116113c9576110e2956113c3946114dd565b146112be565b60405162461bcd60e51b815260206004820152600f60248201526e746f6f206d616e792070726f6f667360881b6044820152606490fd5b60ff168015611411575b6000190190565b611419610fc9565b61140a565b1561142557565b60405162461bcd60e51b815260206004820152601b60248201527f696e74657276616c50726f6f6620746f6f2073686f72742028312900000000006044820152606490fd5b60019063ffffffff809116908114610ff4570190565b61ffff168015611411576000190190565b1561149857565b60405162461bcd60e51b815260206004820152601b60248201527f696e74657276616c50726f6f6620746f6f2073686f72742028322900000000006044820152606490fd5b9193906000905b60ff84166114fe5750505050506114fa90611286565b5190565b855161ffff16956001968783169061154361153e6108566115346115228686611144565b8d61152d878b611144565b1690611144565b60011c617fff1690565b611254565b926000908a838184961461168a575b50889392918b828a935b611600575b9161158d9997959391617fff9997959361ffff80961614611593575b50505050505050971c1693611400565b926114e4565b6115f3956115e1946115d26115ca6115da958963ffffffff946115b987878c1610611491565b6115c281610fe0565b50169061129c565b51959e61146a565b9d1691610ea1565b35906116e3565b926115eb81610fe0565b50168361129c565b523886818088818d61157d565b9550509192905061ffff89898d87848616111561167d57505050908161166961165761163a61166f9561163289610fe0565b98168761129c565b51611650846116488a610fe0565b99168861129c565b51906116e3565b9161166189610fe0565b98168961129c565b526110c6565b92889392918b828a9361155c565b9196909395949250611561565b9450925090506116b763ffffffff6116a589828a161061141e565b6116ae8861146a565b9716888b610ea1565b35906116dc6116ca849361165084611286565b9484956116d688611286565b52611480565b9238611552565b6040918251916116f283610f11565b83368437825260208201522090565b9081602091031261000e5751610f7281610302565b1561171d57565b60405162461bcd60e51b81526020600482015260146024820152731a5b9d985b1a59081b9d5b481d995c9a599a595960621b6044820152606490fd5b9160409060209260018201918281116117bf575b61178e61177984611234565b9361178686519586610f2c565b808552611234565b8386019690601f19013688378351156117b2575b865260051b928392013701902090565b6117ba610e8a565b6117a2565b6117c7610fc9565b61176d565b9081606091031261000e5780516117e281610302565b91610f726040602084015161108481611030565b156117fd57565b60405162461bcd60e51b815260206004820152601260248201527137379039bab1b41039bab136b4b9b9b4b7b760711b6044820152606490fd5b35610f7281611030565b1561184857565b60405162461bcd60e51b81526020600482015260156024820152746c6f636174696f6e206f7574206f662072616e676560581b6044820152606490fd5b6002549093919291906118a0906001600160a01b03166101c8565b92813592606060405180966332bde3f160e21b825281806118c989600483019190602083019252565b03915afa91821561199e575b60009586908794611967575b506118f66001600160401b03881615156117f6565b611919604086019761033661190a8a611837565b61ffff80809616911610611841565b908061192489611837565b92169116101561195b576119426119539261194892610f7299611759565b95611837565b9260208101906111a2565b9490936119bd565b50505050505050600090565b9196505061198d91925060603d8111611997575b6119858183610f2c565b8101906117cc565b92919590386118e1565b503d61197b565b6119a6610f75565b6118d5565b60ff6001911660ff8114610ff4570190565b949192909360ff928385168103611a47576000925b8486166119e3575050505050501490565b617fff611a2291600198959697989586821615600014611a2a57611a17906115da8a611a0e8b6119ab565b9a168789610ea1565b955b1c169396611400565b9493926119d2565b611a4190611a3b8a611a0e8b6119ab565b356116e3565b95611a19565b60405162461bcd60e51b81526020600482015260146024820152730d2dcecc2d8d2c840e0e4dedecc40d8cadccee8d60631b6044820152606490fd5b908160a091031261000e57611af460806040519260a084018481106001600160401b03821117611afc575b604052805184526020810151611ac381610302565b60208501526040810151611ad681610302565b60408501526060810151611ae981611030565b60608501520161103c565b608082015290565b611b04610ebf565b611aae565b15611b1057565b60405162461bcd60e51b81526020600482015260176024820152766d756c74692d70726f6f6620286368616c6c656e67652960481b6044820152606490fd5b15611b5657565b60405162461bcd60e51b815260206004820152601b60248201527f50726f6f662064696765737420646f6573206e6f74206d6174636800000000006044820152606490fd5b6001600160401b0390811660001901919082116110da57565b15611bbb57565b60405162461bcd60e51b8152602060048201526011602482015270141c9bdbd9881b9bdd081cdada5c1c1959607a1b6044820152606490fd5b15611bfb57565b60405162461bcd60e51b815260206004820152600e60248201526d141c9bdbd9881d995c9a599a595960921b6044820152606490fd5b9080601f8301121561000e5760405191611c4a83610f11565b82906040810192831161000e57905b828210611c665750505090565b8151815260209182019101611c59565b81601f8201121561000e57604090815192611c9084610f11565b8390608083019281841161000e57915b838310611caf57505050505090565b60208591611cbd8486611c31565b815201920191611ca0565b90602091828183031261000e5780516001600160401b039182821161000e5701926101e08484031261000e57604091825194611d0386610ef6565b611d0d8582611c31565b8652611d1b85858301611c76565b83870152611d2c8560c08301611c76565b84870152611d3e856101408301611c76565b60608701526101c081015191821161000e57019083601f8301121561000e578151611d6881611234565b94611d7585519687610f2c565b818652828087019260061b8501019381851161000e578301915b848310611da457505050505050608082015290565b838691611db18486611c31565b815201920191611d8f565b9081602091031261000e5751801515810361000e5790565b604090816024823760646000838381015b60028310611dfa575050505060c060e4910137565b908082818660019537019301910190918490611de5565b6000915b60028310611e2257505050565b600190825181526020809101920192019190611e15565b906000905b60028210611e4b57505050565b6020604082611e5d6001948751611e11565b01930191019091611e3e565b929091611e7584611dd4565b610140610100850181905284018190526001600160fb1b03811161000e5760059291921b8061016092838601378301926101208282860301910152611ec261034084019184018351611e11565b6020611ed6818401516101a0860190611e39565b806103606080604095611ef1878201516102208a0190611e39565b611f0460608201516102a08a0190611e39565b0151956101e06103208201528651809552019401926000905b838210611f2c57505050505090565b9091929394838282611f416001948a51611e11565b0196019493920190611f1d565b15611f5557565b60405162461bcd60e51b815260206004820152601860248201527710da185b1b195b99d9481b9bdd081cdd58d8d95cdcd99d5b60421b6044820152606490fd5b6040516020810190611fa682611dd4565b610100815261012081018181106001600160401b03821117611fcc575b60405251902090565b611fd4610ebf565b611fc3565b15611fe057565b60405162461bcd60e51b815260206004820152600960248201526837b7363ca7bbb732b960b91b6044820152606490fd5b1561201857565b60405162461bcd60e51b815260206004820152601f60248201527f66696e616c206469676573742028682920646f6573206e6f74206d61746368006044820152606490fd5b908092918237016000815290565b3d156120b3573d906001600160401b0382116120a6575b6040519161209a601f8201601f191660200184610f2c565b82523d6000602084013e565b6120ae610ebf565b612082565b606090565b156120bf57565b60405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606490fd5b60209193929361210381611254565b9060051b92839101918237206001600160801b0381166101808401350361216f576110e29260009261213f849360801c6101a084013514612011565b60045483906001600160a01b03169261215d6040518094819361205d565b03925af161216961206b565b506120b8565b60405162461bcd60e51b815260206004820152601f60248201527f66696e616c2064696765737420286c2920646f6573206e6f74206d61746368006044820152606490fd5b6007548110156121d0575b600760005260206000200190600090565b6121d8610e8a565b6121bf565b670fffffffffffffff8160041c16906007548210806000146122295761ffff9260f0911561221c575b6007600052602060002001549160041b161c1690565b612224610e8a565b612206565b505050600090565b6001600160801b03908116600101919082116110da57565b1561225057565b60405162461bcd60e51b815260206004820152600d60248201526c0eccac6e8dee440d8cadccee8d609b1b6044820152606490fd5b1561228c57565b60405162461bcd60e51b815260206004820152600c60248201526b766563746f7220656e74727960a01b6044820152606490fd5b9060f0670fffffffffffffff8360041c169260041b1661ffff809216811b91600754841060001461233357916123189161231085946123016110e2976121b4565b9190931b1992549060031b1c90565b1617916121b4565b90919082549060031b600019811b9283911b16911916179055565b50506123806123768360016110e29501600755600760005283816020600020015561237160075460018060801b0361236a84612231565b1614612249565b6121b4565b90549060031b1c90565b14612285565b60f0670fffffffffffffff8260041c169160041b166001811b9060075483106000146123c45782916123189161231061ffff6123016110e2976121b4565b5060018201600790815560008190527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6888301829055546110e29261241791612371906001600160801b0361236a84612231565b90549060031b1c1461228556fea2646970667358221220ae158f9e02614b03dd1b5d39e989e393ad644b36b04f9c6678bcab473076201a64736f6c63430008110033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000000d3523576b3d656678fd173e496a7b2be5e966830000000000000000000000007ee56e7332b4471c71e5d6a733e858e930aad585000000000000000000000000b85eb64229a46ee784ee504bc583e0820551fa7c000000000000000000000000af0e17dc4de072b9b6a356c51418e017804c560d000000000000000000000000af0e17dc4de072b9b6a356c51418e017804c560d

-----Decoded View---------------
Arg [0] : _owner (address): 0x0D3523576b3D656678Fd173E496A7B2be5e96683
Arg [1] : _worker (address): 0x7ee56E7332b4471c71e5D6A733e858E930AAD585
Arg [2] : _proofReceiver (address): 0xb85eb64229A46ee784ee504bc583E0820551fa7c
Arg [3] : _outerVerifier (address): 0xaf0e17dC4De072b9b6a356c51418e017804c560D
Arg [4] : _groth16Verifier (address): 0xaf0e17dC4De072b9b6a356c51418e017804c560D

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 0000000000000000000000000d3523576b3d656678fd173e496a7b2be5e96683
Arg [1] : 0000000000000000000000007ee56e7332b4471c71e5d6a733e858e930aad585
Arg [2] : 000000000000000000000000b85eb64229a46ee784ee504bc583e0820551fa7c
Arg [3] : 000000000000000000000000af0e17dc4de072b9b6a356c51418e017804c560d
Arg [4] : 000000000000000000000000af0e17dc4de072b9b6a356c51418e017804c560d


Deployed Bytecode Sourcemap

1893:18303:8:-:0;;;;;;;;;-1:-1:-1;1893:18303:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;;;;:::o;:::-;;;;;;;;;;;;;;19665:13;1893:18303;19665:37;;1893:18303;;19665:33;;:31;;-1:-1:-1;;;;;1893:18303:8;;-1:-1:-1;;;;;1893:18303:8;;;19665:31;1893:18303;;-1:-1:-1;;;19665:33:8;;1893:18303;;;;;19665:33;;;;;;;1893:18303;19665:33;;;;1893:18303;19665:37;;:::i;:::-;1893:18303;;;;19712:30;;-1:-1:-1;;;;;1893:18303:8;;;19712:30;19701:1;1893:18303;-1:-1:-1;;;;;1893:18303:8;;;19712:61;;;;;1893:18303;;-1:-1:-1;;;19712:61:8;;-1:-1:-1;;;;;1893:18303:8;;;;19712:61;;1893:18303;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;;;;;;;19712:61;;;;;;;;;1893:18303;19712:61;;1893:18303;;;19712:61;;;;;;:::i;:::-;;;:::i;:::-;1893:18303;;19712:61;;;:::i;:::-;;;;1893:18303;;;19665:33;;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;;;1893:18303;;;;;;;;;;-1:-1:-1;;1893:18303:8;;;;2386:39;1893:18303;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;:::o;:::-;;;;;;;-1:-1:-1;;1893:18303:8;;;;;20122:65;1893:18303;;;;;:::i;:::-;20122:65;:::i;:::-;1893:18303;;;;;;;;;;;;;;;-1:-1:-1;;1893:18303:8;;;;;-1:-1:-1;;;;;2829:42:8;1893:18303;;;;;;;;;;;;;;;-1:-1:-1;;1893:18303:8;;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;-1:-1:-1;;1893:18303:8;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;13816:99;13645:39;1893:18303;13563:49;1893:18303;;;;;;;;:::i;:::-;;;;13563:49;:::i;:::-;1893:18303;;;;;13645:13;1893:18303;;;;;;;;;;;;13645:39;;1893:18303;13645:39;;1893:18303;;;;;;;;13645:39;;;;;;;;;;1893:18303;-1:-1:-1;13645:39:8;;;1893:18303;13816:99;;:::i;:::-;1893:18303;13925:45;13645:13;13933:12;;13925:45;:::i;:::-;1893:18303;;13989:13;;1893:18303;;;;;13645:39;;;;1893:18303;13645:39;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;1893:18303;;;;;;;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;;;;;;;:::o;:::-;;;;;;;-1:-1:-1;;1893:18303:8;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;-1:-1:-1;;1893:18303:8;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;;1893:18303:8;;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;;;;;;;-1:-1:-1;;1893:18303:8;;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;;;;;;;-1:-1:-1;;1893:18303:8;;;;2170:40;1893:18303;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;:::o;:::-;;;;;;;;:::i;:::-;17888:5;1893:18303;-1:-1:-1;;;;;1893:18303:8;;17866:41;;1893:18303;;17874:10;:19;17866:41;:::i;:::-;1893:18303;;;;;;;17785:37;1893:18303;;;17785:37;1893:18303;17888:5;1893:18303;;;;;;;;;-1:-1:-1;;1893:18303:8;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1;;;;;1893:18303:8;17971:10;:20;1893:18303;;4744:27;4736:57;4763:7;4744:27;;4736:57;:::i;:::-;5986:25;1893:18303;;;;;-1:-1:-1;;;;;1893:18303:8;;;6055:28;1893:18303;-1:-1:-1;;;;;1893:18303:8;;;;6216:21;-1:-1:-1;6094:29:8;;6268:5574;1893:18303;;;6268:5574;11852:45;;;;;12040:5;11852:45;;11907:55;11852:45;5986:25;1893:18303;;-1:-1:-1;;;;;1893:18303:8;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;5986:25;1893:18303;;11852:45;-1:-1:-1;;;;;1893:18303:8;-1:-1:-1;;;;;1893:18303:8;6055:28;1893:18303;;;6055:28;1893:18303;;11907:55;12040:5;:::i;6268:5574::-;1893:18303;;;;;;;;;;;;;6275:24;;;;;6462:20;;;;;;:::i;:::-;6807:13;1893:18303;;;;;6807:56;;-1:-1:-1;;;;;1893:18303:8;;;6807:56;1893:18303;;;-1:-1:-1;;;6807:65:8;;1893:18303;6807:65;;1893:18303;;;;;;;;;;;;;;6807:65;;;;;;;6268:5574;-1:-1:-1;;;6807:65:8;;;6268:5574;-1:-1:-1;;;;;;1893:18303:8;;;6890:18;;;;1893:18303;;;;;7624:12;1893:18303;6928:125;7674:17;1893:18303;6957:42;1893:18303;5986:25;1893:18303;-1:-1:-1;;;;;1893:18303:8;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;6957:42;-1:-1:-1;6957:42:8;6928:125;:::i;:::-;7128:233;7157:140;:135;;;:::i;:::-;1893:18303;;;;7157:140;;7128:233;:::i;:::-;7379:146;;;:::i;:::-;7583:22;-1:-1:-1;7583:22:8;;7624:12;:::i;:::-;7674:17;;:::i;:::-;7709:48;6886:4946;;6268:5574;;;;;;;;;6886:4946;8139:84;1893:18303;;;;;;;;8181:20;1893:18303;;;8758:102;1893:18303;;7912:139;1893:18303;;;;7941:44;7912:139;:::i;:::-;8181:20;;:::i;:::-;1893:18303;;8139:84;;;:::i;:::-;1893:18303;;-1:-1:-1;;;8758:102:8;;1893:18303;;;8758:102;;1893:18303;;;;;;;;8758:102;;;;;;;6886:4946;8758:102;;-1:-1:-1;;;;;;;8758:102:8;;;6886:4946;1893:18303;;8951:59;-1:-1:-1;;;;;1893:18303:8;;;;;-1:-1:-1;;;;;1893:18303:8;;8959:34;;8951:59;:::i;:::-;9488:123;;;:::i;:::-;9886:32;;;;;;:::i;:::-;9965:24;1893:18303;;;;9965:24;:::i;:::-;1893:18303;;;;;;10038:32;10037:113;1893:18303;;;10037:113;;;;;;;10445:123;1893:18303;;;10474:24;;10445:123;:::i;:::-;10615:31;;;;:::i;:::-;1893:18303;;;;;;;10615:56;;10586:152;;;:::i;:::-;10871:28;1893:18303;10871:28;;;;:::i;:::-;1893:18303;;;;11025:15;;;;:::i;:::-;11109:34;;;:::i;:::-;11182:31;;;;:::i;:::-;11231:156;;;;:::i;:::-;1893:18303;;11556:36;;;11636:17;;;:::i;:::-;11552:200;;6886:4946;;;11552:200;;;;10037:113;;;;;;;;;;8758:102;8951:59;8758:102;;-1:-1:-1;;;;;8758:102:8;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;-1:-1:-1;8758:102:8;;;-1:-1:-1;8758:102:8;;;;;;;;;;;;;:::i;:::-;;;6807:65;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;6275:24;;;;;;;;1893:18303;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;;;;:::i;:::-;17888:5;1893:18303;-1:-1:-1;;;;;1893:18303:8;;17866:41;;1893:18303;;17874:10;:19;17866:41;:::i;:::-;1893:18303;;;;;;;;;;;;;17888:5;1893:18303;;;;;;;;;;;;;;;;;;;;19926:25;1893:18303;-1:-1:-1;;;;;1893:18303:8;;;;;;;;19926:29;;1893:18303;;-1:-1:-1;;;;;1893:18303:8;19926:29;:::i;:::-;19890:66;;;;;;1893:18303;;-1:-1:-1;;;19890:66:8;;-1:-1:-1;;;;;1893:18303:8;;;;19890:66;;1893:18303;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;;;;;;;19890:66;1893:18303;;;;;;;;-1:-1:-1;;1893:18303:8;;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;;;;;;;-1:-1:-1;;1893:18303:8;;;;;-1:-1:-1;;;;;2575:48:8;1893:18303;;;;;;;;;;;;;;;;;-1:-1:-1;;1893:18303:8;;;;;;;;-1:-1:-1;;1893:18303:8;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;15925:54;1893:18303;;;;;;:::i;:::-;15781:83;;;;;;:::i;:::-;15925:13;1893:18303;15925:54;;:40;;-1:-1:-1;;;;;1893:18303:8;;;15925:40;1893:18303;;;;;;;;;;15925:54;;1893:18303;15925:54;;1893:18303;;;;;;;;15925:54;;;;;;;;;;;1893:18303;-1:-1:-1;15925:54:8;;;1893:18303;;;16091:20;;;;;1893:18303;;;;;;;;;16115:1;16091:25;16083:61;;;:::i;:::-;1893:18303;;16300:35;;:::i;:::-;16270:65;16249:139;;;:::i;:::-;1893:18303;16606:24;1893:18303;-1:-1:-1;;;;;1893:18303:8;;16661:25;1893:18303;;;;15925:54;1893:18303;;16661:29;;;:::i;:::-;16640:109;;1893:18303;;;;;16661:45;16640:109;:::i;:::-;16780:65;;;:::i;:::-;1893:18303;16780:86;16759:147;;;:::i;:::-;1893:18303;;-1:-1:-1;;;17038:30:8;;1893:18303;17038:30;;1893:18303;;;;;;;17038:30;;-1:-1:-1;17038:30:8;;17250:68;;17078:123;;17099:52;;1893:18303;;17038:30;;;;1893:18303;-1:-1:-1;17038:30:8;;;1893:18303;-1:-1:-1;1893:18303:8;;-1:-1:-1;;;17099:52:8;;1893:18303;;;;;;;;17099:52;;;:::i;:::-;;;-1:-1:-1;;;;;1893:18303:8;17099:52;;;;;;;1893:18303;-1:-1:-1;17099:52:8;;;1893:18303;17078:123;;:::i;:::-;17250:68;:::i;:::-;1893:18303;;16115:1;1893:18303;;;;;17099:52;;;;1893:18303;17099:52;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;;;17038:30;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;15925:54;;;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;;;;:::i;:::-;;;1893:18303;;;;:::o;:::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;:::o;:::-;;;:::i;:::-;;;:::o;:::-;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;:::o;:::-;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;:::o;:::-;;;;;;;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;:::i;:::-;;;;:::o;:::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;-1:-1:-1;;1893:18303:8;;;;;;;:::o;:::-;;;:::i;:::-;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;:::o;:::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;:::o;:::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;:::o;:::-;;;;:::o;:::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;;:::o;:::-;;;:::i;:::-;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;12059:1307;;;;;;;;;;12551:35;1893:18303;;;12551:35;:::i;:::-;12601:12;12612:1;12641:3;1893:18303;;;;;;12615:24;;;;12641:3;12687:10;12678:20;12687:10;;1893:18303;12687:10;;;:::i;:::-;1893:18303;;12678:20;;:::i;:::-;1893:18303;12717:22;;12612:1;12717:22;;12753:21;1893:18303;;;12753:21;;:::i;:::-;1893:18303;12641:3;:::i;:::-;12601:12;;12615:24;;;;;;;;;;;;12983:31;12615:24;12983:31;;:::i;:::-;1893:18303;13018:1;1893:18303;;;;;;12983:45;1893:18303;;13244:115;13110:124;;;;:::i;:::-;13265:36;13244:115;:::i;1893:18303::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;;;;-1:-1:-1;;1893:18303:8;;:::o;:::-;;;:::i;:::-;;;;;;;:::o;:::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;-1:-1:-1;;1893:18303:8;;:::o;:::-;;;;:::o;:::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;;;;;;;;;1472:4188:4;;;;2118:1;;1893:18303:8;;;;;;5642:11:4;;;;;;;;:::i;:::-;1893:18303:8;1472:4188:4;:::o;2158:3::-;1893:18303:8;;;;2544:1:4;;2535:10;;;;2501:45;2765:27;;2704:21;2501:95;:45;;;;:::i;:::-;2567:23;;;;;:::i;:::-;2566:29;2501:95;;:::i;:::-;1893:18303:8;;;;;;2765:27:4;;:::i;:::-;2953:19;2118:1;2986:40;;;3443:20;;3481:17;;3477:630;;2158:3;4323:481;;;;;;;;;2544:1;;;4323:481;1893:18303:8;2158:3:4;1893:18303:8;;;;;;;;;;;;;;4956:21:4;4952:599;;4323:481;5565:17;;;;;;;1893:18303:8;;;2158:3:4;;:::i;:::-;2134:15;;;4952:599;5144:133;1893:18303:8;5166:111:4;1893:18303:8;5248:10:4;5192:20;5234:25;1893:18303:8;;;;4997:129:4;1893:18303:8;;;;5026:31:4;4997:129;:::i;:::-;5201:10;;;:::i;:::-;;1893:18303:8;5192:20:4;;:::i;:::-;1893:18303:8;5248:10:4;;;:::i;:::-;1893:18303:8;;5234:25:4;;:::i;:::-;1893:18303:8;5166:111:4;;:::i;:::-;5151:11;;;;:::i;:::-;;1893:18303:8;5144:133:4;;:::i;:::-;1893:18303:8;4952:599:4;;;;;;;;;4323:481;1893:18303:8;;;;;;;;;;;;;;;4330:20:4;;;;4427:10;;;;;4370:128;4392:106;4418:20;4516:21;4427:10;;;;:::i;:::-;1893:18303:8;;4418:20:4;;:::i;:::-;1893:18303:8;4460:20:4;4469:10;;;;:::i;:::-;1893:18303:8;;4460:20:4;;:::i;:::-;1893:18303:8;4392:106:4;;:::i;:::-;4377:11;;;;:::i;:::-;1893:18303:8;;4370:128:4;;:::i;:::-;1893:18303:8;4516:21:4;:::i;:::-;4323:481;;;;;;;;;;;4330:20;;;;;;;;;;;3477:630;1893:18303:8;;;;;;3713:25:4;1893:18303:8;3518:129:4;1893:18303:8;;;;3547:31:4;3518:129;:::i;:::-;3727:10;;;:::i;:::-;1893:18303:8;;3713:25:4;;;:::i;:::-;1893:18303:8;3769:10:4;3816:18;3687:111;3769:10;3760:20;;;;:::i;3687:111::-;3672:11;;3665:133;;;;:::i;:::-;1893:18303:8;3816:18:4;:::i;:::-;3477:630;;;;757:281;1893:18303:8;757:281:4;1893:18303:8;;;;;;:::i;:::-;;;;;;;;;;;964:68:4;757:281;:::o;1893:18303:8:-;;;;;;;;;;;;;:::i;:::-;;;;:::o;:::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;-1:-1:-1;;;1893:18303:8;;;;;;;1073:954:6;;1893:18303:8;1073:954:6;1893:18303:8;1073:954:6;1512:1;1893:18303:8;;;;;;;;1073:954:6;1893:18303:8;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;-1:-1:-1;;1893:18303:8;;;;;;;;;1073:954:6;1893:18303:8;;;1767:230:6;;;;;;;;;1073:954;:::o;1893:18303:8:-;;;:::i;:::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;:::o;:::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;:::i;:::-;;;;:::o;:::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;-1:-1:-1;;;1893:18303:8;;;;;;;14016:1489;14262:13;1893:18303;14016:1489;;;;;;14262:57;;-1:-1:-1;;;;;1893:18303:8;;;14262:57;1893:18303;;;;14262:86;1893:18303;;;;;;;14262:86;;;;;;;;;1893:18303;;;;;;;;14262:86;;;;;;;;;;14016:1489;14320:27;;;;;14262:86;;;14016:1489;1893:18303;14358:48;-1:-1:-1;;;;;1893:18303:8;;14366:17;;14358:48;:::i;:::-;14882:99;1893:18303;14594:23;;;14586:69;14594:23;;;:::i;:::-;1893:18303;;;;;;;14594:35;14586:69;:::i;14882:99::-;14995:23;;;;;:::i;:::-;1893:18303;;;;14995:35;;14991:78;;15204:49;15458:26;15204:49;15417:23;15204:49;15282:216;15204:49;;:::i;:::-;15417:23;;:::i;:::-;15458:26;;;;;;:::i;:::-;15282:216;;;;:::i;14991:78::-;15046:12;;;;;;;14320:27;15046:12;:::o;14262:86::-;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;1893:18303;;;;;;;;;;;;:::o;6767:645:4:-;;;;;;1893:18303:8;;;;;6972:21:4;;1893:18303:8;;-1:-1:-1;7078:297:4;1893:18303:8;;;;;;7392:13:4;;;;;;;6767:645;:::o;7078:297::-;1893:18303:8;7357:7:4;7125:1;;;;;;;7114:12;;;;:17;7110:169;7125:1;;;7158:30;7176:10;7170:17;7176:10;;;;:::i;:::-;1893:18303:8;;7170:17:4;;;:::i;7158:30::-;7110:169;;1893:18303:8;;7331:12:4;7357:7;;:::i;:::-;7078:297;;;;;7110:169;7234:30;7245:10;7239:17;7245:10;;;;:::i;7239:17::-;1893:18303:8;7234:30:4;:::i;:::-;7110:169;;;1893:18303:8;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;:::o;:::-;;;:::i;:::-;;;;;;;:::o;:::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;-1:-1:-1;;1893:18303:8;;;;;;;:::o;:::-;;;;:::o;:::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;-1:-1:-1;;;1893:18303:8;;;;;;;2171:148:6;1893:18303:8;;2294:17:6;;;1893:18303:8;;;;:::i;:::-;2294:17:6;;;1893:18303:8;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;2171:148:6;1893:18303:8;;;2284:28:6;;2171:148;:::o;1893:18303:8:-;;;:::i;:::-;;;;;;;:::o;:::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;;;;-1:-1:-1;;1893:18303:8;;;;;:::i;:::-;;;;-1:-1:-1;1893:18303:8;;;;:::o;:::-;;;:::i;:::-;;;;;;:::o;:::-;;;;:::o;:::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;-1:-1:-1;;;1893:18303:8;;;;;;;18533:923;4163:211:6;18533:923:8;;;;4123:30:6;;;:::i;:::-;4163:211;;;;;;;;;;;-1:-1:-1;;;;;5387:29:6;;18988:174:8;;;;19179:17;1893:18303;;19416:33;1893:18303;-1:-1:-1;1893:18303:8;19242:61;1893:18303;;5401:14:6;1893:18303:8;18988:174;;;;19250:17;19242:61;:::i;:::-;19381:13;1893:18303;;;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;;:::i;:::-;19381:25;;;;;;:::i;:::-;;19416:33;:::i;1893:18303::-;;;-1:-1:-1;;;1893:18303:8;;4163:211:6;1893:18303:8;;;;;;;;;;;;;;;;;;9535:23;1893:18303;;;;;;;9535:23;-1:-1:-1;1893:18303:8;;-1:-1:-1;1893:18303:8;;;-1:-1:-1;1893:18303:8;:::o;:::-;;;:::i;:::-;;;357:559:9;1893:18303:8;;;;;;20148:23;1893:18303;571:31:9;;567:343;;571:31;;;1893:18303:8;;;;;;;567:343:9;20148:23:8;-1:-1:-1;1893:18303:8;;-1:-1:-1;1893:18303:8;;;;;;;;831:29:9;567:343;357:559::o;1893:18303:8:-;;;:::i;:::-;;;567:343:9;892:7;;;-1:-1:-1;567:343:9;357:559::o;1893:18303:8:-;-1:-1:-1;;;;;1893:18303:8;;;;;;;;;;;:::o;:::-;;;;:::o;:::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;1893:18303:8;;;;;;;;;;;;-1:-1:-1;;;1893:18303:8;;;;;;;922:2005:9;;1893:18303:8;;;;;;;;;;213:6:9;1893:18303:8;;;;;;9535:23;1893:18303;1474:13:9;;1470:1451;9535:23:8;;;1519::9;1579;1519;1893:18303:8;1519:23:9;;;1579:30;1519:23;;:::i;:::-;1893:18303:8;;;;1248:23:9;1893:18303:8;;;;;;;;;1519:30:9;1518:47;1579:23;;:::i;:::-;:30;1893:18303:8;;;;;;;;;;;;;;;;;;;;;;;1470:1451:9;2019:638;;1893:18303:8;2854:23:9;2019:638;;2846:64;2019:638;;9535:23:8;2019:638:9;9535:23:8;-1:-1:-1;2019:638:9;;;;-1:-1:-1;2019:638:9;;;2770:62;9535:23:8;1893:18303;;5401:14:6;;;;2803:11:9;;;:::i;:::-;1893:18303:8;2778:36:9;2770:62;:::i;:::-;2854:23;:::i;:::-;1893:18303:8;;;;;;;;;2854:39:9;2846:64;:::i;922:2005::-;1893:18303:8;;;;;;;;;;;;;;7208:23;1893:18303;1474:13:9;;1470:1451;7208:23:8;;;1519::9;;1579;1519;1893:18303:8;213:6:9;1519:23;1579:30;1519:23;;:::i;1470:1451::-;-1:-1:-1;1893:18303:8;2019:638:9;;7208:23:8;2019:638:9;;;-1:-1:-1;2019:638:9;;;;;;;;;1893:18303:8;2846:64:9;;2854:23;;2770:62;;-1:-1:-1;;;;;2803:11:9;2019:638;2803:11;:::i;2854:23::-;1893:18303:8;;;;;;2854:39:9;2846:64;:::i

Swarm Source

ipfs://ae158f9e02614b03dd1b5d39e989e393ad644b36b04f9c6678bcab473076201a

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ 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.