Interest Protocol
  • 👋Welcome to Interest Protocol
  • Overview
    • Sui💧
      • Contracts
        • Memez
        • Libs 📚
      • Suicoins
        • Swap
        • Dollar-Cost Averaging (DCA)
        • Airdrop
          • Suiplay Airdrop
        • Incinerator
        • Send
        • Merger
        • Suicoins Terminal
      • Memez.gg
        • Coins on Memez.GG
        • Memez.Fun
          • SDK
            • Pump API
            • Interfaces
          • Configuration
          • Migrators
          • Bonding Curve
          • Fees
      • IPX Coin Standard
    • Movement
      • Interest Protocol Decentralized Exchange (DEX)
        • Key Features
        • Core Innovations
      • sr-AMM
      • Token
        • Tokenomics
        • Utility
      • GTM
    • Audits
    • Security
    • Deprecated
      • Coin X Oracle 🔮
        • Pyth Network
        • Switchboard
      • Sui Tears 💧
        • Airdrop
          • Airdrop
          • Airdrop Utils
          • Linear Vesting Airdrop
        • Capabilities
          • Access Control
          • Owner
          • Quest
          • Timelock
        • Collections
          • Bitmap
          • Coin Decimals
        • DeFi
          • Oracle
          • Farm
          • Fund
          • Linear Vesting Wallet
          • Linear Clawback Vesting Wallet
          • Vesting
        • Governance
          • DAO
          • DAO Admin
          • DAO Treasury
        • Utils
          • ASCII
          • Comparator
          • Merkle Proof
          • Vectors
        • Math
          • Fixed Point 64
          • Fixed Point Roll
          • Fixed Point Wad
          • Int
          • Math64
          • Math128
          • Math256
      • CLAMM🐚
        • Hooks
      • Whitepapers
  • Glossary
Powered by GitBook
On this page
  • Why Pyth?
  • Interface
  • Structs
  • Functions

Was this helpful?

Export as PDF
  1. Overview
  2. Deprecated
  3. Coin X Oracle 🔮

Pyth Network

Reliable, low-latency market data from institutional sources.

PreviousCoin X Oracle 🔮NextSwitchboard

Last updated 1 year ago

Was this helpful?

The first price provider supported by Coin X Oracle is Pyth Network. It is the leading Oracle provider on Sui Network and the largest first-party Oracle Network in the world. It supports of over 50 chains and offers 450 price feeds.

First Party Institutional Providers

Pyth network data sources do not rely on intermediaries to ensure reliability and liveness of the data.

Price Confidence

Pyth Network is the only provider that offers a price confidence metric in all price feeds. Assets do not have a single price in a market at any given point in time. By providing a confidence range, DeFi dApps can design their invariant to take into account price variance.

Structs

struct PriceInfoObjectKey has copy, drop, store {}

A dynamic field key to store the sui::object::ID of the pyth::price_info::PriceInfoObject that can that provide data to the oracle.

struct ConfidenceKey has copy, drop, store {}

A dynamic field key to save the minimum required price confidence. It is a percentage, where 100% is represented by 1e18.

struct PythFeed has drop {}

A witness that is added to the suitears::oracle::Request to prove that it collected data from Coin X Oracle's Pyth Network module.

Functions

report

It requests a price from Pyth Network and submits the information to a Coin X oracle request.

public fun report<Witness: drop>(
    oracle: &Oracle<Witness>, 
    request: &mut Request, 
    wormhole_state: &WormholeState,
    pyth_state: &PythState,
    buf: vector<u8>,
    price_info_object: &mut PriceInfoObject,
    pyth_fee: Coin<SUI>,
    clock_object: &Clock
 )
  • @param self. A suiterars::oracle::Oracle with this module's witness.

  • @param request. A hot potato issued from the self to create a suiterars::oracle::Price.

  • @param wormhole_state. The state of the Wormhole module on Sui.

  • @param pyth_state. The state of the Pyth module on Sui.

  • @param buf. Price attestations in bytes.

  • @param price_info_object. An object that contains price information. One per asset.

  • @param pyth_fee. There is a cost to request a price update from Pyth.

  • @param clock_object. The shared Clock object from Sui

Aborts

  • the price_info_object is not whitelisted.

  • the price confidence is out of range.

  • the price is negative or zero.

Why Pyth?
Interface
https://github.com/interest-protocol/coin-x-oracle/blob/main/contracts/sources/pyth.move
module coin_x_oracle::pyth_oracle {
  // === Imports ===
  use std::type_name;
  
  use sui::object;
  use sui::math::pow;
  use sui::object::ID;
  use sui::clock::Clock;
  use sui::dynamic_field as df;

  use suitears::fixed_point_wad;
  use suitears::math256::mul_div_down;
  use suitears::owner::{Self, OwnerCap};
  use suitears::oracle::{Self, Oracle, Request};  

  use pyth::i64;
  use pyth::state::State as PythState;
  use pyth::price::Self as pyth_price;
  use pyth::pyth::get_price as pyth_get_price;
  use pyth::price_info::{Self, PriceInfoObject};

  // === Errors ===

  const EInvalidPriceObjectInfo: u64 = 0;
  const EZeroPrice: u64 = 1;
  const EPriceConfidenceOutOfRange: u64 = 2;

  // === Constants ===

  const POW_10_18: u256 = 1000000000000000000; // 1e18
  const TWO_PERCENT: u256 = 20000000000000000; // 0.02e18
  const HUNDRED_PERCENT: u256 = 1000000000000000000; // 1e18
  const TIME_SCALAR: u64 = 1000;

  // === Structs ===

