diff --git a/bridges/snowbridge/pallets/system/src/lib.rs b/bridges/snowbridge/pallets/system/src/lib.rs index eb3da095fe855..1e03a0e905148 100644 --- a/bridges/snowbridge/pallets/system/src/lib.rs +++ b/bridges/snowbridge/pallets/system/src/lib.rs @@ -143,6 +143,7 @@ pub mod pallet { use super::*; #[pallet::pallet] + #[pallet::storage_version(migration::STORAGE_VERSION)] pub struct Pallet(_); #[pallet::config] diff --git a/bridges/snowbridge/pallets/system/src/migration.rs b/bridges/snowbridge/pallets/system/src/migration.rs index ee94fc091bd1e..de03b2c644a37 100644 --- a/bridges/snowbridge/pallets/system/src/migration.rs +++ b/bridges/snowbridge/pallets/system/src/migration.rs @@ -2,22 +2,30 @@ // SPDX-FileCopyrightText: 2023 Snowfork //! Governance API for controlling the Ethereum side of the bridge use super::*; -use frame_support::traits::OnRuntimeUpgrade; +use frame_support::{ + migrations::VersionedMigration, + pallet_prelude::*, + traits::{OnRuntimeUpgrade, UncheckedOnRuntimeUpgrade}, + weights::Weight, +}; use log; +use sp_std::marker::PhantomData; #[cfg(feature = "try-runtime")] use sp_runtime::TryRuntimeError; -pub mod v0 { - use frame_support::{pallet_prelude::*, weights::Weight}; +const LOG_TARGET: &str = "ethereum_system::migration"; - use super::*; +/// The in-code storage version. +pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); - const LOG_TARGET: &str = "ethereum_system::migration"; +pub mod v0 { + use super::*; pub struct InitializeOnUpgrade( - sp_std::marker::PhantomData<(T, BridgeHubParaId, AssetHubParaId)>, + PhantomData<(T, BridgeHubParaId, AssetHubParaId)>, ); + impl OnRuntimeUpgrade for InitializeOnUpgrade where @@ -72,3 +80,118 @@ pub mod v0 { } } } + +pub mod v1 { + use super::*; + + #[cfg(feature = "try-runtime")] + use sp_core::U256; + + /// Descreases the fee per gas. + pub struct FeePerGasMigration(PhantomData); + + #[cfg(feature = "try-runtime")] + impl FeePerGasMigration + where + T: Config, + { + /// Calculate the fee required to pay for gas on Ethereum. + fn calculate_remote_fee(params: &PricingParametersOf) -> U256 { + use snowbridge_core::outbound::{ + AgentExecuteCommand, Command, ConstantGasMeter, GasMeter, + }; + let command = Command::AgentExecute { + agent_id: H256::zero(), + command: AgentExecuteCommand::TransferToken { + token: H160::zero(), + recipient: H160::zero(), + amount: 0, + }, + }; + let gas_used_at_most = ConstantGasMeter::maximum_gas_used_at_most(&command); + params + .fee_per_gas + .saturating_mul(gas_used_at_most.into()) + .saturating_add(params.rewards.remote) + } + } + + /// The percentage gas increase. We must adjust the fee per gas by this percentage. + const GAS_INCREASE_PERCENTAGE: u64 = 70; + + impl UncheckedOnRuntimeUpgrade for FeePerGasMigration + where + T: Config, + { + fn on_runtime_upgrade() -> Weight { + let mut params = Pallet::::parameters(); + + let old_fee_per_gas = params.fee_per_gas; + + // Fee per gas can be set based on a percentage in order to keep the remote fee the + // same. + params.fee_per_gas = params.fee_per_gas * GAS_INCREASE_PERCENTAGE / 100; + + log::info!( + target: LOG_TARGET, + "Fee per gas migrated from {old_fee_per_gas:?} to {0:?}.", + params.fee_per_gas, + ); + + PricingParameters::::put(params); + T::DbWeight::get().reads_writes(1, 1) + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + use codec::Encode; + + let params = Pallet::::parameters(); + let remote_fee = Self::calculate_remote_fee(¶ms); + + log::info!( + target: LOG_TARGET, + "Pre fee per gas migration: pricing parameters = {params:?}, remote_fee = {remote_fee:?}" + ); + Ok((params, remote_fee).encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), TryRuntimeError> { + use codec::Decode; + + let (old_params, old_remote_fee): (PricingParametersOf, U256) = + Decode::decode(&mut &state[..]).unwrap(); + + let params = Pallet::::parameters(); + ensure!(old_params.exchange_rate == params.exchange_rate, "Exchange rate unchanged."); + ensure!(old_params.rewards == params.rewards, "Rewards unchanged."); + ensure!( + (old_params.fee_per_gas * GAS_INCREASE_PERCENTAGE / 100) == params.fee_per_gas, + "Fee per gas decreased." + ); + ensure!(old_params.multiplier == params.multiplier, "Multiplier unchanged."); + + let remote_fee = Self::calculate_remote_fee(¶ms); + ensure!( + remote_fee <= old_remote_fee, + "The remote fee can cover the cost of the previous fee." + ); + + log::info!( + target: LOG_TARGET, + "Post fee per gas migration: pricing parameters = {params:?} remote_fee = {remote_fee:?}" + ); + Ok(()) + } + } +} + +/// Run the migration of the gas price and increment the pallet version so it cannot be re-run. +pub type FeePerGasMigrationV0ToV1 = VersionedMigration< + 0, + 1, + v1::FeePerGasMigration, + Pallet, + ::DbWeight, +>; diff --git a/bridges/snowbridge/primitives/core/src/outbound.rs b/bridges/snowbridge/primitives/core/src/outbound.rs index 77770761822a8..53d7d5ef7a416 100644 --- a/bridges/snowbridge/primitives/core/src/outbound.rs +++ b/bridges/snowbridge/primitives/core/src/outbound.rs @@ -444,7 +444,7 @@ impl GasMeter for ConstantGasMeter { // * No gas refund for clearing storage slot of source account in ERC20 contract // * Assume dest account in ERC20 contract does not yet have a storage slot // * ERC20.transferFrom possibly does other business logic besides updating balances - AgentExecuteCommand::TransferToken { .. } => 100_000, + AgentExecuteCommand::TransferToken { .. } => 200_000, }, Command::Upgrade { initializer, .. } => { let initializer_max_gas = match *initializer { @@ -457,7 +457,7 @@ impl GasMeter for ConstantGasMeter { }, Command::SetTokenTransferFees { .. } => 60_000, Command::SetPricingParameters { .. } => 60_000, - Command::TransferNativeToken { .. } => 100_000, + Command::TransferNativeToken { .. } => 200_000, Command::RegisterForeignToken { .. } => 1_200_000, Command::MintForeignToken { .. } => 100_000, } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index 66743fa3a07ea..70db1ce21499c 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -640,7 +640,7 @@ pub mod bridging { /// (initially was calculated by test `OutboundQueue::calculate_fees` - ETH/ROC 1/400 and fee_per_gas 20 GWEI = 2200698000000 + *25%) /// Needs to be more than fee calculated from DefaultFeeConfig FeeConfigRecord in snowbridge:parachain/pallets/outbound-queue/src/lib.rs /// Polkadot uses 10 decimals, Kusama and Rococo 12 decimals. - pub const DefaultBridgeHubEthereumBaseFee: Balance = 2_750_872_500_000; + pub const DefaultBridgeHubEthereumBaseFee: Balance = 3_833_568_200_000; pub storage BridgeHubEthereumBaseFee: Balance = DefaultBridgeHubEthereumBaseFee::get(); pub SiblingBridgeHubWithEthereumInboundQueueInstance: Location = Location::new( 1, diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index 88ccd42dff7f8..f39553d7024a9 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs @@ -655,7 +655,7 @@ pub mod bridging { /// (initially was calculated by test `OutboundQueue::calculate_fees` - ETH/WND 1/400 and fee_per_gas 20 GWEI = 2200698000000 + *25%) /// Needs to be more than fee calculated from DefaultFeeConfig FeeConfigRecord in snowbridge:parachain/pallets/outbound-queue/src/lib.rs /// Polkadot uses 10 decimals, Kusama,Rococo,Westend 12 decimals. - pub const DefaultBridgeHubEthereumBaseFee: Balance = 2_750_872_500_000; + pub const DefaultBridgeHubEthereumBaseFee: Balance = 3_833_568_200_000; pub storage BridgeHubEthereumBaseFee: Balance = DefaultBridgeHubEthereumBaseFee::get(); pub SiblingBridgeHubWithEthereumInboundQueueInstance: Location = Location::new( 1, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 7354ede034bfd..3d11b19abcdad 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -156,6 +156,7 @@ pub type Migrations = ( ConstU32, ConstU32, >, + snowbridge_pallet_system::migration::FeePerGasMigrationV0ToV1, pallet_bridge_messages::migration::v1::MigrationToV1< Runtime, bridge_to_westend_config::WithBridgeHubWestendMessagesInstance, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs index 8be2993c68f4f..fea61991ed764 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs @@ -36,7 +36,7 @@ use sp_runtime::{ }; parameter_types! { - pub const DefaultBridgeHubEthereumBaseFee: Balance = 2_750_872_500_000; + pub const DefaultBridgeHubEthereumBaseFee: Balance = 3_833_568_200_000; } fn collator_session_keys() -> bridge_hub_test_utils::CollatorSessionKeys { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 10f6be2e029c5..67be2f72d44b0 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -166,6 +166,7 @@ pub type Migrations = ( ConstU32, ConstU32, >, + snowbridge_pallet_system::migration::FeePerGasMigrationV0ToV1, bridge_to_ethereum_config::migrations::MigrationForXcmV5, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/snowbridge.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/snowbridge.rs index 1a1ce2a28ea35..0e7bb6a827122 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/snowbridge.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/snowbridge.rs @@ -37,7 +37,7 @@ use sp_runtime::{ }; parameter_types! { - pub const DefaultBridgeHubEthereumBaseFee: Balance = 2_750_872_500_000; + pub const DefaultBridgeHubEthereumBaseFee: Balance = 3_833_568_200_000; } fn collator_session_keys() -> bridge_hub_test_utils::CollatorSessionKeys { diff --git a/prdoc/pr_8258.prdoc b/prdoc/pr_8258.prdoc new file mode 100644 index 0000000000000..c73ccadf15efc --- /dev/null +++ b/prdoc/pr_8258.prdoc @@ -0,0 +1,22 @@ +title: '[stable2412] Backport Snowbridge - Update TransferToken command gas limit.' + +doc: + - audience: Runtime Dev + description: | + Transfering certain ERC20 tokens require more gas than 100_000 gas. An example is LDO token which requires 140_000 gas. + This change updates the gas limit to 200_000 and also updates the default fees for testnet runtimes. + NOTE: make sure to update the relevant runtime fees to account for this change. + +crates: + - name: asset-hub-westend-runtime + bump: patch + - name: asset-hub-rococo-runtime + bump: patch + - name: bridge-hub-westend-runtime + bump: patch + - name: bridge-hub-rococo-runtime + bump: patch + - name: snowbridge-core + bump: patch + - name: snowbridge-pallet-system + bump: patch