Skip to content

Commit

Permalink
Fix fee (#1891)
Browse files Browse the repository at this point in the history
* change fee calculation

* fix fee

* update weight

* update benchmark

* transfer all to treasury

* apply review

* extract calculate rate and use it in test

* set threshold to 2.5 KAR

* udpate testcase

* cargo run --release --color=never --bin=acala --features=runtime-benchmarks --features=with-karura-runtime -- benchmark --chain=karura-dev --steps=50 --repeat=20 --pallet=module_transaction_payment --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --template=./templates/runtime-weight-template.hbs --output=./runtime/karura/src/weights/

* cargo run --release --color=never --bin=acala --features=runtime-benchmarks --features=with-acala-runtime -- benchmark --chain=acala-latest --steps=50 --repeat=20 --pallet=module_transaction_payment --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --template=./templates/runtime-weight-template.hbs --output=./runtime/acala/src/weights/

Co-authored-by: Acala Benchmarking Bot <[email protected]>
Co-authored-by: Bryan Chen <[email protected]>
  • Loading branch information
3 people authored Feb 16, 2022
1 parent 4efe8a0 commit 14bd3bf
Show file tree
Hide file tree
Showing 9 changed files with 383 additions and 50 deletions.
93 changes: 84 additions & 9 deletions modules/transaction-payment/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,8 @@ pub mod module {
InvalidBalance,
/// Can't find rate by the supply token
InvalidRate,
/// Can't find the token info in the charge fee pool
InvalidToken,
/// Dex swap pool is not available now
DexNotAvailable,
/// Charge fee pool is already exist
Expand All @@ -364,7 +366,7 @@ pub mod module {
}

#[pallet::event]
#[pallet::generate_deposit(pub(crate) fn deposit_event)]
#[pallet::generate_deposit(pub fn deposit_event)]
pub enum Event<T: Config> {
/// The global fee swap path was updated.
GlobalFeeSwapPathUpdated {
Expand All @@ -386,6 +388,19 @@ pub mod module {
pool_size: Balance,
swap_threshold: Balance,
},
/// The charge fee pool is swapped
ChargeFeePoolSwapped {
old_exchange_rate: Ratio,
swap_exchange_rate: Ratio,
new_exchange_rate: Ratio,
new_pool_size: Balance,
},
/// The charge fee pool is disabled
ChargeFeePoolDisabled {
currency_id: CurrencyId,
foreign_amount: Balance,
native_amount: Balance,
},
}

/// The next fee multiplier.
Expand Down Expand Up @@ -607,6 +622,14 @@ pub mod module {
T::UpdateOrigin::ensure_origin(origin)?;
Self::initialize_pool(currency_id, pool_size, swap_threshold)
}

/// Disable charge fee pool.
#[pallet::weight(<T as Config>::WeightInfo::disable_charge_fee_pool())]
#[transactional]
pub fn disable_charge_fee_pool(origin: OriginFor<T>, currency_id: CurrencyId) -> DispatchResult {
T::UpdateOrigin::ensure_origin(origin)?;
Self::disable_pool(currency_id)
}
}
}

Expand Down Expand Up @@ -838,24 +861,31 @@ where
// this means the charge fee pool is exhausted for this given token pair.
// we normally set the `SwapBalanceThreshold` gt ED to prevent this case.
let native_balance = T::Currency::free_balance(&sub_account);
if native_balance < SwapBalanceThreshold::<T>::get(supply_currency_id) {
let threshold_balance = SwapBalanceThreshold::<T>::get(supply_currency_id);
if native_balance < threshold_balance {
let trading_path = Self::get_trading_path_by_currency(&sub_account, supply_currency_id);
if let Some(trading_path) = trading_path {
let supply_balance = T::MultiCurrency::free_balance(supply_currency_id, &sub_account);
let supply_amount =
supply_balance.saturating_sub(T::MultiCurrency::minimum_balance(supply_currency_id));
if let Ok((_, swap_native_balance)) = T::DEX::swap_with_specific_path(
if let Ok((supply_amount, swap_native_balance)) = T::DEX::swap_with_specific_path(
&sub_account,
&trading_path,
SwapLimit::ExactSupply(supply_amount, 0),
) {
// calculate and update new rate, also update the pool size
let swap_exchange_rate = Ratio::saturating_from_rational(supply_amount, swap_native_balance);
let new_pool_size = swap_native_balance.saturating_add(native_balance);
let new_native_balance = rate.saturating_mul_int(new_pool_size);
let next_updated_rate =
Ratio::saturating_from_rational(new_native_balance, PoolSize::<T>::get(supply_currency_id));
TokenExchangeRate::<T>::insert(supply_currency_id, next_updated_rate);
let new_exchange_rate = Self::calculate_exchange_rate(supply_currency_id, swap_exchange_rate)?;

TokenExchangeRate::<T>::insert(supply_currency_id, new_exchange_rate);
PoolSize::<T>::insert(supply_currency_id, new_pool_size);
Pallet::<T>::deposit_event(Event::<T>::ChargeFeePoolSwapped {
old_exchange_rate: rate,
swap_exchange_rate,
new_exchange_rate,
new_pool_size,
});
} else {
debug_assert!(false, "Swap tx fee pool should not fail!");
}
Expand Down Expand Up @@ -910,8 +940,21 @@ where
T::PalletId::get().into_sub_account(id)
}

/// Initiate a charge fee swap pool. Usually used in `on_runtime_upgrade` or manual
/// `enable_charge_fee_pool` dispatch call.
/// Calculate the new exchange rate.
/// old_rate * (threshold/poolSize) + swap_exchange_rate * (1-threshold/poolSize)
fn calculate_exchange_rate(currency_id: CurrencyId, swap_exchange_rate: Ratio) -> Result<Ratio, Error<T>> {
let threshold_balance = SwapBalanceThreshold::<T>::get(currency_id);
let old_threshold_rate = Ratio::saturating_from_rational(threshold_balance, PoolSize::<T>::get(currency_id));
let new_threshold_rate = Ratio::one().saturating_sub(old_threshold_rate);

let rate = TokenExchangeRate::<T>::get(currency_id).ok_or(Error::<T>::InvalidRate)?;
let old_parts = rate.saturating_mul(old_threshold_rate);
let new_parts = swap_exchange_rate.saturating_mul(new_threshold_rate);
let new_exchange_rate = old_parts.saturating_add(new_parts);
Ok(new_exchange_rate)
}

/// Initiate a charge fee pool, transfer token from treasury account to sub account.
fn initialize_pool(currency_id: CurrencyId, pool_size: Balance, swap_threshold: Balance) -> DispatchResult {
let treasury_account = T::TreasuryAccount::get();
let sub_account = Self::sub_account_id(currency_id);
Expand Down Expand Up @@ -950,14 +993,46 @@ where
SwapBalanceThreshold::<T>::insert(currency_id, swap_threshold);
TokenExchangeRate::<T>::insert(currency_id, exchange_rate);
PoolSize::<T>::insert(currency_id, pool_size);

Self::deposit_event(Event::ChargeFeePoolEnabled {
sub_account,
currency_id,
exchange_rate,
pool_size,
swap_threshold,
});
Ok(())
}

/// Disable a charge fee pool, return token from sub account to treasury account.
fn disable_pool(currency_id: CurrencyId) -> DispatchResult {
ensure!(
TokenExchangeRate::<T>::contains_key(currency_id),
Error::<T>::InvalidToken
);
let treasury_account = T::TreasuryAccount::get();
let sub_account = Self::sub_account_id(currency_id);
let foreign_amount: Balance = T::MultiCurrency::free_balance(currency_id, &sub_account);
let native_amount: Balance = T::Currency::free_balance(&sub_account);

T::MultiCurrency::transfer(currency_id, &sub_account, &treasury_account, foreign_amount)?;
T::Currency::transfer(
&sub_account,
&treasury_account,
native_amount,
ExistenceRequirement::AllowDeath,
)?;

// remove map entry, then `swap_from_pool_or_dex` method will throw error.
TokenExchangeRate::<T>::remove(currency_id);
PoolSize::<T>::remove(currency_id);
SwapBalanceThreshold::<T>::remove(currency_id);

Self::deposit_event(Event::ChargeFeePoolDisabled {
currency_id,
foreign_amount,
native_amount,
});
Ok(())
}
}
Expand Down
5 changes: 3 additions & 2 deletions modules/transaction-payment/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,11 +236,12 @@ impl PriceProvider<CurrencyId> for MockPriceSource {
parameter_types! {
// DO NOT CHANGE THIS VALUE, AS IT EFFECT THE TESTCASES.
pub const FeePoolSize: Balance = 10_000;
pub const SwapThreshold: Balance = 20;
pub const LowerSwapThreshold: Balance = 20;
pub const MiddSwapThreshold: Balance = 5000;
pub const HigerSwapThreshold: Balance = 9500;
pub const TransactionPaymentPalletId: PalletId = PalletId(*b"aca/fees");
pub const TreasuryPalletId: PalletId = PalletId(*b"aca/trsy");
pub KaruraTreasuryAccount: AccountId = TreasuryPalletId::get().into_account();
pub FeePoolExchangeTokens: Vec<CurrencyId> = vec![AUSD, DOT];
}
ord_parameter_types! {
pub const ListingOrigin: AccountId = ALICE;
Expand Down
Loading

0 comments on commit 14bd3bf

Please sign in to comment.