ETH Price: $3,419.07 (-6.73%)

Contract

0xDd215c64BB70868cC0D45bF3f7c3d97A074920b2
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Verify Age186541272023-11-26 6:41:35389 days ago1700980895IN
0xDd215c64...A074920b2
0 ETH0.0014450716.6842918
Verify Age185962362023-11-18 4:03:11397 days ago1700280191IN
0xDd215c64...A074920b2
0 ETH0.0017854720.61436345
Verify Age185946832023-11-17 22:49:59398 days ago1700261399IN
0xDd215c64...A074920b2
0 ETH0.0019604822.62556377
Verify Age185017132023-11-04 22:42:23411 days ago1699137743IN
0xDd215c64...A074920b2
0 ETH0.0009196113.78459234
Verify Age184128012023-10-23 11:54:35423 days ago1698062075IN
0xDd215c64...A074920b2
0 ETH0.0010891712.56994394
Verify Age184119532023-10-23 9:03:35423 days ago1698051815IN
0xDd215c64...A074920b2
0 ETH0.0011553513.33378692
Verify Age184119532023-10-23 9:03:35423 days ago1698051815IN
0xDd215c64...A074920b2
0 ETH0.0011553513.33378692
Verify Age184119152023-10-23 8:55:23423 days ago1698051323IN
0xDd215c64...A074920b2
0 ETH0.000813499.38834885
Verify Age184081272023-10-22 20:10:47424 days ago1698005447IN
0xDd215c64...A074920b2
0 ETH0.000758668.75565595
Verify Age184057202023-10-22 12:04:23424 days ago1697976263IN
0xDd215c64...A074920b2
0 ETH0.00057626.65082219
Verify Age183686682023-10-17 7:41:47429 days ago1697528507IN
0xDd215c64...A074920b2
0 ETH0.000626667.23219582
Verify Age183614042023-10-16 7:20:11430 days ago1697440811IN
0xDd215c64...A074920b2
0 ETH0.00044955.18626985
Verify Age183607812023-10-16 5:15:11430 days ago1697433311IN
0xDd215c64...A074920b2
0 ETH0.000503435.81171696
Verify Age183606862023-10-16 4:56:11430 days ago1697432171IN
0xDd215c64...A074920b2
0 ETH0.000544536.28608101
Verify Age183606252023-10-16 4:43:59430 days ago1697431439IN
0xDd215c64...A074920b2
0 ETH0.00058296.7290418
Verify Age183547172023-10-15 8:54:23431 days ago1697360063IN
0xDd215c64...A074920b2
0 ETH0.000511765.90537896
Verify Age183546932023-10-15 8:49:35431 days ago1697359775IN
0xDd215c64...A074920b2
0 ETH0.000479145.52738117
Verify Age183540742023-10-15 6:45:23431 days ago1697352323IN
0xDd215c64...A074920b2
0 ETH0.000325564.88092447
Verify Age183522562023-10-15 0:39:35432 days ago1697330375IN
0xDd215c64...A074920b2
0 ETH0.000433185
Verify Age183516522023-10-14 22:38:11432 days ago1697323091IN
0xDd215c64...A074920b2
0 ETH0.00041314.76827308
Verify Age183516352023-10-14 22:34:47432 days ago1697322887IN
0xDd215c64...A074920b2
0 ETH0.000425624.91275398
Verify Age183511492023-10-14 20:57:23432 days ago1697317043IN
0xDd215c64...A074920b2
0 ETH0.000368555.52350596
Verify Age183507482023-10-14 19:36:59432 days ago1697312219IN
0xDd215c64...A074920b2
0 ETH0.000459175.3
Verify Age183504342023-10-14 18:33:47432 days ago1697308427IN
0xDd215c64...A074920b2
0 ETH0.000496565.72842151
Verify Age183453332023-10-14 1:25:47433 days ago1697246747IN
0xDd215c64...A074920b2
0 ETH0.000461315.3239078
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AccountAge

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 1 : AccountAge.flatten.sol
// SPDX-License-Identifier: MIT
// WARNING! This smart contract has not been audited.
// DO NOT USE THIS CONTRACT FOR PRODUCTION
// This is an example contract to demonstrate how to integrate an application with the audited production release of AxiomV1 and AxiomV1Query.
pragma solidity 0.8.19;

// Constants and free functions to be inlined into by AxiomV1Core

// ZK circuit constants:

// AxiomV1 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 = 131072; // 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 AUX_PEAKS_START_IDX = 608; // PUBLIC_BYTES_START_IDX + 7 * 32

// Historical MMR Ring Buffer constants
uint32 constant MMR_RING_BUFFER_SIZE = 8;

/// @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[384: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:608])));
}

// 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]))
    );
}

