feat: initialize Kurdistan SDK - independent fork of Polkadot SDK

This commit is contained in:
2025-12-13 15:44:15 +03:00
commit 286de54384
6841 changed files with 1848356 additions and 0 deletions
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
//! Helpers for implementing runtime api
use snowbridge_core::AgentId;
use xcm::{prelude::*, VersionedLocation};
use crate::{agent_id_of, Config};
pub fn agent_id<Runtime>(location: VersionedLocation) -> Option<AgentId>
where
Runtime: Config,
{
let location: Location = location.try_into().ok()?;
agent_id_of::<Runtime>(&location).ok()
}
@@ -0,0 +1,92 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
//! Benchmarking setup for pallet-template
use super::*;
#[allow(unused)]
use crate::Pallet as SnowbridgeControl;
use frame_benchmarking::v2::*;
use frame_system::RawOrigin;
use snowbridge_core::eth;
use snowbridge_outbound_queue_primitives::OperatingMode;
use sp_runtime::SaturatedConversion;
use xcm::prelude::*;
#[benchmarks]
mod benchmarks {
use super::*;
#[benchmark]
fn upgrade() -> Result<(), BenchmarkError> {
let impl_address = H160::repeat_byte(1);
let impl_code_hash = H256::repeat_byte(1);
// Assume 256 bytes passed to initializer
let params: Vec<u8> = (0..256).map(|_| 1u8).collect();
#[extrinsic_call]
_(
RawOrigin::Root,
impl_address,
impl_code_hash,
Some(Initializer { params, maximum_required_gas: 100000 }),
);
Ok(())
}
#[benchmark]
fn set_operating_mode() -> Result<(), BenchmarkError> {
#[extrinsic_call]
_(RawOrigin::Root, OperatingMode::RejectingOutboundMessages);
Ok(())
}
#[benchmark]
fn set_pricing_parameters() -> Result<(), BenchmarkError> {
let params = T::DefaultPricingParameters::get();
#[extrinsic_call]
_(RawOrigin::Root, params);
Ok(())
}
#[benchmark]
fn set_token_transfer_fees() -> Result<(), BenchmarkError> {
#[extrinsic_call]
_(RawOrigin::Root, 1, 1, eth(1));
Ok(())
}
#[benchmark]
fn register_token() -> Result<(), BenchmarkError> {
let caller: T::AccountId = whitelisted_caller();
let amount: BalanceOf<T> =
(10_000_000_000_000_u128).saturated_into::<u128>().saturated_into();
T::Token::mint_into(&caller, amount)?;
let relay_token_asset_id: Location = Location::parent();
let asset = Box::new(VersionedLocation::from(relay_token_asset_id));
let asset_metadata = AssetMetadata {
name: "wnd".as_bytes().to_vec().try_into().unwrap(),
symbol: "wnd".as_bytes().to_vec().try_into().unwrap(),
decimals: 12,
};
#[extrinsic_call]
_(RawOrigin::Root, asset, asset_metadata);
Ok(())
}
impl_benchmark_test_suite!(
SnowbridgeControl,
crate::mock::new_test_ext(true),
crate::mock::Test
);
}
@@ -0,0 +1,537 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
//! Governance API for controlling the Ethereum side of the bridge
//!
//! # Extrinsics
//!
//! ## Governance
//!
//! Only Pezkuwi governance itself can call these extrinsics. Delivery fees are waived.
//!
//! * [`Call::upgrade`]`: Upgrade the gateway contract
//! * [`Call::set_operating_mode`]: Update the operating mode of the gateway contract
//!
//! ## Pezkuwi-native tokens on Ethereum
//!
//! Tokens deposited on AssetHub pallet can be bridged to Ethereum as wrapped ERC20 tokens. As a
//! prerequisite, the token should be registered first.
//!
//! * [`Call::register_token`]: Register a token location as a wrapped ERC20 contract on Ethereum.
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
pub mod migration;
pub mod api;
pub mod weights;
pub use weights::*;
use frame_support::{
pallet_prelude::*,
traits::{
fungible::{Inspect, Mutate},
tokens::Preservation,
Contains, EnsureOrigin,
},
};
use frame_system::pallet_prelude::*;
use snowbridge_core::{
meth, AgentId, AssetMetadata, Channel, ChannelId, ParaId,
PricingParameters as PricingParametersRecord, TokenId, TokenIdOf, PRIMARY_GOVERNANCE_CHANNEL,
SECONDARY_GOVERNANCE_CHANNEL,
};
use snowbridge_outbound_queue_primitives::{
v1::{Command, Initializer, Message, SendMessage},
OperatingMode, SendError,
};
use sp_core::{RuntimeDebug, H160, H256};
use sp_io::hashing::blake2_256;
use sp_runtime::{traits::MaybeConvert, DispatchError, SaturatedConversion};
use sp_std::prelude::*;
use xcm::prelude::*;
use xcm_executor::traits::ConvertLocation;
#[cfg(feature = "runtime-benchmarks")]
use frame_support::traits::OriginTrait;
pub use pallet::*;
pub type BalanceOf<T> =
<<T as pallet::Config>::Token as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
pub type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
pub type PricingParametersOf<T> = PricingParametersRecord<BalanceOf<T>>;
/// Hash the location to produce an agent id
pub fn agent_id_of<T: Config>(location: &Location) -> Result<H256, DispatchError> {
T::AgentIdOf::convert_location(location).ok_or(Error::<T>::LocationConversionFailed.into())
}
#[cfg(feature = "runtime-benchmarks")]
pub trait BenchmarkHelper<O>
where
O: OriginTrait,
{
fn make_xcm_origin(location: Location) -> O;
}
/// Whether a fee should be withdrawn to an account for sending an outbound message
#[derive(Clone, PartialEq, RuntimeDebug)]
pub enum PaysFee<T>
where
T: Config,
{
/// Fully charge includes (local + remote fee)
Yes(AccountIdOf<T>),
/// Partially charge includes local fee only
Partial(AccountIdOf<T>),
/// No charge
No,
}
#[frame_support::pallet]
pub mod pallet {
use frame_support::dispatch::PostDispatchInfo;
use snowbridge_core::StaticLookup;
use sp_core::U256;
use super::*;
#[pallet::pallet]
#[pallet::storage_version(migration::STORAGE_VERSION)]
pub struct Pallet<T>(_);
#[pallet::config]
pub trait Config: frame_system::Config {
#[allow(deprecated)]
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
/// Send messages to Ethereum
type OutboundQueue: SendMessage<Balance = BalanceOf<Self>>;
/// Origin check for XCM locations that can create agents
type SiblingOrigin: EnsureOrigin<Self::RuntimeOrigin, Success = Location>;
/// Converts Location to AgentId
type AgentIdOf: ConvertLocation<AgentId>;
/// Token reserved for control operations
type Token: Mutate<Self::AccountId>;
/// TreasuryAccount to collect fees
#[pallet::constant]
type TreasuryAccount: Get<Self::AccountId>;
/// Number of decimal places of local currency
type DefaultPricingParameters: Get<PricingParametersOf<Self>>;
/// Cost of delivering a message from Ethereum
#[pallet::constant]
type InboundDeliveryCost: Get<BalanceOf<Self>>;
type WeightInfo: WeightInfo;
/// This chain's Universal Location.
type UniversalLocation: Get<InteriorLocation>;
// The bridges configured Ethereum location
type EthereumLocation: Get<Location>;
#[cfg(feature = "runtime-benchmarks")]
type Helper: BenchmarkHelper<Self::RuntimeOrigin>;
}
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
/// An Upgrade message was sent to the Gateway
Upgrade {
impl_address: H160,
impl_code_hash: H256,
initializer_params_hash: Option<H256>,
},
/// An CreateAgent message was sent to the Gateway
CreateAgent {
location: Box<Location>,
agent_id: AgentId,
},
/// An CreateChannel message was sent to the Gateway
CreateChannel {
channel_id: ChannelId,
agent_id: AgentId,
},
/// An UpdateChannel message was sent to the Gateway
UpdateChannel {
channel_id: ChannelId,
mode: OperatingMode,
},
/// An SetOperatingMode message was sent to the Gateway
SetOperatingMode {
mode: OperatingMode,
},
/// An TransferNativeFromAgent message was sent to the Gateway
TransferNativeFromAgent {
agent_id: AgentId,
recipient: H160,
amount: u128,
},
/// A SetTokenTransferFees message was sent to the Gateway
SetTokenTransferFees {
create_asset_xcm: u128,
transfer_asset_xcm: u128,
register_token: U256,
},
PricingParametersChanged {
params: PricingParametersOf<T>,
},
/// Register Pezkuwi-native token as a wrapped ERC20 token on Ethereum
RegisterToken {
/// Location of Pezkuwi-native token
location: VersionedLocation,
/// ID of Pezkuwi-native token on Ethereum
foreign_token_id: H256,
},
}
#[pallet::error]
pub enum Error<T> {
LocationConversionFailed,
AgentAlreadyCreated,
NoAgent,
ChannelAlreadyCreated,
NoChannel,
UnsupportedLocationVersion,
InvalidLocation,
Send(SendError),
InvalidTokenTransferFees,
InvalidPricingParameters,
InvalidUpgradeParameters,
}
/// The set of registered agents
#[pallet::storage]
#[pallet::getter(fn agents)]
pub type Agents<T: Config> = StorageMap<_, Twox64Concat, AgentId, (), OptionQuery>;
/// The set of registered channels
#[pallet::storage]
#[pallet::getter(fn channels)]
pub type Channels<T: Config> = StorageMap<_, Twox64Concat, ChannelId, Channel, OptionQuery>;
#[pallet::storage]
#[pallet::getter(fn parameters)]
pub type PricingParameters<T: Config> =
StorageValue<_, PricingParametersOf<T>, ValueQuery, T::DefaultPricingParameters>;
/// Lookup table for foreign token ID to native location relative to ethereum
#[pallet::storage]
pub type ForeignToNativeId<T: Config> =
StorageMap<_, Blake2_128Concat, TokenId, Location, OptionQuery>;
#[pallet::genesis_config]
#[derive(frame_support::DefaultNoBound)]
pub struct GenesisConfig<T: Config> {
// Own teyrchain id
pub para_id: ParaId,
// AssetHub's teyrchain id
pub asset_hub_para_id: ParaId,
#[serde(skip)]
pub _config: PhantomData<T>,
}
#[pallet::genesis_build]
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
fn build(&self) {
Pallet::<T>::initialize(self.para_id, self.asset_hub_para_id).expect("infallible; qed");
}
}
#[pallet::call]
impl<T: Config> Pallet<T> {
/// Sends command to the Gateway contract to upgrade itself with a new implementation
/// contract
///
/// Fee required: No
///
/// - `origin`: Must be `Root`.
/// - `impl_address`: The address of the implementation contract.
/// - `impl_code_hash`: The codehash of the implementation contract.
/// - `initializer`: Optionally call an initializer on the implementation contract.
#[pallet::call_index(0)]
#[pallet::weight((T::WeightInfo::upgrade(), DispatchClass::Operational))]
pub fn upgrade(
origin: OriginFor<T>,
impl_address: H160,
impl_code_hash: H256,
initializer: Option<Initializer>,
) -> DispatchResult {
ensure_root(origin)?;
ensure!(
!impl_address.eq(&H160::zero()) && !impl_code_hash.eq(&H256::zero()),
Error::<T>::InvalidUpgradeParameters
);
let initializer_params_hash: Option<H256> =
initializer.as_ref().map(|i| H256::from(blake2_256(i.params.as_ref())));
let command = Command::Upgrade { impl_address, impl_code_hash, initializer };
Self::send(PRIMARY_GOVERNANCE_CHANNEL, command, PaysFee::<T>::No)?;
Self::deposit_event(Event::<T>::Upgrade {
impl_address,
impl_code_hash,
initializer_params_hash,
});
Ok(())
}
/// Sends a message to the Gateway contract to change its operating mode
///
/// Fee required: No
///
/// - `origin`: Must be `Location`
#[pallet::call_index(1)]
#[pallet::weight((T::WeightInfo::set_operating_mode(), DispatchClass::Operational))]
pub fn set_operating_mode(origin: OriginFor<T>, mode: OperatingMode) -> DispatchResult {
ensure_root(origin)?;
let command = Command::SetOperatingMode { mode };
Self::send(PRIMARY_GOVERNANCE_CHANNEL, command, PaysFee::<T>::No)?;
Self::deposit_event(Event::<T>::SetOperatingMode { mode });
Ok(())
}
/// Set pricing parameters on both sides of the bridge
///
/// Fee required: No
///
/// - `origin`: Must be root
#[pallet::call_index(2)]
#[pallet::weight((T::WeightInfo::set_pricing_parameters(), DispatchClass::Operational))]
pub fn set_pricing_parameters(
origin: OriginFor<T>,
params: PricingParametersOf<T>,
) -> DispatchResult {
ensure_root(origin)?;
params.validate().map_err(|_| Error::<T>::InvalidPricingParameters)?;
PricingParameters::<T>::put(params.clone());
let command = Command::SetPricingParameters {
exchange_rate: params.exchange_rate.into(),
delivery_cost: T::InboundDeliveryCost::get().saturated_into::<u128>(),
multiplier: params.multiplier.into(),
};
Self::send(PRIMARY_GOVERNANCE_CHANNEL, command, PaysFee::<T>::No)?;
Self::deposit_event(Event::PricingParametersChanged { params });
Ok(())
}
/// Sends a message to the Gateway contract to update fee related parameters for
/// token transfers.
///
/// Privileged. Can only be called by root.
///
/// Fee required: No
///
/// - `origin`: Must be root
/// - `create_asset_xcm`: The XCM execution cost for creating a new asset class on AssetHub,
/// in HEZ
/// - `transfer_asset_xcm`: The XCM execution cost for performing a reserve transfer on
/// AssetHub, in HEZ
/// - `register_token`: The Ether fee for registering a new token, to discourage spamming
#[pallet::call_index(9)]
#[pallet::weight((T::WeightInfo::set_token_transfer_fees(), DispatchClass::Operational))]
pub fn set_token_transfer_fees(
origin: OriginFor<T>,
create_asset_xcm: u128,
transfer_asset_xcm: u128,
register_token: U256,
) -> DispatchResult {
ensure_root(origin)?;
// Basic validation of new costs. Particularly for token registration, we want to ensure
// its relatively expensive to discourage spamming. Like at least 100 USD.
ensure!(
create_asset_xcm > 0 && transfer_asset_xcm > 0 && register_token > meth(100),
Error::<T>::InvalidTokenTransferFees
);
let command = Command::SetTokenTransferFees {
create_asset_xcm,
transfer_asset_xcm,
register_token,
};
Self::send(PRIMARY_GOVERNANCE_CHANNEL, command, PaysFee::<T>::No)?;
Self::deposit_event(Event::<T>::SetTokenTransferFees {
create_asset_xcm,
transfer_asset_xcm,
register_token,
});
Ok(())
}
/// Registers a Pezkuwi-native token as a wrapped ERC20 token on Ethereum.
/// Privileged. Can only be called by root.
///
/// Fee required: No
///
/// - `origin`: Must be root
/// - `location`: Location of the asset (relative to this chain)
/// - `metadata`: Metadata to include in the instantiated ERC20 contract on Ethereum
#[pallet::call_index(10)]
#[pallet::weight(T::WeightInfo::register_token())]
pub fn register_token(
origin: OriginFor<T>,
location: Box<VersionedLocation>,
metadata: AssetMetadata,
) -> DispatchResultWithPostInfo {
ensure_root(origin)?;
let location: Location =
(*location).try_into().map_err(|_| Error::<T>::UnsupportedLocationVersion)?;
Self::do_register_token(&location, metadata, PaysFee::<T>::No)?;
Ok(PostDispatchInfo {
actual_weight: Some(T::WeightInfo::register_token()),
pays_fee: Pays::No,
})
}
}
impl<T: Config> Pallet<T> {
/// Send `command` to the Gateway on the Channel identified by `channel_id`
fn send(channel_id: ChannelId, command: Command, pays_fee: PaysFee<T>) -> DispatchResult {
let message = Message { id: None, channel_id, command };
let (ticket, fee) =
T::OutboundQueue::validate(&message).map_err(|err| Error::<T>::Send(err))?;
let payment = match pays_fee {
PaysFee::Yes(account) => Some((account, fee.total())),
PaysFee::Partial(account) => Some((account, fee.local)),
PaysFee::No => None,
};
if let Some((payer, fee)) = payment {
T::Token::transfer(
&payer,
&T::TreasuryAccount::get(),
fee,
Preservation::Preserve,
)?;
}
T::OutboundQueue::deliver(ticket).map_err(|err| Error::<T>::Send(err))?;
Ok(())
}
/// Initializes agents and channels.
pub fn initialize(para_id: ParaId, asset_hub_para_id: ParaId) -> Result<(), DispatchError> {
// Asset Hub
let asset_hub_location: Location =
ParentThen(Teyrchain(asset_hub_para_id.into()).into()).into();
let asset_hub_agent_id = agent_id_of::<T>(&asset_hub_location)?;
let asset_hub_channel_id: ChannelId = asset_hub_para_id.into();
Agents::<T>::insert(asset_hub_agent_id, ());
Channels::<T>::insert(
asset_hub_channel_id,
Channel { agent_id: asset_hub_agent_id, para_id: asset_hub_para_id },
);
// Governance channels
let bridge_hub_agent_id = agent_id_of::<T>(&Location::here())?;
// Agent for BridgeHub
Agents::<T>::insert(bridge_hub_agent_id, ());
// Primary governance channel
Channels::<T>::insert(
PRIMARY_GOVERNANCE_CHANNEL,
Channel { agent_id: bridge_hub_agent_id, para_id },
);
// Secondary governance channel
Channels::<T>::insert(
SECONDARY_GOVERNANCE_CHANNEL,
Channel { agent_id: bridge_hub_agent_id, para_id },
);
Ok(())
}
/// Checks if the pallet has been initialized.
pub(crate) fn is_initialized() -> bool {
let primary_exists = Channels::<T>::contains_key(PRIMARY_GOVERNANCE_CHANNEL);
let secondary_exists = Channels::<T>::contains_key(SECONDARY_GOVERNANCE_CHANNEL);
primary_exists && secondary_exists
}
pub(crate) fn do_register_token(
location: &Location,
metadata: AssetMetadata,
pays_fee: PaysFee<T>,
) -> Result<(), DispatchError> {
let ethereum_location = T::EthereumLocation::get();
// reanchor to Ethereum context
let location = location
.clone()
.reanchored(&ethereum_location, &T::UniversalLocation::get())
.map_err(|_| Error::<T>::LocationConversionFailed)?;
let token_id = TokenIdOf::convert_location(&location)
.ok_or(Error::<T>::LocationConversionFailed)?;
if !ForeignToNativeId::<T>::contains_key(token_id) {
ForeignToNativeId::<T>::insert(token_id, location.clone());
}
let command = Command::RegisterForeignToken {
token_id,
name: metadata.name.into_inner(),
symbol: metadata.symbol.into_inner(),
decimals: metadata.decimals,
};
Self::send(SECONDARY_GOVERNANCE_CHANNEL, command, pays_fee)?;
Self::deposit_event(Event::<T>::RegisterToken {
location: location.clone().into(),
foreign_token_id: token_id,
});
Ok(())
}
}
impl<T: Config> StaticLookup for Pallet<T> {
type Source = ChannelId;
type Target = Channel;
fn lookup(channel_id: Self::Source) -> Option<Self::Target> {
Channels::<T>::get(channel_id)
}
}
impl<T: Config> Contains<ChannelId> for Pallet<T> {
fn contains(channel_id: &ChannelId) -> bool {
Channels::<T>::get(channel_id).is_some()
}
}
impl<T: Config> Get<PricingParametersOf<T>> for Pallet<T> {
fn get() -> PricingParametersOf<T> {
PricingParameters::<T>::get()
}
}
impl<T: Config> MaybeConvert<TokenId, Location> for Pallet<T> {
fn maybe_convert(foreign_id: TokenId) -> Option<Location> {
ForeignToNativeId::<T>::get(foreign_id)
}
}
}
@@ -0,0 +1,223 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
//! Governance API for controlling the Ethereum side of the bridge
use super::*;
use frame_support::{
migrations::VersionedMigration,
pallet_prelude::*,
traits::{OnRuntimeUpgrade, UncheckedOnRuntimeUpgrade},
weights::Weight,
};
use sp_std::marker::PhantomData;
#[cfg(feature = "try-runtime")]
use sp_runtime::TryRuntimeError;
const LOG_TARGET: &str = "ethereum_system::migration";
/// The in-code storage version.
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
pub mod v0 {
use super::*;
pub struct InitializeOnUpgrade<T, BridgeHubParaId, AssetHubParaId>(
PhantomData<(T, BridgeHubParaId, AssetHubParaId)>,
);
impl<T, BridgeHubParaId, AssetHubParaId> OnRuntimeUpgrade
for InitializeOnUpgrade<T, BridgeHubParaId, AssetHubParaId>
where
T: Config,
BridgeHubParaId: Get<u32>,
AssetHubParaId: Get<u32>,
{
fn on_runtime_upgrade() -> Weight {
if !Pallet::<T>::is_initialized() {
Pallet::<T>::initialize(
BridgeHubParaId::get().into(),
AssetHubParaId::get().into(),
)
.expect("infallible; qed");
tracing::info!(
target: LOG_TARGET,
"Ethereum system initialized."
);
T::DbWeight::get().reads_writes(2, 5)
} else {
tracing::info!(
target: LOG_TARGET,
"Ethereum system already initialized. Skipping."
);
T::DbWeight::get().reads(2)
}
}
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
if !Pallet::<T>::is_initialized() {
tracing::info!(
target: LOG_TARGET,
"Agents and channels not initialized. Initialization will run."
);
} else {
tracing::info!(
target: LOG_TARGET,
"Agents and channels are initialized. Initialization will not run."
);
}
Ok(vec![])
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(_: Vec<u8>) -> Result<(), TryRuntimeError> {
frame_support::ensure!(
Pallet::<T>::is_initialized(),
"Agents and channels were not initialized."
);
Ok(())
}
}
}
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;
tracing::info!(
target: LOG_TARGET,
from=?old_fee_per_gas,
to=?params.fee_per_gas,
"Fee per gas migrated."
);
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);
tracing::info!(
target: LOG_TARGET,
pricing_parameters=?params, ?remote_fee_v1, ?remote_fee_v2,
"Pre fee per gas migration"
);
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."
);
tracing::info!(
target: LOG_TARGET,
pricing_parameters=?params, ?remote_fee_v1, ?remote_fee_v2,
"Post fee per gas migration"
);
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,
>;
@@ -0,0 +1,261 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
use crate as snowbridge_system;
use frame_support::{
derive_impl, parameter_types,
traits::{tokens::fungible::Mutate, ConstU128, ConstU8},
weights::IdentityFee,
PalletId,
};
use sp_core::H256;
use xcm_executor::traits::ConvertLocation;
use snowbridge_core::{
gwei, meth, sibling_sovereign_account, AgentId, AllowSiblingsOnly, ParaId, PricingParameters,
Rewards,
};
use snowbridge_outbound_queue_primitives::v1::ConstantGasMeter;
use sp_runtime::{
traits::{AccountIdConversion, BlakeTwo256, IdentityLookup, Keccak256},
AccountId32, BuildStorage, FixedU128,
};
use xcm::prelude::*;
#[cfg(feature = "runtime-benchmarks")]
use crate::BenchmarkHelper;
type Block = frame_system::mocking::MockBlock<Test>;
type Balance = u128;
pub type AccountId = AccountId32;
// A stripped-down version of pallet-xcm that only inserts an XCM origin into the runtime
#[allow(dead_code)]
#[frame_support::pallet]
mod pallet_xcm_origin {
use frame_support::{
pallet_prelude::*,
traits::{Contains, OriginTrait},
};
use xcm::latest::prelude::*;
#[pallet::pallet]
pub struct Pallet<T>(_);
#[pallet::config]
pub trait Config: frame_system::Config {
type RuntimeOrigin: From<Origin> + From<<Self as frame_system::Config>::RuntimeOrigin>;
}
// Insert this custom Origin into the aggregate RuntimeOrigin
#[pallet::origin]
#[derive(
PartialEq,
Eq,
Clone,
Encode,
Decode,
DecodeWithMemTracking,
RuntimeDebug,
TypeInfo,
MaxEncodedLen,
)]
pub struct Origin(pub Location);
impl From<Location> for Origin {
fn from(location: Location) -> Origin {
Origin(location)
}
}
/// `EnsureOrigin` implementation succeeding with a `Location` value to recognize and
/// filter the contained location
pub struct EnsureXcm<F>(PhantomData<F>);
impl<O: OriginTrait + From<Origin>, F: Contains<Location>> EnsureOrigin<O> for EnsureXcm<F>
where
for<'a> &'a O::PalletsOrigin: TryInto<&'a Origin>,
{
type Success = Location;
fn try_origin(outer: O) -> Result<Self::Success, O> {
match outer.caller().try_into() {
Ok(Origin(ref location)) if F::contains(location) => return Ok(location.clone()),
_ => (),
}
Err(outer)
}
fn try_successful_origin() -> Result<O, ()> {
Ok(O::from(Origin(Location::new(1, [Teyrchain(2000)]))))
}
}
}
// Configure a mock runtime to test the pallet.
frame_support::construct_runtime!(
pub enum Test
{
System: frame_system,
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
XcmOrigin: pallet_xcm_origin::{Pallet, Origin},
OutboundQueue: snowbridge_pallet_outbound_queue::{Pallet, Call, Storage, Event<T>},
EthereumSystem: snowbridge_system,
MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event<T>}
}
);
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
impl frame_system::Config for Test {
type BaseCallFilter = frame_support::traits::Everything;
type RuntimeOrigin = RuntimeOrigin;
type RuntimeCall = RuntimeCall;
type RuntimeTask = RuntimeTask;
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = AccountId;
type Lookup = IdentityLookup<Self::AccountId>;
type RuntimeEvent = RuntimeEvent;
type PalletInfo = PalletInfo;
type AccountData = pallet_balances::AccountData<u128>;
type Nonce = u64;
type Block = Block;
}
#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)]
impl pallet_balances::Config for Test {
type Balance = Balance;
type ExistentialDeposit = ConstU128<1>;
type AccountStore = System;
}
impl pallet_xcm_origin::Config for Test {
type RuntimeOrigin = RuntimeOrigin;
}
parameter_types! {
pub const HeapSize: u32 = 32 * 1024;
pub const MaxStale: u32 = 32;
pub static ServiceWeight: Option<Weight> = Some(Weight::from_parts(100, 100));
}
impl pallet_message_queue::Config for Test {
type RuntimeEvent = RuntimeEvent;
type WeightInfo = ();
type MessageProcessor = OutboundQueue;
type Size = u32;
type QueueChangeHandler = ();
type HeapSize = HeapSize;
type MaxStale = MaxStale;
type ServiceWeight = ServiceWeight;
type IdleMaxServiceWeight = ();
type QueuePausedQuery = ();
}
parameter_types! {
pub const MaxMessagePayloadSize: u32 = 1024;
pub const MaxMessagesPerBlock: u32 = 20;
pub const OwnParaId: ParaId = ParaId::new(1013);
}
impl snowbridge_pallet_outbound_queue::Config for Test {
type RuntimeEvent = RuntimeEvent;
type Hashing = Keccak256;
type MessageQueue = MessageQueue;
type Decimals = ConstU8<10>;
type MaxMessagePayloadSize = MaxMessagePayloadSize;
type MaxMessagesPerBlock = MaxMessagesPerBlock;
type GasMeter = ConstantGasMeter;
type Balance = u128;
type PricingParameters = EthereumSystem;
type Channels = EthereumSystem;
type WeightToFee = IdentityFee<u128>;
type WeightInfo = ();
}
parameter_types! {
pub const SS58Prefix: u8 = 42;
pub const AnyNetwork: Option<NetworkId> = None;
pub const RelayNetwork: Option<NetworkId> = Some(NetworkId::Pezkuwi);
pub const RelayLocation: Location = Location::parent();
pub UniversalLocation: InteriorLocation =
[GlobalConsensus(RelayNetwork::get().unwrap()), Teyrchain(1013)].into();
pub EthereumNetwork: NetworkId = NetworkId::Ethereum { chain_id: 11155111 };
pub EthereumDestination: Location = Location::new(2,[GlobalConsensus(EthereumNetwork::get())]);
}
pub const HEZ: u128 = 10_000_000_000;
parameter_types! {
pub TreasuryAccount: AccountId = PalletId(*b"py/trsry").into_account_truncating();
pub Fee: u64 = 1000;
pub const InitialFunding: u128 = 1_000_000_000_000;
pub BridgeHubParaId: ParaId = ParaId::new(1002);
pub AssetHubParaId: ParaId = ParaId::new(1000);
pub TestParaId: u32 = 2000;
pub Parameters: PricingParameters<u128> = PricingParameters {
exchange_rate: FixedU128::from_rational(1, 400),
fee_per_gas: gwei(20),
rewards: Rewards { local: HEZ, remote: meth(1) },
multiplier: FixedU128::from_rational(4, 3)
};
pub const InboundDeliveryCost: u128 = 1_000_000_000;
}
#[cfg(feature = "runtime-benchmarks")]
impl BenchmarkHelper<RuntimeOrigin> for () {
fn make_xcm_origin(location: Location) -> RuntimeOrigin {
RuntimeOrigin::from(pallet_xcm_origin::Origin(location))
}
}
impl crate::Config for Test {
type RuntimeEvent = RuntimeEvent;
type OutboundQueue = OutboundQueue;
type SiblingOrigin = pallet_xcm_origin::EnsureXcm<AllowSiblingsOnly>;
type AgentIdOf = snowbridge_core::AgentIdOf;
type TreasuryAccount = TreasuryAccount;
type Token = Balances;
type DefaultPricingParameters = Parameters;
type WeightInfo = ();
type InboundDeliveryCost = InboundDeliveryCost;
type UniversalLocation = UniversalLocation;
type EthereumLocation = EthereumDestination;
#[cfg(feature = "runtime-benchmarks")]
type Helper = ();
}
// Build genesis storage according to the mock runtime.
pub fn new_test_ext(genesis_build: bool) -> sp_io::TestExternalities {
let mut storage = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap();
if genesis_build {
crate::GenesisConfig::<Test> {
para_id: OwnParaId::get(),
asset_hub_para_id: AssetHubParaId::get(),
_config: Default::default(),
}
.assimilate_storage(&mut storage)
.unwrap();
}
let mut ext: sp_io::TestExternalities = storage.into();
let initial_amount = InitialFunding::get();
let test_para_id = TestParaId::get();
let sovereign_account = sibling_sovereign_account::<Test>(test_para_id.into());
let treasury_account = TreasuryAccount::get();
ext.execute_with(|| {
System::set_block_number(1);
Balances::mint_into(&AccountId32::from([0; 32]), initial_amount).unwrap();
Balances::mint_into(&sovereign_account, initial_amount).unwrap();
Balances::mint_into(&treasury_account, initial_amount).unwrap();
});
ext
}
// Test helpers
pub fn make_agent_id(location: Location) -> AgentId {
<Test as snowbridge_system::Config>::AgentIdOf::convert_location(&location)
.expect("convert location")
}
@@ -0,0 +1,360 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
use crate::{mock::*, *};
use frame_support::{assert_noop, assert_ok};
use hex_literal::hex;
use snowbridge_core::eth;
use sp_core::H256;
use sp_runtime::{AccountId32, DispatchError::BadOrigin};
#[test]
fn test_agent_for_here() {
new_test_ext(true).execute_with(|| {
let origin_location = Location::here();
let agent_id = make_agent_id(origin_location);
assert_eq!(
agent_id,
hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").into(),
)
});
}
#[test]
fn upgrade_as_root() {
new_test_ext(true).execute_with(|| {
let origin = RuntimeOrigin::root();
let address: H160 = [1_u8; 20].into();
let code_hash: H256 = [1_u8; 32].into();
assert_ok!(EthereumSystem::upgrade(origin, address, code_hash, None));
System::assert_last_event(RuntimeEvent::EthereumSystem(crate::Event::Upgrade {
impl_address: address,
impl_code_hash: code_hash,
initializer_params_hash: None,
}));
});
}
#[test]
fn upgrade_as_signed_fails() {
new_test_ext(true).execute_with(|| {
let origin = RuntimeOrigin::signed(AccountId32::new([0; 32]));
let address: H160 = Default::default();
let code_hash: H256 = Default::default();
assert_noop!(EthereumSystem::upgrade(origin, address, code_hash, None), BadOrigin);
});
}
#[test]
fn upgrade_with_params() {
new_test_ext(true).execute_with(|| {
let origin = RuntimeOrigin::root();
let address: H160 = [1_u8; 20].into();
let code_hash: H256 = [1_u8; 32].into();
let initializer: Option<Initializer> =
Some(Initializer { params: [0; 256].into(), maximum_required_gas: 10000 });
assert_ok!(EthereumSystem::upgrade(origin, address, code_hash, initializer));
});
}
#[test]
fn set_operating_mode() {
new_test_ext(true).execute_with(|| {
let origin = RuntimeOrigin::root();
let mode = OperatingMode::RejectingOutboundMessages;
assert_ok!(EthereumSystem::set_operating_mode(origin, mode));
System::assert_last_event(RuntimeEvent::EthereumSystem(crate::Event::SetOperatingMode {
mode,
}));
});
}
#[test]
fn set_operating_mode_as_signed_fails() {
new_test_ext(true).execute_with(|| {
let origin = RuntimeOrigin::signed([14; 32].into());
let mode = OperatingMode::RejectingOutboundMessages;
assert_noop!(EthereumSystem::set_operating_mode(origin, mode), BadOrigin);
});
}
#[test]
fn set_pricing_parameters() {
new_test_ext(true).execute_with(|| {
let origin = RuntimeOrigin::root();
let mut params = Parameters::get();
params.rewards.local = 7;
assert_ok!(EthereumSystem::set_pricing_parameters(origin, params));
assert_eq!(PricingParameters::<Test>::get().rewards.local, 7);
});
}
#[test]
fn set_pricing_parameters_as_signed_fails() {
new_test_ext(true).execute_with(|| {
let origin = RuntimeOrigin::signed([14; 32].into());
let params = Parameters::get();
assert_noop!(EthereumSystem::set_pricing_parameters(origin, params), BadOrigin);
});
}
#[test]
fn set_pricing_parameters_invalid() {
new_test_ext(true).execute_with(|| {
let origin = RuntimeOrigin::root();
let mut params = Parameters::get();
params.rewards.local = 0;
assert_noop!(
EthereumSystem::set_pricing_parameters(origin.clone(), params),
Error::<Test>::InvalidPricingParameters
);
let mut params = Parameters::get();
params.exchange_rate = 0u128.into();
assert_noop!(
EthereumSystem::set_pricing_parameters(origin.clone(), params),
Error::<Test>::InvalidPricingParameters
);
params = Parameters::get();
params.fee_per_gas = sp_core::U256::zero();
assert_noop!(
EthereumSystem::set_pricing_parameters(origin.clone(), params),
Error::<Test>::InvalidPricingParameters
);
params = Parameters::get();
params.rewards.local = 0;
assert_noop!(
EthereumSystem::set_pricing_parameters(origin.clone(), params),
Error::<Test>::InvalidPricingParameters
);
params = Parameters::get();
params.rewards.remote = sp_core::U256::zero();
assert_noop!(
EthereumSystem::set_pricing_parameters(origin, params),
Error::<Test>::InvalidPricingParameters
);
});
}
#[test]
fn set_token_transfer_fees() {
new_test_ext(true).execute_with(|| {
let origin = RuntimeOrigin::root();
assert_ok!(EthereumSystem::set_token_transfer_fees(origin, 1, 1, eth(1)));
});
}
#[test]
fn set_token_transfer_fees_root_only() {
new_test_ext(true).execute_with(|| {
let origin = RuntimeOrigin::signed([14; 32].into());
assert_noop!(EthereumSystem::set_token_transfer_fees(origin, 1, 1, 1.into()), BadOrigin);
});
}
#[test]
fn set_token_transfer_fees_invalid() {
new_test_ext(true).execute_with(|| {
let origin = RuntimeOrigin::root();
assert_noop!(
EthereumSystem::set_token_transfer_fees(origin, 0, 0, 0.into()),
Error::<Test>::InvalidTokenTransferFees
);
});
}
#[test]
fn genesis_build_initializes_correctly() {
new_test_ext(true).execute_with(|| {
assert!(EthereumSystem::is_initialized(), "Ethereum uninitialized.");
});
}
#[test]
fn no_genesis_build_is_uninitialized() {
new_test_ext(false).execute_with(|| {
assert!(!EthereumSystem::is_initialized(), "Ethereum initialized.");
});
}
#[test]
fn register_token_with_signed_yields_bad_origin() {
new_test_ext(true).execute_with(|| {
let origin = RuntimeOrigin::signed([14; 32].into());
let location = Location::new(1, [Teyrchain(2000)]);
let versioned_location: Box<VersionedLocation> = Box::new(location.clone().into());
assert_noop!(
EthereumSystem::register_token(origin, versioned_location, Default::default()),
BadOrigin
);
});
}
pub struct RegisterTokenTestCase {
/// Input: Location of Pezkuwi-native token relative to BH
pub native: Location,
/// Output: Reanchored, canonicalized location
pub reanchored: Location,
/// Output: Stable hash of reanchored location
pub foreign: TokenId,
}
#[test]
fn register_all_tokens_succeeds() {
let test_cases = vec![
// HEZ
RegisterTokenTestCase {
native: Location::parent(),
reanchored: Location::new(1, GlobalConsensus(Pezkuwi)),
foreign: hex!("4e241583d94b5d48a27a22064cd49b2ed6f5231d2d950e432f9b7c2e0ade52b2")
.into(),
},
// GLMR (Some Pezkuwi teyrchain currency)
RegisterTokenTestCase {
native: Location::new(1, [Teyrchain(2004)]),
reanchored: Location::new(1, [GlobalConsensus(Pezkuwi), Teyrchain(2004)]),
foreign: hex!("34c08fc90409b6924f0e8eabb7c2aaa0c749e23e31adad9f6d217b577737fafb")
.into(),
},
// USDT
RegisterTokenTestCase {
native: Location::new(1, [Teyrchain(1000), PalletInstance(50), GeneralIndex(1984)]),
reanchored: Location::new(
1,
[GlobalConsensus(Pezkuwi), Teyrchain(1000), PalletInstance(50), GeneralIndex(1984)],
),
foreign: hex!("14b0579be12d7d7f9971f1d4b41f0e88384b9b74799b0150d4aa6cd01afb4444")
.into(),
},
// KSM
RegisterTokenTestCase {
native: Location::new(2, [GlobalConsensus(Kusama)]),
reanchored: Location::new(1, [GlobalConsensus(Kusama)]),
foreign: hex!("03b6054d0c576dd8391e34e1609cf398f68050c23009d19ce93c000922bcd852")
.into(),
},
// KAR (Some Kusama teyrchain currency)
RegisterTokenTestCase {
native: Location::new(2, [GlobalConsensus(Kusama), Teyrchain(2000)]),
reanchored: Location::new(1, [GlobalConsensus(Kusama), Teyrchain(2000)]),
foreign: hex!("d3e39ad6ea4cee68c9741181e94098823b2ea34a467577d0875c036f0fce5be0")
.into(),
},
];
for tc in test_cases.iter() {
new_test_ext(true).execute_with(|| {
let origin = RuntimeOrigin::root();
let versioned_location: VersionedLocation = tc.native.clone().into();
assert_ok!(EthereumSystem::register_token(
origin,
Box::new(versioned_location),
Default::default()
));
assert_eq!(ForeignToNativeId::<Test>::get(tc.foreign), Some(tc.reanchored.clone()));
System::assert_last_event(RuntimeEvent::EthereumSystem(Event::<Test>::RegisterToken {
location: tc.reanchored.clone().into(),
foreign_token_id: tc.foreign,
}));
});
}
}
#[test]
fn register_ethereum_native_token_fails() {
new_test_ext(true).execute_with(|| {
let origin = RuntimeOrigin::root();
let location = Location::new(
2,
[
GlobalConsensus(Ethereum { chain_id: 11155111 }),
AccountKey20 {
network: None,
key: hex!("87d1f7fdfEe7f651FaBc8bFCB6E086C278b77A7d"),
},
],
);
let versioned_location: Box<VersionedLocation> = Box::new(location.clone().into());
assert_noop!(
EthereumSystem::register_token(origin, versioned_location, Default::default()),
Error::<Test>::LocationConversionFailed
);
});
}
#[test]
fn check_pna_token_id_compatibility() {
let test_cases = vec![
// HEZ
RegisterTokenTestCase {
native: Location::parent(),
reanchored: Location::new(1, GlobalConsensus(Pezkuwi)),
foreign: hex!("4e241583d94b5d48a27a22064cd49b2ed6f5231d2d950e432f9b7c2e0ade52b2")
.into(),
},
// GLMR (Some Pezkuwi teyrchain currency)
RegisterTokenTestCase {
native: Location::new(1, [Teyrchain(2004)]),
reanchored: Location::new(1, [GlobalConsensus(Pezkuwi), Teyrchain(2004)]),
foreign: hex!("34c08fc90409b6924f0e8eabb7c2aaa0c749e23e31adad9f6d217b577737fafb")
.into(),
},
// USDT
RegisterTokenTestCase {
native: Location::new(1, [Teyrchain(1000), PalletInstance(50), GeneralIndex(1984)]),
reanchored: Location::new(
1,
[GlobalConsensus(Pezkuwi), Teyrchain(1000), PalletInstance(50), GeneralIndex(1984)],
),
foreign: hex!("14b0579be12d7d7f9971f1d4b41f0e88384b9b74799b0150d4aa6cd01afb4444")
.into(),
},
// KSM
RegisterTokenTestCase {
native: Location::new(2, [GlobalConsensus(Kusama)]),
reanchored: Location::new(1, [GlobalConsensus(Kusama)]),
foreign: hex!("03b6054d0c576dd8391e34e1609cf398f68050c23009d19ce93c000922bcd852")
.into(),
},
// KAR (Some Kusama teyrchain currency)
RegisterTokenTestCase {
native: Location::new(2, [GlobalConsensus(Kusama), Teyrchain(2000)]),
reanchored: Location::new(1, [GlobalConsensus(Kusama), Teyrchain(2000)]),
foreign: hex!("d3e39ad6ea4cee68c9741181e94098823b2ea34a467577d0875c036f0fce5be0")
.into(),
},
];
for tc in test_cases.iter() {
new_test_ext(true).execute_with(|| {
let origin = RuntimeOrigin::root();
let versioned_location: VersionedLocation = tc.native.clone().into();
assert_ok!(EthereumSystem::register_token(
origin,
Box::new(versioned_location),
Default::default()
));
assert_eq!(ForeignToNativeId::<Test>::get(tc.foreign), Some(tc.reanchored.clone()));
System::assert_last_event(RuntimeEvent::EthereumSystem(Event::<Test>::RegisterToken {
location: tc.reanchored.clone().into(),
foreign_token_id: tc.foreign,
}));
});
}
}
@@ -0,0 +1,131 @@
//! Autogenerated weights for `snowbridge_system`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-10-09, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `crake.local`, CPU: `<UNKNOWN>`
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-pezkuwichain-dev")`, DB CACHE: `1024`
// Executed Command:
// target/release/pezkuwi-teyrchain
// benchmark
// pallet
// --chain
// bridge-hub-pezkuwichain-dev
// --pallet=snowbridge_system
// --extrinsic=*
// --execution=wasm
// --wasm-execution=compiled
// --template
// ../teyrchain/templates/module-weight-template.hbs
// --output
// ../teyrchain/pallets/control/src/weights.rs
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
#![allow(missing_docs)]
use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
use core::marker::PhantomData;
/// Weight functions needed for `snowbridge_system`.
pub trait WeightInfo {
fn upgrade() -> Weight;
fn set_operating_mode() -> Weight;
fn set_token_transfer_fees() -> Weight;
fn set_pricing_parameters() -> Weight;
fn register_token() -> Weight;
}
// For backwards compatibility and tests.
impl WeightInfo for () {
/// Storage: TeyrchainInfo TeyrchainId (r:1 w:0)
/// Proof: TeyrchainInfo TeyrchainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
/// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0)
/// Proof: EthereumOutboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen)
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue ServiceHead (r:1 w:1)
/// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen)
/// Storage: MessageQueue Pages (r:0 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn upgrade() -> Weight {
// Proof Size summary in bytes:
// Measured: `80`
// Estimated: `3517`
// Minimum execution time: 44_000_000 picoseconds.
Weight::from_parts(44_000_000, 3517)
.saturating_add(RocksDbWeight::get().reads(4_u64))
.saturating_add(RocksDbWeight::get().writes(3_u64))
}
/// Storage: TeyrchainInfo TeyrchainId (r:1 w:0)
/// Proof: TeyrchainInfo TeyrchainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
/// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0)
/// Proof: EthereumOutboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen)
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue ServiceHead (r:1 w:1)
/// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen)
/// Storage: MessageQueue Pages (r:0 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn set_operating_mode() -> Weight {
// Proof Size summary in bytes:
// Measured: `80`
// Estimated: `3517`
// Minimum execution time: 31_000_000 picoseconds.
Weight::from_parts(31_000_000, 3517)
.saturating_add(RocksDbWeight::get().reads(4_u64))
.saturating_add(RocksDbWeight::get().writes(3_u64))
}
/// Storage: TeyrchainInfo TeyrchainId (r:1 w:0)
/// Proof: TeyrchainInfo TeyrchainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
/// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0)
/// Proof: EthereumOutboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen)
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue ServiceHead (r:1 w:1)
/// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen)
/// Storage: MessageQueue Pages (r:0 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn set_token_transfer_fees() -> Weight {
// Proof Size summary in bytes:
// Measured: `80`
// Estimated: `3517`
// Minimum execution time: 31_000_000 picoseconds.
Weight::from_parts(42_000_000, 3517)
.saturating_add(RocksDbWeight::get().reads(4_u64))
.saturating_add(RocksDbWeight::get().writes(3_u64))
}
/// Storage: TeyrchainInfo TeyrchainId (r:1 w:0)
/// Proof: TeyrchainInfo TeyrchainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
/// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0)
/// Proof: EthereumOutboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen)
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue ServiceHead (r:1 w:1)
/// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen)
/// Storage: MessageQueue Pages (r:0 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn set_pricing_parameters() -> Weight {
// Proof Size summary in bytes:
// Measured: `80`
// Estimated: `3517`
// Minimum execution time: 31_000_000 picoseconds.
Weight::from_parts(42_000_000, 3517)
.saturating_add(RocksDbWeight::get().reads(4_u64))
.saturating_add(RocksDbWeight::get().writes(3_u64))
}
fn register_token() -> Weight {
// Proof Size summary in bytes:
// Measured: `256`
// Estimated: `6044`
// Minimum execution time: 45_000_000 picoseconds.
Weight::from_parts(45_000_000, 6044)
.saturating_add(RocksDbWeight::get().reads(5_u64))
.saturating_add(RocksDbWeight::get().writes(3_u64))
}
}