ETH Price: $3,328.26 (-3.05%)

Contract

0xd9C75fD200C3bcD23D361aF00c74Db4597f7D583
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AxiomV2HeaderVerifier

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 100000 runs

Other Settings:
paris EvmVersion
File 1 of 8 : AxiomV2HeaderVerifier.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import { IAxiomV2HeaderVerifier } from "../interfaces/query/IAxiomV2HeaderVerifier.sol";
import { IAxiomV2State } from "../interfaces/core/IAxiomV2State.sol";
import { MerkleMountainRange } from "../libraries/MerkleMountainRange.sol";
import { PaddedMerkleMountainRange } from "../libraries/PaddedMerkleMountainRange.sol";
import { BLOCK_BATCH_DEPTH, BLOCK_BATCH_SIZE } from "../libraries/configuration/AxiomV2Configuration.sol";

contract AxiomV2HeaderVerifier is IAxiomV2HeaderVerifier {
    using PaddedMerkleMountainRange for PaddedMerkleMountainRange.PMMR;
    using MerkleMountainRange for MerkleMountainRange.MMR;

    address public immutable axiomCoreAddress;

    uint64 internal immutable _CHAIN_ID;

    /// @dev Initialize the contract.
    /// @param chainId The chain ID of the source chain this verifies headers from.
    /// @param _axiomCoreAddress The address of the AxiomV2Core contract.
    constructor(uint64 chainId, address _axiomCoreAddress) {
        _CHAIN_ID = chainId;

        if (_axiomCoreAddress == address(0)) {
            revert AxiomCoreAddressIsZero();
        }
        axiomCoreAddress = _axiomCoreAddress;
    }

    /// @dev This verifier handles the case of the same source and target chain. For the purpose
    ///      of this discussion, we call recent blocks to be blocks in [block.number - 256, block.number)
    ///
    ///      We make the assumption that AxiomV2Core guarantees that `blockhashPmmr` is a commitment
    ///      to block hashes up to a recent block at all times.
    ///
    ///      We consider the state of AxiomV2Core at three block times:
    ///        -- Proof time:      Time of query submission / proof initiation
    ///        -- Submission time: Time of verification tx submission
    ///        -- Execution time:  Time of verification tx execution
    ///
    ///      At proof time, let `blockhashPmmr` commit to blocks `[0, currentPmmrSize)`.
    ///      Each query also has some minimum range of blocks `[0, queryPmmrSize)` which must be accessed.
    ///        -- If `queryBlockNum <= currentBlockNum`, then we check that `blockhashMmrKeccak` is committed
    ///           to in `blockhashPmmr` using the commitment to `blockhashPmmr` in `pmmrSnapshots`.
    ///        -- Otherwise, at transaction submission time, if `blockhashPmmr` is more recent than
    ///           `queryBlockNum`, then `queryBlockNum` is committed to in `blockhashPmmr` and
    ///           we can submit witness data allowing us to check that commitment as in the previous case.
    ///        -- Otherwise, at transaction submission time, `queryBlockNum` must be recent (as otherwise
    ///           `blockhashPmmr` is recent and thus more recent).  At transaction execution time, if:
    ///           -- `queryBlockNum` is still recent, then at least one of the following must hold, and we can use
    ///              recent block hashes to verify:
    ///              -- `pmmrSnapshot` is still recent
    ///              -- `queryBlockNum <= blockhashPmmr.size`
    ///           -- If `queryBlockNum` is no longer recent, the transaction will fail.
    ///              In this case, we should resubmit with the new recent `blockhashPmmr` at time of transaction execution.
    function verifyQueryHeaders(bytes32 proofMmrKeccak, MmrWitness calldata mmrWitness) external view {
        bytes32[] memory peaks = mmrWitness.proofMmrPeaks;
        uint32 snapshotPmmrSize = mmrWitness.snapshotPmmrSize;

        if (proofMmrKeccak != keccak256(abi.encodePacked(peaks))) {
            revert ProofMmrKeccakDoesNotMatch();
        }

        uint32 proofMmrSize;
        uint256 proofMmrPeaksLength = peaks.length;
        // Get proofMmrSize from heights of witnessMmrPeaks
        for (uint256 idx; idx < proofMmrPeaksLength;) {
            if (peaks[idx] != bytes32(0)) {
                proofMmrSize = proofMmrSize + uint32(1 << idx);
            }
            unchecked {
                ++idx;
            }
        }

        if (proofMmrSize <= snapshotPmmrSize) {
            // Creating a proof PMMR with empty padded leaf and complete leaf peaks from proofMmrPeaks[BLOCK_BATCH_DEPTH:]
            PaddedMerkleMountainRange.PMMR memory proofPmmr = PaddedMerkleMountainRange.PMMR({
                paddedLeaf: bytes32(0),
                completeLeaves: MerkleMountainRange.fromPeaks(
                    peaks, BLOCK_BATCH_DEPTH, proofMmrPeaksLength - BLOCK_BATCH_DEPTH
                    ),
                size: proofMmrSize - (proofMmrSize % BLOCK_BATCH_SIZE)
            });

            MerkleMountainRange.MMR memory proofBatchMmr = MerkleMountainRange.fromPeaks(peaks, 0, BLOCK_BATCH_DEPTH);

            // We check `proofMmrPeaks` can be extended to the MMR committed to
            // in `pmmrSnapshots[mmrWitness.snapshotPmmrSize]`
            //
            // This can happen in two possible ways:
            // * If `snapshotPmmrSize - (snapshotPmmrSize % 1024) > proofMmrSize`, then we can check:
            //   -- the completion of proofMmrPeaks[:10] to a full Merkle root
            //   -- the extension of proofMmrPeaks[10:] by this Merkle root and additional Merkle roots
            //   -- the extension of the resulting MMR by a padded leaf
            //   -- this result should match `pmmrSnapshots[snapshotPmmrSize]`
            //
            // * If `snapshotPmmrSize - (snapshotPmmrSize % 1024) <= proofMmrSize`, then we can check:
            //   -- the completion of proofMmrPeaks[:10] to a full Merkle root with zero padding
            //   -- the commitment of the resulting PMMR should match `pmmrSnapshots[snapshotPmmrSize]`

            if (snapshotPmmrSize - (snapshotPmmrSize % BLOCK_BATCH_SIZE) >= proofMmrSize) {
                if (proofMmrSize % BLOCK_BATCH_SIZE > 0) {
                    // complete the first 10 peaks of `proofMmrPeaks` to a full Merkle root and update `proofPmmr`
                    bytes32 completedLeaf =
                        proofBatchMmr.getComplementMerkleRoot(BLOCK_BATCH_DEPTH, mmrWitness.mmrComplementOrPeaks);
                    proofPmmr.updatePaddedLeaf(BLOCK_BATCH_SIZE, completedLeaf, BLOCK_BATCH_SIZE);
                }

                if (snapshotPmmrSize - (snapshotPmmrSize % BLOCK_BATCH_SIZE) > proofMmrSize) {
                    // append additional complete leaves
                    proofPmmr.appendCompleteLeaves(BLOCK_BATCH_SIZE, mmrWitness.mmrComplementOrPeaks[11:]);
                }

                proofPmmr.updatePaddedLeaf(
                    BLOCK_BATCH_SIZE, mmrWitness.mmrComplementOrPeaks[10], snapshotPmmrSize % BLOCK_BATCH_SIZE
                );
            } else {
                // complete the first 10 peaks of `proofMmrPeaks` to a full Merkle root and update `proofPmmr`
                bytes32 completedLeaf =
                    proofBatchMmr.getComplementMerkleRoot(BLOCK_BATCH_DEPTH, mmrWitness.mmrComplementOrPeaks);
                proofPmmr.updatePaddedLeaf(BLOCK_BATCH_SIZE, completedLeaf, snapshotPmmrSize % BLOCK_BATCH_SIZE);
            }

            // check the resulting PMMR is committed to in `pmmrSnapshots[mmrWitness.snapshotPmmrSize]`
            bytes32 completePmmrKeccak = proofPmmr.commit();
            if (completePmmrKeccak != IAxiomV2State(axiomCoreAddress).pmmrSnapshots(snapshotPmmrSize)) {
                revert BlockhashMmrKeccakDoesNotMatchProof();
            }
        } else {
            // We check in order of preference that:
            //   * If `mmrWitness.snapshotPmmrSize >= block.number - 256`, we can check the PMMR committed to
            //     by `pmmrSnapshots[mmrWitness.snapshotPmmrSize]` can be extended to `proofMmrPeaks` by blockhashes
            //     accessible in EVM.  This happens by:
            //     -- Decommit the PMMR in `pmmrSnapshots[mmrWitness.snapshotPmmrSize]`
            //     -- Decommit the padded leaf in the decommitted PMMR.
            //     -- Extend the padded leaf with `blockhash` calls
            //     -- If necessary, extend the MMR and padding with `blockhash` calls
            //
            //   * If `proofMmrSize >= block.number - 256` and `proofMmrSize <= blockhashPmmr.size`,
            //     we can check that `proofMmrPeaks` can be extended to `blockhashPmmr` by blockhashes accessible in EVM via:
            //     -- Extend the MMR with `blockhash` calls
            //     -- Form the padded leaf and check against `blockhashPmmr`

            if (proofMmrSize > block.number) {
                revert MmrEndBlockNotRecent();
            }

            // if both mmrWitness.snapshotPmmrSize >= block.number - 256 and
            // proofMmrSize >= block.number - 256 and `proofMmrSize <= blockhashPmmr.size`
            //
            // then we have two options for which way to validate, which require calling `blockhash`
            // * case 1: `proofMmrSize - snapshotPmmrSize` times
            // * case 2: `blockhashPmmr.size - proofMmrSize` times
            //
            // we choose the smaller one
            uint32 corePmmrSize = IAxiomV2State(axiomCoreAddress).blockhashPmmrSize();
            if (
                snapshotPmmrSize >= block.number - 256
                    && (proofMmrSize > corePmmrSize || proofMmrSize - snapshotPmmrSize <= corePmmrSize - proofMmrSize)
            ) {
                // Decommit the PMMR in `pmmrSnapshots[mmrWitness.snapshotPmmrSize]`
                PaddedMerkleMountainRange.PMMR memory snapshotPmmr = PaddedMerkleMountainRange.PMMR({
                    paddedLeaf: bytes32(0),
                    completeLeaves: MerkleMountainRange.fromPeaks(
                        mmrWitness.mmrComplementOrPeaks,
                        BLOCK_BATCH_DEPTH,
                        mmrWitness.mmrComplementOrPeaks.length - BLOCK_BATCH_DEPTH
                        ),
                    size: snapshotPmmrSize - (snapshotPmmrSize % BLOCK_BATCH_SIZE)
                });

                bytes32 snapshotLeaf = MerkleMountainRange.fromPeaks(
                    mmrWitness.mmrComplementOrPeaks, 0, BLOCK_BATCH_DEPTH
                ).getZeroPaddedMerkleRoot(BLOCK_BATCH_DEPTH);

                snapshotPmmr.updatePaddedLeaf(BLOCK_BATCH_SIZE, snapshotLeaf, snapshotPmmrSize % BLOCK_BATCH_SIZE);
                bytes32 snapshotPmmrKeccak = snapshotPmmr.commit();

                if (snapshotPmmrKeccak != IAxiomV2State(axiomCoreAddress).pmmrSnapshots(snapshotPmmrSize)) {
                    revert BlockhashMmrKeccakDoesNotMatchProof();
                }

                // check appending to the committed MMR with recent blocks will yield the claimed MMR

                uint256 appendRemaining;
                unchecked {
                    // in this branch, proofMmrSize > snapshotPmmrSize
                    appendRemaining = proofMmrSize - snapshotPmmrSize;
                }
                bytes32[] memory append = new bytes32[](appendRemaining);

                for (uint256 idx; idx < appendRemaining;) {
                    unchecked {
                        append[idx] = blockhash(snapshotPmmrSize + idx);
                    }
                    unchecked {
                        ++idx;
                    }
                }

                MerkleMountainRange.MMR memory snapshotMmr =
                    MerkleMountainRange.fromPeaks(mmrWitness.mmrComplementOrPeaks);
                snapshotMmr.appendLeaves(append);

                uint256 snapshotMmrPeaksLength = snapshotMmr.peaksLength;
                for (uint256 idx; idx < snapshotMmrPeaksLength;) {
                    if (snapshotMmr.peaks[idx] != peaks[idx]) {
                        revert ClaimedMmrDoesNotMatchRecent();
                    }
                    unchecked {
                        ++idx;
                    }
                }
            } else if (proofMmrSize >= block.number - 256) {
                if (proofMmrSize > corePmmrSize) {
                    revert NoMoreRecentBlockhashPmmr();
                }

                uint256 appendRemaining;
                unchecked {
                    // in this branch, corePmmrSize >= proofMmrSize
                    appendRemaining = corePmmrSize - proofMmrSize;
                }
                bytes32[] memory append = new bytes32[](appendRemaining);
                for (uint256 idx; idx < appendRemaining;) {
                    unchecked {
                        append[idx] = blockhash(proofMmrSize + idx);
                    }
                    unchecked {
                        ++idx;
                    }
                }

                MerkleMountainRange.MMR memory proofMmr = MerkleMountainRange.fromPeaks(peaks);
                proofMmr.appendLeaves(append);

                PaddedMerkleMountainRange.PMMR memory completePmmr = PaddedMerkleMountainRange.PMMR({
                    paddedLeaf: proofMmr.getZeroPaddedMerkleRoot(BLOCK_BATCH_DEPTH),
                    completeLeaves: proofMmr.getCompleteLeaves(BLOCK_BATCH_DEPTH),
                    size: corePmmrSize
                });
                bytes32 completePmmrKeccak = completePmmr.commit();
                if (completePmmrKeccak != IAxiomV2State(axiomCoreAddress).pmmrSnapshots(corePmmrSize)) {
                    revert BlockhashMmrKeccakDoesNotMatchProof();
                }
            } else {
                revert BlockHashWitnessNotRecent();
            }
        }
    }

    /// @inheritdoc IAxiomV2HeaderVerifier
    function getSourceChainId() external view returns (uint64) {
        return _CHAIN_ID;
    }

    /// @notice Implements ERC-165 interface check
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IAxiomV2HeaderVerifier).interfaceId;
    }
}