interface IAxiomV1Verifier {
    /// @notice A merkle proof to verify a block against the verified blocks cached by Axiom
    /// @dev    `BLOCK_BATCH_DEPTH = 10`
    struct BlockHashWitness {
        uint32 blockNumber;
        bytes32 claimedBlockHash;
        bytes32 prevHash;
        uint32 numFinal;
        bytes32[BLOCK_BATCH_DEPTH] merkleProof;
    }

    /// @notice Verify the blockhash of block blockNumber equals claimedBlockHash. Assumes that blockNumber is within the last 256 most recent blocks.
    /// @param  blockNumber The block number to verify
    /// @param  claimedBlockHash The claimed blockhash of block blockNumber
    function isRecentBlockHashValid(uint32 blockNumber, bytes32 claimedBlockHash) external view returns (bool);

    /// @notice Verify the blockhash of block witness.blockNumber equals witness.claimedBlockHash by checking against Axiom's cache of #historicalRoots.
    /// @dev    For block numbers within the last 256, use #isRecentBlockHashValid instead.
    /// @param  witness The block hash to verify and the Merkle proof to verify it
    ///         witness.blockNumber is the block number to verify
    ///         witness.claimedBlockHash is the claimed blockhash of block witness.blockNumber
    ///         witness.prevHash is the prevHash stored in #historicalRoots(witness.blockNumber - witness.blockNumber % 1024)
    ///         witness.numFinal is the numFinal stored in #historicalRoots(witness.blockNumber - witness.blockNumber % 1024)
    ///         witness.merkleProof is the Merkle inclusion proof of witness.claimedBlockHash to the root stored in #historicalRoots(witness.blockNumber - witness.blockNumber % 1024)
    ///         witness.merkleProof[i] is the sibling of the Merkle node at depth 10 - i, for i = 0, ..., 10
    function isBlockHashValid(BlockHashWitness calldata witness) external view returns (bool);

    /// @notice Verify the blockhash of block blockNumber equals claimedBlockHash by checking against Axiom's cache of historical Merkle mountain ranges in #mmrRingBuffer.
    /// @dev    Use event logs to determine the correct bufferId and get the MMR at that index in the ring buffer.
    /// @param  mmr The Merkle mountain range commited to in #mmrRingBuffer(bufferId), must be correct length
    /// @param  bufferId The index in the ring buffer of #mmrRingBuffer
    /// @param  blockNumber The block number to verify
    /// @param  claimedBlockHash The claimed blockhash of block blockNumber
    /// @param  merkleProof The Merkle inclusion proof of claimedBlockHash to the corresponding peak in mmr. The correct peak is calculated from mmr.length and blockNumber.
    function mmrVerifyBlockHash(
        bytes32[] calldata mmr,
        uint8 bufferId,
        uint32 blockNumber,
        bytes32 claimedBlockHash,
        bytes32[] calldata merkleProof
    ) external view;
}

// The depth of the Merkle root of queries in:
//   `keccakBlockResponse`, `keccakAccountResponse`, and `keccakStorageResponse`
uint32 constant QUERY_MERKLE_DEPTH = 6;

interface IAxiomV1Query {
    /// @notice States of an on-chain query
    /// @param  Inactive The query has not been made or was refunded.
    /// @param  Active The query has been requested, but not fulfilled.
    /// @param  Fulfilled The query was successfully fulfilled.
    enum AxiomQueryState {
        Inactive,
        Active,
        Fulfilled
    }

    /// @notice Stores metadata about a query 
    /// @param  payment The ETH payment received, in wei. 
    /// @param  state The state of the query.
    /// @param  deadlineBlockNumber The deadline (in block number) after which a refund may be granted.
    /// @param  refundee The address funds should be returned to if the query is not fulfilled.
    struct AxiomQueryMetadata {
        uint256 payment;
        AxiomQueryState state; 
        uint32 deadlineBlockNumber;
        address payable refundee;
    }

