Skip to content

Commit

Permalink
updated
Browse files Browse the repository at this point in the history
  • Loading branch information
MJLNSN committed Sep 20, 2024
2 parents 99db47e + 587d1e5 commit 939522d
Show file tree
Hide file tree
Showing 30 changed files with 1,209 additions and 1,342 deletions.
2 changes: 0 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions pallets/fee-share/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ mod benchmarking;

pub mod weights;

use bifrost_primitives::{CurrencyId, DistributionId, Price};
use bifrost_primitives::{CurrencyId, DistributionId, Price, PriceFeeder};
use frame_support::{
pallet_prelude::*,
sp_runtime::{
Expand All @@ -44,7 +44,6 @@ use frame_support::{
use frame_system::pallet_prelude::*;
use orml_traits::MultiCurrency;
pub use pallet::*;
use pallet_traits::PriceFeeder;
use sp_std::cmp::Ordering;
pub use weights::WeightInfo;

Expand Down
19 changes: 18 additions & 1 deletion pallets/fee-share/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ use orml_traits::{
location::RelativeReserveProvider, parameter_type_with_key, DataFeeder, DataProvider,
DataProviderExtended, MultiCurrency,
};
use pallet_traits::PriceFeeder;
use sp_core::ConstU32;
use sp_runtime::{
traits::{AccountIdConversion, IdentityLookup, UniqueSaturatedInto},
Expand Down Expand Up @@ -273,6 +272,24 @@ impl PriceFeeder for MockPriceFeeder {
fn get_normal_price(_asset_id: &CurrencyId) -> Option<u128> {
todo!()
}

fn get_amount_by_prices(
_currency_in: &CurrencyId,
_amount_in: bifrost_primitives::Balance,
_currency_in_price: Price,
_currency_out: &CurrencyId,
_currency_out_price: Price,
) -> Option<bifrost_primitives::Balance> {
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, Price, Price)> {
todo!()
}
}

pub struct ParaInfo;
Expand Down
2 changes: 0 additions & 2 deletions pallets/flexible-fee/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,11 @@ bifrost-currencies = { workspace = true }
sp-core = { workspace = true }
sp-io = { workspace = true }
cumulus-primitives-core = { workspace = true }
bifrost-salp = { workspace = true }
bifrost-asset-registry = { workspace = true }
bifrost-xcm-interface = { workspace = true }
xcm-executor = { workspace = true }
xcm-builder = { workspace = true }
pallet-xcm = { workspace = true }
bifrost-vtoken-voting = { workspace = true, features = ["kusama"] }

[features]
default = ["std"]
Expand Down
2 changes: 1 addition & 1 deletion pallets/flexible-fee/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ benchmarks! {
let caller = whitelisted_caller();
}: _(RawOrigin::Signed(caller),Some(CurrencyId::Token(TokenSymbol::DOT)))

set_universal_fee_currency_order_list {
set_default_fee_currency_list {
let default_list = BoundedVec::try_from(vec![CurrencyId::Token(TokenSymbol::DOT)]).unwrap();
}: _(RawOrigin::Root,default_list)

Expand Down
95 changes: 95 additions & 0 deletions pallets/flexible-fee/src/impls/account_fee_currency.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// 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 <https://www.gnu.org/licenses/>.

use crate::{Config, Error, Pallet, UniversalFeeCurrencyOrderList, UserDefaultFeeCurrency};
use bifrost_primitives::{AccountFeeCurrency, BalanceCmp, CurrencyId, WETH};
use frame_support::traits::{
fungibles::Inspect,
tokens::{Fortitude, Preservation},
};
use sp_arithmetic::traits::UniqueSaturatedInto;
use sp_core::U256;
use sp_std::cmp::Ordering;

/// Provides account's fee payment asset or default fee asset ( Native asset )
impl<T: Config> AccountFeeCurrency<T::AccountId> for Pallet<T> {
type Error = Error<T>;

/// Determines the appropriate currency to be used for paying transaction fees based on a
/// prioritized order:
/// 1. User's default fee currency (`UserDefaultFeeCurrency`)
/// 2. WETH
/// 3. Currencies in the `UniversalFeeCurrencyOrderList`
///
/// The method first checks if the balance of the highest-priority currency is sufficient to
/// cover the fee.If the balance is insufficient, it iterates through the list of currencies in
/// priority order.If no currency has a sufficient balance, it returns the currency with the
/// highest balance.
fn get_fee_currency(account: &T::AccountId, fee: U256) -> Result<CurrencyId, Error<T>> {
let fee: u128 = fee.unique_saturated_into();
let priority_currency = UserDefaultFeeCurrency::<T>::get(account);
let mut currency_list = UniversalFeeCurrencyOrderList::<T>::get();

let first_item_index = 0;
currency_list
.try_insert(first_item_index, WETH)
.map_err(|_| Error::<T>::MaxCurrenciesReached)?;

// When all currency balances are insufficient, return the one with the highest balance
let mut hopeless_currency = WETH;

if let Some(currency) = priority_currency {
currency_list
.try_insert(first_item_index, currency)
.map_err(|_| Error::<T>::MaxCurrenciesReached)?;
hopeless_currency = currency;
}

for maybe_currency in currency_list.iter() {
let comp_res = Self::cmp_with_precision(account, maybe_currency, fee, 18)?;

match comp_res {
Ordering::Less => {
// Get the currency with the highest balance
let hopeless_currency_balance = T::MultiCurrency::reducible_balance(
hopeless_currency,
account,
Preservation::Preserve,
Fortitude::Polite,
);
let maybe_currency_balance = T::MultiCurrency::reducible_balance(
*maybe_currency,
account,
Preservation::Preserve,
Fortitude::Polite,
);
hopeless_currency = match hopeless_currency_balance.cmp(&maybe_currency_balance)
{
Ordering::Less => *maybe_currency,
_ => hopeless_currency,
};
continue;
},
Ordering::Equal => return Ok(*maybe_currency),
Ordering::Greater => return Ok(*maybe_currency),
};
}

return Ok(hopeless_currency);
}
}
20 changes: 20 additions & 0 deletions pallets/flexible-fee/src/impls/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// 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 <https://www.gnu.org/licenses/>.

pub mod account_fee_currency;
pub mod on_charge_transaction;
162 changes: 162 additions & 0 deletions pallets/flexible-fee/src/impls/on_charge_transaction.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
// 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 <https://www.gnu.org/licenses/>.

use crate::{Config, ExtraFeeByCall, Pallet};
use bifrost_primitives::{Balance, CurrencyId, Price, PriceFeeder, BNC};
use orml_traits::MultiCurrency;
use pallet_transaction_payment::OnChargeTransaction;
use parity_scale_codec::Encode;
use sp_core::Get;
use sp_runtime::{
traits::{DispatchInfoOf, PostDispatchInfoOf, Zero},
transaction_validity::{InvalidTransaction, TransactionValidityError},
};

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PaymentInfo {
Native(Balance),
NonNative(Balance, CurrencyId, Price, Price),
}

/// Default implementation for a Currency and an OnUnbalanced handler.
impl<T> OnChargeTransaction<T> for Pallet<T>
where
T: Config,
T::MultiCurrency: MultiCurrency<T::AccountId, CurrencyId = CurrencyId>,
{
type Balance = Balance;
type LiquidityInfo = Option<PaymentInfo>;

/// Withdraw the predicted fee from the transaction origin.
///
/// Note: The `fee` already includes the `tip`.
fn withdraw_fee(
who: &T::AccountId,
call: &T::RuntimeCall,
_info: &DispatchInfoOf<T::RuntimeCall>,
fee: Self::Balance,
_tip: Self::Balance,
) -> Result<Self::LiquidityInfo, TransactionValidityError> {
if fee.is_zero() {
return Ok(None);
}

let (fee_currency, fee_amount, bnc_price, fee_currency_price) =
Self::get_fee_currency_and_fee_amount(who, fee)
.map_err(|_| TransactionValidityError::Invalid(InvalidTransaction::Payment))?;

// withdraw normal extrinsic fee
T::MultiCurrency::withdraw(fee_currency, who, fee_amount)
.map_err(|_| TransactionValidityError::Invalid(InvalidTransaction::Payment))?;

for (call_name, (extra_fee_currency, extra_fee_amount, extra_fee_receiver)) in
ExtraFeeByCall::<T>::iter()
{
let raw_call_name = call_name.to_vec();
let raw_call_name_len = raw_call_name.len();
if call.encode().len() >= raw_call_name_len {
if call.encode()[0..raw_call_name_len].eq(&raw_call_name) {
match Self::charge_extra_fee(
who,
extra_fee_currency,
extra_fee_amount,
&extra_fee_receiver,
) {
Ok(_) => {},
Err(_) => {
return Err(TransactionValidityError::Invalid(
InvalidTransaction::Payment,
));
},
}
};
}
}

if fee_currency == BNC {
Ok(Some(PaymentInfo::Native(fee_amount)))
} else {
Ok(Some(PaymentInfo::NonNative(
fee_amount,
fee_currency,
bnc_price,
fee_currency_price,
)))
}
}

/// Hand the fee and the tip over to the `[OnUnbalanced]` implementation.
/// Since the predicted fee might have been too high, parts of the fee may
/// be refunded.
///
/// Note: The `fee` already includes the `tip`.
fn correct_and_deposit_fee(
who: &T::AccountId,
_dispatch_info: &DispatchInfoOf<T::RuntimeCall>,
_post_info: &PostDispatchInfoOf<T::RuntimeCall>,
corrected_fee: Self::Balance,
tip: Self::Balance,
already_withdrawn: Self::LiquidityInfo,
) -> Result<(), TransactionValidityError> {
if let Some(paid) = already_withdrawn {
// Calculate how much refund we should return
let (currency, refund, fee, tip) = match paid {
PaymentInfo::Native(paid_fee) => (
BNC,
paid_fee.saturating_sub(corrected_fee),
corrected_fee.saturating_sub(tip),
tip,
),
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(
&BNC,
corrected_fee,
bnc_price,
&fee_currency,
fee_currency_price,
)
.ok_or(TransactionValidityError::Invalid(InvalidTransaction::Payment))?;
let refund = paid_fee.saturating_sub(converted_corrected_fee);
let converted_tip = T::PriceFeeder::get_amount_by_prices(
&BNC,
tip,
bnc_price,
&fee_currency,
fee_currency_price,
)
.ok_or(TransactionValidityError::Invalid(InvalidTransaction::Payment))?;
(
fee_currency,
refund,
converted_corrected_fee.saturating_sub(converted_tip),
converted_tip,
)
},
};
// refund to the account that paid the fees
T::MultiCurrency::deposit(currency, who, refund)
.map_err(|_| TransactionValidityError::Invalid(InvalidTransaction::Payment))?;

// deposit the fee
T::MultiCurrency::deposit(currency, &T::TreasuryAccount::get(), fee + tip)
.map_err(|_| TransactionValidityError::Invalid(InvalidTransaction::Payment))?;
}
Ok(())
}
}
Loading

0 comments on commit 939522d

Please sign in to comment.