File 2 of 8 : IAxiomV2HeaderVerifier.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IAxiomV2HeaderVerifier {
    /**
     * @notice Stores witness data for checking MMRs
     * @param  snapshotPmmrSize The `pmmrSize` as in `IAxiomV2State`.
     * @param  proofMmrPeaks Peaks of the MMR, formatted so that `proofMmrPeaks[i]` is a Merkle
     *         root of `2 ** i` claimed block hashes.
     * @param  mmrComplementOrPeaks This has two different semantic meanings depending on the
     *         value of `proofPmmrSize = number of blocks committed to by proofMmrPeaks`.
     *         If `proofPmmrSize <= snapshotPmmrSize`:
     *           -- `mmrComplementOrPeaks[:10]` form a complementary MMR to `proofMmrPeaks[:10]`
     *              formatted so that `mmrComplementOrPeaks[idx]` is a Merkle root of `2 ** idx` hashes
     *              which together with `witnessMmrPeaks` forms a padded leaf.
     *           -- `mmrComplementOrPeaks[10]` is either `bytes32(0x0)` or a Merkle root of a padded leaf.
     *              -- It is expected to be a Merkle root of a padded leaf exactly when
     *                    snapshotPmmrSize % BLOCK_BATCH_SIZE != 0
     *           -- The remaining elements are a list of Merkle roots of 1024 block hashes, to be
     *              appended in increasing index order.
     *         If `proofPmmrSize > snapshotPmmrSize`:
     *           -- This is the MMR peaks committed to in the PMMR at `snapshotPmmrSize`,
     *              formatted so that `mmrComplementOrPeaks[idx]` is a Merkle root of `2 ** idx`
     *              block hashes.
     */
    struct MmrWitness {
        uint32 snapshotPmmrSize;
        bytes32[] proofMmrPeaks;
        bytes32[] mmrComplementOrPeaks;
    }

    /// @notice Error returned if the AxiomV2Core address is 0.
    error AxiomCoreAddressIsZero();

    /// @notice Error returned when the claimed blockhashMmr is not consistent with the source of truth
    error BlockhashMmrKeccakDoesNotMatchProof();

    /// @notice Error returned when last block in the claimed MMR of the proof is not in the recent 256
    ///         block hash window.
    error MmrEndBlockNotRecent();

    /// @notice Error returned when last block in the claimed MMR of the proof is not in the recent 256
    ///         block hash window.
    error BlockHashWitnessNotRecent();

    /// @notice Error returned when the claimed MMR of the proof is not consistent with the source of truth
    error ClaimedMmrDoesNotMatchRecent();

    /// @notice Error returned when the claimed MMR of the proof cannot be verified against a more recent
    ///         blockhashPmmr.
    error NoMoreRecentBlockhashPmmr();

    /// @notice Error returned if the proofMmrKeccak does not match witness.
    error ProofMmrKeccakDoesNotMatch();

    /// @notice Verify the claimed `proofMmrKeccak` is validly read from the history
    ///         of the source chain using witness data from `mmrWitness`
    /// @param  proofMmrKeccak The Keccak hash of the claimed MMR of historic block hashes
    ///         formatted so that hash `idx` is the Merkle root of `2 ** idx` block hashes
    /// @param  mmrWitness Witness data for verification
    function verifyQueryHeaders(bytes32 proofMmrKeccak, MmrWitness calldata mmrWitness) external;

    /// @notice Return the `chainId` of the source chain
    /// @return chainId The `chainId`
    function getSourceChainId() external view returns (uint64);
}