    /// @notice Response values read from ZK proof for query.
    /// @param  poseidonBlockResponse Poseidon Merkle root of `poseidon(blockHash . blockNumber . poseidon_tree_root(block_header))`
    /// @param  keccakBlockResponse Keccak Merkle root of `keccak(blockHash . blockNumber)` 
    /// @param  poseidonAccountResponse Poseidon Merkle root of `poseidon(poseidonBlockResponseRow . poseidon(stateRoot . addr . poseidon_tree_root(account_state)))`
    /// @param  keccakAccountResponse Keccak Merkle root of `keccak(blockNumber . addr . keccak(nonce . balance . storageRoot . codeHash))`
    /// @param  poseidonStorageResponse Poseidon Merkle root of `poseidon(poseidonBlockResponseRow . poseidonAccountResponseRow . poseidon(storageRoot . slot . value))`
    /// @param  keccakStorageResponse Keccak Merkle root of `keccak(blockNumber . addr . slot . value)`
    /// @param  historicalMMRKeccak `keccak256(abi.encodePacked(mmr[10:]))`
    /// @param  recentMMRKeccak `keccak256(abi.encodePacked(mmr[:10]))`
    //  Detailed documentation on format here: https://hackmd.io/@axiom/S17K2drf2
    //  ** `poseidonBlockResponseRow = poseidon(blockHash . blockNumber . poseidon_tree_root(block_header))`
    //  ** `poseidonAccountResponseRow = poseidon(stateRoot . addr . poseidon_tree_root(account_state)))`
    //  ** `mmr` is a variable length array of bytes32 containing the Merkle Mountain Range the ZK proof is proving into.
    //     `mmr[idx]` is either `bytes32(0)` or the Merkle root of `1 << idx` block hashes.
    //  ** `mmr` is guaranteed to have length at least `10` and at most `32`.
    struct AxiomMMRQueryResponse {
        bytes32 poseidonBlockResponse;
        bytes32 keccakBlockResponse;
        bytes32 poseidonAccountResponse; 
        bytes32 keccakAccountResponse;
        bytes32 poseidonStorageResponse;
        bytes32 keccakStorageResponse;
        bytes32 historicalMMRKeccak;
        bytes32 recentMMRKeccak;
    }

    /// @notice Stores witness data for checking MMRs
    /// @param  prevHash The `prevHash` as in `IAxiomV1State`.
    /// @param  root The `root` as in `IAxiomV1State`.
    /// @param  numFinal The `numFinal` as in `IAxiomV1State`.  
    /// @param  startBlockNumber The `startBlockNumber` as in `IAxiomV1State`.
    /// @param  recentMMRPeaks Peaks of the MMR committed to in the public input `recentMMRKeccak` of the ZK proof.
    /// @param  mmrComplementOrPeaks If `len(recentMMRPeaks) <= numFinal`, then this is a complementary MMR containing  
    ///         the complement of `recentMMRPeaks` which together with `recentMMRPeaks` forms `root`.  
    ///         If `len(recentMMRPeaks) > numFinal`, then this is the MMR peaks of the `numFinal` blockhashes commited
    ///         to in `root`.
    struct RecentMMRWitness {
        bytes32 prevHash;
        bytes32 root;
        uint32 numFinal;
        uint32 startBlockNumber;        
        bytes32[10] recentMMRPeaks;
        bytes32[10] mmrComplementOrPeaks;
    }

    /// @notice Store a query result into a single block
    /// @param  blockNumber The block number.
    /// @param  blockHash The block hash.
    /// @param  leafIdx The position of this result in the Merkle tree committed to by `keccakBlockResponse`.
    /// @param  proof A Merkle proof into `keccakBlockResponse`.
    struct BlockResponse {
        uint32 blockNumber;
        bytes32 blockHash;

        uint32 leafIdx;
        bytes32[QUERY_MERKLE_DEPTH] proof;
    }

    /// @notice Store a query result into a single block
    /// @param  blockNumber The block number.
    /// @param  addr The address.
    /// @param  nonce The nonce.
    /// @param  balance The balance.
    /// @param  storageRoot The storage root.
    /// @param  codeHash The code hash.
    /// @param  leafIdx The position of this result in the Merkle tree committed to by `keccakAccountResponse`.
    /// @param  proof A Merkle proof into `keccakAccountResponse`.
    //  Note: Fields are zero-padded by prefixing with zero bytes to:
    //    * `nonce`: 8 bytes
    //    * `balance`: 12 bytes
    //    * `storageRoot`: 32 bytes
    //    * `codeHash`: 32 bytes    
    struct AccountResponse {
        uint32 blockNumber;        
        address addr;
        uint64 nonce;
        uint96 balance;
        bytes32 storageRoot;
        bytes32 codeHash;

        uint32 leafIdx;
        bytes32[QUERY_MERKLE_DEPTH] proof;
    }

    /// @notice Store a query result into a single block
    /// @param  blockNumber The block number.
    /// @param  addr The address.
    /// @param  slot The storage slot index. 
    /// @param  value The storage slot value.
    /// @param  leafIdx The position of this result in the Merkle tree committed to by `keccakStorageResponse`.
    /// @param  proof A Merkle proof into `keccakStorageResponse`.
    struct StorageResponse {
        uint32 blockNumber;
        address addr;
        uint256 slot;
        uint256 value;

        uint32 leafIdx;
        bytes32[QUERY_MERKLE_DEPTH] proof;
    }    

    /// @notice Read the set of verified query responses in Keccak form.
    /// @param  hash `verifiedKeccakResults(keccak256(keccakBlockResponse . keccakAccountResponse . keccakStorageResponse)) == true` 
    ///         if and only if each of `keccakBlockResponse`, `keccakAccountResponse`, and `keccakStorageResponse` have been verified
    ///         on-chain by a ZK proof.
    function verifiedKeccakResults(bytes32 hash) external view returns (bool);

