diff --git a/Cargo.lock b/Cargo.lock index d7c9c0b4a89..cc8954b7514 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6459,6 +6459,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "hex-literal", "log", "pallet-balances", "parity-scale-codec", diff --git a/Cargo.toml b/Cargo.toml index 83988da1770..9aced0377ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = ["node", "pallets/*", "primitives", "runtimes/*", "support"] resolver = "1" [workspace.package] -version= "2.5.3" +version = "2.5.3" authors = ["Nodle Developers "] edition = "2021" @@ -28,7 +28,7 @@ cumulus-primitives-core = { version = "0.7.0", default-features = false } cumulus-primitives-parachain-inherent = { version = "0.7.0", default-features = false } cumulus-primitives-timestamp = { version = "0.7.0", default-features = false } cumulus-primitives-utility = { version = "0.7.0", default-features = false } -cumulus-client-consensus-proposer = { version = "0.7.0", default-features = false} +cumulus-client-consensus-proposer = { version = "0.7.0", default-features = false } cumulus-relay-chain-inprocess-interface = { version = "0.7.0", default-features = false } cumulus-relay-chain-interface = { version = "0.7.0", default-features = false } cumulus-relay-chain-rpc-interface = { version = "0.7.0", default-features = false } @@ -103,7 +103,7 @@ sp-core = { version = "28.0.0", default-features = false } sp-inherents = { version = "26.0.0", default-features = false } sp-io = { version = "30.0.0", default-features = false } sp-keystore = { version = "0.34.0", default-features = false } -sp-genesis-builder = { version = "0.7.0", default-features = false} +sp-genesis-builder = { version = "0.7.0", default-features = false } sp-npos-elections = { version = "26.0.0", default-features = false } sp-offchain = { version = "26.0.0", default-features = false } sp-runtime = { version = "31.0.0", default-features = false } @@ -119,9 +119,9 @@ sp-version = { version = "29.0.0", default-features = false } substrate-build-script-utils = { version = "11.0.0", default-features = false } substrate-prometheus-endpoint = { version = "0.17.0", default-features = false } substrate-wasm-builder = { version = "17.0.0", default-features = false } -xcm-builder = { package="staging-xcm-builder", version = "7.0.0", default-features = false } -xcm-executor = { package="staging-xcm-executor", version = "7.0.0", default-features = false } -xcm = { package = "staging-xcm", version = "7.0.0", default-features = false} +xcm-builder = { package = "staging-xcm-builder", version = "7.0.0", default-features = false } +xcm-executor = { package = "staging-xcm-executor", version = "7.0.0", default-features = false } +xcm = { package = "staging-xcm", version = "7.0.0", default-features = false } #ORML orml-xtokens = { version = "0.7.0", default-features = false } @@ -129,15 +129,19 @@ orml-traits = { version = "0.7.0", default-features = false } #Crates clap = { version = "4.1.8", features = ["derive"] } -codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false} +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } derive_more = "0.99.2" getrandom = { version = "0.2", features = ["js"] } hex-literal = { version = "0.4.1" } jsonrpsee = { version = "0.16.2", features = ["server"] } -lazy_static = {version = "1.4.0", default-features = false, features = ["spin_no_std"] } +lazy_static = { version = "1.4.0", default-features = false, features = [ + "spin_no_std", +] } log = { version = "0.4.17", default-features = false } safe-mix = { version = "1.0.1", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = [ + "derive", +] } serde = { version = "1.0.152", default-features = false } serde_json = { version = "1.0.104", default-features = false } static_assertions = "1.1.0" diff --git a/node/Cargo.toml b/node/Cargo.toml index 159630c2cba..f1f9c7c00ba 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -24,7 +24,7 @@ runtime-benchmarks = [ [dependencies] clap = { workspace = true, features = ["derive"] } derive_more.workspace = true -log = { workspace = true, default-features = true} +log = { workspace = true, default-features = true } codec.workspace = true serde = { workspace = true, features = ["derive"] } serde_json.workspace = true @@ -99,7 +99,6 @@ polkadot-cli.workspace = true polkadot-parachain-primitives.workspace = true polkadot-primitives.workspace = true polkadot-service.workspace = true -xcm = { workspace = true, default-features = false} -hex-literal = "0.4.1" -[dev-dependencies] -hex-literal = {workspace = true } +xcm = { workspace = true, default-features = false } + +hex-literal = { workspace = true } diff --git a/pallets/grants/Cargo.toml b/pallets/grants/Cargo.toml index db454ec60d4..6f3fc5d7cf8 100644 --- a/pallets/grants/Cargo.toml +++ b/pallets/grants/Cargo.toml @@ -16,6 +16,8 @@ std = [ "codec/std", "serde", "frame-support/std", + "frame-benchmarking/std", + "frame-system/std", "pallet-balances/std", "sp-runtime/std", @@ -25,6 +27,7 @@ std = [ runtime-benchmarks = [ "frame-benchmarking", "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", "frame-support/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] @@ -33,7 +36,9 @@ try-runtime = ["frame-support/try-runtime"] log = { workspace = true, default-features = false } codec = { workspace = true, default-features = false, features = ["derive"] } serde = { workspace = true, optional = true } -scale-info = { workspace = true, default-features = false, features = ["derive"] } +scale-info = { workspace = true, default-features = false, features = [ + "derive", +] } frame-benchmarking = { workspace = true, default-features = false, optional = true } frame-support = { workspace = true, default-features = false } frame-system = { workspace = true, default-features = false } @@ -41,8 +46,8 @@ pallet-balances = { workspace = true, default-features = false } sp-io = { workspace = true, default-features = false } sp-runtime = { workspace = true, default-features = false } sp-std = { workspace = true, default-features = false } +hex-literal = { workspace = true } [dev-dependencies] sp-core = { workspace = true, default-features = false } sp-tracing = { workspace = true, default-features = false } - diff --git a/pallets/grants/src/benchmarking.rs b/pallets/grants/src/benchmarking.rs index 7e07944a882..c9a70a12a06 100644 --- a/pallets/grants/src/benchmarking.rs +++ b/pallets/grants/src/benchmarking.rs @@ -25,6 +25,7 @@ use crate::Pallet as Grants; use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, BenchmarkError}; use frame_support::traits::{EnsureOrigin, Get, UnfilteredDispatchable}; use frame_system::RawOrigin; +use hex_literal::hex; use sp_runtime::traits::Bounded; use sp_std::prelude::*; @@ -98,7 +99,33 @@ benchmarks! { let origin = T::CancelOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: { call.dispatch_bypass_filter(origin)? } - renounce { + bridge_all_vesting_schedules { + let config = create_shared_config::(1); + let bridge_name = b"zklocal"; + let bridge_id = 1; + let remote_chain_id = 9924; + Pallet::::set_bridge(RawOrigin::Root.into(), bridge_id, bridge_name.to_vec(), remote_chain_id)?; + + for _x in 1 .. T::MaxSchedule::get() { + Pallet::::do_add_vesting_schedule(&config.granter, &config.grantee, config.schedule.clone())?; + } + + }: _(RawOrigin::Signed(config.grantee.clone()), hex!("2E7F3926Ae74FDCDcAde2c2AB50990C5daFD42bD"), bridge_id) + + set_bridge { + let bridge_name = b"bridge_between_eden_zks_main_era"; + let bridge_id = 1; + let remote_chain_id = 300; + }: _(RawOrigin::Root, bridge_id, bridge_name.to_vec(), remote_chain_id) + + remove_bridge { + let bridge_name = b"bridge_between_eden_zks_main_era"; + let bridge_id = 1; + let remote_chain_id = 300; + Pallet::::set_bridge(RawOrigin::Root.into(), bridge_id, bridge_name.to_vec(), remote_chain_id)?; + }: _(RawOrigin::Root, bridge_id) + + renounce { let config = create_shared_config::(1); let call = Call::::renounce{ who: config.grantee_lookup, diff --git a/pallets/grants/src/lib.rs b/pallets/grants/src/lib.rs index 72fc2d2aceb..1c23f268ce4 100644 --- a/pallets/grants/src/lib.rs +++ b/pallets/grants/src/lib.rs @@ -34,7 +34,7 @@ use frame_support::{ BoundedVec, }; use sp_runtime::{ - traits::{AtLeast32Bit, BlockNumberProvider, CheckedAdd, Saturating, StaticLookup, Zero}, + traits::{AtLeast32Bit, BlockNumberProvider, CheckedAdd, ConstU32, Saturating, StaticLookup, Zero}, DispatchResult, RuntimeDebug, }; use sp_std::{ @@ -77,6 +77,19 @@ pub struct VestingSchedule { pub per_period: Balance, } +const BRIDGE_NAME_MAX_LENGTH: u32 = 32; + +// A unique identifier for a bridge between parachain and a remote ethereum based chain/rollup. +#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug, MaxEncodedLen, scale_info::TypeInfo)] +pub struct BridgeId(u32); + +// Details of a bridge between parachain and a remote ethereum based chain/rollup. +#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug, MaxEncodedLen, scale_info::TypeInfo)] +pub struct BridgeDetails { + chain_id: u64, + name: BoundedVec>, +} + impl VestingSchedule { /// Returns the end of all periods, `None` if calculation overflows. pub fn end(&self) -> Option { @@ -109,7 +122,7 @@ impl VestingSche #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::{DispatchResultWithPostInfo, *}; + use frame_support::pallet_prelude::{DispatchResultWithPostInfo, OptionQuery, *}; use frame_system::pallet_prelude::*; #[pallet::config] @@ -214,6 +227,90 @@ pub mod pallet { Ok(().into()) } + + /// Initiate a bridge transfer of all vested funds to the given `eth_address` on the given `chain_id`. + /// This process will need to be completed by the bridge oracles. + #[pallet::call_index(4)] + #[pallet::weight(T::WeightInfo::bridge_all_vesting_schedules())] + pub fn bridge_all_vesting_schedules( + origin: OriginFor, + eth_address: [u8; 20], + bridge_id: u32, + ) -> DispatchResultWithPostInfo { + let from = ensure_signed(origin)?; + ensure!( + Bridges::::contains_key(&BridgeId(bridge_id)), + Error::::BridgeNotFound + ); + + let locked_amount_left = Self::do_claim(&from); + if locked_amount_left.is_zero() { + >::remove(from); + Self::deposit_event(Event::NoVestedFundsToBridgeAfterClaim); + return Ok(().into()); + } + + let free_balance = T::Currency::free_balance(&from); + let bridgeable_funds = locked_amount_left.min(free_balance); + + T::Currency::remove_lock(VESTING_LOCK_ID, &from); + T::Currency::settle( + &from, + T::Currency::burn(bridgeable_funds), + WithdrawReasons::RESERVE, + ExistenceRequirement::AllowDeath, + ) + .map_err(|_| Error::::FailedToSettleBridge)?; + + let grants = >::take(&from); + + Self::deposit_event(Event::BridgeInitiated { + to: eth_address, + bridge_id, + amount: bridgeable_funds, + grants, + }); + + Ok(().into()) + } + + /// Allow governance to indicate a bridge is setup between the parachain and a remote chain. + #[pallet::call_index(5)] + #[pallet::weight(T::WeightInfo::set_bridge())] + pub fn set_bridge( + origin: OriginFor, + bridge_id: u32, + bridge_name: Vec, + remote_chain_id: u64, + ) -> DispatchResultWithPostInfo { + ensure_root(origin)?; + + let id = BridgeId(bridge_id); + ensure!(!Bridges::::contains_key(&id), Error::::BridgeAlreadyExists); + + let details = BridgeDetails { + chain_id: remote_chain_id, + name: bridge_name.try_into().map_err(|_| Error::::BridgeNameTooLong)?, + }; + + Bridges::::insert(id, details); + + Ok(().into()) + } + + /// Remove a bridge from the list of active bridges. + #[pallet::call_index(6)] + #[pallet::weight(T::WeightInfo::remove_bridge())] + pub fn remove_bridge(origin: OriginFor, bridge_id: u32) -> DispatchResultWithPostInfo { + ensure_root(origin)?; + + let id = BridgeId(bridge_id); + ensure!(Bridges::::contains_key(&id), Error::::BridgeNotFound); + + Bridges::::remove(&id); + + Ok(().into()) + } } #[pallet::event] @@ -227,6 +324,17 @@ pub mod pallet { VestingSchedulesCanceled(T::AccountId), /// Renounced rights to cancel grant for the given account id \[who\] Renounced(T::AccountId), + /// Initiated a bridge transfer of all vested funds \[to, chain_id, amount, grants\] + /// The field amount is crucial for the bridge because it shows the total entitlement of the user on the other side of the bridge. + BridgeInitiated { + to: [u8; 20], + bridge_id: u32, + amount: BalanceOf, + grants: BoundedVec, T::MaxSchedule>, + }, + /// Bridge was initiated and successfully completed one sidedly because + /// there were no vested funds to bridge after claiming free tokens for the user. + NoVestedFundsToBridgeAfterClaim, } #[pallet::error] @@ -239,6 +347,10 @@ pub mod pallet { VestingToSelf, MaxScheduleOverflow, Renounced, + FailedToSettleBridge, + BridgeAlreadyExists, + BridgeNotFound, + BridgeNameTooLong, } #[pallet::storage] @@ -255,6 +367,10 @@ pub mod pallet { #[pallet::getter(fn renounced)] pub type Renounced = StorageMap<_, Blake2_128Concat, T::AccountId, bool, ValueQuery>; + #[pallet::storage] + #[pallet::getter(fn bridges)] + pub type Bridges = StorageMap<_, Blake2_128Concat, BridgeId, BridgeDetails, OptionQuery>; + #[pallet::storage] pub(crate) type StorageVersion = StorageValue<_, Releases, ValueQuery>; diff --git a/pallets/grants/src/tests.rs b/pallets/grants/src/tests.rs index 512ae0c3674..803dcadf50e 100644 --- a/pallets/grants/src/tests.rs +++ b/pallets/grants/src/tests.rs @@ -22,6 +22,7 @@ use super::*; use frame_support::{assert_err, assert_noop, assert_ok, traits::WithdrawReasons}; +use hex_literal::hex; use mock::{ context_events, CancelOrigin, ExtBuilder, PalletBalances, RuntimeEvent as TestEvent, RuntimeOrigin, System, Test as Runtime, Vesting, ALICE, BOB, @@ -285,6 +286,364 @@ fn cancel_auto_claim_recipient_funds_and_wire_the_rest() { }); } +#[test] +fn bridge_all_vesting_schedules_does_claim_first() { + ExtBuilder::default().one_hundred_for_alice().build().execute_with(|| { + let bridge_id = 1; + let bridge_name = b"zklocal"; + let remote_chain_id = 9924; + assert_ok!(Vesting::set_bridge( + RuntimeOrigin::root(), + bridge_id, + bridge_name.into(), + remote_chain_id + )); + let schedule = VestingSchedule { + start: 0u64, + period: 10u64, + period_count: 2u32, + per_period: 10u64, + }; + assert_ok!(Vesting::add_vesting_schedule( + RuntimeOrigin::signed(ALICE::get()), + BOB::get(), + schedule + )); + + System::set_block_number(11); + + assert_eq!(PalletBalances::free_balance(BOB::get()), 20); + assert_eq!(PalletBalances::usable_balance(BOB::get()), 0); + assert_ok!(Vesting::bridge_all_vesting_schedules( + RuntimeOrigin::signed(BOB::get()), + hex!("2E7F3926Ae74FDCDcAde2c2AB50990C5daFD42bD"), + bridge_id + )); + assert_eq!(PalletBalances::free_balance(BOB::get()), 10); + assert_eq!(PalletBalances::usable_balance(BOB::get()), 10); + }); +} + +#[test] +fn bridge_all_vesting_schedules_clears_storage() { + ExtBuilder::default().one_hundred_for_alice().build().execute_with(|| { + let bridge_id = 1; + let bridge_name = b"zklocal"; + let remote_chain_id = 9924; + assert_ok!(Vesting::set_bridge( + RuntimeOrigin::root(), + bridge_id, + bridge_name.into(), + remote_chain_id + )); + let schedule = VestingSchedule { + start: 0u64, + period: 10u64, + period_count: 2u32, + per_period: 10u64, + }; + assert_ok!(Vesting::add_vesting_schedule( + RuntimeOrigin::signed(ALICE::get()), + BOB::get(), + schedule + )); + + System::set_block_number(11); + + assert!(>::contains_key(BOB::get())); + assert_ok!(Vesting::bridge_all_vesting_schedules( + RuntimeOrigin::signed(BOB::get()), + hex!("2E7F3926Ae74FDCDcAde2c2AB50990C5daFD42bD"), + bridge_id + )); + assert!(!>::contains_key(BOB::get())); + assert!(!>::contains_key(BOB::get())); + }); +} + +#[test] +fn bridge_all_vesting_schedules_reduces_total_issuance() { + ExtBuilder::default().one_hundred_for_alice().build().execute_with(|| { + let bridge_id = 1; + let bridge_name = b"zklocal"; + let remote_chain_id = 9924; + assert_ok!(Vesting::set_bridge( + RuntimeOrigin::root(), + bridge_id, + bridge_name.into(), + remote_chain_id + )); + let schedule = VestingSchedule { + start: 0u64, + period: 10u64, + period_count: 2u32, + per_period: 10u64, + }; + assert_ok!(Vesting::add_vesting_schedule( + RuntimeOrigin::signed(ALICE::get()), + BOB::get(), + schedule + )); + + System::set_block_number(11); + + assert_eq!(PalletBalances::total_issuance(), 100); + assert_ok!(Vesting::bridge_all_vesting_schedules( + RuntimeOrigin::signed(BOB::get()), + hex!("2E7F3926Ae74FDCDcAde2c2AB50990C5daFD42bD"), + bridge_id + )); + assert_eq!(PalletBalances::total_issuance(), 90); + }); +} + +#[test] +fn bridge_all_vesting_schedules_emits_expected_event() { + ExtBuilder::default().one_hundred_for_alice().build().execute_with(|| { + let bridge_id = 1; + let bridge_name = b"zklocal"; + let remote_chain_id = 9924; + assert_ok!(Vesting::set_bridge( + RuntimeOrigin::root(), + bridge_id, + bridge_name.into(), + remote_chain_id + )); + let schedule1 = VestingSchedule { + start: 0u64, + period: 10u64, + period_count: 2u32, + per_period: 10u64, + }; + assert_ok!(Vesting::add_vesting_schedule( + RuntimeOrigin::signed(ALICE::get()), + BOB::get(), + schedule1.clone() + )); + let schedule2 = VestingSchedule { + start: 12u64, + period: 13u64, + period_count: 1u32, + per_period: 7u64, + }; + assert_ok!(Vesting::add_vesting_schedule( + RuntimeOrigin::signed(ALICE::get()), + BOB::get(), + schedule2.clone() + )); + + System::set_block_number(11); + + assert_ok!(Vesting::bridge_all_vesting_schedules( + RuntimeOrigin::signed(BOB::get()), + hex!("2E7F3926Ae74FDCDcAde2c2AB50990C5daFD42bD"), + bridge_id + )); + let remaining_grants = BoundedVec::try_from(vec![schedule1, schedule2]).unwrap(); + + assert_eq!( + System::events().last().unwrap().event, + TestEvent::Vesting(Event::BridgeInitiated { + to: hex!("2E7F3926Ae74FDCDcAde2c2AB50990C5daFD42bD"), + bridge_id: 1, + amount: 17, + grants: remaining_grants, + }) + ); + }); +} + +#[test] +fn bridge_all_vesting_schedules_completes_one_sidedly_when_no_grants_after_claim() { + ExtBuilder::default().one_hundred_for_alice().build().execute_with(|| { + let bridge_id = 1; + let bridge_name = b"zklocal"; + let remote_chain_id = 9924; + assert_ok!(Vesting::set_bridge( + RuntimeOrigin::root(), + bridge_id, + bridge_name.into(), + remote_chain_id + )); + let schedule = VestingSchedule { + start: 0u64, + period: 10u64, + period_count: 1u32, + per_period: 100u64, + }; + assert_ok!(Vesting::add_vesting_schedule( + RuntimeOrigin::signed(ALICE::get()), + BOB::get(), + schedule + )); + + System::set_block_number(11); + + assert_ok!(Vesting::bridge_all_vesting_schedules( + RuntimeOrigin::signed(BOB::get()), + hex!("2E7F3926Ae74FDCDcAde2c2AB50990C5daFD42bD"), + bridge_id + )); + assert_eq!(PalletBalances::usable_balance(BOB::get()), 100); + assert_eq!( + System::events().last().unwrap().event, + TestEvent::Vesting(Event::NoVestedFundsToBridgeAfterClaim) + ); + }); +} + +#[test] +fn bridge_all_vesting_schedules_works_for_renounced_account() { + ExtBuilder::default().one_hundred_for_alice().build().execute_with(|| { + let bridge_id = 1; + let bridge_name = b"zklocal"; + let remote_chain_id = 9924; + assert_ok!(Vesting::set_bridge( + RuntimeOrigin::root(), + bridge_id, + bridge_name.into(), + remote_chain_id + )); + let schedule = VestingSchedule { + start: 0u64, + period: 10u64, + period_count: 1u32, + per_period: 100u64, + }; + assert_ok!(Vesting::add_vesting_schedule( + RuntimeOrigin::signed(ALICE::get()), + BOB::get(), + schedule + )); + + System::set_block_number(11); + + assert_ok!(Vesting::renounce( + RuntimeOrigin::signed(CancelOrigin::get()), + BOB::get() + )); + + assert_ok!(Vesting::bridge_all_vesting_schedules( + RuntimeOrigin::signed(BOB::get()), + hex!("2E7F3926Ae74FDCDcAde2c2AB50990C5daFD42bD"), + bridge_id + )); + assert_eq!(PalletBalances::usable_balance(BOB::get()), 100); + }); +} + +#[test] +fn set_bridge_fails_if_bridge_already_exists() { + ExtBuilder::default().build().execute_with(|| { + let bridge_id = 1; + let bridge_name = b"zklocal"; + let remote_chain_id = 9924; + assert_ok!(Vesting::set_bridge( + RuntimeOrigin::root(), + bridge_id, + bridge_name.into(), + remote_chain_id + )); + assert_err!( + Vesting::set_bridge(RuntimeOrigin::root(), bridge_id, bridge_name.into(), remote_chain_id), + Error::::BridgeAlreadyExists + ); + }); +} + +#[test] +fn set_bridge_fails_if_name_too_long() { + ExtBuilder::default().build().execute_with(|| { + let bridge_id = 1; + let bridge_name = b"somereallylonglonglongnnnnnnnnameeee"; + let remote_chain_id = 9924; + assert_err!( + Vesting::set_bridge(RuntimeOrigin::root(), bridge_id, bridge_name.into(), remote_chain_id), + Error::::BridgeNameTooLong + ); + }); +} + +#[test] +fn set_bridge_fails_if_non_root() { + ExtBuilder::default().build().execute_with(|| { + let bridge_id = 1; + let bridge_name = b"zklocal"; + let remote_chain_id = 9924; + assert_err!( + Vesting::set_bridge( + RuntimeOrigin::signed(ALICE::get()), + bridge_id, + bridge_name.into(), + remote_chain_id + ), + BadOrigin + ); + }); +} + +#[test] +fn remove_bridge_fails_if_non_root() { + ExtBuilder::default().build().execute_with(|| { + let bridge_id = 1; + assert_err!( + Vesting::remove_bridge(RuntimeOrigin::signed(ALICE::get()), bridge_id), + BadOrigin + ); + }); +} + +#[test] +fn remove_bridge_works() { + ExtBuilder::default().build().execute_with(|| { + let bridge_id = 1; + let bridge_name = b"zklocal"; + let remote_chain_id = 9924; + assert_ok!(Vesting::set_bridge( + RuntimeOrigin::root(), + bridge_id, + bridge_name.into(), + remote_chain_id + )); + let details = >::get(BridgeId(bridge_id)).unwrap(); + assert_eq!( + details, + BridgeDetails { + name: bridge_name.to_vec().try_into().unwrap(), + chain_id: remote_chain_id + } + ); + assert_ok!(Vesting::remove_bridge(RuntimeOrigin::root(), bridge_id)); + assert!(!>::contains_key(BridgeId(bridge_id))); + }); +} + +#[test] +fn remove_bridge_fails_if_bridge_not_found() { + ExtBuilder::default().build().execute_with(|| { + let bridge_id = 1; + assert_err!( + Vesting::remove_bridge(RuntimeOrigin::root(), bridge_id), + Error::::BridgeNotFound + ); + }); +} + +#[test] +fn bridge_all_vesting_schedules_fails_if_no_bridge() { + ExtBuilder::default().one_hundred_for_alice().build().execute_with(|| { + let bridge_id = 1; + assert_err!( + Vesting::bridge_all_vesting_schedules( + RuntimeOrigin::signed(BOB::get()), + hex!("2E7F3926Ae74FDCDcAde2c2AB50990C5daFD42bD"), + bridge_id + ), + Error::::BridgeNotFound + ); + }); +} + #[test] fn cancel_clears_storage() { ExtBuilder::default().one_hundred_for_alice().build().execute_with(|| { diff --git a/pallets/grants/src/weights.rs b/pallets/grants/src/weights.rs index eaa47adcd4f..a5c088d8034 100644 --- a/pallets/grants/src/weights.rs +++ b/pallets/grants/src/weights.rs @@ -46,6 +46,9 @@ pub trait WeightInfo { fn add_vesting_schedule() -> Weight; fn claim() -> Weight; fn cancel_all_vesting_schedules() -> Weight; + fn bridge_all_vesting_schedules() -> Weight; + fn set_bridge() -> Weight; + fn remove_bridge() -> Weight; fn renounce() -> Weight; } @@ -104,6 +107,40 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } + // Storage: `ParachainSystem::ValidationData` (r:1 w:0) + // Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `Vesting::VestingSchedules` (r:1 w:1) + // Proof: `Vesting::VestingSchedules` (`max_values`: None, `max_size`: Some(2850), added: 5325, mode: `MaxEncodedLen`) + // Storage: `Balances::Locks` (r:1 w:1) + // Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + // Storage: `Balances::Freezes` (r:1 w:0) + // Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + // Storage: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: `Vesting::CounterForVestingSchedules` (r:1 w:1) + // Proof: `Vesting::CounterForVestingSchedules` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn bridge_all_vesting_schedules() -> Weight { + // Minimum execution time: 75_000 nanoseconds. + Weight::from_parts(78_000_000_u64, 0) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + // Storage: `Vesting::Bridges` (r:1 w:1) + // Proof: `Vesting::Bridges` (`max_values`: None, `max_size`: Some(61), added: 2536, mode: `MaxEncodedLen`) + fn set_bridge() -> Weight { + // Minimum execution time: 7_000 nanoseconds. + Weight::from_parts(7_000_000_u64, 0) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + // Storage: `Vesting::Bridges` (r:1 w:1) + // Proof: `Vesting::Bridges` (`max_values`: None, `max_size`: Some(61), added: 2536, mode: `MaxEncodedLen`) + fn remove_bridge() -> Weight { + // Minimum execution time: 8_000 nanoseconds. + Weight::from_parts(9_000_000_u64, 0) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } // Storage: `Vesting::Renounced` (r:0 w:1) // Proof: `Vesting::Renounced` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) fn renounce() -> Weight { @@ -165,6 +202,40 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } + // Storage: `ParachainSystem::ValidationData` (r:1 w:0) + // Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `Vesting::VestingSchedules` (r:1 w:1) + // Proof: `Vesting::VestingSchedules` (`max_values`: None, `max_size`: Some(2850), added: 5325, mode: `MaxEncodedLen`) + // Storage: `Balances::Locks` (r:1 w:1) + // Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + // Storage: `Balances::Freezes` (r:1 w:0) + // Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + // Storage: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: `Vesting::CounterForVestingSchedules` (r:1 w:1) + // Proof: `Vesting::CounterForVestingSchedules` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn bridge_all_vesting_schedules() -> Weight { + // Minimum execution time: 75_000 nanoseconds. + Weight::from_parts(78_000_000_u64, 0) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + // Storage: `Vesting::Bridges` (r:1 w:1) + // Proof: `Vesting::Bridges` (`max_values`: None, `max_size`: Some(61), added: 2536, mode: `MaxEncodedLen`) + fn set_bridge() -> Weight { + // Minimum execution time: 7_000 nanoseconds. + Weight::from_parts(7_000_000_u64, 0) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + // Storage: `Vesting::Bridges` (r:1 w:1) + // Proof: `Vesting::Bridges` (`max_values`: None, `max_size`: Some(61), added: 2536, mode: `MaxEncodedLen`) + fn remove_bridge() -> Weight { + // Minimum execution time: 8_000 nanoseconds. + Weight::from_parts(9_000_000_u64, 0) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } // Storage: `Vesting::Renounced` (r:0 w:1) // Proof: `Vesting::Renounced` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) fn renounce() -> Weight { diff --git a/runtimes/eden/src/weights/pallet_grants.rs b/runtimes/eden/src/weights/pallet_grants.rs index 821231eadcb..17d70630be0 100644 --- a/runtimes/eden/src/weights/pallet_grants.rs +++ b/runtimes/eden/src/weights/pallet_grants.rs @@ -98,6 +98,40 @@ impl pallet_grants::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } + // Storage: `ParachainSystem::ValidationData` (r:1 w:0) + // Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `Vesting::VestingSchedules` (r:1 w:1) + // Proof: `Vesting::VestingSchedules` (`max_values`: None, `max_size`: Some(2850), added: 5325, mode: `MaxEncodedLen`) + // Storage: `Balances::Locks` (r:1 w:1) + // Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + // Storage: `Balances::Freezes` (r:1 w:0) + // Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + // Storage: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: `Vesting::CounterForVestingSchedules` (r:1 w:1) + // Proof: `Vesting::CounterForVestingSchedules` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn bridge_all_vesting_schedules() -> Weight { + // Minimum execution time: 75_000 nanoseconds. + Weight::from_parts(78_000_000_u64, 0) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + // Storage: `Vesting::Bridges` (r:1 w:1) + // Proof: `Vesting::Bridges` (`max_values`: None, `max_size`: Some(61), added: 2536, mode: `MaxEncodedLen`) + fn set_bridge() -> Weight { + // Minimum execution time: 7_000 nanoseconds. + Weight::from_parts(7_000_000_u64, 0) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + // Storage: `Vesting::Bridges` (r:1 w:1) + // Proof: `Vesting::Bridges` (`max_values`: None, `max_size`: Some(61), added: 2536, mode: `MaxEncodedLen`) + fn remove_bridge() -> Weight { + // Minimum execution time: 8_000 nanoseconds. + Weight::from_parts(9_000_000_u64, 0) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } // Storage: `Vesting::Renounced` (r:0 w:1) // Proof: `Vesting::Renounced` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) fn renounce() -> Weight {