File 3 of 8 : IAxiomV2State.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { PaddedMerkleMountainRange } from "../../libraries/PaddedMerkleMountainRange.sol";
import { MerkleMountainRange } from "../../libraries/MerkleMountainRange.sol";

interface IAxiomV2State {
    /// @notice Returns the hash of a batch of consecutive blocks previously verified by the contract
    /// @param  startBlockNumber The block number of the first block in the batch
    /// @dev    The reads here will match the emitted #UpdateEvent
    /// @return historicalRoots(startBlockNumber) is 0 unless (startBlockNumber % 1024 == 0)
    ///         historicalRoots(startBlockNumber) = 0 if block `startBlockNumber` is not verified
    ///         historicalRoots(startBlockNumber) = keccak256(prevHash || root || numFinal) where || is concatenation
    ///         - prevHash is the parent hash of block `startBlockNumber`
    ///         - root is the keccak Merkle root of hash(i) for i in [0, 1024), where
    ///             hash(i) is the blockhash of block `startBlockNumber + i` if i < numFinal,
    ///             hash(i) = bytes32(0x0) if i >= numFinal
    ///         - 0 < numFinal <= 1024 is the number of verified consecutive roots in [startBlockNumber, startBlockNumber + numFinal)
    function historicalRoots(uint32 startBlockNumber) external view returns (bytes32);

    /// @notice Get the number of consecutive blocks from genesis currently committed to in `blockhashPmmr`
    ///         The padded Merkle mountain range `blockhashPmmr` commits to the block hashes of blocks
    ///         `[0, pmmrSize)`
    /// @return pmmrSize indicates that the blockhashPmmr commits to blockhashes of blocks `[0, pmmrSize)`
    function blockhashPmmrSize() external view returns (uint32 pmmrSize);

    /// @notice Get the `paddedLeaf` of the padded Merkle mountain range `blockhashPmmr`
    /// @return paddedLeaf the `paddedLeaf` corresponding to `blockhashPmmr`
    function blockhashPmmrLeaf() external view returns (bytes32);

    /// @notice Returns the PMMR commitment to the blockhashes of blocks `[0, pmmrSize)`, if it exists, `bytes32(0x0)` otherwise
    /// @param  pmmrSize The number of blocks committed to in the PMMR
    /// @return pmmrHash The hash of the PMMR, as computed by `PaddedMerkleMountainRange.commit`
    function pmmrSnapshots(uint32 pmmrSize) external view returns (bytes32);

    /// @notice Returns the Merkle mountain range of peaks in `blockhashPmmr
    /// @return mmr The Merkle mountain range.
    function blockhashPmmrPeaks() external view returns (MerkleMountainRange.MMR memory);

    /// @notice Get the full current `blockhashPmmr`
    /// @return blockhashPmmr The current PMMR commitment to historic block hashes
    function fullBlockhashPmmr() external view returns (PaddedMerkleMountainRange.PMMR memory);
}

File 4 of 8 : MerkleMountainRange.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { MerkleTree } from "./MerkleTree.sol";
import { Hash } from "./Hash.sol";

uint256 constant MAX_MMR_PEAKS = 32;

/// @title  Merkle Mountain Range
/// @author Axiom
/// @notice Library for Merkle Mountain Range data structure
library MerkleMountainRange {
    /// @notice A Merkle mountain range is a data structure for efficiently storing a commitment to a variable length list of bytes32 values.
    /// @param  peaks The peaks of the MMR as a fixed-length array of length 32.
    ///         `peaks` is ordered in *increasing* size of peaks: `peaks[i]` is the Merkle root of a tree of size `2 ** i` corresponding to the `i`th bit of `len` (see @dev for details)
    /// @param  peaksLength The actual number of peaks in the MMR
    /// @dev    peaks stores `peaksLength := bit_length(len)` Merkle roots, with
    ///         `peaks[i] = root(list[((len >> i) << i) - 2^i : ((len >> i) << i)])` if 2^i & len != 0, otherwise 0
    ///         where root(single element) = single element, and `list` is the underlying list for the MMR
    ///         Warning: Only use the check `peaks[i] == 0` to determine if `peaks[i]` is undefined if the original list is guaranteed to not contain 0
    ///         (e.g., if the original list is already of hashes)
    ///         Default initialization is to `len = 0`, `peaksLength = 0`, and all `peaks[i] = 0`
    struct MMR {
        bytes32[MAX_MMR_PEAKS] peaks;
        uint256 peaksLength;
    }

    /// @dev Create an MMR from a variable length array
    /// @param peaks The variable length array
    /// @return out The MMR in memory
    function fromPeaks(bytes32[] memory peaks) internal pure returns (MMR memory out) {
        return fromPeaks(peaks, 0, peaks.length);
    }

    /// @notice Create an MMR from a slice of variable length array
    /// @dev    Only reads the peaks up to `peaksLength`
    /// @param peaks The variable length array
    /// @param start The start index of the subarray
    /// @param length The length of the subarray
    /// @return out The MMR in memory
    function fromPeaks(bytes32[] memory peaks, uint256 start, uint256 length) internal pure returns (MMR memory out) {
        out.peaksLength = length;
        for (uint256 idx; idx < length;) {
            unchecked {
                out.peaks[idx] = peaks[start + idx];
                ++idx;
            }
        }
    }

    /// @notice Copies the MMR to memory
    /// @dev    Only reads the peaks up to `peaksLength`
    /// @param  self The MMR
    /// @return out The MMR in memory
    function clone(MMR storage self) internal view returns (MMR memory out) {
        out.peaksLength = self.peaksLength;

        uint256 outPeaksLength = out.peaksLength;
        for (uint256 i; i < outPeaksLength;) {
            out.peaks[i] = self.peaks[i];
            unchecked {
                ++i;
            }
        }
    }

    /// @notice Copies MMR from memory to storage
    /// @dev    Only changes peaks up to `peaksChanged` to limit SSTOREs
    /// @param  self The MMR in storage
    /// @param  peaksChanged Only copy newMMR.peaks[0 : peaksChanged]
    function persistFrom(MMR storage self, MMR memory newMMR, uint256 peaksChanged) internal {
        self.peaksLength = newMMR.peaksLength;

        for (uint256 i; i < peaksChanged;) {
            self.peaks[i] = newMMR.peaks[i];
            unchecked {
                ++i;
            }
        }
    }

    /// @notice Compute the keccak of the concatenated peaks
    /// @param  self The MMR
    /// @return keccak of the concatenated peaks
    function commit(MMR memory self) internal pure returns (bytes32) {
        bytes32[] memory peaks = new bytes32[](self.peaksLength);

        uint256 peaksLength = self.peaksLength;
        for (uint256 i; i < peaksLength;) {
            peaks[i] = self.peaks[i];
            unchecked {
                ++i;
            }
        }

        return keccak256(abi.encodePacked(peaks));
    }

    /// @notice Append a new element to the underlying list of the MMR
    /// @param  self The MMR
    /// @param  leaf The new element to append
    /// @return peaksChanged self.peaks[0 : peaksChanged] have been changed
    function appendLeaf(MMR memory self, bytes32 leaf) internal pure returns (uint256 peaksChanged) {
        unchecked {
            bytes32 newPeak = leaf;
            uint256 i;
            uint256 peaksLength = self.peaksLength;
            for (; i < peaksLength && self.peaks[i] != bytes32(0);) {
                newPeak = Hash.keccak(self.peaks[i], newPeak);
                delete self.peaks[i];
                ++i;
            }
            self.peaks[i] = newPeak;

            if (i >= peaksLength) {
                self.peaksLength = i + 1;
            }

            peaksChanged = i + 1;
        }
    }

    /// @notice Append a sequence of new elements to the underlying list of the MMR, in order
    /// @dev    Optimized compared to looping over `appendLeaf`
    /// @param  self The MMR
    /// @param  leaves The new elements to append
    /// @return peaksChanged self.peaks[0 : peaksChanged] have been changed
    /// @dev Warning: To save gas, this method overwrites values of `leaves` with intermediate computations.
    ///      The input values of `leaves` should be considered invalidated after calling this method.
    function appendLeaves(MMR memory self, bytes32[] memory leaves) internal pure returns (uint256 peaksChanged) {
        // keeps track of running length of `leaves`
        uint256 toAdd = leaves.length;
        uint256 shift;
        uint256 i;
        bytes32 left;
        bytes32 right;
        uint256 nextAdd;
        uint256 bound;

        while (toAdd != 0) {
            // shift records whether there is an existing peak in the range we should hash with
            shift = (self.peaks[i] == bytes32(0)) ? 0 : 1;
            // if shift, add peaks[i] to beginning of leaves
            // then hash all leaves
            unchecked {
                nextAdd = (toAdd + shift) >> 1;
            }

            bound = (nextAdd << 1);
            for (uint256 j; j < bound;) {
                if (shift == 1) {
                    if (j == 0) {
                        left = self.peaks[i];
                    } else {
                        unchecked {
                            left = leaves[j - 1];
                        }
                    }
                    right = leaves[j];
                } else {
                    left = leaves[j];
                    unchecked {
                        right = leaves[j + 1];
                    }
                }
                leaves[j >> 1] = Hash.keccak(left, right);
                unchecked {
                    j = j + 2;
                }
            }
            // if toAdd + shift is odd, the last element is new self.peaks[i], otherwise 0
            if (toAdd & 1 != shift) {
                unchecked {
                    // toAdd is non-zero in this branch
                    self.peaks[i] = leaves[toAdd - 1];
                }
            } else if (shift == 1) {
                // if shift == 0 then self.peaks[i] is already 0
                self.peaks[i] = 0;
            }

            toAdd = nextAdd;
            unchecked {
                ++i;
            }
        }

        if (i > self.peaksLength) {
            self.peaksLength = i;
        }

        peaksChanged = i;
    }

    /**
     * @notice Compute the `completeLeaves` of an existing MMR when converted to a padded MMR with depth `paddingDepth`.
     * @param  self The MMR.
     * @param  paddingDepth The depth of the padded Merkle tree.
     * @return out The `completeLeaves` of the padded Merkle mountain range corresponding to the MMR.
     */
    function getCompleteLeaves(MMR memory self, uint256 paddingDepth) internal pure returns (MMR memory out) {
        unchecked {
            // if self.peaksLength < paddingDepth, then out.peaksLength = 0
            if (self.peaksLength >= paddingDepth) {
                out.peaksLength = self.peaksLength - paddingDepth;
            }
            for (uint256 i = paddingDepth; i < self.peaksLength;) {
                out.peaks[i - paddingDepth] = self.peaks[i];
                ++i;
            }
        }
    }

    /**
     * @notice Hash an existing MMR to a Merkle root of a 0-padded Merkle tree with depth `paddingDepth`.
     * @param  self The MMR.
     * @param  paddingDepth The depth of the padded Merkle tree.
     * @return root The Merkle root of the padded MMR.
     */
    function getZeroPaddedMerkleRoot(MMR memory self, uint256 paddingDepth) internal pure returns (bytes32) {
        bytes32 root;
        bool started;

        for (uint256 peakIdx; peakIdx < paddingDepth;) {
            if (!started && self.peaks[peakIdx] != bytes32(0)) {
                root = MerkleTree.getEmptyHash(peakIdx);
                started = true;
            }

            if (started) {
                root = self.peaks[peakIdx] != bytes32(0)
                    ? Hash.keccak(self.peaks[peakIdx], root)
                    : Hash.keccak(root, MerkleTree.getEmptyHash(peakIdx));
            }
            unchecked {
                ++peakIdx;
            }
        }

        return root;
    }

    /**
     * @dev    Extend an existing MMR to a Merkle root of a padded list of length `paddingSize` using complement peaks.
     * @param  self The MMR.
     * @param  paddingDepth The depth of the padded Merkle tree.
     * @param  mmrComplement Entries which contain peaks of a complementary MMR, where `mmrComplement[idx]` is either `bytes32(0x0)` or the
     *         Merkle root of a tree of depth `idx`.  Only the relevant indices are accessed.
     * @dev    As an example, if `mmr` has peaks of depth 9 8 6 3, then `mmrComplement` has peaks of depth 3 4 5 7
     *         In this example, the peaks of `mmr` are Merkle roots of the first 2^9 leaves, then the next 2^8 leaves, and so on.
     *         The peaks of `mmrComplement` are Merkle roots of the first 2^3 leaves after `mmr`, then the next 2^4 leaves, and so on.
     * @return root The Merkle root of the completion of `mmr`.
     */
    function getComplementMerkleRoot(MMR memory self, uint256 paddingDepth, bytes32[] memory mmrComplement)
        internal
        pure
        returns (bytes32)
    {
        bytes32 root;
        bool started;

        for (uint256 peakIdx; peakIdx < paddingDepth;) {
            if (!started && self.peaks[peakIdx] != bytes32(0)) {
                root = mmrComplement[peakIdx];
                started = true;
            }

            if (started) {
                root = self.peaks[peakIdx] != bytes32(0)
                    ? Hash.keccak(self.peaks[peakIdx], root)
                    : Hash.keccak(root, mmrComplement[peakIdx]);
            }
            unchecked {
                ++peakIdx;
            }
        }

        return root;
    }
}