    /// @notice Read the set of verified query responses in Poseidon form.
    /// @param  hash `verifiedPoseidonResults(keccak256(poseidonBlockResponse . poseidonAccountResponse . poseidonStorageResponse)) == true` 
    ///         if and only if each of `poseidonBlockResponse`, `poseidonAccountResponse`, and `poseidonStorageResponse` have been
    ///         verified on-chain by a ZK proof.
    function verifiedPoseidonResults(bytes32 hash) external view returns (bool);

    /// @notice Returns the metadata associated to a query
    /// @param  keccakQueryResponse The hash of the query response.
    function queries(bytes32 keccakQueryResponse) external view 
        returns (
            uint256 payment,
            AxiomQueryState state,
            uint32 deadlineBlockNumber,
            address payable refundee
        );

    /// @notice Emitted when the `AxiomV1Core` address is updated.
    /// @param  newAddress The updated address.
    event UpdateAxiomAddress(address newAddress);

    /// @notice Emitted when the batch query verifier address is updated.
    /// @param  newAddress The updated address.
    event UpdateMMRVerifierAddress(address newAddress);

    /// @notice Emitted when a Keccak result is recorded
    /// @param  keccakBlockResponse As documented in `AxiomMMRQueryResponse`.
    /// @param  keccakAccountResponse As documented in `AxiomMMRQueryResponse`.
    /// @param  keccakStorageResponse As documented in `AxiomMMRQueryResponse`.
    event KeccakResultEvent(bytes32 keccakBlockResponse, bytes32 keccakAccountResponse, bytes32 keccakStorageResponse);

    /// @notice Emitted when a Poseidon result is recorded
    /// @param  poseidonBlockResponse As documented in `AxiomMMRQueryResponse`.
    /// @param  poseidonAccountResponse As documented in `AxiomMMRQueryResponse`.
    /// @param  poseidonStorageResponse As documented in `AxiomMMRQueryResponse`.
    event PoseidonResultEvent(bytes32 poseidonBlockResponse, bytes32 poseidonAccountResponse, bytes32 poseidonStorageResponse);

    /// @notice Emitted when the `minQueryPrice` is updated.
    /// @param  minQueryPrice The new `minQueryPrice`.
    event UpdateMinQueryPrice(uint256 minQueryPrice);

    /// @notice Emitted when the `maxQueryPrice` is updated.
    /// @param  maxQueryPrice The new `maxQueryPrice`.
    event UpdateMaxQueryPrice(uint256 maxQueryPrice);

    /// @notice Emitted when the `queryDeadlineInterval` is updated.
    /// @param  queryDeadlineInterval The new `queryDeadlineInterval`.
    event UpdateQueryDeadlineInterval(uint32 queryDeadlineInterval);

    /// @notice Emitted when a new query with off-chain data availability is requested.
    /// @param  keccakQueryResponse The hash of the claimed query response.
    /// @param  payment The ETH payment offered, in wei.
    /// @param  deadlineBlockNumber The deadline block number after which a refund is possible.
    /// @param  refundee The address of the refundee.
    /// @param  ipfsHash A content-addressed hash on IPFS where the query spec may be found.
    event QueryInitiatedOffchain(bytes32 keccakQueryResponse, uint256 payment, uint32 deadlineBlockNumber, address refundee, bytes32 ipfsHash);

    /// @notice Emitted when a new query with on-chain data availability is requested.
    /// @param  keccakQueryResponse The hash of the claimed query response.
    /// @param  payment The ETH payment offered, in wei.
    /// @param  deadlineBlockNumber The deadline block number after which a refund is possible.
    /// @param  refundee The address of the refundee.
    /// @param  queryHash The hash of the on-chain query.    
    event QueryInitiatedOnchain(bytes32 keccakQueryResponse, uint256 payment, uint32 deadlineBlockNumber, address refundee, bytes32 queryHash);

    /// @notice Emitted when a query is fulfilled.
    /// @param  keccakQueryResponse The hash of the query response.
    /// @param  payment The ETH payment collected, in wei.
    /// @param  prover The address of the prover collecting payment.
    event QueryFulfilled(bytes32 keccakQueryResponse, uint256 payment, address prover);

    /// @notice Emitted when a query is refunded.
    /// @param  keccakQueryResponse The hash of the query response.
    /// @param  payment The ETH payment refunded minus gas, in wei.
    /// @param  refundee The address collecting the refund.    
    event QueryRefunded(bytes32 keccakQueryResponse, uint256 payment, uint32 deadlineBlockNumber, address refundee);

