# Axiom Query Protocol

The Axiom V2 Query protocol consists of the following smart contracts:

* `AxiomV2Query`: the primary smart contract for accepting and fulfilling user queries.
* `AxiomV2Prover`: smart contract to manage permissions around who can submit ZK proofs to fulfill queries.
* `AxiomV2HeaderVerifier`: smart contract for verifying the block hashes used in ZK proofs are valid against the block hash cache [maintained](https://intrinsic-1.gitbook.io/axiomv2-sdk/protocol-design/caching-block-hashes) by `AxiomV2Core`.
* `AxiomResultStore`: smart contract that stores the results of queries into `AxiomV2Query`.

## `AxiomV2Query`

`AxiomV2Query` uses `AxiomV2Core` to fulfill queries made by users into Axiom V2. `AxiomV2Query` follows the [Axiom V2 Query Format](https://intrinsic-1.gitbook.io/axiomv2-sdk/protocol-design/axiom-query-protocol/axiom-query-format) and supports:

* On-chain query requests with on- or off\*-chain data availability for queries and on-chain payments or refunds. (\*Off-chain data availability not yet supported in the testnet release.)
* On-chain fulfillment of queries with on-chain proof verification.

For full details of the Axiom V2 Query format, see the following page:

{% content-ref url="axiom-query-protocol/axiom-query-format" %}
[axiom-query-format](https://intrinsic-1.gitbook.io/axiomv2-sdk/protocol-design/axiom-query-protocol/axiom-query-format)
{% endcontent-ref %}

### **Initiating queries on-chain**

Users can initiate a query on-chain with on-chain payment. Both on- and off-chain data availability are supported for the data query:

* `sendQuery`: Send an on-chain query with on-chain data availability.
* `sendQueryWithIpfsData`: Send an on-chain query with data availability on IPFS.
  * This is not yet supported in the testnet release.

On-chain queries are identified by `queryId` as specified in the [Axiom V2 Query Format](https://intrinsic-1.gitbook.io/axiomv2-sdk/protocol-design/axiom-query-protocol/axiom-query-format). For each query, `AxiomQueryMetadata` in `queries[queryId]` stores the relevant metadata, consisting of:

* `state` (`AxiomQueryState`): One of `Inactive`, `Active`, `Fulfilled`, or `Paid`.
* `deadlineBlockNumber` (`uint32`): The block number after which the query is eligible for a refund.
* `payee` (`address`): Once fulfilled, the address payment is due to.
* `payment` (`uint256`): The payment amount, in gwei, escrowed for this query.

### **Query fulfillment**

Query fulfillment is permissioned to the `PROVER_ROLE`, which is initialized to an [`AxiomV2Prover`](#axiomv2prover) contract to manage proving permissions for safety at the moment. There are two ways the `PROVER_ROLE` can fulfill queries:

* `fulfillQuery`: Fulfill an existing on-chain query.
* `fulfillOffchainQuery`: Fulfill a query which was initiated off-chain.

These functions take in a ZK proof verifying a query and fulfill the query by:

* verifying the ZK proof on-chain
* checking the block hashes used in the ZK proof (in the form of a Merkle mountain range) are validated against the cache in [`AxiomV2Core`](https://intrinsic-1.gitbook.io/axiomv2-sdk/protocol-design/caching-block-hashes) using [`AxiomV2HeaderVerifier`](#axiomv2headerverifier)
* for on-chain queries: checking that the query that was just verified corresponds to query originally requested on-chain, by matching the `queryHash`
* calling the desired callback

### **Fees and permissions**

All fees are charged in ETH. User balances are maintained in the `balances` mapping.

* To deposit, users can use `deposit` or transfer ETH together with their on-chain query.
* To withdraw, users can use `withdraw`.

The fee for each query is determined by:

* `maxFeePerGas` (`uint64`): The max fee to use in the fulfillment transaction.
* `callbackGasLimit` (`uint32`): Gas limit allocated for use in the callback.

Each on-chain query will escrow a max payment of

```
maxQueryPri = maxFeePerGas * (callbackGasLimit + proofVerificationGas) + axiomQueryFee;
```

where

* `proofVerificationGas`: Gas cost of proof verification, currently set to `500_000`
* `axiomQueryFee`: Fee charged by Axiom, fixed to `0.003 ether`

To increase gas parameters after making a query, anyone can add funds to a query with `increaseQueryGas`.

Upon fulfillment, the `maxQueryPri` fee is released to the prover, who can call `unescrow` to claim payment.

* The prover can refund the portion of `maxQueryPri` not used in gas or the `axiomQueryFee` to the original query `caller`.
* If the query is not fulfilled by `deadlineBlockNumber`, the `caller` can retrieve their fees paid using `refundQuery`

## `AxiomV2Prover`

`AxiomV2Prover` manages permissions for `fulfillQuery` and `fulfillOffchainQuery` calls into `AxiomV2Query`. These calls are restricted to:

* accounts holding the `PROVER_ROLE`, initially anticipated to be controlled by the Axiom team
  * The `PROVER_ROLE` is currently limited to guard against exploits of the Axiom ZK circuits.  In the event that a ZK circuit is found to be under-constrained, this prevents exploits by malicious provers who could use this to prove inaccurate results to Axiom queries. As the ZK circuit codebase matures, we intend to remove this permissioning.
* additional accounts permissioned for each `(querySchema, target)` pair, tracked in the `allowedProvers` mapping

All calls to `AxiomV2Prover` are forwarded to `AxiomV2Query`.

## `AxiomV2HeaderVerifier`

`AxiomV2HeaderVerifier` verifies that a Merkle mountain range `proofMmr` of block hashes is committed to by block hashes available to [`AxiomV2Core`](https://intrinsic-1.gitbook.io/axiomv2-sdk/protocol-design/caching-block-hashes) in `verifyQueryHeaders`. This happens by comparing `proofMmr` to:

* the padded Merkle mountain ranges committed to in `pmmrSnapshots` and `blockhashPmmr`
* the block hashes available in the EVM via the [`BLOCKHASH`](https://www.evm.codes/#40?fork=shanghai) opcode

## `AxiomResultStore`

`AxiomResultStore` stores results from queries into Axiom V2, indexed by `queryHash`. We store these in the mapping `results`, where `results[queryHash]` stores

```solidity
resultHash = keccak(sourceChainId . dataResultsRoot . dataResultsPoseidonRoot . computeResultsHash)
```