File 5 of 8 : PaddedMerkleMountainRange.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { MerkleMountainRange } from "./MerkleMountainRange.sol";

/// @title  Padded Merkle Mountain Range
/// @author Axiom
/// @notice Library for Merkle Mountain Range data structure
library PaddedMerkleMountainRange {
    using MerkleMountainRange for MerkleMountainRange.MMR;

    /// @dev Error returned if the leaf is too big
    error PmmrLeafIsTooBig();

    /// @dev Error returned if the leaf is not empty
    error PmmrLeafIsNotEmpty();

    /**
     * @notice A Padded Merkle mountain range is a data structure for efficiently storing a commitment
     *         to a variable length list of hash values batched by a specific size.  For a fixed `paddingSize`
     *         which must be a power of two, a PMMR consists of a standard MMR of Merkle roots of batches of
     *         `paddingSize` hashes and a `paddedLeaf`, which is a Merkle root of the 0-padded last partial batch of
     *         hashes, where the number of hashes lies in `[0, paddingSize)`.
     *         We define `paddedLeaf = bytes32(0x0)` if the last partial batch of hashes is empty.
     * @param  completeLeaves The MMR of the complete leaves of the PMMR
     * @param  paddedLeaf The Merkle root of the 0-padded last partial batch of hashes
     * @param  size The number of hashes this PMMR is a commitment to.
     */
    struct PMMR {
        MerkleMountainRange.MMR completeLeaves;
        bytes32 paddedLeaf;
        uint32 size;
    }

    /**
     * @notice Copies the PMMR from storage to memory
     * @param  self The PMMR in storage
     * @return out The PMMR in memory
     */
    function clone(PMMR storage self) internal view returns (PMMR memory out) {
        out.completeLeaves = self.completeLeaves.clone();
        out.paddedLeaf = self.paddedLeaf;
        out.size = self.size;
    }

    /**
     * @notice Copies PMMR from memory to storage
     * @param  self The PMMR in storage
     * @param  sourcePMMR The PMMR in memory
     * @param  peaksChanged Only copy newMMR.peaks[0 : peaksChanged]
     */
    function persistFrom(PMMR storage self, PMMR memory sourcePMMR, uint256 peaksChanged) internal {
        self.completeLeaves.persistFrom(sourcePMMR.completeLeaves, peaksChanged);
        self.paddedLeaf = sourcePMMR.paddedLeaf;
        self.size = sourcePMMR.size;
    }

    /**
     * @notice Compute a commitment to the PMMR, defined by
     *         keccak(paddedLeaf || completeLeaves.peaks[0] || ... || completeLeaves.peaks[completeLeaves.peaksLength - 1])
     * @param  self The PMMR
     * @return keccak the hash of the concatenation
     */
    function commit(PMMR memory self) internal pure returns (bytes32) {
        bytes32[] memory peaks = new bytes32[](self.completeLeaves.peaksLength);

        for (uint256 i; i < self.completeLeaves.peaksLength;) {
            peaks[i] = self.completeLeaves.peaks[i];
            unchecked {
                ++i;
            }
        }

        return keccak256(abi.encodePacked(self.paddedLeaf, peaks));
    }

    /**
     * @notice Updates the first peak representing the padded batch leaf
     * @dev    Warning: This method can overflow if `self.size + leafSize` exceeds `2**32 - 1`.
     *         This cannot happen for realistic values of block numbers, which is not an issue
     *         in our application.
     * @param  self The PMMR
     * @param  paddingSize The size of the padded batch
     * @param  leaf The padded leaf update
     * @param  leafSize The size of the padded leaf, defined as the number of non-zero hashes it contains
     * @return completePeaksChanged amount of peaks that have been changed
     */
    function updatePaddedLeaf(PMMR memory self, uint32 paddingSize, bytes32 leaf, uint32 leafSize)
        internal
        pure
        returns (uint256 completePeaksChanged)
    {
        if (leafSize > paddingSize) {
            revert PmmrLeafIsTooBig();
        }

        unchecked {
            self.size = self.size - self.size % paddingSize + leafSize;
        }

        // just updating the padded leaf that is always at index 0
        if (leafSize < paddingSize) {
            self.paddedLeaf = leaf;
            return 0;
        }

        // If leaf is complete
        delete self.paddedLeaf;
        completePeaksChanged = self.completeLeaves.appendLeaf(leaf);
    }

    /**
     * @notice Append a sequence of complete leaves to the underlying list of the PMMR
     * @dev    The padded leaf should be empty to be able to append complete leaves
     * @param  self The PMMR
     * @param  paddingSize The size of the padded batch
     * @param  leaves The new elements to append
     * @return completePeaksChanged amount of peaks that have been changed
     * @dev Warning: To save gas, this method overwrites values of `leaves` with intermediate computations.
     *      The input values of `leaves` should be considered invalidated after calling this method.
     */
    function appendCompleteLeaves(PMMR memory self, uint32 paddingSize, bytes32[] memory leaves)
        internal
        pure
        returns (uint256 completePeaksChanged)
    {
        if (self.paddedLeaf != bytes32(0)) {
            revert PmmrLeafIsNotEmpty();
        }

        self.size += uint32(leaves.length) * paddingSize;

        completePeaksChanged = self.completeLeaves.appendLeaves(leaves);
    }
}