    /// @notice Verify a query result on-chain.
    /// @param  mmrIdx The index of the cached MMR to verify against.
    /// @param  mmrWitness Witness data to reconcile `recentMMR` against `historicalRoots`.
    /// @param  proof The ZK proof data.
    function verifyResultVsMMR(
        uint32 mmrIdx, 
        RecentMMRWitness calldata mmrWitness,                   
        bytes calldata proof
    ) external;                

    /// @notice Request proof for query with on-chain query data availability.
    /// @param  keccakQueryResponse The Keccak-encoded query response.
    /// @param  refundee The address refunds should be sent to.
    /// @param  query The serialized query.
    function sendQuery(bytes32 keccakQueryResponse, address payable refundee, bytes calldata query) external payable;

    /// @notice Request proof for query with off-chain query data availability.
    /// @param  keccakQueryResponse The Keccak-encoded query response.
    /// @param  refundee The address refunds should be sent to.
    /// @param  ipfsHash The IPFS hash the query should optionally be posted to.
    function sendOffchainQuery(bytes32 keccakQueryResponse, address payable refundee, bytes32 ipfsHash) external payable;

    /// @notice Fulfill a query request on-chain.
    /// @param  keccakQueryResponse The hashed query response.
    /// @param  payee The address to send payment to.
    /// @param  mmrIdx The index of the cached MMR to verify against.
    /// @param  mmrWitness Witness data to reconcile `recentMMR` against `historicalRoots`.
    /// @param  proof The ZK proof data.
    function fulfillQueryVsMMR(
        bytes32 keccakQueryResponse, 
        address payable payee, 
        uint32 mmrIdx, 
        RecentMMRWitness calldata mmrWitness,          
        bytes calldata proof
    ) external;

    /// @notice Trigger refund collection for a query after the deadline has expired.
    /// @param keccakQueryResponse THe hashed query response.
    function collectRefund(bytes32 keccakQueryResponse) external;

    /// @notice Checks whether an unpacked query response has already been verified.
    /// @param  keccakBlockResponse As documented in `AxiomMMRQueryResponse`.
    /// @param  keccakAccountResponse As documented in `AxiomMMRQueryResponse`.
    /// @param  keccakStorageResponse As documented in `AxiomMMRQueryResponse`.
    function isKeccakResultValid(bytes32 keccakBlockResponse, bytes32 keccakAccountResponse, bytes32 keccakStorageResponse)
        external
        view
        returns (bool);

    /// @notice Checks whether an unpacked query response has already been verified.
    /// @param  poseidonBlockResponse As documented in `AxiomMMRQueryResponse`.
    /// @param  poseidonAccountResponse As documented in `AxiomMMRQueryResponse`.
    /// @param  poseidonStorageResponse As documented in `AxiomMMRQueryResponse`.
    function isPoseidonResultValid(bytes32 poseidonBlockResponse, bytes32 poseidonAccountResponse, bytes32 poseidonStorageResponse)
        external
        view
        returns (bool);        

    /// @notice Verify block, account, and storage data against responses which have already been proven.
    /// @param  keccakBlockResponse As documented in `AxiomMMRQueryResponse`.
    /// @param  keccakAccountResponse As documented in `AxiomMMRQueryResponse`.
    /// @param  keccakStorageResponse As documented in `AxiomMMRQueryResponse`.
    /// @param  blockResponses The list of block results.
    /// @param  accountResponses The list of account results.
    /// @param  storageResponses The list of storage results.
    // block_response = keccak(blockHash . blockNumber)
    // account_response = hash(blockNumber . address . hash_tree_root(account_state))
    // storage_response = hash(blockNumber . address . slot . value)
    function areResponsesValid(
        bytes32 keccakBlockResponse,
        bytes32 keccakAccountResponse,
        bytes32 keccakStorageResponse,
        BlockResponse[] calldata blockResponses,
        AccountResponse[] calldata accountResponses,
        StorageResponse[] calldata storageResponses
    ) external view returns (bool);
}

// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

