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
28 changes: 15 additions & 13 deletions bridges/snowbridge/pallets/ethereum-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,31 @@ exclude-from-umbrella = true

[dependencies]
codec = { features = ["derive"], workspace = true }
frame-benchmarking = { optional = true, workspace = true }
frame-support.workspace = true
frame-system.workspace = true
hex-literal = { optional = true, workspace = true, default-features = true }
log = { workspace = true }
pallet-timestamp = { optional = true, workspace = true }
scale-info = { features = ["derive"], workspace = true }
serde = { optional = true, workspace = true, default-features = true }
serde_json = { optional = true, workspace = true, default-features = true }
snowbridge-beacon-primitives.workspace = true
snowbridge-core.workspace = true
snowbridge-ethereum.workspace = true
snowbridge-pallet-ethereum-client-fixtures = { optional = true, workspace = true }
snowbridge-verification-primitives.workspace = true
sp-core.workspace = true

frame-benchmarking = { optional = true, workspace = true }
frame-support = { workspace = true }
frame-system = { workspace = true }
sp-core = { workspace = true }
sp-io = { optional = true, workspace = true }
sp-runtime.workspace = true
sp-std.workspace = true
sp-runtime = { workspace = true }
sp-std = { workspace = true }

pallet-timestamp = { optional = true, workspace = true }
snowbridge-beacon-primitives = { workspace = true }
snowbridge-core = { workspace = true }
snowbridge-ethereum = { workspace = true }
snowbridge-pallet-ethereum-client-fixtures = { optional = true, workspace = true }
snowbridge-verification-primitives = { workspace = true }
static_assertions = { workspace = true }

[dev-dependencies]
hex-literal = { workspace = true, default-features = true }
pallet-timestamp = { default-features = true, workspace = true }
pallet-timestamp = { workspace = true, default-features = true }
serde = { workspace = true, default-features = true }
serde_json = { workspace = true, default-features = true }
snowbridge-pallet-ethereum-client-fixtures = { default-features = true, workspace = true }
Expand Down
10 changes: 5 additions & 5 deletions bridges/snowbridge/pallets/ethereum-client/fixtures/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ exclude-from-umbrella = true

[dependencies]
hex-literal = { workspace = true, default-features = true }
snowbridge-beacon-primitives.workspace = true
snowbridge-core.workspace = true
snowbridge-verification-primitives.workspace = true
sp-core.workspace = true
sp-std.workspace = true
snowbridge-beacon-primitives = { workspace = true }
snowbridge-core = { workspace = true }
snowbridge-verification-primitives = { workspace = true }
sp-core = { workspace = true }
sp-std = { workspace = true }

[features]
default = ["std"]
Expand Down
42 changes: 23 additions & 19 deletions bridges/snowbridge/pallets/outbound-queue-v2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,32 +19,36 @@ exclude-from-umbrella = true

[dependencies]
alloy-core = { workspace = true, features = ["sol-types"] }
bp-relayers.workspace = true
bridge-hub-common.workspace = true
codec = { features = ["derive"], workspace = true }
ethabi = { workspace = true }
frame-benchmarking = { optional = true, workspace = true }
frame-support.workspace = true
frame-system.workspace = true
hex-literal = { workspace = true, default-features = true }
scale-info = { features = ["derive"], workspace = true }
serde = { features = ["alloc", "derive"], workspace = true }
snowbridge-beacon-primitives.workspace = true
snowbridge-core.workspace = true
snowbridge-merkle-tree.workspace = true
snowbridge-outbound-queue-primitives.workspace = true
snowbridge-verification-primitives.workspace = true
sp-arithmetic.workspace = true
sp-core.workspace = true
sp-io.workspace = true
sp-runtime.workspace = true
sp-std.workspace = true
xcm-builder.workspace = true
xcm-executor.workspace = true
xcm.workspace = true

frame-benchmarking = { optional = true, workspace = true }
frame-support = { workspace = true }
frame-system = { workspace = true }
sp-arithmetic = { workspace = true }
sp-core = { workspace = true }
sp-io = { workspace = true }
sp-runtime = { workspace = true }
sp-std = { workspace = true }

bp-relayers = { workspace = true }
bridge-hub-common = { workspace = true }

snowbridge-beacon-primitives = { workspace = true }
snowbridge-core = { workspace = true }
snowbridge-merkle-tree = { workspace = true }
snowbridge-outbound-queue-primitives = { workspace = true }
snowbridge-verification-primitives = { workspace = true }

xcm = { workspace = true }
xcm-builder = { workspace = true }
xcm-executor = { workspace = true }

[dev-dependencies]
pallet-message-queue = { workspace = true, default-features = false }
pallet-message-queue = { workspace = true }

[features]
default = ["std"]
Expand Down
2 changes: 1 addition & 1 deletion bridges/snowbridge/pallets/outbound-queue-v2/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ fn encode_unlock_message() {
let message: Message = mock_message(1000);
let message_abi_encoded = encode_mock_message(message);
println!("{}", HexDisplay::from(&message_abi_encoded));
assert_eq!(hex!("000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000b1185ede04202fe62d38f5db72f71e38ff3e830500000000000000000000000000000000000000000000000000000000000f4240").to_vec(), message_abi_encoded)
assert_eq!(hex!("000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000030d4000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000b1185ede04202fe62d38f5db72f71e38ff3e830500000000000000000000000000000000000000000000000000000000000f4240").to_vec(), message_abi_encoded)
}

