Skip to main content

Axiom Cookbook

This section contains circuit recipes to help you access commonly used types of on-chain data.

ETH balance

The balance method on getAccount returns the user's ETH balance at the specified block number.

Example

The following code gets the balance of an account at a single block:

const account = getAccount(
19000000,
"0xe08c32737c021c7d05d116b00a68a02f2d144ac0"
);
const accountEthBalance = await account.balance();

The following code gets the average balance of an account over 25 periods with an interval of blockInterval blocks, ending at block endBlock:

let user = "0xe08c32737c021c7d05d116b00a68a02f2d144ac0";
let endBlock = 19000000;
let blockInterval = 10;
let total = constant(0);
const periods = 25;
for (let i = 0; i < periods; i++) {
const targetBlock = sub(endBlock, mul(i, blockInterval));
const bal = (await getAccount(targetBlock, user).balance()).toCircuitValue();
total = add(total, bal);
}
const avg = div(total, periods);

ERC-20 token balance

To get the ERC-20 token balance of a wallet at a given block number, you'll need the following information to pass to the Axiom subquery getSolidityMapping:

  • blockNumber: - The block number you want to look in to see if they held the token.
  • address: The address of the smart contract for the ERC-20 token
  • slot: The slot number that holds the mapping that defines the token balances

Because Solidity token balances are held in mappings in a smart contract, you'll need to know the slot number that holds the mapping

mapping(address => uint256) public balances;

that stores the token balances in the contract. For instructions on how to find the slot number, see Finding Storage Slots.

Example

const tokenMapping = getSolidityMapping(
18000000,
"0xb24cd494faE4C180A89975F1328Eab2a7D5d8f11",
0
);
// userAddress is the name of the key of the mapping
const val = await tokenMapping.key(userAddress);

ERC-721 (NFT) token ownership

To prove a wallet holds a specific ERC-721 token at a given block number, you'll need the following information to pass to the Axiom subquery getSolidityMapping:

  • blockNumber: - The block number you want to look in to see if they held the token.
  • address: The address of the smart contract for the ERC-721 token
  • slot: The slot number that holds the mapping that defines the holders of the NFT

Because Solidity token balances are held in mappings in a smart contract, you'll need to know the slot number that holds the mapping

mapping(uint256 => address) owners;

that defines NFT ownership. For instructions on how to find the slot number, see Finding Storage Slots.

Example

For example, to find the address of the owner of CryptoPunk #3 at block 18,000,000, we would run the Axiom subquery:

const nftMapping = getSolidityMapping(
18000000,
"0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb",
10
);
const ownerAddress = await nftMapping.key(3);

where slot = 10 because the ownership mapping is in slot 10 for the CryptoPunks contract.

Accessing event logs

To access an emitted event from Solidity, you can check for a log in a transactions receipt. For more information about events, receipts, and logs, check out Receipts and Logs. You'll need the following information:

  • The eventSchema for the event
  • The blockNumber the event occurred in
  • The index within the block of the transaction the event occurred in
  • The address of the contract which emitted the event

Example

To access a PunkBought event on the CryptoPunks contract, you'll need to use the getReceipt Axiom subquery. In this example, we will access the final event here.

// eventSchema for the event signature:
// PunkBought (index_topic_1 uint256 punkIndex, uint256 value, index_topic_2 address fromAddress, index_topic_3 address toAddress)
// which is given by
// keccak256("PunkBought(uint256,uint256,address,address)")
const cryptoPunkAddress = "0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb";
const eventSchema =
"0x58e5d5a525e3b40bc15abaa38b5882678db1ee68befd2f60bafe3a7fd06db9e3";
const blockNumber = 19051308;
const txIdx = 19;
const logIdx = 2;

// specify and fetch the data you want Axiom to verify
let receipt = getReceipt(blockNumber, txIdx);
let receiptLog = receipt.log(logIdx); //get the log at index 2

// check the CryptoPunk address emitted the event
let address = await receiptLog.address();
checkEqual(address.toCircuitValue(), cryptoPunkAddress);

// get the topic at index 1
// for convenience, we enforce within this subquery that the
// event schema of receiptLog is eventSchema
let punkIndex = await receiptLog.topic(1, eventSchema);