contract AccountAge is Ownable {
    address public axiomQueryAddress;

    mapping(address => uint32) public birthBlocks;

    event UpdateAxiomQueryAddress(address newAddress);
    event AccountAgeVerified(address account, uint32 birthBlock);

    constructor(address _axiomQueryAddress) {
        axiomQueryAddress = _axiomQueryAddress;
        emit UpdateAxiomQueryAddress(_axiomQueryAddress);
    }

    function updateAxiomQueryAddress(address _axiomQueryAddress) external onlyOwner {
        axiomQueryAddress = _axiomQueryAddress;
        emit UpdateAxiomQueryAddress(_axiomQueryAddress);
    }

    function verifyAge(IAxiomV1Query.AccountResponse[] calldata accountProofs, bytes32[3] calldata keccakResponses)
        external
    {
        require(accountProofs.length == 2, "Too many account proofs");
        address account = accountProofs[0].addr;
        require(account == accountProofs[1].addr, "Accounts are not the same");
        require(accountProofs[0].blockNumber + 1 == accountProofs[1].blockNumber, "Block numbers are not consecutive");
        require(accountProofs[0].nonce == 0, "Prev block nonce is not 0");
        require(accountProofs[1].nonce > 0, "No account transactions in curr block");
        uint256 addrSize;
        assembly {
            addrSize := extcodesize(account)
        }
        require(addrSize == 0, "Account is a contract");

        require(
            IAxiomV1Query(axiomQueryAddress).areResponsesValid(
                keccakResponses[0],
                keccakResponses[1],
                keccakResponses[2],
                new IAxiomV1Query.BlockResponse[](0),
                accountProofs,
                new IAxiomV1Query.StorageResponse[](0)
            ),
            "Proof not valid"
        );

        birthBlocks[account] = accountProofs[0].blockNumber;
        emit AccountAgeVerified(account, accountProofs[0].blockNumber);
    }
}

