JSPM

  • Created
  • Published
  • Downloads 8
  • Score
    100M100P100Q53162F
  • License MIT

SDK to build on top of Axiom, the ZK Coprocessor for Ethereum.

Package Exports

  • @axiom-crypto/experimental
  • @axiom-crypto/experimental/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@axiom-crypto/experimental) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

Axiom SDK

Axiom is a ZK coprocessor for Ethereum. Utilizing the properties of Zero Knowledge proofs, Axiom allows anyone to prove historical data on-chain and trustlessly use that data in a smart contract.

Getting started with v2

Create an Axiom instance and a QueryV2 instance from it:

const config: AxiomConfig = {
  privateKey: process.env.PRIVATE_KEY_GOERLI as string,
  providerUri: process.env.PROVIDER_URI_GOERLI as string,
  version: "v2",
  chainId: 5,
};
const overrides = {
  Addresses: {
    AxiomQuery: "AxiomV2Query override address",
  },
};
const axiom = new Axiom(config, overrides); // `overrides` is optional
const query = (axiom.query as QueryV2).new();

Building a Query

There are two ways to build a query. We'll cover both of them here.

// Some constants used below
const WETH_ADDR = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
const WSOL_ADDR = "0xd31a59c85ae9d8edefec411d448f90841571b89c";
const WETH_WHALE = "0x2E15D7AA0650dE1009710FDd45C3468d75AE1392";
const UNI_V3_FACTORY_ADDR = "0x1F98431c8aD98523631AE4a59f267346ea31F984";

Building a Query: Appending method

query.appendHeaderSubquery(
  17000000,
  HeaderField.GasUsed,
);

// 
query.appendReceiptSubquery(
  "0x8d2e6cbd7cf1f88ee174600f31b79382e0028e239bb1af8301ba6fc782758bc6",
  ReceiptSubqueryType.Log,
  0,
  ReceiptSubqueryLogType.Topic,
  1,
  eventSchema
);

// slot 5: mapping(address => mapping(address => mapping(uint24 => address))) public override getPool;
query.appendSolidityNestedMappingSubquery(
  17000000,
  UNI_V3_FACTORY_ADDR,
  "5",
  3,
  [
    WETH_ADDR,
    WSOL_ADDR,
    bytes32(10000),
  ]
);

const callbackQuery = {
  callbackAddr: WETH_ADDR,
  callbackFunctionSelector: getFunctionSelector("balanceOf", ["address"]),
  resultLen: 1,
  callbackExtraData: ethers.solidityPacked(["address"], [WETH_WHALE]),
};

query.setCallback(callbackQuery);
await query.build();

Building a Query: Passing in objects

const dataQuery = {
  headerSubqueries: [
    {
      blockNumber: BLOCK_NUMBER,
      fieldIdx: getHeaderFieldIdx(HeaderField.Nonce),
    },
    {
      blockNumber: BLOCK_NUMBER + 3,
      fieldIdx: getHeaderFieldIdx(HeaderField.Miner),
    },
  ],
  receiptSubqueries: [
    {
      txHash:
        "0x47082a4eaba054312c652a21c6d75a44095b8be43c60bdaeffad03d38a8b1602",
      fieldOrLogIdx: getReceiptFieldIdx(ReceiptField.Status),
      topicOrDataOrAddressIdx: 0,
      eventSchema: ethers.ZeroHash,
    },
  ],
  solidityNestedMappingSubqueries: [
    {
      blockNumber: 17000000,
      addr: "0x1F98431c8aD98523631AE4a59f267346ea31F984",
      mappingSlot: "5",
      mappingDepth: 3,
      keys: [
        bytes32("0x0000000000085d4780b73119b644ae5ecd22b376"),
        bytes32("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"),
        bytes32(3000),
      ],
    },
  ],
};

const callbackQuery = {
  callbackAddr: WETH_ADDR,
  callbackFunctionSelector: getFunctionSelector("balanceOf", ["address"]),
  resultLen: 1,
  callbackExtraData: ethers.solidityPacked(["address"], [WETH_WHALE]),
};

const query = (axiom.query as QueryV2).new(
  dataQuery,
  undefined,  // computeQuery
  callbackQuery,
);

Validating a Query

Validation will write to console.error for any errors detected in each of the fields (it will not throw an error or return early) and will return false if there is any error detected in any of the Query fields.

const isValid = await query.validate();
if (!isValid) {
  throw new Error("Query validation failed.");
}

Submitting a Query

Once a Query has been built, it can be submitted via two methods: On-chain or via IPFS.

Submitting a Query: On-chain

// ensure you've already called `await query.build()`
const payment = query.calculateFee();
await query.sendOnchainQuery(
  payment,
  (receipt: ethers.TransactionReceipt) => {
    // do something here
    console.log("receipt", receipt);
  }
);

Submitting a Query: IPFS

// ensure you've already called `await query.build()`
const payment = query.calculateFee();
await query.sendQueryWithIpfs(
  payment,
  (receipt: ethers.TransactionReceipt) => {
    // do something here
    console.log("receipt", receipt);
  }
);

Additional examples

There are also numerous up-to-date examples in the test/unit/v2/ folder. Some slightly older examples exist in the Examples V2 repo.