diff --git a/pallets/liquidity-pools-gateway/routers/src/lib.rs b/pallets/liquidity-pools-gateway/routers/src/lib.rs index 6c23d9c39a..1dbe10b038 100644 --- a/pallets/liquidity-pools-gateway/routers/src/lib.rs +++ b/pallets/liquidity-pools-gateway/routers/src/lib.rs @@ -33,11 +33,12 @@ use frame_support::{ dispatch::{DispatchError, DispatchResult, Weight}, ensure, traits::OriginTrait, + weights::constants::WEIGHT_REF_TIME_PER_SECOND, }; use pallet_xcm_transactor::{Currency, CurrencyPayment, TransactWeights}; use scale_info::TypeInfo; use sp_core::{bounded::BoundedVec, ConstU32, H160, H256, U256}; -use sp_runtime::traits::{BlakeTwo256, EnsureMul, Hash}; +use sp_runtime::traits::{BlakeTwo256, EnsureAdd, EnsureMul, Hash}; use sp_std::{boxed::Box, marker::PhantomData, vec::Vec}; use xcm::{ latest::{MultiLocation, OriginKind}, @@ -228,15 +229,18 @@ where let ethereum_xcm_call = get_encoded_ethereum_xcm_call::(self.xcm_domain.clone(), msg) .map_err(|_| DispatchError::Other("encoded ethereum xcm call retrieval"))?; - // Note: We are using moonbeams calculation for the ref time here and their - // estimate for the PoV. + // NOTE: We are using Moonbeam's calculation for the ref time and their estimate + // for the PoV. // - // - Transact weight: gasLimit * 25000 as moonbeam is doing (Proof size - // limited fixed) + // ref_time: + // GAS_TO_WEIGHT_MULTIPLIER * MAX_GAS_LIMIT + EthereumXcm.transact's Weight + a + // bit extra let transact_required_weight_at_most = Weight::from_ref_time( self.xcm_domain .max_gas_limit - .ensure_mul(GAS_TO_WEIGHT_MULTIPLIER)?, + .ensure_mul(GAS_TO_WEIGHT_MULTIPLIER)? + .ensure_add(25_000_000)? + .ensure_add(5_000_000)?, ) .set_proof_size(DEFAULT_PROOF_SIZE.saturating_div(2)); @@ -261,9 +265,10 @@ where // The currency in which we want to pay fees. CurrencyPayment { currency: Currency::AsCurrencyId(self.xcm_domain.fee_currency.clone()), - fee_amount: Some( - self.xcm_domain.fee_per_second * Into::::into(overall_weight.ref_time()), - ), + fee_amount: Some(calculate_fee_amount( + overall_weight.ref_time(), + self.xcm_domain.fee_per_second, + )), }, // The call to be executed in the destination chain. ethereum_xcm_call, @@ -278,6 +283,15 @@ where } } +/// Calculate the fee to be charged for the complete XCM message execution on +/// the destination chain +pub fn calculate_fee_amount(overall_weight_ref_time: u64, fee_per_second: u128) -> u128 { + fee_per_second + .saturating_mul(overall_weight_ref_time as u128) + .saturating_add(WEIGHT_REF_TIME_PER_SECOND as u128 - 1) + .saturating_div(WEIGHT_REF_TIME_PER_SECOND as u128) +} + pub(crate) fn get_encoded_ethereum_xcm_call( xcm_domain: XcmDomain, msg: Vec, diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs index 922573ec86..99a48d0f11 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs @@ -782,6 +782,15 @@ fn transferring_invalid_tranche_tokens_should_fail() { }); } +#[test] +fn expected_fee_amount() { + // Roughly 0.15 GLMR + assert_eq!( + liquidity_pools_gateway_routers::calculate_fee_amount(15530000000, default_per_second(18)), + 155548480000000000 + ) +} + #[test] fn add_currency() { TestNet::reset(); @@ -814,10 +823,27 @@ fn add_currency() { }) )); + assert_eq!( + OrmlTokens::free_balance( + GLIMMER_CURRENCY_ID, + &::Sender::get() + ), + DEFAULT_BALANCE_GLMR + ); + assert_ok!(LiquidityPools::add_currency( RuntimeOrigin::signed(BOB.into()), currency_id )); + + assert_eq!( + OrmlTokens::free_balance( + GLIMMER_CURRENCY_ID, + &::Sender::get() + ), + /// Ensure it only charged roughly 0.15 GLMR for fees + DEFAULT_BALANCE_GLMR - 155548480000000000 + ); }); } @@ -1681,6 +1707,8 @@ mod utils { use liquidity_pools_gateway_routers::{ ethereum_xcm::EthereumXCMRouter, DomainRouter, XCMRouter, XcmTransactInfo, }; + use runtime_common::xcm_fees::native_per_second; + use sp_runtime::traits::{EnsureDiv, EnsureMul}; use super::*; use crate::{ @@ -1688,7 +1716,8 @@ mod utils { utils::{AUSD_CURRENCY_ID, GLIMMER_CURRENCY_ID, MOONBEAM_EVM_CHAIN_ID}, }; - pub const DEFAULT_BALANCE_GLMR: Balance = 1_000_000_000_000; + // 10 GLMR (18 decimals) + pub const DEFAULT_BALANCE_GLMR: Balance = 10000000000000000000; pub const DOMAIN_MOONBEAM: Domain = Domain::EVM(MOONBEAM_EVM_CHAIN_ID); pub const DEFAULT_EVM_ADDRESS_MOONBEAM: [u8; 20] = [99; 20]; pub const DEFAULT_DOMAIN_ADDRESS_MOONBEAM: DomainAddress = @@ -1748,7 +1777,7 @@ mod utils { location: Box::new(xcm_domain_location), ethereum_xcm_transact_call_index: BoundedVec::truncate_from(vec![38, 0]), contract_address: H160::from(utils::DEFAULT_EVM_ADDRESS_MOONBEAM), - max_gas_limit: 700_000, + max_gas_limit: 500_000, fee_currency: currency_id, fee_per_second: default_per_second(18), }, @@ -1805,7 +1834,7 @@ mod utils { OrmlTokens::deposit( GLIMMER_CURRENCY_ID, &::Sender::get(), - DEFAULT_BALANCE_GLMR * dollar(18), + DEFAULT_BALANCE_GLMR, ); // Register AUSD in the asset registry which is the default pool currency in