Skip to main content

Writing an Axiom Circuit

The first step is to write an Axiom circuit using the Axiom Typescript SDK to verify the criteria we decided on for parameters from the Swap event. To learn more about writing an Axiom circuit, see the full guide here.

Circuit Inputs

In order to compile a circuit, you must supply it with a set of valid example inputs. The Axiom CLI will, by default, look for inputs in app/axiom/data/inputs.json. More information can be found in the Axiom CLI Reference.

app/axiom/data/inputs.json
{
"blockNumber": 9610835,
"txIdx": 6,
"logIdx": 3
}
info

Every transaction's transactionHash maps to a unique blockNumber and txIdx combination.

Although we compile with a static set of inputs, after the circuit is compiled it can be used to prove any other set of valid inputs it is given. In the case of this Axiom app, we will use a data service in a later section that will allow users of our app to automatically find the correct inputs to the circuit that are relevant to them.

The inputs that we're interested in can be auto-parsed from the blockNumber, txIdx, and logIdx of a user's Swap transaction that your web app provides.

Circuit Function

The following Typescript circuit code implements logic for validating that the inputs supplied point to an event log with a topic that has an eventSchema that matches the hard-coded value in the circuit. The circuit then sets three pieces of data that will be sent via callback to your smart contract via addToCallback calls.

app/axiom/swapEvent.circuit.ts
import {
addToCallback,
CircuitValue,
CircuitValue256,
getReceipt,
} from "@axiom-crypto/client";

/// For type safety, define the input types to your circuit here.
/// These should be the _variable_ inputs to your circuit. Constants can be hard-coded into the circuit itself.
export interface CircuitInputs {
blockNumber: CircuitValue;
txIdx: CircuitValue;
logIdx: CircuitValue;
}

// The function name `circuit` is searched for by default by our Axiom CLI; if you decide to
// change the function name, you'll also need to ensure that you also pass the Axiom CLI flag
// `-f <circuitFunctionName>` for it to work
export const circuit = async (inputs: CircuitInputs) => {
const eventSchema =
"0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67";

// specify and fetch the data you want Axiom to verify
const receipt = getReceipt(inputs.blockNumber, inputs.txIdx);
const receiptLog = receipt.log(inputs.logIdx);

// get the topic at index 2
const swapTo = await receiptLog.topic(2, eventSchema);

// get the `address` field of the receipt log
const receiptAddr = await receiptLog.address();

addToCallback(swapTo);
addToCallback(inputs.blockNumber);
addToCallback(receiptAddr);
};

To learn more about how to fetch receipt data, see Receipts and Logs.

Compiling, Proving, and Generating sendQuery Arguments

You can run the following commands on the circuit.

# Compile
npx axiom circuit compile app/axiom/swapEvent.circuit.ts --provider $PROVIDER_URI_SEPOLIA

# Prove
npx axiom circuit prove app/axiom/data/compiled.json app/axiom/data/inputs.json --provider $PROVIDER_URI_SEPOLIA

# Generate sendQuery arguments
npx axiom circuit query-params <callback addr> --sourceChainId 11155111 --refundAddress <your wallet addr> --provider $PROVIDER_URI_SEPOLIA

More details are available on the Axiom CLI reference page.