Skip to content

Commit

Permalink
Add get_oracle_amount_by_currency_and_amount_in (#1429)
Browse files Browse the repository at this point in the history
* Add get_oracle_amount_by_currency_and_amount_in

* Fix ci

* Optimize get_oracle_amount_by_currency_and_amount_in
  • Loading branch information
hqwangningbo authored Sep 15, 2024
1 parent 40f5c64 commit c901e38
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 3 deletions.
8 changes: 8 additions & 0 deletions pallets/fee-share/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,14 @@ impl PriceFeeder for MockPriceFeeder {
fn get_normal_price(_asset_id: &CurrencyId) -> Option<u128> {
todo!()
}

fn get_oracle_amount_by_currency_and_amount_in(
_currency_in: &CurrencyId,
_amount_in: bifrost_primitives::Balance,
_currency_out: &CurrencyId,
) -> Option<bifrost_primitives::Balance> {
todo!()
}
}

pub struct ParaInfo;
Expand Down
8 changes: 8 additions & 0 deletions pallets/lend-market/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,14 @@ impl PriceFeeder for MockPriceFeeder {
fn get_normal_price(_asset_id: &CurrencyId) -> Option<u128> {
todo!()
}

fn get_oracle_amount_by_currency_and_amount_in(
_currency_in: &CurrencyId,
_amount_in: Balance,
_currency_out: &CurrencyId,
) -> Option<Balance> {
todo!()
}
}

parameter_types! {
Expand Down
8 changes: 8 additions & 0 deletions pallets/leverage-staking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,14 @@ impl PriceFeeder for MockPriceFeeder {
fn get_normal_price(_asset_id: &CurrencyId) -> Option<u128> {
todo!()
}

fn get_oracle_amount_by_currency_and_amount_in(
_currency_in: &CurrencyId,
_amount_in: Balance,
_currency_out: &CurrencyId,
) -> Option<Balance> {
todo!()
}
}

parameter_types! {
Expand Down
24 changes: 24 additions & 0 deletions pallets/prices/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,11 @@ impl<T: Config> Pallet<T> {
})
}

fn get_storage_price(asset_id: &CurrencyId) -> Option<Price> {
EmergencyPrice::<T>::get(asset_id)
.or_else(|| T::Source::get(asset_id).and_then(|price| Some(price.value)))
}

fn get_asset_mantissa(asset_id: &CurrencyId) -> Option<u128> {
10u128.checked_pow(
asset_id
Expand Down Expand Up @@ -248,6 +253,25 @@ impl<T: Config> PriceFeeder for Pallet<T> {
.and_then(|price| Some(price.value.into_inner().saturating_div(decimals)))
})
}

/// Get the amount of currencies according to the oracle price data.
fn get_oracle_amount_by_currency_and_amount_in(
currency_in: &CurrencyId,
amount_in: Balance,
currency_out: &CurrencyId,
) -> Option<Balance> {
let currency_in_mantissa = Self::get_asset_mantissa(currency_in)?;
let currency_out_mantissa = Self::get_asset_mantissa(currency_out)?;
let currency_in_price = Self::get_storage_price(currency_in)?;
let currency_out_price = Self::get_storage_price(currency_out)?;
let total_value = currency_in_price
.mul(FixedU128::from_inner(amount_in))
.div(FixedU128::from_inner(currency_in_mantissa));
let amount_out = total_value
.mul(FixedU128::from_inner(currency_out_mantissa))
.div(currency_out_price);
Some(amount_out.into_inner())
}
}