#[test]
Expand Down
1 change: 1 addition & 0 deletions bridges/snowbridge/pallets/system/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ pub mod pallet {
use super::*;

#[pallet::pallet]
#[pallet::storage_version(migration::STORAGE_VERSION)]
pub struct Pallet<T>(_);

#[pallet::config]
Expand Down
159 changes: 153 additions & 6 deletions bridges/snowbridge/pallets/system/src/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,30 @@
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
//! 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<T, BridgeHubParaId, AssetHubParaId>(
sp_std::marker::PhantomData<(T, BridgeHubParaId, AssetHubParaId)>,
PhantomData<(T, BridgeHubParaId, AssetHubParaId)>,
);

impl<T, BridgeHubParaId, AssetHubParaId> OnRuntimeUpgrade
for InitializeOnUpgrade<T, BridgeHubParaId, AssetHubParaId>
where
Expand Down Expand Up @@ -72,3 +80,142 @@ pub mod v0 {
}
}
}

pub mod v1 {
use super::*;

#[cfg(feature = "try-runtime")]
use sp_core::U256;

/// Descreases the fee per gas.
pub struct FeePerGasMigration<T>(PhantomData<T>);

#[cfg(feature = "try-runtime")]
impl<T> FeePerGasMigration<T>
where
T: Config,
{
/// Calculate the fee required to pay for gas on Ethereum.
fn calculate_remote_fee_v1(params: &PricingParametersOf<T>) -> U256 {
use snowbridge_outbound_queue_primitives::v1::{
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)
}

/// Calculate the fee required to pay for gas on Ethereum.
fn calculate_remote_fee_v2(params: &PricingParametersOf<T>) -> U256 {
use snowbridge_outbound_queue_primitives::v2::{Command, ConstantGasMeter, GasMeter};
let command = Command::UnlockNativeToken {
token: H160::zero(),
recipient: H160::zero(),
amount: 0,
};
let gas_used_at_most = ConstantGasMeter::maximum_dispatch_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<T> UncheckedOnRuntimeUpgrade for FeePerGasMigration<T>
where
T: Config,
{
fn on_runtime_upgrade() -> Weight {
let mut params = Pallet::<T>::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::<T>::put(params);
T::DbWeight::get().reads_writes(1, 1)
}

#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
use codec::Encode;

let params = Pallet::<T>::parameters();
let remote_fee_v1 = Self::calculate_remote_fee_v1(&params);
let remote_fee_v2 = Self::calculate_remote_fee_v2(&params);

log::info!(
target: LOG_TARGET,
"Pre fee per gas migration: pricing parameters = {params:?}, remote_fee_v1 = {remote_fee_v1:?}, remote_fee_v2 = {remote_fee_v2:?}"
);
Ok((params, remote_fee_v1, remote_fee_v2).encode())
}

#[cfg(feature = "try-runtime")]
fn post_upgrade(state: Vec<u8>) -> Result<(), TryRuntimeError> {
use codec::Decode;

let (old_params, old_remote_fee_v1, old_remote_fee_v2): (
PricingParametersOf<T>,
U256,
U256,
) = Decode::decode(&mut &state[..]).unwrap();

let params = Pallet::<T>::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_v1 = Self::calculate_remote_fee_v1(&params);
let remote_fee_v2 = Self::calculate_remote_fee_v2(&params);
ensure!(
remote_fee_v1 <= old_remote_fee_v1,
"The v1 remote fee can cover the cost of the previous fee."
);
ensure!(
remote_fee_v2 <= old_remote_fee_v2,
"The v2 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_v1 = {remote_fee_v1:?} remote_fee_v2 = {remote_fee_v2:?}"
);
Ok(())
}
}
}

/// Run the migration of the gas price and increment the pallet version so it cannot be re-run.
pub type FeePerGasMigrationV0ToV1<T> = VersionedMigration<
0,
1,
v1::FeePerGasMigration<T>,
Pallet<T>,
<T as frame_system::Config>::DbWeight,
>;
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,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 {
Expand All @@ -362,7 +362,7 @@ impl GasMeter for ConstantGasMeter {
},
Command::SetTokenTransferFees { .. } => 60_000,
Command::SetPricingParameters { .. } => 60_000,
Command::UnlockNativeToken { .. } => 100_000,
Command::UnlockNativeToken { .. } => 200_000,
Command::RegisterForeignToken { .. } => 1_200_000,
Command::MintForeignToken { .. } => 100_000,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ impl GasMeter for ConstantGasMeter {
// the the initializer is called.
50_000 + initializer.maximum_required_gas
},
Command::UnlockNativeToken { .. } => 100_000,
Command::UnlockNativeToken { .. } => 200_000,
Command::RegisterForeignToken { .. } => 1_200_000,
Command::MintForeignToken { .. } => 100_000,
Command::CallContract { gas: gas_limit, .. } => *gas_limit,
Expand Down
Loading
Loading