  struct PriceInfoObjectKey has copy, drop, store {}

  struct ConfidenceKey has copy, drop, store {}

  struct PythFeed has drop {}

  // === Public-Mutative Functions ===

  /*
  * @notice Adds a `PythFeed` report to a `suitears::oracle::Request`.  
  *
  * @param self A `suiterars::oracle::Oracle` with this module's witness.    
  * @param request A hot potato issued from the `self` to create a `suiterars::oracle::Price`.  
  * @param wormhole_state The state of the Wormhole module on Sui.
  * @param pyth_state The state of the Pyth module on Sui.
  * @param price_info_object An object that contains price information. One per asset.
  * @param clock_object The shared Clock object from Sui.
  *
  * aborts-if:    
  * - The `price_info_object` is not whitelisted.   
  * - The price confidence is out of range.  
  * - The price is negative or zero.   
  */
  public fun report<Witness: drop>(
    oracle: &Oracle<Witness>, 
    request: &mut Request, 
    pyth_state: &PythState,
    price_info_object: &mut PriceInfoObject,
    clock_object: &Clock
  ) {
    let whitelisted_id = *df::borrow<PriceInfoObjectKey, ID>(oracle::uid(oracle), PriceInfoObjectKey {});

    assert!(whitelisted_id == price_info::uid_to_inner(price_info_object), EInvalidPriceObjectInfo);

    // Get the price raw value, exponent and timestamp
    let pyth_price = pyth_get_price(pyth_state, price_info_object, clock_object);
    let pyth_price_value = pyth_price::get_price(&pyth_price);
    let pyth_price_expo = pyth_price::get_expo(&pyth_price);
    let latest_timestamp = pyth_price::get_timestamp(&pyth_price);
    let price_conf = pyth_price::get_conf(&pyth_price);

    let pyth_price_u64 = i64::get_magnitude_if_positive(&pyth_price_value);

    assert_price_conf(oracle, pyth_price_u64, price_conf);

    assert!(pyth_price_u64 != 0, EZeroPrice);

    let is_exponent_negative = i64::get_is_negative(&pyth_price_expo);
    
    let pyth_exp_u64 = if (is_exponent_negative) 
      i64::get_magnitude_if_negative(&pyth_price_expo) 
    else 
      i64::get_magnitude_if_positive(&pyth_price_expo);

    let value = if (is_exponent_negative) 
      mul_div_down((pyth_price_u64 as u256), POW_10_18, (pow(10, (pyth_exp_u64 as u8)) as u256))
    else 
      (pyth_price_u64 as u256)  * (pow(10, 18 - (pyth_exp_u64 as u8)) as u256);

    oracle::report(request, PythFeed {}, latest_timestamp * TIME_SCALAR, (value as u128), 18);
  }  

  // === Admin Functions ===  

  /*
  * @notice Adds the `PythFeed` feed to the `oracle`.  
  *
  * @dev By default, this oracle will require prices to have a confidence level of 98% or higher.
  * 
  * @param self The `suiterars::oracle::Oracle` that will require a Pyth report.     
  * @param cap The `suitears::owner::OwnerCap` of `self`.   
  * @param price_info_object This Pyth Network Price Info Object will be whitelisted.
  */
  public fun add<Witness: drop>(oracle: &mut Oracle<Witness>, cap: &OwnerCap<Witness>, price_info_object: &PriceInfoObject) {
    oracle::add(oracle, cap, type_name::get<PythFeed>());
    let uid = oracle::uid_mut(oracle, cap);
    df::add(uid, PriceInfoObjectKey {}, price_info::uid_to_inner(price_info_object));
    df::add(uid, ConfidenceKey {}, TWO_PERCENT);
  }  

  /*
  * @notice Updates the required confidence interval percentage for the `self`.  
  * 
  * @dev Note that you can add a confidence interval percentage of 0%. We recommend a value higher than 95%.
  *
  * @param self The `suiterars::oracle::Oracle` that will require a Pyth report.     
  * @param cap The `suitears::owner::OwnerCap` of `self`.   
  * @param conf The new confidence.
  *
  * aborts-if 
  * - The `cap` does not own the `self`.
  * - The `conf` is higher than 100%.
  */
  public fun update_confidence<Witness: drop>(oracle: &mut Oracle<Witness>, cap: &OwnerCap<Witness>, conf: u256) {
    owner::assert_ownership(cap, object::id(oracle));
    let saved_conf = df::borrow_mut<ConfidenceKey, u256>(oracle::uid_mut(oracle, cap), ConfidenceKey {});
    *saved_conf = HUNDRED_PERCENT - conf;
  }

  // === Private Functions ===
  
  /*
  * @notice Ensures that we are reporting a price within the required confidence interval. 
  *
  * @dev Read about price confidence intervals here: https://docs.pyth.network/price-feeds/pythnet-price-feeds/best-practices
  *
  * @param self The `suiterars::oracle::Oracle` that contains the required confidence percentage.   
  * @param price_value The price
  * @param price_conf The confidence interval for the `price_value`
  *
  * aborts-if:  
  * - The `price_value`'s confidence interval is lower than the `oracle` allows. 
  */
  fun assert_price_conf<Witness: drop>(oracle: &Oracle<Witness>, price_value: u64, price_conf: u64) {
    let price_conf_percentage = fixed_point_wad::div_up((price_conf as u256), (price_value as u256));
    let required_conf = *df::borrow<ConfidenceKey, u256>(oracle::uid(oracle), ConfidenceKey {});
    assert!(required_conf >= price_conf_percentage, EPriceConfidenceOutOfRange);
  }  
}