File 6 of 8 : AxiomV2Configuration.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Constants and free functions to be inlined into by AxiomV2Core and AxiomV2Query

/*
 * Constants for AxiomV2Core
 */

// AxiomV2Core caches blockhashes in batches, stored as Merkle roots of binary Merkle trees
uint32 constant BLOCK_BATCH_SIZE = 1024;
uint32 constant BLOCK_BATCH_DEPTH = 10;

// constants for batch import of historical block hashes
// historical uploads a bigger batch of block hashes, stored as Merkle roots of binary Merkle trees
uint32 constant HISTORICAL_BLOCK_BATCH_SIZE = 131_072; // 2 ** 17
uint32 constant HISTORICAL_BLOCK_BATCH_DEPTH = 17;
// we will consider the historical Merkle tree of blocks as a Merkle tree of the block batch roots
uint32 constant HISTORICAL_NUM_ROOTS = 128; // HISTORICAL_BATCH_SIZE / BLOCK_BATCH_SIZE

// The first 4 * 3 * 32 bytes of proof calldata are reserved for two BN254 G1 points for a pairing check
// It will then be followed by (7 + BLOCK_BATCH_DEPTH * 2) * 32 bytes of public inputs/outputs
uint32 constant PUBLIC_BYTES_START_IDX = 384; // 4 * 3 * 32
uint32 constant AUX_PEAKS_START_IDX = 608; // PUBLIC_BYTES_START_IDX + 7 * 32

/// @notice Read public instances from the ZK proof
/// @param  proofData the entire ZK proof
/// @return prevHash the hash of the previous block
/// @return endHash the hash of the last block in the batch
/// @return startBlockNumber the block number of the first block in the batch
/// @return endBlockNumber the block number of the last block in the batch
/// @return root the Merkle root of the 0-padded batch of blocks
/// @dev proofData stores bytes32 and uint256 values in hi-lo format as two uint128 values because the BN254 scalar field is 254 bits
/// @dev The first 12 * 32 bytes of proofData are reserved for ZK proof verification data
// Extract public instances from proof
// The public instances are laid out in the proof calldata as follows:
// First 4 * 3 * 32 = 384 bytes are reserved for proof verification data used with the pairing precompile
// 384..384 + 32 * 2: prevHash (32 bytes) as two uint128 cast to uint256, because zk proof uses 254 bit field and cannot fit uint256 into a single element
// 384 + 32 * 2..384 + 32 * 4: endHash (32 bytes) as two uint128 cast to uint256
// 384 + 32 * 4..384 + 32 * 5: startBlockNumber (uint32: 4 bytes) and endBlockNumber (uint32: 4 bytes) are concatenated as `startBlockNumber . endBlockNumber` (8 bytes) and then cast to uint256
// 384 + 32 * 5..384 + 32 * 7: root (32 bytes) as two uint128 cast to uint256, this is the highest peak of the MMR if endBlockNumber - startBlockNumber == 1023, otherwise 0
function getBoundaryBlockData(bytes calldata proofData)
    pure
    returns (bytes32 prevHash, bytes32 endHash, uint32 startBlockNumber, uint32 endBlockNumber, bytes32 root)
{
    prevHash =
        bytes32(uint256(bytes32(proofData[PUBLIC_BYTES_START_IDX:416])) << 128 | uint256(bytes32(proofData[416:448])));
    endHash = bytes32(uint256(bytes32(proofData[448:480])) << 128 | uint256(bytes32(proofData[480:512])));
    startBlockNumber = uint32(bytes4(proofData[536:540]));
    endBlockNumber = uint32(bytes4(proofData[540:544]));
    root = bytes32(uint256(bytes32(proofData[544:576])) << 128 | uint256(bytes32(proofData[576:AUX_PEAKS_START_IDX])));
}

// We have a Merkle mountain range of max depth BLOCK_BATCH_DEPTH (so length BLOCK_BATCH_DEPTH + 1 total) ordered in **decreasing** order of peak size, so:
// `root` from `getBoundaryBlockData` is the peak for depth BLOCK_BATCH_DEPTH
// `getAuxMmrPeak(proofData, i)` is the peaks for depth BLOCK_BATCH_DEPTH - 1 - i
// 384 + 32 * 7 + 32 * 2 * i .. 384 + 32 * 7 + 32 * 2 * (i + 1): (32 bytes) as two uint128 cast to uint256, same as blockHash
// Note that the decreasing ordering is *different* than the convention in library MerkleMountainRange
function getAuxMmrPeak(bytes calldata proofData, uint256 i) pure returns (bytes32) {
    return bytes32(
        uint256(bytes32(proofData[AUX_PEAKS_START_IDX + i * 64:AUX_PEAKS_START_IDX + i * 64 + 32])) << 128
            | uint256(bytes32(proofData[AUX_PEAKS_START_IDX + i * 64 + 32:AUX_PEAKS_START_IDX + (i + 1) * 64]))
    );
}

/*
 * Constants for AxiomV2Query
 */

/// @dev Chain IDs for Ethereum mainnet and testnets
uint64 constant MAINNET_CHAIN_ID = 1;
uint64 constant GOERLI_CHAIN_ID = 5;
uint64 constant SEPOLIA_CHAIN_ID = 11_155_111;
uint64 constant HOLESKY_CHAIN_ID = 17_000;

/// @dev Constant recording the fact that this is Axiom V2
uint8 constant VERSION = 2;

/// @dev Largest deposit allowed at one time
uint256 constant MAX_DEPOSIT_SIZE = 100 ether;

/// @dev Conservative upper bound for `proofVerificationGas`.  Real values should be lower.
uint32 constant MAX_PROOF_VERIFICATION_GAS = 600_000;

/// @dev Conservative upper bound for `axiomQueryFee`. Real values should be lower.
uint256 constant MAX_AXIOM_QUERY_FEE = 0.05 ether;

File 7 of 8 : MerkleTree.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { HISTORICAL_NUM_ROOTS } from "./configuration/AxiomV2Configuration.sol";
import { Hash } from "./Hash.sol";

/// @title Merkle Tree
/// @notice Helper functions for computing Merkle roots of Merkle trees
library MerkleTree {
    /// @dev Error returned if the empty hash depth is not in range [0, 10)
    error InvalidEmptyHashDepth();

    /// @notice Compute the Merkle root of a Merkle tree with HISTORICAL_NUM_ROOTS leaves
    /// @param  leaves The HISTORICAL_NUM_ROOTS leaves of the Merkle tree
    function merkleRoot(bytes32[HISTORICAL_NUM_ROOTS] memory leaves) internal pure returns (bytes32) {
        // we create a new array to avoid mutating `leaves`, which is passed by reference
        // unnecessary if calldata `leaves` is passed in since it is automatically copied to memory
        bytes32[] memory hashes = new bytes32[](HISTORICAL_NUM_ROOTS / 2);
        for (uint256 i; i < HISTORICAL_NUM_ROOTS / 2;) {
            hashes[i] = Hash.keccak(leaves[i << 1], leaves[(i << 1) | 1]);
            unchecked {
                ++i;
            }
        }
        uint256 len = HISTORICAL_NUM_ROOTS / 4;
        while (len != 0) {
            for (uint256 i; i < len;) {
                hashes[i] = Hash.keccak(hashes[i << 1], hashes[(i << 1) | 1]);
                unchecked {
                    ++i;
                }
            }
            len >>= 1;
        }
        return hashes[0];
    }

    /// @notice Compute the Merkle root of a Merkle tree with 2^depth leaves all equal to bytes32(0x0)
    /// @param depth The depth of the Merkle tree, 0 <= depth < BLOCK_BATCH_DEPTH.
    function getEmptyHash(uint256 depth) internal pure returns (bytes32) {
        // emptyHashes[idx] is the Merkle root of a tree of depth idx with 0's as leaves
        if (depth == 0) {
            return bytes32(0x0000000000000000000000000000000000000000000000000000000000000000);
        }
        if (depth == 1) {
            return bytes32(0xad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5);
        }
        if (depth == 2) {
            return bytes32(0xb4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30);
        }
        if (depth == 3) {
            return bytes32(0x21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85);
        }
        if (depth == 4) {
            return bytes32(0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344);
        }
        if (depth == 5) {
            return bytes32(0x0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d);
        }
        if (depth == 6) {
            return bytes32(0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968);
        }
        if (depth == 7) {
            return bytes32(0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83);
        }
        if (depth == 8) {
            return bytes32(0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af);
        }
        if (depth == 9) {
            return bytes32(0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0);
        }
        revert InvalidEmptyHashDepth();
    }
}

