# "Oracles that pay you" (dApps)
Api3 provides data feeds and pays dApps for using them.
1. [Api3 Market](#api3-market) serves a large and dynamic catalog of data feeds on all major EVM networks.
2. Api3 enables the Oracle Extractable Value (OEV) resulting from the usage of these data feeds to be captured, and pays it to the respective dApps in the form of [OEV Rewards.](#oev-rewards)
::: info 💡 Tip
For quick reference, you can copy-paste [`llms-full.txt`](https://docs.api3.org/llms-full.txt) to your choice of AI assistant.
:::
## Api3 Market
Liquidity is increasingly shifting to newly launched L2 networks, and dApps that are able to branch out to these more quickly are at a significant competitive advantage.
For dApps that utilize data feeds, this is only possible with a data feed provider that has recognized this fact and designed their solutions accordingly.
Our answer to this is [Api3 Market,](https://market.api3.org/) which enables a dApp developer to purchase a plan for the data feed they need and integrate it within minutes, without speaking to a representative or signing a contract.
Furthermore, the whole system is designed to streamline the addition of support for new networks and data feed types, resulting in a large and dynamic catalog.
## OEV Rewards
The state of a blockchain can only be updated in a discrete manner, with a confirmed block or a sequenced transaction.
Practical limits (such as block size and block time) apply to this process, which implies that these updates will invariably lag.
Since data feeds are also updated by updating the chain state, every data feed is at least slightly out of date at all times.
Rent-seeking third parties can exploit this fact to extract funds from data feed users in the form of Maximal Extractable Value (MEV).
[Oracle Extractable Value (OEV)](https://medium.com/api3/oracle-extractable-value-oev-13c1b6d53c5b) is a subset of MEV that oracles have priority in extracting by batching additional operations with their updates.
Furthermore, instead of searching for such OEV opportunities themselves, oracles can auction off this privilege.
Api3 facilitates the capturing of such OEV opportunities, and pays 80% of the associated revenue to the respective partner dApps in the form of [OEV Rewards](/dapps/oev-rewards/), which serves as a new and sustainable revenue stream for them.
::: info ⚠️ Disclaimer
We refer you to the Api3 [terms and conditions](https://api3.org/terms-and-conditions/), which apply to all services and software provided by Api3 (including but not limited to data feeds, and any example OEV bots).
Nothing in this documentation nor related materials should be interpreted as financial, business, nor professional advice.
:::
# Quickstart (dApps)
[Api3 Market](https://market.api3.org/) serves a large and dynamic catalog of data feeds on all major EVM networks.
Follow this guide to learn how to use Api3 Market to integrate a data feed into an example contract.
## Using Api3 Market
- Go to [market.api3.org.](https://market.api3.org/)
- Click the toggle button to view the testnets, and pick one where you have funds.
- On the network page, you will see a search bar (1), some of the data feeds that are already active on the network under "Featured Feeds" (2), and a link to the catalog (3).
Start typing the name of a data feed in the search bar, and click it once it appears in the drop-down.
Alternatively, you can view the catalog and click the data feed there, which will be equivalent to searching the full name of the data feed.
::: info 💡 Tip
All data feeds are inactive by default.
Purchasing a plan activates it until the plan expires.
Everyone can use an active data feed.
On the network page, active feeds appear as cards, and inactive feeds appear as rows with "Activate" buttons.
If you pick a data feed that is already active on the network, you will be taken to the data feed page directly.
Otherwise, you will be taken to the activation page first.
To experience the entire flow, we recommend picking a data feed that is not active.
:::
- If you have picked a data feed that is not active, you will be taken to the activation page next.
Select the parameters, review the duration and price, and click the "Purchase" button to pay.
- Once your purchase transaction is confirmed, you can proceed to view the data feed page.
Leave this tab open, as we will come back to it later in the guide.
Congratulations! 🎉 You have successfully activated a data feed.
Let's use it in an example contract now.
## Remix example
::: info 💡 Tip
This section uses Remix IDE.
If you prefer using Hardhat, you can clone [`data-feed-reader-example`](https://github.com/api3dao/data-feed-reader-example) and follow the instructions in its README.
:::
- Go to [Remix.](https://remix.ethereum.org)
- With the "File explorer" tab selected on the left sidebar, click the hamburger button and select "Clone".
Enter `https://github.com/api3dao/data-feed-reader-example` and click "OK".
- With the "File explorer" tab selected on the left sidebar, double-click `contracts/` to expand it, then click `DataFeedReaderExample.sol`.
- With the "Solidity compiler" tab selected on the left sidebar, click "Compile DataFeedReaderExample".
- With the "Deploy & run transactions" tab selected on the left sidebar, select "Injected Provider - MetaMask" from the "Environment" drop-down.
::: info 💡 Tip
If you just purchased a plan on Api3 Market, your MetaMask wallet should be connected to the correct network.
If not, ensure your wallet is connected to the network where the data feed exists, where we'll deploy DataFeedReaderExample.
:::
- Return to the data feed page on Api3 Market and click "Integrate".
- Click the copy icon next to the displayed Api3ReaderProxyV1 address.
Please note that [OEV Rewards](/dapps/oev-rewards/) is disabled on testnets.
For information about using this selection on mainnets, refer to [this section.](/dapps/integration/index.md#integration-information)
- Return to Remix IDE.
With the "Deploy & run transactions" tab selected on the left sidebar, paste the Api3ReaderProxyV1 address into the textbox next to the "Deploy" button, then click the button.
- After the transaction is confirmed, you can call the publicly accessible functions of DataFeedReaderExample.
Under "Deployed Contracts", expand 'DATAFEEDREADEREXAMPLE AT ...', then click "readDataFeed".
You'll see the values that DataFeedReaderExample reads from Api3ReaderProxyV1.
## What next?
This guide should help you get started with a hackathon project.
For production use of Api3 data feeds, please continue to the [integration section.](/dapps/integration/)
You can also learn how to [get paid](/dapps/oev-rewards/) for using Api3 data feeds.
# Using Api3 Market (dApps → Integration)
See the [Quickstart](/dapps/quickstart/index.md) page for a basic guide on how to use [Api3 Market.](https://market.api3.org/)
This page provides further details about using it in production.
## Update parameters
Update parameters specify the conditions that trigger a data feed update.
Api3 Market supports two update parameters: [deviation threshold](#deviation-threshold) and [heartbeat interval](#heartbeat-interval).
### Deviation threshold
Deviation is the difference between the on-chain and off-chain values of a data feed.
It is measured as a percentage, and an update is initiated when the deviation exceeds the **deviation threshold**.
For example, if the deviation threshold is 1% and the on-chain value of the data feed is 100, an update is initiated when the off-chain value goes below 99 or above 101.
::: info ℹ️ Info
Note that it is not possible to guarantee a maximum deviation amount, as there is no theoretical limit to how fast the off-chain value of a data feed can change.
When we refer to a 1% deviation threshold, we mean that at the time of a deviation threshold-related update, the deviation will have exceeded 1%.
:::
Api3 Market offers the following deviation threshold options:
- 5%
- 2.5%
- 1%
- 0.5%
- 0.25%
::: info ⚠️ Warning
We assume that lower deviation thresholds are always more desirable, and thus do not validate if updates are necessary according to the update parameters.
In simpler terms, a data feed with a 1% deviation threshold can be updated even if it has only deviated by 0.5%.
For rare use cases that require different behavior, we do not recommend using Api3 data feeds.
:::
Upholding a lower deviation threshold requires more frequent data feed updates.
Consequently, you can expect higher [prices](#pricing) for lower deviation thresholds.
### Heartbeat interval
A heartbeat is a data feed update that is made to uphold a maximum period of time between two consecutive updates, which is called the **heartbeat interval**.
Api3 Market only offers a 24-hour heartbeat interval.
::: info ℹ️ Info
Similar to how the deviation threshold works, an update is expected to be initiated when the on-chain value is older than the heartbeat interval.
However, we have observed that some users include `require()` statements in their contracts to verify that the heartbeat interval is upheld.
To reduce the probability of this usage pattern causing transactions to revert, we initiate heartbeat interval-related updates 2 minutes earlier than necessary.
Note that this still does not provide a hard guarantee, and your contract should be able to handle cases where the on-chain value is older than the heartbeat interval.
:::
## Plan durations
Api3 Market offers 7-day plans on testnets and 3-month plans on mainnets.
Each purchased plan has an expiration date, and the respective update parameters will stop being upheld after that.
Let's go over a few example cases:
- BTC/USD on Ethereum is inactive.
The user purchases a 1% deviation threshold for 3 months.
The data feed will immediately activate and deactivate 3 months later.
- BTC/USD on Ethereum is active with a 1% deviation threshold, set to expire 1 month later.
The user purchases a 1% deviation threshold for 3 months (with a [discount](#discounts)).
The expiration will be extended to 3 months from now.
- BTC/USD on Ethereum is active with a 5% deviation threshold, set to expire 1 month later.
The user purchases a 1% deviation threshold for 3 months (with a [discount](#discounts)).
The data feed will switch to a 1% deviation threshold and deactivate 3 months later.
- BTC/USD on Ethereum is active with a 0.5% deviation threshold, set to expire 1 month later.
The user purchases a 1% deviation threshold for 3 months (with a [discount](#discounts)).
The data feed will continue running with a 0.5% deviation threshold for 1 month, switch to a 1% deviation threshold, run for another 2 months, and deactivate.
When plans with different deviation parameters are queued, the Api3 Market interface displays them as shown below.
::: info 💡 Tip
Once a plan has been purchased, Api3 guarantees that the [update parameters](#update-parameters) will be upheld for the [plan duration](#plan-durations).
However, it is the user's responsibility to ensure that plans are purchased to keep the data feed active as long as necessary.
You can use the "Set Reminder" button under the expiration date to avoid forgetting to renew your plans.
:::
## Pricing
The gas cost of operating a data feed is a function of:
- The expense of data feed updates
- The frequency of data feed updates
- The duration of data feed operation
We maintain a history of data feed update gas costs and update counts required to uphold the offered deviation thresholds, and estimate the future operational costs of the offered plans based on these.
::: info 💰 Financial
The prices you see on Api3 Market are the exact operational costs that we estimate (or $0.05/day, whichever is higher).
This means that it is unlikely that you will find a better bargain.
We do not plan to monetize data feed plans at any point.
Our monetization model is designed around OEV, which makes this pricing strategy sustainable.
:::
### Discounts
It is not possible to estimate the future gas cost of operating a data feed with perfect accuracy.
If we underestimate and find that the price was below the gas cost, we cover the difference.
::: info ⚠️ Warning
**On testnets only**, we stop updating if the payment runs out, even if the plan has not expired yet.
To resume updates in such cases, simply purchase a new plan.
:::
If we overestimate the price, the remainder rolls over to the next plan purchased for the same network–data feed pair, which appears as a **discount** on Api3 Market as seen below.
Similarly, when a user purchases a plan for a data feed that is already active, the remainder of the payments made for earlier purchases will appear as a discount.
::: info 💰 Financial
In some cases, the discount allows you to get the plan for free.
:::
### Gas grants
You can request a gas grant for your dApp by filling out [this form,](https://api3dao.typeform.com/to/TBTu8bJt) where you can ask us to purchase plans for you.
## Integration information
Clicking "Integrate" on a data feed page will display the information needed for a [contract integration.](/dapps/integration/contract-integration.md)
By default, you will see that "Skip OEV Rewards" is selected and an Api3ReaderProxyV1 address is displayed.
If you wish to forgo OEV Rewards, you can simply use this address in your integration.
Alternatively, you can select the "Earn OEV Rewards" option, provide the name of your dApp, and (if the proxy has not been deployed earlier) click the "Deploy Proxy" button to send a transaction.
Once the transaction goes through, the Api3ReaderProxyV1 address you should use in your integration will be displayed.
Note that this address is different from the one displayed when "Skip OEV Rewards" is selected.
::: info 💡 Tip
Can't find your dApp?
Follow the OEV Rewards [onboarding steps](/dapps/oev-rewards/index.md#how-to-get-onboard) first.
:::
## Verifying first-party sources
The term _first-party oracle_ is coined in the Api3 whitepaper and refers to an API provider that provides oracle services without depending on any middlemen.
There are three conditions to be verified to check if an oracle service is first-party:
- The operator of each individual node must also operate an independent API service as their primary business model for them to be called API providers.
- Each API provider must certify their public key and sign their data with the respective private key.
- Each API provider must make their signed data available themselves, without depending on third-party APIs, blockchains, or state channels.
Api3 provides the only first-party oracle solution.
Furthermore, we have implemented functionality for the public to be able to easily audit this.
On a data feed page, when you hover your mouse over the logo of a source, you can observe the Market frontend verifying the conditions above in real-time.
If you want to see what happens under the hood, you can click "Verified," which allows you to make an HTTP request to the "signed API" of the source, https://signed-api.coingecko.com/, and receive a response such as the following:
```json
{
"stage": "aws",
"version": "3.0.1",
"currentTimestamp": "1740583493",
"deploymentTimestamp": "1739870993",
"configHash": "0xbd159fb423d5eef7abd7947cf8ad1731f0c60cc2e093877837988907580539c9",
"certifiedAirnodes": ["0xf19572194e6aD6d84666906D5287e2c9427655C2"]
}
```
We know that CoinGecko is a reputable API provider, they own the `coingecko.com` domain, and this response comes from that domain.
`certifiedAirnodes` is the list of addresses of the accounts that CoinGecko uses to sign its data (only `0xf19572194e6aD6d84666906D5287e2c9427655C2` in this case), and the Market frontend confirms that the respective data feed is configured to use data signed by one of these certified accounts.
Finally, all recent data points signed by CoinGecko can be fetched directly from them through https://signed-api.coingecko.com/public/0xf19572194e6aD6d84666906D5287e2c9427655C2.
# Contract integration (dApps → Integration)
This page provides important information on how to integrate Api3 data feeds into a contract.
Please read it in its entirety before attempting an integration.
::: info ⚠️ Warning
Api3 does not authorize any members or affiliates to provide security advice.
You are solely responsible for following the instructions on this page.
:::
## Api3ReaderProxyV1
Api3ReaderProxyV1 is a contract that is used to read a specific Api3 data feed.
For example, to read ETH/USD on Ethereum, one can simply call the [`read()` function](https://etherscan.io/address/0x5b0cf2b36a65a6BB085D501B971e4c102B9Cd473#readProxyContract#F17) of a respective Api3ReaderProxyV1.
You can use Api3 Market to see the Api3ReaderProxyV1 address you should use for a specific data feed, as described [here.](/dapps/integration/index.md#integration-information)
To summarize, you should use the Api3ReaderProxyV1 address that appears after selecting "Earn OEV Rewards" and entering the name of your dApp.
::: info ⚠️ Warning
To be eligible for OEV Rewards, you are required to use the Api3ReaderProxyV1 contracts belonging to your dApp.
:::
### Printing Api3ReaderProxyV1 addresses
For your convenience, Api3 representatives may deploy OEV Rewards-enabled Api3ReaderProxyV1 contracts on your behalf and provide you with a list of commands that will print their addresses.
By running these commands yourself, you can ensure that you are using the correct addresses.
::: info 💡 Tip
We try to verify our contracts on all block explorers, with varying success due to their practical limitations.
Since Api3ReaderProxyV1 is deployed deterministically, the lack of verification on a block explorer does not pose a security concern.
:::
These commands should be in the following format, where the dApp alias (assigned to you by Api3 during [registration](/dapps/oev-rewards/index.md#how-to-get-onboard)), chain ID, and dAPI names match your specific case:
```sh
npx @api3/contracts@latest print-api3readerproxyv1-address \
--dapp-alias lendle \
--chain-id 5000 \
--dapi-name ETH/USD
```
The command above prints:
```
dApp alias: lendle
chain: Mantle
dAPI name: ETH/USD
• Please confirm that https://market.api3.org/mantle/eth-usd points to an active feed.
• Your proxy address is https://mantlescan.xyz/address/0x776E79D916e49BBDb8FEe0F43fF148C2Ed3bE125
Please confirm that there is a contract deployed at this address before using it.
```
Note that if an Api3 representative has provided you with this command, you can expect the Market page to point to an active feed and the proxy to already be deployed.
Do not proceed with the integration until you confirm both conditions.
### Reading the data feed
Api3ReaderProxyV1 implements IApi3ReaderProxy, which you can import from [`@api3/contracts`](/dapps/integration/api3-contracts.md) to use in your contract.
```solidity
interface IApi3ReaderProxy {
function read() external view returns (int224 value, uint32 timestamp);
}
```
::: info 💡 Tip
Api3ReaderProxyV1 also implements Chainlink's AggregatorV2V3Interface, which enables it to be used as a drop-in replacement for Chainlink data feeds.
Refer to the [AggregatorV2V3Interface page](/dapps/integration/aggregatorv2v3interface.md) for details.
:::
#### Using `value`
`value` is an `int224`, which is the median of individual on-chain data feed `value`s that contribute to the aggregation.
::: info 💡 Tip
Note that `value` has a signed type.
However, in the context of a data feed that reports the price of an asset, non-positive values do not make sense.
It is good practice to validate against such conditions, as in `require(value > 0)`.
:::
All Api3 data feeds have 18 decimals.
For example, if ETH/USD is `2918.5652133`, `value` will read `2918565213300000000000`.
::: info ⚠️ Warning
It is extremely risky to validate the data feed value based on practical assumptions.
An example where doing so went wrong was Chainlink requiring their LUNA/USD data feed value to be at least `0.1`.
Doing so caused them to misreport by an order of magnitude during the UST depeg, and caused a dApp to suffer more than $14MM in damages.
We do not utilize such heuristics on our end, and recommend that you be very careful if you do.
:::
#### Using `timestamp`
`timestamp` is a `uint32`, which is the median of individual on-chain data feed `timestamp`s that contribute to the aggregation.
The `timestamp` of an individual data feed represents the system timestamp that the respective API provider reported when they called their API to get the value.
Its main role is to act as a nonce that prevents data feed updates from being replayed.
::: info ⚠️ Warning
`timestamp` is not the block timestamp at the time of the update.
It is the reported system (i.e., off-chain) time.
One common mistake is using `require(timestamp <= block.timestamp)`.
This check should be avoided for two reasons:
1. If `block.timestamp` lags compared to actual time, this will revert.
However, that is not a valid reason to avoid using the data feed, as doing so will cause unnecessary downtime for your contract.
2. Some L2 implementations use the timestamp of the latest block as `block.timestamp` (rather than the system time of the node) when a static call is made to the RPC endpoint.
This means that the `require()` will revert during static calls even when `block.timestamp` does not actually lag.
This prevents OEV searchers from using the intended workflow and reduces the amount of OEV Rewards you will receive in practice.
:::
In general, the only acceptable use of `timestamp` is validating whether the heartbeat interval is upheld, as in `require(timestamp + 24 hours > block.timestamp)`.
However, unless your contract design specifically relies on the data feed value being at most a day old (which is unlikely), we do not necessarily recommend this approach either.
::: info 💡 Tip
Your auditors may not be familiar with best practices in the context of Api3 data feeds.
We recommend directing them to this page.
:::
## Api3ReaderProxyV1 combinations
See the [`data-feed-proxy-combinators`](https://github.com/api3dao/data-feed-proxy-combinators) repository for various modular contracts that you can use to create combinations out of Api3ReaderProxyV1 contracts.
For example, you can combine an `ETH/USD` Api3ReaderProxyV1 contract and a `wstETH/ETH Exchange Rate` Api3ReaderProxyV1 contract to read a `wstETH/USD` value.
## Mixed oracle design
Some dApps choose to mix oracle solutions, either by refusing service if they are not in consensus, or by using one primarily and deferring to another in case of inconsistency.
In such setups, Api3 data feeds need to be treated differently due to OEV considerations.
Specifically, the vast majority of OEV is extracted during times of volatility, and allowing other oracle solutions interfere during such times may result in the loss of a significant amount of OEV revenue, reducing your [OEV Rewards](/dapps/oev-rewards/).
The golden standard is only using Api3 data feeds, and if you must use Api3 data feeds as your primary source with another solution as a fallback, you should tolerate as much inconsistency as possible.
::: info 💡 Tip
We recommend that you tolerate at least 10% inconsistency.
Based on our analysis, any less will hinder OEV extraction during times of high volatility.
:::
Note that using Api3 data feeds for only some asset prices still counts as a mixed design.
Consider a lending platform that uses the ETH/USD Api3 data feed and the USDT/USD data feed from another oracle solution.
A user takes out a USDT loan with ETH collateral, and the following price action renders the position liquidatable once the ETH/USD data feed is updated.
However, a rogue USDT/USD update by the other oracle solution may expose the OEV opportunity to the public before it can be claimed for you.
::: info 💰 Financial
It is up to you to maximize your OEV Rewards by integrating correctly.
Not maximizing OEV Rewards causes a loss of profits and therefore constitutes a security issue.
:::
# AggregatorV2V3Interface (dApps → Integration)
AggregatorV2V3Interface is intended for use by contracts that were originally built to use Chainlink data feeds.
All considerations from the [contract integration page](/dapps/integration/contract-integration.md) still apply.
::: info ⚠️ Warning
Api3 data feeds are aggregated from asynchronous data feeds to provide maximal availability guarantees, which means they are not updated in rounds.
As a side effect, Api3ReaderProxyV1 does not implement the round-related functionality of AggregatorV2V3Interface.
If your contract depends on round-related functionality, it would not be appropriate to use Api3ReaderProxyV1 via AggregatorV2V3Interface.
Instead, we recommend using IApi3ReaderProxy with a custom adapter that fits your specific needs.
:::
You can interact with Api3ReaderProxyV1 through AggregatorV2V3Interface if all of the following conditions apply:
- Your contract primarily relies on the current data feed value (`latestAnswer()` of AggregatorInterface or `answer` returned by `latestRoundData()` of AggregatorV3Interface).
- If your contract uses the current data feed timestamp (`latestTimestamp()` of AggregatorInterface or `updatedAt` returned by `latestRoundData()` of AggregatorV3Interface), it uses it only for a staleness check (e.g., to verify if the feed has been updated within the last heartbeat interval).
- Any other values used do not affect your contract's logic or your dApp's off-chain infrastructure.
For example, your contract may emit `roundId` in an event strictly for logging purposes.
- Your dApp's off-chain infrastructure does not depend on events defined in AggregatorInterface.
::: info 💡 Tip
Lending protocols typically satisfy these conditions.
:::
On the other hand, you should not interact with Api3ReaderProxyV1 through AggregatorV2V3Interface if any of the following conditions applies:
- Your contract depends on Chainlink feed implementation details, such as the round ID increasing with every update.
- Your contract depends on querying past updates using `getAnswer()` or `getTimestamp()` of AggregatorInterface, or `getRoundData()` of AggregatorV3Interface.
- Your dApp's off-chain infrastructure depends on events defined in AggregatorInterface.
::: info 💡 Tip
DeFi protocols such as perpetual derivative exchanges are typically vulnerable to MEV searchers performing time arbitrage.
Chainlink data feeds provide past round data primarily to address this issue, but this solution significantly degrades UX by requiring multiple transactions for certain actions.
Instead, you can simply read the latest data feed value from an Api3 data feed and receive compensation for time arbitrage value extraction through [OEV Rewards.](/dapps/oev-rewards/)
:::
If you have any doubts about interacting with Api3ReaderProxyV1 through AggregatorV2V3Interface, you can refer to the [Api3ReaderProxyV1 implementation](https://github.com/api3dao/contracts/blob/main/contracts/api3-server-v1/proxies/Api3ReaderProxyV1.sol) to see exactly how these functions behave.
# `@api3/contracts` (dApps → Integration)
[`@api3/contracts`](https://www.npmjs.com/package/@api3/contracts) is an npm package that provides three basic features for Api3 data feed users:
1. `@api3/contracts/interfaces/IApi3ReaderProxy.sol` is imported by contracts that call Api3ReaderProxyV1 contracts through IApi3ReaderProxy.
2. `@api3/contracts/mock/MockApi3ReaderProxy.sol` is used in tests.
3. - `computeCommunalApi3ReaderProxyV1Address()` is used to validate adresses shown by Api3 Market when ["Skip OEV Rewards"](/dapps/integration/index.md#integration-information) is selected.
- `computeDappSpecificApi3ReaderProxyV1Address()` is used to validate adresses shown by Api3 Market when ["Earn OEV Rewards"](/dapps/integration/index.md#integration-information) is selected.
For detailed examples of how to use these features, see the [`data-feed-reader-example` repository.](https://github.com/api3dao/data-feed-reader-example)
Additionally, `@api3/contracts` provides a CLI command for printing OEV Rewards-enabled (i.e., dApp-specific) Api3ReaderProxyV1 addresses, as described [here.](/dapps/integration/contract-integration.md#printing-api3readerproxyv1-addresses)
::: info ℹ️ Info
[AggregatorV2V3Interface](/dapps/integration/aggregatorv2v3interface.md) is not exported from this package, since contracts using this interface must have already imported it from elsewhere.
:::
# Security considerations (dApps → Integration)
A data feed is an on-chain service that is driven by off-chain components.
Therefore, as long as you continue to use it, there will be ongoing security considerations that you should be aware of.
::: info ℹ️ Info
Api3 data feeds have never misreported or experienced an outage.
This page merely discusses theoretical scenarios that apply to any data feed.
:::
## Smart contract risk
Imperfections in a smart contract implementation may cause it to behave unexpectedly, potentially resulting in financial losses for interacting parties—a scenario known as smart contract risk.
Like all smart contracts, Api3ReaderProxyV1 carries this inherent risk.
We propose three methods to assess the smart contract risk.
You can refer to the related [audit reports.](https://github.com/api3dao/contracts?tab=readme-ov-file#security)
A more practical approach is to refer to [our historical TVS](https://defillama.com/oracles/Api3) to understand the _battle-testedness_ of our data feeds.
Additionally, you are welcome to review the contracts behind [Api3ReaderProxyV1](/dapps/integration/contract-integration.md#api3readerproxyv1), specifically [Api3ServerV1](https://github.com/api3dao/contracts/blob/main/contracts/api3-server-v1/Api3ServerV1.sol) and [Api3ServerV1OevExtension](https://github.com/api3dao/contracts/blob/main/contracts/api3-server-v1/Api3ServerV1OevExtension.sol).
Our [contract developer docs](https://github.com/api3dao/contracts/tree/main/docs) provide additional context for understanding the design decisions behind these contracts.
## Privileged accounts
Api3ReaderProxyV1 is a [UUPS-upgradeable](https://eips.ethereum.org/EIPS/eip-1822) contract, which can be upgraded by [a 4-of-8 multisig](https://github.com/api3dao/contracts/blob/main/data/manager-multisig-metadata.json#L2) that is owned by members of the Api3 technical team.
This upgradeability feature is intended to be used only in exceptional occasions to respond to newly discovered compiler, library or contract vulnerabilities, or to migrate users to potential new versions of the contracts.
[A 4-of-4 multisig,](https://github.com/api3dao/contracts/blob/main/data/dapi-management-metadata.json#L2) which again is owned by members of the Api3 technical team, approves the root of a Merkle tree containing data feed configurations.
This means adding, removing or replacing API providers that contribute to the aggregation of data feeds requires signatures from all owners of this multisig.
::: info ℹ️ Info
Data feed source configuration depends on multiple factors including uptime, accuracy, incident response time, and qualitative considerations.
Multisig signers have access to this data and are responsible for its verification.
:::
## Data correctness
The [Api3 whitepaper](https://github.com/api3dao/api3-whitepaper) poses that all oracle data comes from API providers in practice, and the trust-minimized way to receive data from an API provider is for there to be no third-party intermediaries.
We have coined the term _first-party oracle_ to refer to this architecture, where API providers deliver oracle services without needing third parties to facilitate.
Api3 data feeds are on-chain aggregations of data feeds powered by individual first-party oracles.
Each API provider powers a single-source data feed on-chain, and the Api3 data feed is an on-chain median of these individual data feeds, which provides the strongest security guarantees (for example, compared to off-chain aggregation).
You can easily verify the first-party nature of our data feeds [directly on the data feed page in Api3 Market.](/dapps/integration/index.md#verifying-first-party-sources)
::: info ⚠️ Warning
While some oracle solutions are at peace with their third-party status, other oracle solutions such as Pyth incorrectly claim their oracles are first party.
This claim fails in two ways:
First, an API provider is a business that provides an API as a service, and most Pyth oracles are not API providers.
Second, even when a Pyth oracle is an API provider, their data is aggregated and served through Wormhole, introducing a third-party point of failure.
In general, when oracle services use an intermediary blockchain or state channel for delivery, they create a third-party system since the intermediary's consensus model will not match the aggregation model.
Consider a system where 7 API providers supply data and 100+ node operators provide aggregation and data availability—this creates two points of failure, typical of third-party oracle designs.
The secondary point of failure (the node operators) is typically weaker than the primary one (the API providers).
Consequently, when dApps use Pyth data on Ethereum, users pay Ethereum gas fees while only receiving security equivalent to [Wormhole.](https://www.google.com/search?q=wormhole+outage+downtime+"pyth")
:::
## Update parameters
Once a plan is purchased on Api3 Market, the respective data feed will maintain the advertised deviation threshold and heartbeat interval until plan expiration.
This depends on the Api3 technical team to keep the wallets that will send the update transactions funded, and maintain the infrastructure that will use these wallets to send the update transactions.
The operation is backed by the technical team's continuous monitoring, automated alerts, and redundant infrastructure layers.
::: info ℹ️ Info
We have been providing oracle services as early as [2019](https://etherscan.io/txs?a=0x78e76126719715eddf107cd70f3a31dddf31f85a&p=1029), and were listed as the [best responding oracle](/assets/reputation-link.CxhU2iIj.png) among all Chainlink oracles by [`reputation.link`](https://www.google.com/search?q=%22reputation.link%22+chainlink) as of September 2020, which is when we published the [Api3 whitepaper](https://github.com/api3dao/api3-whitepaper) and requested to be removed from Chainlink data feeds.
An important driving factor for this was our insight into systemic issues that could harm users and our confidence in building a better solution.
With this understanding, we designed our architecture and operations from the ground up, leading to our current performance.
:::
## Data availability
We obtain API provider-signed data for feed updates from publicly accessible APIs (the same ones you can use to [verify first-party sources on Api3 Market.](/dapps/integration/index.md#verifying-first-party-sources))
While similar to the [Coinbase price oracle](https://www.coinbase.com/blog/introducing-the-coinbase-price-oracle), our approach involves multiple API providers using our standardized protocol, enabling aggregation.
As a result, even if we cease updating a data feed, further updates remain possible.
MEV searchers, for instance, can access these APIs to perform financially relevant updates.
Similarly, our OEV implementation uses this mechanism, ensuring OEV updates continue even if we stop updating the feed according to the update parameters.
## Oracle Extractable Value (OEV)
[OEV](/oev/) updates provide identical guarantees to regular updates—they are on-chain aggregations of API provider-signed data—so they introduce no additional [data correctness](#data-correctness) risk.
The OEV updates allows winners to frontrun updates of an artificially delayed base feed, a tradeoff designed to benefit the dApp.
dApps using our system will experience a 0–20 second delay in their data feed.
While this delay concerns some users, we can evaluate its impact through a simple framework:
Consider a dApp that generates `X1` revenue with its current oracle solution.
Using Api3 data feeds would generate `X2` revenue (potentially lower than `X1` due to the delay) plus `Y` in OEV Rewards.
When `X1 < X2 + Y`—which is common—Api3 feeds are the more secure choice.
::: info 💡 Tip
An overlooked fact is that traditional oracle solutions without OEV capture are inherently vulnerable.
Their users have faced [hundreds of millions of dollars](https://members.delphidigital.io/reports/api3-the-state-of-oev) in exploits over the years—exploits that were entirely preventable.
Auditors should flag dApps lacking effective OEV capture mechanisms, and dApps continuing to use vulnerable traditional solutions should be required to justify this choice.
:::
# Getting paid (dApps → OEV Rewards)
dApps that use traditional data feeds are constantly exploited by MEV bots that manipulate the order of operations around individual data feed updates.
In practice, this causes dApps to suffer significant and continuous financial losses.
As the antidote, Api3 enables OEV searchers to determine the order of operations around data feed updates.
80% of the resulting revenue is paid to the dApp in the form of OEV Rewards.
::: info 💰 Financial
Api3 provides data feeds [at cost](/dapps/integration/index#pricing) and enables dApps to benefit from OEV Rewards on top.
You might ask, "What's the catch?"
There is none; OEV Rewards come at the expense of third parties who would otherwise solely benefit from MEV.
:::
Api3 data feeds work identically to traditional data feeds, which means that you do not need to modify your contracts in any way to use them.
You can drop in Api3 data feeds to replace your current data feeds and immediately start earning OEV Rewards.
## How to get onboard
Use [this form](https://api3dao.typeform.com/to/FHhFIL41) to get in contact with an Api3 representative who will walk you through the following steps:
1. We register your dApp for it to show up on the Api3 Market [integration page.](/dapps/integration/index.md#integration-information)
2. You let us know which chains you operate on and which data feeds you will use.
::: info 💡 Tip
Don't forget to notify us if you expand to new chains and data feeds later on.
:::
If a gas grant is applicable, we purchase subscriptions for you and deploy an OEV Rewards-enabled Api3ReaderProxyV1 contract for each data feed.
::: info 💡 Tip
Alternatively, you can complete this step on your own using [Api3 Market.](https://market.api3.org/)
:::
3. You let us know an address where to receive the OEV Rewards.
::: info 💡 Tip
OEV Rewards are paid in the native currency of your dApp's chain.
The receiving address must be an EOA you control or a contract capable of receiving native currency payments.
:::
4. You [integrate](/dapps/integration/contract-integration) the OEV Rewards-enabled Api3ReaderProxyV1 contracts.
At the end of each month, Api3 will make available a report and 80% of the OEV revenue in the native gas token of the network where your dApp is deployed, with the remainder retained as the protocol fee.
# Overview (OEV)
Oracle Extractable Value (OEV) is a subset of Maximal Extractable Value (MEV) that occurs as a result of an oracle update.
The idea is that different oracle updates have different importance.
Some updates expose profitable opportunities on the market. Searchers actively compete
with each other to be the first to realize these - paying a majority of the exposed value
to block validators in the process. This dynamic is unhealthy, because the
majority of the value should be split between the dApp and the searcher that
realizes the opportunity.
OEV solves this problem by offering the exclusive rights to execute the
oracle update(s), allowing searchers to atomically update the price feed(s) used
by the dApps and profit from the opportunities on the market. The exclusive update
rights guarantee no competition and searchers avoid paying premiums on gas fees.
Api3 facilitates OEV using two ways:
1. Private auctions performed via partnered searchers on non-delayed data.
2. Searching using public Signed APIs on delayed data, open for anyone to participate.
::: info 💡 Tip
For quick reference, you can copy-paste [`llms-full.txt`](https://docs.api3.org/llms-full.txt) to your choice of AI assistant.
:::
## Practical example
Imagine an overcollateralized lending platform that uses Api3 price feeds.
Borrowers in the protocol can be liquidated with an incentive whenever their
position becomes unhealthy to ensure the protocol remains solvent. Say
liquidations can occur if the loan-to-value ratio exceeds 90%. Let's look at
what happens with the protocol's health over time.
Assume that initially there are no unhealthy positions. Many of the price feed
updates that happen are "unnecessary" because they don't expose any unhealthy
positions and the protocol remains healthy. However, after some time there is a
price drop that causes many positions using that asset as collateral to approach
the 90% liquidation threshold.
In this scenario, the next price update that causes a position to become
unhealthy is valuable. Api3 partnered searchers monitor the dApp and public Api3 data sources and notice that a position will become unhealthy after the next oracle update. They submit a transaction that executes the oracle update and perform the liquidation
atomically.
The concept of OEV is not limited to liquidations, but can occur anywhere where
price feed updates potentially expose profitable opportunities, such as
arbitrage and many others.
## OEV distribution
Thus, the majority of the OEV is distributed to the dApp and the
searchers.
Api3 searching revenue is split between:
1. Paying the dApps in the form of [OEV Rewards](/dapps/oev-rewards/).
2. Api3 protocol fee.
For [Api3-curated markets](/curation/), the entirety of the OEV belongs to Api3.
## Get started with OEV
Here are resources to help you get started with OEV:
1. See [OEV Dashboard](https://oev-dashboard.api3.org/) to browse the past OEV performance.
2. Dive deeper into OEV by reading the
[OEV Litepaper](https://raw.githubusercontent.com/api3dao/oev-litepaper/main/oev-litepaper.pdf).
3. Connect with other developers and OEV enthusiasts in our
[OEV Discord channel](https://discord.com/channels/758003776174030948/1062909222347603989).
4. Follow Api3 on [X](https://x.com/api3dao) for the latest news and updates on
OEV.
# Getting started (OEV → In Depth)
To dive deep into OEV, there are two key parts to understand:
1. [Data feeds](/oev/in-depth/data-feeds/) - Focuses on the underlying smart contract architecture and explain how OEV is possible on the lowest level.
2. [MEV with Signed APIs](/oev/in-depth/mev-with-signed-apis) - Explains how to utilize the public Api3 signed data endpoints for the delayed data to start searching.
# Data feeds (OEV → In Depth)
Searchers need a way to monitor real-time off-chain prices to find profitable
opportunities. Traditionally, searchers have needed to buy API subscriptions
from underlying oracle sources, creating additional friction in the process.
Api3 simplifies this process by providing the same data that is used for
updating data feeds to searchers publicly and without cost. But before that, one needs to understand how Api3 oracles work.
## How data feeds work?
Let's start from the ground up. The data feed logic is dictated by the Api3ServerV1
contract. The central part of Api3 feeds is first-party oracles, relying on
cryptographic signatures verified on-chain.
Internally, we refer to our data feeds as dAPIs. This is also the terminology used across Api3 contracts. We'll be following the same terminology in this section.
### dAPI structure
The simplest primitive is a "beacon".
It consists of:
- Airnode address = The identifier of the data provider, e.g. Nodary.
- Template ID = A template represents an endpoint of the data provider API, e.g.
ETH/USD.
Together they represent a data point from a specific data provider. Beacons are
identified by beacon ID, which is the hash of their Airnode address and template ID. They can be
aggregated into "beacon sets" which are identified by the IDs of the constituent
beacons.
Both beacons and beacon sets can be used as price feeds. We use the term "data feed" to refer to
either of them. Term data feed ID is a common name for beacon ID or beacon set ID. Finally, a dAPI is simply a mapping from a human-readable data feed name
to a data feed ID.
### Updating data feed value
So far, we've referred to dAPIs and data feeds as sources of data, not
mentioning how they are kept up-to-date. Api3 feeds are permissionless and
anyone can perform an update, provided they have valid data. To update a beacon,
anyone can call `updateBeaconWithSignedData` on the Api3ServerV1 contract:
```solidity
function updateBeaconWithSignedData(
address airnode, // Airnode address of the beacon to update
bytes32 templateId, // Template ID of the beacon to update
uint256 timestamp, // The off-chain timestamp of the data
bytes calldata data, // The encoded price feed data (decoded as int256 internally)
bytes calldata signature // The signature of the fields above signed by the airnode wallet (owned by the data provider).
) external returns (bytes32 beaconId); // The beacon ID that was updated
```
Similarly, to update a beacon set, one first updates the constituent beacons and
then calls `updateBeaconSetWithBeacons`:
```solidity
function updateBeaconSetWithBeacons(
bytes32[] memory beaconIds // The beacon IDs of the constituent beacons
) external returns (bytes32 beaconSetId); // The beacon set ID that was updated
```
By updating a beacon set, we aggregate the values and timestamps of the
constituent beacons. The typical dAPI refers to a beacon set of multiple
sources. As dAPI references a particular data feed under the hood, modifying the underlying beacon set also updates the dAPI value.
### Off-chain components
There are several off-chain components that are used to keep dAPI values up to
date:
1. [Airnode feed](https://github.com/api3dao/signed-api/tree/main/packages/airnode-feed) -
Deployed by the data providers themselves, Airnode feed continuously queries
the API of the data provider, processes the response, and signs it with the
Airnode wallet. The cryptographically signed data is then pushed to Signed
APIs.
2. [Signed API](https://github.com/api3dao/signed-api/tree/main/packages/signed-api) -
Signed API accepts signed data from API providers and provides an API layer
for off-chain querying.
3. [Airseeker](https://github.com/api3dao/airseeker) - Airseeker is an Api3 push
oracle. It monitors the off-chain and on-chain data and triggers an update
when needed.
All of these tools are open-sourced for transparency.
### Update schedule
dAPIs are updated based on the configured update parameters. An update is
performed whenever a dAPI value exceeds the allowed threshold or the feed was
not updated for a particular amount time.
## OEV updates
::: warning ⚠️ Warning
Currently, OEV updates are possible only for the Api3 partnered searchers and not the general public.
:::
After a dAPI is updated, the changed value is reflected across all protocols
that use the particular dAPI. We call these "base feed updates" to differentiate
them from the OEV updates, which are dApp-specific.
For dApps, OEV is an extension to base feeds, supported by the Api3ReaderProxyV1
contract. This contract is a simple proxy that reads the value either from the
base feed or the OEV feed, whichever is fresher.
The OEV feed is specific to the dApp, and its update only reflects the price for
the dApp that uses this proxy. This is accomplished by the proxy being tied to an
immutable dApp ID field. This allows separate value capturing for each dApp.
::: info ℹ️ Info
Base feeds are configured to serve the signed data with a delay. This design choice guarantees searchers the exclusive rights for OEV update.
:::
### OEV feed
The OEV feed is derived from the base feed by changing its beacons to "OEV
beacons".
An OEV beacon is derived from the base feed beacon by hashing its template ID
using `keccak256`. This makes it possible to share the signed data for OEV
beacons freely, because they cannot be used to update the base feed. The
Api3ServerV1OevExtension contract allows them to be used only with a valid signature and after paying the adequate auction amount.
::: info ℹ️ Example
Say we have the following base feed beacon:
```jsonc
"0xfe395743aff41835420d109be4bf98b93e9d9670f5539fc6392578b4626ecedf": { // Beacon ID
"airnode": "0xc52EeA00154B4fF1EbbF8Ba39FDe37F1AC3B9Fd4",
"templateId": "0x1bb9efc88ac9d910a9edc28e8cad8959d196a551e15c9af3af21247f1605873f",
}
```
To derive the template ID of the OEV beacon, we hash its template ID:
```solidity
keccak256(abi.encodePacked(bytes32(0x1bb9efc88ac9d910a9edc28e8cad8959d196a551e15c9af3af21247f1605873f)))
// Output: 0xbc7896315bfd4b1186a05f219ec71a95def0d038617e7ae534075317866bfd1b
```
Which gives us the following OEV beacon:
```json
"0x154ca7c81eb1ed9ce151d5b6ad894c5ab79d19bee20d89eb061aaf24f788221f": { // Beacon ID
"airnode": "0xc52EeA00154B4fF1EbbF8Ba39FDe37F1AC3B9Fd4",
"templateId": "0xbc7896315bfd4b1186a05f219ec71a95def0d038617e7ae534075317866bfd1b",
}
```
Notice that the beacon ID is different, but the Airnode address is the same.
:::
### dApp IDs
Each dApp that uses OEV feeds is assigned a unique ID, called the "dApp ID". The
granularity of auctions is at the dApp level, meaning the auction winner is able
to update any of the price feeds associated with this dApp ID. This ID is
hardcoded in the OEV proxies of the dApp.
The ID has no meaning other than to group proxies of the same dApp together.
#### Programmatically
Searchers can use [unsafeComputeDappId](https://github.com/api3dao/contracts/blob/52109d0d285d3ac485a2f0ed68bd7799e75a9722/src/proxy.ts#L57) from the `@api3/contracts` package available as an NPM package.
::: info ℹ️ Example
Say we want to determine dApp ID for [dTRINITY](https://dtrinity.org/). From the OEV dapps catalog, we see the dApp alias is `dtrinity` and the chain is Fraxtal. Fraxtal has chain ID `252`. To derive the dApp ID we call `unsafeComputeDappId` with arguments `dtrinity` and `252`.
```js
const dTrinityDappId = unsafeComputeDappId('dtrinity', 252);
// 16210721173577624589952893185091679941657223823840386808143855919126917477566
```
:::
#### Using the CLI
Alternatively, searchers can use the `compute-dapp-id` command from the `@api3/contracts` package.
::: info ℹ️ Example
For the same example as above, run the following command:
```sh
npx @api3/contracts@latest compute-dapp-id \
--dapp-alias dtrinity \
--chain-id 252
```
The command will output:
```
dApp alias: dtrinity
chain: Fraxtal
• dApp ID: 16210721173577624589952893185091679941657223823840386808143855919126917477566
```
:::
### dApp sources
Searchers need to know the proxy address and the underlying dAPI name used by
the OEV proxy. The dApps have full control over what proxies they use, and searchers
should refer to their documentation or inspect the chain-state of their contracts to get an
up-to-date proxy address.
To determine the underlying beacons used by the dAPI, you can use the
AirseekerRegistry contract on the target chain. Searchers need to monitor values for these beacons with the public Signed APIs. Note
that these are the base feed beacons and the searcher is expected to derive
the OEV beacons to monitor the OEV data.
#### Data feed details encoding
The AirseekerRegistry contract uses a particular encoding for data feed details
so that the details can be persisted on-chain as a single `bytes` value. The
callers need to decode this value to get the actual data feed details.
Decoding depends on whether the feed is a beacon or a beacon set. Assume we have
encoded `dataFeedDetails` and we need to decode it. Note that the encoding
follows a similar principle.
The decoding of a beacon:
```solidity
(address airnode, bytes32 templateId) = abi.decode(
dataFeedDetails,
(address, bytes32)
);
```
The decoding of a beacon set:
```solidity
(address[] memory airnodes, bytes32[] memory templateIds) = abi.decode(
dataFeedDetails,
(address[], bytes32[])
);
```
To know which encoding to use, you can check the length of the
`dataFeedDetails`. For a single beacon, the length is always `64` bytes, because
both `address` and `bytes32` are encoded using 32 bytes. For a beacon set, the
length depends on the number of beacons encoded.
::: warning ⚠️ Airnode Mnemonic Rotation
Data providers rotate their Airnode mnemonics every 6 months as part of Api3's security practices. This results in new Airnode addresses being generated. Please refer to the [Api3 Market](https://market.api3.org) or directly on-chain data for the latest Airnode addresses.
:::
::: info ℹ️ Example
Say there is a dApp proxy that uses the `ETH/USD` dAPI. We can compute the
details for this dAPI off-chain by:
```js
const encodedDapiName = ethers.utils.formatBytes32String('ETH/USD'); // 0x4554482f55534400000000000000000000000000000000000000000000000000
const encodedDapiNameHash = ethers.utils.keccak256(encodedDapiName); // 0x9e6138f8f57d7b493a8364edb0a0ac92399dfd890eecb9121050836a1749ba42
```
To determine the data feed ID for this dAPI, we can use the
`dapiNameHashToDataFeedId` function on the Api3ServerV1 contract:
```js
const api3ServerV1 = new ethers.Contract(
api3ServerV1Address,
api3ServerV1Abi,
provider
);
const dataFeedId =
await api3ServerV1.dapiNameHashToDataFeedId(encodedDapiNameHash); // e.g. 0x28d7af9ef50bde705ccabb77f27cfa481b998a4a01eaae22825835f611bf7ffe
```
To determine the data feed details, use the `dataFeedIdToDetails` function on
the AirseekerRegistry contract:
```js
const airseekerRegistry = new ethers.Contract(
airseekerRegistryAddress,
airseekerRegistryAbi,
provider
);
const dataFeedDetails = await airseekerRegistry.dataFeedIdToDetails(dataFeedId);
```
The data feed details need to be decoded first. The following is a simplified
version of that decodes the data off-chain:
```js
const deriveBeaconId = (airnodeAddress, templateId) => {
return ethers.utils.solidityKeccak256(
['address', 'bytes32'],
[airnodeAddress, templateId]
);
};
const decodeDataFeedDetails = (dataFeed) => {
// The contract returns empty bytes if the data feed is not registered.
if (dataFeed === '0x') return null;
// This is a hex encoded string, the contract works with bytes directly
// 2 characters for the '0x' preamble + 32 * 2 hexadecimals for 32 bytes + 32 * 2 hexadecimals for 32 bytes
if (dataFeed.length === 2 + 32 * 2 + 32 * 2) {
const [airnodeAddress, templateId] = ethers.utils.defaultAbiCoder.decode(
['address', 'bytes32'],
dataFeed
);
const dataFeedId = deriveBeaconId(airnodeAddress, templateId);
return [{ beaconId: dataFeedId, airnodeAddress, templateId }];
}
const [airnodeAddresses, templateIds] = ethers.utils.defaultAbiCoder.decode(
['address[]', 'bytes32[]'],
dataFeed
);
const beacons = airnodeAddresses.map((airnodeAddress, idx) => {
const templateId = templateIds[idx];
const beaconId = deriveBeaconId(airnodeAddress, templateId);
return { beaconId, airnodeAddress, templateId };
});
return beacons;
};
```
Say the following is the output after decoding the data feed details:
```json
[
{
"beaconId": "0x853a5cc0a517489779025cc8a48e771461a0616665efd6a61424e57997e6dbed",
"airnodeAddress": "0xC9B494D3c6eA3fD42779Df9A136Db10374c98D80",
"templateId": "0x3bdd99217e0be6a0c7812aad3138bd941c2eaf60410740cac7d716d1c5e05558"
},
{
"beaconId": "0xefec8dab2bc20fcc03141d6e521148564e548046d291e116d02581aea7407533",
"airnodeAddress": "0x6b56E47DccFbC82D63Df3da417d26e8B1B877f0f",
"templateId": "0xdeda2f7938bf877d2f011aa550852d3459794e16944ea0b7513465479752ba93"
},
{
"beaconId": "0x00be0673ee8afc9a25fc12edddb7fbe293a7da8f04953171243b594c257141d7",
"airnodeAddress": "0xa924847354c551C79BAE7E75529364bA0449e51A",
"templateId": "0x9f66583540b490e11ee1b40c7b561946eceb96273489c95328c0cd290060129b"
},
{
"beaconId": "0x83a32cce0fc108005ffb0f745f58f1f730770a361a3f051fd058357d525a2182",
"airnodeAddress": "0x5791Fb78D4e37A9D0f0003199D1AE1A8C04C8d89",
"templateId": "0x0970b1e622f50950bf55b3375a849cdd8f8ecbb0ff47d4bde3cbfb225dfcc607"
},
{
"beaconId": "0x752bb8fa00e8c35657a8414884ad4ab976a56fa7d015eb7ade1d60eb15e2a895",
"airnodeAddress": "0xbC6471E88d8aFe936A45bEB8bd20a210EBEF6822",
"templateId": "0xb501fe47e4ad40fd34f5e5a685e79b991b51e2c887d2dbe35bc645ed1f390241"
},
{
"beaconId": "0x4385954e058fbe6b6a744f32a4f89d67aad099f8fb8b23e7ea8dd366ae88151d",
"airnodeAddress": "0xc52EeA00154B4fF1EbbF8Ba39FDe37F1AC3B9Fd4",
"templateId": "0x154c34adf151cf4d91b7abe7eb6dcd193104ef2a29738ddc88020a58d6cf6183"
},
{
"beaconId": "0xf580f27c696b05c8572266e6db5cb5b12a562cac5dfb2e7c240a5ef7d845aebf",
"airnodeAddress": "0x31C7db0e12e002E071ca0FF243ec4788a8AD189F",
"templateId": "0x046e65143918e48adc0a77bada55931622531819be4a7473d80b7f906b813105"
}
]
```
:::
## Public Signed APIs
Signed APIs store the data pushed by Airnode feeds and expose them to the public
via an API. As mentioned, base feed updates are delayed, permissionless and can be
updated by anyone. The OEV feeds are real-time and can only be updated by the Api3 partnered searchers.
The Signed APIs are publicly available. They are deployed on
AWS, ensuring maximum uptime and reliability.
Signed APIs only support querying data for a particular Airnode feed at a time. The
Airnode address is supplied as an HTTP path parameter. The endpoint is cached
and can be called repeatedly. However, excessive call frequency is restricted by
rate limiting or full access denial.
### Base feed endpoints
The following are the base feed endpoints that are publicly available:
1. `https://signed-api.api3.org/public/` - The official Api3
Signed APIs used by the push oracle to update the base feeds.
For example, see the
[Api3 response for Nodary Airnode feed](https://signed-api.api3.org/public/0xc52EeA00154B4fF1EbbF8Ba39FDe37F1AC3B9Fd4).
### OEV endpoints
The following are the OEV endpoints that are publicly available:
1. `https://signed-api.api3.org/public-oev/`
For example, see the
[Api3 response for Nodary Airnode feed](https://signed-api.api3.org/public-oev/0xc52EeA00154B4fF1EbbF8Ba39FDe37F1AC3B9Fd4).
### Response
The response of the Signed API is a JSON object with the following fields:
1. `count` - The number of signed data entries.
2. `data` - An object with the signed data entries. The keys are the beacon IDs
and the values are the signed data objects for the particular beacon(s).
For example:
```json
{
"count": 2,
"data": {
"0xcdaf3ecba9e3f1457b64b1dd33dd6dbd5d3a0d43dbcb6b94fbf755ca8a64f1c2": {
"airnode": "0x31C7db0e12e002E071ca0FF243ec4788a8AD189F",
"encodedValue": "0x0000000000000000000000000000000000000000000000000f710eec75e16680",
"signature": "0x5d382d6636f6b87642db580586bac7f57609f47d30e133dbb6bedede233a6d58065cb4aefbe2d2db1bd61ee9734a8671c05a5f2f79a0192ef491662ba3e390ac1c",
"templateId": "0x174bd80b61ec8451784391df43c8c4ffc4ae82216a65cc15107bfdf4c29f6ca1",
"timestamp": "1727085105"
},
"0x4048c53a7e6d4b857fb04bd4f496691e526f1de8f38880469ec834bc46021cd4": {
"airnode": "0x31C7db0e12e002E071ca0FF243ec4788a8AD189F",
"encodedValue": "0x0000000000000000000000000000000000000000000000000210a4cfc6940000",
"signature": "0x00b84c978f9bab8639a8931990aede93ce34b8f9564ced755499bac503a39d7e7dad882dd1be77954bbbf152b436912204a29a1260283dda863cf489f631a17b1c",
"templateId": "0xee8d0cab5281c59547d4ae9021121df9aec759d457c51b905296610fbef58bed",
"timestamp": "1727085103"
}
}
}
```
# MEV with Signed APIs (OEV → In Depth)
The straightforward way to start OEV searching is to extend MEV bots to utilize the
public
[base feed endpoints](/oev/in-depth/data-feeds/#base-feed-endpoints). This data is delayed compared to data in the [OEV endpoints](/oev/in-depth/data-feeds/#oev-endpoints), so it's expected searchers won't be able to extract much value this way.
The existing MEV bot can utilize the off-chain open-source data and make a base
feed update on-chain whenever there is OEV to be captured. Refer to
[updating data feed value](/oev/in-depth/data-feeds/#updating-data-feed-value)
section for more details.
One advantage of using this data is that searchers can easily simulate the data
feed update (which is permissionless for base feeds) to determine OEV
opportunities more easily. This is a direct improvement over monitoring data
source values and predicting the next oracle update.
::: info 💰 Financial
This improvement on its own provides a major competitive advantage over existing MEV competition and leads to a significant increase in profits. That said, this strategy will not work when the competition is utilizing OEV updates.
:::
## Monitor signed data
First, searchers need to have a list of data feeds used by the dApp and
[obtain its beacons](/oev/in-depth/data-feeds/#dapp-sources). Note that
this can be cached because beacons change only when the
underlying base feed dAPI changes, which happens rarely, only when a dAPI is reconfigured.
Once the list of base feed beacons is known, searchers should periodically call
the public
[base feed endpoints](/oev/in-depth/data-feeds/#base-feed-endpoints) to get
the real-time values for the base feed beacons used by the dApp. This data may
be used immediately to look for OEV opportunities.
## Simulate a data feed update
Assuming a searcher called the Signed APIs and has valid data to update the base
feed, they can use them to simulate the data feed update on-chain followed by a
call to check for OEV opportunities.
The code below demonstrates how this process can be implemented in JavaScript
with the `ethers` library for an imaginary liquidation protocol. Note that this
code makes use of variables that are not defined in the context of the code snippet for brevity. Their
purpose can be understood from the context. The snippet makes use of a well-known [Multicall3 contract](https://www.multicall3.com/).
```javascript
const beaconIds = []; // Assume the data feed is a beacon set with these beacons
const dataFeedSignedData = []; // Assume we have some signed data to update
// 1. Create the calldata for updating the base feed beacons
const dataFeedUpdateCalldata = dataFeedSignedData.map((signedData) => {
const { airnode, templateId, timestamp, encodedValue, signature } =
signedData;
return {
target: api3ServerAddress,
allowFailure: true,
callData: api3ServerV1.interface.encodeFunctionData(
'updateBeaconWithSignedData',
[airnode, templateId, timestamp, encodedValue, signature]
),
};
});
dataFeedUpdateCalldata.push({
target: api3ServerAddress,
allowFailure: true,
callData: api3ServerV1.interface.encodeFunctionData(
'updateBeaconSetWithBeacons',
[beaconIds]
),
});
// 2. Create calldata to simulate liquidation opportunity
const liquidationOpportunityCalldata = {
target: liquidatorContract,
callData: liquidatorContract.interface.encodeFunctionData('liquidate', [
borrower,
]),
allowFailure: false,
};
// 3. Merge the calldata for updating the feeds and capturing the liquidation
const calldata = [...dataFeedUpdateCalldata, liquidationOpportunityCalldata];
// 4. Execute the staticcall multicall, using a standard Multicall3 contract
const result = await multicall3.aggregate3.staticCall(calldata);
```
## Capture MEV
If a searcher successfully simulates a profitable MEV opportunity, they can use
the same data feed calldata and submit the transaction instead of using a
staticcall.
Note that the signed data for base feeds is delayed to ensure OEV searchers have
exclusive priority for OEV extraction.
## Reference implementation
- [Example OEV Compound bot](https://github.com/api3dao/oev-v1-compound-bot/tree/mev-with-signed-apis) - You can also inspect the
[changes](https://github.com/api3dao/oev-v1-compound-bot/compare/mev...mev-with-signed-apis)
needed to add the MEV with Signed APIs functionality to an existing MEV bot.
# Curation (Curation)
Api3 operates as a vault curator on [Morpho,](https://morpho.org/) the largest decentralized lending protocol on Ethereum.
Morpho is a permissionless protocol that allows anyone to create isolated lending markets with custom parameters.
Morpho Vaults aggregate deposits and allocate them across these markets, abstracting the complexity of individual market selection for depositors.
As a curator, Api3 selects lending markets, manages risk parameters, and allocates capital to generate yield for vault depositors.
Api3 operates a set of USDC vaults on Ethereum mainnet, each targeting different markets and strategies.
::: info 💡 Tip
For quick reference, you can copy-paste [`llms-full.txt`](https://docs.api3.org/llms-full.txt) to your choice of AI assistant.
:::
## Skin in the game
Unlike most curators who manage third-party capital exclusively, Api3 deploys a majority of its own treasury as the primary supplier in its vaults.
This means Api3 has direct financial exposure to every market it enables and every risk decision it makes.
External depositors are welcome to supply alongside the Api3 treasury, benefiting from the same risk management and yield strategies, with the assurance that Api3's own capital is subject to identical conditions.
## OEV advantage
Api3 is uniquely positioned as a curator because it is also the oracle provider for its own markets.
This creates a competitive advantage that no other lending protocol or curator has.
During market turmoil, liquidations on lending markets generate [Oracle Extractable Value (OEV)](/oev/) — value that the oracle has priority in capturing by batching additional operations with price updates.
On Api3-curated markets, the entirety of this OEV belongs to Api3 as protocol revenue.
Other protocols, at best, capture only a fraction of the OEV generated on their markets.
This allows Api3 to set lower curation fees to attract borrowers, which in turn decreases the cost of borrowing.
While this means supply-side APY may be lower during calm markets, it makes Api3 markets more attractive to borrowers, driving higher utilization and a healthier lending ecosystem.
The OEV captured during volatile periods more than compensates, providing Api3 with a sustainable revenue stream that is independent of the fee structure.
## Vaults
Api3 operates three USDC vaults on Ethereum mainnet.
All vaults share the same [role structure](/curation/roles-and-operations) and [risk framework](/curation/risk-management).
| Vault | Asset | Strategy | Collateral |
| ------------------------------ | ----- | ---------------------------------- | -------------------------------------------- |
| [Api3 Core](#api3-core) | USDC | Conservative, blue-chip collateral | wstETH, cbBTC |
| [Kabu](#kabu) | USDC | Mid-cap governance tokens | COMP, MORPHO, EIGEN, SYRUP, FLUID, ONDO, BAL |
| [Api3 dCOMP](#api3-dcomp) | USDC | Single dCOMP collateral market | dCOMP |
### Api3 Core
Api3 Core is Api3's flagship conservative vault.
It supplies USDC to lending markets backed by blue-chip collateral assets — wstETH (Lido wrapped staked ETH) and cbBTC (Coinbase wrapped BTC).
These are high-liquidity, battle-tested assets with deep on-chain liquidity and well-established oracle infrastructure.
The vault targets stable, lower-risk yield from borrowing demand against these widely held collateral types.
### Kabu
Kabu supplies USDC to lending markets backed by mid-cap governance and protocol tokens — COMP, MORPHO, EIGEN, SYRUP, FLUID, ONDO, and BAL.
These markets serve borrowers who wish to access liquidity against their governance token holdings without selling.
Given the higher volatility and lower liquidity of these assets compared to blue-chip collateral, supply caps and risk parameters are set more conservatively on a per-market basis.
### Api3 dCOMP
Api3 dCOMP is a single-market vault collateralized by [dCOMP](https://github.com/api3dao/dcomp) — a lightweight, ownable wrapper for the COMP governance token configured with a specific delegate.
While preserving the inherent voting power of the underlying COMP, this wrapper allows the owner to reassign the delegated address. Users can wrap their COMP to receive dCOMP tokens, which can then be deposited as collateral. By wrapping COMP into dCOMP, users can effectively amplify the voting power of the designated delegate.
The Api3 dCOMP vault supplies the USDC borrow-side liquidity for this market, making the mechanism viable.
## Fees
All Api3 vaults use a V1 vault as an intermediary layer that handles the actual market allocations (see [vault architecture](/curation/roles-and-operations#vault-architecture)).
A **5% performance fee** on earned interest is charged at the V1 vault layer. This is the only fee — the V2 (user-facing) vault charges nothing additional.
| Layer | Fee type | Amount |
| -------- | --------------- | ------ |
| V2 Vault | Performance fee | 0% |
| V1 Vault | Performance fee | 5% |
The fee is charged only on interest earned from borrowers, not on deposited principal.
# Roles and operations (Curation)
All Api3 vaults share the same role structure and operational setup stewarded by the API3 Foundation.
## Roles
| Role | Held by |
| --------- | ------------------------ |
| Owner | Api3 Foundation Multisig |
| Curator | Api3 Foundation Multisig |
| Allocator | Api3 Foundation Multisig |
| Guardian | Api3 monitoring team |
The Api3 Foundation Multisig holds the owner, curator, and allocator roles, consolidating governance and operational control under a single entity whose express mission is the development, operation, and maintenance of Api3 services and operations. Role names correspond to terminology in underlying smart contracts and protocols, and do not carry any legal nor other significance or meaning.
The guardian role is operated by the Api3 monitoring team, who can revoke pending actions in case of misconfiguration.
The monitoring team also maintains an emergency fund for manual liquidations in the event that automated liquidation bots fail. Api3 provides no guarantee of the effectiveness or sufficiency of such bots or emergency fund's operation.
## Vault architecture
All Api3 vaults follow a two-layer architecture:
```
Depositor → V2 Vault → V1 Vault → Morpho Markets
```
1. **V2 Vault** — The user-facing vault where depositors supply USDC and receive vault shares. Configured with the Api3 role structure and governance controls described above.
2. **V1 Vault** — The intermediary vault that executes the actual market allocations. The V1 vault holds two allocators:
- The **Morpho Public Allocator**, which enables permissionless reallocation to improve liquidity across markets.
- An **Api3 automated bot** that rebalances allocations to maintain a competitive APY across all enabled markets.
The owner of the V1 vault parameter adjustment abilities is also the Api3 Foundation Multisig. The 5% performance fee is charged at this layer (see [Fees](/curation/#fees)).
## Allocation and rebalancing
Capital allocation across markets is automated.
The Api3 allocation bot monitors market conditions and rebalances the vault's positions to maintain target utilization and competitive APY.
The Morpho Public Allocator complements this by enabling permissionless reallocation when liquidity is needed.
A portion of vault deposits is kept idle to assist with depositor withdrawals and mitigate delays, but does not guarantee delay-free withdrawal.
## Monitoring
Api3 leverages its existing data feed infrastructure to monitor token liquidity and market conditions — the same infrastructure that powers its oracle operations.
- **Liquidity bots** — Ensure smooth and automatic management of vault positions and market allocations.
- **Risk engine alerts** — An alerts-based system that flags suspicious activity, unusual market conditions, or parameter deviations.
- **24/7 monitoring team** — Api3's monitoring team handles escalations from the risk engine around the clock.
## Liquidations
Healthy liquidation markets are essential for vault safety.
When borrowers become undercollateralized, third-party liquidation bots may repay their debt and claim collateral at a discount, aiming to keep the vault solvent.
In the event that automated liquidation bots fail to act, the Api3 monitoring team can execute manual liquidations using a dedicated emergency fund. The amount and usage of such fund is at Api3's sole discretion.
# Risk management (Curation)
Api3's curation risk framework builds on the same rigorous evaluation processes used for its data feed listing policies — processes that have maintained Api3's track record of never misreporting a data feed.
## Market selection
The primary prerequisite for listing a collateral asset is that it passes the Api3 data feed listing policy.
This policy avoids many common industry pitfalls — for example, it prevents listing "stablecoin" assets with weakly protected minting functions.
An asset that passes the listing policy is eligible for market creation.
Beyond the listing policy, Api3 evaluates:
- **Token liquidity** — Is there sufficient on-chain liquidity to support healthy liquidations under adverse market conditions?
- **Token volatility** — Volatile tokens can be listed as long as there is enough liquidity. In these cases, market parameters (such as LLTV) are set conservatively.
- **Smart contract risk** — Has the collateral token been audited and battle-tested in production?
Api3 also lists assets that are unique on the market to fill gaps in the lending ecosystem, even when borrowing demand is not yet established.
## Supply caps
Each enabled market is assigned a supply cap that limits the maximum amount of USDC the vault can allocate to that market.
Supply caps are set according to Api3's internal risk guidelines and are calibrated based on:
- The collateral asset's on-chain liquidity depth
- Historical and expected borrowing demand
- The liquidation loan-to-value (LLTV) ratio configured for the market
- The overall portfolio concentration across all enabled markets
Caps are reviewed and adjusted as market conditions evolve.
## Treasury-backed risk alignment
A distinguishing feature of Api3's curation is that Api3 deploys a majority of its own treasury as vault supply.
This creates a direct alignment of incentives:
- Api3 bears the primary and largest loss in the event of bad debt.
- Every risk parameter decision — market selection, supply caps, LLTV configuration — directly affects Api3's own capital.
- External depositors benefit from the same risk management applied to protect the Api3 treasury.
This "skin in the game" model stands in contrast to curators who manage exclusively third-party capital with limited personal exposure to their risk decisions.
# Disclosure (Curation)
This page describes the scope of Api3's role as a Morpho vault curator, the risks involved in interacting with Api3-curated vaults, and the limits of Api3's responsibility and ability.
By depositing into, withdrawing from, or otherwise interacting with any vault curated by Api3, you acknowledge and accept the Api3 [terms and conditions,](https://api3.org/terms-and-conditions/) which apply to all services and software provided by the API3 Foundation ("Api3"), as well as the additional supplemental disclosures in these docs.
## Scope of curation
Api3's role as a curator is limited to setting on-chain vault parameters within the [Morpho Protocol](https://morpho.org/) — selecting enabled markets, configuring supply caps, assigning roles, and operating the automation described elsewhere in these docs.
Api3 does not hold, control, or take custody of any user assets.
All deposits, withdrawals, and market interactions occur directly through Morpho's open-source, non-custodial smart contracts.
Users remain solely responsible for the custody and security of their private keys and digital assets.
Interactions with Morpho's smart contracts, interfaces, and other services are governed by Morpho's own [terms](https://morpho.org/terms-of-use/) and documentation. Api3 has no responsibility for nor ability to affect the Morpho Protocol services, smart contracts, nor its operation or maintenance.
## No offer, no advice
Nothing in this documentation, nor any parameters, strategies, or materials related to Api3-curated vaults, constitutes:
- An offer to sell or solicitation to buy any financial instrument, investment product, or security.
- Financial, investment, legal, tax, accounting, or other professional advice.
- A recommendation to take or refrain from taking any action.
Api3 does not act as your broker, investment adviser, fiduciary, or asset manager. All information is provided for general informational purposes only, and users are expected to conduct their own due diligence before interacting with any vault, including the verification of any transaction settings and parameters whether or not shown or suggested by any Api3 service or site.
## Risks
Interacting with Api3-curated vaults involves significant risks. These include, but are not limited to:
- **Market risk** — Collateral assets may experience extreme volatility or illiquidity, leading to bad debt in the underlying lending markets that cannot be fully liquidated.
- **Smart contract risk** — Vulnerabilities or bugs in the Morpho Protocol, the collateral tokens, the oracle infrastructure, or any other contract in the stack may result in partial or total loss of funds.
- **Oracle risk** — Although Api3 operates as the oracle provider for its own markets, oracle systems can fail, be manipulated, or behave unexpectedly during adverse market conditions.
- **Parameter and governance risk** — Market configurations, supply caps, role assignments, and other parameters may be changed. Such changes may adversely affect vault performance or withdrawal availability.
- **Liquidity risk** — Under stressed market conditions, withdrawals may be temporarily delayed pending the availability of idle liquidity or successful rebalancing across markets.
- **Regulatory risk** — Legal and regulatory treatment of vaults, tokenized positions, and DeFi lending may change in ways that adversely affect users.
Past performance does not guarantee future results. Vault strategies may be changed, expanded, or discontinued at any time, and parameter changes are at Api3's sole discretion.
## No guarantees
Api3's curation services are provided on an "as is" basis, without warranties of any kind, whether express or implied.
Api3 makes no representation or guarantee as to:
- The safety of assets deposited into any vault.
- The accuracy or appropriateness of any parameter or risk classification.
- The future yield or performance of any strategy.
- The availability of withdrawal liquidity at any given time.
The fact that Api3 deploys a portion of its own treasury into the vaults it curates (as described under [Skin in the game](/curation/#skin-in-the-game)) reflects alignment of incentives, but is not a guarantee, backstop, or commitment to compensate third-party depositors for any loss.
## Restricted access
To Api3's knowledge, Morpho's vaults (whether or not Api3-curated) are not registered with, or approved by, any financial regulatory authority in any jurisdiction.
They are not available to, and must not be accessed by, persons or entities located, incorporated, or resident in jurisdictions where such access is restricted or prohibited — including, without limitation, jurisdictions subject to comprehensive sanctions administered by the UN, OFAC or other competent authorities.
By interacting with an Api3-curated vault, you represent that you are not a prohibited person and that you are acting in full compliance with Api3's terms and all laws applicable to you.
## Limitation of liability
Api3's role is limited to setting vault parameters within the Morpho Protocol. Api3 has no contractual relationship with vault users and assumes no liability nor responsibility for any losses, damages, or claims arising out of or in connection with the use of any vault nor any of the Risks enumerated above, including but not limited to those caused by:
- Smart contract failures, exploits, or forks of the underlying protocols.
- Failures or inaccuracies of any third-party data source, valuation, or price feed.
- User error, loss of private keys, or compromised wallets.
- Regulatory actions, changes in law, or force majeure events (including cyberattacks and network failures).
To the maximum extent permitted by law, Api3 shall not be liable for any direct, indirect, incidental, special, consequential, or punitive damages arising from your use of any Api3-curated vault or other service. In the event of any conflict between these disclosures and the Api3 [terms and conditions](https://api3.org/terms-and-conditions/), the Api3 terms and conditions shall control.