axelar-cgp-sui

Module 0x0::deep_price

DEEP price module. This module maintains the conversion rate between DEEP and the base and quote assets.

use 0x0::math;
use 0x1::vector;
use 0x2::event;
use 0x2::object;

Struct Price

DEEP price point.

struct Price has drop, store
Fields
conversion_rate: u64
timestamp: u64

Struct PriceAdded

DEEP price point added event.

struct PriceAdded has copy, drop
Fields
conversion_rate: u64
timestamp: u64
is_base_conversion: bool
reference_pool: object::ID
target_pool: object::ID

Struct DeepPrice

DEEP price points used for trading fee calculations.

struct DeepPrice has drop, store
Fields
base_prices: vector<deep_price::Price>
cumulative_base: u64
quote_prices: vector<deep_price::Price>
cumulative_quote: u64

Struct OrderDeepPrice

struct OrderDeepPrice has copy, drop, store
Fields
asset_is_base: bool
deep_per_asset: u64

Constants

const EDataPointRecentlyAdded: u64 = 1;

const ENoDataPoints: u64 = 2;

const MAX_DATA_POINTS: u64 = 100;

const MAX_DATA_POINT_AGE_MS: u64 = 86400000;

const MIN_DURATION_BETWEEN_DATA_POINTS_MS: u64 = 60000;

Function asset_is_base

public fun asset_is_base(self: &deep_price::OrderDeepPrice): bool
Implementation
public fun asset_is_base(self: &OrderDeepPrice): bool {
    self.asset_is_base
}

Function deep_per_asset

public fun deep_per_asset(self: &deep_price::OrderDeepPrice): u64
Implementation
public fun deep_per_asset(self: &OrderDeepPrice): u64 {
    self.deep_per_asset
}

Function empty

public(friend) fun empty(): deep_price::DeepPrice
Implementation
public(package) fun empty(): DeepPrice {
    DeepPrice {
        base_prices: vector[],
        cumulative_base: 0,
        quote_prices: vector[],
        cumulative_quote: 0,
    }
}

Function new_order_deep_price

public(friend) fun new_order_deep_price(asset_is_base: bool, deep_per_asset: u64): deep_price::OrderDeepPrice
Implementation
public(package) fun new_order_deep_price(
    asset_is_base: bool,
    deep_per_asset: u64,
): OrderDeepPrice {
    OrderDeepPrice {
        asset_is_base: asset_is_base,
        deep_per_asset: deep_per_asset,
    }
}

Function get_order_deep_price

public(friend) fun get_order_deep_price(self: &deep_price::DeepPrice, whitelisted: bool): deep_price::OrderDeepPrice
Implementation
public(package) fun get_order_deep_price(
    self: &DeepPrice,
    whitelisted: bool,
): OrderDeepPrice {
    let (asset_is_base, deep_per_asset) = self.calculate_order_deep_price(
        whitelisted,
    );

    new_order_deep_price(asset_is_base, deep_per_asset)
}

Function deep_quantity

public(friend) fun deep_quantity(self: &deep_price::OrderDeepPrice, base_quantity: u64, quote_quantity: u64): u64
Implementation
public(package) fun deep_quantity(
    self: &OrderDeepPrice,
    base_quantity: u64,
    quote_quantity: u64,
): u64 {
    if (self.asset_is_base) {
        math::mul(base_quantity, self.deep_per_asset)
    } else {
        math::mul(quote_quantity, self.deep_per_asset)
    }
}

Function deep_quantity_u128

public(friend) fun deep_quantity_u128(self: &deep_price::OrderDeepPrice, base_quantity: u128, quote_quantity: u128): u128
Implementation
public(package) fun deep_quantity_u128(
    self: &OrderDeepPrice,
    base_quantity: u128,
    quote_quantity: u128,
): u128 {
    if (self.asset_is_base) {
        math::mul_u128(base_quantity, self.deep_per_asset as u128)
    } else {
        math::mul_u128(quote_quantity, self.deep_per_asset as u128)
    }
}

