Typescript SDK for building Queries into Axiom.

Create a new project

In the command line, create and initialize a new Node.js project with the following commands:
  1. 1.
    mkdir axiom-quickstart
  2. 2.
    cd axiom-quickstart
  3. 3.
    npm init
  4. 4.
    touch index.js


You can use your favorite package manager (npm, yarn, pnpm) to install the Axiom SDK:
npm i @axiom-crypto/core
Install Ethers.js:
npm i ethers
Install dotenv to allow us to load in environment variables safely:
npm i dotenv


Create a .env.local file to store your provider URI from Alchemy. You can do this in the terminal with the following command:
touch .env.local
Your .env.local file should only have one line:
In your index.js file, start by importing the Axiom SDK, Ethers.js, and Dotenv library at the top of the page:
import {
} from '@axiom-crypto/core';
import type { QueryBuilder } from '@axiom-crypto/core/query/queryBuilder';
import { ethers } from 'ethers';
import dotenv from 'dotenv';
Now let's set up a new instance of the Axiom SDK:
const config: AxiomConfig = {
providerUri: process.env.PROVIDER_URI_GOERLI || 'http://localhost:8545',
version: "v1",
chainId: 5,
mock: true,
const ax = new Axiom(config);
We'll create mock proofs (they are of the same form as real proofs, but verification will always pass) and submit them to Axiom on Goerli testnet.
Create an instance of a signer (wallet) that can sign transactions:
const provider = new ethers.JsonRpcProvider(process.env.PROVIDER_URI_GOERLI as string);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY as string, provider);

Creating a Query into Axiom

Depending on the historical data you want to query, you can add a QueryRow with block, account, or storage data:
Block data
Account data
Storage data
  • block number
  • address
  • nonce
  • balance
  • storage root
  • code hash
  • block number
  • address
  • slot number
  • slot value

Building a Query

You can build a query by using the newQueryBuilder convenience function and appending data to it with its append function:
const queryData = [
blockNumber: 9335357,
address: "0x4Fb202140c5319106F15706b1A69E441c9536306",
slot: "0x1f5f6074f4419ff8032f6dd23e65794ca104b323667b66be5a0c73fd6ba2857e",
}, {
blockNumber: 9335466,
address: "0x4Fb202140c5319106F15706b1A69E441c9536306",
slot: "0xe162aef9009a7c65cb8d0c7992b1086de24c2a149b9b0d3db4ed7e64df46fa0f",
}, {
blockNumber: 9335492,
address: "0x4Fb202140c5319106F15706b1A69E441c9536306",
slot: "0x9704ebc2f19c9b523a93412dbd2135a468af6ab1ca28a2e272acd0f27d7f33b0",
const qb = ax.newQueryBuilder();
await qb.append(queryData[0]);
await qb.append(queryData[1]);
await qb.append(queryData[2]);

Submitting a built Query to Axiom

Next we'll write a function to submit the query onchain to Axiom:
async function submitQuery(qb: QueryBuilder) {
const { keccakQueryResponse, queryHash, query } = await;
// Create instance of the axiomV1Query contract - later we'll call methods from this contract
const axiomV1Query = new ethers.Contract(
ax.getAxiomQueryAddress() as string,
// Create an on-chain transaction encoding this query using the sendQuery function in the AxiomV1Query contract
const txResult = await axiomV1Query.sendQuery(
value: ethers.parseEther("0.01"), // Goerli payment amount
const txReceipt = await txResult.wait();
console.log("sendQuery Receipt", txReceipt);
console.log("Waiting for proof to be generated. This may take a few minutes...")
// Listen for the QueryFulfilled event emitted by the Axiom contract indicating the proof has been generated
axiomV1Query.on("QueryFulfilled", async (keccakQueryResponse, _payment, _prover) => {
console.log("Proof generated!")
For more details, see: Submitting a Query

Using the result

Once the QueryFulfilled event is emitted, you can then use the dataset of the Query you just built in your smart contract.

AxiomV1Query Contract

The AxiomV1Query contracts are located at:
Mainnet: 0xd617ab7f787adF64C2b5B920c251ea10Cd35a952
Goerli: 0x4Fb202140c5319106F15706b1A69E441c9536306