From 37f3d91fd85aa0dceac0065d731d1b0857208132 Mon Sep 17 00:00:00 2001 From: freakstatic Date: Mon, 22 Apr 2024 02:04:13 +0100 Subject: [PATCH 01/16] WIP: argo bridge --- Cargo.lock | 27 ++ bin/node/src/chain_spec/argo_bridge_config.rs | 21 + bin/node/src/chain_spec/mod.rs | 15 +- bin/utils/chain-spec-builder/src/main.rs | 12 +- runtime-modules/argo-bridge/Cargo.toml | 56 +++ .../argo-bridge/src/benchmarking.rs | 100 +++++ runtime-modules/argo-bridge/src/errors.rs | 35 ++ runtime-modules/argo-bridge/src/events.rs | 26 ++ runtime-modules/argo-bridge/src/lib.rs | 221 +++++++++++ runtime-modules/argo-bridge/src/tests/mock.rs | 199 ++++++++++ runtime-modules/argo-bridge/src/tests/mod.rs | 370 ++++++++++++++++++ runtime-modules/argo-bridge/src/types.rs | 61 +++ runtime-modules/argo-bridge/src/weights.rs | 69 ++++ runtime-modules/proposals/codex/Cargo.toml | 2 + .../proposals/codex/src/benchmarking.rs | 32 ++ runtime-modules/proposals/codex/src/lib.rs | 19 + .../proposals/codex/src/tests/mock.rs | 1 + runtime-modules/proposals/codex/src/types.rs | 7 + .../proposals/codex/src/weights.rs | 20 + runtime/Cargo.toml | 4 + .../integration/proposals/proposal_encoder.rs | 3 + runtime/src/lib.rs | 16 + .../src/proposals_configuration/defaults.rs | 14 + runtime/src/proposals_configuration/mod.rs | 3 + .../src/proposals_configuration/playground.rs | 14 + .../src/proposals_configuration/staging.rs | 14 + .../src/proposals_configuration/testing.rs | 14 + 27 files changed, 1368 insertions(+), 7 deletions(-) create mode 100644 bin/node/src/chain_spec/argo_bridge_config.rs create mode 100644 runtime-modules/argo-bridge/Cargo.toml create mode 100644 runtime-modules/argo-bridge/src/benchmarking.rs create mode 100644 runtime-modules/argo-bridge/src/errors.rs create mode 100644 runtime-modules/argo-bridge/src/events.rs create mode 100644 runtime-modules/argo-bridge/src/lib.rs create mode 100644 runtime-modules/argo-bridge/src/tests/mock.rs create mode 100644 runtime-modules/argo-bridge/src/tests/mod.rs create mode 100644 runtime-modules/argo-bridge/src/types.rs create mode 100644 runtime-modules/argo-bridge/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index 70a2ae9597..1ebd18333f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3463,6 +3463,7 @@ dependencies = [ "lazy_static", "lite-json", "log", + "pallet-argo-bridge", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", @@ -5048,6 +5049,31 @@ dependencies = [ "libm 0.1.4", ] +[[package]] +name = "pallet-argo-bridge" +version = "1.0.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "pallet-balances", + "pallet-common", + "pallet-insecure-randomness-collective-flip", + "pallet-membership", + "pallet-staking-handler", + "pallet-storage", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "serde", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-storage", +] + [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" @@ -5570,6 +5596,7 @@ dependencies = [ "frame-election-provider-support", "frame-support", "frame-system", + "pallet-argo-bridge", "pallet-bags-list", "pallet-balances", "pallet-common", diff --git a/bin/node/src/chain_spec/argo_bridge_config.rs b/bin/node/src/chain_spec/argo_bridge_config.rs new file mode 100644 index 0000000000..13ec4d4ab6 --- /dev/null +++ b/bin/node/src/chain_spec/argo_bridge_config.rs @@ -0,0 +1,21 @@ +use node_runtime::{argo_bridge::types::BridgeStatus, ArgoBridgeConfig}; + +pub fn production_config() -> ArgoBridgeConfig { + ArgoBridgeConfig { + status: BridgeStatus::Paused, + mint_allowance: 0, + bridging_fee: 0, + thawn_duration: 1, + ..Default::default() + } +} + +pub fn testing_config() -> ArgoBridgeConfig { + ArgoBridgeConfig { + status: BridgeStatus::Paused, + mint_allowance: 0, + bridging_fee: 0, + thawn_duration: 1, + ..Default::default() + } +} diff --git a/bin/node/src/chain_spec/mod.rs b/bin/node/src/chain_spec/mod.rs index 26ec138914..96c900703b 100644 --- a/bin/node/src/chain_spec/mod.rs +++ b/bin/node/src/chain_spec/mod.rs @@ -19,6 +19,7 @@ // Example: voting_period: 1 * DAY #![allow(clippy::identity_op)] +pub mod argo_bridge_config; pub mod content_config; pub mod council_config; pub mod forum_config; @@ -30,10 +31,10 @@ pub use grandpa_primitives::AuthorityId as GrandpaId; use node_runtime::{ constants::currency::{DOLLARS, MIN_NOMINATOR_BOND, MIN_VALIDATOR_BOND}, - wasm_binary_unwrap, AuthorityDiscoveryConfig, BabeConfig, BalancesConfig, Block, ContentConfig, - ExistentialDeposit, GrandpaConfig, ImOnlineConfig, MaxNominations, ProjectTokenConfig, - SessionConfig, SessionKeys, StakerStatus, StakingConfig, StorageConfig, SystemConfig, - TransactionPaymentConfig, VestingConfig, + wasm_binary_unwrap, ArgoBridgeConfig, AuthorityDiscoveryConfig, BabeConfig, BalancesConfig, + Block, ContentConfig, ExistentialDeposit, GrandpaConfig, ImOnlineConfig, MaxNominations, + ProjectTokenConfig, SessionConfig, SessionKeys, StakerStatus, StakingConfig, StorageConfig, + SystemConfig, TransactionPaymentConfig, VestingConfig, }; pub use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use sc_chain_spec::ChainSpecExtension; @@ -183,6 +184,7 @@ pub fn testnet_genesis( content_cfg: ContentConfig, storage_cfg: StorageConfig, project_token_cfg: ProjectTokenConfig, + argo_bridge_cfg: ArgoBridgeConfig, ) -> GenesisConfig { // staking benchmakrs is not sensitive to actual value of min bonds so // accounts are not funded with sufficient funds and fail with InsufficientBond err @@ -335,6 +337,7 @@ pub fn testnet_genesis( content: content_cfg, storage: storage_cfg, project_token: project_token_cfg, + argo_bridge: argo_bridge_cfg, proposals_discussion: Default::default(), members: Default::default(), } @@ -354,6 +357,7 @@ fn development_config_genesis() -> GenesisConfig { content_config::testing_config(), storage_config::testing_config(), project_token_config::testing_config(), + argo_bridge_config::testing_config(), ) } @@ -387,6 +391,7 @@ fn local_testnet_genesis() -> GenesisConfig { content_config::testing_config(), storage_config::testing_config(), project_token_config::testing_config(), + argo_bridge_config::testing_config(), ) } @@ -417,6 +422,7 @@ fn prod_test_config_genesis() -> GenesisConfig { content_config::production_config(), storage_config::production_config(), project_token_config::production_config(), + argo_bridge_config::production_config(), ) } @@ -454,6 +460,7 @@ pub(crate) mod tests { content_config::testing_config(), storage_config::testing_config(), project_token_config::testing_config(), + argo_bridge_config::testing_config(), ) } diff --git a/bin/utils/chain-spec-builder/src/main.rs b/bin/utils/chain-spec-builder/src/main.rs index c2bf429ce0..e2356d29c8 100644 --- a/bin/utils/chain-spec-builder/src/main.rs +++ b/bin/utils/chain-spec-builder/src/main.rs @@ -24,9 +24,9 @@ use std::{ }; use joystream_node::chain_spec::{ - self, content_config, initial_balances, joy_chain_spec_properties, project_token_config, - storage_config, AccountId, AuthorityDiscoveryId, BabeId, GrandpaId, ImOnlineId, - JOY_ADDRESS_PREFIX, + self, argo_bridge_config, content_config, initial_balances, joy_chain_spec_properties, + project_token_config, storage_config, AccountId, AuthorityDiscoveryId, BabeId, GrandpaId, + ImOnlineId, JOY_ADDRESS_PREFIX, }; use sc_chain_spec::ChainType; @@ -267,6 +267,11 @@ fn genesis_constructor( _ => project_token_config::testing_config(), }; + let argo_bridge_cfg = match deployment { + ChainDeployment::mainnet => argo_bridge_config::production_config(), + _ => argo_bridge_config::testing_config(), + }; + chain_spec::testnet_genesis( fund_accounts, authorities, @@ -277,6 +282,7 @@ fn genesis_constructor( content_cfg, storage_cfg, project_token_cfg, + argo_bridge_cfg, ) } diff --git a/runtime-modules/argo-bridge/Cargo.toml b/runtime-modules/argo-bridge/Cargo.toml new file mode 100644 index 0000000000..ed5141e95e --- /dev/null +++ b/runtime-modules/argo-bridge/Cargo.toml @@ -0,0 +1,56 @@ +[package] +name = "pallet-argo-bridge" +version = '1.0.0' +authors = ['Joystream contributors'] +edition = '2018' + +[dependencies] +sp-io = { package = 'sp-io', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9'} +sp-std = { package = 'sp-std', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9'} +sp-runtime = { package = 'sp-runtime', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9'} +frame-support = { package = 'frame-support', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9'} +frame-system = { package = 'frame-system', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9'} +sp-arithmetic = { package = 'sp-arithmetic', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9'} +common = { package = 'pallet-common', default-features = false, path = '../common'} +storage = { package = 'pallet-storage', default-features = false, path = '../storage'} +balances = { package = 'pallet-balances', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9'} +membership = { package = 'pallet-membership', default-features = false, path = '../membership'} +codec = { package = 'parity-scale-codec', version = '3.1.2', default-features = false, features = ['derive'] } +serde = {version = '1.0.101', features = ['derive'], optional = true} +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +sp-core = { package = 'sp-core', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9', optional = true } + +# Benchmarking dependencies +frame-benchmarking = { package = 'frame-benchmarking', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9', optional = true} + +[dev-dependencies] +sp-core = { package = 'sp-core', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9' } +randomness-collective-flip = { package = 'pallet-insecure-randomness-collective-flip', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9'} +staking-handler = { package = 'pallet-staking-handler', default-features = false, path = '../staking-handler'} +pallet-timestamp = { package = 'pallet-timestamp', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9'} +sp-storage = { package = 'sp-storage', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9'} + +[features] +default = ['std', 'runtime-benchmarks'] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + 'sp-core', + "common/runtime-benchmarks", +] +std = [ + 'sp-std/std', + 'sp-io/std', + 'sp-runtime/std', + 'frame-support/std', + 'frame-system/std', + 'sp-arithmetic/std', + 'common/std', + 'storage/std', + 'balances/std', + 'membership/std', + 'codec/std', + 'serde', + 'scale-info/std', + 'frame-benchmarking?/std', +] +try-runtime = ["frame-support/try-runtime"] diff --git a/runtime-modules/argo-bridge/src/benchmarking.rs b/runtime-modules/argo-bridge/src/benchmarking.rs new file mode 100644 index 0000000000..2a27e23dc3 --- /dev/null +++ b/runtime-modules/argo-bridge/src/benchmarking.rs @@ -0,0 +1,100 @@ +#![cfg(feature = "runtime-benchmarks")] + +use frame_support::{assert_err, assert_ok}; + +use super::*; +use crate::types::*; +use crate::Module as ArgoBridge; +use balances::Pallet as Balances; +use core::convert::TryFrom; +use frame_benchmarking::v1::{account, benchmarks}; +use frame_system::Pallet as System; +use frame_system::{EventRecord, RawOrigin}; +use sp_runtime::traits::One; +use sp_std::convert::TryInto; +use sp_std::vec; + +use crate::{BridgeConstraints, BridgeStatus, RemoteAccount, RemoteTransfer}; + +const SEED: u32 = 0; + +// We create this trait because we need to be compatible with the runtime +// in the mock for tests. In that case we need to be able to have `membership_id == account_id` +// We can't create an account from an `u32` or from a memberhsip_dd, +// so this trait allows us to get an account id from an u32, in the case of `64` which is what +// the mock use we get the parameter as a return. +// In the case of `AccountId32` we use the method provided by `frame_benchmarking` to get an +// AccountId. +pub trait CreateAccountId { + fn create_account_id(id: u32) -> Self; +} + +impl CreateAccountId for u64 { + fn create_account_id(id: u32) -> Self { + id.into() + } +} + +impl CreateAccountId for u32 { + fn create_account_id(id: u32) -> Self { + id.into() + } +} + +impl CreateAccountId for sp_core::crypto::AccountId32 { + fn create_account_id(id: u32) -> Self { + account::("default", id, SEED) + } +} + +fn assert_last_event(generic_event: ::RuntimeEvent) { + let events = frame_system::Pallet::::events(); + let system_event: ::RuntimeEvent = generic_event.into(); + assert!( + !events.is_empty(), + "If you are checking for last event there must be at least 1 event" + ); + let EventRecord { event, .. } = &events[events.len() - 1]; + assert_eq!(event, &system_event); +} + +benchmarks! { + where_clause { + where + T: balances::Config, + T::AccountId: CreateAccountId + } + + request_outbound_transfer{ + let fee: BalanceOf = 10u32.into(); + let remote_chains = BoundedVec::try_from(vec![1u32]).unwrap(); + let parameters = BridgeConstraints { + operator_account: Some(T::AccountId::create_account_id(1u32.into())), + pauser_accounts: Some(vec![T::AccountId::create_account_id(2u32.into())]), + bridging_fee: Some(fee), + thawn_duration: None::, + remote_chains: Some(remote_chains) + }; + assert_ok!(ArgoBridge::::update_bridge_constrains( + RawOrigin::Root.into(), + parameters + )); + + let dest_account = RemoteAccount { + account: [0; 32], + chain_id: 1, + }; + let sender = T::AccountId::create_account_id(1u32.into()); + let origin = RawOrigin::Signed(sender); + let transfer_id = ArgoBridge::::next_transfer_id(); + let amount = 100u32.into(); + }: _(origin, dest_account, amount, fee) + verify { + let sender = T::AccountId::create_account_id(1u32.into()); + assert_last_event::( + RawEvent::OutboundTransferRequested(transfer_id, sender, dest_account, amount, fee).into()); + } +} + +#[cfg(test)] +mod tests {} diff --git a/runtime-modules/argo-bridge/src/errors.rs b/runtime-modules/argo-bridge/src/errors.rs new file mode 100644 index 0000000000..7d5f668257 --- /dev/null +++ b/runtime-modules/argo-bridge/src/errors.rs @@ -0,0 +1,35 @@ +use crate::Module; +use frame_support::decl_error; +use sp_std::convert::TryInto; + +decl_error! { + pub enum Error for Module { + + /// Bridge not on active state + BridgeNotActive, + + /// Insufficient JOY Balance to cover the transaction costs + InsufficientJoyBalance, + + /// The bridging_fee changed since the request transfer + FeeDifferentThanExpected, + + /// Not enough mint allowance for transaction + InsufficienBridgMintAllowance, + + /// Operator account required + NotOperatorAccount, + + /// Pauser account required + NotPauserAccount, + + /// Number of pauser accounts over the maximum allowed + InvalidNumberOfPauserAccounts, + + /// Current block is lower than thawn_started_at + thawn_duration + ThawnNotFinished, + + /// ChainId is not on the list of the supported chains + NotSupportedRemoteChainId + } +} diff --git a/runtime-modules/argo-bridge/src/events.rs b/runtime-modules/argo-bridge/src/events.rs new file mode 100644 index 0000000000..7facc1cb53 --- /dev/null +++ b/runtime-modules/argo-bridge/src/events.rs @@ -0,0 +1,26 @@ +#![allow(clippy::unused_unit)] + +use frame_support::decl_event; + +use crate::{RemoteAccount, RemoteTransfer, TransferId}; + +use crate::types::*; + +// Balance type alias +type BalanceOf = ::Balance; + +decl_event!( + pub enum Event + where + AccountId = ::AccountId, + Balance = BalanceOf, + BridgeConstraints = BridgeConstraintsOf, + { + OutboundTransferRequested(TransferId, AccountId, RemoteAccount, Balance, Balance), + InboundTransferFinalized(RemoteTransfer, AccountId, Balance), + BridgePaused(AccountId), + BridgeThawnStarted(AccountId), + BridgeThawnFinished(), + BridgeConfigUpdated(BridgeConstraints), + } +); diff --git a/runtime-modules/argo-bridge/src/lib.rs b/runtime-modules/argo-bridge/src/lib.rs new file mode 100644 index 0000000000..9942d94e1f --- /dev/null +++ b/runtime-modules/argo-bridge/src/lib.rs @@ -0,0 +1,221 @@ +// Ensure we're `no_std` when compiling for Wasm. +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr( + not(any(test, feature = "runtime-benchmarks")), + deny(clippy::panic), + deny(clippy::panic_in_result_fn), + deny(clippy::unwrap_used), + deny(clippy::expect_used), + deny(clippy::indexing_slicing), + deny(clippy::integer_arithmetic), + deny(clippy::match_on_vec_items), + deny(clippy::unreachable) +)] + +#[cfg(not(any(test, feature = "runtime-benchmarks")))] +#[allow(unused_imports)] +#[macro_use] +extern crate common; + +use core::{convert::TryInto, default::Default}; +use frame_support::{ + decl_module, decl_storage, + dispatch::{marker::Copy, DispatchResult}, + ensure, + storage::bounded_vec::BoundedVec, + traits::{ConstU32, Currency, Get}, +}; +use frame_system::{ensure_root, ensure_signed}; + +use sp_std::vec; + +// crate modules +mod benchmarking; +mod errors; +mod events; +mod tests; +pub mod types; +pub mod weights; +pub use weights::WeightInfo; + +// crate imports +use common::costs::{burn_from_usable, has_sufficient_balance_for_payment}; +pub use errors::Error; +pub use events::{Event, RawEvent}; +use types::*; +type WeightInfoArgo = ::WeightInfo; + +pub trait Config: frame_system::Config + balances::Config { + // /// Events + type RuntimeEvent: From> + Into<::RuntimeEvent>; + + type MaxPauserAccounts: Get; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + + /// Defines the default bridging fee. + type DefaultBridgingFee: Get>; +} + +decl_storage! { generate_storage_info + trait Store for Module as ArgoBridge { + pub Status get(fn status) config(): BridgeStatus; + + /// Account ID that operates the bridge + pub OperatorAccount get(fn operator_account): Option; + + /// List of account IDs with permission to pause the bridge operations + pub PauserAccounts get(fn pauser_accounts): BoundedVec; + + /// Number of tokens that the bridge pallet is able to mint + pub MintAllowance get(fn mint_allowance) config(): BalanceOf; + + /// Amount of JOY burned as a fee for each transfer + pub BridgingFee get(fn bridging_fee) config(): BalanceOf; + + /// Number of blocks needed before bridge unpause can be finalised + pub ThawnDuration get(fn thawn_duration) config(): T::BlockNumber; + + pub NextTransferId get(fn next_transfer_id): TransferId; + + pub RemoteChains get(fn remote_chains): BoundedVec>; + } +} + +decl_module! { + pub struct Module for enum Call + where + origin: T::RuntimeOrigin + { + + /// Default deposit_event() handler + fn deposit_event() = default; + + #[weight = WeightInfoArgo::::request_outbound_transfer()] + pub fn request_outbound_transfer(origin, dest_account: RemoteAccount, amount: BalanceOf, expected_fee: BalanceOf) -> DispatchResult { + ensure!(Self::status() == BridgeStatus::Active, Error::::BridgeNotActive); + ensure!(RemoteChains::get().contains(&dest_account.chain_id), Error::::NotSupportedRemoteChainId); + + let fee = Self::bridging_fee(); + ensure!(fee == expected_fee, Error::::FeeDifferentThanExpected); + + let amount_with_fees = fee + amount; + let sender = ensure_signed(origin)?; + ensure!(has_sufficient_balance_for_payment::(&sender, amount_with_fees), Error::::InsufficientJoyBalance); + + burn_from_usable::(&sender, amount_with_fees)?; + >::put(Self::mint_allowance() + amount); + + let transfer_id = NextTransferId::get(); + Self::deposit_event(RawEvent::OutboundTransferRequested(transfer_id, sender, dest_account, amount, fee)); + NextTransferId::put(transfer_id + 1); + + Ok(()) + } + + #[weight = WeightInfoArgo::::finalize_inbound_transfer()] + pub fn finalize_inbound_transfer(origin, remote_transfer: RemoteTransfer, dest_account: T::AccountId, amount: BalanceOf) -> DispatchResult { + ensure!(!Self::operator_account().is_none(), Error::::NotOperatorAccount); + let caller = ensure_signed(origin)?; + ensure!(caller == Self::operator_account().unwrap(), Error::::NotOperatorAccount); + + ensure!(Self::status() == BridgeStatus::Active, Error::::BridgeNotActive); + ensure!(amount < Self::mint_allowance(), Error::::InsufficienBridgMintAllowance); + + ensure!(RemoteChains::get().contains(&remote_transfer.chain_id), Error::::NotSupportedRemoteChainId); + + >::put(Self::mint_allowance() - amount); + let _ = balances::Pallet::::deposit_creating( + &caller, + amount + ); + + Self::deposit_event(RawEvent::InboundTransferFinalized(remote_transfer, dest_account, amount)); + + Ok(()) + } + + #[weight = WeightInfoArgo::::pause_bridge()] + pub fn pause_bridge(origin) -> DispatchResult { + let caller = ensure_signed(origin)?; + let accounts = Self::pauser_accounts(); + ensure!(accounts.contains(&caller), Error::::NotPauserAccount); + + >::put(BridgeStatus::Paused); + Self::deposit_event(RawEvent::BridgePaused(caller)); + + Ok(()) + } + + #[weight = WeightInfoArgo::::init_unpause_bridge()] + pub fn init_unpause_bridge(origin) -> DispatchResult{ + let caller = ensure_signed(origin)?; + ensure!(Self::pauser_accounts().contains(&caller), Error::::NotPauserAccount); + + let current_block = >::block_number(); + >::put(BridgeStatus::Thawn { thawn_ends_at: current_block + Self::thawn_duration()}); + Self::deposit_event(RawEvent::BridgeThawnStarted(caller)); + + Ok(()) + } + + #[weight = WeightInfoArgo::::finish_unpause_bridge()] + pub fn finish_unpause_bridge(origin) -> DispatchResult { + let caller = ensure_signed(origin)?; + ensure!(!Self::operator_account().is_none(), Error::::NotOperatorAccount); + ensure!(caller == Self::operator_account().unwrap(), Error::::NotOperatorAccount); + + let current_block = >::block_number(); + ensure!( + matches!(Self::status(), BridgeStatus::Thawn { thawn_ends_at } + if current_block >= thawn_ends_at), Error::::ThawnNotFinished); + + >::put(BridgeStatus::Active); + Self::deposit_event(RawEvent::BridgeThawnFinished()); + + Ok(()) + } + + #[weight = WeightInfoArgo::::update_bridge_constrains()] + pub fn update_bridge_constrains(origin, parameters: BridgeConstraintsOf) -> DispatchResult { + ensure_root(origin)?; + + if let Some(ref new_operator_account) = parameters.operator_account { + >::put(new_operator_account); + } + + if let Some(ref new_pauser_accounts) = parameters.pauser_accounts { + ensure!(new_pauser_accounts.len() <= T::MaxPauserAccounts::get().try_into().unwrap(), Error::::InvalidNumberOfPauserAccounts); + >::put(BoundedVec::truncate_from(new_pauser_accounts.to_vec())); + } + + if let Some(new_bridging_fee) = parameters.bridging_fee { + >::put(new_bridging_fee); + } + + if let Some(new_thawn_duration) = parameters.thawn_duration { + >::put(new_thawn_duration); + } + + if let Some(ref new_remote_chains) = parameters.remote_chains { + RemoteChains::put(new_remote_chains); + } + + Self::deposit_event(RawEvent::BridgeConfigUpdated(parameters)); + + Ok(()) + } + + } +} + +/// Module implementation +impl Module {} + +impl frame_support::traits::Hooks for Pallet { + #[cfg(feature = "try-runtime")] + fn try_state(_: T::BlockNumber) -> Result<(), &'static str> { + Ok(()) + } +} diff --git a/runtime-modules/argo-bridge/src/tests/mock.rs b/runtime-modules/argo-bridge/src/tests/mock.rs new file mode 100644 index 0000000000..49ef1d6089 --- /dev/null +++ b/runtime-modules/argo-bridge/src/tests/mock.rs @@ -0,0 +1,199 @@ +#![cfg(test)] + +use crate as argo_bridge; +use crate::*; + +use frame_support::{ + parameter_types, + traits::{Currency, OnFinalize, OnInitialize}, +}; + +use common::{ + council, + membership::{MemberOriginValidator, MembershipInfoProvider}, +}; +use common::{ + locks::{BoundStakingAccountLockId, InvitedMemberLockId}, + numerical::one_plus_interest_pow_fixed, +}; +use frame_support::{ + ensure, + traits::{ConstU16, ConstU32, ConstU64, LockIdentifier, WithdrawReasons}, + PalletId, +}; +use frame_system::ensure_signed; +use sp_arithmetic::{FixedPointNumber, Perbill}; +use sp_io::TestExternalities; +use sp_runtime::testing::{Header, H256}; +use sp_runtime::traits::{BlakeTwo256, IdentityLookup}; +use sp_runtime::{DispatchError, DispatchResult, PerThing, Permill}; +use sp_std::convert::{TryFrom, TryInto}; +use staking_handler::{LockComparator, StakingHandler}; + +// Crate aliases +type BalanceOf = ::Balance; +pub type Balance = BalanceOf; +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; +pub type AccountId = ::AccountId; +pub type BlockNumber = ::BlockNumber; + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MinimumPeriod: u64 = 5; + pub const ExistentialDeposit: u64 = 10; + pub const DefaultMembershipPrice: u64 = 100; + pub const DefaultInitialInvitationBalance: u64 = 100; + pub const DefaultMemberInvitesCount: u32 = 2; +} + +// Config constants +parameter_types! { + pub const MaxPauserAccounts: u32 = 10; + pub const DefaultBridgingFee: Balance = 1000; +} + +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system, + Balances: balances, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, + ArgoBridge: argo_bridge::{Pallet, Call, Storage, Event}, + } +); + +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU64<250>; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = ConstU16<42>; + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +impl pallet_timestamp::Config for Test { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = MinimumPeriod; + type WeightInfo = (); +} + +impl balances::Config for Test { + type Balance = u64; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type MaxLocks = (); + type MaxReserves = ConstU32<2>; + type ReserveIdentifier = [u8; 8]; + type WeightInfo = (); +} + +impl Config for Test { + type RuntimeEvent = RuntimeEvent; + type MaxPauserAccounts = MaxPauserAccounts; + type WeightInfo = argo_bridge::weights::SubstrateWeight; + type DefaultBridgingFee = DefaultBridgingFee; +} + +pub fn default_genesis_config() -> argo_bridge::GenesisConfig { + argo_bridge::GenesisConfig:: { + status: BridgeStatus::Active, + mint_allowance: 0, + bridging_fee: DefaultBridgingFee::get(), + thawn_duration: 1, + } +} + +pub fn build_test_externalities(mint_allowance: Balance) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::default() + .build_storage::() + .unwrap(); + + let mut configs = default_genesis_config(); + configs.mint_allowance = mint_allowance; + configs.assimilate_storage(&mut t).unwrap(); + + t.into() +} + +/// Generate enviroment with test externalities +pub fn with_test_externalities R>(f: F) -> R { + /* + Events are not emitted on block 0. + So any dispatchable calls made during genesis block formation will have no events emitted. + https://substrate.dev/recipes/2-appetizers/4-events.html + */ + let func = || { + increase_block_number_by(1); + f() + }; + + build_test_externalities(0).execute_with(func) +} + +pub fn with_test_externalities_custom_mint_allowance R>( + mint_allowance: Balance, + f: F, +) -> R { + /* + Events are not emitted on block 0. + So any dispatchable calls made during genesis block formation will have no events emitted. + https://substrate.dev/recipes/2-appetizers/4-events.html + */ + let func = || { + increase_block_number_by(1); + f() + }; + + build_test_externalities(mint_allowance).execute_with(func) +} + +/// Moving past n blocks +pub fn increase_block_number_by(n: u64) { + let init_block = System::block_number(); + (0..=n).for_each(|offset| { + >::on_finalize(System::block_number()); + >::on_finalize(System::block_number()); + System::set_block_number(init_block.saturating_add(offset)); + >::on_initialize(System::block_number()); + >::on_initialize(System::block_number()); + }) +} + +#[macro_export] +macro_rules! joy { + ($bal:expr) => { + Balance::from($bal as u64) + }; +} + +#[macro_export] +macro_rules! account { + ($acc:expr) => { + AccountId::from($acc as u64) + }; +} diff --git a/runtime-modules/argo-bridge/src/tests/mod.rs b/runtime-modules/argo-bridge/src/tests/mod.rs new file mode 100644 index 0000000000..ae8b0a50a5 --- /dev/null +++ b/runtime-modules/argo-bridge/src/tests/mod.rs @@ -0,0 +1,370 @@ +#![cfg(test)] + +use core::convert::TryFrom; + +use frame_support::{assert_err, assert_ok}; +use sp_runtime::BoundedVec; + +use crate::{ + account, joy, + tests::mock::{increase_block_number_by, AccountId, Balance, Balances, BlockNumber, Test}, + BridgeConstraints, BridgeStatus, RemoteAccount, RemoteTransfer, +}; + +use self::mock::{ + with_test_externalities, with_test_externalities_custom_mint_allowance, ArgoBridge, + RuntimeOrigin, +}; +use crate::Error; + +mod mock; + +#[test] +fn request_outbound_transfer_success() { + with_test_externalities(|| { + let fee = joy!(10); + let remote_chains = BoundedVec::try_from(vec![1u32]).unwrap(); + let parameters = BridgeConstraints { + operator_account: Some(account!(1)), + pauser_accounts: Some(vec![account!(2), account!(3)]), + bridging_fee: Some(fee), + thawn_duration: None, + remote_chains: Some(remote_chains), + }; + assert_ok!(ArgoBridge::update_bridge_constrains( + RuntimeOrigin::root(), + parameters + )); + + Balances::set_balance(RuntimeOrigin::root(), account!(1), joy!(1020), joy!(0)).unwrap(); + + let remote_account = RemoteAccount { + account: [0; 32], + chain_id: 1, + }; + let result = ArgoBridge::request_outbound_transfer( + RuntimeOrigin::signed(account!(1)), + remote_account, + joy!(1000), + joy!(fee), + ); + assert_ok!(result); + }); +} + +#[test] +fn request_outbound_transfer_with_bridge_paused() { + with_test_externalities(|| { + let fee = joy!(10); + let remote_chains = BoundedVec::try_from(vec![1u32]).unwrap(); + let parameters = BridgeConstraints { + operator_account: Some(account!(1)), + pauser_accounts: Some(vec![account!(2), account!(3)]), + bridging_fee: Some(fee), + thawn_duration: None, + remote_chains: Some(remote_chains), + }; + ArgoBridge::update_bridge_constrains(RuntimeOrigin::root(), parameters).unwrap(); + + ArgoBridge::pause_bridge(RuntimeOrigin::signed(account!(2))).unwrap(); + + let remote_account = RemoteAccount { + account: [0; 32], + chain_id: 1, + }; + let result = ArgoBridge::request_outbound_transfer( + RuntimeOrigin::signed(account!(1)), + remote_account, + joy!(1000), + fee, + ); + assert_err!(result, Error::::BridgeNotActive); + }); +} + +#[test] +fn request_outbound_transfer_with_insufficient_balance() { + with_test_externalities(|| { + let fee = joy!(10); + let remote_chains = BoundedVec::try_from(vec![1u32]).unwrap(); + let parameters = BridgeConstraints { + operator_account: Some(account!(1)), + pauser_accounts: Some(vec![account!(2), account!(3)]), + bridging_fee: Some(fee), + thawn_duration: None, + remote_chains: Some(remote_chains), + }; + assert_ok!(ArgoBridge::update_bridge_constrains( + RuntimeOrigin::root(), + parameters + )); + + let transfer_amount = joy!(1000); + assert_ok!(Balances::set_balance( + RuntimeOrigin::root(), + account!(1), + transfer_amount + fee - 1, + joy!(0) + )); + + let remote_account = RemoteAccount { + account: [0; 32], + chain_id: 1, + }; + let result = ArgoBridge::request_outbound_transfer( + RuntimeOrigin::signed(account!(1)), + remote_account, + transfer_amount, + fee, + ); + assert_err!(result, Error::::InsufficientJoyBalance); + }); +} + +#[test] +fn request_outbound_transfer_with_unexpected_fee() { + with_test_externalities(|| { + let remote_chains = BoundedVec::try_from(vec![1u32]).unwrap(); + let parameters = BridgeConstraints { + operator_account: Some(account!(1)), + pauser_accounts: Some(vec![account!(2), account!(3)]), + bridging_fee: Some(joy!(20)), + thawn_duration: None, + remote_chains: Some(remote_chains), + }; + assert_ok!(ArgoBridge::update_bridge_constrains( + RuntimeOrigin::root(), + parameters + )); + + let transfer_amount = joy!(1000); + assert_ok!(Balances::set_balance( + RuntimeOrigin::root(), + account!(1), + transfer_amount + 50, + joy!(0) + )); + + let remote_account = RemoteAccount { + account: [0; 32], + chain_id: 1, + }; + let result = ArgoBridge::request_outbound_transfer( + RuntimeOrigin::signed(account!(1)), + remote_account, + transfer_amount, + joy!(10), + ); + assert_err!(result, Error::::FeeDifferentThanExpected); + }); +} + +#[test] +fn finalize_inbound_transfer_success() { + with_test_externalities_custom_mint_allowance(joy!(1000), || { + let remote_chains = BoundedVec::try_from(vec![1u32]).unwrap(); + let parameters = BridgeConstraints { + operator_account: Some(account!(1)), + pauser_accounts: None, + bridging_fee: None, + thawn_duration: None, + remote_chains: Some(remote_chains), + }; + assert_ok!(ArgoBridge::update_bridge_constrains( + RuntimeOrigin::root(), + parameters + )); + + let remote_transfer = RemoteTransfer { id: 0, chain_id: 1 }; + let result = ArgoBridge::finalize_inbound_transfer( + RuntimeOrigin::signed(account!(1)), + remote_transfer, + account!(2), + 1000, + ); + assert_err!(result, Error::::InsufficienBridgMintAllowance); + }); +} + +#[test] +fn finalize_inbound_transfer_with_no_operator_account() { + with_test_externalities(|| { + let remote_transfer = RemoteTransfer { id: 0, chain_id: 1 }; + let result = ArgoBridge::finalize_inbound_transfer( + RuntimeOrigin::signed(account!(1)), + remote_transfer, + account!(2), + 1000, + ); + assert_err!(result, Error::::NotOperatorAccount); + }); +} + +#[test] +fn finalize_inbound_transfer_with_unauthorized_account() { + with_test_externalities(|| { + let remote_chains = BoundedVec::try_from(vec![1u32]).unwrap(); + let parameters = BridgeConstraints { + operator_account: Some(account!(1)), + pauser_accounts: None, + bridging_fee: None, + thawn_duration: None, + remote_chains: Some(remote_chains), + }; + assert_ok!(ArgoBridge::update_bridge_constrains( + RuntimeOrigin::root(), + parameters + )); + + let remote_transfer = RemoteTransfer { id: 0, chain_id: 1 }; + let result = ArgoBridge::finalize_inbound_transfer( + RuntimeOrigin::signed(account!(2)), + remote_transfer, + account!(2), + 1000, + ); + assert_err!(result, Error::::NotOperatorAccount); + }); +} + +#[test] +fn finalize_inbound_transfer_with_insufficient_bridge_mint() { + with_test_externalities(|| { + let remote_chains = BoundedVec::try_from(vec![1u32]).unwrap(); + let parameters = BridgeConstraints { + operator_account: Some(account!(1)), + pauser_accounts: None, + bridging_fee: None, + thawn_duration: None, + remote_chains: Some(remote_chains), + }; + assert_ok!(ArgoBridge::update_bridge_constrains( + RuntimeOrigin::root(), + parameters + )); + + let remote_transfer = RemoteTransfer { id: 0, chain_id: 1 }; + let result = ArgoBridge::finalize_inbound_transfer( + RuntimeOrigin::signed(account!(1)), + remote_transfer, + account!(2), + 1000, + ); + assert_err!(result, Error::::InsufficienBridgMintAllowance); + }); +} + +#[test] +fn pause_bridge_success() { + with_test_externalities(|| { + let parameters = BridgeConstraints { + operator_account: None, + pauser_accounts: Some(vec![account!(2)]), + bridging_fee: None, + thawn_duration: None, + remote_chains: None, + }; + assert_ok!(ArgoBridge::update_bridge_constrains( + RuntimeOrigin::root(), + parameters + )); + assert_ok!(ArgoBridge::pause_bridge(RuntimeOrigin::signed(account!(2)))); + }); +} + +#[test] +fn pause_bridge_with_unathorized_account() { + with_test_externalities(|| { + let parameters = BridgeConstraints { + operator_account: None, + pauser_accounts: Some(vec![account!(2)]), + bridging_fee: None, + thawn_duration: None, + remote_chains: None, + }; + assert_ok!(ArgoBridge::update_bridge_constrains( + RuntimeOrigin::root(), + parameters + )); + + let result = ArgoBridge::pause_bridge(RuntimeOrigin::signed(account!(1))); + assert_err!(result, Error::::NotPauserAccount); + }); +} + +#[test] +fn unpause_bridge_success() { + with_test_externalities(|| { + let parameters = BridgeConstraints { + operator_account: Some(account!(1)), + pauser_accounts: Some(vec![account!(2)]), + bridging_fee: None, + thawn_duration: Some(1), + remote_chains: None, + }; + ArgoBridge::update_bridge_constrains(RuntimeOrigin::root(), parameters).unwrap(); + + ArgoBridge::pause_bridge(RuntimeOrigin::signed(account!(2))).unwrap(); + + ArgoBridge::init_unpause_bridge(RuntimeOrigin::signed(account!(2))).unwrap(); + let current_block = >::block_number(); + assert_eq!( + ArgoBridge::status(), + BridgeStatus::Thawn { + thawn_ends_at: current_block + 1 + } + ); + increase_block_number_by(2); + assert_ok!(ArgoBridge::finish_unpause_bridge(RuntimeOrigin::signed( + account!(1) + ))); + }); +} + +#[test] +fn unpause_bridge_during_thawn() { + with_test_externalities(|| { + let thawn_duration: BlockNumber = 2; + let parameters = BridgeConstraints { + operator_account: Some(account!(1)), + pauser_accounts: Some(vec![account!(2)]), + bridging_fee: None, + thawn_duration: Some(thawn_duration), + remote_chains: None, + }; + ArgoBridge::update_bridge_constrains(RuntimeOrigin::root(), parameters).unwrap(); + + ArgoBridge::pause_bridge(RuntimeOrigin::signed(account!(2))).unwrap(); + + ArgoBridge::init_unpause_bridge(RuntimeOrigin::signed(account!(2))).unwrap(); + let current_block = >::block_number(); + assert_eq!( + ArgoBridge::status(), + BridgeStatus::Thawn { + thawn_ends_at: current_block + thawn_duration + } + ); + increase_block_number_by(1); + let result = ArgoBridge::finish_unpause_bridge(RuntimeOrigin::signed(account!(1))); + assert_err!(result, Error::::ThawnNotFinished); + }); +} + +#[test] +fn init_unpause_bridge_with_unathorized_account() { + with_test_externalities(|| { + let parameters = BridgeConstraints { + operator_account: Some(account!(1)), + pauser_accounts: Some(vec![account!(2)]), + bridging_fee: None, + thawn_duration: None, + remote_chains: None, + }; + ArgoBridge::update_bridge_constrains(RuntimeOrigin::root(), parameters).unwrap(); + + ArgoBridge::pause_bridge(RuntimeOrigin::signed(account!(2))).unwrap(); + + let result = ArgoBridge::init_unpause_bridge(RuntimeOrigin::signed(account!(1))); + assert_err!(result, Error::::NotPauserAccount); + }); +} diff --git a/runtime-modules/argo-bridge/src/types.rs b/runtime-modules/argo-bridge/src/types.rs new file mode 100644 index 0000000000..3b21d47c04 --- /dev/null +++ b/runtime-modules/argo-bridge/src/types.rs @@ -0,0 +1,61 @@ +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{storage::bounded_vec::BoundedVec, traits::ConstU32}; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; + +use sp_std::vec::Vec; + +// Balance type alias +pub type BalanceOf = ::Balance; + +pub type ChainId = u32; +pub type TransferId = u64; + +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)] +pub struct BridgeConstraints { + pub operator_account: Option, + pub pauser_accounts: Option>, + pub bridging_fee: Option, + pub thawn_duration: Option, + pub remote_chains: Option>>, +} + +pub type BridgeConstraintsOf = BridgeConstraints< + ::AccountId, + BalanceOf, + ::BlockNumber, +>; + +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)] +pub struct RemoteAccount { + // Ethereum addresses only need 20 bytes but we use 32 bytes to enable compatibility with other chains + // When using Ethereum addresses, the last 12 bytes should be zero + pub account: [u8; 32], + pub chain_id: ChainId, +} + +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)] +pub struct RemoteTransfer { + pub id: TransferId, + pub chain_id: ChainId, +} + +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)] +pub enum BridgeStatus { + Active, + Paused, + Thawn { thawn_ends_at: BlockNumber }, +} + +impl Default for BridgeStatus { + fn default() -> Self { + BridgeStatus::Thawn { + thawn_ends_at: Default::default(), + } + } +} diff --git a/runtime-modules/argo-bridge/src/weights.rs b/runtime-modules/argo-bridge/src/weights.rs new file mode 100644 index 0000000000..41ab26ca9e --- /dev/null +++ b/runtime-modules/argo-bridge/src/weights.rs @@ -0,0 +1,69 @@ +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(unused_variables)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for project_token. +pub trait WeightInfo { + fn request_outbound_transfer() -> Weight; + + fn finalize_inbound_transfer() -> Weight; + + fn pause_bridge() -> Weight; + + fn init_unpause_bridge() -> Weight; + + fn finish_unpause_bridge() -> Weight; + + fn update_bridge_constrains() -> Weight; +} + +/// Weights for project_token using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + + fn request_outbound_transfer() -> Weight + { + Weight::from_parts(10_506_000, 0u64) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + + fn finalize_inbound_transfer() -> Weight + { + Weight::from_parts(10_506_000, 0u64) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + + fn pause_bridge() -> Weight + { + Weight::from_parts(10_506_000, 0u64) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + + fn init_unpause_bridge() -> Weight + { + Weight::from_parts(10_506_000, 0u64) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + + fn finish_unpause_bridge() -> Weight + { + Weight::from_parts(10_506_000, 0u64) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + + fn update_bridge_constrains() -> Weight + { + Weight::from_parts(10_506_000, 0u64) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} \ No newline at end of file diff --git a/runtime-modules/proposals/codex/Cargo.toml b/runtime-modules/proposals/codex/Cargo.toml index 5f311d7eea..2346f4a5a4 100644 --- a/runtime-modules/proposals/codex/Cargo.toml +++ b/runtime-modules/proposals/codex/Cargo.toml @@ -30,6 +30,7 @@ content = { package = 'pallet-content', default-features = false, path = '../../ balances = { package = 'pallet-balances', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9', optional = true } council = { package = 'pallet-council', default-features = false, path = '../../council' } token = { package = 'pallet-project-token', default-features = false, path = '../../project-token' } +argo-bridge = { package = 'pallet-argo-bridge', default-features = false, path = '../../argo-bridge' } # Benchmarking dependencies frame-benchmarking = { package = 'frame-benchmarking', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9', optional = true } @@ -76,6 +77,7 @@ std = [ 'membership/std', 'content/std', 'token/std', + 'argo-bridge/std', 'storage/std', 'staking/std', 'scale-info/std', diff --git a/runtime-modules/proposals/codex/src/benchmarking.rs b/runtime-modules/proposals/codex/src/benchmarking.rs index ae5568af54..b91347c646 100644 --- a/runtime-modules/proposals/codex/src/benchmarking.rs +++ b/runtime-modules/proposals/codex/src/benchmarking.rs @@ -957,6 +957,38 @@ benchmarks! { ); } + create_proposal_argo_bridge_constraints { + let t in 1 .. to_kb(T::TitleMaxLength::get()); + let d in 1 .. to_kb(T::DescriptionMaxLength::get()); + + let (account_id, member_id, general_proposal_paramters) = + create_proposal_parameters::(t, d); + + // let member_id = Membership::::members_created(); + + let proposal_details = ProposalDetails::UpdateArgoBridgeConstraints( + argo_bridge::types::BridgeConstraints { + operator_account: Some(account::("operator", 0, SEED)), + pauser_accounts: Some(vec![account::("pauser", 0, SEED), account::("pauser", 1, SEED)] ), + bridging_fee: Some(100u32.into()), + thawn_duration: None, + remote_chains: None + } + ); + }: create_proposal( + RawOrigin::Signed(account_id.clone()), + general_proposal_paramters.clone(), + proposal_details.clone() + ) + verify { + create_proposal_verify::( + account_id, + member_id, + general_proposal_paramters, + proposal_details + ); + } + create_proposal_set_era_payout_damping_factor { let t in 1 .. to_kb(T::TitleMaxLength::get()); let d in 1 .. to_kb(T::DescriptionMaxLength::get()); diff --git a/runtime-modules/proposals/codex/src/lib.rs b/runtime-modules/proposals/codex/src/lib.rs index 733f08ef7e..e5b4ae3bda 100644 --- a/runtime-modules/proposals/codex/src/lib.rs +++ b/runtime-modules/proposals/codex/src/lib.rs @@ -287,6 +287,9 @@ pub trait Config: ProposalParameters>, >; + /// `Update pallet project token` proposal parameters + type UpdateArgoBridgeConstraints: Get>>; + /// `Set Era Payout Damping Factor` proposal parameters type SetEraPayoutDampingFactorProposalParameters: Get< ProposalParameters>, @@ -535,6 +538,10 @@ decl_module! { const UpdateTokenPalletTokenConstraints: ProposalParameters> = T::UpdateTokenPalletTokenConstraints::get(); + /// Set Argo Bridge Constraints + const UpdateArgoBridgeConstraints: + ProposalParameters> = T::UpdateArgoBridgeConstraints::get(); + /// Era payout damping factor const SetEraPayoutDampingFactorProposalParameters: ProposalParameters> = T::SetEraPayoutDampingFactorProposalParameters::get(); @@ -919,6 +926,9 @@ impl Module { ProposalDetails::UpdateTokenPalletTokenConstraints(..) => { // Note: No checks for this proposal for now } + ProposalDetails::UpdateArgoBridgeConstraints(..) => { + // Note: No checks for this proposal for now + } ProposalDetails::SetEraPayoutDampingFactor(..) => { // Note: No checks for this proposal for now } @@ -998,6 +1008,9 @@ impl Module { ProposalDetails::UpdateTokenPalletTokenConstraints(..) => { T::UpdateTokenPalletTokenConstraints::get() } + ProposalDetails::UpdateArgoBridgeConstraints(..) => { + T::UpdateArgoBridgeConstraints::get() + } ProposalDetails::SetEraPayoutDampingFactor(..) => { T::SetEraPayoutDampingFactorProposalParameters::get() } @@ -1180,6 +1193,12 @@ impl Module { to_kb(description_length.saturated_into()), ) } + ProposalDetails::UpdateArgoBridgeConstraints(..) => { + WeightInfoCodex::::create_proposal_update_argo_bridge_constraints( + to_kb(title_length.saturated_into()), + to_kb(description_length.saturated_into()), + ) + } ProposalDetails::SetEraPayoutDampingFactor(..) => { WeightInfoCodex::::create_proposal_set_era_payout_damping_factor( to_kb(title_length.saturated_into()), diff --git a/runtime-modules/proposals/codex/src/tests/mock.rs b/runtime-modules/proposals/codex/src/tests/mock.rs index 73ada48810..b880aa09b1 100644 --- a/runtime-modules/proposals/codex/src/tests/mock.rs +++ b/runtime-modules/proposals/codex/src/tests/mock.rs @@ -786,6 +786,7 @@ impl crate::Config for Test { type SetMaxValidatorCountProposalMaxValidators = SetMaxValidatorCountProposalMaxValidators; type SetPalletFozenStatusProposalParameters = DefaultProposalParameters; type UpdateTokenPalletTokenConstraints = DefaultProposalParameters; + type UpdateArgoBridgeConstraints = DefaultProposalParameters; type SetEraPayoutDampingFactorProposalParameters = DefaultProposalParameters; type DecreaseCouncilBudgetProposalParameters = DefaultProposalParameters; } diff --git a/runtime-modules/proposals/codex/src/types.rs b/runtime-modules/proposals/codex/src/types.rs index bcbc013ee4..6eaf20c34e 100644 --- a/runtime-modules/proposals/codex/src/types.rs +++ b/runtime-modules/proposals/codex/src/types.rs @@ -34,6 +34,7 @@ pub type ProposalDetailsOf = ProposalDetails< ::ProposalId, content::UpdateChannelPayoutsParameters, token::TokenConstraintsOf, + argo_bridge::types::BridgeConstraintsOf, >; /// Proposal details provide voters the information required for the perceived voting. @@ -48,6 +49,7 @@ pub enum ProposalDetails< ProposalId, UpdateChannelPayoutsParameters, TokenConstraints, + ArgoBridgeConstraints, > { /// The signal of the `Signal` proposal Signal(Vec), @@ -129,6 +131,9 @@ pub enum ProposalDetails< /// Update token constraints UpdateTokenPalletTokenConstraints(TokenConstraints), + /// Update Argo Bridge contraints + UpdateArgoBridgeConstraints(ArgoBridgeConstraints), + /// `SetEraPayoutDampingFactor` proposal SetEraPayoutDampingFactor(Percent), @@ -145,6 +150,7 @@ impl< ProposalId, UpdateChannelPayoutsParameters, TokenConstraints, + ArgoBridgeConstraints, > Default for ProposalDetails< Balance, @@ -155,6 +161,7 @@ impl< ProposalId, UpdateChannelPayoutsParameters, TokenConstraints, + ArgoBridgeConstraints, > { fn default() -> Self { diff --git a/runtime-modules/proposals/codex/src/weights.rs b/runtime-modules/proposals/codex/src/weights.rs index e697e620fb..31deaf1a4f 100644 --- a/runtime-modules/proposals/codex/src/weights.rs +++ b/runtime-modules/proposals/codex/src/weights.rs @@ -69,6 +69,7 @@ pub trait WeightInfo { fn create_proposal_update_channel_payouts(_t: u32, _d: u32, _i: u32, ) -> Weight; fn create_proposal_freeze_pallet(_t: u32, _d: u32, ) -> Weight; fn create_proposal_update_token_pallet_token_constraints(_t: u32, _d: u32, ) -> Weight; + fn create_proposal_update_argo_bridge_constraints(_t: u32, _d: u32, ) -> Weight; fn create_proposal_set_era_payout_damping_factor(_t: u32, _d: u32, ) -> Weight; fn create_proposal_decrease_council_budget(_t: u32, _d: u32, ) -> Weight; } @@ -1060,6 +1061,22 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(9_u64)) } + + fn create_proposal_update_argo_bridge_constraints(t: u32, d: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `651` + // Estimated: `19940` + // Minimum execution time: 103_350 nanoseconds. + Weight::from_parts(82_522_075, 0u64) + .saturating_add(Weight::from_parts(0, 19940)) + // Standard Error: 12_486 + .saturating_add(Weight::from_parts(1_112_896, 0u64).saturating_mul(t.into())) + // Standard Error: 12_486 + .saturating_add(Weight::from_parts(1_256_380, 0u64).saturating_mul(d.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(9_u64)) + } + // Storage: Membership MembershipById (r:1 w:0) // Proof: Membership MembershipById (max_values: None, max_size: Some(125), added: 2600, mode: MaxEncodedLen) // Storage: ProposalEngine ActiveProposalCount (r:1 w:1) @@ -1215,6 +1232,9 @@ impl WeightInfo for () { fn create_proposal_update_token_pallet_token_constraints(t: u32, d: u32, ) -> Weight { Weight::from_parts(0, 0) } + fn create_proposal_update_argo_bridge_constraints(t: u32, d: u32, ) -> Weight { + Weight::from_parts(0, 0) + } fn create_proposal_set_era_payout_damping_factor(t: u32, d: u32, ) -> Weight { Weight::from_parts(0, 0) } diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 7dca078144..fd8fa7b622 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -99,6 +99,7 @@ bounty = { package = 'pallet-bounty', default-features = false, path = '../runti content = { package = 'pallet-content', default-features = false, path = '../runtime-modules/content' } joystream-utility = { package = 'pallet-joystream-utility', default-features = false, path = '../runtime-modules/utility' } project-token = { package = 'pallet-project-token', default-features = false, path = '../runtime-modules/project-token' } +argo-bridge = { package = 'pallet-argo-bridge', default-features = false, path = '../runtime-modules/argo-bridge' } [dev-dependencies] sp-io = { package = 'sp-io', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9' } @@ -189,6 +190,7 @@ std = [ 'joystream-utility/std', 'content/std', 'project-token/std', + 'argo-bridge/std', 'log/std', ] runtime-benchmarks = [ @@ -233,6 +235,7 @@ runtime-benchmarks = [ 'storage/runtime-benchmarks', 'content/runtime-benchmarks', "project-token/runtime-benchmarks", + "argo-bridge/runtime-benchmarks" ] # Configuration suitable for staging networks and playground @@ -290,4 +293,5 @@ try-runtime = [ 'joystream-utility/try-runtime', 'content/try-runtime', 'project-token/try-runtime', + 'argo-bridge/try-runtime' ] diff --git a/runtime/src/integration/proposals/proposal_encoder.rs b/runtime/src/integration/proposals/proposal_encoder.rs index 1b76c6719b..1c772f2d51 100644 --- a/runtime/src/integration/proposals/proposal_encoder.rs +++ b/runtime/src/integration/proposals/proposal_encoder.rs @@ -171,6 +171,9 @@ impl ProposalEncoder for ExtrinsicProposalEncoder { parameters, }) } + ProposalDetails::UpdateArgoBridgeConstraints(parameters) => { + RuntimeCall::ArgoBridge(argo_bridge::Call::update_bridge_constrains { parameters }) + } ProposalDetails::SetPalletFozenStatus(freeze, pallet) => match pallet { FreezablePallet::ProjectToken => { RuntimeCall::ProjectToken(project_token::Call::set_frozen_status { freeze }) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 8cc543791d..cd5f35bdac 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -139,6 +139,8 @@ pub use content; pub use content::LimitPerPeriod; pub use content::MaxNumber; +pub use argo_bridge; + /// This runtime version. #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { @@ -935,6 +937,18 @@ impl project_token::Config for Runtime { type WeightInfo = project_token::weights::SubstrateWeight; } +parameter_types! { + pub const MaxPauserAccounts: u32 = 10; + pub const DefaultBridgingFee: Balance = dollars!(1_000); +} + +impl argo_bridge::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type MaxPauserAccounts = MaxPauserAccounts; + type WeightInfo = argo_bridge::weights::SubstrateWeight; + type DefaultBridgingFee = DefaultBridgingFee; +} + // The referendum instance alias. pub type ReferendumInstance = referendum::Instance1; pub type ReferendumModule = referendum::Module; @@ -1717,6 +1731,7 @@ impl proposals_codex::Config for Runtime { type FundingRequestProposalMaxAccounts = FundingRequestProposalMaxAccounts; type SetMaxValidatorCountProposalMaxValidators = SetMaxValidatorCountProposalMaxValidators; type UpdateTokenPalletTokenConstraints = UpdateTokenPalletTokenConstraints; + type UpdateArgoBridgeConstraints = UpdateArgoBridgeConstraints; type SetPalletFozenStatusProposalParameters = SetPalletFozenStatusProposalParameters; type SetEraPayoutDampingFactorProposalParameters = SetEraPayoutDampingFactorProposalParameters; type WeightInfo = proposals_codex::weights::SubstrateWeight; @@ -1979,6 +1994,7 @@ construct_runtime!( Content: content::{Pallet, Call, Storage, Event, Config}, Storage: storage::{Pallet, Call, Storage, Event, Config}, ProjectToken: project_token::{Pallet, Call, Storage, Event, Config}, + ArgoBridge: argo_bridge::{Pallet, Call, Storage, Event, Config}, // --- Proposals ProposalsEngine: proposals_engine::{Pallet, Call, Storage, Event}, ProposalsDiscussion: proposals_discussion::{Pallet, Call, Storage, Event, Config}, diff --git a/runtime/src/proposals_configuration/defaults.rs b/runtime/src/proposals_configuration/defaults.rs index 6b942f1ffd..44e69d3491 100644 --- a/runtime/src/proposals_configuration/defaults.rs +++ b/runtime/src/proposals_configuration/defaults.rs @@ -358,6 +358,20 @@ pub(crate) fn update_token_pallet_token_governance_parameters( } } +// Proposal parameters for the 'Update Argo Bridge Parameters' proposal +pub(crate) fn update_argo_bridge_parameters() -> ProposalParameters { + ProposalParameters { + voting_period: days!(7), + grace_period: days!(1), + approval_quorum_percentage: TWO_OUT_OF_THREE, + approval_threshold_percentage: ALL, + slashing_quorum_percentage: ALL, + slashing_threshold_percentage: ALL, + required_stake: Some(dollars!(100)), + constitutionality: 1, + } +} + // Proposal parameters for the 'Freeze Pallet' proposal pub(crate) fn freeze_pallet_proposal() -> ProposalParameters { ProposalParameters { diff --git a/runtime/src/proposals_configuration/mod.rs b/runtime/src/proposals_configuration/mod.rs index 9f71890b28..692d46e169 100644 --- a/runtime/src/proposals_configuration/mod.rs +++ b/runtime/src/proposals_configuration/mod.rs @@ -113,6 +113,9 @@ parameter_types! { pub UpdateTokenPalletTokenConstraints: ProposalParameters = update_token_pallet_token_governance_parameters(); + pub UpdateArgoBridgeConstraints: ProposalParameters = + update_argo_bridge_parameters(); + pub SetEraPayoutDampingFactorProposalParameters: ProposalParameters = set_era_payout_damping_factor(); diff --git a/runtime/src/proposals_configuration/playground.rs b/runtime/src/proposals_configuration/playground.rs index aaffcd1b04..4de8efb2ba 100644 --- a/runtime/src/proposals_configuration/playground.rs +++ b/runtime/src/proposals_configuration/playground.rs @@ -374,6 +374,20 @@ pub(crate) fn update_token_pallet_token_governance_parameters( } } +// Proposal parameters for the 'Update Argo Bridge Parameters' proposal +pub(crate) fn update_argo_bridge_parameters() -> ProposalParameters { + ProposalParameters { + voting_period: 200, + grace_period: 0, + approval_quorum_percentage: 60, + approval_threshold_percentage: 75, + slashing_quorum_percentage: 60, + slashing_threshold_percentage: 80, + required_stake: Some(dollars!(50)), + constitutionality: 1, + } +} + // Proposal parameters for the 'Decrease Council Budget' proposal pub(crate) fn decrease_council_budget() -> ProposalParameters { ProposalParameters { diff --git a/runtime/src/proposals_configuration/staging.rs b/runtime/src/proposals_configuration/staging.rs index 5163a80b03..54add58753 100644 --- a/runtime/src/proposals_configuration/staging.rs +++ b/runtime/src/proposals_configuration/staging.rs @@ -371,6 +371,20 @@ pub(crate) fn update_token_pallet_token_governance_parameters( } } +// Proposal parameters for the 'Update Argo Bridge Parameters' proposal +pub(crate) fn update_argo_bridge_parameters() -> ProposalParameters { + ProposalParameters { + voting_period: minutes!(20), + grace_period: 0, + approval_quorum_percentage: TWO_OUT_OF_THREE, + approval_threshold_percentage: TWO_OUT_OF_THREE, + slashing_quorum_percentage: ALL, + slashing_threshold_percentage: ALL, + required_stake: Some(dollars!(50)), + constitutionality: 1, + } +} + // Proposal parameters for the 'Set Era Payout Damping Factor' proposal pub(crate) fn set_era_payout_damping_factor() -> ProposalParameters { ProposalParameters { diff --git a/runtime/src/proposals_configuration/testing.rs b/runtime/src/proposals_configuration/testing.rs index 2e9849e974..268ae1585b 100644 --- a/runtime/src/proposals_configuration/testing.rs +++ b/runtime/src/proposals_configuration/testing.rs @@ -361,6 +361,20 @@ pub(crate) fn update_token_pallet_token_governance_parameters( } } +// Proposal parameters for the 'Update Argo Bridge Parameters' proposal +pub(crate) fn update_argo_bridge_parameters() -> ProposalParameters { + ProposalParameters { + voting_period: 30, + grace_period: 0, + approval_quorum_percentage: 60, + approval_threshold_percentage: 75, + slashing_quorum_percentage: 60, + slashing_threshold_percentage: 80, + required_stake: Some(currency::DOLLARS.saturating_mul(50)), + constitutionality: 1, + } +} + // Proposal parameters for the 'Set Era Payout Damping Factor' proposal pub(crate) fn set_era_payout_damping_factor() -> ProposalParameters { ProposalParameters { From 69263dffd97d58114eed6c272e4dd3ffc38cd373 Mon Sep 17 00:00:00 2001 From: Ricardo Date: Wed, 29 May 2024 03:12:54 +0100 Subject: [PATCH 02/16] change Argo Bridge configs --- bin/node/src/chain_spec/argo_bridge_config.rs | 6 +++--- runtime/src/lib.rs | 2 +- runtime/src/proposals_configuration/defaults.rs | 2 +- runtime/src/proposals_configuration/staging.rs | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bin/node/src/chain_spec/argo_bridge_config.rs b/bin/node/src/chain_spec/argo_bridge_config.rs index 13ec4d4ab6..831a5014b8 100644 --- a/bin/node/src/chain_spec/argo_bridge_config.rs +++ b/bin/node/src/chain_spec/argo_bridge_config.rs @@ -1,10 +1,10 @@ -use node_runtime::{argo_bridge::types::BridgeStatus, ArgoBridgeConfig}; +use node_runtime::{argo_bridge::types::BridgeStatus, ArgoBridgeConfig, DefaultBridgingFee}; pub fn production_config() -> ArgoBridgeConfig { ArgoBridgeConfig { status: BridgeStatus::Paused, mint_allowance: 0, - bridging_fee: 0, + bridging_fee: DefaultBridgingFee::get(), thawn_duration: 1, ..Default::default() } @@ -14,7 +14,7 @@ pub fn testing_config() -> ArgoBridgeConfig { ArgoBridgeConfig { status: BridgeStatus::Paused, mint_allowance: 0, - bridging_fee: 0, + bridging_fee: DefaultBridgingFee::get(), thawn_duration: 1, ..Default::default() } diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index cd5f35bdac..b5384d885d 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -939,7 +939,7 @@ impl project_token::Config for Runtime { parameter_types! { pub const MaxPauserAccounts: u32 = 10; - pub const DefaultBridgingFee: Balance = dollars!(1_000); + pub const DefaultBridgingFee: Balance = dollars!(1); } impl argo_bridge::Config for Runtime { diff --git a/runtime/src/proposals_configuration/defaults.rs b/runtime/src/proposals_configuration/defaults.rs index 44e69d3491..15e3fc6d1f 100644 --- a/runtime/src/proposals_configuration/defaults.rs +++ b/runtime/src/proposals_configuration/defaults.rs @@ -363,7 +363,7 @@ pub(crate) fn update_argo_bridge_parameters() -> ProposalParameters ProposalParameters Date: Wed, 29 May 2024 03:13:44 +0100 Subject: [PATCH 03/16] tests: improve Argo Bridge tests --- runtime-modules/argo-bridge/src/tests/mock.rs | 30 ++-- runtime-modules/argo-bridge/src/tests/mod.rs | 142 ++++++++++++++---- 2 files changed, 129 insertions(+), 43 deletions(-) diff --git a/runtime-modules/argo-bridge/src/tests/mock.rs b/runtime-modules/argo-bridge/src/tests/mock.rs index 49ef1d6089..1c56db7b6a 100644 --- a/runtime-modules/argo-bridge/src/tests/mock.rs +++ b/runtime-modules/argo-bridge/src/tests/mock.rs @@ -5,30 +5,16 @@ use crate::*; use frame_support::{ parameter_types, - traits::{Currency, OnFinalize, OnInitialize}, + traits::{OnFinalize, OnInitialize}, }; -use common::{ - council, - membership::{MemberOriginValidator, MembershipInfoProvider}, -}; -use common::{ - locks::{BoundStakingAccountLockId, InvitedMemberLockId}, - numerical::one_plus_interest_pow_fixed, -}; use frame_support::{ - ensure, - traits::{ConstU16, ConstU32, ConstU64, LockIdentifier, WithdrawReasons}, + traits::{ConstU16, ConstU32, ConstU64}, PalletId, }; -use frame_system::ensure_signed; -use sp_arithmetic::{FixedPointNumber, Perbill}; -use sp_io::TestExternalities; use sp_runtime::testing::{Header, H256}; use sp_runtime::traits::{BlakeTwo256, IdentityLookup}; -use sp_runtime::{DispatchError, DispatchResult, PerThing, Permill}; use sp_std::convert::{TryFrom, TryInto}; -use staking_handler::{LockComparator, StakingHandler}; // Crate aliases type BalanceOf = ::Balance; @@ -50,7 +36,17 @@ parameter_types! { // Config constants parameter_types! { pub const MaxPauserAccounts: u32 = 10; - pub const DefaultBridgingFee: Balance = 1000; + pub const DefaultBridgingFee: Balance = 1; +} + +#[macro_export] +macro_rules! last_event_eq { + ($e:expr) => { + assert_eq!( + System::events().last().unwrap().event, + RuntimeEvent::ArgoBridge($e) + ) + }; } frame_support::construct_runtime!( diff --git a/runtime-modules/argo-bridge/src/tests/mod.rs b/runtime-modules/argo-bridge/src/tests/mod.rs index ae8b0a50a5..26a83382c5 100644 --- a/runtime-modules/argo-bridge/src/tests/mod.rs +++ b/runtime-modules/argo-bridge/src/tests/mod.rs @@ -2,13 +2,14 @@ use core::convert::TryFrom; +use crate::tests::mock::*; use frame_support::{assert_err, assert_ok}; use sp_runtime::BoundedVec; use crate::{ - account, joy, + account, joy, last_event_eq, tests::mock::{increase_block_number_by, AccountId, Balance, Balances, BlockNumber, Test}, - BridgeConstraints, BridgeStatus, RemoteAccount, RemoteTransfer, + BridgeConstraints, BridgeStatus, RawEvent, RemoteAccount, RemoteTransfer, }; use self::mock::{ @@ -35,20 +36,36 @@ fn request_outbound_transfer_success() { RuntimeOrigin::root(), parameters )); - - Balances::set_balance(RuntimeOrigin::root(), account!(1), joy!(1020), joy!(0)).unwrap(); + let inital_balance = joy!(1020); + let sender = account!(1); + Balances::set_balance(RuntimeOrigin::root(), sender, inital_balance, joy!(0)).unwrap(); let remote_account = RemoteAccount { account: [0; 32], chain_id: 1, }; + + let transfer_amount = joy!(1000); + let transfer_id = ArgoBridge::next_transfer_id(); let result = ArgoBridge::request_outbound_transfer( - RuntimeOrigin::signed(account!(1)), + RuntimeOrigin::signed(sender), remote_account, - joy!(1000), - joy!(fee), + transfer_amount, + fee, ); assert_ok!(result); + assert_eq!(ArgoBridge::mint_allowance(), transfer_amount); + assert_eq!( + Balances::free_balance(sender), + inital_balance - transfer_amount - fee + ); + last_event_eq!(RawEvent::OutboundTransferRequested( + transfer_id, + sender, + remote_account, + transfer_amount, + fee + )); }); } @@ -68,14 +85,18 @@ fn request_outbound_transfer_with_bridge_paused() { ArgoBridge::pause_bridge(RuntimeOrigin::signed(account!(2))).unwrap(); + let sender = account!(1); + let transfer_amount = joy!(1000); + Balances::set_balance(RuntimeOrigin::root(), sender, transfer_amount, joy!(0)).unwrap(); + let remote_account = RemoteAccount { account: [0; 32], chain_id: 1, }; let result = ArgoBridge::request_outbound_transfer( - RuntimeOrigin::signed(account!(1)), + RuntimeOrigin::signed(sender), remote_account, - joy!(1000), + transfer_amount, fee, ); assert_err!(result, Error::::BridgeNotActive); @@ -159,6 +180,43 @@ fn request_outbound_transfer_with_unexpected_fee() { }); } +#[test] +fn request_outbound_transfer_with_not_supported_remote_chain() { + with_test_externalities(|| { + let parameters = BridgeConstraints { + operator_account: Some(account!(1)), + pauser_accounts: Some(vec![account!(2), account!(3)]), + bridging_fee: Some(joy!(20)), + thawn_duration: None, + remote_chains: Some(BoundedVec::try_from(vec![1u32]).unwrap()), + }; + assert_ok!(ArgoBridge::update_bridge_constrains( + RuntimeOrigin::root(), + parameters + )); + + let transfer_amount = joy!(1000); + assert_ok!(Balances::set_balance( + RuntimeOrigin::root(), + account!(1), + transfer_amount + 50, + joy!(0) + )); + + let remote_account = RemoteAccount { + account: [0; 32], + chain_id: 2, + }; + let result = ArgoBridge::request_outbound_transfer( + RuntimeOrigin::signed(account!(1)), + remote_account, + transfer_amount, + joy!(10), + ); + assert_err!(result, Error::::NotSupportedRemoteChainId); + }); +} + #[test] fn finalize_inbound_transfer_success() { with_test_externalities_custom_mint_allowance(joy!(1000), || { @@ -170,19 +228,23 @@ fn finalize_inbound_transfer_success() { thawn_duration: None, remote_chains: Some(remote_chains), }; - assert_ok!(ArgoBridge::update_bridge_constrains( - RuntimeOrigin::root(), - parameters - )); + ArgoBridge::update_bridge_constrains(RuntimeOrigin::root(), parameters).unwrap(); - let remote_transfer = RemoteTransfer { id: 0, chain_id: 1 }; + let transfer_amount = joy!(1000); + let dest_account = account!(2); let result = ArgoBridge::finalize_inbound_transfer( RuntimeOrigin::signed(account!(1)), - remote_transfer, - account!(2), - 1000, + RemoteTransfer { id: 0, chain_id: 1 }, + dest_account, + transfer_amount, ); - assert_err!(result, Error::::InsufficienBridgMintAllowance); + assert_ok!(result); + assert_eq!(Balances::free_balance(dest_account), transfer_amount); + last_event_eq!(RawEvent::InboundTransferFinalized( + RemoteTransfer { id: 0, chain_id: 1 }, + dest_account, + transfer_amount + )); }); } @@ -196,7 +258,7 @@ fn finalize_inbound_transfer_with_no_operator_account() { account!(2), 1000, ); - assert_err!(result, Error::::NotOperatorAccount); + assert_err!(result, Error::::OperatorAccountNotSet); }); } @@ -250,16 +312,17 @@ fn finalize_inbound_transfer_with_insufficient_bridge_mint() { account!(2), 1000, ); - assert_err!(result, Error::::InsufficienBridgMintAllowance); + assert_err!(result, Error::::InsufficientBridgeMintAllowance); }); } #[test] fn pause_bridge_success() { with_test_externalities(|| { + let pauser_account = account!(2); let parameters = BridgeConstraints { operator_account: None, - pauser_accounts: Some(vec![account!(2)]), + pauser_accounts: Some(vec![pauser_account]), bridging_fee: None, thawn_duration: None, remote_chains: None, @@ -268,12 +331,16 @@ fn pause_bridge_success() { RuntimeOrigin::root(), parameters )); - assert_ok!(ArgoBridge::pause_bridge(RuntimeOrigin::signed(account!(2)))); + + assert_ok!(ArgoBridge::pause_bridge(RuntimeOrigin::signed( + pauser_account + ))); + last_event_eq!(RawEvent::BridgePaused(pauser_account)); }); } #[test] -fn pause_bridge_with_unathorized_account() { +fn pause_bridge_with_unauthorized_account() { with_test_externalities(|| { let parameters = BridgeConstraints { operator_account: None, @@ -318,6 +385,7 @@ fn unpause_bridge_success() { assert_ok!(ArgoBridge::finish_unpause_bridge(RuntimeOrigin::signed( account!(1) ))); + last_event_eq!(RawEvent::BridgeThawnFinished()); }); } @@ -325,8 +393,9 @@ fn unpause_bridge_success() { fn unpause_bridge_during_thawn() { with_test_externalities(|| { let thawn_duration: BlockNumber = 2; + let operator = account!(1); let parameters = BridgeConstraints { - operator_account: Some(account!(1)), + operator_account: Some(operator), pauser_accounts: Some(vec![account!(2)]), bridging_fee: None, thawn_duration: Some(thawn_duration), @@ -345,13 +414,34 @@ fn unpause_bridge_during_thawn() { } ); increase_block_number_by(1); - let result = ArgoBridge::finish_unpause_bridge(RuntimeOrigin::signed(account!(1))); + let result = ArgoBridge::finish_unpause_bridge(RuntimeOrigin::signed(operator)); assert_err!(result, Error::::ThawnNotFinished); }); } #[test] -fn init_unpause_bridge_with_unathorized_account() { +fn unpause_bridge_without_operator_account() { + with_test_externalities(|| { + let thawn_duration: BlockNumber = 1; + let parameters = BridgeConstraints { + operator_account: None, + pauser_accounts: Some(vec![account!(2)]), + bridging_fee: None, + thawn_duration: Some(thawn_duration), + remote_chains: None, + }; + ArgoBridge::update_bridge_constrains(RuntimeOrigin::root(), parameters).unwrap(); + ArgoBridge::init_unpause_bridge(RuntimeOrigin::signed(account!(2))).unwrap(); + + increase_block_number_by(1); + + let result = ArgoBridge::finish_unpause_bridge(RuntimeOrigin::signed(account!(1))); + assert_err!(result, Error::::OperatorAccountNotSet); + }); +} + +#[test] +fn init_unpause_bridge_with_unauthorized_account() { with_test_externalities(|| { let parameters = BridgeConstraints { operator_account: Some(account!(1)), From 53302211baed9f334ab2eef75e27e30cffb75c05 Mon Sep 17 00:00:00 2001 From: Ricardo Date: Wed, 29 May 2024 03:15:59 +0100 Subject: [PATCH 04/16] fix: use the right destination account on finalize_inbound_transfer --- runtime-modules/argo-bridge/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/runtime-modules/argo-bridge/src/lib.rs b/runtime-modules/argo-bridge/src/lib.rs index 9942d94e1f..eb613a232c 100644 --- a/runtime-modules/argo-bridge/src/lib.rs +++ b/runtime-modules/argo-bridge/src/lib.rs @@ -116,18 +116,18 @@ decl_module! { #[weight = WeightInfoArgo::::finalize_inbound_transfer()] pub fn finalize_inbound_transfer(origin, remote_transfer: RemoteTransfer, dest_account: T::AccountId, amount: BalanceOf) -> DispatchResult { - ensure!(!Self::operator_account().is_none(), Error::::NotOperatorAccount); + ensure!(!Self::operator_account().is_none(), Error::::OperatorAccountNotSet); let caller = ensure_signed(origin)?; ensure!(caller == Self::operator_account().unwrap(), Error::::NotOperatorAccount); ensure!(Self::status() == BridgeStatus::Active, Error::::BridgeNotActive); - ensure!(amount < Self::mint_allowance(), Error::::InsufficienBridgMintAllowance); + ensure!(amount <= Self::mint_allowance(), Error::::InsufficientBridgeMintAllowance); ensure!(RemoteChains::get().contains(&remote_transfer.chain_id), Error::::NotSupportedRemoteChainId); >::put(Self::mint_allowance() - amount); let _ = balances::Pallet::::deposit_creating( - &caller, + &dest_account, amount ); From cbde78cfe9f736225dee9d81a3cbcbe20134ef48 Mon Sep 17 00:00:00 2001 From: Ricardo Date: Wed, 29 May 2024 03:17:29 +0100 Subject: [PATCH 05/16] fix: Argo Bridge - add new error (OperatorAccountNotSet) --- runtime-modules/argo-bridge/src/errors.rs | 7 +++++-- runtime-modules/argo-bridge/src/events.rs | 3 ++- runtime-modules/argo-bridge/src/lib.rs | 9 +++++---- runtime-modules/argo-bridge/src/types.rs | 2 +- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/runtime-modules/argo-bridge/src/errors.rs b/runtime-modules/argo-bridge/src/errors.rs index 7d5f668257..1819059f9b 100644 --- a/runtime-modules/argo-bridge/src/errors.rs +++ b/runtime-modules/argo-bridge/src/errors.rs @@ -15,18 +15,21 @@ decl_error! { FeeDifferentThanExpected, /// Not enough mint allowance for transaction - InsufficienBridgMintAllowance, + InsufficientBridgeMintAllowance, /// Operator account required NotOperatorAccount, + /// Operator was not yet set + OperatorAccountNotSet, + /// Pauser account required NotPauserAccount, /// Number of pauser accounts over the maximum allowed InvalidNumberOfPauserAccounts, - /// Current block is lower than thawn_started_at + thawn_duration + /// Current block is lower than thawn_ends_at ThawnNotFinished, /// ChainId is not on the list of the supported chains diff --git a/runtime-modules/argo-bridge/src/events.rs b/runtime-modules/argo-bridge/src/events.rs index 7facc1cb53..1d2e7e05a8 100644 --- a/runtime-modules/argo-bridge/src/events.rs +++ b/runtime-modules/argo-bridge/src/events.rs @@ -15,11 +15,12 @@ decl_event!( AccountId = ::AccountId, Balance = BalanceOf, BridgeConstraints = BridgeConstraintsOf, + BlockNumber = ::BlockNumber, { OutboundTransferRequested(TransferId, AccountId, RemoteAccount, Balance, Balance), InboundTransferFinalized(RemoteTransfer, AccountId, Balance), BridgePaused(AccountId), - BridgeThawnStarted(AccountId), + BridgeThawnStarted(AccountId, BlockNumber), BridgeThawnFinished(), BridgeConfigUpdated(BridgeConstraints), } diff --git a/runtime-modules/argo-bridge/src/lib.rs b/runtime-modules/argo-bridge/src/lib.rs index eb613a232c..278c5d4f81 100644 --- a/runtime-modules/argo-bridge/src/lib.rs +++ b/runtime-modules/argo-bridge/src/lib.rs @@ -69,7 +69,7 @@ decl_storage! { generate_storage_info pub PauserAccounts get(fn pauser_accounts): BoundedVec; /// Number of tokens that the bridge pallet is able to mint - pub MintAllowance get(fn mint_allowance) config(): BalanceOf; + pub MintAllowance get(fn mint_allowance) config(): BalanceOf = 0u32.into(); /// Amount of JOY burned as a fee for each transfer pub BridgingFee get(fn bridging_fee) config(): BalanceOf; @@ -154,8 +154,9 @@ decl_module! { ensure!(Self::pauser_accounts().contains(&caller), Error::::NotPauserAccount); let current_block = >::block_number(); - >::put(BridgeStatus::Thawn { thawn_ends_at: current_block + Self::thawn_duration()}); - Self::deposit_event(RawEvent::BridgeThawnStarted(caller)); + let thawn_end_block = current_block + Self::thawn_duration(); + >::put(BridgeStatus::Thawn { thawn_ends_at: thawn_end_block}); + Self::deposit_event(RawEvent::BridgeThawnStarted(caller, thawn_end_block)); Ok(()) } @@ -163,7 +164,7 @@ decl_module! { #[weight = WeightInfoArgo::::finish_unpause_bridge()] pub fn finish_unpause_bridge(origin) -> DispatchResult { let caller = ensure_signed(origin)?; - ensure!(!Self::operator_account().is_none(), Error::::NotOperatorAccount); + ensure!(!Self::operator_account().is_none(), Error::::OperatorAccountNotSet); ensure!(caller == Self::operator_account().unwrap(), Error::::NotOperatorAccount); let current_block = >::block_number(); diff --git a/runtime-modules/argo-bridge/src/types.rs b/runtime-modules/argo-bridge/src/types.rs index 3b21d47c04..018e8dba04 100644 --- a/runtime-modules/argo-bridge/src/types.rs +++ b/runtime-modules/argo-bridge/src/types.rs @@ -31,7 +31,7 @@ pub type BridgeConstraintsOf = BridgeConstraints< #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)] pub struct RemoteAccount { - // Ethereum addresses only need 20 bytes but we use 32 bytes to enable compatibility with other chains + // EVM-based addresses only need 20 bytes but we use 32 bytes to enable compatibility with other chains // When using Ethereum addresses, the last 12 bytes should be zero pub account: [u8; 32], pub chain_id: ChainId, From c649652170cf5f021e20287c39ea8d63797e0035 Mon Sep 17 00:00:00 2001 From: Ricardo Date: Thu, 30 May 2024 05:32:13 +0100 Subject: [PATCH 06/16] add const for number of max remote chains --- runtime-modules/argo-bridge/src/lib.rs | 11 +++++++++++ runtime-modules/argo-bridge/src/tests/mod.rs | 9 +++++---- runtime-modules/argo-bridge/src/types.rs | 4 +++- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/runtime-modules/argo-bridge/src/lib.rs b/runtime-modules/argo-bridge/src/lib.rs index 278c5d4f81..dcf652d69b 100644 --- a/runtime-modules/argo-bridge/src/lib.rs +++ b/runtime-modules/argo-bridge/src/lib.rs @@ -49,6 +49,7 @@ pub trait Config: frame_system::Config + balances::Config { // /// Events type RuntimeEvent: From> + Into<::RuntimeEvent>; + /// Max number of accounts allow to pause the bridge type MaxPauserAccounts: Get; /// Weight information for extrinsics in this pallet. @@ -178,6 +179,16 @@ decl_module! { Ok(()) } + /// Allow Governance to Set constraints + /// Preconditions: + /// - origin is signed by `root` + /// PostConditions: + /// - governance parameters storage value set to the provided values + /// + /// + /// ## Weight + /// `O (1)` + /// # #[weight = WeightInfoArgo::::update_bridge_constrains()] pub fn update_bridge_constrains(origin, parameters: BridgeConstraintsOf) -> DispatchResult { ensure_root(origin)?; diff --git a/runtime-modules/argo-bridge/src/tests/mod.rs b/runtime-modules/argo-bridge/src/tests/mod.rs index 26a83382c5..1a2cc5c728 100644 --- a/runtime-modules/argo-bridge/src/tests/mod.rs +++ b/runtime-modules/argo-bridge/src/tests/mod.rs @@ -18,7 +18,7 @@ use self::mock::{ }; use crate::Error; -mod mock; +pub mod mock; #[test] fn request_outbound_transfer_success() { @@ -36,9 +36,9 @@ fn request_outbound_transfer_success() { RuntimeOrigin::root(), parameters )); - let inital_balance = joy!(1020); + let initial_balance = joy!(1020); let sender = account!(1); - Balances::set_balance(RuntimeOrigin::root(), sender, inital_balance, joy!(0)).unwrap(); + Balances::set_balance(RuntimeOrigin::root(), sender, initial_balance, joy!(0)).unwrap(); let remote_account = RemoteAccount { account: [0; 32], @@ -57,7 +57,7 @@ fn request_outbound_transfer_success() { assert_eq!(ArgoBridge::mint_allowance(), transfer_amount); assert_eq!( Balances::free_balance(sender), - inital_balance - transfer_amount - fee + initial_balance - transfer_amount - fee ); last_event_eq!(RawEvent::OutboundTransferRequested( transfer_id, @@ -335,6 +335,7 @@ fn pause_bridge_success() { assert_ok!(ArgoBridge::pause_bridge(RuntimeOrigin::signed( pauser_account ))); + assert_eq!(ArgoBridge::status(), BridgeStatus::Paused); last_event_eq!(RawEvent::BridgePaused(pauser_account)); }); } diff --git a/runtime-modules/argo-bridge/src/types.rs b/runtime-modules/argo-bridge/src/types.rs index 018e8dba04..73204fe0da 100644 --- a/runtime-modules/argo-bridge/src/types.rs +++ b/runtime-modules/argo-bridge/src/types.rs @@ -12,6 +12,8 @@ pub type BalanceOf = ::Balance; pub type ChainId = u32; pub type TransferId = u64; +pub const MAX_REMOTE_CHAINS: u32 = 10; + #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)] pub struct BridgeConstraints { @@ -19,7 +21,7 @@ pub struct BridgeConstraints { pub pauser_accounts: Option>, pub bridging_fee: Option, pub thawn_duration: Option, - pub remote_chains: Option>>, + pub remote_chains: Option>>, } pub type BridgeConstraintsOf = BridgeConstraints< From 6fe1642ccf1d7b10ea374053be816ce41e28cca6 Mon Sep 17 00:00:00 2001 From: Ricardo Date: Thu, 30 May 2024 05:32:57 +0100 Subject: [PATCH 07/16] Add Argo Bridge benchmark tests --- .../argo-bridge/src/benchmarking.rs | 225 +++++++++++++++++- 1 file changed, 214 insertions(+), 11 deletions(-) diff --git a/runtime-modules/argo-bridge/src/benchmarking.rs b/runtime-modules/argo-bridge/src/benchmarking.rs index 2a27e23dc3..03dcf151eb 100644 --- a/runtime-modules/argo-bridge/src/benchmarking.rs +++ b/runtime-modules/argo-bridge/src/benchmarking.rs @@ -4,15 +4,15 @@ use frame_support::{assert_err, assert_ok}; use super::*; use crate::types::*; +use crate::vec::Vec; use crate::Module as ArgoBridge; use balances::Pallet as Balances; use core::convert::TryFrom; use frame_benchmarking::v1::{account, benchmarks}; use frame_system::Pallet as System; use frame_system::{EventRecord, RawOrigin}; -use sp_runtime::traits::One; +use sp_runtime::traits::{One, StaticLookup}; use sp_std::convert::TryInto; -use sp_std::vec; use crate::{BridgeConstraints, BridgeStatus, RemoteAccount, RemoteTransfer}; @@ -65,36 +65,239 @@ benchmarks! { T::AccountId: CreateAccountId } + // Worst case scenario: + // - max number of remote chains being use + // - using the last chain request_outbound_transfer{ let fee: BalanceOf = 10u32.into(); - let remote_chains = BoundedVec::try_from(vec![1u32]).unwrap(); + let remote_chains: Vec = (0..MAX_REMOTE_CHAINS).collect(); let parameters = BridgeConstraints { operator_account: Some(T::AccountId::create_account_id(1u32.into())), - pauser_accounts: Some(vec![T::AccountId::create_account_id(2u32.into())]), + pauser_accounts: None, bridging_fee: Some(fee), thawn_duration: None::, - remote_chains: Some(remote_chains) + remote_chains: Some(BoundedVec::try_from(remote_chains).unwrap()) }; + assert_ok!(ArgoBridge::::update_bridge_constrains( RawOrigin::Root.into(), parameters )); + let initial_balance: u32 = 1020u32.into(); + let sender = T::AccountId::create_account_id(1u32.into()); + let lookup_sender = T::Lookup::unlookup(sender.clone()); + Balances::::set_balance(RawOrigin::Root.into(), lookup_sender, + initial_balance.into(), 0u32.into()).unwrap(); + let dest_account = RemoteAccount { account: [0; 32], - chain_id: 1, + chain_id: MAX_REMOTE_CHAINS - 1, }; - let sender = T::AccountId::create_account_id(1u32.into()); let origin = RawOrigin::Signed(sender); let transfer_id = ArgoBridge::::next_transfer_id(); - let amount = 100u32.into(); - }: _(origin, dest_account, amount, fee) + let transfer_amount = 1000u32.into(); + }: _(origin, dest_account, transfer_amount, fee) verify { let sender = T::AccountId::create_account_id(1u32.into()); assert_last_event::( - RawEvent::OutboundTransferRequested(transfer_id, sender, dest_account, amount, fee).into()); + RawEvent::OutboundTransferRequested(transfer_id, sender, dest_account, transfer_amount, fee).into()); + } + + + // Worst case scenario: + // - max number of remote chains being use + // - using the last chain + finalize_inbound_transfer{ + let fee: BalanceOf = 10u32.into(); + let remote_chains: Vec = (0..MAX_REMOTE_CHAINS).collect(); + let parameters = BridgeConstraints { + operator_account: Some(T::AccountId::create_account_id(1u32.into())), + pauser_accounts: None, + bridging_fee: Some(fee), + thawn_duration: None::, + remote_chains: Some(BoundedVec::try_from(remote_chains).unwrap()) + }; + + assert_ok!(ArgoBridge::::update_bridge_constrains( + RawOrigin::Root.into(), + parameters + )); + + let sender = T::AccountId::create_account_id(1u32.into()); + let dest_account = T::AccountId::create_account_id(1u32.into()); + + let transfer_amount = 100u32.into(); + let remote_transfer = RemoteTransfer { id: 0, chain_id: MAX_REMOTE_CHAINS - 1 }; + }: _(RawOrigin::Signed(sender), remote_transfer.clone(), dest_account.clone(), transfer_amount) + verify { + assert_last_event::( + RawEvent::InboundTransferFinalized(remote_transfer, dest_account, transfer_amount).into()); + } + + // Worst case scenario: + // - max number of pauser accounts being use + // - using the last pauser account + pause_bridge{ + let mut pauser_accounts :Vec = Vec::new(); + for i in 0u32..T::MaxPauserAccounts::get() { + pauser_accounts.push(T::AccountId::create_account_id(i)); + } + let parameters = BridgeConstraints { + operator_account: None, + pauser_accounts: Some(pauser_accounts), + bridging_fee: None, + thawn_duration: None::, + remote_chains: None + }; + + assert_ok!(ArgoBridge::::update_bridge_constrains( + RawOrigin::Root.into(), + parameters + )); + + let pauser_acount = T::AccountId::create_account_id((T::MaxPauserAccounts::get() - 1).into()); + }: _(RawOrigin::Signed(pauser_acount.clone())) + verify { + assert_eq!(ArgoBridge::::status(), BridgeStatus::Paused); + assert_last_event::( + RawEvent::BridgePaused(pauser_acount.clone()).into()); + } + + // Worst case scenario: + // - max number of pauser accounts being use + // - using the last pauser account + init_unpause_bridge{ + let pauser_accounts: Vec = (0..T::MaxPauserAccounts::get()) + .map(|i| T::AccountId::create_account_id(i)) + .collect(); + let parameters = BridgeConstraints { + operator_account: None, + pauser_accounts: Some(pauser_accounts), + bridging_fee: None, + thawn_duration: Some(1u32.into()), + remote_chains: None + }; + + assert_ok!(ArgoBridge::::update_bridge_constrains( + RawOrigin::Root.into(), + parameters + )); + + let pauser_acount = T::AccountId::create_account_id((T::MaxPauserAccounts::get() - 1) .into()); + ArgoBridge::::pause_bridge(RawOrigin::Signed(pauser_acount.clone()).into()).unwrap(); + }: _(RawOrigin::Signed(pauser_acount.clone())) + verify { + let current_block = System::::block_number(); + assert_last_event::( + RawEvent::BridgeThawnStarted(pauser_acount, current_block + 1u32.into()).into()); + } + + // Worst case scenario: + // - max number of pauser accounts being use + // - using the last pauser account + finish_unpause_bridge{ + let pauser_accounts: Vec = (0..T::MaxPauserAccounts::get()) + .map(|i| T::AccountId::create_account_id(i)) + .collect(); + let operator_account = T::AccountId::create_account_id(1u32.into()); + let parameters = BridgeConstraints { + operator_account: Some(operator_account.clone().into()), + pauser_accounts: Some(pauser_accounts), + bridging_fee: None, + thawn_duration: Some(1u32.into()), + remote_chains: None + }; + + assert_ok!(ArgoBridge::::update_bridge_constrains( + RawOrigin::Root.into(), + parameters + )); + + let pauser_acount = T::AccountId::create_account_id((T::MaxPauserAccounts::get() - 1) .into()); + let origin = RawOrigin::Signed(pauser_acount.clone()); + ArgoBridge::::pause_bridge(origin.clone().into()).unwrap(); + ArgoBridge::::init_unpause_bridge(origin.into()).unwrap(); + System::::set_block_number(3u32.into()); + }: _(RawOrigin::Signed(operator_account)) + verify { + let current_block = System::::block_number(); + assert_last_event::( + RawEvent::BridgeThawnFinished().into()); + } + + // Worst case scenario: + // - update all parameters + update_bridge_constrains{ + let fee: BalanceOf = 10u32.into(); + let pauser_accounts: Vec = (0..T::MaxPauserAccounts::get()) + .map(|i| T::AccountId::create_account_id(i)) + .collect(); + let remote_chains: Vec = (0..MAX_REMOTE_CHAINS).collect(); + + let parameters = BridgeConstraints { + operator_account: Some(T::AccountId::create_account_id(1u32.into())), + pauser_accounts: Some(pauser_accounts), + bridging_fee: Some(fee), + thawn_duration: Some(1u32.into()), + remote_chains: Some(BoundedVec::try_from(remote_chains).unwrap()) + }; + + }: _(RawOrigin::Root, parameters.clone()) + verify { + assert_last_event::( + RawEvent::BridgeConfigUpdated(parameters).into()); } } #[cfg(test)] -mod tests {} +mod tests { + use crate::tests::mock::{ + with_test_externalities, with_test_externalities_custom_mint_allowance, Test, + }; + use frame_support::assert_ok; + + type ArgoBridge = crate::Module; + + #[test] + fn test_request_outbound_transfer() { + with_test_externalities(|| { + assert_ok!(ArgoBridge::test_benchmark_request_outbound_transfer()); + }); + } + + #[test] + fn test_finalize_inbound_transfer() { + with_test_externalities_custom_mint_allowance(1000u32.into(), || { + assert_ok!(ArgoBridge::test_benchmark_finalize_inbound_transfer()); + }); + } + + #[test] + fn test_pause_bridge() { + with_test_externalities(|| { + assert_ok!(ArgoBridge::test_benchmark_pause_bridge()); + }); + } + + #[test] + fn test_init_unpause_bridge() { + with_test_externalities(|| { + assert_ok!(ArgoBridge::test_benchmark_init_unpause_bridge()); + }); + } + + #[test] + fn test_finish_unpause_bridge() { + with_test_externalities(|| { + assert_ok!(ArgoBridge::test_benchmark_finish_unpause_bridge()); + }); + } + + #[test] + fn test_init_update_bridge_constrains() { + with_test_externalities(|| { + assert_ok!(ArgoBridge::test_benchmark_update_bridge_constrains()); + }); + } +} From 60830b1308a1bd2f8db681e27285b68ca671e808 Mon Sep 17 00:00:00 2001 From: Ricardo Date: Thu, 30 May 2024 11:04:01 +0100 Subject: [PATCH 08/16] change RemoteAccount comment --- runtime-modules/argo-bridge/src/types.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime-modules/argo-bridge/src/types.rs b/runtime-modules/argo-bridge/src/types.rs index 73204fe0da..25b674bab9 100644 --- a/runtime-modules/argo-bridge/src/types.rs +++ b/runtime-modules/argo-bridge/src/types.rs @@ -33,8 +33,8 @@ pub type BridgeConstraintsOf = BridgeConstraints< #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)] pub struct RemoteAccount { - // EVM-based addresses only need 20 bytes but we use 32 bytes to enable compatibility with other chains - // When using Ethereum addresses, the last 12 bytes should be zero + // Ethereum addresses only need 20 bytes but we use 32 bytes to enable compatibility with other chains + // When using EVM addresses, the 12 most-significant bytes should be zero pub account: [u8; 32], pub chain_id: ChainId, } From 8f3c830b4ac157bd662fb3f35ca7d6ba4f5f3e09 Mon Sep 17 00:00:00 2001 From: Ricardo Date: Thu, 30 May 2024 11:04:50 +0100 Subject: [PATCH 09/16] bump spec version to 2004 --- runtime/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index b5384d885d..f104cbf8bd 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -147,7 +147,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("joystream-node"), impl_name: create_runtime_str!("joystream-node"), authoring_version: 12, - spec_version: 2003, + spec_version: 2004, impl_version: 0, apis: crate::runtime_api::EXPORTED_RUNTIME_API_VERSIONS, transaction_version: 2, @@ -1994,7 +1994,6 @@ construct_runtime!( Content: content::{Pallet, Call, Storage, Event, Config}, Storage: storage::{Pallet, Call, Storage, Event, Config}, ProjectToken: project_token::{Pallet, Call, Storage, Event, Config}, - ArgoBridge: argo_bridge::{Pallet, Call, Storage, Event, Config}, // --- Proposals ProposalsEngine: proposals_engine::{Pallet, Call, Storage, Event}, ProposalsDiscussion: proposals_discussion::{Pallet, Call, Storage, Event, Config}, @@ -2010,6 +2009,7 @@ construct_runtime!( OperationsWorkingGroupGamma: working_group::::{Pallet, Call, Storage, Event}, DistributionWorkingGroup: working_group::::{Pallet, Call, Storage, Event}, Proxy: pallet_proxy, + ArgoBridge: argo_bridge::{Pallet, Call, Storage, Event, Config}, } ); From e1db690f11e4a954ca1da95439f0aa4f69e6971b Mon Sep 17 00:00:00 2001 From: Ricardo Date: Fri, 31 May 2024 01:05:38 +0100 Subject: [PATCH 10/16] add Argo Bridge pallet to benchmarks definition --- runtime/src/runtime_api.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/src/runtime_api.rs b/runtime/src/runtime_api.rs index 8d3a06316a..c57e968e51 100644 --- a/runtime/src/runtime_api.rs +++ b/runtime/src/runtime_api.rs @@ -127,6 +127,7 @@ mod benches { [content, Content] [project_token, ProjectToken] [pallet_proxy, Proxy] + [argo_bridge, ArgoBridge] ); } From 3c20a1fcea4cf89d5d7bd4285983c924eb6c6482 Mon Sep 17 00:00:00 2001 From: Ricardo Date: Fri, 31 May 2024 13:01:20 +0100 Subject: [PATCH 11/16] tests: add benchmarking tests to Argo Bridge pallet --- .../argo-bridge/src/benchmarking.rs | 122 +++++++++++------- 1 file changed, 76 insertions(+), 46 deletions(-) diff --git a/runtime-modules/argo-bridge/src/benchmarking.rs b/runtime-modules/argo-bridge/src/benchmarking.rs index 03dcf151eb..4e4b90fd2c 100644 --- a/runtime-modules/argo-bridge/src/benchmarking.rs +++ b/runtime-modules/argo-bridge/src/benchmarking.rs @@ -1,7 +1,5 @@ #![cfg(feature = "runtime-benchmarks")] -use frame_support::{assert_err, assert_ok}; - use super::*; use crate::types::*; use crate::vec::Vec; @@ -11,8 +9,6 @@ use core::convert::TryFrom; use frame_benchmarking::v1::{account, benchmarks}; use frame_system::Pallet as System; use frame_system::{EventRecord, RawOrigin}; -use sp_runtime::traits::{One, StaticLookup}; -use sp_std::convert::TryInto; use crate::{BridgeConstraints, BridgeStatus, RemoteAccount, RemoteTransfer}; @@ -58,10 +54,39 @@ fn assert_last_event(generic_event: ::RuntimeEvent) { assert_eq!(event, &system_event); } +fn activate_bridge(pauser_acount: &T::AccountId, operator_acount: &T::AccountId) { + let pauser_origin = RawOrigin::Signed(pauser_acount.clone()); + ArgoBridge::::init_unpause_bridge(pauser_origin.clone().into()).unwrap(); + System::::set_block_number(3u32.into()); + ArgoBridge::::finish_unpause_bridge(RawOrigin::Signed(operator_acount.clone()).into()) + .unwrap(); +} + +fn set_bridge_mint_allowance(amount: BalanceOf, fee: BalanceOf) +where + T::AccountId: CreateAccountId, +{ + let sender = T::AccountId::create_account_id(1u32.into()); + let _ = Balances::::deposit_creating( + &sender, + T::ExistentialDeposit::get() + amount.into() + fee + 10u32.into(), + ); + let remote_account = RemoteAccount { + account: [0; 32], + chain_id: MAX_REMOTE_CHAINS - 1, + }; + ArgoBridge::::request_outbound_transfer( + RawOrigin::Signed(sender.clone()).into(), + remote_account, + amount + fee, + fee, + ) + .unwrap(); +} + benchmarks! { where_clause { where - T: balances::Config, T::AccountId: CreateAccountId } @@ -70,25 +95,26 @@ benchmarks! { // - using the last chain request_outbound_transfer{ let fee: BalanceOf = 10u32.into(); - let remote_chains: Vec = (0..MAX_REMOTE_CHAINS).collect(); + let remote_chains: Vec = (0..MAX_REMOTE_CHAINS).collect(); + let pauser_acount = T::AccountId::create_account_id(1); + let operator_account = T::AccountId::create_account_id(1u32.into()); let parameters = BridgeConstraints { - operator_account: Some(T::AccountId::create_account_id(1u32.into())), - pauser_accounts: None, + operator_account: Some(operator_account.clone()), + pauser_accounts: Some(vec![pauser_acount.clone().into()]), bridging_fee: Some(fee), thawn_duration: None::, remote_chains: Some(BoundedVec::try_from(remote_chains).unwrap()) }; - assert_ok!(ArgoBridge::::update_bridge_constrains( + ArgoBridge::::update_bridge_constrains( RawOrigin::Root.into(), parameters - )); + ).unwrap(); + activate_bridge::(&pauser_acount, &operator_account); - let initial_balance: u32 = 1020u32.into(); + let initial_balance: u32 = 1030u32.into(); let sender = T::AccountId::create_account_id(1u32.into()); - let lookup_sender = T::Lookup::unlookup(sender.clone()); - Balances::::set_balance(RawOrigin::Root.into(), lookup_sender, - initial_balance.into(), 0u32.into()).unwrap(); + let _ = Balances::::deposit_creating(&sender, T::ExistentialDeposit::get() + initial_balance.into()); let dest_account = RemoteAccount { account: [0; 32], @@ -96,7 +122,7 @@ benchmarks! { }; let origin = RawOrigin::Signed(sender); let transfer_id = ArgoBridge::::next_transfer_id(); - let transfer_amount = 1000u32.into(); + let transfer_amount = 100u32.into(); }: _(origin, dest_account, transfer_amount, fee) verify { let sender = T::AccountId::create_account_id(1u32.into()); @@ -111,25 +137,28 @@ benchmarks! { finalize_inbound_transfer{ let fee: BalanceOf = 10u32.into(); let remote_chains: Vec = (0..MAX_REMOTE_CHAINS).collect(); + let pauser_acount = T::AccountId::create_account_id(1); + let operator_account = T::AccountId::create_account_id(1u32.into()); let parameters = BridgeConstraints { - operator_account: Some(T::AccountId::create_account_id(1u32.into())), - pauser_accounts: None, + operator_account: Some(operator_account.clone()), + pauser_accounts: Some(vec![pauser_acount.clone().into()]), bridging_fee: Some(fee), - thawn_duration: None::, + thawn_duration: Some(1u32.into()), remote_chains: Some(BoundedVec::try_from(remote_chains).unwrap()) }; - - assert_ok!(ArgoBridge::::update_bridge_constrains( + ArgoBridge::::update_bridge_constrains( RawOrigin::Root.into(), parameters - )); - - let sender = T::AccountId::create_account_id(1u32.into()); - let dest_account = T::AccountId::create_account_id(1u32.into()); + ).unwrap(); + activate_bridge::(&pauser_acount, &operator_account); let transfer_amount = 100u32.into(); + set_bridge_mint_allowance::(1030u32.into(), fee); + + let operator = T::AccountId::create_account_id(1u32.into()); + let dest_account = T::AccountId::create_account_id(1u32.into()); let remote_transfer = RemoteTransfer { id: 0, chain_id: MAX_REMOTE_CHAINS - 1 }; - }: _(RawOrigin::Signed(sender), remote_transfer.clone(), dest_account.clone(), transfer_amount) + }: _(RawOrigin::Signed(operator), remote_transfer.clone(), dest_account.clone(), transfer_amount) verify { assert_last_event::( RawEvent::InboundTransferFinalized(remote_transfer, dest_account, transfer_amount).into()); @@ -143,18 +172,19 @@ benchmarks! { for i in 0u32..T::MaxPauserAccounts::get() { pauser_accounts.push(T::AccountId::create_account_id(i)); } + let operator_account = T::AccountId::create_account_id(1u32.into()); let parameters = BridgeConstraints { - operator_account: None, - pauser_accounts: Some(pauser_accounts), + operator_account: Some(operator_account.clone()), + pauser_accounts: Some(pauser_accounts.clone()), bridging_fee: None, thawn_duration: None::, remote_chains: None }; - - assert_ok!(ArgoBridge::::update_bridge_constrains( + ArgoBridge::::update_bridge_constrains( RawOrigin::Root.into(), parameters - )); + ).unwrap(); + activate_bridge::(&pauser_accounts[0], &operator_account); let pauser_acount = T::AccountId::create_account_id((T::MaxPauserAccounts::get() - 1).into()); }: _(RawOrigin::Signed(pauser_acount.clone())) @@ -171,18 +201,19 @@ benchmarks! { let pauser_accounts: Vec = (0..T::MaxPauserAccounts::get()) .map(|i| T::AccountId::create_account_id(i)) .collect(); + let operator_account = T::AccountId::create_account_id(1u32.into()); let parameters = BridgeConstraints { - operator_account: None, - pauser_accounts: Some(pauser_accounts), + operator_account: Some(operator_account.clone()), + pauser_accounts: Some(pauser_accounts.clone()), bridging_fee: None, thawn_duration: Some(1u32.into()), remote_chains: None }; - - assert_ok!(ArgoBridge::::update_bridge_constrains( + ArgoBridge::::update_bridge_constrains( RawOrigin::Root.into(), parameters - )); + ).unwrap(); + activate_bridge::(&pauser_accounts[0], &operator_account); let pauser_acount = T::AccountId::create_account_id((T::MaxPauserAccounts::get() - 1) .into()); ArgoBridge::::pause_bridge(RawOrigin::Signed(pauser_acount.clone()).into()).unwrap(); @@ -202,23 +233,23 @@ benchmarks! { .collect(); let operator_account = T::AccountId::create_account_id(1u32.into()); let parameters = BridgeConstraints { - operator_account: Some(operator_account.clone().into()), - pauser_accounts: Some(pauser_accounts), + operator_account: Some(operator_account.clone()), + pauser_accounts: Some(pauser_accounts.clone()), bridging_fee: None, thawn_duration: Some(1u32.into()), remote_chains: None }; - - assert_ok!(ArgoBridge::::update_bridge_constrains( + ArgoBridge::::update_bridge_constrains( RawOrigin::Root.into(), parameters - )); + ).unwrap(); + activate_bridge::(&pauser_accounts[0], &operator_account); let pauser_acount = T::AccountId::create_account_id((T::MaxPauserAccounts::get() - 1) .into()); let origin = RawOrigin::Signed(pauser_acount.clone()); ArgoBridge::::pause_bridge(origin.clone().into()).unwrap(); ArgoBridge::::init_unpause_bridge(origin.into()).unwrap(); - System::::set_block_number(3u32.into()); + System::::set_block_number(System::::block_number() + 3u32.into()); }: _(RawOrigin::Signed(operator_account)) verify { let current_block = System::::block_number(); @@ -233,10 +264,11 @@ benchmarks! { let pauser_accounts: Vec = (0..T::MaxPauserAccounts::get()) .map(|i| T::AccountId::create_account_id(i)) .collect(); + let operator_account = T::AccountId::create_account_id(1u32.into()); let remote_chains: Vec = (0..MAX_REMOTE_CHAINS).collect(); let parameters = BridgeConstraints { - operator_account: Some(T::AccountId::create_account_id(1u32.into())), + operator_account: Some(operator_account), pauser_accounts: Some(pauser_accounts), bridging_fee: Some(fee), thawn_duration: Some(1u32.into()), @@ -252,9 +284,7 @@ benchmarks! { #[cfg(test)] mod tests { - use crate::tests::mock::{ - with_test_externalities, with_test_externalities_custom_mint_allowance, Test, - }; + use crate::tests::mock::{with_test_externalities, Test}; use frame_support::assert_ok; type ArgoBridge = crate::Module; @@ -268,7 +298,7 @@ mod tests { #[test] fn test_finalize_inbound_transfer() { - with_test_externalities_custom_mint_allowance(1000u32.into(), || { + with_test_externalities(|| { assert_ok!(ArgoBridge::test_benchmark_finalize_inbound_transfer()); }); } From afedc96104114d18c7fa6e191031112a62a6cdaa Mon Sep 17 00:00:00 2001 From: Ricardo Date: Fri, 31 May 2024 15:00:10 +0100 Subject: [PATCH 12/16] update Argo Bridge weights --- runtime-modules/argo-bridge/src/weights.rs | 218 ++++++++++++++++----- 1 file changed, 167 insertions(+), 51 deletions(-) diff --git a/runtime-modules/argo-bridge/src/weights.rs b/runtime-modules/argo-bridge/src/weights.rs index 41ab26ca9e..0fd08a2c54 100644 --- a/runtime-modules/argo-bridge/src/weights.rs +++ b/runtime-modules/argo-bridge/src/weights.rs @@ -1,3 +1,39 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for argo_bridge +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2024-05-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("prod-test"), DB CACHE: 1024 + +// Executed Command: +// ./scripts/../target/debug/joystream-node +// benchmark +// pallet +// --pallet=argo-bridge +// --extrinsic=* +// --chain=prod-test +// --steps=50 +// --repeat=20 +// --execution=wasm +// --template=./scripts/../devops/joystream-pallet-weight-template.hbs +// --output=./scripts/../runtime-modules/argo-bridge/src/weights.rs + #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] @@ -6,64 +42,144 @@ use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions needed for project_token. +/// Weight functions needed for argo_bridge. pub trait WeightInfo { - fn request_outbound_transfer() -> Weight; - - fn finalize_inbound_transfer() -> Weight; - - fn pause_bridge() -> Weight; - - fn init_unpause_bridge() -> Weight; - - fn finish_unpause_bridge() -> Weight; - - fn update_bridge_constrains() -> Weight; + fn request_outbound_transfer() -> Weight; + fn finalize_inbound_transfer() -> Weight; + fn pause_bridge() -> Weight; + fn init_unpause_bridge() -> Weight; + fn finish_unpause_bridge() -> Weight; + fn update_bridge_constrains() -> Weight; } -/// Weights for project_token using the Substrate node and recommended hardware. +/// Weights for argo_bridge using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - - fn request_outbound_transfer() -> Weight - { - Weight::from_parts(10_506_000, 0u64) - .saturating_add(Weight::from_parts(0, 0)) + // Storage: ArgoBridge Status (r:1 w:0) + // Proof: ArgoBridge Status (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + // Storage: ArgoBridge RemoteChains (r:1 w:0) + // Proof: ArgoBridge RemoteChains (max_values: Some(1), max_size: Some(41), added: 536, mode: MaxEncodedLen) + // Storage: ArgoBridge BridgingFee (r:1 w:0) + // Proof: ArgoBridge BridgingFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + // Storage: System Account (r:1 w:1) + // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Storage: ArgoBridge MintAllowance (r:1 w:1) + // Proof: ArgoBridge MintAllowance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + // Storage: ArgoBridge NextTransferId (r:1 w:1) + // Proof: ArgoBridge NextTransferId (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + fn request_outbound_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `430` + // Estimated: `11104` + // Minimum execution time: 998_107 nanoseconds. + Weight::from_parts(1_038_838_000, 0u64) + .saturating_add(Weight::from_parts(0, 11104)) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + // Storage: ArgoBridge OperatorAccount (r:1 w:0) + // Proof: ArgoBridge OperatorAccount (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + // Storage: ArgoBridge Status (r:1 w:0) + // Proof: ArgoBridge Status (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + // Storage: ArgoBridge MintAllowance (r:1 w:1) + // Proof: ArgoBridge MintAllowance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + // Storage: ArgoBridge RemoteChains (r:1 w:0) + // Proof: ArgoBridge RemoteChains (max_values: Some(1), max_size: Some(41), added: 536, mode: MaxEncodedLen) + // Storage: System Account (r:1 w:1) + // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn finalize_inbound_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `473` + // Estimated: `9627` + // Minimum execution time: 883_138 nanoseconds. + Weight::from_parts(900_668_000, 0u64) + .saturating_add(Weight::from_parts(0, 9627)) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + // Storage: ArgoBridge PauserAccounts (r:1 w:0) + // Proof: ArgoBridge PauserAccounts (max_values: Some(1), max_size: Some(321), added: 816, mode: MaxEncodedLen) + // Storage: ArgoBridge Status (r:0 w:1) + // Proof: ArgoBridge Status (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + fn pause_bridge() -> Weight { + // Proof Size summary in bytes: + // Measured: `498` + // Estimated: `1806` + // Minimum execution time: 371_039 nanoseconds. + Weight::from_parts(382_129_000, 0u64) + .saturating_add(Weight::from_parts(0, 1806)) + .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) - } - - fn finalize_inbound_transfer() -> Weight - { - Weight::from_parts(10_506_000, 0u64) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - - fn pause_bridge() -> Weight - { - Weight::from_parts(10_506_000, 0u64) - .saturating_add(Weight::from_parts(0, 0)) + } + // Storage: ArgoBridge PauserAccounts (r:1 w:0) + // Proof: ArgoBridge PauserAccounts (max_values: Some(1), max_size: Some(321), added: 816, mode: MaxEncodedLen) + // Storage: ArgoBridge ThawnDuration (r:1 w:0) + // Proof: ArgoBridge ThawnDuration (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + // Storage: ArgoBridge Status (r:0 w:1) + // Proof: ArgoBridge Status (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + fn init_unpause_bridge() -> Weight { + // Proof Size summary in bytes: + // Measured: `498` + // Estimated: `3295` + // Minimum execution time: 402_659 nanoseconds. + Weight::from_parts(420_319_000, 0u64) + .saturating_add(Weight::from_parts(0, 3295)) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) - } - - fn init_unpause_bridge() -> Weight - { - Weight::from_parts(10_506_000, 0u64) - .saturating_add(Weight::from_parts(0, 0)) + } + // Storage: ArgoBridge OperatorAccount (r:1 w:0) + // Proof: ArgoBridge OperatorAccount (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + // Storage: ArgoBridge Status (r:1 w:1) + // Proof: ArgoBridge Status (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + fn finish_unpause_bridge() -> Weight { + // Proof Size summary in bytes: + // Measured: `173` + // Estimated: `3007` + // Minimum execution time: 412_269 nanoseconds. + Weight::from_parts(422_459_000, 0u64) + .saturating_add(Weight::from_parts(0, 3007)) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) - } - - fn finish_unpause_bridge() -> Weight - { - Weight::from_parts(10_506_000, 0u64) + } + // Storage: ArgoBridge RemoteChains (r:0 w:1) + // Proof: ArgoBridge RemoteChains (max_values: Some(1), max_size: Some(41), added: 536, mode: MaxEncodedLen) + // Storage: ArgoBridge PauserAccounts (r:0 w:1) + // Proof: ArgoBridge PauserAccounts (max_values: Some(1), max_size: Some(321), added: 816, mode: MaxEncodedLen) + // Storage: ArgoBridge OperatorAccount (r:0 w:1) + // Proof: ArgoBridge OperatorAccount (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + // Storage: ArgoBridge BridgingFee (r:0 w:1) + // Proof: ArgoBridge BridgingFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + // Storage: ArgoBridge ThawnDuration (r:0 w:1) + // Proof: ArgoBridge ThawnDuration (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn update_bridge_constrains() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 293_519 nanoseconds. + Weight::from_parts(298_009_000, 0u64) .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } + .saturating_add(T::DbWeight::get().writes(5_u64)) + } +} - fn update_bridge_constrains() -> Weight - { - Weight::from_parts(10_506_000, 0u64) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } -} \ No newline at end of file +// Default implementation for tests +impl WeightInfo for () { + fn request_outbound_transfer() -> Weight { + Weight::from_parts(0, 0) + } + fn finalize_inbound_transfer() -> Weight { + Weight::from_parts(0, 0) + } + fn pause_bridge() -> Weight { + Weight::from_parts(0, 0) + } + fn init_unpause_bridge() -> Weight { + Weight::from_parts(0, 0) + } + fn finish_unpause_bridge() -> Weight { + Weight::from_parts(0, 0) + } + fn update_bridge_constrains() -> Weight { + Weight::from_parts(0, 0) + } +} From 0faf5ec94f231798c7181a1386457a0fb70505e9 Mon Sep 17 00:00:00 2001 From: Ricardo Date: Fri, 31 May 2024 23:32:12 +0100 Subject: [PATCH 13/16] Update Proposals Codex benchmarking to include Argo Bridge constraints proposal --- runtime-modules/argo-bridge/src/lib.rs | 2 +- .../proposals/codex/src/benchmarking.rs | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/runtime-modules/argo-bridge/src/lib.rs b/runtime-modules/argo-bridge/src/lib.rs index dcf652d69b..3627b33d56 100644 --- a/runtime-modules/argo-bridge/src/lib.rs +++ b/runtime-modules/argo-bridge/src/lib.rs @@ -80,7 +80,7 @@ decl_storage! { generate_storage_info pub NextTransferId get(fn next_transfer_id): TransferId; - pub RemoteChains get(fn remote_chains): BoundedVec>; + pub RemoteChains get(fn remote_chains): BoundedVec>; } } diff --git a/runtime-modules/proposals/codex/src/benchmarking.rs b/runtime-modules/proposals/codex/src/benchmarking.rs index b91347c646..d61e724caa 100644 --- a/runtime-modules/proposals/codex/src/benchmarking.rs +++ b/runtime-modules/proposals/codex/src/benchmarking.rs @@ -286,7 +286,8 @@ benchmarks! { where_clause { where T: membership::Config, T: council::Config, - T: working_group::Config + T: working_group::Config, + T: argo_bridge::Config } create_proposal_signal { @@ -964,15 +965,17 @@ benchmarks! { let (account_id, member_id, general_proposal_paramters) = create_proposal_parameters::(t, d); - // let member_id = Membership::::members_created(); - + let pauser_accounts: Vec = (0..T::MaxPauserAccounts::get()) + .map(|i| account::("pauser", 0, SEED)) + .collect(); + let chains: Vec = (0u32..argo_bridge::types::MAX_REMOTE_CHAINS).collect(); let proposal_details = ProposalDetails::UpdateArgoBridgeConstraints( argo_bridge::types::BridgeConstraints { operator_account: Some(account::("operator", 0, SEED)), - pauser_accounts: Some(vec![account::("pauser", 0, SEED), account::("pauser", 1, SEED)] ), + pauser_accounts: Some(pauser_accounts), bridging_fee: Some(100u32.into()), - thawn_duration: None, - remote_chains: None + thawn_duration: Some(1u32.into()), + remote_chains: Some(chains.try_into().unwrap()) } ); }: create_proposal( From 0fb0b20788f3daba71092150cfa34b322f2ab8a5 Mon Sep 17 00:00:00 2001 From: Ricardo Date: Fri, 31 May 2024 23:33:01 +0100 Subject: [PATCH 14/16] small improvements on Argo Bridge benchmarking --- runtime-modules/argo-bridge/src/benchmarking.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/runtime-modules/argo-bridge/src/benchmarking.rs b/runtime-modules/argo-bridge/src/benchmarking.rs index 4e4b90fd2c..e557b648b6 100644 --- a/runtime-modules/argo-bridge/src/benchmarking.rs +++ b/runtime-modules/argo-bridge/src/benchmarking.rs @@ -102,7 +102,7 @@ benchmarks! { operator_account: Some(operator_account.clone()), pauser_accounts: Some(vec![pauser_acount.clone().into()]), bridging_fee: Some(fee), - thawn_duration: None::, + thawn_duration: Some(1u32.into()), remote_chains: Some(BoundedVec::try_from(remote_chains).unwrap()) }; @@ -168,16 +168,15 @@ benchmarks! { // - max number of pauser accounts being use // - using the last pauser account pause_bridge{ - let mut pauser_accounts :Vec = Vec::new(); - for i in 0u32..T::MaxPauserAccounts::get() { - pauser_accounts.push(T::AccountId::create_account_id(i)); - } + let pauser_accounts: Vec = (0..T::MaxPauserAccounts::get()) + .map(|i| T::AccountId::create_account_id(i)) + .collect(); let operator_account = T::AccountId::create_account_id(1u32.into()); let parameters = BridgeConstraints { operator_account: Some(operator_account.clone()), pauser_accounts: Some(pauser_accounts.clone()), bridging_fee: None, - thawn_duration: None::, + thawn_duration: Some(1u32.into()), remote_chains: None }; ArgoBridge::::update_bridge_constrains( From bed43b088aa3a4af7ff8f4d75afddb8b3b0a439e Mon Sep 17 00:00:00 2001 From: Klaudiusz Dembler Date: Sun, 2 Jun 2024 13:21:32 +0200 Subject: [PATCH 15/16] fix clippy warnings --- bin/node/src/chain_spec/argo_bridge_config.rs | 2 - .../argo-bridge/src/benchmarking.rs | 54 +++++++++---------- runtime-modules/argo-bridge/src/lib.rs | 4 +- runtime-modules/argo-bridge/src/tests/mock.rs | 5 +- 4 files changed, 30 insertions(+), 35 deletions(-) diff --git a/bin/node/src/chain_spec/argo_bridge_config.rs b/bin/node/src/chain_spec/argo_bridge_config.rs index 831a5014b8..38528f60be 100644 --- a/bin/node/src/chain_spec/argo_bridge_config.rs +++ b/bin/node/src/chain_spec/argo_bridge_config.rs @@ -6,7 +6,6 @@ pub fn production_config() -> ArgoBridgeConfig { mint_allowance: 0, bridging_fee: DefaultBridgingFee::get(), thawn_duration: 1, - ..Default::default() } } @@ -16,6 +15,5 @@ pub fn testing_config() -> ArgoBridgeConfig { mint_allowance: 0, bridging_fee: DefaultBridgingFee::get(), thawn_duration: 1, - ..Default::default() } } diff --git a/runtime-modules/argo-bridge/src/benchmarking.rs b/runtime-modules/argo-bridge/src/benchmarking.rs index e557b648b6..b22b7bcd4a 100644 --- a/runtime-modules/argo-bridge/src/benchmarking.rs +++ b/runtime-modules/argo-bridge/src/benchmarking.rs @@ -33,7 +33,7 @@ impl CreateAccountId for u64 { impl CreateAccountId for u32 { fn create_account_id(id: u32) -> Self { - id.into() + id } } @@ -56,7 +56,7 @@ fn assert_last_event(generic_event: ::RuntimeEvent) { fn activate_bridge(pauser_acount: &T::AccountId, operator_acount: &T::AccountId) { let pauser_origin = RawOrigin::Signed(pauser_acount.clone()); - ArgoBridge::::init_unpause_bridge(pauser_origin.clone().into()).unwrap(); + ArgoBridge::::init_unpause_bridge(pauser_origin.into()).unwrap(); System::::set_block_number(3u32.into()); ArgoBridge::::finish_unpause_bridge(RawOrigin::Signed(operator_acount.clone()).into()) .unwrap(); @@ -66,17 +66,17 @@ fn set_bridge_mint_allowance(amount: BalanceOf, fee: BalanceOf) where T::AccountId: CreateAccountId, { - let sender = T::AccountId::create_account_id(1u32.into()); + let sender = T::AccountId::create_account_id(1u32); let _ = Balances::::deposit_creating( &sender, - T::ExistentialDeposit::get() + amount.into() + fee + 10u32.into(), + T::ExistentialDeposit::get() + amount + fee + 10u32.into(), ); let remote_account = RemoteAccount { account: [0; 32], chain_id: MAX_REMOTE_CHAINS - 1, }; ArgoBridge::::request_outbound_transfer( - RawOrigin::Signed(sender.clone()).into(), + RawOrigin::Signed(sender).into(), remote_account, amount + fee, fee, @@ -97,10 +97,10 @@ benchmarks! { let fee: BalanceOf = 10u32.into(); let remote_chains: Vec = (0..MAX_REMOTE_CHAINS).collect(); let pauser_acount = T::AccountId::create_account_id(1); - let operator_account = T::AccountId::create_account_id(1u32.into()); + let operator_account = T::AccountId::create_account_id(1u32); let parameters = BridgeConstraints { operator_account: Some(operator_account.clone()), - pauser_accounts: Some(vec![pauser_acount.clone().into()]), + pauser_accounts: Some(vec![pauser_acount.clone()]), bridging_fee: Some(fee), thawn_duration: Some(1u32.into()), remote_chains: Some(BoundedVec::try_from(remote_chains).unwrap()) @@ -112,8 +112,8 @@ benchmarks! { ).unwrap(); activate_bridge::(&pauser_acount, &operator_account); - let initial_balance: u32 = 1030u32.into(); - let sender = T::AccountId::create_account_id(1u32.into()); + let initial_balance: u32 = 1030u32; + let sender = T::AccountId::create_account_id(1u32); let _ = Balances::::deposit_creating(&sender, T::ExistentialDeposit::get() + initial_balance.into()); let dest_account = RemoteAccount { @@ -125,7 +125,7 @@ benchmarks! { let transfer_amount = 100u32.into(); }: _(origin, dest_account, transfer_amount, fee) verify { - let sender = T::AccountId::create_account_id(1u32.into()); + let sender = T::AccountId::create_account_id(1u32); assert_last_event::( RawEvent::OutboundTransferRequested(transfer_id, sender, dest_account, transfer_amount, fee).into()); } @@ -138,10 +138,10 @@ benchmarks! { let fee: BalanceOf = 10u32.into(); let remote_chains: Vec = (0..MAX_REMOTE_CHAINS).collect(); let pauser_acount = T::AccountId::create_account_id(1); - let operator_account = T::AccountId::create_account_id(1u32.into()); + let operator_account = T::AccountId::create_account_id(1u32); let parameters = BridgeConstraints { operator_account: Some(operator_account.clone()), - pauser_accounts: Some(vec![pauser_acount.clone().into()]), + pauser_accounts: Some(vec![pauser_acount.clone()]), bridging_fee: Some(fee), thawn_duration: Some(1u32.into()), remote_chains: Some(BoundedVec::try_from(remote_chains).unwrap()) @@ -155,8 +155,8 @@ benchmarks! { let transfer_amount = 100u32.into(); set_bridge_mint_allowance::(1030u32.into(), fee); - let operator = T::AccountId::create_account_id(1u32.into()); - let dest_account = T::AccountId::create_account_id(1u32.into()); + let operator = T::AccountId::create_account_id(1u32); + let dest_account = T::AccountId::create_account_id(1u32); let remote_transfer = RemoteTransfer { id: 0, chain_id: MAX_REMOTE_CHAINS - 1 }; }: _(RawOrigin::Signed(operator), remote_transfer.clone(), dest_account.clone(), transfer_amount) verify { @@ -169,9 +169,9 @@ benchmarks! { // - using the last pauser account pause_bridge{ let pauser_accounts: Vec = (0..T::MaxPauserAccounts::get()) - .map(|i| T::AccountId::create_account_id(i)) + .map(T::AccountId::create_account_id) .collect(); - let operator_account = T::AccountId::create_account_id(1u32.into()); + let operator_account = T::AccountId::create_account_id(1u32); let parameters = BridgeConstraints { operator_account: Some(operator_account.clone()), pauser_accounts: Some(pauser_accounts.clone()), @@ -185,12 +185,12 @@ benchmarks! { ).unwrap(); activate_bridge::(&pauser_accounts[0], &operator_account); - let pauser_acount = T::AccountId::create_account_id((T::MaxPauserAccounts::get() - 1).into()); + let pauser_acount = T::AccountId::create_account_id(T::MaxPauserAccounts::get() - 1); }: _(RawOrigin::Signed(pauser_acount.clone())) verify { assert_eq!(ArgoBridge::::status(), BridgeStatus::Paused); assert_last_event::( - RawEvent::BridgePaused(pauser_acount.clone()).into()); + RawEvent::BridgePaused(pauser_acount).into()); } // Worst case scenario: @@ -198,9 +198,9 @@ benchmarks! { // - using the last pauser account init_unpause_bridge{ let pauser_accounts: Vec = (0..T::MaxPauserAccounts::get()) - .map(|i| T::AccountId::create_account_id(i)) + .map(T::AccountId::create_account_id) .collect(); - let operator_account = T::AccountId::create_account_id(1u32.into()); + let operator_account = T::AccountId::create_account_id(1u32); let parameters = BridgeConstraints { operator_account: Some(operator_account.clone()), pauser_accounts: Some(pauser_accounts.clone()), @@ -214,7 +214,7 @@ benchmarks! { ).unwrap(); activate_bridge::(&pauser_accounts[0], &operator_account); - let pauser_acount = T::AccountId::create_account_id((T::MaxPauserAccounts::get() - 1) .into()); + let pauser_acount = T::AccountId::create_account_id(T::MaxPauserAccounts::get() - 1); ArgoBridge::::pause_bridge(RawOrigin::Signed(pauser_acount.clone()).into()).unwrap(); }: _(RawOrigin::Signed(pauser_acount.clone())) verify { @@ -228,9 +228,9 @@ benchmarks! { // - using the last pauser account finish_unpause_bridge{ let pauser_accounts: Vec = (0..T::MaxPauserAccounts::get()) - .map(|i| T::AccountId::create_account_id(i)) + .map(T::AccountId::create_account_id) .collect(); - let operator_account = T::AccountId::create_account_id(1u32.into()); + let operator_account = T::AccountId::create_account_id(1u32); let parameters = BridgeConstraints { operator_account: Some(operator_account.clone()), pauser_accounts: Some(pauser_accounts.clone()), @@ -244,8 +244,8 @@ benchmarks! { ).unwrap(); activate_bridge::(&pauser_accounts[0], &operator_account); - let pauser_acount = T::AccountId::create_account_id((T::MaxPauserAccounts::get() - 1) .into()); - let origin = RawOrigin::Signed(pauser_acount.clone()); + let pauser_acount = T::AccountId::create_account_id(T::MaxPauserAccounts::get() - 1); + let origin = RawOrigin::Signed(pauser_acount); ArgoBridge::::pause_bridge(origin.clone().into()).unwrap(); ArgoBridge::::init_unpause_bridge(origin.into()).unwrap(); System::::set_block_number(System::::block_number() + 3u32.into()); @@ -261,9 +261,9 @@ benchmarks! { update_bridge_constrains{ let fee: BalanceOf = 10u32.into(); let pauser_accounts: Vec = (0..T::MaxPauserAccounts::get()) - .map(|i| T::AccountId::create_account_id(i)) + .map(T::AccountId::create_account_id) .collect(); - let operator_account = T::AccountId::create_account_id(1u32.into()); + let operator_account = T::AccountId::create_account_id(1u32); let remote_chains: Vec = (0..MAX_REMOTE_CHAINS).collect(); let parameters = BridgeConstraints { diff --git a/runtime-modules/argo-bridge/src/lib.rs b/runtime-modules/argo-bridge/src/lib.rs index 3627b33d56..bd8622950a 100644 --- a/runtime-modules/argo-bridge/src/lib.rs +++ b/runtime-modules/argo-bridge/src/lib.rs @@ -117,7 +117,7 @@ decl_module! { #[weight = WeightInfoArgo::::finalize_inbound_transfer()] pub fn finalize_inbound_transfer(origin, remote_transfer: RemoteTransfer, dest_account: T::AccountId, amount: BalanceOf) -> DispatchResult { - ensure!(!Self::operator_account().is_none(), Error::::OperatorAccountNotSet); + ensure!(Self::operator_account().is_some(), Error::::OperatorAccountNotSet); let caller = ensure_signed(origin)?; ensure!(caller == Self::operator_account().unwrap(), Error::::NotOperatorAccount); @@ -165,7 +165,7 @@ decl_module! { #[weight = WeightInfoArgo::::finish_unpause_bridge()] pub fn finish_unpause_bridge(origin) -> DispatchResult { let caller = ensure_signed(origin)?; - ensure!(!Self::operator_account().is_none(), Error::::OperatorAccountNotSet); + ensure!(Self::operator_account().is_some(), Error::::OperatorAccountNotSet); ensure!(caller == Self::operator_account().unwrap(), Error::::NotOperatorAccount); let current_block = >::block_number(); diff --git a/runtime-modules/argo-bridge/src/tests/mock.rs b/runtime-modules/argo-bridge/src/tests/mock.rs index 1c56db7b6a..09e3bc8001 100644 --- a/runtime-modules/argo-bridge/src/tests/mock.rs +++ b/runtime-modules/argo-bridge/src/tests/mock.rs @@ -8,10 +8,7 @@ use frame_support::{ traits::{OnFinalize, OnInitialize}, }; -use frame_support::{ - traits::{ConstU16, ConstU32, ConstU64}, - PalletId, -}; +use frame_support::traits::{ConstU16, ConstU32, ConstU64}; use sp_runtime::testing::{Header, H256}; use sp_runtime::traits::{BlakeTwo256, IdentityLookup}; use sp_std::convert::{TryFrom, TryInto}; From b278c0869d164593c02b8a00da0fab8518c4287a Mon Sep 17 00:00:00 2001 From: Ricardo Date: Mon, 3 Jun 2024 11:53:11 +0100 Subject: [PATCH 16/16] fix: add missing argo bridge configs to project codex pallet --- runtime-modules/proposals/codex/src/tests/mock.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/runtime-modules/proposals/codex/src/tests/mock.rs b/runtime-modules/proposals/codex/src/tests/mock.rs index b880aa09b1..954bfd0461 100644 --- a/runtime-modules/proposals/codex/src/tests/mock.rs +++ b/runtime-modules/proposals/codex/src/tests/mock.rs @@ -111,6 +111,7 @@ frame_support::construct_runtime!( Council: council::{Pallet, Call, Storage, Event}, Storage: storage::{Pallet, Call, Storage, Event}, Token: token::{Pallet, Call, Storage, Event}, + ArgoBridge: argo_bridge::{Pallet, Call, Storage, Event} } ); @@ -348,6 +349,9 @@ parameter_types! { pub const MinDistributionBucketsPerBag: u32 = 3; pub const MaxDistributionBucketsPerBag: u32 = 10; pub const MaxNumberOfOperatorsPerDistributionBucket: u32 = 5; + /// constants for argo_bridge::config + pub const MaxPauserAccounts: u32 = 10; + pub const DefaultBridgingFee: Balance = 1; } impl storage::Config for Test { @@ -395,6 +399,13 @@ impl token::Config for Test { type MaxOutputs = MaxOutputs; } +impl argo_bridge::Config for Test { + type RuntimeEvent = RuntimeEvent; + type MaxPauserAccounts = MaxPauserAccounts; + type WeightInfo = argo_bridge::weights::SubstrateWeight; + type DefaultBridgingFee = DefaultBridgingFee; +} + pub struct Wg; impl common::working_group::WorkingGroupBudgetHandler for Wg { fn get_budget() -> u64 {