Skip to content

Latest commit

 

History

History
631 lines (531 loc) · 29.6 KB

README.md

File metadata and controls

631 lines (531 loc) · 29.6 KB

Table of Contents

  1. Intro
  2. Terminology
  3. Settlement process in DIVA Protocol
  4. Relevant functions
  5. Data monitoring
    5.1 DIVA subgraph
    5.2 General guidance for implementing listeners
  6. Data submission
  7. Reporting rewards
    7.1 Query rewards from subgraph
    7.2. Query rewards from contract
    7.3 Transfer reward

Intro

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:

  1. Tellor adapter

Other adapters currently in development:

  1. Shamba adapter (⚠️ centralized setup)
  2. 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.

Terminology

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

Settlement process in DIVA Protocol

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:

  1. 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.
  2. Defaut: If the fallback data provider also fails to submit a value, the payout will default to gradient for the long position and 1-gradient for the short position token, minus applicable fees. The gradient 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.

Relevant functions

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.

Data monitoring

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:

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.

DIVA subgraph

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.

General guidance for implementing listeners

Handling challenges

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.

Capturing all pools

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.

Fees and settlement periods

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.

Timezones

Ensure that the timezone of the expiryTime and your off-chain data source are using the same timezone (UTC).

Fallback data source

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.

Testing

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.

Data submission

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 for 18.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"
}

Reporting rewards

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.

Query rewards from subgraph

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
      }
    }
  }
}

Query rewards from contract

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"
}

Transfer reward

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"
  }