---
description: Using Axiom-verified results in your contract
---

# Handling Axiom Callbacks

Callbacks are triggered automatically once your Query is fulfilled by the Axiom V2 prover. The proof will be verified via Axiom's on-chain verifier before the callback to your smart contract is called.

## Specifying a callback in the Axiom SDK

The `AxiomV2Callback` struct can be built with the following fields:

* `target`: the address of the contract to call the callback on
* `extraData`: data that's passed to the callback (the EVM will automatically right-pad zeroes to this field for any size, which is probably not what you want, so it's recommended that you convert this to `bytes32` if you are dealing with types that are not a multiple of 32 bytes)

```typescript
const exampleClientAddr = "0x888d44c887DFCfaeBBf41C53eD87C0C9ED994165";
const callback: AxiomV2Callback = {
    target: exampleClientAddr,
    extraData: bytes32(0),
}
```

And subsequently set for the Query:

```typescript
query.setCallback(callback);
```

The callback's `resultLen` will be automatically updated based on the `dataQuery` or `computeQuery` set on the Query.

## Receiving the Callback

In order to properly receive the Axiom V2 callback in your contract, you'll need to create a function that has the following argument format:

```solidity
function axiomV2Callback(
    uint64 sourceChainId,
    address caller,
    bytes32 querySchema,
    uint256 queryId,
    bytes32[] calldata axiomResults,
    bytes calldata extraData
) external { 
    // validate msg.sender against the AxiomV2Query address
    <...>
    
    // validate the sourceChainId, caller, querySchema, and queryId
    <...>
    
    // perform your application logic
    <...>
}
```

* `sourceChainId`: The numerical ID of the chain that the Query was generated from
* `caller`: The original contract or EOA that sent the query to Axiom V2
* `querySchema`: The hashed schema, defined as `keccak256(k . vkeyLen . vkey)` and is essentially a commitment to the circuit defined in the `computeQuery`
* `queryId`: A unique identifier for the submitted Query
* `axiomResults`:  An array of the results in `bytes32` format
  * If you used a ComputeQuery, your results will be returned in the order and number of times in which you called `addToCallback(value)`
  * If you used a DataQuery, your results will be returned as value of the results of your data subqueries in the order that you appended them to the `Query`

## Parsing the Callback

When you receive the callback, you will want to validate that all of the fields match so that no one who maliciously submits a Query with invalid data is able to pass the validation.&#x20;

Additionally, you will want to parse the `axiomResults` array to ensure that the data that is passed in matches all of the conditions that are required for the user. For example, if you require that a user submits a proof that their account balance is above 1 ETH at some historic block, you'll likely want to validate that the value of the index of the `axiomResults` array of the account balance is greater than 1 ETH.

## Examples

* We have an [example client implementation here](https://goerli.etherscan.io/address/0x888d44c887dfcfaebbf41c53ed87c0c9ed994165).
* Additionally, the [Autonomous Airdrop example](../examples/autonomous-airdrop) also contains an example implementation.