Settings
{
  "remappings": [
    "@openzeppelin/contracts-upgradeable/=/Users/jpw/github/axiom-apps/lib/axiom-v1-contracts/lib/openzeppelin-contracts-upgradeable/contracts/",
    "@openzeppelin/contracts/=/Users/jpw/github/axiom-apps/lib/axiom-v1-contracts/lib/openzeppelin-contracts/contracts/",
    "axiom-contracts/=../lib/axiom-v1-contracts/",
    "axiom-v1-contracts/=/Users/jpw/github/axiom-apps/lib/axiom-v1-contracts/contracts/",
    "ds-test/=../lib/forge-std/lib/ds-test/src/",
    "forge-std/=../lib/forge-std/src/",
    "openzeppelin-contracts-upgradeable/=/Users/jpw/github/axiom-apps/lib/axiom-v1-contracts/lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=../lib/openzeppelin-contracts/contracts/",
    "utils/=../lib/utils/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_axiomQueryAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint32","name":"birthBlock","type":"uint32"}],"name":"AccountAgeVerified","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newAddress","type":"address"}],"name":"UpdateAxiomQueryAddress","type":"event"},{"inputs":[],"name":"axiomQueryAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"birthBlocks","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_axiomQueryAddress","type":"address"}],"name":"updateAxiomQueryAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"blockNumber","type":"uint32"},{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"uint96","name":"balance","type":"uint96"},{"internalType":"bytes32","name":"storageRoot","type":"bytes32"},{"internalType":"bytes32","name":"codeHash","type":"bytes32"},{"internalType":"uint32","name":"leafIdx","type":"uint32"},{"internalType":"bytes32[6]","name":"proof","type":"bytes32[6]"}],"internalType":"struct IAxiomV1Query.AccountResponse[]","name":"accountProofs","type":"tuple[]"},{"internalType":"bytes32[3]","name":"keccakResponses","type":"bytes32[3]"}],"name":"verifyAge","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6080346100d357601f610b4438819003918201601f19168301916001600160401b038311848410176100d8578084926020946040528339810103126100d357516001600160a01b0390818116908190036100d3577f68de448da211dae8043270d0ad5291d8fc6f9345e1acf4cfacabbe9a7233ae9d918160209260005460018060a01b0319903382821617600055604051943391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a360015416176001558152a1604051610a5590816100ef8239f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe608080604052600436101561001357600080fd5b60003560e01c9081633ba7c59a146108fe575080633cc7922114610892578063715018a6146108395780638449e692146107f95780638da5cb5b146107d0578063c20c5ca9146101355763f2fde38b1461006c57600080fd5b3461013057602036600319011261013057610085610922565b61008d610938565b6001600160a01b039081169081156100dc57600054826001600160601b0360a01b821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b600080fd5b346101305760803660031901126101305760043567ffffffffffffffff811161013057366023820112156101305767ffffffffffffffff816004013511610130573660246101a083600401350283010111610130573660841161013057600281600401350361078b57806004013515610775576101b460448201610990565b90806004013560011015610775576001600160a01b036101d76101e48301610990565b166001600160a01b0383160361073057600163ffffffff6101fa602484016109a4565b160163ffffffff811161071a5763ffffffff8061021a6101c485016109a4565b169116036106cb5767ffffffffffffffff610237606483016109b5565b166106865767ffffffffffffffff61025261020483016109b5565b161561063357813b6105f657600154604051906001600160a01b0316610277826109ca565b6000825260405191610288836109ca565b6000835260405192839163190e7a7560e21b835260243560048401526044356024840152606435604484015260c0606484015280518060c4850152602060e4850192019060005b8181106105a457505050828103600319016084840152600486013581526020016024860160005b876004013581106104d55750506003198382030160a48401526020808351928381520192019060005b81811061046a5750505091818060209403915afa90811561045e576000916103f7575b50156103c0577f9fd5d31537ef0f7a1029cf79fdbec67607971ea7ee11a78c731e0f33a7a12e579163ffffffff6103a860248461038282604097016109a4565b60018060a01b0386166000526002602052848760002091168519825416179055016109a4565b83516001600160a01b039093168352166020820152a1005b60405162461bcd60e51b815260206004820152600f60248201526e141c9bdbd9881b9bdd081d985b1a59608a1b6044820152606490fd5b905060203d602011610457575b601f8101601f1916820167ffffffffffffffff81118382101761044157602091839160405281010312610130575180151581036101305783610342565b634e487b7160e01b600052604160045260246000fd5b503d610404565b6040513d6000823e3d90fd5b9193509160206101606001926104c7875163ffffffff8151168352858060a01b03858201511685840152604081015160408401526060808201519084015263ffffffff608082015116608084015260a080910151908301906109e6565b01940191019185939261031f565b919092935063ffffffff6104e884610a0e565b16815260208301356001600160a01b0381168103610130576001600160a01b03166020820152604083013567ffffffffffffffff811681036101305767ffffffffffffffff1660408201526060830135906001600160601b0382168203610130576101a080916001600160601b036001941660608201526080860135608082015260a0808701359082015263ffffffff61058460c08801610a0e565b1660c082015260c060e0870160e0830137019301910190859392916102f6565b919394509160206101206001926105e7875163ffffffff8151168352848101518584015263ffffffff6040820151166040840152606080910151908301906109e6565b019401910191869493926102cf565b60405162461bcd60e51b81526020600482015260156024820152741058d8dbdd5b9d081a5cc8184818dbdb9d1c9858dd605a1b6044820152606490fd5b60405162461bcd60e51b815260206004820152602560248201527f4e6f206163636f756e74207472616e73616374696f6e7320696e206375727220604482015264626c6f636b60d81b6064820152608490fd5b60405162461bcd60e51b815260206004820152601960248201527f5072657620626c6f636b206e6f6e6365206973206e6f742030000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152602160248201527f426c6f636b206e756d6265727320617265206e6f7420636f6e736563757469766044820152606560f81b6064820152608490fd5b634e487b7160e01b600052601160045260246000fd5b60405162461bcd60e51b815260206004820152601960248201527f4163636f756e747320617265206e6f74207468652073616d65000000000000006044820152606490fd5b634e487b7160e01b600052603260045260246000fd5b60405162461bcd60e51b815260206004820152601760248201527f546f6f206d616e79206163636f756e742070726f6f66730000000000000000006044820152606490fd5b34610130576000366003190112610130576000546040516001600160a01b039091168152602090f35b34610130576020366003190112610130576001600160a01b0361081a610922565b166000526002602052602063ffffffff60406000205416604051908152f35b3461013057600036600319011261013057610852610938565b600080546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b34610130576020366003190112610130577f68de448da211dae8043270d0ad5291d8fc6f9345e1acf4cfacabbe9a7233ae9d60206108ce610922565b6108d6610938565b600180546001600160a01b0319166001600160a01b03929092169182179055604051908152a1005b34610130576000366003190112610130576001546001600160a01b03168152602090f35b600435906001600160a01b038216820361013057565b6000546001600160a01b0316330361094c57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b356001600160a01b03811681036101305790565b3563ffffffff811681036101305790565b3567ffffffffffffffff811681036101305790565b6020810190811067ffffffffffffffff82111761044157604052565b6000915b600683106109f757505050565b6001908251815260208091019201920191906109ea565b359063ffffffff821682036101305756fea26469706673582212207f0a4522a605e9abdecd9a2714e47b3a0f5f4b802016efb16722f2b7b51f6c9464736f6c63430008130033000000000000000000000000d617ab7f787adf64c2b5b920c251ea10cd35a952

Deployed Bytecode

