From dd18411260ebbae354af88e6095ce71322903c7e Mon Sep 17 00:00:00 2001 From: hqwangningbo <2536935847@qq.com> Date: Fri, 20 Sep 2024 19:53:25 +0800 Subject: [PATCH 1/2] Optimised calculation of evm fee --- pallets/fee-share/src/lib.rs | 8 +- pallets/fee-share/src/mock.rs | 12 +- .../src/impls/on_charge_transaction.rs | 6 +- pallets/flexible-fee/src/lib.rs | 8 +- pallets/flexible-fee/src/mock.rs | 4 +- pallets/flexible-fee/src/mock_price.rs | 48 +++--- pallets/lend-market/src/lib.rs | 6 +- pallets/lend-market/src/mock.rs | 12 +- pallets/lend-market/src/tests.rs | 10 +- .../lend-market/src/tests/interest_rate.rs | 2 +- .../lend-market/src/tests/liquidate_borrow.rs | 19 ++- pallets/leverage-staking/src/mock.rs | 14 +- pallets/prices/src/lib.rs | 36 ++-- pallets/traits/src/lib.rs | 2 +- primitives/src/price.rs | 3 +- runtime/bifrost-kusama/src/lib.rs | 6 +- runtime/bifrost-polkadot/src/evm/evm_fee.rs | 129 ++++++--------- runtime/bifrost-polkadot/src/evm/mod.rs | 23 +-- runtime/bifrost-polkadot/src/evm/runner.rs | 60 ++++++- runtime/bifrost-polkadot/src/lib.rs | 6 +- runtime/common/src/lib.rs | 4 - runtime/common/src/price.rs | 116 ------------- runtime/common/src/ratio.rs | 154 ------------------ 23 files changed, 215 insertions(+), 473 deletions(-) delete mode 100644 runtime/common/src/price.rs delete mode 100644 runtime/common/src/ratio.rs diff --git a/pallets/fee-share/src/lib.rs b/pallets/fee-share/src/lib.rs index df6049865..cc1b45fd1 100644 --- a/pallets/fee-share/src/lib.rs +++ b/pallets/fee-share/src/lib.rs @@ -30,7 +30,7 @@ mod benchmarking; pub mod weights; -use bifrost_primitives::{CurrencyId, DistributionId, Price, PriceFeeder}; +use bifrost_primitives::{CurrencyId, DistributionId, OraclePriceProvider, Price}; use frame_support::{ pallet_prelude::*, sp_runtime::{ @@ -102,7 +102,7 @@ pub mod pallet { type FeeSharePalletId: Get; /// The oracle price feeder - type PriceFeeder: PriceFeeder; + type OraclePriceProvider: OraclePriceProvider; } #[pallet::event] @@ -492,8 +492,8 @@ pub mod pallet { } pub fn get_price(currency_id: CurrencyIdOf) -> Result { - let (price, _) = - T::PriceFeeder::get_price(¤cy_id).ok_or(Error::::PriceOracleNotReady)?; + let (price, _) = T::OraclePriceProvider::get_price(¤cy_id) + .ok_or(Error::::PriceOracleNotReady)?; log::trace!( target: "fee-share::get_price", "price: {:?}", price.into_inner() ); diff --git a/pallets/fee-share/src/mock.rs b/pallets/fee-share/src/mock.rs index 3e7060766..16945802b 100644 --- a/pallets/fee-share/src/mock.rs +++ b/pallets/fee-share/src/mock.rs @@ -182,7 +182,7 @@ impl bifrost_fee_share::Config for Runtime { type ControlOrigin = EnsureSignedBy; type WeightInfo = (); type FeeSharePalletId = FeeSharePalletId; - type PriceFeeder = MockPriceFeeder; + type OraclePriceProvider = MockOraclePriceProvider; } impl pallet_prices::Config for Runtime { @@ -224,7 +224,7 @@ impl DataFeeder for MockDataProvider { Ok(()) } } -pub struct MockPriceFeeder; +pub struct MockOraclePriceProvider; #[derive(Encode, Decode, Clone, Copy, RuntimeDebug)] pub struct CurrencyIdWrap(CurrencyId); @@ -242,7 +242,7 @@ impl PartialEq for CurrencyIdWrap { impl Eq for CurrencyIdWrap {} -impl MockPriceFeeder { +impl MockOraclePriceProvider { thread_local! { pub static PRICES: RefCell>> = { RefCell::new( @@ -269,15 +269,11 @@ impl MockPriceFeeder { } } -impl PriceFeeder for MockPriceFeeder { +impl OraclePriceProvider for MockOraclePriceProvider { fn get_price(asset_id: &CurrencyId) -> Option { Self::PRICES.with(|prices| *prices.borrow().get(&CurrencyIdWrap(*asset_id)).unwrap()) } - fn get_normal_price(_asset_id: &CurrencyId) -> Option { - todo!() - } - fn get_amount_by_prices( _currency_in: &CurrencyId, _amount_in: bifrost_primitives::Balance, diff --git a/pallets/flexible-fee/src/impls/on_charge_transaction.rs b/pallets/flexible-fee/src/impls/on_charge_transaction.rs index 0f217eed5..336605884 100644 --- a/pallets/flexible-fee/src/impls/on_charge_transaction.rs +++ b/pallets/flexible-fee/src/impls/on_charge_transaction.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use crate::{Config, ExtraFeeByCall, Pallet}; -use bifrost_primitives::{Balance, CurrencyId, Price, PriceFeeder, BNC}; +use bifrost_primitives::{Balance, CurrencyId, OraclePriceProvider, Price, BNC}; use orml_traits::MultiCurrency; use pallet_transaction_payment::OnChargeTransaction; use parity_scale_codec::Encode; @@ -124,7 +124,7 @@ where ), PaymentInfo::NonNative(paid_fee, fee_currency, bnc_price, fee_currency_price) => { // calculate corrected_fee in the non-native currency - let converted_corrected_fee = T::PriceFeeder::get_amount_by_prices( + let converted_corrected_fee = T::OraclePriceProvider::get_amount_by_prices( &BNC, corrected_fee, bnc_price, @@ -133,7 +133,7 @@ where ) .ok_or(TransactionValidityError::Invalid(InvalidTransaction::Payment))?; let refund = paid_fee.saturating_sub(converted_corrected_fee); - let converted_tip = T::PriceFeeder::get_amount_by_prices( + let converted_tip = T::OraclePriceProvider::get_amount_by_prices( &BNC, tip, bnc_price, diff --git a/pallets/flexible-fee/src/lib.rs b/pallets/flexible-fee/src/lib.rs index f0e76dec7..889b9f494 100644 --- a/pallets/flexible-fee/src/lib.rs +++ b/pallets/flexible-fee/src/lib.rs @@ -22,7 +22,7 @@ pub use crate::pallet::*; use bifrost_primitives::{ currency::{VGLMR, VMANTA, WETH}, traits::XcmDestWeightAndFeeHandler, - Balance, BalanceCmp, CurrencyId, DerivativeIndex, Price, PriceFeeder, TryConvertFrom, + Balance, BalanceCmp, CurrencyId, DerivativeIndex, OraclePriceProvider, Price, TryConvertFrom, XcmOperationType, BNC, DOT, GLMR, MANTA, VBNC, VDOT, }; use bifrost_xcm_interface::{polkadot::RelaychainCall, traits::parachains, PolkadotXcmCall}; @@ -74,7 +74,7 @@ pub enum TargetChain { #[frame_support::pallet] pub mod pallet { use super::*; - use bifrost_primitives::{Balance, PriceFeeder}; + use bifrost_primitives::{Balance, OraclePriceProvider}; use frame_support::traits::fungibles::Inspect; #[pallet::config] @@ -91,7 +91,7 @@ pub mod pallet { /// Zenlink interface type DexOperator: ExportZenlink; /// The oracle price feeder - type PriceFeeder: PriceFeeder; + type OraclePriceProvider: OraclePriceProvider; /// The only origin that can set universal fee currency order list type ControlOrigin: EnsureOrigin; /// Get the weight and fee for executing Xcm. @@ -389,7 +389,7 @@ impl Pallet { } } else { let (fee_amount, price_in, price_out) = - T::PriceFeeder::get_oracle_amount_by_currency_and_amount_in( + T::OraclePriceProvider::get_oracle_amount_by_currency_and_amount_in( &BNC, fee_amount, ¤cy_id, diff --git a/pallets/flexible-fee/src/mock.rs b/pallets/flexible-fee/src/mock.rs index 3dea71af4..d8ef4559d 100644 --- a/pallets/flexible-fee/src/mock.rs +++ b/pallets/flexible-fee/src/mock.rs @@ -19,7 +19,7 @@ #![cfg(test)] use super::*; -use crate::{self as flexible_fee, mock_price::MockPriceFeeder}; +use crate::{self as flexible_fee, mock_price::MockOraclePriceProvider}; use bifrost_currencies::BasicCurrencyAdapter; use bifrost_primitives::{Balance, CurrencyId, TokenSymbol}; use cumulus_primitives_core::ParaId as Pid; @@ -167,7 +167,7 @@ impl crate::Config for Test { type RelaychainCurrencyId = RelayCurrencyId; type XcmRouter = (); type PalletId = FlexibleFeePalletId; - type PriceFeeder = MockPriceFeeder; + type OraclePriceProvider = MockOraclePriceProvider; } pub struct XcmDestWeightAndFee; diff --git a/pallets/flexible-fee/src/mock_price.rs b/pallets/flexible-fee/src/mock_price.rs index 80e7d0bca..18374e46e 100644 --- a/pallets/flexible-fee/src/mock_price.rs +++ b/pallets/flexible-fee/src/mock_price.rs @@ -19,8 +19,8 @@ #![cfg(test)] use bifrost_primitives::{ - Balance, CurrencyId, Price, PriceDetail, PriceFeeder, BNC, DOT, DOT_U, KSM, MANTA, VDOT, VKSM, - WETH, + Balance, CurrencyId, OraclePriceProvider, Price, PriceDetail, BNC, DOT, DOT_U, KSM, MANTA, + VDOT, VKSM, WETH, }; use frame_support::parameter_types; use sp_runtime::FixedU128; @@ -39,8 +39,8 @@ parameter_types! { ]); } -pub struct MockPriceFeeder; -impl MockPriceFeeder { +pub struct MockOraclePriceProvider; +impl MockOraclePriceProvider { pub fn set_price(currency_id: CurrencyId, price: Price) { let mut storage_price = StoragePrice::get(); match storage_price.get(¤cy_id) { @@ -55,7 +55,7 @@ impl MockPriceFeeder { } } -impl PriceFeeder for MockPriceFeeder { +impl OraclePriceProvider for MockOraclePriceProvider { fn get_price(currency_id: &CurrencyId) -> Option { match StoragePrice::get().get(currency_id) { Some((price, _)) => Some((*price, 0)), @@ -63,10 +63,6 @@ impl PriceFeeder for MockPriceFeeder { } } - fn get_normal_price(_asset_id: &CurrencyId) -> Option { - todo!() - } - fn get_amount_by_prices( currency_in: &CurrencyId, amount_in: Balance, @@ -119,14 +115,14 @@ mod test { #[test] fn set_price() { assert_eq!( - MockPriceFeeder::get_price(&BNC), + MockOraclePriceProvider::get_price(&BNC), Some((FixedU128::from_inner(200_000_000_000_000_000), 0)) ); - MockPriceFeeder::set_price(BNC, FixedU128::from(100)); - assert_eq!(MockPriceFeeder::get_price(&BNC), Some((FixedU128::from(100), 0))); + MockOraclePriceProvider::set_price(BNC, FixedU128::from(100)); + assert_eq!(MockOraclePriceProvider::get_price(&BNC), Some((FixedU128::from(100), 0))); - MockPriceFeeder::set_price(DOT, FixedU128::from(100)); - assert_eq!(MockPriceFeeder::get_price(&DOT), Some((FixedU128::from(100), 0))); + MockOraclePriceProvider::set_price(DOT, FixedU128::from(100)); + assert_eq!(MockOraclePriceProvider::get_price(&DOT), Some((FixedU128::from(100), 0))); } #[test] @@ -137,19 +133,27 @@ mod test { let usdt_amount = 20 * 10u128.pow(6); let manta_amount = 25 * 10u128.pow(18); assert_eq!( - MockPriceFeeder::get_oracle_amount_by_currency_and_amount_in(&BNC, bnc_amount, &DOT), + MockOraclePriceProvider::get_oracle_amount_by_currency_and_amount_in( + &BNC, bnc_amount, &DOT + ), Some((dot_amount, FixedU128::from_inner(200_000_000_000_000_000), FixedU128::from(5))) ); assert_eq!( - MockPriceFeeder::get_oracle_amount_by_currency_and_amount_in(&BNC, bnc_amount, &DOT_U), + MockOraclePriceProvider::get_oracle_amount_by_currency_and_amount_in( + &BNC, bnc_amount, &DOT_U + ), Some((usdt_amount, FixedU128::from_inner(200_000_000_000_000_000), FixedU128::from(1))) ); assert_eq!( - MockPriceFeeder::get_oracle_amount_by_currency_and_amount_in(&BNC, bnc_amount, &KSM), + MockOraclePriceProvider::get_oracle_amount_by_currency_and_amount_in( + &BNC, bnc_amount, &KSM + ), Some((ksm_amount, FixedU128::from_inner(200_000_000_000_000_000), FixedU128::from(20))) ); assert_eq!( - MockPriceFeeder::get_oracle_amount_by_currency_and_amount_in(&BNC, bnc_amount, &MANTA), + MockOraclePriceProvider::get_oracle_amount_by_currency_and_amount_in( + &BNC, bnc_amount, &MANTA + ), Some(( manta_amount, FixedU128::from_inner(200_000_000_000_000_000), @@ -157,11 +161,15 @@ mod test { )) ); assert_eq!( - MockPriceFeeder::get_oracle_amount_by_currency_and_amount_in(&DOT, dot_amount, &DOT_U), + MockOraclePriceProvider::get_oracle_amount_by_currency_and_amount_in( + &DOT, dot_amount, &DOT_U + ), Some((usdt_amount, FixedU128::from(5), FixedU128::from(1))) ); assert_eq!( - MockPriceFeeder::get_oracle_amount_by_currency_and_amount_in(&DOT, dot_amount, &KSM), + MockOraclePriceProvider::get_oracle_amount_by_currency_and_amount_in( + &DOT, dot_amount, &KSM + ), Some((ksm_amount, FixedU128::from(5), FixedU128::from(20))) ); } diff --git a/pallets/lend-market/src/lib.rs b/pallets/lend-market/src/lib.rs index 45b0903be..743701a0e 100644 --- a/pallets/lend-market/src/lib.rs +++ b/pallets/lend-market/src/lib.rs @@ -26,7 +26,7 @@ use core::cmp::max; pub use crate::rate_model::*; use bifrost_primitives::{ - Balance, CurrencyId, Liquidity, Price, PriceFeeder, Rate, Ratio, Shortfall, Timestamp, + Balance, CurrencyId, Liquidity, OraclePriceProvider, Price, Rate, Ratio, Shortfall, Timestamp, }; use frame_support::{ pallet_prelude::*, @@ -103,7 +103,7 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The oracle price feeder - type PriceFeeder: PriceFeeder; + type OraclePriceProvider: OraclePriceProvider; /// The loan's module id, keep all collaterals of CDPs. #[pallet::constant] @@ -1959,7 +1959,7 @@ impl Pallet { // Returns `Err` if the oracle price not ready pub fn get_price(asset_id: AssetIdOf) -> Result { let (price, _) = - T::PriceFeeder::get_price(&asset_id).ok_or(Error::::PriceOracleNotReady)?; + T::OraclePriceProvider::get_price(&asset_id).ok_or(Error::::PriceOracleNotReady)?; if price.is_zero() { return Err(Error::::PriceIsZero.into()); } diff --git a/pallets/lend-market/src/mock.rs b/pallets/lend-market/src/mock.rs index 294c4e24e..eecf3f21d 100644 --- a/pallets/lend-market/src/mock.rs +++ b/pallets/lend-market/src/mock.rs @@ -205,7 +205,7 @@ impl SortedMembers for AliceCreatePoolOrigin { } } -pub struct MockPriceFeeder; +pub struct MockOraclePriceProvider; #[derive(Encode, Decode, Clone, Copy, RuntimeDebug)] pub struct CurrencyIdWrap(CurrencyId); @@ -223,7 +223,7 @@ impl PartialEq for CurrencyIdWrap { impl Eq for CurrencyIdWrap {} -impl MockPriceFeeder { +impl MockOraclePriceProvider { thread_local! { pub static PRICES: RefCell>> = { RefCell::new( @@ -250,15 +250,11 @@ impl MockPriceFeeder { } } -impl PriceFeeder for MockPriceFeeder { +impl OraclePriceProvider for MockOraclePriceProvider { fn get_price(asset_id: &CurrencyId) -> Option { Self::PRICES.with(|prices| *prices.borrow().get(&CurrencyIdWrap(*asset_id)).unwrap()) } - fn get_normal_price(_asset_id: &CurrencyId) -> Option { - todo!() - } - fn get_amount_by_prices( _currency_in: &CurrencyId, _amount_in: Balance, @@ -327,7 +323,7 @@ parameter_types! { impl Config for Test { type RuntimeEvent = RuntimeEvent; - type PriceFeeder = MockPriceFeeder; + type OraclePriceProvider = MockOraclePriceProvider; type PalletId = LendMarketPalletId; type ReserveOrigin = EnsureRoot; type UpdateOrigin = EnsureRoot; diff --git a/pallets/lend-market/src/tests.rs b/pallets/lend-market/src/tests.rs index f8e2aec9e..b17c7a9df 100644 --- a/pallets/lend-market/src/tests.rs +++ b/pallets/lend-market/src/tests.rs @@ -656,7 +656,7 @@ fn get_account_liquidation_threshold_liquidity_works() { assert_eq!(liquidity, FixedU128::from_inner(unit(20))); assert_eq!(lf_liquidity, FixedU128::from_inner(unit(10))); - MockPriceFeeder::set_price(KSM, 2.into()); + MockOraclePriceProvider::set_price(KSM, 2.into()); let (liquidity, shortfall, lf_liquidity, _) = LendMarket::get_account_liquidation_threshold_liquidity(&ALICE).unwrap(); @@ -1259,10 +1259,10 @@ fn get_price_works() { BNC, vec![DOT, BNC, KSM, DOT_U, PHA] )); - MockPriceFeeder::set_price(DOT, 0.into()); + MockOraclePriceProvider::set_price(DOT, 0.into()); assert_noop!(LendMarket::get_price(DOT), Error::::PriceIsZero); - MockPriceFeeder::set_price(DOT, 2.into()); + MockOraclePriceProvider::set_price(DOT, 2.into()); assert_eq!(LendMarket::get_price(DOT).unwrap(), Price::saturating_from_integer(2)); }) } @@ -1813,7 +1813,7 @@ fn reward_calculation_after_liquidate_borrow_works() { assert_eq!(almost_equal(RewardAccrued::::get(ALICE), unit(14)), true); assert_eq!(almost_equal(RewardAccrued::::get(BOB), unit(16)), true); - MockPriceFeeder::set_price(KSM, 2.into()); + MockOraclePriceProvider::set_price(KSM, 2.into()); // since we set liquidate_threshold more than collateral_factor,with KSM price as 2 alice // not shortfall yet. so we can not liquidate_borrow here assert_noop!( @@ -1828,7 +1828,7 @@ fn reward_calculation_after_liquidate_borrow_works() { // Bob KSM Deposit: 500 // Bob KSM Borrow: 75 // incentive_reward_account DOT Deposit: 75*0.03 = 2.25 - MockPriceFeeder::set_price(KSM, 3.into()); + MockOraclePriceProvider::set_price(KSM, 3.into()); assert_ok!(LendMarket::liquidate_borrow( RuntimeOrigin::signed(BOB), ALICE, diff --git a/pallets/lend-market/src/tests/interest_rate.rs b/pallets/lend-market/src/tests/interest_rate.rs index 8bd5a22ba..fa391ca8f 100644 --- a/pallets/lend-market/src/tests/interest_rate.rs +++ b/pallets/lend-market/src/tests/interest_rate.rs @@ -371,7 +371,7 @@ fn accrue_interest_works_after_liquidate_borrow() { assert_eq!(BorrowIndex::::get(KSM), Rate::one()); TimestampPallet::set_timestamp(12000); // Adjust KSM price to make shortfall - MockPriceFeeder::set_price(KSM, 2.into()); + MockOraclePriceProvider::set_price(KSM, 2.into()); // BOB repay the KSM loan and get DOT callateral from ALICE assert_ok!(LendMarket::liquidate_borrow( RuntimeOrigin::signed(BOB), diff --git a/pallets/lend-market/src/tests/liquidate_borrow.rs b/pallets/lend-market/src/tests/liquidate_borrow.rs index 9e04e4a1e..17cb806da 100644 --- a/pallets/lend-market/src/tests/liquidate_borrow.rs +++ b/pallets/lend-market/src/tests/liquidate_borrow.rs @@ -1,6 +1,7 @@ use crate::{ mock::{ - new_test_ext, LendMarket, MockPriceFeeder, RuntimeOrigin, ALICE, BOB, DOT, DOT_U, KSM, *, + new_test_ext, LendMarket, MockOraclePriceProvider, RuntimeOrigin, ALICE, BOB, DOT, DOT_U, + KSM, *, }, tests::unit, Error, MarketState, @@ -23,7 +24,7 @@ fn liquidate_borrow_allowed_works() { initial_setup(); alice_borrows_100_ksm(); // Adjust KSM price to make shortfall - MockPriceFeeder::set_price(KSM, 2.into()); + MockOraclePriceProvider::set_price(KSM, 2.into()); let ksm_market = LendMarket::market(KSM).unwrap(); // Here the balance sheet of Alice is: // Collateral LendMarket @@ -82,8 +83,8 @@ fn lf_liquidate_borrow_allowed_works() { // CDOT's price is highly relative to DOT's price in real runtime. Thus we must update them // at the same time. - MockPriceFeeder::set_price(DOT, 2.into()); - MockPriceFeeder::set_price(PHA, 2.into()); + MockOraclePriceProvider::set_price(DOT, 2.into()); + MockOraclePriceProvider::set_price(PHA, 2.into()); // ALICE // Collateral Borrowed // DOT_U $100 DOT $400 @@ -113,7 +114,7 @@ fn deposit_of_borrower_must_be_collateral() { initial_setup(); alice_borrows_100_ksm(); // Adjust KSM price to make shortfall - MockPriceFeeder::set_price(KSM, 2.into()); + MockOraclePriceProvider::set_price(KSM, 2.into()); let market = LendMarket::market(KSM).unwrap(); assert_noop!( LendMarket::liquidate_borrow_allowed(&ALICE, KSM, unit(51), &market), @@ -134,7 +135,7 @@ fn collateral_value_must_be_greater_than_liquidation_value() { assert_ok!(LendMarket::add_market_bond(RuntimeOrigin::root(), BNC, vec![DOT, BNC, KSM])); initial_setup(); alice_borrows_100_ksm(); - MockPriceFeeder::set_price(KSM, Rate::from_float(2000.0)); + MockOraclePriceProvider::set_price(KSM, Rate::from_float(2000.0)); LendMarket::mutate_market(KSM, |market| { market.liquidate_incentive = Rate::from_float(200.0); market.clone() @@ -156,7 +157,7 @@ fn full_workflow_works_as_expected() { initial_setup(); alice_borrows_100_ksm(); // adjust KSM price to make ALICE generate shortfall - MockPriceFeeder::set_price(KSM, 2.into()); + MockOraclePriceProvider::set_price(KSM, 2.into()); // BOB repay the KSM borrow balance and get DOT from ALICE assert_ok!(LendMarket::liquidate_borrow( RuntimeOrigin::signed(BOB), @@ -227,7 +228,7 @@ fn liquidator_cannot_take_inactive_market_currency() { initial_setup(); alice_borrows_100_ksm(); // Adjust KSM price to make shortfall - MockPriceFeeder::set_price(KSM, 2.into()); + MockOraclePriceProvider::set_price(KSM, 2.into()); assert_ok!(LendMarket::mutate_market(DOT, |stored_market| { stored_market.state = MarketState::Supervision; stored_market.clone() @@ -247,7 +248,7 @@ fn liquidator_can_not_repay_more_than_the_close_factor_pct_multiplier() { assert_ok!(LendMarket::add_market_bond(RuntimeOrigin::root(), BNC, vec![DOT, BNC, KSM])); initial_setup(); alice_borrows_100_ksm(); - MockPriceFeeder::set_price(KSM, 20.into()); + MockOraclePriceProvider::set_price(KSM, 20.into()); assert_noop!( LendMarket::liquidate_borrow(RuntimeOrigin::signed(BOB), ALICE, KSM, unit(51), DOT), Error::::TooMuchRepay diff --git a/pallets/leverage-staking/src/mock.rs b/pallets/leverage-staking/src/mock.rs index a7c9944cf..f7ab5dd74 100644 --- a/pallets/leverage-staking/src/mock.rs +++ b/pallets/leverage-staking/src/mock.rs @@ -22,7 +22,7 @@ use bifrost_asset_registry::AssetIdMaps; pub use bifrost_primitives::{ currency::*, Balance, CurrencyId, CurrencyIdMapping, SlpOperator, SlpxOperator, TokenSymbol, }; -use bifrost_primitives::{Moment, MoonbeamChainId, Price, PriceDetail, PriceFeeder, Ratio}; +use bifrost_primitives::{Moment, MoonbeamChainId, OraclePriceProvider, Price, PriceDetail, Ratio}; use bifrost_runtime_common::milli; use frame_support::{ derive_impl, ord_parameter_types, parameter_types, @@ -340,7 +340,7 @@ impl pallet_timestamp::Config for Test { type WeightInfo = (); } -pub struct MockPriceFeeder; +pub struct MockOraclePriceProvider; #[derive(Encode, Decode, Clone, Copy, RuntimeDebug)] pub struct CurrencyIdWrap(CurrencyId); @@ -387,7 +387,7 @@ impl DataFeeder for MockDataProvider { } } -impl MockPriceFeeder { +impl MockOraclePriceProvider { thread_local! { pub static PRICES: RefCell>> = { RefCell::new( @@ -414,15 +414,11 @@ impl MockPriceFeeder { } } -impl PriceFeeder for MockPriceFeeder { +impl OraclePriceProvider for MockOraclePriceProvider { fn get_price(asset_id: &CurrencyId) -> Option { Self::PRICES.with(|prices| *prices.borrow().get(&CurrencyIdWrap(*asset_id)).unwrap()) } - fn get_normal_price(_asset_id: &CurrencyId) -> Option { - todo!() - } - fn get_amount_by_prices( _currency_in: &CurrencyId, _amount_in: Balance, @@ -450,7 +446,7 @@ parameter_types! { impl lend_market::Config for Test { type RuntimeEvent = RuntimeEvent; - type PriceFeeder = MockPriceFeeder; + type OraclePriceProvider = MockOraclePriceProvider; type PalletId = LendMarketPalletId; type ReserveOrigin = EnsureRoot; type UpdateOrigin = EnsureRoot; diff --git a/pallets/prices/src/lib.rs b/pallets/prices/src/lib.rs index 859826e63..a65516974 100644 --- a/pallets/prices/src/lib.rs +++ b/pallets/prices/src/lib.rs @@ -17,15 +17,15 @@ //! ## Overview //! //! This pallet provides the price from Oracle Module by implementing the -//! `PriceFeeder` trait. In case of emergency, the price can be set directly +//! `OraclePriceProvider` trait. In case of emergency, the price can be set directly //! by Oracle Collective. #![cfg_attr(not(feature = "std"), no_std)] use bifrost_asset_registry::AssetMetadata; use bifrost_primitives::{ - Balance, CurrencyId, CurrencyIdMapping, Price, PriceDetail, PriceFeeder, TimeStampedPrice, - TokenInfo, + Balance, CurrencyId, CurrencyIdMapping, OraclePriceProvider, Price, PriceDetail, + TimeStampedPrice, TokenInfo, }; use frame_support::{dispatch::DispatchClass, pallet_prelude::*, transactional}; use frame_system::pallet_prelude::*; @@ -144,7 +144,7 @@ pub mod pallet { price: Price, ) -> DispatchResultWithPostInfo { T::FeederOrigin::ensure_origin(origin)?; - as EmergencyPriceFeeder>::set_emergency_price( + as EmergencyOraclePriceProvider>::set_emergency_price( asset_id, price, ); Ok(().into()) @@ -159,7 +159,9 @@ pub mod pallet { asset_id: CurrencyId, ) -> DispatchResultWithPostInfo { T::FeederOrigin::ensure_origin(origin)?; - as EmergencyPriceFeeder>::reset_emergency_price(asset_id); + as EmergencyOraclePriceProvider>::reset_emergency_price( + asset_id, + ); Ok(().into()) } @@ -226,7 +228,7 @@ impl Pallet { } } -impl PriceFeeder for Pallet { +impl OraclePriceProvider for Pallet { /// Returns the uniform format price and timestamp by asset id. /// Formula: `price = oracle_price * 10.pow(18 - asset_decimal)` /// We use `oracle_price.checked_div(&FixedU128::from_inner(mantissa))` represent that. @@ -245,16 +247,6 @@ impl PriceFeeder for Pallet { }) } - fn get_normal_price(asset_id: &CurrencyId) -> Option { - let decimals = Self::get_asset_mantissa(asset_id)?; - EmergencyPrice::::get(asset_id) - .and_then(|p| Some(p.into_inner().saturating_div(decimals))) - .or_else(|| { - T::Source::get(&asset_id) - .and_then(|price| Some(price.value.into_inner().saturating_div(decimals))) - }) - } - /// Get the amount of currencies according to the input price data. /// Parameters: /// - `currency_in`: The currency to be converted. @@ -296,13 +288,17 @@ impl PriceFeeder for Pallet { currency_out: &CurrencyId, ) -> Option<(Balance, Price, Price)> { let price_in = Self::get_storage_price(currency_in)?; - let price_out = Self::get_storage_price(currency_out)?; - Self::get_amount_by_prices(currency_in, amount_in, price_in, currency_out, price_out) - .map(|amount_out| (amount_out, price_in, price_out)) + if currency_in == currency_out { + Some((amount_in, price_in, price_in)) + } else { + let price_out = Self::get_storage_price(currency_out)?; + Self::get_amount_by_prices(currency_in, amount_in, price_in, currency_out, price_out) + .map(|amount_out| (amount_out, price_in, price_out)) + } } } -impl EmergencyPriceFeeder for Pallet { +impl EmergencyOraclePriceProvider for Pallet { /// Set emergency price fn set_emergency_price(asset_id: CurrencyId, price: Price) { // set price direct diff --git a/pallets/traits/src/lib.rs b/pallets/traits/src/lib.rs index b51ec1b7d..3de362e4a 100644 --- a/pallets/traits/src/lib.rs +++ b/pallets/traits/src/lib.rs @@ -11,7 +11,7 @@ pub trait EmergencyCallFilter { fn contains(call: &Call) -> bool; } -pub trait EmergencyPriceFeeder { +pub trait EmergencyOraclePriceProvider { fn set_emergency_price(asset_id: CurrencyId, price: Price); fn reset_emergency_price(asset_id: CurrencyId); } diff --git a/primitives/src/price.rs b/primitives/src/price.rs index 22e09d2a5..aaaebe435 100644 --- a/primitives/src/price.rs +++ b/primitives/src/price.rs @@ -18,9 +18,8 @@ use crate::{Balance, CurrencyId, Price, PriceDetail}; -pub trait PriceFeeder { +pub trait OraclePriceProvider { fn get_price(asset_id: &CurrencyId) -> Option; - fn get_normal_price(asset_id: &CurrencyId) -> Option; fn get_amount_by_prices( currency_in: &CurrencyId, amount_in: Balance, diff --git a/runtime/bifrost-kusama/src/lib.rs b/runtime/bifrost-kusama/src/lib.rs index 24fe2de75..e57af8814 100644 --- a/runtime/bifrost-kusama/src/lib.rs +++ b/runtime/bifrost-kusama/src/lib.rs @@ -1040,7 +1040,7 @@ impl bifrost_flexible_fee::Config for Runtime { type RelaychainCurrencyId = RelayCurrencyId; type XcmRouter = XcmRouter; type PalletId = FlexibleFeePalletId; - type PriceFeeder = Prices; + type OraclePriceProvider = Prices; } parameter_types! { @@ -1345,7 +1345,7 @@ impl bifrost_fee_share::Config for Runtime { type ControlOrigin = CoreAdminOrCouncil; type WeightInfo = weights::bifrost_fee_share::BifrostWeight; type FeeSharePalletId = FeeSharePalletId; - type PriceFeeder = Prices; + type OraclePriceProvider = Prices; } impl bifrost_cross_in_out::Config for Runtime { @@ -1640,7 +1640,7 @@ impl pallet_prices::Config for Runtime { impl lend_market::Config for Runtime { type RuntimeEvent = RuntimeEvent; type PalletId = LendMarketPalletId; - type PriceFeeder = Prices; + type OraclePriceProvider = Prices; type ReserveOrigin = TechAdminOrCouncil; type UpdateOrigin = TechAdminOrCouncil; type WeightInfo = lend_market::weights::BifrostWeight; diff --git a/runtime/bifrost-polkadot/src/evm/evm_fee.rs b/runtime/bifrost-polkadot/src/evm/evm_fee.rs index 01656d02b..f85680b85 100644 --- a/runtime/bifrost-polkadot/src/evm/evm_fee.rs +++ b/runtime/bifrost-polkadot/src/evm/evm_fee.rs @@ -17,39 +17,38 @@ // along with this program. If not, see . use crate::Currencies; -use bifrost_primitives::{AccountFeeCurrency, Balance, CurrencyId}; -use bifrost_runtime_common::Ratio; -use frame_support::traits::{Get, OnUnbalanced, TryDrop}; +use bifrost_primitives::{ + AccountFeeCurrency, Balance, CurrencyId, OraclePriceProvider, Price, WETH, +}; +use frame_support::traits::TryDrop; use orml_traits::MultiCurrency; use pallet_evm::{AddressMapping, Error, OnChargeEVMTransaction}; use sp_core::{H160, U256}; -use sp_runtime::{ - helpers_128bit::multiply_by_rational_with_rounding, - traits::{Convert, UniqueSaturatedInto}, - Rounding, -}; +use sp_runtime::traits::UniqueSaturatedInto; use sp_std::marker::PhantomData; -#[derive(Copy, Clone, Default)] +#[derive(Copy, Debug, Clone, Default, PartialEq)] pub struct EvmPaymentInfo { - amount: Balance, - currency_id: CurrencyId, - price: Ratio, + fee_amount: Balance, + fee_currency: CurrencyId, + fee_currency_price: Price, + gas_fee_price: Price, } impl EvmPaymentInfo { pub fn merge(self, other: Self) -> Self { EvmPaymentInfo { - amount: self.amount.saturating_add(other.amount), - currency_id: self.currency_id, - price: self.price, + fee_amount: self.fee_amount.saturating_add(other.fee_amount), + fee_currency: self.fee_currency, + fee_currency_price: self.fee_currency_price, + gas_fee_price: self.gas_fee_price, } } } impl TryDrop for EvmPaymentInfo { fn try_drop(self) -> Result<(), Self> { - if self.amount == 0 { + if self.fee_amount == 0 { Ok(()) } else { Err(self) @@ -58,27 +57,21 @@ impl TryDrop for EvmPaymentInfo { } /// Implements the transaction payment for EVM transactions. -/// Supports multi-currency fees based on what is provided by AC - account currency. -pub struct TransferEvmFees(PhantomData<(OU, AC, EC, C, MC)>); +/// Supports multi-currency fees based on what is provided by AccountFeeCurrency - account currency. +pub struct TransferEvmFees(PhantomData<(AC, MC, Price)>); -impl OnChargeEVMTransaction for TransferEvmFees +impl OnChargeEVMTransaction for TransferEvmFees where T: pallet_evm::Config, - OU: OnUnbalanced, - U256: UniqueSaturatedInto, AC: AccountFeeCurrency, // AccountCurrency - EC: Get, // Evm default fee asset - C: Convert<(CurrencyId, CurrencyId, Balance), Option<(Balance, Ratio)>>, /* Conversion from - * default fee - * asset to account - * currency */ - U256: UniqueSaturatedInto, + Price: OraclePriceProvider, // PriceProvider MC: MultiCurrency, + U256: UniqueSaturatedInto, sp_runtime::AccountId32: From<::AccountId>, { type LiquidityInfo = Option; - fn withdraw_fee(who: &H160, fee: U256) -> Result> { + fn withdraw_fee(who: &H160, fee: U256) -> Result> { if fee.is_zero() { return Ok(None); } @@ -87,14 +80,18 @@ where let fee_currency = AC::get_fee_currency(&account_id, fee).map_err(|_| Error::::BalanceLow)?; - let Some((converted, price)) = - C::convert((EC::get(), fee_currency, fee.unique_saturated_into())) + let Some((fee_amount, gas_fee_price, fee_currency_price)) = + Price::get_oracle_amount_by_currency_and_amount_in( + &WETH, + fee.unique_saturated_into(), + &fee_currency, + ) else { return Err(Error::::WithdrawFailed); }; // Ensure that converted fee is not zero - if converted == 0 { + if fee_amount == 0 { return Err(Error::::WithdrawFailed); } @@ -103,13 +100,13 @@ where "Withdrew fee from account {:?} in currency {:?} amount {:?}", account_id, fee_currency, - converted + fee_amount ); - MC::withdraw(fee_currency, &account_id, converted) + MC::withdraw(fee_currency, &account_id, fee_amount) .map_err(|_| Error::::WithdrawFailed)?; - Ok(Some(EvmPaymentInfo { amount: converted, currency_id: fee_currency, price })) + Ok(Some(EvmPaymentInfo { fee_amount, fee_currency, fee_currency_price, gas_fee_price })) } fn correct_and_deposit_fee( @@ -118,71 +115,51 @@ where _base_fee: U256, already_withdrawn: Self::LiquidityInfo, ) -> Self::LiquidityInfo { - if let Some(paid) = already_withdrawn { + if let Some(payment_info) = already_withdrawn { let account_id = T::AddressMapping::into_account_id(*who); - // fee / weth = amounts[1] / amounts[0] - // fee = weth * amounts[1] / amounts[0] - let adjusted_paid = if let Some(converted_corrected_fee) = - multiply_by_rational_with_rounding( - corrected_fee.unique_saturated_into(), - paid.price.n, - paid.price.d, - Rounding::Up, - ) { + let adjusted_paid = if let Some(converted_corrected_fee) = Price::get_amount_by_prices( + &WETH, + corrected_fee.unique_saturated_into(), + payment_info.gas_fee_price, + &payment_info.fee_currency, + payment_info.fee_currency_price, + ) { // Calculate how much refund we should return - let refund_amount = paid.amount.saturating_sub(converted_corrected_fee); + let refund_amount = payment_info.fee_amount.saturating_sub(converted_corrected_fee); // refund to the account that paid the fees. If this fails, the // account might have dropped below the existential balance. In // that case we don't refund anything. let refund_imbalance = - match MC::deposit(paid.currency_id, &account_id, refund_amount) { + match MC::deposit(payment_info.fee_currency, &account_id, refund_amount) { Ok(_) => 0, Err(_) => refund_amount, }; // figure out how much is left to mint back // refund_amount already minted back to account, imbalance is what is left to mint // if any - paid.amount.saturating_sub(refund_amount).saturating_add(refund_imbalance) + payment_info + .fee_amount + .saturating_sub(refund_amount) + .saturating_add(refund_imbalance) } else { // if conversion failed for some reason, we refund the whole amount back to treasury - paid.amount + payment_info.fee_amount }; // We can simply refund all the remaining amount back to treasury - OU::on_unbalanced(EvmPaymentInfo { - amount: adjusted_paid, - currency_id: paid.currency_id, - price: paid.price, - }); - return None; + let result = Currencies::deposit( + payment_info.fee_currency, + &crate::BifrostTreasuryAccount::get(), + adjusted_paid, + ); + debug_assert_eq!(result, Ok(())); } None } fn pay_priority_fee(tip: Self::LiquidityInfo) { - if let Some(tip) = tip { - OU::on_unbalanced(tip); - } - } -} - -pub struct DepositEvmFeeToTreasury; -impl OnUnbalanced for DepositEvmFeeToTreasury { - // this is called for substrate-based transactions - fn on_unbalanceds(amounts: impl Iterator) { - Self::on_unbalanced(amounts.fold(EvmPaymentInfo::default(), |i, x| x.merge(i))) - } - - // this is called from pallet_evm for Ethereum-based transactions - // (technically, it calls on_unbalanced, which calls this when non-zero) - fn on_nonzero_unbalanced(payment_info: EvmPaymentInfo) { - let result = Currencies::deposit( - payment_info.currency_id, - &crate::BifrostTreasuryAccount::get(), - payment_info.amount, - ); - debug_assert_eq!(result, Ok(())); + debug_assert_eq!(tip, None); } } diff --git a/runtime/bifrost-polkadot/src/evm/mod.rs b/runtime/bifrost-polkadot/src/evm/mod.rs index db779492e..9b154e959 100644 --- a/runtime/bifrost-polkadot/src/evm/mod.rs +++ b/runtime/bifrost-polkadot/src/evm/mod.rs @@ -23,17 +23,14 @@ use pallet_evm::EnsureAddressTruncated; use pallet_transaction_payment::Multiplier; use primitive_types::U256; -use bifrost_primitives::{currency::WETH, CurrencyId}; -use bifrost_runtime_common::price::{ - ConvertAmount, FeeAssetBalanceInCurrency, OraclePriceProvider, -}; - pub use crate::evm::accounts_conversion::{ExtendedAddressMapping, FindAuthorTruncated}; use crate::{ - evm::runner::WrapRunner, governance::TechAdminOrCouncil, Aura, ConstU32, DynamicFee, - EVMChainId, Prices, Runtime, RuntimeEvent, Timestamp, Weight, EVM, MAXIMUM_BLOCK_WEIGHT, - NORMAL_DISPATCH_RATIO, WEIGHT_REF_TIME_PER_SECOND, + evm::runner::{FeeAssetBalanceInCurrency, WrapRunner}, + governance::TechAdminOrCouncil, + Aura, ConstU32, DynamicFee, EVMChainId, Runtime, RuntimeEvent, Timestamp, Weight, EVM, + MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, WEIGHT_REF_TIME_PER_SECOND, }; +use bifrost_primitives::{currency::WETH, CurrencyId}; mod accounts_conversion; mod evm_fee; @@ -107,18 +104,16 @@ impl pallet_evm::Config for Runtime { Self, pallet_evm::runner::stack::Runner, // Evm runner that we wrap FeeAssetBalanceInCurrency< - crate::Runtime, - ConvertAmount>, + Runtime, + crate::Prices, // Price provider crate::FlexibleFee, // Get account's fee payment asset crate::Currencies, // Account balance inspector >, >; type OnChargeTransaction = evm_fee::TransferEvmFees< - evm_fee::DepositEvmFeeToTreasury, crate::FlexibleFee, // Get account's fee payment asset - WethAssetId, - ConvertAmount>, - crate::Currencies, // Multi currency support + crate::Currencies, // Multi currency support + crate::Prices, // Price provider >; type OnCreate = (); type FindAuthor = FindAuthorTruncated; diff --git a/runtime/bifrost-polkadot/src/evm/runner.rs b/runtime/bifrost-polkadot/src/evm/runner.rs index 4e1e1058c..1bce82653 100644 --- a/runtime/bifrost-polkadot/src/evm/runner.rs +++ b/runtime/bifrost-polkadot/src/evm/runner.rs @@ -22,16 +22,68 @@ //! asset. //! //! Shamelessly copied from pallet-evm and modified to support multi-currency fees. + use crate::{evm::WethAssetId, Weight}; -use bifrost_primitives::{AccountFeeCurrencyBalanceInCurrency, Balance}; +use bifrost_primitives::{ + AccountFeeCurrency, AccountFeeCurrencyBalanceInCurrency, Balance, CurrencyId, + OraclePriceProvider, +}; use fp_evm::{Account, TransactionValidationError}; -use frame_support::traits::Get; +use frame_support::traits::{ + tokens::{Fortitude, Preservation}, + Get, +}; use pallet_evm::{ runner::Runner, AddressMapping, CallInfo, Config, CreateInfo, FeeCalculator, RunnerError, }; use primitive_types::{H160, H256, U256}; -use sp_runtime::traits::UniqueSaturatedInto; -use sp_std::vec::Vec; +use sp_runtime::{traits::UniqueSaturatedInto, DispatchError}; +use sp_std::{marker::PhantomData, vec::Vec}; + +/// AccountFeeCurrencyBalanceInCurrency implementation for the FeeAssetBalanceInCurrency. +/// Provides account's balance of fee asset currency in a given currency +pub struct FeeAssetBalanceInCurrency(PhantomData<(T, Price, AC, I)>); + +impl AccountFeeCurrencyBalanceInCurrency + for FeeAssetBalanceInCurrency +where + T: frame_system::Config, + Price: OraclePriceProvider, + AC: AccountFeeCurrency, + I: frame_support::traits::fungibles::Inspect< + T::AccountId, + AssetId = CurrencyId, + Balance = Balance, + >, +{ + type Output = (Balance, Weight); + type Error = DispatchError; + + fn get_balance_in_currency( + to_currency: CurrencyId, + account: &T::AccountId, + fee: U256, + ) -> Result { + let from_currency = AC::get_fee_currency(account, fee) + .map_err(|_| DispatchError::Other("Get Currency Error."))?; + let account_balance = + I::reducible_balance(from_currency, account, Preservation::Preserve, Fortitude::Polite); + let price_weight = T::DbWeight::get().reads(2); // 1 read to get currency and 1 read to get balance + + if from_currency == to_currency { + return Ok((account_balance, price_weight)); + } + + let Some((converted, _, _)) = Price::get_oracle_amount_by_currency_and_amount_in( + &from_currency, + account_balance, + &to_currency, + ) else { + return Ok((0, price_weight)); + }; + Ok((converted, price_weight)) + } +} pub struct WrapRunner(sp_std::marker::PhantomData<(T, R, B)>); diff --git a/runtime/bifrost-polkadot/src/lib.rs b/runtime/bifrost-polkadot/src/lib.rs index 778aad7b6..21cc7e077 100644 --- a/runtime/bifrost-polkadot/src/lib.rs +++ b/runtime/bifrost-polkadot/src/lib.rs @@ -925,7 +925,7 @@ impl bifrost_flexible_fee::Config for Runtime { type RelaychainCurrencyId = RelayCurrencyId; type XcmRouter = XcmRouter; type PalletId = FlexibleFeePalletId; - type PriceFeeder = Prices; + type OraclePriceProvider = Prices; } parameter_types! { @@ -1206,7 +1206,7 @@ impl bifrost_fee_share::Config for Runtime { type ControlOrigin = CoreAdminOrCouncil; type WeightInfo = weights::bifrost_fee_share::BifrostWeight; type FeeSharePalletId = FeeSharePalletId; - type PriceFeeder = Prices; + type OraclePriceProvider = Prices; } impl bifrost_cross_in_out::Config for Runtime { @@ -1481,7 +1481,7 @@ impl pallet_prices::Config for Runtime { impl lend_market::Config for Runtime { type RuntimeEvent = RuntimeEvent; type PalletId = LendMarketPalletId; - type PriceFeeder = Prices; + type OraclePriceProvider = Prices; type ReserveOrigin = TechAdminOrCouncil; type UpdateOrigin = TechAdminOrCouncil; type WeightInfo = lend_market::weights::BifrostWeight; diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index 4b44c00e4..c7fccfce8 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -32,10 +32,6 @@ use sp_runtime::{traits::Bounded, FixedPointNumber, Perquintill}; pub mod constants; pub mod currency_adapter; pub mod currency_converter; -pub mod price; -pub mod ratio; - -pub use ratio::Ratio; #[cfg(test)] mod tests; diff --git a/runtime/common/src/price.rs b/runtime/common/src/price.rs deleted file mode 100644 index c4e628af7..000000000 --- a/runtime/common/src/price.rs +++ /dev/null @@ -1,116 +0,0 @@ -// This file is part of Bifrost. - -// Copyright (C) Liebi Technologies PTE. LTD. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use frame_support::{ - pallet_prelude::Get, - traits::tokens::{Fortitude, Preservation}, -}; -use sp_core::U256; -use sp_runtime::{ - helpers_128bit::multiply_by_rational_with_rounding, traits::Convert, DispatchError, Rounding, -}; -use sp_std::marker::PhantomData; -use xcm::latest::Weight; - -use bifrost_primitives::{ - AccountFeeCurrency, AccountFeeCurrencyBalanceInCurrency, Balance, CurrencyId, PriceFeeder, - PriceProvider, -}; - -use crate::Ratio; - -pub struct OraclePriceProvider(PhantomData); - -impl PriceProvider for OraclePriceProvider -where - PF: PriceFeeder, -{ - type Price = Ratio; - - fn get_price(asset_a: CurrencyId, asset_b: CurrencyId) -> Option { - if let Some(a) = PF::get_normal_price(&asset_a) { - if let Some(b) = PF::get_normal_price(&asset_b) { - Some(Ratio::from((a, b))) - } else { - None - } - } else { - None - } - } -} - -pub struct FeeAssetBalanceInCurrency(PhantomData<(T, C, AC, I)>); - -impl AccountFeeCurrencyBalanceInCurrency - for FeeAssetBalanceInCurrency -where - T: frame_system::Config, - C: Convert<(CurrencyId, CurrencyId, Balance), Option<(Balance, Ratio)>>, - AC: AccountFeeCurrency, - I: frame_support::traits::fungibles::Inspect< - T::AccountId, - AssetId = CurrencyId, - Balance = Balance, - >, -{ - type Output = (Balance, Weight); - type Error = DispatchError; - - fn get_balance_in_currency( - to_currency: CurrencyId, - account: &T::AccountId, - fee: U256, - ) -> Result { - let from_currency = AC::get_fee_currency(account, fee) - .map_err(|_| DispatchError::Other("Get Currency Error."))?; - let account_balance = - I::reducible_balance(from_currency, account, Preservation::Preserve, Fortitude::Polite); - let price_weight = T::DbWeight::get().reads(2); // 1 read to get currency and 1 read to get balance - - if from_currency == to_currency { - return Ok((account_balance, price_weight)); - } - - let Some((converted, _)) = C::convert((from_currency, to_currency, account_balance)) else { - return Ok((0, price_weight)); - }; - Ok((converted, price_weight)) - } -} - -pub struct ConvertAmount

(PhantomData

); - -// Converts `amount` of `from_currency` to `to_currency` using given oracle -// Input: (from_currency, to_currency, amount) -// Output: Option<(converted_amount, price)> -impl

Convert<(CurrencyId, CurrencyId, Balance), Option<(Balance, Ratio)>> for ConvertAmount

-where - P: PriceProvider, -{ - fn convert( - (from_currency, to_currency, amount): (CurrencyId, CurrencyId, Balance), - ) -> Option<(Balance, Ratio)> { - if from_currency == to_currency { - return Some((amount, Ratio::one())); - } - let price = P::get_price(from_currency, to_currency)?; - let converted = multiply_by_rational_with_rounding(amount, price.n, price.d, Rounding::Up)?; - Some((converted, price)) - } -} diff --git a/runtime/common/src/ratio.rs b/runtime/common/src/ratio.rs deleted file mode 100644 index 01022e8e7..000000000 --- a/runtime/common/src/ratio.rs +++ /dev/null @@ -1,154 +0,0 @@ -// This file is part of Bifrost. - -// Copyright (C) Liebi Technologies PTE. LTD. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::cmp::{Ord, Ordering, PartialOrd}; -use num_traits::Zero; -use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; -use serde::{Deserialize, Serialize}; -use sp_arithmetic::helpers_128bit; - -/// A rational number represented by a `n`umerator and `d`enominator. -#[derive( - Clone, - Copy, - Default, - PartialEq, - Eq, - Encode, - Decode, - Serialize, - Deserialize, - TypeInfo, - MaxEncodedLen, -)] -pub struct Ratio { - pub n: u128, - pub d: u128, -} - -impl Ratio { - /// Build from a raw `n/d`. Ensures that `d > 0`. - pub const fn new(n: u128, d: u128) -> Self { - // reimplement `.max(1)` so this can be `const` - let d = if d > 0 { d } else { 1 }; - Self { n, d } - } - - /// Build from a raw `n/d`. This could lead to / 0 if not properly handled. - pub const fn new_unchecked(n: u128, d: u128) -> Self { - Self { n, d } - } - - /// Return a representation of one. - /// - /// Note that more than one combination of `n` and `d` can be one. - pub const fn one() -> Self { - Self::new_unchecked(1, 1) - } - - /// Return whether `self` is one. - /// - /// Should a denominator of 0 happen, this function will return `false`. - /// - /// Note that more than one combination of `n` and `d` can be one. - pub const fn is_one(&self) -> bool { - self.d > 0 && self.n == self.d - } - - /// Return a representation of zero. - /// - /// Note that any combination of `n == 0` and `d` represents zero. - pub const fn zero() -> Self { - Self::new_unchecked(0, 1) - } - - /// Return whether `self` is zero. - /// - /// Note that any combination of `n == 0` and `d` represents zero. - pub const fn is_zero(&self) -> bool { - self.n == 0 - } - - /// Invert `n/d` to `d/n`. - /// - /// NOTE: Zero inverts to zero. - pub const fn inverted(self) -> Self { - if self.is_zero() { - self - } else { - Self { n: self.d, d: self.n } - } - } -} - -impl From for (u128, u128) { - fn from(ratio: Ratio) -> (u128, u128) { - (ratio.n, ratio.d) - } -} - -impl From for Ratio { - fn from(n: u128) -> Self { - Self::new(n, 1) - } -} - -impl From<(u128, u128)> for Ratio { - fn from((n, d): (u128, u128)) -> Self { - Self::new(n, d) - } -} - -impl PartialOrd for Ratio { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -// Taken from Substrate's `Rational128`. -impl Ord for Ratio { - fn cmp(&self, other: &Self) -> Ordering { - if self.d == other.d { - self.n.cmp(&other.n) - } else if self.d.is_zero() { - Ordering::Greater - } else if other.d.is_zero() { - Ordering::Less - } else { - let self_n = helpers_128bit::to_big_uint(self.n) * helpers_128bit::to_big_uint(other.d); - let other_n = - helpers_128bit::to_big_uint(other.n) * helpers_128bit::to_big_uint(self.d); - self_n.cmp(&other_n) - } - } -} - -#[cfg(feature = "std")] -impl sp_std::fmt::Debug for Ratio { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - write!(f, "Ratio({} / {} ≈ {:.8})", self.n, self.d, self.n as f64 / self.d as f64) - } -} - -#[cfg(not(feature = "std"))] -impl sp_std::fmt::Debug for Ratio { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - write!(f, "Ratio({} / {})", self.n, self.d) - } -} From 3da46f5bc958d3db824e7e508514c4e6cf2e2694 Mon Sep 17 00:00:00 2001 From: hqwangningbo <2536935847@qq.com> Date: Fri, 20 Sep 2024 23:32:26 +0800 Subject: [PATCH 2/2] Update gas_fee_price to weth_price --- runtime/bifrost-polkadot/src/evm/evm_fee.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/runtime/bifrost-polkadot/src/evm/evm_fee.rs b/runtime/bifrost-polkadot/src/evm/evm_fee.rs index f85680b85..ce0de8c0d 100644 --- a/runtime/bifrost-polkadot/src/evm/evm_fee.rs +++ b/runtime/bifrost-polkadot/src/evm/evm_fee.rs @@ -32,7 +32,7 @@ pub struct EvmPaymentInfo { fee_amount: Balance, fee_currency: CurrencyId, fee_currency_price: Price, - gas_fee_price: Price, + weth_price: Price, } impl EvmPaymentInfo { @@ -41,7 +41,7 @@ impl EvmPaymentInfo { fee_amount: self.fee_amount.saturating_add(other.fee_amount), fee_currency: self.fee_currency, fee_currency_price: self.fee_currency_price, - gas_fee_price: self.gas_fee_price, + weth_price: self.weth_price, } } } @@ -80,7 +80,7 @@ where let fee_currency = AC::get_fee_currency(&account_id, fee).map_err(|_| Error::::BalanceLow)?; - let Some((fee_amount, gas_fee_price, fee_currency_price)) = + let Some((fee_amount, weth_price, fee_currency_price)) = Price::get_oracle_amount_by_currency_and_amount_in( &WETH, fee.unique_saturated_into(), @@ -106,7 +106,7 @@ where MC::withdraw(fee_currency, &account_id, fee_amount) .map_err(|_| Error::::WithdrawFailed)?; - Ok(Some(EvmPaymentInfo { fee_amount, fee_currency, fee_currency_price, gas_fee_price })) + Ok(Some(EvmPaymentInfo { fee_amount, fee_currency, fee_currency_price, weth_price })) } fn correct_and_deposit_fee( @@ -121,7 +121,7 @@ where let adjusted_paid = if let Some(converted_corrected_fee) = Price::get_amount_by_prices( &WETH, corrected_fee.unique_saturated_into(), - payment_info.gas_fee_price, + payment_info.weth_price, &payment_info.fee_currency, payment_info.fee_currency_price, ) {