Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Cargo.lock

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

7 changes: 7 additions & 0 deletions node/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#![cfg_attr(not(feature = "std"), no_std)]

use sp_core::{Decode, Encode, RuntimeDebug};
use sp_runtime::{
generic,
traits::{BlakeTwo256, IdentifyAccount, Verify},
Expand Down Expand Up @@ -125,3 +126,9 @@ pub type LeasePeriod = BlockNumber;

/// Index used for the child trie
pub type TrieIndex = u32;

#[derive(Encode, Decode, Eq, PartialEq, Copy, Clone, RuntimeDebug, PartialOrd, Ord)]
pub enum ExtraFeeName {
SalpContribute,
NoExtraFee,
}
6 changes: 6 additions & 0 deletions node/primitives/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,9 @@ pub trait MinterRewardExt<AccountId, Balance, CurrencyId, BlockNumber> {
pub trait BancorHandler<Balance> {
fn add_token(currency_id: super::CurrencyId, amount: Balance) -> DispatchResult;
}

impl<Balance> BancorHandler<Balance> for () {
fn add_token(_currency_id: super::CurrencyId, _amount: Balance) -> DispatchResult {
unimplemented!()
}
}
23 changes: 23 additions & 0 deletions node/primitives/src/xcm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
// 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 core::ops::{Add, Mul};

use codec::{Decode, Encode};
use sp_std::prelude::*;

Expand All @@ -29,6 +31,12 @@ pub enum TransferOriginType {

pub struct XcmBaseWeight(u64);

impl XcmBaseWeight {
pub fn new(x: u64) -> Self {
XcmBaseWeight(x)
}
}

impl From<u64> for XcmBaseWeight {
fn from(u: u64) -> Self {
XcmBaseWeight(u)
Expand All @@ -41,6 +49,21 @@ impl From<XcmBaseWeight> for u64 {
}
}

impl Add for XcmBaseWeight {
type Output = Self;
fn add(self, other: Self) -> Self::Output {
(self.0 + other.0).into()
}
}

impl Mul<u64> for XcmBaseWeight {
type Output = Self;

fn mul(self, rhs: u64) -> Self {
XcmBaseWeight::new(self.0 * rhs)
}
}

/// represent the transact type
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode)]
pub enum ParachainTransactType {
Expand Down
6 changes: 6 additions & 0 deletions pallets/flexible-fee/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ sp-std = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v
node-primitives = { path = "../../node/primitives", default-features = false }
zenlink-protocol = { version = "*", default-features = false }
orml-traits = { version = "0.4.1-dev", default-features = false }
impl-trait-for-tuples = "0.2.1"

[dev-dependencies]
orml-tokens = { version = "0.4.1-dev" }
Expand All @@ -25,6 +26,11 @@ sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-
sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.9" }
smallvec = "1.4.1"
cumulus-primitives-core = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.9" }
xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.9" }
pallet-xcm = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.9" }
xcm = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.9"}
xcm-support = { path = "../../xcm-support"}
bifrost-salp = { path = "../salp" }

[features]
default = ["std"]
Expand Down
53 changes: 45 additions & 8 deletions pallets/flexible-fee/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use frame_support::{
},
};
use frame_system::pallet_prelude::*;
use node_primitives::{CurrencyId, TokenSymbol};
use node_primitives::{CurrencyId, ExtraFeeName, TokenSymbol};
use orml_traits::MultiCurrency;
pub use pallet::*;
use pallet_transaction_payment::OnChargeTransaction;
Expand All @@ -44,11 +44,15 @@ use sp_std::{vec, vec::Vec};
pub use weights::WeightInfo;
use zenlink_protocol::{AssetBalance, AssetId, ExportZenlink};

use crate::fee_dealer::FeeDealer;
use crate::{
fee_dealer::FeeDealer,
misc_fees::{FeeDeductor, FeeGetter},
};

#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
pub mod fee_dealer;
pub mod misc_fees;
mod mock;
mod tests;
mod weights;
Expand All @@ -75,6 +79,16 @@ pub mod pallet {
type OnUnbalanced: OnUnbalanced<NegativeImbalanceOf<Self>>;
type DexOperator: ExportZenlink<Self::AccountId>;
type FeeDealer: FeeDealer<Self::AccountId, PalletBalanceOf<Self>, CurrencyIdOf<Self>>;
/// Filter if this transaction needs to be deducted extra fee besides basic transaction fee,
/// and get the name of the fee
type ExtraFeeMatcher: FeeGetter<CallOf<Self>>;
/// In charge of deducting extra fees
type MiscFeeHandler: FeeDeductor<
Self::AccountId,
CurrencyIdOf<Self>,
PalletBalanceOf<Self>,
CallOf<Self>,
>;

#[pallet::constant]
type TreasuryAccount: Get<Self::AccountId>;
Expand All @@ -101,6 +115,7 @@ pub mod pallet {
pub type PositiveImbalanceOf<T> = <<T as Config>::Currency as Currency<
<T as frame_system::Config>::AccountId,
>>::PositiveImbalance;
pub type CallOf<T> = <T as frame_system::Config>::Call;

#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
Expand All @@ -110,6 +125,7 @@ pub mod pallet {
pub enum Event<T: Config> {
FlexibleFeeExchanged(CurrencyIdOf<T>, u128), // token and amount
FixedRateFeeExchanged(CurrencyIdOf<T>, PalletBalanceOf<T>),
ExtraFeeDeducted(ExtraFeeName, CurrencyIdOf<T>, PalletBalanceOf<T>),
}

#[pallet::type_value]
Expand Down Expand Up @@ -187,7 +203,7 @@ where
/// Note: The `fee` already includes the `tip`.
fn withdraw_fee(
who: &T::AccountId,
_call: &T::Call,
call: &T::Call,
_info: &DispatchInfoOf<T::Call>,
fee: Self::Balance,
tip: Self::Balance,
Expand All @@ -207,16 +223,20 @@ where
let (fee_sign, fee_amount) = T::FeeDealer::ensure_can_charge_fee(who, fee, withdraw_reason)
.map_err(|_| TransactionValidityError::Invalid(InvalidTransaction::Payment))?;

let rs;
// if the user has enough BNC for fee
if fee_sign == false {
match T::Currency::withdraw(who, fee, withdraw_reason, ExistenceRequirement::AllowDeath)
{
rs = match T::Currency::withdraw(
who,
fee,
withdraw_reason,
ExistenceRequirement::AllowDeath,
) {
Ok(imbalance) => Ok(Some(imbalance)),
Err(_msg) => Err(InvalidTransaction::Payment.into()),
}
};
// if the user donsn't enough BNC but has enough KSM
} else {
// deduct fee currency and increase native currency amount
// This withdraw operation allows death. So it will succeed given the remaining amount
// less than the existential deposit.
let fee_currency_id = T::AlternativeFeeCurrencyId::get();
Expand All @@ -231,8 +251,25 @@ where
// need to return 0 value of imbalance type
// this value will be used to see post dispatch refund in BNC
// if charge less than actual payment, no refund will be paid
Ok(Some(NegativeImbalanceOf::<T>::zero()))
rs = Ok(Some(NegativeImbalanceOf::<T>::zero()));
}

// See if the this Call needs to pay extra fee
let (fee_name, if_extra_fee) = T::ExtraFeeMatcher::get_fee_info(call.clone());
if if_extra_fee {
// We define 77 as the error of extra fee deduction failure.
let (extra_fee_currency, extra_fee_amount) =
T::MiscFeeHandler::deduct_fee(who, &T::TreasuryAccount::get(), call).map_err(
|_| TransactionValidityError::Invalid(InvalidTransaction::Custom(77u8)),
)?;
Self::deposit_event(Event::ExtraFeeDeducted(
fee_name,
extra_fee_currency,
extra_fee_amount,
));
}

rs
}

/// Hand the fee and the tip over to the `[OnUnbalanced]` implementation.
Expand Down
114 changes: 114 additions & 0 deletions pallets/flexible-fee/src/misc_fees.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// This file is part of Bifrost.

// Copyright (C) 2019-2021 Liebi Technologies (UK) 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/>.

// The swap pool algorithm implements Balancer protocol
// For more details, refer to https://balancer.finance/whitepaper/

use frame_support::{
traits::Contains,
weights::{Weight, WeightToFeePolynomial},
};
use node_primitives::ExtraFeeName;

use super::*;
use crate::Config;

pub struct MiscFeeHandler<T, FeeCurrency, WeightToFee, WeightHolder, FeeFilter>(
PhantomData<(T, FeeCurrency, WeightToFee, WeightHolder, FeeFilter)>,
);

impl<T: Config, FeeCurrency, WeightToFee, WeightHolder, FeeFilter>
FeeDeductor<T::AccountId, CurrencyIdOf<T>, PalletBalanceOf<T>, T::Call>
for MiscFeeHandler<T, FeeCurrency, WeightToFee, WeightHolder, FeeFilter>
where
FeeCurrency: Get<CurrencyIdOf<T>>,
WeightToFee: WeightToFeePolynomial<Balance = PalletBalanceOf<T>>,
WeightHolder: Get<Weight>,
FeeFilter: Contains<CallOf<T>>,
{
fn deduct_fee(
who: &T::AccountId,
receiver: &T::AccountId,
call: &T::Call,
) -> Result<(CurrencyIdOf<T>, PalletBalanceOf<T>), DispatchError> {
// If this call matches a specific extra-fee call
if FeeFilter::contains(call) {
let total_fee = WeightToFee::calc(&WeightHolder::get());
let fee_currency = FeeCurrency::get();

<T as pallet::Config>::MultiCurrency::transfer(fee_currency, who, receiver, total_fee)?;
Ok((fee_currency, total_fee))
} else {
Err(DispatchError::Other("Failed to deduct extra fee."))
}
}
}

pub trait FeeDeductor<AccountId, CurrencyId, Balance, Call> {
fn deduct_fee(
who: &AccountId,
receiver: &AccountId,
call: &Call,
) -> Result<(CurrencyId, Balance), DispatchError>;
}

#[impl_trait_for_tuples::impl_for_tuples(30)]
impl<AccountId, CurrencyId, Balance, Call> FeeDeductor<AccountId, CurrencyId, Balance, Call>
for Tuple
{
fn deduct_fee(
who: &AccountId,
receiver: &AccountId,
call: &Call,
) -> Result<(CurrencyId, Balance), DispatchError> {
for_tuples!(
#(
if let Ok(result) = Tuple::deduct_fee(who, receiver, call) {
return Ok(result);
}
)*
);

return Err(DispatchError::Other("Failed to deduct extra fee."));
}
}

pub trait NameGetter<Call> {
fn get_name(call: &Call) -> ExtraFeeName;
}

pub trait FeeGetter<Call> {
fn get_fee_info(call: &Call) -> (ExtraFeeName, bool);
}

pub struct ExtraFeeMatcher<T, FeeNameGetter, AggregateExtraFeeFilter>(
PhantomData<(T, FeeNameGetter, AggregateExtraFeeFilter)>,
);
impl<T: Config, FeeNameGetter, AggregateExtraFeeFilter> FeeGetter<CallOf<T>>
for ExtraFeeMatcher<T, FeeNameGetter, AggregateExtraFeeFilter>
where
FeeNameGetter: NameGetter<CallOf<T>>,
AggregateExtraFeeFilter: Contains<CallOf<T>>,
{
fn get_fee_info(call: &CallOf<T>) -> (ExtraFeeName, bool) {
let fee_name = FeeNameGetter::get_name(call.clone());
let if_extra_fee = AggregateExtraFeeFilter::contains(call);

(fee_name, if_extra_fee)
}
}
Loading