Using Proven Data in your Smart Contract

Explaining how to use data that is proven by Axiom in a smart contract.

Generally, when using the data proven by Axiom in a smart contract, you'll want to follow two steps:

  1. Verify user inputs against proven data in AxiomV1Query

  2. Check application logic with the data in your contract

Additionally, it can be helpful to create a struct that holds all of the data

struct ResponseStruct {
    bytes32 keccakBlockResponse;
    bytes32 keccakAccountResponse;
    bytes32 keccakStorageResponse;
    IAxiomV1Query.BlockResponse[] blockResponses;
    IAxiomV1Query.AccountResponse[] accountResponses;
    IAxiomV1Query.StorageResponse[] storageResponses;
}

Verify user inputs against proven data in AxiomV1Query

Using the appropriate AxiomV1Contract address (use the proxy address), send all of the data to areResponsesValid:

IAxiomV1Query axiomV1Query = IAxiomV1Query(AXIOM_V1_QUERY_GOERLI_ADDR);
bool valid = axiomV1Query.areResponsesValid(
    response.keccakBlockResponse,
    response.keccakAccountResponse,
    response.keccakStorageResponse,
    response.blockResponses,
    response.accountResponses,
    response.storageResponses
);
if (!valid) {
    revert ProofError();    // custom error
}

Check application logic with the data in your contract

Now that you've checked the data was validly read from the history of Ethereum by verifying it against AxiomV1Query, you will want to check that it passes your application logic.

// Decode the query metadata 
uint256 length = response.accountResponses.length;
if (length != 1) {
    revert InvalidDataLengthError();    // custom error
}

// Get values for first transaction from submitted proof response struct
uint256 blockNumber = response.accountResponses[0].blockNumber;
uint256 nonce = response.accountResponses[0].nonce;
address addr = response.accountResponses[0].addr;

// Get current block
uint256 currentBlock = block.number;

// Check that the account nonce at the end of the bear market is a set threshold 
// above the account nonce at the start of the bear market, since it acts as a 
// transaction counter
if (nonce != 1) {
    revert InvalidNonceError();    // custom error
}

// Check that the proof submitted is for the same address that is submitting the 
// transaction
if (addr != _msgSender()) {
    revert InvalidSenderError();    // custom error
}

// Check that the start and end blocks proved match the values set in the contract
if (currentBlock - ACCOUNT_AGE_THRESHOLD < blockNumber) {
    revert AccountAgeBelowThresholdError();    // custom error
}

A full example can be found here: https://github.com/axiom-crypto/examples/blob/main/age-gate-mint/contracts/src/Distributor.sol

Last updated