0x608080604052600436101561001357600080fd5b60003560e01c9081633ba7c59a146108fe575080633cc7922114610892578063715018a6146108395780638449e692146107f95780638da5cb5b146107d0578063c20c5ca9146101355763f2fde38b1461006c57600080fd5b3461013057602036600319011261013057610085610922565b61008d610938565b6001600160a01b039081169081156100dc57600054826001600160601b0360a01b821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b600080fd5b346101305760803660031901126101305760043567ffffffffffffffff811161013057366023820112156101305767ffffffffffffffff816004013511610130573660246101a083600401350283010111610130573660841161013057600281600401350361078b57806004013515610775576101b460448201610990565b90806004013560011015610775576001600160a01b036101d76101e48301610990565b166001600160a01b0383160361073057600163ffffffff6101fa602484016109a4565b160163ffffffff811161071a5763ffffffff8061021a6101c485016109a4565b169116036106cb5767ffffffffffffffff610237606483016109b5565b166106865767ffffffffffffffff61025261020483016109b5565b161561063357813b6105f657600154604051906001600160a01b0316610277826109ca565b6000825260405191610288836109ca565b6000835260405192839163190e7a7560e21b835260243560048401526044356024840152606435604484015260c0606484015280518060c4850152602060e4850192019060005b8181106105a457505050828103600319016084840152600486013581526020016024860160005b876004013581106104d55750506003198382030160a48401526020808351928381520192019060005b81811061046a5750505091818060209403915afa90811561045e576000916103f7575b50156103c0577f9fd5d31537ef0f7a1029cf79fdbec67607971ea7ee11a78c731e0f33a7a12e579163ffffffff6103a860248461038282604097016109a4565b60018060a01b0386166000526002602052848760002091168519825416179055016109a4565b83516001600160a01b039093168352166020820152a1005b60405162461bcd60e51b815260206004820152600f60248201526e141c9bdbd9881b9bdd081d985b1a59608a1b6044820152606490fd5b905060203d602011610457575b601f8101601f1916820167ffffffffffffffff81118382101761044157602091839160405281010312610130575180151581036101305783610342565b634e487b7160e01b600052604160045260246000fd5b503d610404565b6040513d6000823e3d90fd5b9193509160206101606001926104c7875163ffffffff8151168352858060a01b03858201511685840152604081015160408401526060808201519084015263ffffffff608082015116608084015260a080910151908301906109e6565b01940191019185939261031f565b919092935063ffffffff6104e884610a0e565b16815260208301356001600160a01b0381168103610130576001600160a01b03166020820152604083013567ffffffffffffffff811681036101305767ffffffffffffffff1660408201526060830135906001600160601b0382168203610130576101a080916001600160601b036001941660608201526080860135608082015260a0808701359082015263ffffffff61058460c08801610a0e565b1660c082015260c060e0870160e0830137019301910190859392916102f6565b919394509160206101206001926105e7875163ffffffff8151168352848101518584015263ffffffff6040820151166040840152606080910151908301906109e6565b019401910191869493926102cf565b60405162461bcd60e51b81526020600482015260156024820152741058d8dbdd5b9d081a5cc8184818dbdb9d1c9858dd605a1b6044820152606490fd5b60405162461bcd60e51b815260206004820152602560248201527f4e6f206163636f756e74207472616e73616374696f6e7320696e206375727220604482015264626c6f636b60d81b6064820152608490fd5b60405162461bcd60e51b815260206004820152601960248201527f5072657620626c6f636b206e6f6e6365206973206e6f742030000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152602160248201527f426c6f636b206e756d6265727320617265206e6f7420636f6e736563757469766044820152606560f81b6064820152608490fd5b634e487b7160e01b600052601160045260246000fd5b60405162461bcd60e51b815260206004820152601960248201527f4163636f756e747320617265206e6f74207468652073616d65000000000000006044820152606490fd5b634e487b7160e01b600052603260045260246000fd5b60405162461bcd60e51b815260206004820152601760248201527f546f6f206d616e79206163636f756e742070726f6f66730000000000000000006044820152606490fd5b34610130576000366003190112610130576000546040516001600160a01b039091168152602090f35b34610130576020366003190112610130576001600160a01b0361081a610922565b166000526002602052602063ffffffff60406000205416604051908152f35b3461013057600036600319011261013057610852610938565b600080546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b34610130576020366003190112610130577f68de448da211dae8043270d0ad5291d8fc6f9345e1acf4cfacabbe9a7233ae9d60206108ce610922565b6108d6610938565b600180546001600160a01b0319166001600160a01b03929092169182179055604051908152a1005b34610130576000366003190112610130576001546001600160a01b03168152602090f35b600435906001600160a01b038216820361013057565b6000546001600160a01b0316330361094c57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b356001600160a01b03811681036101305790565b3563ffffffff811681036101305790565b3567ffffffffffffffff811681036101305790565b6020810190811067ffffffffffffffff82111761044157604052565b6000915b600683106109f757505050565b6001908251815260208091019201920191906109ea565b359063ffffffff821682036101305756fea26469706673582212207f0a4522a605e9abdecd9a2714e47b3a0f5f4b802016efb16722f2b7b51f6c9464736f6c63430008130033

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

000000000000000000000000d617ab7f787adf64c2b5b920c251ea10cd35a952

-----Decoded View---------------
Arg [0] : _axiomQueryAddress (address): 0xd617ab7f787adF64C2b5B920c251ea10Cd35a952

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000d617ab7f787adf64c2b5b920c251ea10cd35a952


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
[ 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.