File 8 of 8 : Hash.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title Hash
/// @notice Gas-optimized library for computing packed Keccak hashes
library Hash {
    /// @notice Compute the Keccak hash of the packed values `keccak(a || b)`
    ///         Gas-optimized equivalent of `keccak256(abi.encodePacked(a, b))`
    function keccak(bytes32 a, bytes32 b) internal pure returns (bytes32 hash) {
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            hash := keccak256(0x00, 0x40)
        }
    }
}

Settings
{
  "remappings": [
    "@create3-factory/=lib/create3-factory/src/",
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "@solmate-utils/=lib/solmate/src/utils/",
    "create3-factory/=lib/create3-factory/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "nitro-contracts/=lib/nitro-contracts/src/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "solmate/=lib/solmate/src/",
    "weird-erc20/=lib/solmate/lib/weird-erc20/src/",
    "lib/create3-factory:ds-test/=lib/create3-factory/lib/forge-std/lib/ds-test/src/",
    "lib/create3-factory:forge-std/=lib/create3-factory/lib/forge-std/src/",
    "lib/create3-factory:solmate/=lib/create3-factory/lib/solmate/src/",
    "lib/forge-std:ds-test/=lib/forge-std/lib/ds-test/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 100000,
    "details": {
      "constantOptimizer": false,
      "yul": false
    }
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"address","name":"_axiomCoreAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AxiomCoreAddressIsZero","type":"error"},{"inputs":[],"name":"BlockHashWitnessNotRecent","type":"error"},{"inputs":[],"name":"BlockhashMmrKeccakDoesNotMatchProof","type":"error"},{"inputs":[],"name":"ClaimedMmrDoesNotMatchRecent","type":"error"},{"inputs":[],"name":"InvalidEmptyHashDepth","type":"error"},{"inputs":[],"name":"MmrEndBlockNotRecent","type":"error"},{"inputs":[],"name":"NoMoreRecentBlockhashPmmr","type":"error"},{"inputs":[],"name":"PmmrLeafIsNotEmpty","type":"error"},{"inputs":[],"name":"PmmrLeafIsTooBig","type":"error"},{"inputs":[],"name":"ProofMmrKeccakDoesNotMatch","type":"error"},{"inputs":[],"name":"axiomCoreAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSourceChainId","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"proofMmrKeccak","type":"bytes32"},{"components":[{"internalType":"uint32","name":"snapshotPmmrSize","type":"uint32"},{"internalType":"bytes32[]","name":"proofMmrPeaks","type":"bytes32[]"},{"internalType":"bytes32[]","name":"mmrComplementOrPeaks","type":"bytes32[]"}],"internalType":"struct IAxiomV2HeaderVerifier.MmrWitness","name":"mmrWitness","type":"tuple"}],"name":"verifyQueryHeaders","outputs":[],"stateMutability":"view","type":"function"}]

60c06040523480156200001157600080fd5b5060405162001c3838038062001c38833981016040819052620000349162000115565b67ffffffffffffffff821660a05273ffffffffffffffffffffffffffffffffffffffff811662000090576040517ff0f7b81f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff166080525062000158565b67ffffffffffffffff81165b8114620000c857600080fd5b50565b8051620000d881620000b0565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff8216620000d8565b620000bc81620000de565b8051620000d881620000fd565b600080604083850312156200012d576200012d600080fd5b60006200013b8585620000cb565b92505060206200014e8582860162000108565b9150509250929050565b60805160a051611a9f62000199600039600061010701526000818160c1015281816104930152818161058d015281816107c60152610b6d0152611a9f6000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806301ffc9a714610051578063cddc3b93146100bc578063edc55b94146100f0578063fe428ed314610105575b600080fd5b6100a661005f366004611626565b7fffffffff00000000000000000000000000000000000000000000000000000000167f1387d547000000000000000000000000000000000000000000000000000000001490565b6040516100b39190611651565b60405180910390f35b6100e37f000000000000000000000000000000000000000000000000000000000000000081565b6040516100b39190611686565b6101036100fe3660046116c0565b610133565b005b7f00000000000000000000000000000000000000000000000000000000000000006040516100b39190611728565b60006101426020830183611736565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201829052509394506101839250505060208401846117c8565b9050816040516020016101969190611845565b6040516020818303038152906040528051906020012084146101e4576040517ff7e4c42900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8151600090815b8181101561022e576000801b85828151811061020957610209611858565b602002602001015114610226576102236001821b846118b6565b92505b6001016101eb565b508263ffffffff168263ffffffff16116105495760408051606081019091526000908061026687600a61026181886118d6565b610c61565b81526000602082015260400161027e61040086611918565b6102889086611936565b63ffffffff169052905060006102a08682600a610c61565b905063ffffffff84166102b561040087611918565b6102bf9087611936565b63ffffffff16106104155760006102d861040086611918565b63ffffffff161115610346576000610333600a6102f860408b018b611736565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250879493925050610cc29050565b9050610343836104008381610db8565b50505b63ffffffff841661035961040087611918565b6103639087611936565b63ffffffff1611156103cd576103cb61040061038260408a018a611736565b61039091600b908290611956565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250879493925050610e809050565b505b61040f6104006103e060408a018a611736565b600a8181106103f1576103f1611858565b90506020020135610400886104069190611918565b85929190610db8565b50610448565b6000610429600a6102f860408b018b611736565b90506104456104008261043c828a611918565b86929190610db8565b50505b600061045383610ef8565b6040517f5ed3661300000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690635ed36613906104c8908990600401611995565b602060405180830381865afa1580156104e5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050991906119ae565b8114610541576040517feff8f8f200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050610c59565b438263ffffffff161115610589576040517f299b0e4100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663596ef8a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061a91906119da565b9050610628610100436118d6565b8463ffffffff161015801561067057508063ffffffff168363ffffffff16118061067057506106578382611936565b63ffffffff166106678585611936565b63ffffffff1611155b156109e657600060405180606001604052806106e48980604001906106959190611736565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250600a92508291506106d9905060408e018e611736565b6102619291506118d6565b8152600060208201526040016106fc61040088611918565b6107069088611936565b63ffffffff16905290506000610767600a61076161072760408c018c611736565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201829052509250600a9150610c619050565b90610fca565b905061077a61040082610406828a611918565b50600061078683610ef8565b6040517f5ed3661300000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690635ed36613906107fb908a90600401611995565b602060405180830381865afa158015610818573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061083c91906119ae565b8114610874576040517feff8f8f200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63ffffffff8787031660008167ffffffffffffffff811115610898576108986119fb565b6040519080825280602002602001820160405280156108c1578160200160208202803683370190505b50905060005b828110156108fe57808a63ffffffff1601408282815181106108eb576108eb611858565b60209081029190910101526001016108c7565b50600061094861091160408e018e611736565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061108a92505050565b9050610954818361109f565b50602081015160005b818110156109d9578c818151811061097757610977611858565b60200260200101518360000151826020811061099557610995611858565b6020020151146109d1576040517fb21aeaed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60010161095d565b5050505050505050610c57565b6109f2610100436118d6565b8363ffffffff1610610c25578063ffffffff168363ffffffff161115610a44576040517f8d034e6f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63ffffffff8382031660008167ffffffffffffffff811115610a6857610a686119fb565b604051908082528060200260200182016040528015610a91578160200160208202803683370190505b50905060005b82811015610ace57808663ffffffff160140828281518110610abb57610abb611858565b6020908102919091010152600101610a97565b506000610ada8861108a565b9050610ae6818361109f565b50604080516060810190915260009080610b0184600a611297565b8152602001610b1184600a610fca565b81526020018663ffffffff1681525090506000610b2d82610ef8565b6040517f5ed3661300000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690635ed3661390610ba2908990600401611995565b602060405180830381865afa158015610bbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610be391906119ae565b8114610c1b576040517feff8f8f200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050610c57565b6040517f7df2555400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b505050505050565b610c696115aa565b6020810182905260005b82811015610cba578481850181518110610c8f57610c8f611858565b602002602001015182600001518260208110610cad57610cad611858565b6020020152600101610c73565b509392505050565b6000806000805b85811015610dad5781158015610cf8575086516000908260208110610cf057610cf0611858565b602002015114155b15610d1e57848181518110610d0f57610d0f611858565b60200260200101519250600191505b8115610da55786516000908260208110610d3a57610d3a611858565b602002015103610d7657610d7183868381518110610d5a57610d5a611858565b602002602001015160009182526020526040902090565b610da2565b8651610da2908260208110610d8d57610d8d611858565b60200201518460009182526020526040902090565b92505b600101610cc9565b509095945050505050565b60008363ffffffff168263ffffffff161115610e00576040517f6f4617f300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818463ffffffff16866040015163ffffffff1681610e2057610e206118e9565b0686604001510301856040019063ffffffff16908163ffffffff16815250508363ffffffff168263ffffffff161015610e625750602084018290526000610e78565b600060208601528451610e75908461130a565b90505b949350505050565b602083015160009015610ebf576040517f27e3c14100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b828251610ecc9190611a2a565b84604001818151610edd91906118b6565b63ffffffff9081169091528551610e78925090849061109f16565b60008082600001516020015167ffffffffffffffff811115610f1c57610f1c6119fb565b604051908082528060200260200182016040528015610f45578160200160208202803683370190505b50905060005b835160200151811015610f96578351518160208110610f6c57610f6c611858565b6020020151828281518110610f8357610f83611858565b6020908102919091010152600101610f4b565b50602080840151604051610fac92849101611a4d565b60405160208183030381529060405280519060200120915050919050565b6000806000805b8481101561107e5781158015611000575085516000908260208110610ff857610ff8611858565b602002015114155b156110155761100e816113bf565b9250600191505b8115611076578551600090826020811061103157611031611858565b60200201510361105c5761105783611048836113bf565b60009182526020526040902090565b611073565b8551611073908260208110610d8d57610d8d611858565b92505b600101610fd1565b50909150505b92915050565b6110926115aa565b6110848260008451610c61565b80516000908180808080805b861561127557895160009086602081106110c7576110c7611858565b6020020151146110d85760016110db565b60005b60ff1695505050848401600181901c907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1660005b818110156111fb57866001036111885780600003611147578a51866020811061113b5761113b611858565b60200201519450611167565b89600182038151811061115c5761115c611858565b602002602001015194505b89818151811061117957611179611858565b602002602001015193506111c4565b89818151811061119a5761119a611858565b602002602001015194508981600101815181106111b9576111b9611858565b602002602001015193505b60008581526020859052604090208a600183901c815181106111e8576111e8611858565b6020908102919091010152600201611110565b508587600116146112435788600188038151811061121b5761121b611858565b60200260200101518a60000151866020811061123957611239611858565b6020020152611267565b85600103611267578951600090866020811061126157611261611858565b60200201525b8196508460010194506110ab565b89602001518511156112895760208a018590525b509298975050505050505050565b61129f6115aa565b818360200151106112b857602080840151839003908201525b815b836020015181101561130357835181602081106112d9576112d9611858565b60200201518260000151848303602081106112f6576112f6611858565b60200201526001016112ba565b5092915050565b6020820151600090829082905b808210801561133f57508551600090836020811061133757611337611858565b602002015114155b1561138857855161135b908360208110610d8d57610d8d611858565b8651909350826020811061137157611371611858565b602002016000801916815250816001019150611317565b85518390836020811061139d5761139d611858565b60200201528082106113b3576001820160208701525b50600101949350505050565b6000816000036113d157506000919050565b8160010361140057507fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5919050565b8160020361142f57507fb4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30919050565b8160030361145e57507f21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85919050565b8160040361148d57507fe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344919050565b816005036114bc57507f0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d919050565b816006036114eb57507f887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968919050565b8160070361151a57507fffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83919050565b8160080361154957507f9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af919050565b8160090361157857507fcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0919050565b6040517f90fa88a700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052806115bd6115ca565b8152602001600081525090565b6040518061040001604052806020906020820280368337509192915050565b7fffffffff0000000000000000000000000000000000000000000000000000000081165b811461161857600080fd5b50565b8035611084816115e9565b60006020828403121561163b5761163b600080fd5b6000610e78848461161b565b8015155b82525050565b602081016110848284611647565b600073ffffffffffffffffffffffffffffffffffffffff8216611084565b61164b8161165f565b60208101611084828461167d565b8061160d565b803561108481611694565b6000606082840312156116ba576116ba600080fd5b50919050565b600080604083850312156116d6576116d6600080fd5b60006116e2858561169a565b925050602083013567ffffffffffffffff81111561170257611702600080fd5b61170e858286016116a5565b9150509250929050565b67ffffffffffffffff811661164b565b602081016110848284611718565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe13685900301811261176f5761176f600080fd5b80840192508235915067ffffffffffffffff82111561179057611790600080fd5b602092830192820236038313156117a9576117a9600080fd5b509250929050565b63ffffffff811661160d565b8035611084816117b1565b6000602082840312156117dd576117dd600080fd5b6000610e7884846117bd565b8061164b565b60006117fb83836117e9565b505060200190565b600061180d825190565b602083018060005b8381101561183a57815161182988826117ef565b975060208301925050600101611815565b509495945050505050565b60006118518284611803565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b63ffffffff91821691908116908282019081111561108457611084611887565b8181038181111561108457611084611887565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b63ffffffff9182169116600082611931576119316118e9565b500690565b63ffffffff91821691908116908282039081111561108457611084611887565b6000808585111561196957611969600080fd5b8386111561197957611979600080fd5b5050602083020193919092039150565b63ffffffff811661164b565b602081016110848284611989565b805161108481611694565b6000602082840312156119c3576119c3600080fd5b6000610e7884846119a3565b8051611084816117b1565b6000602082840312156119ef576119ef600080fd5b6000610e7884846119cf565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b63ffffffff91821691908116908282029081169081811461130357611303611887565b6000611a5982856117e9565b602082019150610e78828461180356fea26469706673582212204203c50a1f48c76f62d3fcbad5f186fd184b3f7b0671c0f45c29a3a304c48cb864736f6c63430008130033000000000000000000000000000000000000000000000000000000000000000100000000000000000000000069963768f8407de501029680de46945f838fc98b

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061004c5760003560e01c806301ffc9a714610051578063cddc3b93146100bc578063edc55b94146100f0578063fe428ed314610105575b600080fd5b6100a661005f366004611626565b7fffffffff00000000000000000000000000000000000000000000000000000000167f1387d547000000000000000000000000000000000000000000000000000000001490565b6040516100b39190611651565b60405180910390f35b6100e37f00000000000000000000000069963768f8407de501029680de46945f838fc98b81565b6040516100b39190611686565b6101036100fe3660046116c0565b610133565b005b7f00000000000000000000000000000000000000000000000000000000000000016040516100b39190611728565b60006101426020830183611736565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201829052509394506101839250505060208401846117c8565b9050816040516020016101969190611845565b6040516020818303038152906040528051906020012084146101e4576040517ff7e4c42900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8151600090815b8181101561022e576000801b85828151811061020957610209611858565b602002602001015114610226576102236001821b846118b6565b92505b6001016101eb565b508263ffffffff168263ffffffff16116105495760408051606081019091526000908061026687600a61026181886118d6565b610c61565b81526000602082015260400161027e61040086611918565b6102889086611936565b63ffffffff169052905060006102a08682600a610c61565b905063ffffffff84166102b561040087611918565b6102bf9087611936565b63ffffffff16106104155760006102d861040086611918565b63ffffffff161115610346576000610333600a6102f860408b018b611736565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250879493925050610cc29050565b9050610343836104008381610db8565b50505b63ffffffff841661035961040087611918565b6103639087611936565b63ffffffff1611156103cd576103cb61040061038260408a018a611736565b61039091600b908290611956565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250879493925050610e809050565b505b61040f6104006103e060408a018a611736565b600a8181106103f1576103f1611858565b90506020020135610400886104069190611918565b85929190610db8565b50610448565b6000610429600a6102f860408b018b611736565b90506104456104008261043c828a611918565b86929190610db8565b50505b600061045383610ef8565b6040517f5ed3661300000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000069963768f8407de501029680de46945f838fc98b1690635ed36613906104c8908990600401611995565b602060405180830381865afa1580156104e5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050991906119ae565b8114610541576040517feff8f8f200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050610c59565b438263ffffffff161115610589576040517f299b0e4100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007f00000000000000000000000069963768f8407de501029680de46945f838fc98b73ffffffffffffffffffffffffffffffffffffffff1663596ef8a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061a91906119da565b9050610628610100436118d6565b8463ffffffff161015801561067057508063ffffffff168363ffffffff16118061067057506106578382611936565b63ffffffff166106678585611936565b63ffffffff1611155b156109e657600060405180606001604052806106e48980604001906106959190611736565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250600a92508291506106d9905060408e018e611736565b6102619291506118d6565b8152600060208201526040016106fc61040088611918565b6107069088611936565b63ffffffff16905290506000610767600a61076161072760408c018c611736565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201829052509250600a9150610c619050565b90610fca565b905061077a61040082610406828a611918565b50600061078683610ef8565b6040517f5ed3661300000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000069963768f8407de501029680de46945f838fc98b1690635ed36613906107fb908a90600401611995565b602060405180830381865afa158015610818573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061083c91906119ae565b8114610874576040517feff8f8f200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63ffffffff8787031660008167ffffffffffffffff811115610898576108986119fb565b6040519080825280602002602001820160405280156108c1578160200160208202803683370190505b50905060005b828110156108fe57808a63ffffffff1601408282815181106108eb576108eb611858565b60209081029190910101526001016108c7565b50600061094861091160408e018e611736565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061108a92505050565b9050610954818361109f565b50602081015160005b818110156109d9578c818151811061097757610977611858565b60200260200101518360000151826020811061099557610995611858565b6020020151146109d1576040517fb21aeaed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60010161095d565b5050505050505050610c57565b6109f2610100436118d6565b8363ffffffff1610610c25578063ffffffff168363ffffffff161115610a44576040517f8d034e6f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63ffffffff8382031660008167ffffffffffffffff811115610a6857610a686119fb565b604051908082528060200260200182016040528015610a91578160200160208202803683370190505b50905060005b82811015610ace57808663ffffffff160140828281518110610abb57610abb611858565b6020908102919091010152600101610a97565b506000610ada8861108a565b9050610ae6818361109f565b50604080516060810190915260009080610b0184600a611297565b8152602001610b1184600a610fca565b81526020018663ffffffff1681525090506000610b2d82610ef8565b6040517f5ed3661300000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000069963768f8407de501029680de46945f838fc98b1690635ed3661390610ba2908990600401611995565b602060405180830381865afa158015610bbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610be391906119ae565b8114610c1b576040517feff8f8f200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050610c57565b6040517f7df2555400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b505050505050565b610c696115aa565b6020810182905260005b82811015610cba578481850181518110610c8f57610c8f611858565b602002602001015182600001518260208110610cad57610cad611858565b6020020152600101610c73565b509392505050565b6000806000805b85811015610dad5781158015610cf8575086516000908260208110610cf057610cf0611858565b602002015114155b15610d1e57848181518110610d0f57610d0f611858565b60200260200101519250600191505b8115610da55786516000908260208110610d3a57610d3a611858565b602002015103610d7657610d7183868381518110610d5a57610d5a611858565b602002602001015160009182526020526040902090565b610da2565b8651610da2908260208110610d8d57610d8d611858565b60200201518460009182526020526040902090565b92505b600101610cc9565b509095945050505050565b60008363ffffffff168263ffffffff161115610e00576040517f6f4617f300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818463ffffffff16866040015163ffffffff1681610e2057610e206118e9565b0686604001510301856040019063ffffffff16908163ffffffff16815250508363ffffffff168263ffffffff161015610e625750602084018290526000610e78565b600060208601528451610e75908461130a565b90505b949350505050565b602083015160009015610ebf576040517f27e3c14100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b828251610ecc9190611a2a565b84604001818151610edd91906118b6565b63ffffffff9081169091528551610e78925090849061109f16565b60008082600001516020015167ffffffffffffffff811115610f1c57610f1c6119fb565b604051908082528060200260200182016040528015610f45578160200160208202803683370190505b50905060005b835160200151811015610f96578351518160208110610f6c57610f6c611858565b6020020151828281518110610f8357610f83611858565b6020908102919091010152600101610f4b565b50602080840151604051610fac92849101611a4d565b60405160208183030381529060405280519060200120915050919050565b6000806000805b8481101561107e5781158015611000575085516000908260208110610ff857610ff8611858565b602002015114155b156110155761100e816113bf565b9250600191505b8115611076578551600090826020811061103157611031611858565b60200201510361105c5761105783611048836113bf565b60009182526020526040902090565b611073565b8551611073908260208110610d8d57610d8d611858565b92505b600101610fd1565b50909150505b92915050565b6110926115aa565b6110848260008451610c61565b80516000908180808080805b861561127557895160009086602081106110c7576110c7611858565b6020020151146110d85760016110db565b60005b60ff1695505050848401600181901c907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1660005b818110156111fb57866001036111885780600003611147578a51866020811061113b5761113b611858565b60200201519450611167565b89600182038151811061115c5761115c611858565b602002602001015194505b89818151811061117957611179611858565b602002602001015193506111c4565b89818151811061119a5761119a611858565b602002602001015194508981600101815181106111b9576111b9611858565b602002602001015193505b60008581526020859052604090208a600183901c815181106111e8576111e8611858565b6020908102919091010152600201611110565b508587600116146112435788600188038151811061121b5761121b611858565b60200260200101518a60000151866020811061123957611239611858565b6020020152611267565b85600103611267578951600090866020811061126157611261611858565b60200201525b8196508460010194506110ab565b89602001518511156112895760208a018590525b509298975050505050505050565b61129f6115aa565b818360200151106112b857602080840151839003908201525b815b836020015181101561130357835181602081106112d9576112d9611858565b60200201518260000151848303602081106112f6576112f6611858565b60200201526001016112ba565b5092915050565b6020820151600090829082905b808210801561133f57508551600090836020811061133757611337611858565b602002015114155b1561138857855161135b908360208110610d8d57610d8d611858565b8651909350826020811061137157611371611858565b602002016000801916815250816001019150611317565b85518390836020811061139d5761139d611858565b60200201528082106113b3576001820160208701525b50600101949350505050565b6000816000036113d157506000919050565b8160010361140057507fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5919050565b8160020361142f57507fb4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30919050565b8160030361145e57507f21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85919050565b8160040361148d57507fe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344919050565b816005036114bc57507f0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d919050565b816006036114eb57507f887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968919050565b8160070361151a57507fffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83919050565b8160080361154957507f9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af919050565b8160090361157857507fcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0919050565b6040517f90fa88a700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052806115bd6115ca565b8152602001600081525090565b6040518061040001604052806020906020820280368337509192915050565b7fffffffff0000000000000000000000000000000000000000000000000000000081165b811461161857600080fd5b50565b8035611084816115e9565b60006020828403121561163b5761163b600080fd5b6000610e78848461161b565b8015155b82525050565b602081016110848284611647565b600073ffffffffffffffffffffffffffffffffffffffff8216611084565b61164b8161165f565b60208101611084828461167d565b8061160d565b803561108481611694565b6000606082840312156116ba576116ba600080fd5b50919050565b600080604083850312156116d6576116d6600080fd5b60006116e2858561169a565b925050602083013567ffffffffffffffff81111561170257611702600080fd5b61170e858286016116a5565b9150509250929050565b67ffffffffffffffff811661164b565b602081016110848284611718565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe13685900301811261176f5761176f600080fd5b80840192508235915067ffffffffffffffff82111561179057611790600080fd5b602092830192820236038313156117a9576117a9600080fd5b509250929050565b63ffffffff811661160d565b8035611084816117b1565b6000602082840312156117dd576117dd600080fd5b6000610e7884846117bd565b8061164b565b60006117fb83836117e9565b505060200190565b600061180d825190565b602083018060005b8381101561183a57815161182988826117ef565b975060208301925050600101611815565b509495945050505050565b60006118518284611803565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b63ffffffff91821691908116908282019081111561108457611084611887565b8181038181111561108457611084611887565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b63ffffffff9182169116600082611931576119316118e9565b500690565b63ffffffff91821691908116908282039081111561108457611084611887565b6000808585111561196957611969600080fd5b8386111561197957611979600080fd5b5050602083020193919092039150565b63ffffffff811661164b565b602081016110848284611989565b805161108481611694565b6000602082840312156119c3576119c3600080fd5b6000610e7884846119a3565b8051611084816117b1565b6000602082840312156119ef576119ef600080fd5b6000610e7884846119cf565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b63ffffffff91821691908116908282029081169081811461130357611303611887565b6000611a5982856117e9565b602082019150610e78828461180356fea26469706673582212204203c50a1f48c76f62d3fcbad5f186fd184b3f7b0671c0f45c29a3a304c48cb864736f6c63430008130033

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

000000000000000000000000000000000000000000000000000000000000000100000000000000000000000069963768f8407de501029680de46945f838fc98b

-----Decoded View---------------
Arg [0] : chainId (uint64): 1
Arg [1] : _axiomCoreAddress (address): 0x69963768F8407dE501029680dE46945F838Fc98B

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [1] : 00000000000000000000000069963768f8407de501029680de46945f838fc98b


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

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.