diff --git a/Cargo.lock b/Cargo.lock index d5a3e0454..e73fd428c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6551,7 +6551,7 @@ dependencies = [ [[package]] name = "node-cli" -version = "0.9.82" +version = "0.9.84" dependencies = [ "clap", "cumulus-client-cli", @@ -15512,6 +15512,7 @@ dependencies = [ name = "xcm-interface" version = "0.8.0" dependencies = [ + "bifrost-asset-registry", "cumulus-primitives-core", "frame-benchmarking", "frame-support", diff --git a/integration-tests/bifrost-kusama/src/statemine.rs b/integration-tests/bifrost-kusama/src/statemine.rs index 594b8be2c..a08ed9559 100644 --- a/integration-tests/bifrost-kusama/src/statemine.rs +++ b/integration-tests/bifrost-kusama/src/statemine.rs @@ -138,6 +138,11 @@ fn cross_usdt() { Some((Weight::from_parts(10000000000, 1000000), 10_000_000_000)), )); + // get the fee balance of the alice before the transfer transaction + let alice_fee_balance_before = + Currencies::free_balance(RelayCurrencyId::get(), &AccountId::from(ALICE)); + + // Alice transfers 5 statemine asset to Bob assert_ok!(XcmInterface::transfer_statemine_assets( RuntimeOrigin::signed(ALICE.into()), 5 * USDT, @@ -145,6 +150,16 @@ fn cross_usdt() { Some(sp_runtime::AccountId32::from(BOB)) )); + // get the fee balance of the alice after the transfer transaction + let alice_fee_balance_after = + Currencies::free_balance(RelayCurrencyId::get(), &AccountId::from(ALICE)); + + // assert alice_fee_balance_before and alice_fee_balance_after are equal, since we + // didn't deduct any fee from alice in this test (integration test doesn't go through + // flexible fee) + assert_eq!(alice_fee_balance_before, alice_fee_balance_after); + + // assert Alice has 10-5 =5 statemine asset assert_eq!( Tokens::free_balance(CurrencyId::Token2(0), &AccountId::from(ALICE),), 5 * USDT @@ -153,7 +168,10 @@ fn cross_usdt() { Statemine::execute_with(|| { use statemine_runtime::*; println!("{:?}", System::events()); + + // assert Bob has 5 statemine asset assert_eq!(Assets::balance(1984, AccountId::from(BOB)), 5 * USDT); + assert!(System::events().iter().any(|r| matches!( r.event, RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index b0e4fa052..dd58c945a 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "node-cli" -version = "0.9.82" +version = "0.9.84" authors = ["Liebi Technologies "] description = "Bifrost Parachain Node" build = "build.rs" diff --git a/pallets/flexible-fee/src/mock.rs b/pallets/flexible-fee/src/mock.rs index 2c42a6fc0..372c08860 100644 --- a/pallets/flexible-fee/src/mock.rs +++ b/pallets/flexible-fee/src/mock.rs @@ -513,6 +513,10 @@ impl VTokenSupplyProvider for SimpleVTokenSupplyProvider { } } +parameter_types! { + pub const ReferendumCheckInterval: BlockNumber = 300; +} + impl bifrost_vtoken_voting::Config for Test { type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; @@ -527,6 +531,7 @@ impl bifrost_vtoken_voting::Config for Test { type MaxVotes = ConstU32<256>; type ParachainId = ParaInfo; type QueryTimeout = QueryTimeout; + type ReferendumCheckInterval = ReferendumCheckInterval; type WeightInfo = (); } diff --git a/pallets/salp/src/mock.rs b/pallets/salp/src/mock.rs index a0a2315c3..b59bcae5b 100644 --- a/pallets/salp/src/mock.rs +++ b/pallets/salp/src/mock.rs @@ -568,6 +568,7 @@ impl xcm_interface::Config for Test { type SalpHelper = Salp; type ParachainId = ParaInfo; type CallBackTimeOut = ConstU32<10>; + type CurrencyIdConvert = AssetIdMaps; } pub struct ParaInfo; diff --git a/pallets/slpx/src/lib.rs b/pallets/slpx/src/lib.rs index 25c491732..f8ead2785 100644 --- a/pallets/slpx/src/lib.rs +++ b/pallets/slpx/src/lib.rs @@ -38,7 +38,7 @@ use scale_info::TypeInfo; use sp_core::{Hasher, H160}; use sp_runtime::{ traits::{BlakeTwo256, CheckedSub}, - DispatchError, Saturating, + DispatchError, }; use sp_std::vec; use xcm::{latest::prelude::*, v3::MultiLocation}; @@ -655,16 +655,16 @@ impl Pallet { let free_balance = T::MultiCurrency::free_balance(currency_id, evm_caller_account_id); let execution_fee = Self::execution_fee(currency_id).unwrap_or_else(|| Self::get_default_fee(currency_id)); - let minimum_balance = T::MultiCurrency::minimum_balance(currency_id); + T::MultiCurrency::transfer( currency_id, evm_caller_account_id, &T::TreasuryAccount::get(), execution_fee, )?; - let balance_exclude_fee = free_balance - .checked_sub(&execution_fee.saturating_add(minimum_balance)) - .ok_or(Error::::FreeBalanceTooLow)?; + + let balance_exclude_fee = + free_balance.checked_sub(&execution_fee).ok_or(Error::::FreeBalanceTooLow)?; Ok(balance_exclude_fee) } diff --git a/pallets/slpx/src/mock.rs b/pallets/slpx/src/mock.rs index c29b65955..b2ceb667d 100644 --- a/pallets/slpx/src/mock.rs +++ b/pallets/slpx/src/mock.rs @@ -133,7 +133,7 @@ impl frame_system::Config for Test { // Pallet balances configuration parameter_types! { - pub const ExistentialDeposit: u128 = 1; + pub const ExistentialDeposit: u128 = 10_000_000_000; } impl pallet_balances::Config for Test { @@ -168,8 +168,12 @@ impl bifrost_currencies::Config for Test { // Pallet orml-tokens configuration parameter_type_with_key! { - pub ExistentialDeposits: |_currency_id: CurrencyId| -> u128 { - 0 + pub ExistentialDeposits: |currency_id: CurrencyId| -> u128 { + match currency_id { + &CurrencyId::Native(TokenSymbol::BNC) => 10 * 1_000_000_000, + &CurrencyId::Token(TokenSymbol::KSM) => 10 * 1_000_000_000, + _=> 10 * 1_000_000_000 + } }; } pub type ReserveIdentifier = [u8; 8]; diff --git a/pallets/slpx/src/tests.rs b/pallets/slpx/src/tests.rs index aaef5456e..0ce0c5e9b 100644 --- a/pallets/slpx/src/tests.rs +++ b/pallets/slpx/src/tests.rs @@ -102,25 +102,41 @@ fn test_whitelist_work() { #[test] fn test_execution_fee_work() { sp_io::TestExternalities::default().execute_with(|| { - assert_ok!(Currencies::deposit(CurrencyId::Token2(0), &ALICE, 50)); + assert_ok!(Currencies::deposit(CurrencyId::Token2(0), &ALICE, 50 * 1_000_000_000)); - assert_ok!(Slpx::set_execution_fee(RuntimeOrigin::root(), CurrencyId::Token2(0), 10)); - assert_eq!(Slpx::execution_fee(CurrencyId::Token2(0)), Some(10)); + assert_ok!(Slpx::set_execution_fee( + RuntimeOrigin::root(), + CurrencyId::Token2(0), + 10 * 1_000_000_000 + )); + assert_eq!(Slpx::execution_fee(CurrencyId::Token2(0)), Some(10 * 1_000_000_000)); let balance_exclude_fee = Slpx::charge_execution_fee(CurrencyId::Token2(0), &ALICE).unwrap(); - assert_eq!(balance_exclude_fee, 40); + assert_eq!(balance_exclude_fee, 40 * 1_000_000_000); - assert_ok!(Slpx::set_transfer_to_fee(RuntimeOrigin::root(), SupportChain::Moonbeam, 10)); - assert_eq!(Slpx::transfer_to_fee(SupportChain::Moonbeam), Some(10)); + assert_ok!(Slpx::set_transfer_to_fee( + RuntimeOrigin::root(), + SupportChain::Moonbeam, + 10 * 1_000_000_000 + )); + assert_eq!(Slpx::transfer_to_fee(SupportChain::Moonbeam), Some(10 * 1_000_000_000)); }); } #[test] fn test_zenlink() { sp_io::TestExternalities::default().execute_with(|| { - assert_ok!(Currencies::deposit(CurrencyId::Native(TokenSymbol::BNC), &ALICE, 50)); - assert_ok!(Currencies::deposit(CurrencyId::Token(TokenSymbol::KSM), &ALICE, 50)); + assert_ok!(Currencies::deposit( + CurrencyId::Native(TokenSymbol::BNC), + &ALICE, + 50 * 1_000_000_000 + )); + assert_ok!(Currencies::deposit( + CurrencyId::Token(TokenSymbol::KSM), + &ALICE, + 50 * 1_000_000_000 + )); let bnc_token: AssetId = AssetId::try_convert_from(CurrencyId::Native(TokenSymbol::BNC), 2001).unwrap(); @@ -132,14 +148,20 @@ fn test_zenlink() { RawOrigin::Signed(ALICE).into(), bnc_token, ksm_token, - 20u128, - 20u128, + 20u128 * 1_000_000_000, + 20u128 * 1_000_000_000, 0, 0, 100 )); - assert_eq!(Currencies::free_balance(CurrencyId::Native(TokenSymbol::BNC), &ALICE), 30u128); - assert_eq!(Currencies::free_balance(CurrencyId::Token(TokenSymbol::KSM), &ALICE), 30u128); + assert_eq!( + Currencies::free_balance(CurrencyId::Native(TokenSymbol::BNC), &ALICE), + 30u128 * 1_000_000_000 + ); + assert_eq!( + Currencies::free_balance(CurrencyId::Token(TokenSymbol::KSM), &ALICE), + 30u128 * 1_000_000_000 + ); let path = vec![bnc_token, ksm_token]; let balance = Currencies::free_balance(CurrencyId::Native(TokenSymbol::BNC), &ALICE); @@ -171,3 +193,41 @@ fn test_get_default_fee() { ); }); } + +#[test] +fn test_ed() { + sp_io::TestExternalities::default().execute_with(|| { + assert_ok!(Currencies::deposit( + CurrencyId::Native(TokenSymbol::BNC), + &ALICE, + 50 * 1_000_000_000 + )); + assert_ok!(Currencies::deposit( + CurrencyId::Token(TokenSymbol::KSM), + &ALICE, + 50 * 1_000_000_000 + )); + + assert_eq!( + Currencies::free_balance(CurrencyId::Native(TokenSymbol::BNC), &ALICE), + 50 * 1_000_000_000 + ); + assert_eq!( + Currencies::free_balance(CurrencyId::Token(TokenSymbol::KSM), &ALICE), + 50 * 1_000_000_000 + ); + + assert_ok!(Currencies::transfer( + RawOrigin::Signed(ALICE).into(), + BOB, + CurrencyId::Native(TokenSymbol::BNC), + 50 * 1_000_000_000 + )); + assert_ok!(Currencies::transfer( + RawOrigin::Signed(ALICE).into(), + BOB, + CurrencyId::Token(TokenSymbol::KSM), + 50 * 1_000_000_000 + )); + }); +} diff --git a/pallets/stable-asset/src/lib.rs b/pallets/stable-asset/src/lib.rs index e94516df1..e6c6acb12 100644 --- a/pallets/stable-asset/src/lib.rs +++ b/pallets/stable-asset/src/lib.rs @@ -41,7 +41,7 @@ use frame_support::{ }; use orml_traits::MultiCurrency; use scale_info::TypeInfo; -use sp_core::U512; +use sp_core::{U256, U512}; use sp_runtime::{ traits::{AccountIdConversion, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, One, Zero}, SaturatedConversion, @@ -798,11 +798,23 @@ impl Pallet { let time_diff_div: T::AtLeast64BitUnsigned = t1.checked_sub(&t0)?.into(); if a1 > a0 { let diff = a1.checked_sub(&a0)?; - let amount = diff.checked_mul(&time_diff)?.checked_div(&time_diff_div)?; + let amount = u128::try_from( + U256::from(diff.saturated_into::()) + .checked_mul(U256::from(time_diff.saturated_into::()))? + .checked_div(U256::from(time_diff_div.saturated_into::()))?, + ) + .ok()? + .into(); Some(a0.checked_add(&amount)?) } else { let diff = a0.checked_sub(&a1)?; - let amount = diff.checked_mul(&time_diff)?.checked_div(&time_diff_div)?; + let amount = u128::try_from( + U256::from(diff.saturated_into::()) + .checked_mul(U256::from(time_diff.saturated_into::()))? + .checked_div(U256::from(time_diff_div.saturated_into::()))?, + ) + .ok()? + .into(); Some(a0.checked_sub(&amount)?) } } else { @@ -962,11 +974,16 @@ impl Pallet { let mint_fee: T::AtLeast64BitUnsigned = pool_info.mint_fee; if pool_info.mint_fee > zero { - fee_amount = mint_amount - .checked_mul(&mint_fee) - .ok_or(Error::::Math)? - .checked_div(&fee_denominator) - .ok_or(Error::::Math)?; + fee_amount = u128::try_from( + U256::from(mint_amount.saturated_into::()) + .checked_mul(U256::from(mint_fee.saturated_into::())) + .ok_or(Error::::Math)? + .checked_div(U256::from(fee_denominator.saturated_into::())) + .ok_or(Error::::Math)?, + ) + .map_err(|_| Error::::Math)? + .into(); + mint_amount = mint_amount.checked_sub(&fee_amount).ok_or(Error::::Math)?; } @@ -1033,11 +1050,15 @@ impl Pallet { .checked_div(&pool_info.precisions[output_index_usize]) .ok_or(Error::::Math)?; if pool_info.swap_fee > zero { - let fee_amount: T::AtLeast64BitUnsigned = dy - .checked_mul(&pool_info.swap_fee) - .ok_or(Error::::Math)? - .checked_div(&fee_denominator) - .ok_or(Error::::Math)?; + let fee_amount = u128::try_from( + U256::from(dy.saturated_into::()) + .checked_mul(U256::from(pool_info.swap_fee.saturated_into::())) + .ok_or(Error::::Math)? + .checked_div(U256::from(fee_denominator.saturated_into::())) + .ok_or(Error::::Math)?, + ) + .map_err(|_| Error::::Math)? + .into(); dy = dy.checked_sub(&fee_amount).ok_or(Error::::Math)?; } Ok(SwapResult { @@ -1080,7 +1101,13 @@ impl Pallet { let swap_exact_over_amount = T::SwapExactOverAmount::get(); if pool_info.swap_fee > zero { let diff = fee_denominator.checked_sub(&pool_info.swap_fee)?; - dy = dy.checked_mul(&fee_denominator)?.checked_div(&diff)?; + dy = u128::try_from( + U256::from(dy.saturated_into::()) + .checked_mul(U256::from(fee_denominator.saturated_into::()))? + .checked_div(U256::from(diff.saturated_into::()))?, + ) + .ok()? + .into(); } let a: T::AtLeast64BitUnsigned = Self::get_a( @@ -1132,22 +1159,30 @@ impl Pallet { let mut fee_amount: T::AtLeast64BitUnsigned = zero; if pool_info.redeem_fee > zero { - fee_amount = amount - .checked_mul(&pool_info.redeem_fee) - .ok_or(Error::::Math)? - .checked_div(&fee_denominator) - .ok_or(Error::::Math)?; + fee_amount = u128::try_from( + U256::from(amount.saturated_into::()) + .checked_mul(U256::from(pool_info.redeem_fee.saturated_into::())) + .ok_or(Error::::Math)? + .checked_div(U256::from(fee_denominator.saturated_into::())) + .ok_or(Error::::Math)?, + ) + .map_err(|_| Error::::Math)? + .into(); // Redemption fee is charged with pool token before redemption. amount = amount.checked_sub(&fee_amount).ok_or(Error::::Math)?; } for i in 0..pool_info.balances.len() { let balance_i: T::AtLeast64BitUnsigned = balances[i]; - let diff_i: T::AtLeast64BitUnsigned = balance_i - .checked_mul(&amount) - .ok_or(Error::::Math)? - .checked_div(&d) - .ok_or(Error::::Math)?; + let diff_i: T::AtLeast64BitUnsigned = u128::try_from( + U256::from(balance_i.saturated_into::()) + .checked_mul(U256::from(amount.saturated_into::())) + .ok_or(Error::::Math)? + .checked_div(U256::from(d.saturated_into::())) + .ok_or(Error::::Math)?, + ) + .map_err(|_| Error::::Math)? + .into(); balances[i] = balance_i.checked_sub(&diff_i).ok_or(Error::::Math)?; let amounts_i: T::AtLeast64BitUnsigned = diff_i.checked_div(&pool_info.precisions[i]).ok_or(Error::::Math)?; @@ -1196,11 +1231,15 @@ impl Pallet { let mut fee_amount: T::AtLeast64BitUnsigned = zero; if pool_info.redeem_fee > zero { - fee_amount = amount - .checked_mul(&pool_info.redeem_fee) - .ok_or(Error::::Math)? - .checked_div(&fee_denominator) - .ok_or(Error::::Math)?; + fee_amount = u128::try_from( + U256::from(amount.saturated_into::()) + .checked_mul(U256::from(pool_info.redeem_fee.saturated_into::())) + .ok_or(Error::::Math)? + .checked_div(U256::from(fee_denominator.saturated_into::())) + .ok_or(Error::::Math)?, + ) + .map_err(|_| Error::::Math)? + .into(); // Redemption fee is charged with pool token before redemption. amount = amount.checked_sub(&fee_amount).ok_or(Error::::Math)?; } @@ -1270,11 +1309,15 @@ impl Pallet { let div_amount: T::AtLeast64BitUnsigned = fee_denominator .checked_sub(&pool_info.redeem_fee) .ok_or(Error::::Math)?; - redeem_amount = redeem_amount - .checked_mul(&fee_denominator) - .ok_or(Error::::Math)? - .checked_div(&div_amount) - .ok_or(Error::::Math)?; + redeem_amount = u128::try_from( + U256::from(redeem_amount.saturated_into::()) + .checked_mul(U256::from(fee_denominator.saturated_into::())) + .ok_or(Error::::Math)? + .checked_div(U256::from(div_amount.saturated_into::())) + .ok_or(Error::::Math)?, + ) + .map_err(|_| Error::::Math)? + .into(); let sub_amount: T::AtLeast64BitUnsigned = old_d.checked_sub(&new_d).ok_or(Error::::Math)?; fee_amount = redeem_amount.checked_sub(&sub_amount).ok_or(Error::::Math)?; } @@ -1306,11 +1349,15 @@ impl Pallet { let mut balance_of: T::AtLeast64BitUnsigned = T::Assets::free_balance(pool_info.assets[i], &pool_info.account_id).into(); if let Some((denominator, numerator)) = Self::get_token_rate(pool_info.pool_id, pool_info.assets[i]) { - balance_of = balance_of - .checked_mul(&numerator) - .ok_or(Error::::Math)? - .checked_div(&denominator) - .ok_or(Error::::Math)?; + balance_of = u128::try_from( + U256::from(balance_of.saturated_into::()) + .checked_mul(U256::from(numerator.saturated_into::())) + .ok_or(Error::::Math)? + .checked_div(U256::from(denominator.saturated_into::())) + .ok_or(Error::::Math)?, + ) + .map_err(|_| Error::::Math)? + .into(); } *balance = balance_of .checked_mul(&pool_info.precisions[i]) @@ -1370,11 +1417,15 @@ impl Pallet { let mut balance_of: T::AtLeast64BitUnsigned = T::Assets::free_balance(pool_info.assets[i], &pool_info.account_id).into(); if let Some((denominator, numerator)) = Self::get_token_rate(pool_info.pool_id, pool_info.assets[i]) { - balance_of = balance_of - .checked_mul(&numerator) - .ok_or(Error::::Math)? - .checked_div(&denominator) - .ok_or(Error::::Math)?; + balance_of = u128::try_from( + U256::from(balance_of.saturated_into::()) + .checked_mul(U256::from(numerator.saturated_into::())) + .ok_or(Error::::Math)? + .checked_div(U256::from(denominator.saturated_into::())) + .ok_or(Error::::Math)?, + ) + .map_err(|_| Error::::Math)? + .into(); } *balance = balance_of .checked_mul(&pool_info.precisions[i]) @@ -2094,7 +2145,13 @@ impl StableAsset for Pallet { let mut balance_of: T::AtLeast64BitUnsigned = T::Assets::free_balance(output_asset, &pool_info.account_id).into(); if let Some((denominator, numerator)) = Self::get_token_rate(pool_info.pool_id, output_asset) { - balance_of = balance_of.checked_mul(&numerator)?.checked_div(&denominator)?; + balance_of = u128::try_from( + U256::from(balance_of.saturated_into::()) + .checked_mul(U256::from(numerator.saturated_into::()))? + .checked_div(U256::from(denominator.saturated_into::()))?, + ) + .ok()? + .into(); } // make sure pool can affort the output amount if swap_result.dy <= balance_of.into() { diff --git a/pallets/stable-pool/src/lib.rs b/pallets/stable-pool/src/lib.rs index 2e23bd491..1c98eaf53 100644 --- a/pallets/stable-pool/src/lib.rs +++ b/pallets/stable-pool/src/lib.rs @@ -240,6 +240,13 @@ pub mod pallet { redeem_fee: Option, ) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; + let fee_denominator: T::AtLeast64BitUnsigned = T::FeePrecision::get(); + ensure!( + mint_fee.map(|x| x < fee_denominator).unwrap_or(true) && + swap_fee.map(|x| x < fee_denominator).unwrap_or(true) && + redeem_fee.map(|x| x < fee_denominator).unwrap_or(true), + nutsfinance_stable_asset::Error::::ArgumentsError + ); Pools::::try_mutate_exists(pool_id, |maybe_pool_info| -> DispatchResult { let pool_info = maybe_pool_info .as_mut() @@ -614,14 +621,6 @@ impl Pallet { } T::MultiCurrency::transfer(pool_info.assets[i_usize], &pool_info.account_id, who, dy)?; T::MultiCurrency::withdraw(pool_info.pool_asset, who, redeem_amount)?; - let mut amounts: Vec = Vec::new(); - for idx in 0..pool_size { - if idx == i_usize { - amounts.push(dy); - } else { - amounts.push(Zero::zero()); - } - } pool_info.total_supply = total_supply; pool_info.balances = balances; diff --git a/pallets/stable-pool/src/mock.rs b/pallets/stable-pool/src/mock.rs index 9a8ead303..d0b82188f 100644 --- a/pallets/stable-pool/src/mock.rs +++ b/pallets/stable-pool/src/mock.rs @@ -25,6 +25,7 @@ use frame_support::{ }; use frame_system::{EnsureRoot, EnsureSignedBy}; pub use node_primitives::{ + currency::{MOVR, VMOVR}, AccountId, Balance, CurrencyId, CurrencyIdMapping, SlpOperator, SlpxOperator, TokenSymbol, ASTR, BNC, DOT, DOT_TOKEN_ID, GLMR, VBNC, VDOT, }; @@ -368,6 +369,14 @@ impl Default for ExtBuilder { } } +pub fn million_unit(d: u128) -> u128 { + d.saturating_mul(10_u128.pow(18)) +} + +pub fn unit(d: u128) -> u128 { + d.saturating_mul(10_u128.pow(12)) +} + impl ExtBuilder { pub fn balances(mut self, endowed_accounts: Vec<(u128, CurrencyId, Balance)>) -> Self { self.endowed_accounts = endowed_accounts; @@ -376,10 +385,11 @@ impl ExtBuilder { pub fn new_test_ext(self) -> Self { self.balances(vec![ + (0, BNC, unit(1000)), + (0, MOVR, million_unit(1_000_000)), + (0, VMOVR, million_unit(1_000_000)), (1, BNC, 1_000_000_000_000), - // (1, VDOT, 100_000_000), (1, DOT, 100_000_000_000_000), - // (2, VDOT, 100_000_000_000_000), (3, DOT, 200_000_000), (4, DOT, 100_000_000), (6, BNC, 100_000_000_000_000), @@ -398,8 +408,9 @@ impl ExtBuilder { (DOT, 1_000_000, None), (ASTR, 10_000_000, None), (GLMR, 10_000_000, None), + (MOVR, 10_000_000, None), ], - vcurrency: vec![VDOT], + vcurrency: vec![VDOT, VMOVR], vsbond: vec![], phantom: Default::default(), } diff --git a/pallets/stable-pool/src/tests.rs b/pallets/stable-pool/src/tests.rs index c6093cd41..92063177d 100644 --- a/pallets/stable-pool/src/tests.rs +++ b/pallets/stable-pool/src/tests.rs @@ -63,6 +63,26 @@ fn create_pool2() -> (CurrencyId, CurrencyId, CurrencyId, u128) { (coin0, coin1, pool_asset, 30160825295207673652903702381u128) } +fn create_movr_pool() -> (CurrencyId, CurrencyId, CurrencyId, u128) { + let coin0 = MOVR; + let coin1 = VMOVR; + let pool_asset: CurrencyId = CurrencyId::BLP(0); + + assert_ok!(StablePool::create_pool( + RuntimeOrigin::root(), + vec![coin0, coin1], + vec![1u128, 1u128], + 10000000u128, + 20000000u128, + 50000000u128, + 10000u128, + 2, + 1, + million_unit(1), + )); + (coin0, coin1, pool_asset, 30160825295207673652903702381u128) +} + #[test] fn modify_a_argument_error_failed() { env_logger::try_init().unwrap_or(()); @@ -529,6 +549,48 @@ fn redeem_single() { 2 )); assert_eq!(Tokens::free_balance(coin1, &6), 904_596_263_064); + assert_noop!( + StablePool::modify_fees( + RuntimeOrigin::root(), + 0, + Some(10_000_000_000), + Some(10_000_000_000), + Some(10_000_000_000) + ), + nutsfinance_stable_asset::Error::::ArgumentsError + ); + assert_ok!(StablePool::modify_fees( + RuntimeOrigin::root(), + 0, + Some(9_999_999_999), + Some(9_999_999_999), + Some(9_999_999_999), + )); + assert_ok!(StablePool::redeem_single( + RuntimeOrigin::signed(6).into(), + 0, + 5_000_000_000u128, + 1, + 0, + 2 + )); + assert_eq!(Tokens::free_balance(coin1, &6), 904_596_263_064); + assert_ok!(StablePool::modify_fees( + RuntimeOrigin::root(), + 0, + Some(9_999_999_999), + Some(9_999_999_999), + Some(999_999_999), + )); + assert_ok!(StablePool::redeem_single( + RuntimeOrigin::signed(6).into(), + 0, + 5_000_000_000u128, + 1, + 0, + 2 + )); + assert_eq!(Tokens::free_balance(coin1, &6), 908_716_032_298); }); } @@ -725,3 +787,22 @@ fn edit_token_rate() { ); }); } + +#[test] +fn redeem_movr() { + ExtBuilder::default().new_test_ext().build().execute_with(|| { + let (coin0, coin1, pool_asset, _swap_id) = create_movr_pool(); + assert_ok!(StablePool::edit_token_rate( + RuntimeOrigin::root(), + 0, + vec![(coin0, (1, 1)), (coin1, (90_000_000, 100_000_000))] + )); + let amounts = vec![million_unit(100_000), million_unit(200_000)]; + assert_ok!(StablePool::mint_inner(&0, 0, amounts, 0)); + assert_eq!(Tokens::free_balance(pool_asset, &0), 321765598211330627258732); + assert_ok!(StablePool::redeem_proportion_inner(&0, 0, million_unit(300_000), vec![0, 0])); + assert_eq!(Tokens::free_balance(pool_asset, &0), 21765598211330627258732); + assert_eq!(Tokens::free_balance(coin0, &0), 992676625984156921892393); + assert_eq!(Tokens::free_balance(coin1, &0), 985353251968313843784786); + }); +} diff --git a/pallets/vtoken-voting/src/benchmarking.rs b/pallets/vtoken-voting/src/benchmarking.rs index 1a190e514..1c3f6c11f 100644 --- a/pallets/vtoken-voting/src/benchmarking.rs +++ b/pallets/vtoken-voting/src/benchmarking.rs @@ -83,7 +83,7 @@ mod benchmarks { let r = T::MaxVotes::get() - 1; let response = Response::DispatchResult(MaybeErrorCode::Success); for (i, index) in (0..T::MaxVotes::get()).collect::>().iter().skip(1).enumerate() { - Pallet::::on_initialize(Zero::zero()); + Pallet::::on_idle(Zero::zero(), Weight::MAX); Pallet::::vote(RawOrigin::Signed(caller.clone()).into(), vtoken, *index, vote)?; Pallet::::notify_vote( control_origin.clone() as ::RuntimeOrigin, @@ -166,6 +166,12 @@ mod benchmarks { )?; Pallet::::set_vote_locking_period(RawOrigin::Root.into(), vtoken, 0u32.into())?; + let notify_origin = + T::ResponseOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let query_id = 0u64; + let response = Response::DispatchResult(MaybeErrorCode::Success); + Pallet::::notify_vote(notify_origin, query_id, response)?; + #[extrinsic_call] _(origin, vtoken, poll_index); diff --git a/pallets/vtoken-voting/src/lib.rs b/pallets/vtoken-voting/src/lib.rs index ce045008d..aa3b5ed13 100644 --- a/pallets/vtoken-voting/src/lib.rs +++ b/pallets/vtoken-voting/src/lib.rs @@ -29,6 +29,8 @@ mod tests; mod call; mod vote; + +pub mod migration; pub mod weights; use crate::vote::{Casting, Tally, Voting}; @@ -81,7 +83,11 @@ pub type ReferendumInfoOf = ReferendumInfo, TallyOf>; pub mod pallet { use super::*; + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); #[pallet::config] @@ -122,6 +128,9 @@ pub mod pallet { #[pallet::constant] type QueryTimeout: Get>; + #[pallet::constant] + type ReferendumCheckInterval: Get>; + /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; } @@ -228,6 +237,8 @@ pub mod pallet { TooMany, /// Change delegator is not allowed. ChangeDelegator, + /// DelegatorVoteRole mismatch. + DelegatorVoteRoleMismatch, } /// Information concerning any given referendum. @@ -290,12 +301,17 @@ pub mod pallet { StorageMap<_, Twox64Concat, CurrencyIdOf, BlockNumberFor>; #[pallet::storage] - pub type DelegatorVote = StorageDoubleMap< + pub type DelegatorVoteRole = + StorageDoubleMap<_, Twox64Concat, CurrencyIdOf, Twox64Concat, DerivativeIndex, VoteRole>; + + #[pallet::storage] + pub type DelegatorVote = StorageNMap< _, - Twox64Concat, - CurrencyIdOf, - Twox64Concat, - DerivativeIndex, + ( + NMapKey>, + NMapKey, + NMapKey, + ), AccountVote>, >; @@ -321,27 +337,23 @@ pub mod pallet { #[pallet::genesis_config] pub struct GenesisConfig { - pub delegator_votes: Vec<(CurrencyIdOf, u8, DerivativeIndex)>, + pub delegator_vote_roles: Vec<(CurrencyIdOf, u8, DerivativeIndex)>, pub undeciding_timeouts: Vec<(CurrencyIdOf, BlockNumberFor)>, } #[cfg(feature = "std")] impl Default for GenesisConfig { fn default() -> Self { - GenesisConfig { delegator_votes: vec![], undeciding_timeouts: vec![] } + GenesisConfig { delegator_vote_roles: vec![], undeciding_timeouts: vec![] } } } #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { - self.delegator_votes.iter().for_each(|(vtoken, role, derivative_index)| { + self.delegator_vote_roles.iter().for_each(|(vtoken, role, derivative_index)| { let vote_role = VoteRole::try_from(*role).unwrap(); - DelegatorVote::::insert( - vtoken, - derivative_index, - AccountVote::>::from(vote_role), - ); + DelegatorVoteRole::::insert(vtoken, derivative_index, vote_role); }); self.undeciding_timeouts.iter().for_each(|(vtoken, undeciding_timeout)| { UndecidingTimeout::::insert(vtoken, undeciding_timeout); @@ -351,35 +363,44 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { - fn on_initialize(_: BlockNumberFor) -> Weight { - let mut weight = T::DbWeight::get().reads(1); + fn on_idle(n: BlockNumberFor, remaining_weight: Weight) -> Weight { + let db_weight = T::DbWeight::get(); + let mut used_weight = db_weight.reads(3); + if remaining_weight.any_lt(used_weight) || + n % T::ReferendumCheckInterval::get() != Zero::zero() + { + return Weight::zero(); + } let relay_current_block_number = T::RelaychainBlockNumberProvider::current_block_number(); - weight += T::DbWeight::get().reads(1); - let timeout = ReferendumTimeout::::get(relay_current_block_number); - if !timeout.is_empty() { - timeout.iter().for_each(|(vtoken, poll_index)| { - ReferendumInfoFor::::mutate( - vtoken, - poll_index, - |maybe_info| match maybe_info { - Some(info) => - if let ReferendumInfo::Ongoing(_) = info { - *info = ReferendumInfo::Completed( - relay_current_block_number.into(), - ); - }, - None => {}, - }, - ); - weight += T::DbWeight::get().reads_writes(1, 1); - }); - weight += T::DbWeight::get().reads_writes(1, 1); - ReferendumTimeout::::remove(relay_current_block_number); + for relay_block_number in ReferendumTimeout::::iter_keys() { + if relay_current_block_number >= relay_block_number { + let info_list = ReferendumTimeout::::get(relay_block_number); + let len = info_list.len() as u64; + let temp_weight = db_weight.reads_writes(len, len) + db_weight.writes(1); + if remaining_weight.any_lt(used_weight + temp_weight) { + return used_weight; + } + used_weight += temp_weight; + for (vtoken, poll_index) in info_list.iter() { + ReferendumInfoFor::::mutate(vtoken, poll_index, |maybe_info| { + match maybe_info { + Some(info) => + if let ReferendumInfo::Ongoing(_) = info { + *info = ReferendumInfo::Completed( + relay_current_block_number.into(), + ); + }, + None => {}, + } + }); + } + ReferendumTimeout::::remove(relay_block_number); + } } - weight + used_weight } } @@ -402,7 +423,7 @@ pub mod pallet { Self::ensure_no_pending_vote(vtoken, poll_index)?; let new_vote = Self::compute_new_vote(vtoken, vote)?; - let derivative_index = Self::try_select_derivative_index(vtoken, new_vote)?; + let derivative_index = Self::try_select_derivative_index(vtoken, poll_index, new_vote)?; if let Some(d) = VoteDelegatorFor::::get((&who, vtoken, poll_index)) { ensure!(d == derivative_index, Error::::ChangeDelegator) } @@ -423,6 +444,15 @@ pub mod pallet { submitted = true; } + if !DelegatorVote::::contains_key((vtoken, poll_index, derivative_index)) { + let role = DelegatorVoteRole::::get(vtoken, derivative_index) + .ok_or(Error::::NoData)?; + let target_role = VoteRole::from(vote); + ensure!(role == target_role, Error::::DelegatorVoteRoleMismatch); + let default_vote: AccountVote> = target_role.into(); + DelegatorVote::::insert((vtoken, poll_index, derivative_index), default_vote); + } + // record vote info let maybe_old_vote = Self::try_vote( &who, @@ -434,8 +464,8 @@ pub mod pallet { )?; // send XCM message - let delegator_vote = - DelegatorVote::::get(vtoken, derivative_index).ok_or(Error::::NoData)?; + let delegator_vote = DelegatorVote::::get((vtoken, poll_index, derivative_index)) + .ok_or(Error::::NoData)?; let vote_call = as ConvictionVotingCall>::vote(poll_index, delegator_vote); let notify_call = Call::::notify_vote { query_id: 0, response: Default::default() }; @@ -481,11 +511,12 @@ pub mod pallet { ) -> DispatchResult { let who = ensure_signed(origin)?; Self::ensure_vtoken(&vtoken)?; - Self::ensure_referendum_expired(vtoken, poll_index) + Self::ensure_referendum_completed(vtoken, poll_index) .or(Self::ensure_referendum_killed(vtoken, poll_index)) - .map_err(|_| Error::::NotExpired)?; + .map_err(|_| Error::::NoPermissionYet)?; + Self::ensure_no_pending_vote(vtoken, poll_index)?; - Self::try_remove_vote(&who, vtoken, poll_index, UnvoteScope::Any)?; + Self::try_remove_vote(&who, vtoken, poll_index, UnvoteScope::OnlyExpired)?; Self::update_lock(&who, vtoken, &poll_index)?; Self::deposit_event(Event::::Unlocked { who, vtoken, poll_index }); @@ -507,7 +538,10 @@ pub mod pallet { let who = ensure_signed(origin)?; Self::ensure_vtoken(&vtoken)?; Self::ensure_referendum_expired(vtoken, poll_index)?; - ensure!(DelegatorVote::::contains_key(vtoken, derivative_index), Error::::NoData); + ensure!( + DelegatorVote::::contains_key((vtoken, poll_index, derivative_index)), + Error::::NoData + ); let notify_call = Call::::notify_remove_delegator_vote { query_id: 0, @@ -577,15 +611,11 @@ pub mod pallet { Error::::NoData ); ensure!( - !DelegatorVote::::contains_key(vtoken, derivative_index), + !DelegatorVoteRole::::contains_key(vtoken, derivative_index), Error::::DerivativeIndexOccupied ); - DelegatorVote::::insert( - vtoken, - derivative_index, - AccountVote::>::from(vote_role), - ); + DelegatorVoteRole::::insert(vtoken, derivative_index, vote_role); Self::deposit_event(Event::::DelegatorRoleSet { vtoken, @@ -738,8 +768,7 @@ pub mod pallet { let success = Response::DispatchResult(MaybeErrorCode::Success) == response; if success { DelegatorVote::::try_mutate_exists( - vtoken, - derivative_index, + (vtoken, poll_index, derivative_index), |maybe_vote| { if let Some(inner_vote) = maybe_vote { inner_vote @@ -775,7 +804,7 @@ pub mod pallet { vtoken_balance: BalanceOf, ) -> Result>, BalanceOf)>, DispatchError> { ensure!( - vote.balance() <= T::MultiCurrency::total_balance(vtoken, who), + vtoken_balance <= T::MultiCurrency::total_balance(vtoken, who), Error::::InsufficientFunds ); let mut old_vote = None; @@ -787,7 +816,9 @@ pub mod pallet { Ok(i) => { // Shouldn't be possible to fail, but we handle it gracefully. tally.remove(votes[i].1).ok_or(ArithmeticError::Underflow)?; - Self::try_sub_delegator_vote(vtoken, votes[i].2, votes[i].1)?; + Self::try_sub_delegator_vote( + vtoken, poll_index, votes[i].2, votes[i].1, + )?; old_vote = Some((votes[i].1, votes[i].3)); if let Some(approve) = votes[i].1.as_standard() { tally.reduce(approve, *delegations); @@ -807,7 +838,7 @@ pub mod pallet { } // Shouldn't be possible to fail, but we handle it gracefully. tally.add(vote).ok_or(ArithmeticError::Overflow)?; - Self::try_add_delegator_vote(vtoken, derivative_index, vote)?; + Self::try_add_delegator_vote(vtoken, poll_index, derivative_index, vote)?; if let Some(approve) = vote.as_standard() { tally.increase(approve, *delegations); } @@ -848,14 +879,14 @@ pub mod pallet { ensure!(matches!(scope, UnvoteScope::Any), Error::::NoPermission); // Shouldn't be possible to fail, but we handle it gracefully. tally.remove(v.1).ok_or(ArithmeticError::Underflow)?; - Self::try_sub_delegator_vote(vtoken, v.2, v.1)?; + Self::try_sub_delegator_vote(vtoken, poll_index, v.2, v.1)?; if let Some(approve) = v.1.as_standard() { tally.reduce(approve, *delegations); } Ok(()) }, PollStatus::Completed(end, approved) => { - if let Some((lock_periods, balance)) = v.1.locked_if(approved) { + if let Some((lock_periods, _)) = v.1.locked_if(approved) { let unlock_at = end.saturating_add( VoteLockingPeriod::::get(vtoken) .ok_or(Error::::NoData)? @@ -867,12 +898,14 @@ pub mod pallet { matches!(scope, UnvoteScope::Any), Error::::NoPermissionYet ); - prior.accumulate(unlock_at, balance) + // v.3 is the actual locked vtoken balance + prior.accumulate(unlock_at, v.3) } } Ok(()) }, - PollStatus::None => Ok(()), // Poll was cancelled. + PollStatus::Killed(_) => Ok(()), // Poll was killed. + PollStatus::None => Ok(()), // Poll was cancelled. }) } else { Ok(()) @@ -887,21 +920,11 @@ pub mod pallet { vtoken: CurrencyIdOf, poll_index: &PollIndex, ) -> DispatchResult { - let class_lock_needed = VotingFor::::mutate(who, |voting| { - voting.rejig(frame_system::Pallet::::block_number()); - voting.locked_balance() + VotingFor::::mutate(who, |voting| { + voting.rejig(T::RelaychainBlockNumberProvider::current_block_number()); }); let lock_needed = ClassLocksFor::::mutate(who, |locks| { locks.retain(|x| &x.0 != poll_index); - if !class_lock_needed.is_zero() { - let ok = locks.try_push((*poll_index, class_lock_needed)).is_ok(); - debug_assert!( - ok, - "Vec bounded by number of classes; \ - all items in Vec associated with a unique class; \ - qed" - ); - } locks.iter().map(|x| x.1).max().unwrap_or(Zero::zero()) }); if lock_needed.is_zero() { @@ -1095,68 +1118,86 @@ pub mod pallet { Ok(result) }, Some(ReferendumInfo::Completed(end)) => f(PollStatus::Completed(end, false)), + Some(ReferendumInfo::Killed(end)) => f(PollStatus::Killed(end)), _ => f(PollStatus::None), } } fn try_select_derivative_index( vtoken: CurrencyIdOf, - my_vote: AccountVote>, + poll_index: PollIndex, + new_vote: AccountVote>, ) -> Result { let token = CurrencyId::to_token(&vtoken).map_err(|_| Error::::NoData)?; - let mut data = DelegatorVote::::iter_prefix(vtoken) - .map(|(index, vote)| { - let (_, active) = T::DerivativeAccount::get_stake_info(token, index) + let vote_roles = DelegatorVoteRole::::iter_prefix(vtoken).collect::>(); + let mut delegator_votes = + DelegatorVote::::iter_prefix((vtoken, poll_index)).collect::>(); + let delegator_vote_keys = + delegator_votes.iter().map(|(index, _)| *index).collect::>(); + for vote_role in vote_roles { + if !delegator_vote_keys.contains(&vote_role.0) { + delegator_votes + .push((vote_role.0, AccountVote::>::from(vote_role.1))); + } + } + let mut data = delegator_votes + .into_iter() + .map(|(index, voted)| { + let (_, available_vote) = T::DerivativeAccount::get_stake_info(token, index) .unwrap_or(Default::default()); - (active, vote, index) + (available_vote, voted, index) }) - .filter(|(_, vote, _)| VoteRole::from(*vote) == VoteRole::from(my_vote)) + .filter(|(_, voted, _)| VoteRole::from(*voted) == VoteRole::from(new_vote)) .collect::>(); data.sort_by(|a, b| { (b.0.saturating_sub(b.1.balance())).cmp(&(a.0.saturating_sub(a.1.balance()))) }); - let (active, vote, index) = data.first().ok_or(Error::::NoData)?; - active - .checked_sub(&vote.balance()) + let (available_vote, voted, index) = data.first().ok_or(Error::::NoData)?; + available_vote + .checked_sub(&voted.balance()) .ok_or(ArithmeticError::Underflow)? - .checked_sub(&my_vote.balance()) + .checked_sub(&new_vote.balance()) .ok_or(ArithmeticError::Underflow)?; Ok(*index) } - fn try_add_delegator_vote( + pub(crate) fn try_add_delegator_vote( vtoken: CurrencyIdOf, + poll_index: PollIndex, derivative_index: DerivativeIndex, vote: AccountVote>, ) -> Result>, DispatchError> { - DelegatorVote::::try_mutate_exists(vtoken, derivative_index, |maybe_vote| { - match maybe_vote { + DelegatorVote::::try_mutate_exists( + (vtoken, poll_index, derivative_index), + |maybe_vote| match maybe_vote { Some(inner_vote) => { inner_vote.checked_add(vote).map_err(|_| ArithmeticError::Overflow)?; Ok(*inner_vote) }, None => Err(Error::::NoData.into()), - } - }) + }, + ) } fn try_sub_delegator_vote( vtoken: CurrencyIdOf, + poll_index: PollIndex, derivative_index: DerivativeIndex, vote: AccountVote>, ) -> Result>, DispatchError> { - DelegatorVote::::try_mutate_exists(vtoken, derivative_index, |maybe_vote| { - match maybe_vote { + DelegatorVote::::try_mutate_exists( + (vtoken, poll_index, derivative_index), + |maybe_vote| match maybe_vote { Some(inner_vote) => { inner_vote.checked_sub(vote).map_err(|_| ArithmeticError::Underflow)?; Ok(*inner_vote) }, None => Err(Error::::NoData.into()), - } - }) + }, + ) } fn compute_new_vote( diff --git a/pallets/vtoken-voting/src/migration.rs b/pallets/vtoken-voting/src/migration.rs new file mode 100644 index 000000000..8be115336 --- /dev/null +++ b/pallets/vtoken-voting/src/migration.rs @@ -0,0 +1,122 @@ +// This file is part of Bifrost. + +// Copyright (C) 2019-2022 Liebi Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use super::*; +use frame_support::{storage_alias, traits::OnRuntimeUpgrade, weights::Weight}; + +mod v0 { + use super::*; + + #[storage_alias] + pub(super) type DelegatorVote = StorageDoubleMap< + Pallet, + Twox64Concat, + CurrencyIdOf, + Twox64Concat, + DerivativeIndex, + AccountVote>, + >; +} + +pub mod v1 { + use super::*; + use frame_support::traits::StorageVersion; + + pub struct MigrateToV1(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV1 { + fn on_runtime_upgrade() -> Weight { + if StorageVersion::get::>() == 0 { + let weight_consumed = migrate_to_v1::(); + log::info!("Migrating vtoken-voting storage to v1"); + StorageVersion::new(1).put::>(); + weight_consumed + } else { + log::warn!("vtoken-voting migration should be removed."); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + log::info!( + "vtoken-voting before migration: version: {:?}", + StorageVersion::get::>(), + ); + log::info!( + "vtoken-voting before migration: v0 count: {}", + v0::DelegatorVote::::iter().count(), + ); + ensure!( + v0::DelegatorVote::::iter().count() > 0, + "v0::DelegatorVote should not be empty before the migration" + ); + + Ok(Vec::new()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_: Vec) -> Result<(), &'static str> { + log::info!( + "vtoken-voting after migration: version: {:?}", + StorageVersion::get::>(), + ); + log::info!( + "vtoken-voting after migration: v1 count: {}", + DelegatorVote::::iter().count() + ); + ensure!( + DelegatorVote::::iter().count() > 0, + "DelegatorVote should not be empty after the migration" + ); + + Ok(()) + } + } +} + +pub fn migrate_to_v1() -> Weight { + let mut weight: Weight = Weight::zero(); + + let old_keys = v0::DelegatorVote::::iter_keys(); + let vtoken = VKSM; + + for (_, voting) in VotingFor::::iter() { + if let Voting::Casting(Casting { votes, .. }) = voting { + for (poll_index, vote, derivative_index, _) in votes.iter() { + if DelegatorVote::::contains_key((vtoken, poll_index, derivative_index)) { + let _ = Pallet::::try_add_delegator_vote( + vtoken, + *poll_index, + *derivative_index, + *vote, + ); + weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 2)); + } else { + DelegatorVote::::insert((vtoken, poll_index, derivative_index), vote); + weight = weight.saturating_add(T::DbWeight::get().writes(1)); + } + } + } + } + + for (vtoken, derivative_index) in old_keys { + v0::DelegatorVote::::remove(vtoken, derivative_index); + } + + weight +} diff --git a/pallets/vtoken-voting/src/mock.rs b/pallets/vtoken-voting/src/mock.rs index cf527979e..45871b118 100644 --- a/pallets/vtoken-voting/src/mock.rs +++ b/pallets/vtoken-voting/src/mock.rs @@ -26,6 +26,7 @@ use frame_support::{ pallet_prelude::Weight, parameter_types, traits::{Everything, GenesisBuild, Get, Nothing}, + weights::RuntimeDbWeight, }; use frame_system::EnsureRoot; use node_primitives::{ @@ -73,6 +74,7 @@ frame_support::construct_runtime!( parameter_types! { pub const BlockHashCount: u64 = 250; + pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { read: 1, write: 2 }; } impl frame_system::Config for Runtime { type AccountData = pallet_balances::AccountData; @@ -83,7 +85,7 @@ impl frame_system::Config for Runtime { type BlockNumber = u64; type BlockWeights = (); type RuntimeCall = RuntimeCall; - type DbWeight = (); + type DbWeight = DbWeight; type RuntimeEvent = RuntimeEvent; type Hash = H256; type Hashing = BlakeTwo256; @@ -290,6 +292,7 @@ impl DerivativeAccountHandler for DerivativeAccount { parameter_types! { pub static RelaychainBlockNumber: BlockNumber = 1; + pub static ReferendumCheckInterval: BlockNumber = 1; } pub struct RelaychainDataProvider; @@ -334,6 +337,7 @@ impl vtoken_voting::Config for Runtime { type MaxVotes = ConstU32<256>; type ParachainId = ParachainId; type QueryTimeout = QueryTimeout; + type ReferendumCheckInterval = ReferendumCheckInterval; type WeightInfo = (); } @@ -352,7 +356,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { .unwrap(); vtoken_voting::GenesisConfig:: { - delegator_votes: vec![ + delegator_vote_roles: vec![ (VKSM, 0, 0), (VKSM, 1, 1), (VKSM, 2, 2), diff --git a/pallets/vtoken-voting/src/tests.rs b/pallets/vtoken-voting/src/tests.rs index e3690e48a..dd7fd457a 100644 --- a/pallets/vtoken-voting/src/tests.rs +++ b/pallets/vtoken-voting/src/tests.rs @@ -26,6 +26,7 @@ use frame_support::{ fungibles::Inspect, tokens::{Fortitude::Polite, Preservation::Expendable}, }, + weights::RuntimeDbWeight, }; use node_primitives::currency::{VBNC, VKSM}; use pallet_conviction_voting::Vote; @@ -248,6 +249,12 @@ fn unsuccessful_conviction_vote_balance_can_be_unlocked() { new_test_ext().execute_with(|| { let poll_index = 3; let vtoken = VKSM; + let locking_period = 10; + assert_ok!(VtokenVoting::set_vote_locking_period( + RuntimeOrigin::root(), + vtoken, + locking_period, + )); assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, poll_index, aye(1, 1))); assert_ok!(VtokenVoting::notify_vote(origin_response(), 0, response_success())); @@ -260,6 +267,7 @@ fn unsuccessful_conviction_vote_balance_can_be_unlocked() { poll_index, ReferendumInfoOf::::Completed(3), )); + RelaychainDataProvider::set_block_number(13); assert_ok!(VtokenVoting::try_remove_vote(&ALICE, vtoken, poll_index, UnvoteScope::Any)); assert_ok!(VtokenVoting::update_lock(&ALICE, vtoken, &poll_index)); assert_eq!(usable_balance(vtoken, &ALICE), 10); @@ -271,7 +279,12 @@ fn successful_conviction_vote_balance_stays_locked_for_correct_time() { new_test_ext().execute_with(|| { let poll_index = 3; let vtoken = VKSM; - + let locking_period = 10; + assert_ok!(VtokenVoting::set_vote_locking_period( + RuntimeOrigin::root(), + vtoken, + locking_period, + )); for i in 1..=5 { assert_ok!(VtokenVoting::vote( RuntimeOrigin::signed(i), @@ -287,6 +300,7 @@ fn successful_conviction_vote_balance_stays_locked_for_correct_time() { poll_index, ReferendumInfoOf::::Completed(3), )); + RelaychainDataProvider::set_block_number(163); for i in 1..=5 { assert_ok!(VtokenVoting::try_remove_vote(&i, vtoken, poll_index, UnvoteScope::Any)); } @@ -301,12 +315,17 @@ fn successful_conviction_vote_balance_stays_locked_for_correct_time() { fn lock_amalgamation_valid_with_multiple_removed_votes() { new_test_ext().execute_with(|| { let vtoken = VKSM; + let response = response_success(); assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, 0, aye(5, 1))); assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, 1, aye(10, 1))); assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, 2, aye(5, 2))); assert_eq!(usable_balance(vtoken, &ALICE), 0); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 0, response.clone())); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 1, response.clone())); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 2, response.clone())); + assert_ok!(VtokenVoting::set_referendum_status( RuntimeOrigin::root(), vtoken, @@ -325,30 +344,116 @@ fn lock_amalgamation_valid_with_multiple_removed_votes() { 2, ReferendumInfoOf::::Completed(1), )); - assert_ok!(VtokenVoting::kill_referendum(RuntimeOrigin::root(), vtoken, 0)); - assert_ok!(VtokenVoting::kill_referendum(RuntimeOrigin::root(), vtoken, 1)); - assert_ok!(VtokenVoting::kill_referendum(RuntimeOrigin::root(), vtoken, 2)); + let locking_period = 10; + assert_ok!(VtokenVoting::set_vote_locking_period( + RuntimeOrigin::root(), + vtoken, + locking_period, + )); + + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(u32, u128), ConstU32<256>>::try_from(vec![(0, 5), (1, 10), (2, 5)]) + .unwrap() + ); + + RelaychainDataProvider::set_block_number(10); + assert_noop!( + VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 0), + Error::::NoPermissionYet + ); + + RelaychainDataProvider::set_block_number(11); assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 0)); assert_eq!(usable_balance(vtoken, &ALICE), 0); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(u32, u128), ConstU32<256>>::try_from(vec![(1, 10), (2, 5)]).unwrap() + ); + RelaychainDataProvider::set_block_number(11); assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 1)); - assert_eq!(usable_balance(vtoken, &ALICE), 0); + assert_eq!(usable_balance(vtoken, &ALICE), 5); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(u32, u128), ConstU32<256>>::try_from(vec![(2, 5)]).unwrap() + ); + RelaychainDataProvider::set_block_number(21); assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 2)); + assert_eq!(usable_balance(vtoken, &ALICE), 10); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(u32, u128), ConstU32<256>>::try_from(vec![]).unwrap() + ); + }); +} + +#[test] +fn removed_votes_when_referendum_killed() { + new_test_ext().execute_with(|| { + let vtoken = VKSM; + let response = response_success(); + + assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, 0, aye(5, 1))); + assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, 1, aye(10, 1))); + assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, 2, aye(5, 2))); assert_eq!(usable_balance(vtoken, &ALICE), 0); - // run_to(3); - assert_ok!(VtokenVoting::update_lock(&ALICE, vtoken, &0)); - assert_eq!(usable_balance(vtoken, &ALICE), 5); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 0, response.clone())); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 1, response.clone())); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 2, response.clone())); - // run_to(6); - assert_ok!(VtokenVoting::update_lock(&ALICE, vtoken, &1)); - assert_eq!(usable_balance(vtoken, &ALICE), 10); + assert_ok!(VtokenVoting::set_referendum_status( + RuntimeOrigin::root(), + vtoken, + 0, + ReferendumInfoOf::::Completed(1), + )); + assert_ok!(VtokenVoting::set_referendum_status( + RuntimeOrigin::root(), + vtoken, + 1, + ReferendumInfoOf::::Completed(1), + )); + assert_ok!(VtokenVoting::set_referendum_status( + RuntimeOrigin::root(), + vtoken, + 2, + ReferendumInfoOf::::Completed(1), + )); - // run_to(7); - assert_ok!(VtokenVoting::update_lock(&ALICE, vtoken, &2)); + assert_ok!(VtokenVoting::kill_referendum(RuntimeOrigin::root(), vtoken, 0)); + assert_ok!(VtokenVoting::kill_referendum(RuntimeOrigin::root(), vtoken, 1)); + assert_ok!(VtokenVoting::kill_referendum(RuntimeOrigin::root(), vtoken, 2)); + + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(u32, u128), ConstU32<256>>::try_from(vec![(0, 5), (1, 10), (2, 5)]) + .unwrap() + ); + + assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 0)); + assert_eq!(usable_balance(vtoken, &ALICE), 0); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(u32, u128), ConstU32<256>>::try_from(vec![(1, 10), (2, 5)]).unwrap() + ); + + assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 1)); + assert_eq!(usable_balance(vtoken, &ALICE), 5); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(u32, u128), ConstU32<256>>::try_from(vec![(2, 5)]).unwrap() + ); + + assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 2)); assert_eq!(usable_balance(vtoken, &ALICE), 10); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(u32, u128), ConstU32<256>>::try_from(vec![]).unwrap() + ); }); } @@ -594,7 +699,10 @@ fn notify_vote_success_works() { tally: TallyOf::::from_parts(10, 0, 2), })) ); - assert_eq!(DelegatorVote::::get(vtoken, derivative_index), Some(aye(2, 5))); + assert_eq!( + DelegatorVote::::get((vtoken, poll_index, derivative_index)), + Some(aye(2, 5)) + ); assert_eq!(tally(vtoken, poll_index), Tally::from_parts(10, 0, 2)); System::assert_last_event(RuntimeEvent::VtokenVoting(Event::Voted { who: ALICE, @@ -612,7 +720,10 @@ fn notify_vote_success_works() { tally: TallyOf::::from_parts(10, 0, 2), })) ); - assert_eq!(DelegatorVote::::get(vtoken, derivative_index), Some(aye(2, 5))); + assert_eq!( + DelegatorVote::::get((vtoken, poll_index, derivative_index)), + Some(aye(2, 5)) + ); System::assert_has_event(RuntimeEvent::VtokenVoting(Event::VoteNotified { vtoken, poll_index, @@ -657,7 +768,7 @@ fn notify_vote_success_max_works() { RelaychainDataProvider::set_block_number( 1 + UndecidingTimeout::::get(vtoken).unwrap(), ); - VtokenVoting::on_initialize(Zero::zero()); + VtokenVoting::on_idle(Zero::zero(), Weight::MAX); } }); } @@ -706,7 +817,10 @@ fn notify_vote_fail_works() { tally: TallyOf::::from_parts(10, 0, 2), })) ); - assert_eq!(DelegatorVote::::get(vtoken, derivative_index), Some(aye(2, 5))); + assert_eq!( + DelegatorVote::::get((vtoken, poll_index, derivative_index)), + Some(aye(2, 5)) + ); assert_eq!(tally(vtoken, poll_index), Tally::from_parts(10, 0, 2)); System::assert_last_event(RuntimeEvent::VtokenVoting(Event::Voted { who: ALICE, @@ -718,7 +832,10 @@ fn notify_vote_fail_works() { assert_ok!(VtokenVoting::notify_vote(origin_response(), query_id, response.clone())); assert_eq!(ReferendumInfoFor::::get(vtoken, poll_index), None); - assert_eq!(DelegatorVote::::get(vtoken, derivative_index), Some(aye(0, 5))); + assert_eq!( + DelegatorVote::::get((vtoken, poll_index, derivative_index)), + Some(aye(0, 5)) + ); System::assert_has_event(RuntimeEvent::VtokenVoting(Event::VoteNotified { vtoken, poll_index, @@ -757,7 +874,10 @@ fn notify_remove_delegator_vote_success_works() { let response = response_success(); assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, poll_index, aye(2, 5))); - assert_eq!(DelegatorVote::::get(vtoken, derivative_index), Some(aye(2, 5))); + assert_eq!( + DelegatorVote::::get((vtoken, poll_index, derivative_index)), + Some(aye(2, 5)) + ); assert_eq!(tally(vtoken, poll_index), Tally::from_parts(10, 0, 2)); System::assert_last_event(RuntimeEvent::VtokenVoting(Event::Voted { who: ALICE, @@ -783,7 +903,10 @@ fn notify_remove_delegator_vote_success_works() { poll_index, derivative_index, )); - assert_eq!(DelegatorVote::::get(vtoken, derivative_index), Some(aye(2, 5))); + assert_eq!( + DelegatorVote::::get((vtoken, poll_index, derivative_index)), + Some(aye(2, 5)) + ); query_id = 1; assert_ok!(VtokenVoting::notify_remove_delegator_vote( @@ -791,7 +914,10 @@ fn notify_remove_delegator_vote_success_works() { query_id, response.clone() )); - assert_eq!(DelegatorVote::::get(vtoken, derivative_index), Some(aye(0, 5))); + assert_eq!( + DelegatorVote::::get((vtoken, poll_index, derivative_index)), + Some(aye(0, 5)) + ); System::assert_has_event(RuntimeEvent::VtokenVoting(Event::DelegatorVoteRemovedNotified { vtoken, poll_index, @@ -840,7 +966,10 @@ fn notify_remove_delegator_vote_fail_works() { poll_index, derivative_index, )); - assert_eq!(DelegatorVote::::get(vtoken, derivative_index), Some(aye(2, 5))); + assert_eq!( + DelegatorVote::::get((vtoken, poll_index, derivative_index)), + Some(aye(2, 5)) + ); query_id = 1; assert_ok!(VtokenVoting::notify_remove_delegator_vote( @@ -848,7 +977,10 @@ fn notify_remove_delegator_vote_fail_works() { query_id, response.clone() )); - assert_eq!(DelegatorVote::::get(vtoken, derivative_index), Some(aye(2, 5))); + assert_eq!( + DelegatorVote::::get((vtoken, poll_index, derivative_index)), + Some(aye(2, 5)) + ); System::assert_last_event(RuntimeEvent::VtokenVoting(Event::ResponseReceived { responder: Parent.into(), query_id, @@ -877,11 +1009,13 @@ fn notify_remove_delegator_vote_with_no_data_works() { } #[test] -fn on_initialize_works() { +fn on_idle_works() { new_test_ext().execute_with(|| { let vtoken = VKSM; - RelaychainDataProvider::set_block_number(1); - for (query_id, poll_index) in (0..50).collect::>().iter().enumerate() { + for (index, poll_index) in (0..50).collect::>().iter().enumerate() { + let relay_block_number = index as BlockNumber; + let query_id = index as QueryId; + RelaychainDataProvider::set_block_number(relay_block_number); assert_ok!(VtokenVoting::vote( RuntimeOrigin::signed(ALICE), vtoken, @@ -895,16 +1029,27 @@ fn on_initialize_works() { )); } + let count = 30; RelaychainDataProvider::set_block_number( - 1 + UndecidingTimeout::::get(vtoken).unwrap(), + count + UndecidingTimeout::::get(vtoken).unwrap(), ); - VtokenVoting::on_initialize(Zero::zero()); + let db_weight = RuntimeDbWeight { read: 1, write: 1 }; + let weight = + db_weight.reads(3) + db_weight.reads_writes(1, 2) * count + db_weight.writes(2) * count; + let used_weight = VtokenVoting::on_idle(Zero::zero(), weight); + assert_eq!(used_weight, Weight::from_parts(153, 0)); + let mut actual_count = 0; for poll_index in 0..50 { - assert_eq!( - ReferendumInfoFor::::get(vtoken, poll_index), - Some(ReferendumInfo::Completed(101)) - ); + let relay_block_number = poll_index as BlockNumber; + if ReferendumTimeout::::get( + relay_block_number + UndecidingTimeout::::get(vtoken).unwrap(), + ) + .is_empty() + { + actual_count += 1; + } } + assert_eq!(actual_count, count); }); } diff --git a/pallets/vtoken-voting/src/vote.rs b/pallets/vtoken-voting/src/vote.rs index 07ef6f504..d9f9e58db 100644 --- a/pallets/vtoken-voting/src/vote.rs +++ b/pallets/vtoken-voting/src/vote.rs @@ -100,21 +100,21 @@ impl TryFrom for VoteRole { type Error = (); fn try_from(i: u8) -> Result { Ok(match i { - 0 => VoteRole::Standard { aye: true, conviction: Conviction::None }, // TODO remove + 0 => VoteRole::Standard { aye: true, conviction: Conviction::None }, 1 => VoteRole::Standard { aye: true, conviction: Conviction::Locked1x }, 2 => VoteRole::Standard { aye: true, conviction: Conviction::Locked2x }, 3 => VoteRole::Standard { aye: true, conviction: Conviction::Locked3x }, 4 => VoteRole::Standard { aye: true, conviction: Conviction::Locked4x }, 5 => VoteRole::Standard { aye: true, conviction: Conviction::Locked5x }, 6 => VoteRole::Standard { aye: true, conviction: Conviction::Locked6x }, - 10 => VoteRole::Standard { aye: false, conviction: Conviction::None }, // TODO remove + 10 => VoteRole::Standard { aye: false, conviction: Conviction::None }, 11 => VoteRole::Standard { aye: false, conviction: Conviction::Locked1x }, 12 => VoteRole::Standard { aye: false, conviction: Conviction::Locked2x }, 13 => VoteRole::Standard { aye: false, conviction: Conviction::Locked3x }, 14 => VoteRole::Standard { aye: false, conviction: Conviction::Locked4x }, 15 => VoteRole::Standard { aye: false, conviction: Conviction::Locked5x }, 16 => VoteRole::Standard { aye: false, conviction: Conviction::Locked6x }, - 20 => VoteRole::Split, // TODO remove + 20 => VoteRole::Split, 21 => VoteRole::SplitAbstain, _ => return Err(()), }) @@ -125,6 +125,7 @@ pub enum PollStatus { None, Ongoing(Tally), Completed(Moment, bool), + Killed(Moment), } impl PollStatus { @@ -153,11 +154,11 @@ pub enum AccountVote { impl AccountVote { /// Returns `Some` of the lock periods that the account is locked for, assuming that the /// referendum passed iff `approved` is `true`. - pub fn locked_if(self, approved: bool) -> Option<(u32, Balance)> { + pub fn locked_if(self, _approved: bool) -> Option<(u32, Balance)> { // winning side: can only be removed after the lock period ends. match self { AccountVote::Standard { vote: Vote { conviction: Conviction::None, .. }, .. } => None, - AccountVote::Standard { vote, balance } if vote.aye == approved => + AccountVote::Standard { vote, balance } /* if vote.aye == _approved */ => Some((vote.conviction.lock_periods(), balance)), _ => None, } diff --git a/pallets/xcm-interface/Cargo.toml b/pallets/xcm-interface/Cargo.toml index a4cac5ae3..b91ab8771 100644 --- a/pallets/xcm-interface/Cargo.toml +++ b/pallets/xcm-interface/Cargo.toml @@ -23,6 +23,7 @@ xcm = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.4 cumulus-primitives-core = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.42", default-features = false } orml-traits = { version = "0.4.1-dev", default-features = false } node-primitives = { path = "../../node/primitives", default-features = false } +bifrost-asset-registry = { path = "../asset-registry", default-features = false } [dev-dependencies] sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } diff --git a/pallets/xcm-interface/src/lib.rs b/pallets/xcm-interface/src/lib.rs index db2c780ac..905b11805 100644 --- a/pallets/xcm-interface/src/lib.rs +++ b/pallets/xcm-interface/src/lib.rs @@ -20,8 +20,9 @@ pub mod calls; pub mod traits; +use bifrost_asset_registry::AssetMetadata; pub use calls::*; -use node_primitives::{traits::XcmDestWeightAndFeeHandler, XcmOperationType}; +use node_primitives::{traits::XcmDestWeightAndFeeHandler, CurrencyIdMapping, XcmOperationType}; use orml_traits::MultiCurrency; pub use pallet::*; pub use traits::{ChainId, MessageId, Nonce, SalpHelper}; @@ -108,6 +109,13 @@ pub mod pallet { BalanceOf, >; + /// Convert MultiLocation to `T::CurrencyId`. + type CurrencyIdConvert: CurrencyIdMapping< + CurrencyIdOf, + MultiLocation, + AssetMetadata>, + >; + #[pallet::constant] type RelayNetwork: Get; @@ -124,6 +132,7 @@ pub mod pallet { XcmExecutionFailed, XcmSendFailed, OperationWeightAndFeeNotExist, + FailToConvert, } #[pallet::event] @@ -217,11 +226,27 @@ pub mod pallet { Some(account) => account, None => who.clone(), }; - let origin_location = T::AccountIdToMultiLocation::convert(who.clone()); - let dst_location = T::AccountIdToMultiLocation::convert(dest.clone()); + let amount_u128 = TryInto::::try_into(amount).map_err(|_| Error::::FeeConvertFailed)?; + // get currency_id from asset_id + let asset_location = MultiLocation::new( + 1, + X3( + Parachain(parachains::Statemine::ID), + PalletInstance(parachains::Statemine::PALLET_ID), + GeneralIndex(asset_id.into()), + ), + ); + let currency_id = T::CurrencyIdConvert::get_currency_id(asset_location) + .ok_or(Error::::FailToConvert)?; + + // first, we need to withdraw the statemine asset from the user's account + T::MultiCurrency::withdraw(currency_id, &who, amount)?; + + let dst_location = T::AccountIdToMultiLocation::convert(dest.clone()); + let (dest_weight, xcm_fee) = Self::xcm_dest_weight_and_fee( T::RelaychainCurrencyId::get(), XcmOperationType::StatemineTransfer, @@ -234,9 +259,8 @@ pub mod pallet { let mut assets = MultiAssets::new(); let statemine_asset = MultiAsset { id: Concrete(MultiLocation::new( - 1, - X3( - Parachain(parachains::Statemine::ID), + 0, + X2( PalletInstance(parachains::Statemine::PALLET_ID), GeneralIndex(asset_id.into()), ), @@ -247,28 +271,22 @@ pub mod pallet { id: Concrete(MultiLocation::new(1, Junctions::Here)), fun: Fungible(xcm_fee_u128), }; - assets.push(statemine_asset); + assets.push(statemine_asset.clone()); assets.push(fee_asset.clone()); let msg = Xcm(vec![ WithdrawAsset(assets), - InitiateReserveWithdraw { - assets: All.into(), - reserve: MultiLocation::new(1, X1(Parachain(parachains::Statemine::ID))), - xcm: Xcm(vec![ - BuyExecution { fees: fee_asset, weight_limit: Unlimited }, - DepositAsset { assets: AllCounted(2).into(), beneficiary: dst_location }, - ]), + BuyExecution { + fees: fee_asset, + weight_limit: cumulus_primitives_core::Limited(dest_weight), }, + DepositAsset { assets: AllCounted(2).into(), beneficiary: dst_location }, ]); - let hash = msg.using_encoded(sp_io::hashing::blake2_256); - ::XcmExecutor::execute_xcm_in_credit( - origin_location, + + pallet_xcm::Pallet::::send_xcm( + Here, + MultiLocation::new(1, X1(Parachain(parachains::Statemine::ID))), msg, - hash, - dest_weight, - dest_weight, ) - .ensure_complete() .map_err(|_| Error::::XcmExecutionFailed)?; Self::deposit_event(Event::::TransferredStatemineMultiAsset(dest, amount)); diff --git a/runtime/bifrost-kusama/src/governance/mod.rs b/runtime/bifrost-kusama/src/governance/mod.rs index 2d21427b5..019de14ae 100644 --- a/runtime/bifrost-kusama/src/governance/mod.rs +++ b/runtime/bifrost-kusama/src/governance/mod.rs @@ -23,9 +23,19 @@ pub use bifrost_runtime_common::dollar; mod fellowship; mod origins; pub use origins::{ - custom_origins, Fellows, FellowshipAdmin, FellowshipExperts, FellowshipInitiates, + custom_origins, CoreAdmin, Fellows, FellowshipAdmin, FellowshipExperts, FellowshipInitiates, FellowshipMasters, ReferendumCanceller, ReferendumKiller, SALPAdmin, SystemStakingAdmin, - ValidatorElection, WhitelistedCaller, *, + TechAdmin, ValidatorElection, WhitelistedCaller, *, }; mod tracks; pub use tracks::TracksInfo; + +pub type CoreAdminOrCouncil = EitherOfDiverse< + CoreAdmin, + EitherOfDiverse, +>; + +pub type TechAdminOrCouncil = EitherOfDiverse< + TechAdmin, + EitherOfDiverse, +>; diff --git a/runtime/bifrost-kusama/src/lib.rs b/runtime/bifrost-kusama/src/lib.rs index fc781312e..6b0309880 100644 --- a/runtime/bifrost-kusama/src/lib.rs +++ b/runtime/bifrost-kusama/src/lib.rs @@ -26,10 +26,8 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -pub mod migration; use bifrost_slp::{DerivativeAccountProvider, QueryResponseManager}; use core::convert::TryInto; -use frame_support::pallet_prelude::StorageVersion; // A few exports that help ease life for downstream crates. pub use frame_support::{ construct_runtime, match_types, parameter_types, @@ -107,7 +105,10 @@ use zenlink_stable_amm::traits::{StableAmmApi, StablePoolLpCurrencyIdGenerate, V // Governance configurations. pub mod governance; -use governance::{custom_origins, CoreAdmin, TechAdmin}; +use governance::{ + custom_origins, CoreAdmin, CoreAdminOrCouncil, SALPAdmin, SystemStakingAdmin, TechAdmin, + TechAdminOrCouncil, ValidatorElection, +}; // xcm config mod xcm_config; @@ -132,7 +133,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("bifrost"), impl_name: create_runtime_str!("bifrost"), authoring_version: 1, - spec_version: 982, + spec_version: 984, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -713,7 +714,7 @@ parameter_types! { pub VotingBondFactor: Balance = deposit::(0, 32); /// Daily council elections pub const TermDuration: BlockNumber = 24 * HOURS; - pub const DesiredMembers: u32 = 7; + pub const DesiredMembers: u32 = 3; pub const DesiredRunnersUp: u32 = 7; pub const PhragmenElectionPalletId: LockIdentifier = *b"phrelect"; pub const MaxVoters: u32 = 512; @@ -1139,7 +1140,7 @@ impl bifrost_flexible_fee::Config for Runtime { type WeightInfo = weights::bifrost_flexible_fee::BifrostWeight; type ExtraFeeMatcher = ExtraFeeMatcher; type ParachainId = ParachainInfo; - type ControlOrigin = EitherOfDiverse; + type ControlOrigin = TechAdminOrCouncil; type XcmWeightAndFeeHandler = XcmInterface; } @@ -1258,10 +1259,7 @@ impl bifrost_salp::Config for Runtime { type SlotLength = SlotLength; type VSBondValidPeriod = VSBondValidPeriod; type WeightInfo = weights::bifrost_salp::BifrostWeight; - type EnsureConfirmAsGovernance = EitherOfDiverse< - TechAdmin, - EitherOfDiverse, - >; + type EnsureConfirmAsGovernance = EitherOfDiverse; type XcmInterface = XcmInterface; type TreasuryAccount = BifrostTreasuryAccount; type BuybackPalletId = BuybackPalletId; @@ -1300,10 +1298,7 @@ impl bifrost_token_issuer::Config for Runtime { impl bifrost_call_switchgear::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type UpdateOrigin = EitherOfDiverse< - CoreAdmin, - EitherOfDiverse, - >; + type UpdateOrigin = CoreAdminOrCouncil; type WeightInfo = weights::bifrost_call_switchgear::BifrostWeight; } @@ -1369,10 +1364,7 @@ impl bifrost_slp::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type MultiCurrency = Currencies; - type ControlOrigin = EitherOfDiverse< - TechAdmin, - EitherOfDiverse, - >; + type ControlOrigin = EitherOfDiverse; type WeightInfo = weights::bifrost_slp::BifrostWeight; type VtokenMinting = VtokenMinting; type BifrostSlpx = Slpx; @@ -1393,10 +1385,7 @@ impl bifrost_vstoken_conversion::Config for Runtime { type MultiCurrency = Currencies; type RelayCurrencyId = RelayCurrencyId; type TreasuryAccount = BifrostTreasuryAccount; - type ControlOrigin = EitherOfDiverse< - CoreAdmin, - EitherOfDiverse, - >; + type ControlOrigin = CoreAdminOrCouncil; type VsbondAccount = BifrostVsbondPalletId; type CurrencyIdConversion = AssetIdMaps; type WeightInfo = weights::bifrost_vstoken_conversion::BifrostWeight; @@ -1409,10 +1398,7 @@ parameter_types! { impl bifrost_farming::Config for Runtime { type RuntimeEvent = RuntimeEvent; type MultiCurrency = Currencies; - type ControlOrigin = EitherOfDiverse< - TechAdmin, - EitherOfDiverse, - >; + type ControlOrigin = TechAdminOrCouncil; type TreasuryAccount = BifrostTreasuryAccount; type Keeper = FarmingKeeperPalletId; type RewardIssuer = FarmingRewardIssuerPalletId; @@ -1432,10 +1418,7 @@ parameter_types! { impl bifrost_system_staking::Config for Runtime { type RuntimeEvent = RuntimeEvent; type MultiCurrency = Currencies; - type EnsureConfirmAsGovernance = EitherOfDiverse< - CoreAdmin, - EitherOfDiverse, - >; + type EnsureConfirmAsGovernance = EitherOfDiverse; type WeightInfo = weights::bifrost_system_staking::BifrostWeight; type FarmingInfo = Farming; type VtokenMintingInterface = VtokenMinting; @@ -1463,7 +1446,7 @@ impl bifrost_system_maker::Config for Runtime { impl bifrost_fee_share::Config for Runtime { type RuntimeEvent = RuntimeEvent; type MultiCurrency = Currencies; - type ControlOrigin = EitherOfDiverse; + type ControlOrigin = CoreAdminOrCouncil; type WeightInfo = weights::bifrost_fee_share::BifrostWeight; type FeeSharePalletId = FeeSharePalletId; } @@ -1471,7 +1454,7 @@ impl bifrost_fee_share::Config for Runtime { impl bifrost_cross_in_out::Config for Runtime { type RuntimeEvent = RuntimeEvent; type MultiCurrency = Currencies; - type ControlOrigin = EitherOfDiverse; + type ControlOrigin = TechAdminOrCouncil; type EntrancePalletId = SlpEntrancePalletId; type WeightInfo = weights::bifrost_cross_in_out::BifrostWeight; type MaxLengthLimit = MaxLengthLimit; @@ -1479,6 +1462,7 @@ impl bifrost_cross_in_out::Config for Runtime { parameter_types! { pub const QueryTimeout: BlockNumber = 100; + pub const ReferendumCheckInterval: BlockNumber = 300; } pub struct DerivativeAccountTokenFilter; @@ -1502,6 +1486,7 @@ impl bifrost_vtoken_voting::Config for Runtime { type ParachainId = SelfParaChainId; type MaxVotes = ConstU32<256>; type QueryTimeout = QueryTimeout; + type ReferendumCheckInterval = ReferendumCheckInterval; type WeightInfo = weights::bifrost_vtoken_voting::BifrostWeight; } @@ -1615,10 +1600,7 @@ parameter_types! { impl bifrost_vtoken_minting::Config for Runtime { type RuntimeEvent = RuntimeEvent; type MultiCurrency = Currencies; - type ControlOrigin = EitherOfDiverse< - TechAdmin, - EitherOfDiverse, - >; + type ControlOrigin = TechAdminOrCouncil; type MaximumUnlockIdOfUser = MaximumUnlockIdOfUser; type MaximumUnlockIdOfTimeUnit = MaximumUnlockIdOfTimeUnit; type EntranceAccount = SlpEntrancePalletId; @@ -1639,7 +1621,7 @@ impl bifrost_vtoken_minting::Config for Runtime { impl bifrost_slpx::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type ControlOrigin = EitherOfDiverse; + type ControlOrigin = TechAdminOrCouncil; type MultiCurrency = Currencies; type DexOperator = ZenlinkProtocol; type VtokenMintingInterface = VtokenMinting; @@ -1680,7 +1662,7 @@ impl nutsfinance_stable_asset::Config for Runtime { impl bifrost_stable_pool::Config for Runtime { type WeightInfo = weights::bifrost_stable_pool::BifrostWeight; - type ControlOrigin = EitherOfDiverse; + type ControlOrigin = TechAdminOrCouncil; type CurrencyId = CurrencyId; type MultiCurrency = Currencies; type StableAsset = StableAsset; @@ -1914,8 +1896,18 @@ pub type CheckedExtrinsic = generic::CheckedExtrinsic; -parameter_types! { - pub const XcmActionStr: &'static str = "XcmAction"; +/// All migrations that will run on the next runtime upgrade. +/// +/// This contains the combined migrations of the last 10 releases. It allows to skip runtime +/// upgrades in case governance decides to do so. THE ORDER IS IMPORTANT. +pub type Migrations = migrations::Unreleased; + +/// The runtime migrations per release. +pub mod migrations { + use super::*; + + /// Unreleased migrations. Add new ones here: + pub type Unreleased = (bifrost_vtoken_voting::migration::v1::MigrateToV1,); } /// Executive: handles dispatch to the various modules. @@ -1925,62 +1917,9 @@ pub type Executive = frame_executive::Executive< frame_system::ChainContext, Runtime, AllPalletsWithSystem, - (migration::XcmInterfaceMigration, BLPOnRuntimeUpgrade), + Migrations, >; -use frame_support::traits::OnRuntimeUpgrade; -pub struct BLPOnRuntimeUpgrade(PhantomData); -impl OnRuntimeUpgrade for BLPOnRuntimeUpgrade { - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, &'static str> { - #[allow(unused_imports)] - use frame_support::{migration, Identity}; - log::info!("Bifrost `pre_upgrade`..."); - - let pool_count = nutsfinance_stable_asset::PoolCount::::get(); - for pool_id in 0..pool_count { - if let Some(old_metadata) = - bifrost_asset_registry::CurrencyMetadatas::::get(CurrencyId::BLP(pool_id)) - { - log::info!("Old currency_metadatas name is {:?}", old_metadata.name); - } - } - - Ok(vec![]) - } - - fn on_runtime_upgrade() -> Weight { - log::info!("Bifrost `on_runtime_upgrade`..."); - - let pool_count = nutsfinance_stable_asset::PoolCount::::get(); - let weight = bifrost_asset_registry::migration::update_blp_metadata::(pool_count); - - log::info!("Bifrost `on_runtime_upgrade finished`"); - - weight - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(_: sp_std::prelude::Vec) -> Result<(), &'static str> { - #[allow(unused_imports)] - use frame_support::{migration, Identity}; - log::info!("Bifrost `post_upgrade`..."); - - let pool_count = nutsfinance_stable_asset::PoolCount::::get(); - for pool_id in 0..pool_count { - if let Some(new_metadata) = - bifrost_asset_registry::CurrencyMetadatas::::get(CurrencyId::BLP(pool_id)) - { - let symbol = scale_info::prelude::format!("BLP{}", pool_id).as_bytes().to_vec(); - assert_eq!(new_metadata.symbol, symbol); - log::info!("New currency_metadatas name is {:?}", new_metadata.name); - } - } - - Ok(()) - } -} - #[cfg(feature = "runtime-benchmarks")] #[macro_use] extern crate frame_benchmarking; diff --git a/runtime/bifrost-kusama/src/xcm_config.rs b/runtime/bifrost-kusama/src/xcm_config.rs index e351797d4..1661bb3ee 100644 --- a/runtime/bifrost-kusama/src/xcm_config.rs +++ b/runtime/bifrost-kusama/src/xcm_config.rs @@ -905,7 +905,7 @@ parameter_types! { impl xcm_interface::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type UpdateOrigin = EitherOfDiverse; + type UpdateOrigin = TechAdminOrCouncil; type MultiCurrency = Currencies; type RelayNetwork = RelayNetwork; type RelaychainCurrencyId = RelayCurrencyId; @@ -918,4 +918,5 @@ impl xcm_interface::Config for Runtime { type SalpHelper = Salp; type ParachainId = SelfParaChainId; type CallBackTimeOut = ConstU32<10>; + type CurrencyIdConvert = AssetIdMaps; } diff --git a/runtime/bifrost-polkadot/src/governance/mod.rs b/runtime/bifrost-polkadot/src/governance/mod.rs index 2d21427b5..019de14ae 100644 --- a/runtime/bifrost-polkadot/src/governance/mod.rs +++ b/runtime/bifrost-polkadot/src/governance/mod.rs @@ -23,9 +23,19 @@ pub use bifrost_runtime_common::dollar; mod fellowship; mod origins; pub use origins::{ - custom_origins, Fellows, FellowshipAdmin, FellowshipExperts, FellowshipInitiates, + custom_origins, CoreAdmin, Fellows, FellowshipAdmin, FellowshipExperts, FellowshipInitiates, FellowshipMasters, ReferendumCanceller, ReferendumKiller, SALPAdmin, SystemStakingAdmin, - ValidatorElection, WhitelistedCaller, *, + TechAdmin, ValidatorElection, WhitelistedCaller, *, }; mod tracks; pub use tracks::TracksInfo; + +pub type CoreAdminOrCouncil = EitherOfDiverse< + CoreAdmin, + EitherOfDiverse, +>; + +pub type TechAdminOrCouncil = EitherOfDiverse< + TechAdmin, + EitherOfDiverse, +>; diff --git a/runtime/bifrost-polkadot/src/lib.rs b/runtime/bifrost-polkadot/src/lib.rs index 4a0e39371..d6a1e95c1 100644 --- a/runtime/bifrost-polkadot/src/lib.rs +++ b/runtime/bifrost-polkadot/src/lib.rs @@ -26,10 +26,8 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -pub mod migration; use bifrost_slp::{DerivativeAccountProvider, QueryResponseManager}; use core::convert::TryInto; -use frame_support::pallet_prelude::StorageVersion; // A few exports that help ease life for downstream crates. use cumulus_pallet_parachain_system::{RelayNumberStrictlyIncreases, RelaychainDataProvider}; pub use frame_support::{ @@ -100,7 +98,6 @@ pub use node_primitives::{ GLMR_TOKEN_ID, }; // zenlink imports -use bifrost_salp::remove_storage::RemoveUnusedQueryIdContributionInfo; use zenlink_protocol::{ AssetBalance, AssetId as ZenlinkAssetId, LocalAssetHandler, MultiAssetsHandler, PairInfo, PairLpGenerate, ZenlinkMultiAssets, @@ -117,7 +114,10 @@ use xcm_config::{ use xcm_executor::XcmExecutor; pub mod governance; -use governance::{custom_origins, CoreAdmin, TechAdmin}; +use governance::{ + custom_origins, CoreAdminOrCouncil, SALPAdmin, SystemStakingAdmin, TechAdmin, + TechAdminOrCouncil, ValidatorElection, +}; impl_opaque_keys! { pub struct SessionKeys { @@ -131,7 +131,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("bifrost_polkadot"), impl_name: create_runtime_str!("bifrost_polkadot"), authoring_version: 0, - spec_version: 982, + spec_version: 984, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -684,7 +684,7 @@ parameter_types! { pub const VotingBondFactor: Balance = deposit(0, 32); /// Daily council elections pub const TermDuration: BlockNumber = 7 * DAYS; - pub const DesiredMembers: u32 = 13; + pub const DesiredMembers: u32 = 3; pub const DesiredRunnersUp: u32 = 20; pub const PhragmenElectionPalletId: LockIdentifier = *b"phrelect"; pub const MaxVoters: u32 = 512; @@ -996,7 +996,7 @@ impl bifrost_flexible_fee::Config for Runtime { type WeightInfo = weights::bifrost_flexible_fee::BifrostWeight; type ExtraFeeMatcher = ExtraFeeMatcher; type ParachainId = ParachainInfo; - type ControlOrigin = EitherOfDiverse; + type ControlOrigin = TechAdminOrCouncil; type XcmWeightAndFeeHandler = XcmInterface; } @@ -1114,10 +1114,7 @@ impl bifrost_salp::Config for Runtime { type SlotLength = SlotLength; type VSBondValidPeriod = VSBondValidPeriod; type WeightInfo = weights::bifrost_salp::BifrostWeight; - type EnsureConfirmAsGovernance = EitherOfDiverse< - TechAdmin, - EitherOfDiverse, - >; + type EnsureConfirmAsGovernance = EitherOfDiverse; type XcmInterface = XcmInterface; type TreasuryAccount = BifrostTreasuryAccount; type BuybackPalletId = BuybackPalletId; @@ -1131,10 +1128,7 @@ impl bifrost_salp::Config for Runtime { impl bifrost_call_switchgear::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type UpdateOrigin = EitherOfDiverse< - CoreAdmin, - EitherOfDiverse, - >; + type UpdateOrigin = CoreAdminOrCouncil; type WeightInfo = weights::bifrost_call_switchgear::BifrostWeight; } @@ -1198,10 +1192,7 @@ impl bifrost_slp::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type MultiCurrency = Currencies; - type ControlOrigin = EitherOfDiverse< - TechAdmin, - EitherOfDiverse, - >; + type ControlOrigin = EitherOfDiverse; type WeightInfo = weights::bifrost_slp::BifrostWeight; type VtokenMinting = VtokenMinting; type BifrostSlpx = Slpx; @@ -1226,10 +1217,7 @@ impl bifrost_vstoken_conversion::Config for Runtime { type MultiCurrency = Currencies; type RelayCurrencyId = RelayCurrencyId; type TreasuryAccount = BifrostTreasuryAccount; - type ControlOrigin = EitherOfDiverse< - CoreAdmin, - EitherOfDiverse, - >; + type ControlOrigin = CoreAdminOrCouncil; type VsbondAccount = BifrostVsbondPalletId; type CurrencyIdConversion = AssetIdMaps; type WeightInfo = weights::bifrost_vstoken_conversion::BifrostWeight; @@ -1242,10 +1230,7 @@ parameter_types! { impl bifrost_farming::Config for Runtime { type RuntimeEvent = RuntimeEvent; type MultiCurrency = Currencies; - type ControlOrigin = EitherOfDiverse< - TechAdmin, - EitherOfDiverse, - >; + type ControlOrigin = TechAdminOrCouncil; type TreasuryAccount = BifrostTreasuryAccount; type Keeper = FarmingKeeperPalletId; type RewardIssuer = FarmingRewardIssuerPalletId; @@ -1265,10 +1250,7 @@ parameter_types! { impl bifrost_system_staking::Config for Runtime { type RuntimeEvent = RuntimeEvent; type MultiCurrency = Currencies; - type EnsureConfirmAsGovernance = EitherOfDiverse< - CoreAdmin, - EitherOfDiverse, - >; + type EnsureConfirmAsGovernance = EitherOfDiverse; type WeightInfo = weights::bifrost_system_staking::BifrostWeight; type FarmingInfo = Farming; type VtokenMintingInterface = VtokenMinting; @@ -1296,7 +1278,7 @@ impl bifrost_system_maker::Config for Runtime { impl bifrost_fee_share::Config for Runtime { type RuntimeEvent = RuntimeEvent; type MultiCurrency = Currencies; - type ControlOrigin = EitherOfDiverse; + type ControlOrigin = CoreAdminOrCouncil; type WeightInfo = weights::bifrost_fee_share::BifrostWeight; type FeeSharePalletId = FeeSharePalletId; } @@ -1304,7 +1286,7 @@ impl bifrost_fee_share::Config for Runtime { impl bifrost_cross_in_out::Config for Runtime { type RuntimeEvent = RuntimeEvent; type MultiCurrency = Currencies; - type ControlOrigin = EitherOfDiverse; + type ControlOrigin = TechAdminOrCouncil; type EntrancePalletId = SlpEntrancePalletId; type WeightInfo = weights::bifrost_cross_in_out::BifrostWeight; type MaxLengthLimit = MaxLengthLimit; @@ -1312,7 +1294,7 @@ impl bifrost_cross_in_out::Config for Runtime { impl bifrost_slpx::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type ControlOrigin = EitherOfDiverse; + type ControlOrigin = TechAdminOrCouncil; type MultiCurrency = Currencies; type DexOperator = ZenlinkProtocol; type VtokenMintingInterface = VtokenMinting; @@ -1353,7 +1335,7 @@ impl nutsfinance_stable_asset::Config for Runtime { impl bifrost_stable_pool::Config for Runtime { type WeightInfo = weights::bifrost_stable_pool::BifrostWeight; - type ControlOrigin = EitherOfDiverse; + type ControlOrigin = TechAdminOrCouncil; type CurrencyId = CurrencyId; type MultiCurrency = Currencies; type StableAsset = StableAsset; @@ -1364,6 +1346,7 @@ impl bifrost_stable_pool::Config for Runtime { parameter_types! { pub const QueryTimeout: BlockNumber = 100; + pub const ReferendumCheckInterval: BlockNumber = 300; } pub struct DerivativeAccountTokenFilter; @@ -1387,6 +1370,7 @@ impl bifrost_vtoken_voting::Config for Runtime { type ParachainId = SelfParaChainId; type MaxVotes = ConstU32<256>; type QueryTimeout = QueryTimeout; + type ReferendumCheckInterval = ReferendumCheckInterval; type WeightInfo = weights::bifrost_vtoken_voting::BifrostWeight; } @@ -1453,10 +1437,7 @@ parameter_types! { impl bifrost_vtoken_minting::Config for Runtime { type RuntimeEvent = RuntimeEvent; type MultiCurrency = Currencies; - type ControlOrigin = EitherOfDiverse< - TechAdmin, - EitherOfDiverse, - >; + type ControlOrigin = TechAdminOrCouncil; type MaximumUnlockIdOfUser = MaximumUnlockIdOfUser; type MaximumUnlockIdOfTimeUnit = MaximumUnlockIdOfTimeUnit; type EntranceAccount = SlpEntrancePalletId; @@ -1720,8 +1701,16 @@ pub type CheckedExtrinsic = generic::CheckedExtrinsic; -parameter_types! { - pub const XcmActionStr: &'static str = "XcmAction"; +/// All migrations that will run on the next runtime upgrade. +/// +/// This contains the combined migrations of the last 10 releases. It allows to skip runtime +/// upgrades in case governance decides to do so. THE ORDER IS IMPORTANT. +pub type Migrations = migrations::Unreleased; + +/// The runtime migrations per release. +pub mod migrations { + /// Unreleased migrations. Add new ones here: + pub type Unreleased = (); } /// Executive: handles dispatch to the various modules. @@ -1731,7 +1720,7 @@ pub type Executive = frame_executive::Executive< frame_system::ChainContext, Runtime, AllPalletsWithSystem, - (RemoveUnusedQueryIdContributionInfo, migration::XcmInterfaceMigration), + Migrations, >; #[cfg(feature = "runtime-benchmarks")] diff --git a/runtime/bifrost-polkadot/src/xcm_config.rs b/runtime/bifrost-polkadot/src/xcm_config.rs index 29be0e6e2..809744930 100644 --- a/runtime/bifrost-polkadot/src/xcm_config.rs +++ b/runtime/bifrost-polkadot/src/xcm_config.rs @@ -718,7 +718,7 @@ parameter_types! { impl xcm_interface::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type UpdateOrigin = EitherOfDiverse; + type UpdateOrigin = TechAdminOrCouncil; type MultiCurrency = Currencies; type RelayNetwork = RelayNetwork; type RelaychainCurrencyId = RelayCurrencyId; @@ -728,4 +728,5 @@ impl xcm_interface::Config for Runtime { type SalpHelper = Salp; type ParachainId = SelfParaChainId; type CallBackTimeOut = ConstU32<10>; + type CurrencyIdConvert = AssetIdMaps; }