- Intro
- Terminology
- Settlement process in DIVA Protocol
- Relevant functions
- Data monitoring
5.1 DIVA subgraph
5.2 General guidance for implementing listeners - Data submission
- Reporting rewards
7.1 Query rewards from subgraph
7.2. Query rewards from contract
7.3 Transfer reward
DIVA Protocol is a smart contract that allows its users to create derivative contracts on virtually any metric with pre-defined expiration times. To calculate the payouts for the long and short positions of the contract, an oracle input is required following the contract's expiration. In DIVA Protocol, the responsibility of outcome reporting is assigned to an Ethereum address at the time of the derivative contract's creation, which can be any EOA or smart contract.
This repository contains a collection of smart contract-based oracle adapters that can be easily plugged into DIVA Protocol by simply providing the corresponding contract address as the data provider when creating a derivative contract.
Audited adapters that can be used:
Other adapters currently in development:
- Shamba adapter (
⚠️ centralized setup) - Arbor adapter (
⚠️ unaudited)
Important: DO NOT use unaudited adapters! Use centralized oracles at your own risk!
This document provides general information about the settlement process in DIVA Protocol and guidance for data providers how to access relevant data. Oracle adapter specific documentation is available in the /docs
directory.
In this document, the following terms will be used interchangeably to refer to the same concepts:
- Derivative contract, contingent pool, and pool
- Protocol, smart contract, and contract
The goal of the settlement process in DIVA Protocol is to determine the value of the reference asset at the time of expiration and, as a result, the payoffs for short and long position tokens. The settlement process begins immediately after the pool expires and concludes when the final reference value attains "Confirmed" status, at which point position token holders can start redeeming their position tokens.
DIVA Protocol's settlement mechanism includes an optional challenge feature that allows human oracles to correct errors made in the submission of data. For smart contract-based oracles that cannot realistically re-submit data, this feature is typically disabled. As a result, the first value submitted by the oracle to DIVA Protocol determines the payouts and users can start redeeming their position tokens.
DIVA Protocol has two fallback layers:
- Fallback data provider: In the event that the assigned data provider fails to submit a value during the submission window, the fallback data provider will step in. It is important to confirm with the DIVA Protocol community, under which circumstances users can expect the fallback data provider to step in.
- Defaut: If the fallback data provider also fails to submit a value, the payout will default to
gradient
for the long position and1-gradient
for the short position token, minus applicable fees. Thegradient
is one of the parameters that determines the shape of the payoff profile and is specified at the time of derivative contract creation.
For more information on DIVA's settlement process, please refer to the official DIVA Protocol documentation.
The following overview provides a list of DIVA Protocol functions that are most relevant for data providers:
Name | |
---|---|
Value submission related functions | |
setFinalReferenceValue |
Function to submit the final value of the reference asset. |
challengeFinalReferenceValue |
Function to challenge the final reference value submitted by the data provider. Only relevant when centralized oracles are used. |
Reward related functions | |
transferFeeClaim |
Function to transfer a fee claim to another recipient. |
claimFee |
Function to claim fee. |
Getter functions | |
getPoolParameters |
Function to return the pool parameters for a given pool Id. |
getPoolParametersByAddress |
Function to return the pool parameters for a given position token address. |
getClaim |
Function to get the fee claim for a given recipient denominated in a given collateral token. |
getTip |
Function to return the amout tipped in collateral token for a given pool. |
getFees |
Function to return the fees applicable for a given _indexFees , which is returned as part of getPoolParameters . The settlement fee is the relevant fee for data providers. |
getSettlementPeriods |
Function to return the settlement periods applicable for a given _indexSettlementPeriods , which is returned as part of getPoolParameters . |
Batch functions | |
batchSetFinalReferenceValue |
Batch version of setFinalReferenceValue |
batchChallengeFinalReferenceValue |
Batch version of challengeFinalReferenceValue |
batchClaimFee |
Batch version of claimFee function. |
batchTransferFeeClaim |
Batch version of transferFeeClaim function. |
The creation of a derivative contract, also referred to as a "contingent pool" or simply "pool", constitutes a request to a data provider to supply a data point at a predetermined future time. It is the responsibility of the data provider to set up the necessary listeners and notification services to not miss the reporting window.
For monitoring pools, we recommend using the DIVA subgraph, which captures both data stored within the DIVA smart contract and data emitted as part of events. The DIVA subgraph is available on the following networks:
- Goerli: https://thegraph.com/hosted-service/subgraph/divaprotocol/diva-goerli-new
- Sepolia: n/a
- Polygon: n/a
- Mainnet: n/a
- Arbitrum: n/a
Alternatively, reporters can use DIVA's getPoolParameters
function to access pool information. However, please note that the returned information is limited to the data stored within the DIVA smart contract and does not include event data.
Below provides an example subgraph query including the most relevant pool information for data providers. The full list of available fields can be found in here.
{
pools (first: 1000, where: {
expiryTime_gt: "1667147292",
expiryTime_lte: "1667752092",
statusFinalReferenceValue: "Open",
dataProvider: "0x9f6cd21bf0f18cf7bcd1bd9af75476537d8295fb"}
) {
id
referenceAsset
expiryTime
dataProvider
finalReferenceValue
statusFinalReferenceValue
statusTimestamp
collateralToken {
id
name
symbol
decimals
}
collateralBalanceGross
settlementFee
challenges {
challengedBy
proposedFinalReferenceValue
}
submissionPeriod
challengePeriod
reviewPeriod
createdAt
createdBy
}
}
where:
Parameter | Description |
---|---|
id |
Id of the contingent pool; incrementally increasing integer starting at 1. |
referenceAsset |
The metric or event for which reporting is required (e.g., BTC/USD, ETH/USD, etc). |
expiryTime |
Expiration time of the pool expressed as a unix timestamp in seconds since epoch (UTC). |
dataProvider |
Ethereum account (EOA or smart contract) that was assigned to report the final reference value. |
finalReferenceValue |
Current reference asset value stored in the DIVA smart contract for the corresponding pool, expressed as an integer with 18 decimals. Set to 0 at pool creation. Update when a value is Submitted or Confirmed. Not updated when a submission was challenged. |
statusFinalReferenceValue |
Status of final reference value (0 = Open, 1 = Submitted, 2 = Challenged, 3 = Confirmed). "Open" at pool creation. |
statusTimestamp |
Status timestamp expressed as a unix timestamp in seconds since epoch (UTC). Updated when the statusFinalReferenceValue changes. Equal to time of creation initially. |
collateralToken.id |
Address of the ERC20 token used as collateral in the pool. Payouts are denominated in that asset. |
collateralToken.name |
Name of collateral token. |
collateralToken.symbol |
Symbol of collateral token. |
collateralToken.decimals |
Number of decimals of collateral token. |
collateralBalanceGross |
Total collateral added to the pool during its lifetime. Used as the basis to estimate fee rewards. |
settlementFee |
Fee that goes to the data provider when users remove liquidity / redeem, in % of the collateral amount being removed/redeemed; expressed as an integer with 18 decimals (e.g., 500000000000000 = 0.05%). |
challenges.challengedBy |
Address that submitted a challenge for the submitted value. Only relevant if the possibility to challenge was enabled by the data provider in the first place. |
challenges.proposedFinalReferenceValue |
Final value proposed by challenger; expressed as an integer with 18 decimals. IMPORTANT: Those values DO NOT overwrite finalReferenceValue but are only emitted as part of the event. Only relevant if the possibility to challenge was enabled by the data provider in the first place. |
submissionPeriod |
Submission period in seconds applicable to the corresponding pool. |
challengePeriod |
Challenge period in seconds applicable to the corresponding pool. |
reviewPeriod |
Review period in seconds applicable to the corresponding pool. |
createdAt |
Timestamp of pool creation in seconds since epoch (UTC). |
createdBy |
Address that created the pool. |
If an oracle adapter enables DIVA's challenge functionality, they should monitor all challenges using a separate script with statusFinalReferenceValue: "Challenged"
as the query condition. As challenges may be valid, data providers should handle them manually rather than reporting them automatically on dispute.
Challenges are typically enabled when a centralized party acts as the data provider. Challenges are disabled for decentralized oracles like Tellor that come with their own dispute resolution mechanisms.
By default, the subgraph query returns a maximum of 1000 entries. To ensure that all pools are captured by the listener, it is recommended to implement a loop using id_gt
as is described in the Graph Protocol docs.
The settlement fee and the settlement-related periods (submissionPeriod
, challengePeriod
and reviewPeriod
) are specific to each pool. The fee ranges between 0% and 1.5% and the settlement related periods can be between 3 and 15 days.
Ensure that the timezone of the expiryTime
and your off-chain data source are using the same timezone (UTC).
As the subgraph is an off-chain process that reads and aggregates data emitted on the blockchain, there is a risk that it may go down for various reasons. Reporters are recommended to also implement a fallback option using DIVA's getPoolParameter
function.
The most important thing: Test your oracle adapter extensively before using it in production. The DIVA Protocol team is happy to review your implementation. Please reach out in the oracles channel in their Discord.
To submit data to the DIVA smart contract, the assigned data provider must call the setFinalReferenceValue
function within the submission window.
After the data provider submits a value, the statusFinalReferenceValue
parameter switches from "Open" (0) to either "Submitted" (1) or "Confirmed" (3), depending on whether the optional challenge mechanism was activated or not. If the challenge mechanism is activated and a challenge is initiated, the status changes from "Submitted" to "Challenged" (2), and the data provider has a chance to resubmit a new value within the review window or confirm the previous one by re-submitting the previous value again or not submitting at all.
Once the value reaches "Confirmed" stage, it is considered final and no further submissions can be made. Refer to the official DIVA Protocol documentation for more details.
The setFinalReferenceValue
function can be either called directly or wrapped into another smart contract, as done in the Tellor adapter, for instance.
function setFinalReferenceValue(
uint256 _poolId, // The pool Id for which the final value is being submitted
uint256 _finalReferenceValue, // Proposed final value by the data provider expressed as an integer with 18 decimals (e.g., 18500000000000000000 for 18.5)
bool _allowChallenge // Flag indicating whether the challenge functionality should be enabled (1) or not (0)
)
external;
Important: The submitted value has to be represented as an integer with 18 decimals, e.g.,
18500000000000000000
for18.5
. Further, DIVA Protocol does not accept negative values. If the underlying metric can go negative, it is recommended to apply a shift or normalization to render it positive.
ABI:
{
"inputs": [
{
"internalType": "uint256",
"name": "_poolId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_finalReferenceValue",
"type": "uint256"
},
{
"internalType": "bool",
"name": "_allowChallenge",
"type": "bool"
}
],
"name": "setFinalReferenceValue",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
DIVA Protocol rewards reporters in two ways:
- Settlement fee: DIVA Protocol pays a settlement fee of 0.05% (updateable by DIVA owner) of the gross collateral deposited into the pool over time to the data provider in the pool's collateral token. For example, reporting for a pool that has had USDC 100k in liquidity added over its lifetime would yield a settlement fee of USDC 50.
- Tips: In addition to the settlement fee, users can add a tip using DIVA Protocol's
addTip
function to incentivize reporting. This can be particularly useful when the gross collateral of the pool is relatively small and the settlement fee alone would not justify the gas cost for reporting. Note that in DIVA Protocol, the tip can only be given in the collateral token of the respective pool.
Additional incentives and tipping features can be implemented in the adapter contract. For instance, check out the Tellor adapter that enables users to tip using any ERC20 token.
Claimable rewards are stored inside the FeeRecipient
entity in the DIVA subgraph. Note that settlement fees and tips are only reflected in claimable rewards when a pool moves to "Confirmed" stage. Below is an example subgraph query to retrieve the claimable amount for a given data provider address (id
).
Note: The address in the
where
condition should be in lowercase.
{
feeRecipients(where: {id: "0x9adefeb576dcf52f5220709c1b267d89d5208d78"}) {
id
collateralTokens {
amount
collateralToken {
id
name
symbol
decimals
}
}
}
}
To check the claimable rewards from the DIVA smart contract, reporters can use the getClaim
function. If a pool is in "Confirmed" stage, the returned amount includes both settlement fees and tips.
If a pool has not yet been confirmed, reporters can retrieve the tips using the getTip
function. For confirmed pools, the function will return zero as the tip is already included in the claimable amount.
function getClaim(
address _collateralToken, // Address of the token in which the fee is denominated
address _recipient // Address of the fee claim recipient
)
external
view
returns (uint256);
function getTip(
uint256 _poolId // Id of pool
)
external
view
returns (uint256);
ABI:
{
"inputs": [
{
"internalType": "address",
"name": "_collateralToken",
"type": "address"
},
{ "internalType": "address",
"name": "_recipient",
"type": "address" }
],
"name": "getClaim",
"outputs": [{
"internalType": "uint256",
"name": "",
"type": "uint256"
}],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_poolId",
"type": "uint256"
}
],
"name": "getTip",
"outputs": [{
"internalType": "uint256",
"name": "",
"type": "uint256"
}],
"stateMutability": "view",
"type": "function"
}
By default, the assigned data provider is entitled to claim the reward. If the data provider is a smart contract, it may be desireable to transfer the fee claim to another recipient using the transferFeeClaim
function:
function transferFeeClaim(
address _recipient, // Address of fee claim recipient
address _collateralToken, // Collateral token address
uint256 _amount // Amount (expressed as an integer with collateral token decimals) to transfer to recipient
)
external;
ABI:
{
"inputs": [
{ "internalType": "address",
"name": "_recipient",
"type": "address"
},
{
"internalType": "address",
"name": "_collateralToken",
"type": "address"
},
{ "internalType": "uint256",
"name": "_amount",
"type": "uint256"
}
],
"name": "transferFeeClaim",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}