Function add_price_point

Add a price point. If max data points are reached, the oldest data point is removed. Remove all data points older than MAX_DATA_POINT_AGE_MS.

public(friend) fun add_price_point(self: &mut deep_price::DeepPrice, conversion_rate: u64, timestamp: u64, is_base_conversion: bool)
Implementation
public(package) fun add_price_point(
    self: &mut DeepPrice,
    conversion_rate: u64,
    timestamp: u64,
    is_base_conversion: bool,
) {
    assert!(
        self.last_insert_timestamp(is_base_conversion) +
        MIN_DURATION_BETWEEN_DATA_POINTS_MS <
        timestamp,
        EDataPointRecentlyAdded,
    );
    let asset_prices = if (is_base_conversion) {
        &mut self.base_prices
    } else {
        &mut self.quote_prices
    };

    asset_prices.push_back(Price {
        timestamp: timestamp,
        conversion_rate: conversion_rate,
    });
    if (is_base_conversion) {
        self.cumulative_base = self.cumulative_base + conversion_rate;
        while (
            asset_prices.length() == MAX_DATA_POINTS + 1 ||
            asset_prices[0].timestamp + MAX_DATA_POINT_AGE_MS < timestamp
        ) {
            self.cumulative_base =
                self.cumulative_base - asset_prices[0].conversion_rate;
            asset_prices.remove(0);
        }
    } else {
        self.cumulative_quote = self.cumulative_quote + conversion_rate;
        while (
            asset_prices.length() == MAX_DATA_POINTS + 1 ||
            asset_prices[0].timestamp + MAX_DATA_POINT_AGE_MS < timestamp
        ) {
            self.cumulative_quote =
                self.cumulative_quote - asset_prices[0].conversion_rate;
            asset_prices.remove(0);
        }
    };
}

Function emit_deep_price_added

public(friend) fun emit_deep_price_added(conversion_rate: u64, timestamp: u64, is_base_conversion: bool, reference_pool: object::ID, target_pool: object::ID)
Implementation
public(package) fun emit_deep_price_added(
    conversion_rate: u64,
    timestamp: u64,
    is_base_conversion: bool,
    reference_pool: ID,
    target_pool: ID,
) {
    event::emit(PriceAdded {
        conversion_rate,
        timestamp,
        is_base_conversion,
        reference_pool,
        target_pool,
    });
}

Function calculate_order_deep_price

Returns the conversion rate of DEEP per asset token. Base will be used by default, if there are no base data then quote will be used

fun calculate_order_deep_price(self: &deep_price::DeepPrice, whitelisted: bool): (bool, u64)
Implementation
fun calculate_order_deep_price(
    self: &DeepPrice,
    whitelisted: bool,
): (bool, u64) {
    if (whitelisted) {
        return (false, 0) // no fees for whitelist
    };
    assert!(
        self.last_insert_timestamp(true) > 0 ||
        self.last_insert_timestamp(false) > 0,
        ENoDataPoints,
    );

    let is_base_conversion = self.last_insert_timestamp(false) == 0;

    let cumulative_asset = if (is_base_conversion) {
        self.cumulative_base
    } else {
        self.cumulative_quote
    };
    let asset_length = if (is_base_conversion) {
        self.base_prices.length()
    } else {
        self.quote_prices.length()
    };
    let deep_per_asset = cumulative_asset / asset_length;

    (is_base_conversion, deep_per_asset)
}

Function last_insert_timestamp

fun last_insert_timestamp(self: &deep_price::DeepPrice, is_base_conversion: bool): u64
Implementation
fun last_insert_timestamp(self: &DeepPrice, is_base_conversion: bool): u64 {
    let prices = if (is_base_conversion) {
        &self.base_prices
    } else {
        &self.quote_prices
    };
    if (prices.length() > 0) {
        prices[prices.length() - 1].timestamp
    } else {
        0
    }
}