Links

Quickstart

Typescript SDK for building Queries into Axiom.

Github repo

The Github repository for this Quickstart is located here:

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 src/index.ts

Installation

You can use your favorite package manager (npm, yarn, pnpm) to install the Axiom SDK:
npm i @axiom-crypto/[email protected]
Install the following additional packages:
npm i ethers dotenv typescript ts-node @types/node

Setup

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
Fill in your .env file with the following information:
PROVIDER_URI_GOERLI=<https Goerli provider URI>
PRIVATE_KEY=<private key for account on Goerli>
Create a new tsconfig.json file via:
tsc --init
The index.ts file in a new src folder inside the axiom-quickstart project. Start by importing the Axiom SDK, Ethers.js, and Dotenv library at the top of the page:
src/index.ts
import {
Axiom,
AxiomConfig,
} from '@axiom-crypto/core';
import type { QueryBuilder } from '@axiom-crypto/core/query/queryBuilder';
import { ethers } from 'ethers';
import dotenv from 'dotenv';
dotenv.config();
Now let's set up a new instance of the Axiom SDK:
src/index.ts
const config: AxiomConfig = {
providerUri: process.env.PROVIDER_URI_GOERLI || 'http://localhost:8545',
version: "v1",
chainId: 5, // Goerli
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:
src/index.ts
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:
async function buildQuery(): Promise<QueryBuilder> {
const queryData = [
{
blockNumber: 9335357,
address: "0x4Fb202140c5319106F15706b1A69E441c9536306",
slot: "0x1f5f6074f4419ff8032f6dd23e65794ca104b323667b66be5a0c73fd6ba2857e",
}, {
blockNumber: 9335466,
address: "0x4Fb202140c5319106F15706b1A69E441c9536306",
slot: "0xe162aef9009a7c65cb8d0c7992b1086de24c2a149b9b0d3db4ed7e64df46fa0f",
}, {
blockNumber: 9335492,
address: "0x4Fb202140c5319106F15706b1A69E441c9536306",
slot: (Math.floor(Math.random()*2**53)).toString(), // random slot
}
];
const qb = ax.newQueryBuilder();
await qb.append(queryData[0]);
await qb.append(queryData[1]);
await qb.append(queryData[2]);
return qb;
}

Submitting a built Query to Axiom

Next we'll write a function to submit the query on-chain to Axiom:
src/index.ts
async function submitQuery(qb: QueryBuilder) {
const { keccakQueryResponse, queryHash, query } = await qb.build();
// Create instance of the axiomV1Query contract - later we'll call methods from this contract
const axiomV1Query = new ethers.Contract(
ax.getAxiomQueryAddress() as string,
ax.getAxiomQueryAbi(),
wallet
);
// Create an on-chain transaction encoding this query using the sendQuery function in the AxiomV1Query contract
const txResult = await axiomV1Query.sendQuery(
keccakQueryResponse,
await wallet.getAddress(),
query,
{
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.

Running the Example

In order to run the whole thing, call buildQuery and submitQuery in a main function:
src/index.ts
async function main() {
const qb = await buildQuery();
await submitQuery(qb);
}
main();
Run this via the following command:
ts-node src/index.ts

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