impl<T: Config> EmergencyPriceFeeder<CurrencyId, Price> for Pallet<T> {
Expand Down
10 changes: 9 additions & 1 deletion pallets/prices/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use sp_runtime::{traits::IdentityLookup, FixedPointNumber};
use bifrost_asset_registry::AssetIdMaps;
pub use bifrost_primitives::{
currency::{FIL, VFIL},
DOT, KSM, VDOT,
DOT, KSM, MANTA, VDOT,
};
use bifrost_primitives::{Moment, ASTR, BNC, DOT_U, GLMR};
use sp_runtime::BuildStorage;
Expand Down Expand Up @@ -54,10 +54,18 @@ pub struct MockDataProvider;
impl DataProvider<CurrencyId, TimeStampedPrice> for MockDataProvider {
fn get(asset_id: &CurrencyId) -> Option<TimeStampedPrice> {
match *asset_id {
BNC => Some(TimeStampedPrice {
value: Price::from_inner(200_000_000_000_000_000),
timestamp: 0,
}),
DOT =>
Some(TimeStampedPrice { value: Price::saturating_from_integer(100), timestamp: 0 }),
KSM =>
Some(TimeStampedPrice { value: Price::saturating_from_integer(500), timestamp: 0 }),
MANTA => Some(TimeStampedPrice {
value: Price::from_inner(600_000_000_000_000_000),
timestamp: 0,
}),
VDOT => Some(TimeStampedPrice {
value: Price::from_inner(15000000000_0000000000),
timestamp: 0,
Expand Down
77 changes: 76 additions & 1 deletion pallets/prices/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
//! Unit tests for the prices pallet.
use super::*;
use bifrost_primitives::VKSM;
use bifrost_asset_registry::AssetMetadata;
use bifrost_primitives::{BNC, MANTA, VKSM};
use frame_support::{assert_noop, assert_ok};
use mock::{RuntimeEvent, *};
use sp_runtime::{traits::BadOrigin, FixedPointNumber};
Expand Down Expand Up @@ -194,3 +195,77 @@ fn get_foreign_token_price_work() {
assert_eq!(Prices::get_price(&FIL), Prices::get_price(&VFIL));
});
}

#[test]
fn fixed_u128() {
new_test_ext().execute_with(|| {
let bnc_decimal = 10u128.pow(12);
let bnc_amount = 100 * 10u128.pow(12);
let bnc_price = FixedU128::from_inner(200_000_000_000_000_000);
// 100 * 0.2 = 20 U
let dot_decimal = 10u128.pow(10);
let dot_amount = 5 * 10u128.pow(10);
let dot_price = FixedU128::from(4);

let bnc_total_value =
bnc_price / FixedU128::from_inner(bnc_decimal) * FixedU128::from_inner(bnc_amount);
let dot_total_value =
dot_price / FixedU128::from_inner(dot_decimal) * FixedU128::from_inner(dot_amount);
let dot_amount_fixed_u128 =
dot_total_value * FixedU128::from_inner(dot_decimal) / dot_price;
assert_eq!(bnc_total_value, dot_total_value);
println!("{:?}", bnc_total_value);
println!("{:?}", dot_amount_fixed_u128);
assert_eq!(dot_amount, dot_amount_fixed_u128.into_inner());
})
}

#[test]
fn get_oracle_amount_by_currency_and_amount_in() {
new_test_ext().execute_with(|| {
assert_ok!(AssetRegistry::do_register_metadata(
MANTA,
&AssetMetadata {
name: b"Manta".to_vec(),
symbol: b"Manta".to_vec(),
decimals: 18,
minimal_balance: 1_000_000_000_000_000u128,
}
));
// 100 * 0.2 = 20u
let bnc_amount = 100 * 10u128.pow(12);
// 0.2 DOT
assert_eq!(
Some(2_000_000_000),
Prices::get_oracle_amount_by_currency_and_amount_in(&BNC, bnc_amount, &DOT)
);
// 0.04 KSM
assert_eq!(
Some(40_000_000_000),
Prices::get_oracle_amount_by_currency_and_amount_in(&BNC, bnc_amount, &KSM)
);
// 33.33333333333333333333
assert_eq!(
Some(33_333_333_333_333_333_333),
Prices::get_oracle_amount_by_currency_and_amount_in(&BNC, bnc_amount, &MANTA)
);

// 0.01 * 0.2 = 0.002 U
let bnc_amount = 10u128.pow(10);
// 0.00002 DOT * 100 = 0.002 U
assert_eq!(
Some(200_000),
Prices::get_oracle_amount_by_currency_and_amount_in(&BNC, bnc_amount, &DOT)
);
// 0.000004 KSM * 500 = 0.002 U
assert_eq!(
Some(4_000_000),
Prices::get_oracle_amount_by_currency_and_amount_in(&BNC, bnc_amount, &KSM)
);
// 0.003333333333333333333333 MANTA
assert_eq!(
Some(3_333_333_333_333_333),
Prices::get_oracle_amount_by_currency_and_amount_in(&BNC, bnc_amount, &MANTA)
);
});
}
7 changes: 6 additions & 1 deletion pallets/traits/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![cfg_attr(not(feature = "std"), no_std)]

use bifrost_primitives::{CurrencyId, PriceDetail};
use bifrost_primitives::{Balance, CurrencyId, PriceDetail};
use num_bigint::{BigUint, ToBigUint};

pub mod evm;
Expand All @@ -15,6 +15,11 @@ pub trait EmergencyCallFilter<Call> {
pub trait PriceFeeder {
fn get_price(asset_id: &CurrencyId) -> Option<PriceDetail>;
fn get_normal_price(asset_id: &CurrencyId) -> Option<u128>;
fn get_oracle_amount_by_currency_and_amount_in(
currency_in: &CurrencyId,
amount_in: Balance,
currency_out: &CurrencyId,
) -> Option<Balance>;
}

pub trait EmergencyPriceFeeder<CurrencyId, Price> {
Expand Down

0 comments on commit c901e38

Please sign in to comment.