diff --git a/Cargo.lock b/Cargo.lock index ec2f24e71..57df5b06b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12992,10 +12992,13 @@ dependencies = [ "alloy-sol-macro", "alloy-sol-types", "anyhow", + "frame-benchmarking", "frame-support 37.0.0", "frame-system", "ismp", "log", + "pallet-assets", + "pallet-balances", "pallet-hyperbridge", "pallet-ismp", "parity-scale-codec", diff --git a/modules/ismp/pallets/token-gateway/Cargo.toml b/modules/ismp/pallets/token-gateway/Cargo.toml index 3b50b0a6e..4353e6fe7 100644 --- a/modules/ismp/pallets/token-gateway/Cargo.toml +++ b/modules/ismp/pallets/token-gateway/Cargo.toml @@ -14,6 +14,7 @@ readme = "./README.md" [dependencies] frame-support = { workspace = true } frame-system = { workspace = true } +frame-benchmarking = { workspace = true} sp-runtime = { workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } @@ -34,11 +35,16 @@ alloy-sol-types = { workspace = true } token-gateway-primitives = { workspace = true } pallet-hyperbridge = { workspace = true } +[dev-dependencies] +pallet-balances = { workspace = true } +pallet-assets = { workspace = true} + [features] default = ["std"] std = [ "frame-support/std", "frame-system/std", + "frame-benchmarking/std", "sp-runtime/std", "sp-core/std", "sp-io/std", @@ -50,6 +56,14 @@ std = [ "anyhow/std", "alloy-primitives/std", "pallet-hyperbridge/std", - "token-gateway-primitives/std" + "token-gateway-primitives/std", + "pallet-balances/std", + "pallet-assets/std" +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", ] -try-runtime = [] +try-runtime = [] \ No newline at end of file diff --git a/modules/ismp/pallets/token-gateway/src/benchmarking.rs b/modules/ismp/pallets/token-gateway/src/benchmarking.rs new file mode 100644 index 000000000..f0aaf11a2 --- /dev/null +++ b/modules/ismp/pallets/token-gateway/src/benchmarking.rs @@ -0,0 +1,191 @@ +#![cfg(feature = "runtime-benchmarks")] + +use crate::*; +use frame_benchmarking::v2::*; +use frame_support::BoundedVec; +use frame_system::RawOrigin; +use ismp::host::StateMachine; +use pallet_balances::AdjustmentDirection; +use scale_info::prelude::collections::BTreeMap; +use sp_runtime::{traits::StaticLookup, AccountId32}; +use token_gateway_primitives::{GatewayAssetRegistration, GatewayAssetUpdate}; + +fn dummy_teleport_asset( +) -> TeleportParams, <::NativeCurrency as Currency>::Balance> + where + T: Config, + <::Assets as fungibles::Inspect>::AssetId: From, + <::NativeCurrency as Currency>::Balance: From, +{ + TeleportParams { + asset_id: <::Assets as fungibles::Inspect>::AssetId::from( + H256::zero(), + ), + destination: StateMachine::Evm(100), + recepient: H256::from([1u8; 32]), + amount: 1100000000u128.into(), + timeout: 10, + token_gateway: vec![1, 2, 3, 4, 5], + relayer_fee: 1000000002u128.into(), + } +} + +fn create_dummy_asset( + asset_details: GatewayAssetRegistration, +) -> AssetRegistration> + where + <::Assets as fungibles::Inspect>::AssetId: From, +{ + AssetRegistration { local_id: H256::zero().into(), reg: asset_details } +} + +#[benchmarks( + where + T: pallet_balances::Config, + T: pallet_assets::Config, + <::Assets as fungibles::Inspect>::AssetId: From, + <::NativeCurrency as Currency>::Balance: From, + ::AccountId: From<[u8; 32]>, + u128: From<<::NativeCurrency as Currency>::Balance>, + ::Balance: From<<::NativeCurrency as Currency>::Balance>, + <::Assets as fungibles::Inspect>::Balance: From<<::NativeCurrency as Currency>::Balance>, + <::Assets as fungibles::Inspect>::Balance: From, + [u8; 32]: From<::AccountId>, + ::RuntimeOrigin: From>, +)] +mod benches { + use super::*; + + #[benchmark] + fn create_erc6160_asset() -> Result<(), BenchmarkError> { + let account: T::AccountId = whitelisted_caller(); + + let asset_details = GatewayAssetRegistration { + name: BoundedVec::try_from(b"Spectre".to_vec()).unwrap(), + symbol: BoundedVec::try_from(b"SPC".to_vec()).unwrap(), + chains: vec![StateMachine::Evm(100)], + minimum_balance: Some(10), + }; + let asset = create_dummy_asset::(asset_details); + + // Set balances + let ed = ::ExistentialDeposit::get(); + + // Adjust total issuance + pallet_balances::Pallet::::force_adjust_total_issuance( + RawOrigin::Root.into(), + AdjustmentDirection::Increase, + ed * 1000, + )?; + + let acc = <::Lookup as StaticLookup>::unlookup(account.clone()); + + pallet_balances::Pallet::::force_set_balance(RawOrigin::Root.into(), acc, ed * 100u128)?; + + #[extrinsic_call] + _(RawOrigin::Signed(account), asset); + + Ok(()) + } + + #[benchmark] + fn teleport() -> Result<(), BenchmarkError> { + let account: T::AccountId = whitelisted_caller(); + + let asset_details = GatewayAssetRegistration { + name: BoundedVec::try_from(b"Spectre".to_vec()).unwrap(), + symbol: BoundedVec::try_from(b"SPC".to_vec()).unwrap(), + chains: vec![StateMachine::Evm(100)], + minimum_balance: None, + }; + let asset = create_dummy_asset::(asset_details); + + Pallet::::create_erc6160_asset(RawOrigin::Signed(account.clone()).into(), asset)?; + + let dummy_teleport_params = dummy_teleport_asset::(); + + // Set balances + let ed = ::ExistentialDeposit::get(); + + // Adjust total issuance + pallet_balances::Pallet::::force_adjust_total_issuance( + RawOrigin::Root.into(), + AdjustmentDirection::Increase, + ed * 1000, + )?; + + let acc = <::Lookup as StaticLookup>::unlookup(account.clone()); + + pallet_balances::Pallet::::force_set_balance( + RawOrigin::Root.into(), + acc.clone(), + ed * 100u128, + )?; + + #[extrinsic_call] + teleport(RawOrigin::Signed(account), dummy_teleport_params); + Ok(()) + } + + #[benchmark] + fn set_token_gateway_addresses(x: Linear<5, 100>) -> Result<(), BenchmarkError> { + let mut addresses = BTreeMap::new(); + for i in 0..x { + let addr = i.to_string().as_bytes().to_vec(); + addresses.insert(StateMachine::Evm(100), addr); + } + + #[extrinsic_call] + _(RawOrigin::Root, addresses); + Ok(()) + } + + #[benchmark] + fn update_erc6160_asset() -> Result<(), BenchmarkError> { + let acc_origin: T::AccountId = whitelisted_caller(); + + let asset_details = GatewayAssetRegistration { + name: BoundedVec::try_from(b"Spectre".to_vec()).unwrap(), + symbol: BoundedVec::try_from(b"SPC".to_vec()).unwrap(), + chains: vec![StateMachine::Evm(100)], + minimum_balance: None, + }; + let asset = create_dummy_asset::(asset_details); + let asset_id: H256 = sp_io::hashing::keccak_256(asset.reg.symbol.as_ref()).into(); + + // set balances + + let acc_o = + <::Lookup as StaticLookup>::unlookup(acc_origin.clone()); + let ed = ::ExistentialDeposit::get(); + pallet_balances::Pallet::::force_set_balance( + RawOrigin::Root.into(), + acc_o.clone(), + ed * 100u128, + )?; + + // set asset balance + pallet_assets::Pallet::::create( + RawOrigin::Signed(acc_origin.clone()).into(), + H256::zero().into(), + acc_o.clone(), + 1000000000, + )?; + + Pallet::::create_erc6160_asset( + RawOrigin::Signed(acc_origin.clone()).into(), + asset.clone(), + )?; + + let asset_update = GatewayAssetUpdate { + asset_id, + add_chains: BoundedVec::try_from(vec![StateMachine::Evm(200)]).unwrap(), + remove_chains: BoundedVec::try_from(Vec::new()).unwrap(), + new_admins: BoundedVec::try_from(Vec::new()).unwrap(), + }; + + #[extrinsic_call] + _(RawOrigin::Signed(acc_origin), asset_update); + Ok(()) + } +} diff --git a/modules/ismp/pallets/token-gateway/src/lib.rs b/modules/ismp/pallets/token-gateway/src/lib.rs index 0bba2de4d..a1f1ccab3 100644 --- a/modules/ismp/pallets/token-gateway/src/lib.rs +++ b/modules/ismp/pallets/token-gateway/src/lib.rs @@ -20,19 +20,22 @@ extern crate alloc; pub mod impls; pub mod types; + +mod benchmarking; +mod weights; use crate::impls::{convert_to_balance, convert_to_erc20}; use alloy_sol_types::SolValue; use anyhow::anyhow; use codec::Decode; use frame_support::{ ensure, - pallet_prelude::Weight, traits::{ fungibles::{self, Mutate}, tokens::{fungible::Mutate as FungibleMutate, Preservation}, Currency, ExistenceRequirement, }, }; +pub use weights::WeightInfo; use ismp::{ events::Meta, @@ -82,7 +85,7 @@ pub mod pallet { /// The pallet's configuration trait. #[pallet::config] pub trait Config: - frame_system::Config + pallet_ismp::Config + pallet_hyperbridge::Config + frame_system::Config + pallet_ismp::Config + pallet_hyperbridge::Config { /// The overarching runtime event type. type RuntimeEvent: From> + IsType<::RuntimeEvent>; @@ -99,10 +102,10 @@ pub mod pallet { /// Fungible asset implementation type Assets: fungibles::Mutate - + fungibles::Inspect - + fungibles::Create - + fungibles::metadata::Mutate - + fungibles::roles::Inspect; + + fungibles::Inspect + + fungibles::Create + + fungibles::metadata::Mutate + + fungibles::roles::Inspect; /// The native asset ID type NativeAssetId: Get>; @@ -113,13 +116,16 @@ pub mod pallet { /// The decimals of the native currency #[pallet::constant] type Decimals: Get; + + /// weights + type WeightInfo: WeightInfo; } /// Assets supported by this instance of token gateway /// A map of the local asset id to the token gateway asset id #[pallet::storage] pub type SupportedAssets = - StorageMap<_, Blake2_128Concat, AssetId, H256, OptionQuery>; + StorageMap<_, Blake2_128Concat, AssetId, H256, OptionQuery>; /// Assets supported by this instance of token gateway /// A map of the token gateway asset id to the local asset id @@ -133,7 +139,7 @@ pub mod pallet { /// The token gateway adresses on different chains #[pallet::storage] pub type TokenGatewayAddresses = - StorageMap<_, Blake2_128Concat, StateMachine, Vec, OptionQuery>; + StorageMap<_, Blake2_128Concat, StateMachine, Vec, OptionQuery>; /// Pallet events that functions in this pallet can emit. #[pallet::event] @@ -205,20 +211,20 @@ pub mod pallet { #[pallet::call] impl Pallet - where - ::AccountId: From<[u8; 32]>, - u128: From<<::NativeCurrency as Currency>::Balance>, - ::Balance: + where + ::AccountId: From<[u8; 32]>, + u128: From<<::NativeCurrency as Currency>::Balance>, + ::Balance: From<<::NativeCurrency as Currency>::Balance>, - <::Assets as fungibles::Inspect>::Balance: + <::Assets as fungibles::Inspect>::Balance: From<<::NativeCurrency as Currency>::Balance>, - <::Assets as fungibles::Inspect>::Balance: From, - [u8; 32]: From<::AccountId>, + <::Assets as fungibles::Inspect>::Balance: From, + [u8; 32]: From<::AccountId>, { /// Teleports a registered asset /// locks the asset and dispatches a request to token gateway on the destination #[pallet::call_index(0)] - #[pallet::weight(weight())] + #[pallet::weight(T::WeightInfo::teleport())] pub fn teleport( origin: OriginFor, params: TeleportParams< @@ -301,7 +307,7 @@ pub mod pallet { /// Set the token gateway address for specified chains #[pallet::call_index(1)] - #[pallet::weight(weight())] + #[pallet::weight(T::WeightInfo::set_token_gateway_addresses(addresses.len() as u32))] pub fn set_token_gateway_addresses( origin: OriginFor, addresses: BTreeMap>, @@ -318,7 +324,7 @@ pub mod pallet { /// This works by dispatching a request to the TokenGateway module on each requested chain /// to create the asset. #[pallet::call_index(2)] - #[pallet::weight(weight())] + #[pallet::weight(T::WeightInfo::create_erc6160_asset())] pub fn create_erc6160_asset( origin: OriginFor, asset: AssetRegistration>, @@ -371,7 +377,7 @@ pub mod pallet { /// This works by dispatching a request to the TokenGateway module on each requested chain /// to create the asset. #[pallet::call_index(3)] - #[pallet::weight(weight())] + #[pallet::weight(T::WeightInfo::update_erc6160_asset())] pub fn update_erc6160_asset( origin: OriginFor, asset: GatewayAssetUpdate, @@ -425,10 +431,10 @@ pub mod pallet { } impl IsmpModule for Pallet -where - ::AccountId: From<[u8; 32]>, - <::NativeCurrency as Currency>::Balance: From, - <::Assets as fungibles::Inspect>::Balance: From, + where + ::AccountId: From<[u8; 32]>, + <::NativeCurrency as Currency>::Balance: From, + <::Assets as fungibles::Inspect>::Balance: From, { fn on_accept( &self, @@ -451,7 +457,7 @@ where local_asset_id.clone(), ), ) - .map_err(|e| anyhow!("{e:?}"))?; + .map_err(|e| anyhow!("{e:?}"))?; // Note the asset's ERC counterpart decimal Decimals::::insert(local_asset_id, metadata.decimals); } else { @@ -464,7 +470,7 @@ where true, min_balance.into(), ) - .map_err(|e| anyhow!("{e:?}"))?; + .map_err(|e| anyhow!("{e:?}"))?; >::set( local_asset_id.clone(), &T::AssetAdmin::get(), @@ -472,7 +478,7 @@ where metadata.symbol.to_vec(), 18, ) - .map_err(|e| anyhow!("{e:?}"))?; + .map_err(|e| anyhow!("{e:?}"))?; SupportedAssets::::insert(local_asset_id.clone(), asset_id.clone()); LocalAssets::::insert(asset_id, local_asset_id.clone()); // Note the asset's ERC counterpart decimal @@ -529,10 +535,10 @@ where erc_decimals, decimals, ) - .map_err(|_| ismp::error::Error::ModuleDispatchError { - msg: "Token Gateway: Trying to withdraw Invalid amount".to_string(), - meta: Meta { source, dest, nonce }, - })?; + .map_err(|_| ismp::error::Error::ModuleDispatchError { + msg: "Token Gateway: Trying to withdraw Invalid amount".to_string(), + meta: Meta { source, dest, nonce }, + })?; let beneficiary: T::AccountId = body.to.0.into(); if local_asset_id == T::NativeAssetId::get() { ::NativeCurrency::transfer( @@ -541,10 +547,10 @@ where amount.into(), ExistenceRequirement::AllowDeath, ) - .map_err(|_| ismp::error::Error::ModuleDispatchError { - msg: "Token Gateway: Failed to complete asset transfer".to_string(), - meta: Meta { source, dest, nonce }, - })?; + .map_err(|_| ismp::error::Error::ModuleDispatchError { + msg: "Token Gateway: Failed to complete asset transfer".to_string(), + meta: Meta { source, dest, nonce }, + })?; } else { ::Assets::transfer( local_asset_id, @@ -553,10 +559,10 @@ where amount.into(), Preservation::Protect, ) - .map_err(|_| ismp::error::Error::ModuleDispatchError { - msg: "Token Gateway: Failed to complete asset transfer".to_string(), - meta: Meta { source, dest, nonce }, - })?; + .map_err(|_| ismp::error::Error::ModuleDispatchError { + msg: "Token Gateway: Failed to complete asset transfer".to_string(), + meta: Meta { source, dest, nonce }, + })?; } Self::deposit_event(Event::::AssetReceived { @@ -600,10 +606,10 @@ where erc_decimals, decimals, ) - .map_err(|_| ismp::error::Error::ModuleDispatchError { - msg: "Token Gateway: Trying to withdraw Invalid amount".to_string(), - meta: Meta { source, dest, nonce }, - })?; + .map_err(|_| ismp::error::Error::ModuleDispatchError { + msg: "Token Gateway: Trying to withdraw Invalid amount".to_string(), + meta: Meta { source, dest, nonce }, + })?; if local_asset_id == T::NativeAssetId::get() { ::NativeCurrency::transfer( @@ -612,10 +618,10 @@ where amount.into(), ExistenceRequirement::AllowDeath, ) - .map_err(|_| ismp::error::Error::ModuleDispatchError { - msg: "Token Gateway: Failed to complete asset transfer".to_string(), - meta: Meta { source, dest, nonce }, - })?; + .map_err(|_| ismp::error::Error::ModuleDispatchError { + msg: "Token Gateway: Failed to complete asset transfer".to_string(), + meta: Meta { source, dest, nonce }, + })?; } else { ::Assets::transfer( local_asset_id, @@ -624,10 +630,10 @@ where amount.into(), Preservation::Protect, ) - .map_err(|_| ismp::error::Error::ModuleDispatchError { - msg: "Token Gateway: Failed to complete asset transfer".to_string(), - meta: Meta { source, dest, nonce }, - })?; + .map_err(|_| ismp::error::Error::ModuleDispatchError { + msg: "Token Gateway: Failed to complete asset transfer".to_string(), + meta: Meta { source, dest, nonce }, + })?; } Pallet::::deposit_event(Event::::AssetRefunded { @@ -654,11 +660,6 @@ where } } -/// Static weights because benchmarks suck, and we'll be getting PolkaVM soon anyways -fn weight() -> Weight { - Weight::from_parts(300_000_000, 0) -} - impl Pallet { /// Ensure the signer is the asset admin pub fn ensure_admin(who: T::AccountId, asset_id: AssetId) -> Result<(), Error> { diff --git a/modules/ismp/pallets/token-gateway/src/weights.rs b/modules/ismp/pallets/token-gateway/src/weights.rs new file mode 100644 index 000000000..233716f85 --- /dev/null +++ b/modules/ismp/pallets/token-gateway/src/weights.rs @@ -0,0 +1,28 @@ +use frame_support::weights::Weight; + +// ============================== INTERFACE ============================================ // +/// Weight functions needed for `pallet_token_gateway. +pub trait WeightInfo { + fn create_erc6160_asset() -> Weight; + fn teleport() -> Weight; + fn set_token_gateway_addresses(x: u32) -> Weight; + fn update_erc6160_asset() -> Weight; +} + +impl WeightInfo for () { + fn create_erc6160_asset() -> Weight { + Weight::zero() + } + + fn teleport() -> Weight { + Weight::zero() + } + + fn set_token_gateway_addresses(_x: u32) -> Weight { + Weight::zero() + } + + fn update_erc6160_asset() -> Weight { + Weight::zero() + } +}