Quickstart
Typescript SDK for building Queries into Axiom.
In the command line, create and initialize a new Node.js project with the following commands:
- 1.
mkdir axiom-quickstart
- 2.
cd axiom-quickstart
- 3.
npm init
- 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:ALCHEMY_PROVIDER_URI_GOERLI=
In your
index.js
file, start by importing the Axiom SDK, Ethers.js, and Dotenv library at the top of the page: import {
Axiom,
AxiomConfig,
SolidityAccountResponse,
SolidityBlockResponse,
SolidityStorageResponse,
ValidationWitnessResponse,
} 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:
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);
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 |
---|---|---|
|
|
|
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]);
Next we'll write a function to submit the query onchain to Axiom:
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,
walletAddress,
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!")
});
}
Once the
QueryFulfilled
event is emitted, you can then use the dataset of the Query you just built in your smart contract.The AxiomV1Query contracts are located at:
Mainnet:
0xd617ab7f787adF64C2b5B920c251ea10Cd35a952
Goerli:
0x4Fb202140c5319106F15706b1A69E441c9536306
Last modified 23d ago