From 897528a182255075160ef936e61b52e203f96587 Mon Sep 17 00:00:00 2001 From: SunTiebing <1045060705@qq.com> Date: Thu, 19 Sep 2024 12:06:24 +0800 Subject: [PATCH 01/30] Bifrost v0.14.0 --- Cargo.lock | 2 +- node/cli/Cargo.toml | 2 +- runtime/bifrost-kusama/src/lib.rs | 2 +- runtime/bifrost-polkadot/src/lib.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 008dbdeaa..3bcd412b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1011,7 +1011,7 @@ dependencies = [ [[package]] name = "bifrost-cli" -version = "0.13.0" +version = "0.14.0" dependencies = [ "bifrost-primitives", "bifrost-service", diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index 1adb0e8fb..11b753212 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bifrost-cli" -version = "0.13.0" +version = "0.14.0" authors = ["Liebi Technologies "] description = "Bifrost Parachain Node" build = "build.rs" diff --git a/runtime/bifrost-kusama/src/lib.rs b/runtime/bifrost-kusama/src/lib.rs index ee116c46a..eacd32e5b 100644 --- a/runtime/bifrost-kusama/src/lib.rs +++ b/runtime/bifrost-kusama/src/lib.rs @@ -145,7 +145,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("bifrost"), impl_name: create_runtime_str!("bifrost"), authoring_version: 1, - spec_version: 13000, + spec_version: 14000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/runtime/bifrost-polkadot/src/lib.rs b/runtime/bifrost-polkadot/src/lib.rs index db5bd4b9a..c35de71bb 100644 --- a/runtime/bifrost-polkadot/src/lib.rs +++ b/runtime/bifrost-polkadot/src/lib.rs @@ -169,7 +169,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: 13000, + spec_version: 14000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From ef3c9edaf8e73f9467c6e36ecc9cc6cffd9498de Mon Sep 17 00:00:00 2001 From: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Date: Mon, 23 Sep 2024 13:12:44 +0800 Subject: [PATCH 02/30] Feat/optimize salp (#1433) * Backup salp pallet * remove unused BancorHandler * remove unused Call of SALP * remove extra fee of bifrost_salp::Call::contribute in runtime * adjust test and benchmarking * remove unused interface type of SALP * fix clippy --- pallets/deprecated/salp/Cargo.toml | 78 + pallets/deprecated/salp/rpc/Cargo.toml | 16 + .../salp/rpc/runtime-api/Cargo.toml | 18 + .../salp/rpc/runtime-api/src/lib.rs | 35 + pallets/deprecated/salp/rpc/src/lib.rs | 101 + pallets/deprecated/salp/src/benchmarking.rs | 558 ++++++ pallets/deprecated/salp/src/lib.rs | 1756 +++++++++++++++++ pallets/deprecated/salp/src/mock.rs | 641 ++++++ pallets/deprecated/salp/src/tests.rs | 1604 +++++++++++++++ pallets/deprecated/salp/src/weights.rs | 458 +++++ pallets/flexible-fee/src/tests.rs | 43 - pallets/salp/src/benchmarking.rs | 246 +-- pallets/salp/src/lib.rs | 1164 ++++------- pallets/salp/src/mock.rs | 8 +- pallets/salp/src/tests.rs | 592 +----- pallets/salp/src/weights.rs | 89 - primitives/src/traits.rs | 12 +- runtime/bifrost-kusama/src/lib.rs | 5 - .../src/weights/bifrost_salp.rs | 85 - runtime/bifrost-kusama/src/xcm_config.rs | 7 +- runtime/bifrost-polkadot/src/lib.rs | 5 - .../src/weights/bifrost_salp.rs | 85 - runtime/bifrost-polkadot/src/xcm_config.rs | 7 +- 23 files changed, 5606 insertions(+), 2007 deletions(-) create mode 100644 pallets/deprecated/salp/Cargo.toml create mode 100644 pallets/deprecated/salp/rpc/Cargo.toml create mode 100644 pallets/deprecated/salp/rpc/runtime-api/Cargo.toml create mode 100644 pallets/deprecated/salp/rpc/runtime-api/src/lib.rs create mode 100644 pallets/deprecated/salp/rpc/src/lib.rs create mode 100644 pallets/deprecated/salp/src/benchmarking.rs create mode 100644 pallets/deprecated/salp/src/lib.rs create mode 100644 pallets/deprecated/salp/src/mock.rs create mode 100644 pallets/deprecated/salp/src/tests.rs create mode 100644 pallets/deprecated/salp/src/weights.rs diff --git a/pallets/deprecated/salp/Cargo.toml b/pallets/deprecated/salp/Cargo.toml new file mode 100644 index 000000000..ae26cb32e --- /dev/null +++ b/pallets/deprecated/salp/Cargo.toml @@ -0,0 +1,78 @@ +[package] +name = "bifrost-salp" +version = "0.8.0" +authors = ["Edwin Wang ", "Ron yang"] +edition = "2021" + +[dependencies] +parity-scale-codec = { workspace = true, features = ["derive"] } +scale-info = { workspace = true, features = ["derive"] } +log = { workspace = true } +bifrost-primitives = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-benchmarking = { workspace = true, optional = true } +sp-std = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +sp-arithmetic = { workspace = true } +orml-traits = { workspace = true } +orml-tokens = { workspace = true } +bifrost-xcm-interface = { workspace = true } +zenlink-protocol = { workspace = true } +cumulus-primitives-core = { workspace = true } +pallet-xcm = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } +bifrost-stable-pool = { workspace = true } +bifrost-stable-asset = { workspace = true } +bifrost-vtoken-minting = { workspace = true } + +[dev-dependencies] +pallet-multisig = { workspace = true } +pallet-sudo = { workspace = true } +pallet-collective = { workspace = true } +sp-core = { workspace = true } +bifrost-currencies = { workspace = true } +orml-xtokens = { workspace = true } +pallet-balances = { workspace = true } +bifrost-asset-registry = { workspace = true } +xcm-executor = { workspace = true } + + +[features] +default = ["std"] +std = [ + "parity-scale-codec/std", + "scale-info/std", + "log/std", + "bifrost-primitives/std", + "frame-support/std", + "frame-system/std", + "sp-std/std", + "sp-io/std", + "sp-runtime/std", + "sp-arithmetic/std", + "orml-traits/std", + "bifrost-xcm-interface/std", + "xcm-builder/std", + "zenlink-protocol/std", + "bifrost-asset-registry/std", + "cumulus-primitives-core/std", + "pallet-xcm/std", + "pallet-sudo/std", + "xcm/std", + "pallet-multisig/std", + "pallet-collective/std", + "orml-xtokens/std", +] + +runtime-benchmarks = [ + "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "pallet-collective/runtime-benchmarks", +] +try-runtime = [ "frame-support/try-runtime" ] diff --git a/pallets/deprecated/salp/rpc/Cargo.toml b/pallets/deprecated/salp/rpc/Cargo.toml new file mode 100644 index 000000000..1015d62ab --- /dev/null +++ b/pallets/deprecated/salp/rpc/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "bifrost-salp-rpc" +version = "0.8.0" +authors = ["Ron Yang "] +edition = "2021" + +[dependencies] +parity-scale-codec = { workspace = true, features = ["derive"] } +jsonrpsee = { workspace = true, features = ["server", "macros"] } +sp-api = { workspace = true } +sp-runtime = { workspace = true } +sp-blockchain = { workspace = true } +sp-core = { workspace = true } +sp-rpc = { workspace = true } +bifrost-primitives = { workspace = true } +bifrost-salp-rpc-runtime-api = { workspace = true } diff --git a/pallets/deprecated/salp/rpc/runtime-api/Cargo.toml b/pallets/deprecated/salp/rpc/runtime-api/Cargo.toml new file mode 100644 index 000000000..4d40d9b24 --- /dev/null +++ b/pallets/deprecated/salp/rpc/runtime-api/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "bifrost-salp-rpc-runtime-api" +version = "0.8.0" +authors = ["Ron Yang"] +edition = "2021" + +[dependencies] +parity-scale-codec = { workspace = true, features = ["derive"] } +sp-api = { workspace = true } +bifrost-primitives = { workspace = true } + +[features] +default = ["std"] +std = [ + "parity-scale-codec/std", + "sp-api/std", + "bifrost-primitives/std", +] diff --git a/pallets/deprecated/salp/rpc/runtime-api/src/lib.rs b/pallets/deprecated/salp/rpc/runtime-api/src/lib.rs new file mode 100644 index 000000000..108b16270 --- /dev/null +++ b/pallets/deprecated/salp/rpc/runtime-api/src/lib.rs @@ -0,0 +1,35 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . + +#![cfg_attr(not(feature = "std"), no_std)] + +use bifrost_primitives::{Balance, RpcContributionStatus}; +use parity_scale_codec::Codec; +use sp_api::decl_runtime_apis; + +decl_runtime_apis! { + pub trait SalpRuntimeApi where + ParaId: Codec, + AccountId: Codec, + { + fn get_contribution( + index: ParaId, + who: AccountId + ) -> (Balance,RpcContributionStatus); + } +} diff --git a/pallets/deprecated/salp/rpc/src/lib.rs b/pallets/deprecated/salp/rpc/src/lib.rs new file mode 100644 index 000000000..ebd2a8222 --- /dev/null +++ b/pallets/deprecated/salp/rpc/src/lib.rs @@ -0,0 +1,101 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 std::{marker::PhantomData, sync::Arc}; + +use bifrost_primitives::{Balance, RpcContributionStatus}; +pub use bifrost_salp_rpc_runtime_api::{self as runtime_api, SalpRuntimeApi}; +use jsonrpsee::{ + core::{async_trait, RpcResult}, + proc_macros::rpc, + types::error::{ErrorCode, ErrorObject}, +}; +use parity_scale_codec::Codec; +use sp_api::ProvideRuntimeApi; +use sp_blockchain::HeaderBackend; +use sp_rpc::number::NumberOrHex; +use sp_runtime::{sp_std::convert::TryInto, traits::Block as BlockT}; + +#[derive(Clone, Debug)] +pub struct SalpRpc { + client: Arc, + _marker: PhantomData, +} + +impl SalpRpc { + pub fn new(client: Arc) -> Self { + Self { client, _marker: PhantomData } + } +} + +fn convert_rpc_params(value: Balance) -> RpcResult { + value.try_into().map_err(|e| { + ErrorObject::owned( + ErrorCode::InvalidParams.code(), + format!("{} doesn't fit in NumberOrHex representation", value), + Some(format!("{:?}", e)), + ) + }) +} + +#[rpc(client, server)] +pub trait SalpRpcApi { + /// rpc method for getting current contribution + #[method(name = "salp_getContribution")] + fn get_contribution( + &self, + index: ParaId, + who: AccountId, + at: Option, + ) -> RpcResult<(NumberOrHex, RpcContributionStatus)>; +} + +#[async_trait] +impl SalpRpcApiServer<::Hash, ParaId, AccountId> + for SalpRpc +where + Block: BlockT, + C: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, + C::Api: SalpRuntimeApi, + ParaId: Codec, + AccountId: Codec, +{ + fn get_contribution( + &self, + index: ParaId, + account: AccountId, + at: Option<::Hash>, + ) -> RpcResult<(NumberOrHex, RpcContributionStatus)> { + let salp_rpc_api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + let rs = salp_rpc_api.get_contribution(at, index, account); + + match rs { + Ok((val, status)) => match convert_rpc_params(val) { + Ok(value) => Ok((value, status)), + Err(e) => Err(e), + }, + Err(e) => Err(ErrorObject::owned( + ErrorCode::InternalError.code(), + "Failed to get salp contribution.", + Some(format!("{:?}", e)), + )), + } + } +} diff --git a/pallets/deprecated/salp/src/benchmarking.rs b/pallets/deprecated/salp/src/benchmarking.rs new file mode 100644 index 000000000..cbb3f249b --- /dev/null +++ b/pallets/deprecated/salp/src/benchmarking.rs @@ -0,0 +1,558 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . + +// Ensure we're `no_std` when compiling for Wasm. +#[cfg(feature = "runtime-benchmarks")] +use crate::{Pallet as Salp, *}; +use bifrost_primitives::{CurrencyId, ParaId, XcmOperationType, KSM, VSKSM}; +use bifrost_stable_pool::AtLeast64BitUnsignedOf; +use bifrost_xcm_interface::XcmWeightAndFee; +use frame_benchmarking::v2::*; +use frame_support::assert_ok; +use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; +use sp_runtime::{ + traits::{AccountIdConversion, Bounded, StaticLookup, UniqueSaturatedFrom}, + SaturatedConversion, +}; +use sp_std::prelude::*; + +fn assert_last_event(generic_event: ::RuntimeEvent) { + let events = frame_system::Pallet::::events(); + let system_event: ::RuntimeEvent = generic_event.into(); + // compare to the last event record + let frame_system::EventRecord { event, .. } = &events[events.len() - 1]; + assert_eq!(event, &system_event); +} + +fn create_fund(id: u32) -> ParaId { + let cap = BalanceOf::::max_value(); + let first_period = 0u32.into(); + let last_period = 7u32.into(); + let para_id = id; + + assert_ok!(Salp::::create(RawOrigin::Root.into(), para_id, cap, first_period, last_period)); + + para_id +} + +fn contribute_fund( + index: ParaId, +) -> (T::AccountId, BalanceOf) +where + <::MultiCurrency as MultiCurrency< + ::AccountId, + >>::CurrencyId: From, +{ + let who: T::AccountId = whitelisted_caller(); + let value = T::MinContribution::get(); + assert_ok!(Salp::::set_balance(&who, value)); + XcmWeightAndFee::::insert( + bifrost_xcm_interface::CurrencyIdOf::::from(KSM.into()), + XcmOperationType::UmpContributeTransact, + ( + Weight::from_parts(4000000000, 100000), + bifrost_xcm_interface::BalanceOf::::from(4000000000u32), + ), + ); + assert_ok!(Salp::::contribute(RawOrigin::Signed(who.clone()).into(), index, value)); + QueryIdContributionInfo::::insert(0u64, (index, who.clone(), value)); + MultisigConfirmAccount::::put(who.clone()); + (who, value) +} + +#[benchmarks( +where T: Config + bifrost_stable_pool::Config + bifrost_stable_asset::Config + orml_tokens::Config + bifrost_vtoken_minting::Config + bifrost_xcm_interface::Config + zenlink_protocol::Config, +<::MultiCurrency as MultiCurrency<::AccountId>>::CurrencyId: From +)] +mod benchmarks { + use super::*; + + #[benchmark] + fn contribute() { + let fund_index = create_fund::(1); + let caller: T::AccountId = whitelisted_caller(); + let contribution = T::MinContribution::get(); + XcmWeightAndFee::::insert( + bifrost_xcm_interface::CurrencyIdOf::::from(KSM.into()), + XcmOperationType::UmpContributeTransact, + ( + Weight::from_parts(4000000000, 100000), + bifrost_xcm_interface::BalanceOf::::from(4000000000u32), + ), + ); + assert_ok!(Salp::::set_balance(&caller, contribution)); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), fund_index, contribution); + } + + #[benchmark] + fn refund() { + let fund_index = create_fund::(1); + let (caller, contribution) = contribute_fund::(fund_index); + assert_ok!(Pallet::::confirm_contribute( + RawOrigin::Signed(caller.clone()).into(), + 0u64, + true + )); + + assert_ok!(Salp::::fund_fail(RawOrigin::Root.into(), fund_index)); + assert_ok!(Salp::::withdraw(RawOrigin::Root.into(), fund_index)); + let fund = Funds::::get(fund_index).unwrap(); + let (_, status) = Salp::::contribution(fund.trie_index, &caller); + assert_eq!(status, ContributionStatus::Idle); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), fund_index, 0u32.into(), 7u32.into(), contribution); + + let (_, status) = Salp::::contribution(fund.trie_index, &caller); + assert_eq!(status, ContributionStatus::Idle); + assert_last_event::( + Event::::Refunded( + caller.clone(), + fund_index, + 0u32.into(), + 7u32.into(), + contribution, + ) + .into(), + ) + } + + #[benchmark] + fn unlock() { + let fund_index = create_fund::(1); + let (caller, _) = contribute_fund::(fund_index); + assert_ok!(Pallet::::confirm_contribute( + RawOrigin::Signed(caller.clone()).into(), + 0u64, + true + )); + + assert_ok!(Salp::::fund_success(RawOrigin::Root.into(), fund_index)); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), caller.clone(), fund_index); + } + + #[benchmark] + fn batch_unlock() { + let fund_index = create_fund::(1); + let caller: T::AccountId = whitelisted_caller(); + for _ in 0..5 { + let (caller, _) = contribute_fund::(fund_index); + assert_ok!(Pallet::::confirm_contribute( + RawOrigin::Signed(caller.clone()).into(), + 0u64, + true + )); + } + + assert_ok!(Salp::::fund_success(RawOrigin::Root.into(), fund_index)); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), fund_index); + } + + #[benchmark] + fn redeem() { + let fund_index = create_fund::(1); + let (caller, contribution) = contribute_fund::(fund_index); + assert_ok!(Pallet::::confirm_contribute( + RawOrigin::Signed(caller.clone()).into(), + 0u64, + true + )); + + assert_ok!(Salp::::fund_success(RawOrigin::Root.into(), fund_index)); + assert_ok!(Salp::::unlock( + RawOrigin::Signed(caller.clone()).into(), + caller.clone(), + fund_index + )); + assert_ok!(Salp::::fund_retire(RawOrigin::Root.into(), fund_index)); + assert_ok!(Salp::::withdraw(RawOrigin::Root.into(), fund_index)); + assert_eq!(RedeemPool::::get(), T::MinContribution::get()); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), fund_index, contribution); + + assert_eq!(RedeemPool::::get(), 0_u32.saturated_into()); + } + + #[benchmark] + fn set_multisig_confirm_account() { + #[extrinsic_call] + _(RawOrigin::Root, whitelisted_caller()); + } + + #[benchmark] + fn fund_success() { + let fund_index = create_fund::(1); + let (caller, _) = contribute_fund::(fund_index); + assert_ok!(Pallet::::confirm_contribute( + RawOrigin::Signed(caller.clone()).into(), + 0u64, + true + )); + + #[extrinsic_call] + _(RawOrigin::Root, fund_index); + } + + #[benchmark] + fn fund_fail() { + let fund_index = create_fund::(1); + let (caller, _) = contribute_fund::(fund_index); + assert_ok!(Pallet::::confirm_contribute( + RawOrigin::Signed(caller.clone()).into(), + 0u64, + true + )); + + #[extrinsic_call] + _(RawOrigin::Root, fund_index); + } + + #[benchmark] + fn continue_fund() { + let fund_index = create_fund::(1); + let (caller, _) = contribute_fund::(fund_index); + assert_ok!(Pallet::::confirm_contribute( + RawOrigin::Signed(caller.clone()).into(), + 0u64, + true + )); + + assert_ok!(Salp::::fund_fail(RawOrigin::Root.into(), fund_index)); + assert_ok!(Salp::::withdraw(RawOrigin::Root.into(), fund_index)); + #[extrinsic_call] + _(RawOrigin::Root, fund_index, 0u32.into(), 3u32.into()); + } + + #[benchmark] + fn fund_retire() { + let fund_index = create_fund::(1); + let (caller, _) = contribute_fund::(fund_index); + assert_ok!(Pallet::::confirm_contribute( + RawOrigin::Signed(caller.clone()).into(), + 0u64, + true + )); + + assert_ok!(Salp::::fund_success(RawOrigin::Root.into(), fund_index)); + assert_ok!(Salp::::unlock( + RawOrigin::Signed(caller.clone()).into(), + caller.clone(), + fund_index + )); + #[extrinsic_call] + _(RawOrigin::Root, fund_index); + } + + #[benchmark] + fn fund_end() { + let fund_index = create_fund::(1); + let (caller, _) = contribute_fund::(fund_index); + assert_ok!(Pallet::::confirm_contribute( + RawOrigin::Signed(caller.clone()).into(), + 0u64, + true + )); + + assert_ok!(Salp::::fund_fail(RawOrigin::Root.into(), fund_index)); + assert_ok!(Salp::::withdraw(RawOrigin::Root.into(), fund_index)); + #[extrinsic_call] + _(RawOrigin::Root, fund_index); + } + + #[benchmark] + fn create() { + #[extrinsic_call] + _(RawOrigin::Root, 2001u32, BalanceOf::::max_value(), 0u32.into(), 3u32.into()); + } + + #[benchmark] + fn edit() { + create_fund::(2001u32); + #[extrinsic_call] + _( + RawOrigin::Root, + 2001u32, + BalanceOf::::max_value(), + BalanceOf::::max_value(), + 0u32.into(), + 8u32.into(), + None, + ); + } + + #[benchmark] + fn confirm_contribute() { + let fund_index = create_fund::(1); + let (caller, _) = contribute_fund::(fund_index); + + #[extrinsic_call] + _(RawOrigin::Signed(caller), 0, true) + } + + #[benchmark] + fn withdraw() { + let fund_index = create_fund::(1); + contribute_fund::(fund_index); + + assert_ok!(Salp::::fund_fail(RawOrigin::Root.into(), fund_index)); + #[extrinsic_call] + _(RawOrigin::Root, fund_index) + } + + #[benchmark] + fn dissolve_refunded() { + let fund_index = create_fund::(1); + let (caller, _) = contribute_fund::(fund_index); + assert_ok!(Pallet::::confirm_contribute( + RawOrigin::Signed(caller.clone()).into(), + 0u64, + true + )); + + assert_ok!(Salp::::fund_fail(RawOrigin::Root.into(), fund_index)); + assert_ok!(Salp::::withdraw(RawOrigin::Root.into(), fund_index)); + assert_ok!(Salp::::continue_fund( + RawOrigin::Root.into(), + fund_index, + 2, + T::SlotLength::get() + 1 + )); + #[extrinsic_call] + _(RawOrigin::Root, fund_index, 0, 7) + } + + #[benchmark] + fn dissolve() { + let fund_index = create_fund::(1); + let (caller, _) = contribute_fund::(fund_index); + assert_ok!(Pallet::::confirm_contribute( + RawOrigin::Signed(caller.clone()).into(), + 0u64, + true + )); + + assert_ok!(Salp::::fund_success(RawOrigin::Root.into(), fund_index)); + assert_ok!(Salp::::fund_retire(RawOrigin::Root.into(), fund_index)); + assert_ok!(Salp::::withdraw(RawOrigin::Root.into(), fund_index)); + assert_ok!(Salp::::fund_end(RawOrigin::Root.into(), fund_index)); + #[extrinsic_call] + _(RawOrigin::Root, fund_index) + } + + #[benchmark] + fn buyback() { + let caller: T::AccountId = whitelisted_caller(); + let relay_currency_id = ::RelayChainToken::get(); + let relay_vstoken_id = + ::CurrencyIdConversion::convert_to_vstoken(relay_currency_id).unwrap(); + + let caller_lookup: ::Source = + T::Lookup::unlookup(caller.clone()); + assert_ok!(zenlink_protocol::Pallet::::create_pair( + RawOrigin::Root.into(), + zenlink_protocol::AssetId { chain_id: 2001, asset_type: 2, asset_index: 516 }, + zenlink_protocol::AssetId { chain_id: 2001, asset_type: 2, asset_index: 1028 }, + caller_lookup + )); + + let buybck_caller = T::BuybackPalletId::get().into_account_truncating(); + assert_ok!(::MultiCurrency::deposit( + relay_currency_id, + &buybck_caller, + BalanceOf::::unique_saturated_from(1_000_000_000_000_000u128) + )); + assert_ok!(::MultiCurrency::deposit( + relay_vstoken_id, + &buybck_caller, + BalanceOf::::unique_saturated_from(1_000_000_000_000_000u128) + )); + + assert_ok!(zenlink_protocol::Pallet::::add_liquidity( + RawOrigin::Signed(buybck_caller).into(), + zenlink_protocol::AssetId { chain_id: 2001, asset_type: 2, asset_index: 516 }, + zenlink_protocol::AssetId { chain_id: 2001, asset_type: 2, asset_index: 1028 }, + 1_000_000_000_000u128, + 100_000_000_000_000u128, + 0u128, + 0u128, + BlockNumberFor::::from(10u32), + )); + + #[extrinsic_call] + _(RawOrigin::Signed(caller), BalanceOf::::unique_saturated_from(1000u128)) + } + + #[benchmark] + fn buyback_vstoken_by_stable_pool() { + let caller: T::AccountId = whitelisted_caller(); + let fee_account: T::AccountId = account("seed", 1, 1); + let buyback_account: T::AccountId = T::BuybackPalletId::get().into_account_truncating(); + + let amounts1: AtLeast64BitUnsignedOf = 1_000_000_000_000u128.into(); + let amounts: ::Balance = amounts1.into(); + assert_ok!(bifrost_stable_pool::Pallet::::create_pool( + RawOrigin::Root.into(), + vec![KSM.into(), VSKSM.into()], + vec![1u128.into(), 1u128.into()], + 0u128.into(), + 0u128.into(), + 0u128.into(), + 220u128.into(), + fee_account.clone(), + fee_account.clone(), + 1000000000000u128.into() + )); + assert_ok!(bifrost_stable_pool::Pallet::::edit_token_rate( + RawOrigin::Root.into(), + 0, + vec![ + (VSKSM.into(), (1u128.into(), 1u128.into())), + (KSM.into(), (10u128.into(), 30u128.into())) + ] + )); + + assert_ok!(::MultiCurrency::deposit( + KSM, + &buyback_account, + BalanceOf::::unique_saturated_from(1_000_000_000_000_000_000u128) + )); + assert_ok!(::MultiCurrency::deposit( + KSM, + &caller, + BalanceOf::::unique_saturated_from(1_000_000_000_000_000_000u128) + )); + assert_ok!(::MultiCurrency::deposit( + VSKSM, + &caller, + BalanceOf::::unique_saturated_from(1_000_000_000_000_000_000u128) + )); + + assert_ok!(bifrost_stable_pool::Pallet::::add_liquidity( + RawOrigin::Signed(caller.clone()).into(), + 0, + vec![amounts, amounts], + amounts + )); + let minimum_mint_value = + bifrost_vtoken_minting::BalanceOf::::unique_saturated_from(0u128); + let token_amount = + bifrost_vtoken_minting::BalanceOf::::unique_saturated_from(1_000_000_000_000u128); + assert_ok!(bifrost_vtoken_minting::Pallet::::set_minimum_mint( + RawOrigin::Root.into(), + KSM, + minimum_mint_value + )); + assert_ok!(bifrost_vtoken_minting::Pallet::::mint( + RawOrigin::Signed(caller.clone()).into(), + KSM, + token_amount, + BoundedVec::default(), + None + )); + #[extrinsic_call] + _(RawOrigin::Signed(caller), 0, KSM, 1_000_000_000u32.into()) + } + + #[benchmark] + fn reserve() { + let fund_index = create_fund::(1); + let (caller, contribution) = contribute_fund::(fund_index); + assert_ok!(Pallet::::confirm_contribute( + RawOrigin::Signed(caller.clone()).into(), + 0u64, + true + )); + + assert_ok!(Salp::::fund_success(RawOrigin::Root.into(), fund_index)); + assert_ok!(Salp::::unlock( + RawOrigin::Signed(caller.clone()).into(), + caller.clone(), + fund_index + )); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), fund_index, contribution, false); + } + + #[benchmark] + fn cancel_reservation() { + let fund_index = create_fund::(1); + let (caller, contribution) = contribute_fund::(fund_index); + assert_ok!(Pallet::::confirm_contribute( + RawOrigin::Signed(caller.clone()).into(), + 0u64, + true + )); + + assert_ok!(Salp::::fund_success(RawOrigin::Root.into(), fund_index)); + assert_ok!(Salp::::unlock( + RawOrigin::Signed(caller.clone()).into(), + caller.clone(), + fund_index + )); + assert_ok!(Salp::::reserve( + RawOrigin::Signed(caller.clone()).into(), + fund_index, + contribution, + false + )); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), fund_index); + } + + #[benchmark] + fn batch_handle_reserve() { + let fund_index = create_fund::(1); + let (caller, contribution) = contribute_fund::(fund_index); + assert_ok!(Pallet::::confirm_contribute( + RawOrigin::Signed(caller.clone()).into(), + 0u64, + true + )); + + assert_ok!(Salp::::fund_success(RawOrigin::Root.into(), fund_index)); + assert_ok!(Salp::::unlock( + RawOrigin::Signed(caller.clone()).into(), + caller.clone(), + fund_index + )); + assert_ok!(Salp::::reserve( + RawOrigin::Signed(caller.clone()).into(), + fund_index, + contribution, + false + )); + assert_ok!(Salp::::fund_retire(RawOrigin::Root.into(), fund_index)); + assert_ok!(Salp::::withdraw(RawOrigin::Root.into(), fund_index)); + assert_eq!(RedeemPool::::get(), T::MinContribution::get()); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), fund_index); + } + + // `cargo test -p pallet-example-basic --all-features`, you will see one line per case: + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/pallets/deprecated/salp/src/lib.rs b/pallets/deprecated/salp/src/lib.rs new file mode 100644 index 000000000..b2fae3ff3 --- /dev/null +++ b/pallets/deprecated/salp/src/lib.rs @@ -0,0 +1,1756 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . + +// Ensure we're `no_std` when compiling for Wasm. +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; +#[cfg(test)] +pub mod mock; +#[cfg(test)] +mod tests; +pub mod weights; +pub use weights::WeightInfo; + +// Re-export pallet items so that they can be accessed from the crate namespace. +use bifrost_primitives::{ + ContributionStatus, CurrencyIdConversion, CurrencyIdRegister, TrieIndex, TryConvertFrom, + VtokenMintingInterface, +}; +use bifrost_stable_pool::{traits::StablePoolHandler, StableAssetPoolId}; +use bifrost_xcm_interface::ChainId; +use cumulus_primitives_core::{QueryId, Response}; +use frame_support::{pallet_prelude::*, sp_runtime::SaturatedConversion, traits::LockIdentifier}; +use orml_traits::MultiCurrency; +pub use pallet::*; +use pallet_xcm::ensure_response; +use scale_info::TypeInfo; +use sp_runtime::traits::One; +use zenlink_protocol::{AssetId, ExportZenlink}; + +pub type AccountIdOf = ::AccountId; + +type BalanceOf = <::MultiCurrency as MultiCurrency>>::Balance; + +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +pub enum FundStatus { + Ongoing, + Retired, + Success, + Failed, + RefundWithdrew, + RedeemWithdrew, + FailedToContinue, + End, +} + +impl Default for FundStatus { + fn default() -> Self { + FundStatus::Ongoing + } +} + +/// Information on a funding effort for a pre-existing parachain. We assume that the parachain +/// ID is known as it's used for the key of the storage item for which this is the value +/// (`Funds`). +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[codec(dumb_trait_bound)] +pub struct FundInfo { + /// The total amount raised. + pub raised: Balance, + /// A hard-cap on the amount that may be contributed. + pub cap: Balance, + /// First slot in range to bid on; it's actually a LeasePeriod, but that's the same type as + /// BlockNumber. + pub first_slot: LeasePeriod, + /// Last slot in range to bid on; it's actually a LeasePeriod, but that's the same type as + /// BlockNumber. + pub last_slot: LeasePeriod, + /// Index used for the child trie of this fund + pub trie_index: TrieIndex, + /// Fund status + pub status: FundStatus, +} + +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, Default)] +pub struct ReserveInfo { + value: Balance, + if_mint: bool, +} + +#[frame_support::pallet] +pub mod pallet { + // Import various types used to declare pallet in scope. + use bifrost_primitives::{ + BancorHandler, CurrencyId, CurrencyId::VSBond, LeasePeriod, MessageId, Nonce, ParaId, + }; + use bifrost_xcm_interface::traits::XcmHelper; + use frame_support::{ + pallet_prelude::{storage::child, *}, + sp_runtime::traits::{AccountIdConversion, CheckedAdd, Hash, Saturating, Zero}, + storage::ChildTriePrefixIterator, + PalletId, + }; + use frame_system::pallet_prelude::*; + use orml_traits::{ + currency::TransferAll, MultiCurrency, MultiLockableCurrency, MultiReservableCurrency, + }; + use sp_arithmetic::Percent; + use sp_std::{convert::TryInto, prelude::*}; + use xcm::v3::MaybeErrorCode; + + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type RuntimeOrigin: IsType<::RuntimeOrigin> + + Into::RuntimeOrigin>>; + + type RuntimeCall: Parameter + From>; + + /// ModuleID for the crowdloan module. An appropriate value could be + /// ```ModuleId(*b"py/cfund")``` + #[pallet::constant] + type PalletId: Get; + + /// The minimum amount that may be contributed into a crowdloan. Should almost certainly be + /// at least ExistentialDeposit. + #[pallet::constant] + type MinContribution: Get>; + + #[pallet::constant] + type RelayChainToken: Get; + + /// The number of blocks over which a single period lasts. + #[pallet::constant] + type LeasePeriod: Get>; + + #[pallet::constant] + type VSBondValidPeriod: Get>; + + /// The time interval from 1:1 redeem-pool to bancor-pool to release. + #[pallet::constant] + type ReleaseCycle: Get>; + + /// The release ratio from the 1:1 redeem-pool to the bancor-pool per cycle. + /// + /// **NOTE: THE RELEASE RATIO MUST BE IN [0, 1].** + #[pallet::constant] + type ReleaseRatio: Get; + + #[pallet::constant] + type RemoveKeysLimit: Get; + + #[pallet::constant] + type SlotLength: Get; + + type MultiCurrency: TransferAll> + + MultiCurrency, CurrencyId = CurrencyId> + + MultiReservableCurrency, CurrencyId = CurrencyId> + + MultiLockableCurrency>; + + type BancorPool: BancorHandler>; + + type EnsureConfirmAsGovernance: EnsureOrigin<::RuntimeOrigin>; + + type WeightInfo: WeightInfo; + + /// The XcmInterface to manage the staking of sub-account on relaychain. + type XcmInterface: XcmHelper, BalanceOf>; + + #[pallet::constant] + type TreasuryAccount: Get; + + #[pallet::constant] + type BuybackPalletId: Get; + + type DexOperator: ExportZenlink; + + type CurrencyIdConversion: CurrencyIdConversion; + + type CurrencyIdRegister: CurrencyIdRegister; + + type ParachainId: Get; + + type StablePool: StablePoolHandler, AccountId = Self::AccountId>; + + type VtokenMinting: VtokenMintingInterface>; + + #[pallet::constant] + type LockId: Get; + + #[pallet::constant] + type BatchLimit: Get; + } + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Create a new crowdloaning campaign. [fund_index] + Created(ParaId), + /// Contributing to a crowd sale. [who, fund_index, amount] + Contributing(AccountIdOf, ParaId, BalanceOf, MessageId), + /// Contributed to a crowd sale. [who, fund_index, amount] + Contributed(AccountIdOf, ParaId, BalanceOf), + /// Fail on contribute to crowd sale. [who, fund_index, amount] + ContributeFailed(AccountIdOf, ParaId, BalanceOf), + /// Withdrew full balance of a contributor. [who, fund_index, amount] + Withdrew(ParaId, BalanceOf), + /// refund to account. [who, fund_index,value] + Refunded(AccountIdOf, ParaId, LeasePeriod, LeasePeriod, BalanceOf), + /// all refund + AllRefunded(ParaId), + /// redeem to account. [who, fund_index, first_slot, last_slot, value] + Redeemed(AccountIdOf, ParaId, LeasePeriod, LeasePeriod, BalanceOf), + /// Fund is edited. [fund_index] + Edited(ParaId), + /// Fund is dissolved. [fund_index] + Dissolved(ParaId), + /// The vsToken/vsBond was be unlocked. [who, fund_index, value] + Unlocked(AccountIdOf, ParaId, BalanceOf), + AllUnlocked(ParaId), + /// Fund status change + Failed(ParaId), + Success(ParaId), + Retired(ParaId), + End(ParaId), + Continued(ParaId, LeasePeriod, LeasePeriod), + RefundedDissolved(ParaId, LeasePeriod, LeasePeriod), + Buyback(BalanceOf), + VstokenUnlocked(AccountIdOf), + BuybackByStablePool { + pool_id: StableAssetPoolId, + currency_id_in: CurrencyId, + value: BalanceOf, + }, + Reserved { + who: AccountIdOf, + para_id: ParaId, + value: BalanceOf, + if_mint: bool, + }, + ReservationCancelled { + who: AccountIdOf, + para_id: ParaId, + }, + ReservationFullyHandled { + para_id: ParaId, + }, + ReservationHandled { + para_id: ParaId, + }, + } + + #[pallet::error] + pub enum Error { + /// The first slot needs to at least be less than 3 `max_value`. + FirstSlotTooFarInFuture, + /// Last slot must be greater than first slot. + LastSlotBeforeFirstSlot, + /// The last slot cannot be more then 3 slots after the first slot. + LastSlotTooFarInFuture, + /// There was an overflow. + Overflow, + /// The contribution was below the minimum, `MinContribution`. + ContributionTooSmall, + /// The account doesn't have any contribution to the fund. + ZeroContribution, + /// Invalid fund index. + InvalidParaId, + /// Invalid fund status. + InvalidFundStatus, + /// Invalid contribution status. + InvalidContributionStatus, + /// Contributions exceed maximum amount. + CapExceeded, + /// The fund has been registered. + FundAlreadyCreated, + /// Crosschain xcm failed + XcmFailed, + /// Don't have enough vsToken/vsBond to refund + NotEnoughReservedAssetsToRefund, + /// Don't have enough token to refund by users + NotEnoughBalanceInRefundPool, + /// Don't have enough vsToken/vsBond to unlock + NotEnoughBalanceToUnlock, + /// The vsBond is expired now + VSBondExpired, + /// The vsBond cannot be redeemed by now + UnRedeemableNow, + /// Dont have enough vsToken/vsBond to redeem + NotEnoughFreeAssetsToRedeem, + /// Don't have enough token to redeem by users + NotEnoughBalanceInRedeemPool, + NotEnoughBalanceInFund, + InvalidFundSameSlot, + InvalidFundNotExist, + InvalidRefund, + NotEnoughBalanceToContribute, + NotSupportTokenType, + /// Responder is not a relay chain + ResponderNotRelayChain, + /// No contribution record found + NotFindContributionValue, + ArgumentsError, + } + + /// Multisig confirm account + #[pallet::storage] + pub type MultisigConfirmAccount = StorageValue<_, AccountIdOf, OptionQuery>; + + /// Tracker for the next available fund index + #[pallet::storage] + pub(super) type CurrentTrieIndex = StorageValue<_, TrieIndex, ValueQuery>; + + /// Tracker for the next nonce index + #[pallet::storage] + pub(super) type CurrentNonce = + StorageMap<_, Blake2_128Concat, ParaId, Nonce, ValueQuery>; + + /// Record contribution + #[pallet::storage] + pub type QueryIdContributionInfo = + StorageMap<_, Blake2_128Concat, QueryId, (ParaId, AccountIdOf, BalanceOf)>; + + /// Info on all of the funds. + #[pallet::storage] + pub(super) type Funds = StorageMap< + _, + Blake2_128Concat, + ParaId, + Option, LeasePeriod>>, + ValueQuery, + >; + + /// The balance can be redeemed to users. + #[pallet::storage] + pub type RedeemPool = StorageValue<_, BalanceOf, ValueQuery>; + + #[pallet::storage] + pub(super) type FailedFundsToRefund = StorageNMap< + _, + ( + NMapKey, + NMapKey, + NMapKey, + ), + Option, LeasePeriod>>, + ValueQuery, + >; + + #[pallet::storage] + pub type ReserveInfos = StorageDoubleMap< + _, + Twox64Concat, + ParaId, + Twox64Concat, + T::AccountId, + ReserveInfo>, + ValueQuery, + >; + + #[pallet::genesis_config] + #[derive(frame_support::DefaultNoBound)] + pub struct GenesisConfig { + pub initial_multisig_account: Option>, + } + + #[pallet::genesis_build] + impl BuildGenesisConfig for GenesisConfig { + fn build(&self) { + if let Some(ref key) = self.initial_multisig_account { + MultisigConfirmAccount::::put(key) + } + } + } + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight(T::WeightInfo::set_multisig_confirm_account())] + pub fn set_multisig_confirm_account( + origin: OriginFor, + account: AccountIdOf, + ) -> DispatchResult { + T::EnsureConfirmAsGovernance::ensure_origin(origin)?; + + Self::set_multisig_account(account); + + Ok(()) + } + + #[pallet::call_index(1)] + #[pallet::weight(T::WeightInfo::fund_success())] + pub fn fund_success( + origin: OriginFor, + #[pallet::compact] index: ParaId, + ) -> DispatchResult { + T::EnsureConfirmAsGovernance::ensure_origin(origin)?; + + let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + ensure!(fund.status == FundStatus::Ongoing, Error::::InvalidFundStatus); + + let fund_new = FundInfo { status: FundStatus::Success, ..fund }; + Funds::::insert(index, Some(fund_new)); + Self::deposit_event(Event::::Success(index)); + + Ok(()) + } + + #[pallet::call_index(2)] + #[pallet::weight(T::WeightInfo::fund_fail())] + pub fn fund_fail(origin: OriginFor, #[pallet::compact] index: ParaId) -> DispatchResult { + T::EnsureConfirmAsGovernance::ensure_origin(origin)?; + + // crownload is failed, so enable the withdrawal function of vsToken/vsBond + let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + ensure!(fund.status == FundStatus::Ongoing, Error::::InvalidFundStatus); + + let fund_new = FundInfo { status: FundStatus::Failed, ..fund }; + Funds::::insert(index, Some(fund_new)); + Self::deposit_event(Event::::Failed(index)); + + Ok(()) + } + + #[pallet::call_index(3)] + #[pallet::weight(T::WeightInfo::continue_fund())] + pub fn continue_fund( + origin: OriginFor, + #[pallet::compact] index: ParaId, + #[pallet::compact] first_slot: LeasePeriod, + #[pallet::compact] last_slot: LeasePeriod, + ) -> DispatchResult { + T::EnsureConfirmAsGovernance::ensure_origin(origin)?; + + // crownload is failed, so enable the withdrawal function of vsToken/vsBond + let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + ensure!(fund.status == FundStatus::RefundWithdrew, Error::::InvalidFundStatus); + ensure!( + fund.first_slot != first_slot || fund.last_slot != last_slot, + Error::::InvalidFundSameSlot + ); + + let fund_old = FundInfo { status: FundStatus::FailedToContinue, ..fund }; + FailedFundsToRefund::::insert( + (index, fund.first_slot, fund.last_slot), + Some(fund_old.clone()), + ); + let fund_new = FundInfo { status: FundStatus::Ongoing, first_slot, last_slot, ..fund }; + Funds::::insert(index, Some(fund_new)); + + match T::RelayChainToken::get() { + CurrencyId::Token(token_symbol) => + if !T::CurrencyIdRegister::check_vsbond_registered( + token_symbol, + index, + first_slot, + last_slot, + ) { + T::CurrencyIdRegister::register_vsbond_metadata( + token_symbol, + index, + first_slot, + last_slot, + )?; + }, + CurrencyId::Token2(token_id) => { + if !T::CurrencyIdRegister::check_vsbond2_registered( + token_id, index, first_slot, last_slot, + ) { + T::CurrencyIdRegister::register_vsbond2_metadata( + token_id, index, first_slot, last_slot, + )?; + } + }, + _ => (), + } + + Self::deposit_event(Event::::Continued( + index, + fund_old.first_slot, + fund_old.last_slot, + )); + + Ok(()) + } + + #[pallet::call_index(4)] + #[pallet::weight(T::WeightInfo::fund_retire())] + pub fn fund_retire( + origin: OriginFor, + #[pallet::compact] index: ParaId, + ) -> DispatchResult { + T::EnsureConfirmAsGovernance::ensure_origin(origin)?; + + let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + ensure!(fund.status == FundStatus::Success, Error::::InvalidFundStatus); + + let fund_new = FundInfo { status: FundStatus::Retired, ..fund }; + Funds::::insert(index, Some(fund_new)); + Self::deposit_event(Event::::Retired(index)); + + Ok(()) + } + + #[pallet::call_index(5)] + #[pallet::weight(T::WeightInfo::fund_end())] + pub fn fund_end(origin: OriginFor, #[pallet::compact] index: ParaId) -> DispatchResult { + T::EnsureConfirmAsGovernance::ensure_origin(origin)?; + + let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + ensure!( + fund.status == FundStatus::RefundWithdrew || + fund.status == FundStatus::RedeemWithdrew, + Error::::InvalidFundStatus + ); + + let fund_new = FundInfo { status: FundStatus::End, ..fund }; + Funds::::insert(index, Some(fund_new)); + Self::deposit_event(Event::::End(index)); + + Ok(()) + } + + /// Create a new crowdloaning campaign for a parachain slot deposit for the current auction. + #[pallet::call_index(6)] + #[pallet::weight(T::WeightInfo::create())] + pub fn create( + origin: OriginFor, + #[pallet::compact] index: ParaId, + #[pallet::compact] cap: BalanceOf, + #[pallet::compact] first_slot: LeasePeriod, + #[pallet::compact] last_slot: LeasePeriod, + ) -> DispatchResult { + T::EnsureConfirmAsGovernance::ensure_origin(origin)?; + + ensure!(!Funds::::contains_key(index), Error::::FundAlreadyCreated); + + ensure!(first_slot <= last_slot, Error::::LastSlotBeforeFirstSlot); + + let last_slot_limit = first_slot + .checked_add(((T::SlotLength::get() as u32) - 1).into()) + .ok_or(Error::::FirstSlotTooFarInFuture)?; + ensure!(last_slot <= last_slot_limit, Error::::LastSlotTooFarInFuture); + + Funds::::insert( + index, + Some(FundInfo { + raised: Zero::zero(), + cap, + first_slot, + last_slot, + trie_index: Self::next_trie_index()?, + status: FundStatus::Ongoing, + }), + ); + + match T::RelayChainToken::get() { + CurrencyId::Token(token_symbol) => + if !T::CurrencyIdRegister::check_vsbond_registered( + token_symbol, + index, + first_slot, + last_slot, + ) { + T::CurrencyIdRegister::register_vsbond_metadata( + token_symbol, + index, + first_slot, + last_slot, + )?; + }, + CurrencyId::Token2(token_id) => { + if !T::CurrencyIdRegister::check_vsbond2_registered( + token_id, index, first_slot, last_slot, + ) { + T::CurrencyIdRegister::register_vsbond2_metadata( + token_id, index, first_slot, last_slot, + )?; + } + }, + _ => (), + } + + Self::deposit_event(Event::::Created(index)); + + Ok(()) + } + + /// Edit the configuration for an in-progress crowdloan. + /// + /// Can only be called by Root origin. + #[pallet::call_index(7)] + #[pallet::weight(T::WeightInfo::edit())] + pub fn edit( + origin: OriginFor, + #[pallet::compact] index: ParaId, + #[pallet::compact] cap: BalanceOf, + #[pallet::compact] raised: BalanceOf, + #[pallet::compact] first_slot: LeasePeriod, + #[pallet::compact] last_slot: LeasePeriod, + fund_status: Option, + ) -> DispatchResult { + T::EnsureConfirmAsGovernance::ensure_origin(origin)?; + + let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + + let status = match fund_status { + None => fund.status, + Some(status) => status, + }; + Funds::::insert( + index, + Some(FundInfo { + cap, + first_slot, + last_slot, + status, + raised, + trie_index: fund.trie_index, + }), + ); + Self::deposit_event(Event::::Edited(index)); + Ok(()) + } + + /// Contribute to a crowd sale. This will transfer some balance over to fund a parachain + /// slot. It will be withdrawable in two instances: the parachain becomes retired; or the + /// slot is unable to be purchased and the timeout expires. + #[pallet::call_index(8)] + #[pallet::weight(T::WeightInfo::contribute())] + pub fn contribute( + origin: OriginFor, + #[pallet::compact] index: ParaId, + #[pallet::compact] value: BalanceOf, + ) -> DispatchResult { + let who = ensure_signed(origin.clone())?; + + let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + ensure!(fund.status == FundStatus::Ongoing, Error::::InvalidFundStatus); + + ensure!(value >= T::MinContribution::get(), Error::::ContributionTooSmall); + + let raised = fund.raised.checked_add(&value).ok_or(Error::::Overflow)?; + ensure!(raised <= fund.cap, Error::::CapExceeded); + + let (contributed, status) = Self::contribution(fund.trie_index, &who); + ensure!( + status == ContributionStatus::Idle || + status == ContributionStatus::Refunded || + status == ContributionStatus::Redeemed || + status == ContributionStatus::Unlocked, + Error::::InvalidContributionStatus + ); + + ensure!( + T::MultiCurrency::can_reserve(T::RelayChainToken::get(), &who, value), + Error::::NotEnoughBalanceToContribute + ); + + T::MultiCurrency::reserve(T::RelayChainToken::get(), &who, value)?; + + Self::put_contribution( + fund.trie_index, + &who, + contributed, + ContributionStatus::Contributing(value), + ); + + let message_id = T::XcmInterface::contribute(who.clone(), index, value)?; + + Self::deposit_event(Event::Contributing(who, index, value, message_id)); + Ok(()) + } + + /// Confirm contribute + #[pallet::call_index(9)] + #[pallet::weight(T::WeightInfo::confirm_contribute())] + pub fn confirm_contribute( + origin: OriginFor, + query_id: QueryId, + is_success: bool, + ) -> DispatchResult { + let confirmor = ensure_signed(origin.clone())?; + if Some(confirmor) != MultisigConfirmAccount::::get() { + return Err(DispatchError::BadOrigin.into()); + } + + let (index, contributer, _amount) = QueryIdContributionInfo::::get(query_id) + .ok_or(Error::::NotFindContributionValue)?; + + let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + let can_confirm = fund.status == FundStatus::Ongoing || + fund.status == FundStatus::Failed || + fund.status == FundStatus::Success; + ensure!(can_confirm, Error::::InvalidFundStatus); + + let (contributed, status) = Self::contribution(fund.trie_index, &contributer); + ensure!(status.is_contributing(), Error::::InvalidContributionStatus); + let contributing = status.contributing(); + + let vs_token = T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) + .map_err(|_| Error::::NotSupportTokenType)?; + let vs_bond = T::CurrencyIdConversion::convert_to_vsbond( + T::RelayChainToken::get(), + index, + fund.first_slot, + fund.last_slot, + ) + .map_err(|_| Error::::NotSupportTokenType)?; + + if is_success { + // Issue reserved vsToken/vsBond to contributor + T::MultiCurrency::deposit(vs_token, &contributer, contributing)?; + T::MultiCurrency::deposit(vs_bond, &contributer, contributing)?; + + // Update the raised of fund + let fund_new = + FundInfo { raised: fund.raised.saturating_add(contributing), ..fund }; + Funds::::insert(index, Some(fund_new)); + + T::MultiCurrency::unreserve(T::RelayChainToken::get(), &contributer, contributing); + T::MultiCurrency::transfer( + T::RelayChainToken::get(), + &contributer, + &Self::fund_account_id(index), + contributing, + )?; + + // Update the contribution of contributer + let contributed_new = contributed.saturating_add(contributing); + Self::put_contribution( + fund.trie_index, + &contributer, + contributed_new, + ContributionStatus::Idle, + ); + Self::deposit_event(Event::Contributed(contributer, index, contributing)); + } else { + // Update the contribution of contributer + Self::put_contribution( + fund.trie_index, + &contributer, + contributed, + ContributionStatus::Idle, + ); + T::MultiCurrency::unreserve(T::RelayChainToken::get(), &contributer, contributing); + Self::deposit_event(Event::ContributeFailed(contributer, index, contributing)); + } + + QueryIdContributionInfo::::remove(query_id); + + Ok(()) + } + + /// Unlock the reserved vsToken/vsBond after fund success + #[pallet::call_index(10)] + #[pallet::weight(T::WeightInfo::unlock())] + pub fn unlock( + origin: OriginFor, + who: AccountIdOf, + #[pallet::compact] index: ParaId, + ) -> DispatchResult { + ensure_signed(origin)?; + let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + + let (contributed, _) = Self::contribution(fund.trie_index, &who); + + let vs_token = T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) + .map_err(|_| Error::::NotSupportTokenType)?; + let vs_bond = T::CurrencyIdConversion::convert_to_vsbond( + T::RelayChainToken::get(), + index, + fund.first_slot, + fund.last_slot, + ) + .map_err(|_| Error::::NotSupportTokenType)?; + + T::MultiCurrency::unreserve(vs_token, &who, contributed); + T::MultiCurrency::unreserve(vs_bond, &who, contributed); + + Self::deposit_event(Event::::Unlocked(who, index, contributed)); + + Ok(()) + } + + #[pallet::call_index(11)] + #[pallet::weight(T::WeightInfo::unlock())] + pub fn unlock_by_vsbond( + origin: OriginFor, + who: AccountIdOf, + vsbond: CurrencyId, + ) -> DispatchResult { + ensure_signed(origin)?; + + let index = match vsbond { + CurrencyId::VSBond(token_symbol, paraid, first_slot, last_slot) => { + if !T::CurrencyIdRegister::check_vsbond_registered( + token_symbol, + paraid, + first_slot, + last_slot, + ) { + return Err(Error::::NotSupportTokenType.into()); + } + paraid + }, + CurrencyId::VSBond2(token_id, paraid, first_slot, last_slot) => { + if !T::CurrencyIdRegister::check_vsbond2_registered( + token_id, paraid, first_slot, last_slot, + ) { + return Err(Error::::NotSupportTokenType.into()); + } + paraid + }, + _ => return Err(Error::::NotSupportTokenType.into()), + }; + + let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + + let (contributed, _) = Self::contribution(fund.trie_index, &who); + + let vs_token = T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) + .map_err(|_| Error::::NotSupportTokenType)?; + let vs_bond = T::CurrencyIdConversion::convert_to_vsbond( + T::RelayChainToken::get(), + index, + fund.first_slot, + fund.last_slot, + ) + .map_err(|_| Error::::NotSupportTokenType)?; + + T::MultiCurrency::unreserve(vs_token, &who, contributed); + T::MultiCurrency::unreserve(vs_bond, &who, contributed); + + Self::deposit_event(Event::::Unlocked(who, index, contributed)); + Ok(()) + } + + #[pallet::call_index(12)] + #[pallet::weight(T::WeightInfo::unlock())] + pub fn unlock_vstoken(origin: OriginFor, who: AccountIdOf) -> DispatchResult { + ensure_signed(origin)?; + + match T::RelayChainToken::get() { + CurrencyId::Token(token_symbol) => { + let vsbond_list = vec![ + VSBond(token_symbol, 2106, 19, 26), + VSBond(token_symbol, 2011, 19, 26), + VSBond(token_symbol, 2102, 18, 25), + VSBond(token_symbol, 2102, 19, 26), + VSBond(token_symbol, 2101, 18, 25), + VSBond(token_symbol, 2100, 18, 25), + VSBond(token_symbol, 2100, 17, 24), + VSBond(token_symbol, 2095, 17, 24), + VSBond(token_symbol, 2096, 17, 24), + VSBond(token_symbol, 2087, 17, 24), + VSBond(token_symbol, 2085, 15, 22), + VSBond(token_symbol, 2092, 15, 22), + VSBond(token_symbol, 2088, 15, 22), + VSBond(token_symbol, 2090, 15, 22), + ]; + + let vs_token = + T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) + .map_err(|_| Error::::NotSupportTokenType)?; + let reserved_vstoken = T::MultiCurrency::reserved_balance(vs_token, &who); + T::MultiCurrency::unreserve(vs_token, &who, reserved_vstoken); + vsbond_list.into_iter().for_each(|vs_bond| { + let reserved_vsbond = T::MultiCurrency::reserved_balance(vs_bond, &who); + T::MultiCurrency::unreserve(vs_bond, &who, reserved_vsbond); + }); + }, + _ => return Err(DispatchError::BadOrigin.into()), + } + + Self::deposit_event(Event::::VstokenUnlocked(who)); + Ok(()) + } + + /// Unlock the reserved vsToken/vsBond after fund success + #[pallet::call_index(13)] + #[pallet::weight(T::WeightInfo::batch_unlock())] + pub fn batch_unlock( + origin: OriginFor, + #[pallet::compact] index: ParaId, + ) -> DispatchResult { + ensure_signed(origin)?; + + let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + + let mut unlock_count = 0u32; + let contributions = Self::contribution_iterator(fund.trie_index); + // Assume everyone will be refunded. + let mut all_unlocked = true; + + for (who, (contributed, status)) in contributions { + if unlock_count >= T::RemoveKeysLimit::get() { + // Not everyone was able to be refunded this time around. + all_unlocked = false; + break; + } + if status != ContributionStatus::Unlocked { + let vs_token = + T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) + .map_err(|_| Error::::NotSupportTokenType)?; + let vs_bond = T::CurrencyIdConversion::convert_to_vsbond( + T::RelayChainToken::get(), + index, + fund.first_slot, + fund.last_slot, + ) + .map_err(|_| Error::::NotSupportTokenType)?; + T::MultiCurrency::unreserve(vs_token, &who, contributed); + T::MultiCurrency::unreserve(vs_bond, &who, contributed); + + unlock_count += 1; + } + } + + if all_unlocked { + Self::deposit_event(Event::::AllUnlocked(index)); + } + + Ok(()) + } + + /// Withdraw full balance of the parachain. + /// - `index`: The parachain to whose crowdloan the contribution was made. + #[pallet::call_index(14)] + #[pallet::weight(T::WeightInfo::withdraw())] + pub fn withdraw(origin: OriginFor, #[pallet::compact] index: ParaId) -> DispatchResult { + T::EnsureConfirmAsGovernance::ensure_origin(origin.clone())?; + + let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + let can = fund.status == FundStatus::Failed || fund.status == FundStatus::Retired; + ensure!(can, Error::::InvalidFundStatus); + + let amount_withdrew = fund.raised; + let total = RedeemPool::::get() + .checked_add(&amount_withdrew) + .ok_or(Error::::Overflow)?; + RedeemPool::::set(total); + + if fund.status == FundStatus::Retired { + let fund_new = FundInfo { status: FundStatus::RedeemWithdrew, ..fund }; + Funds::::insert(index, Some(fund_new)); + } else if fund.status == FundStatus::Failed { + let fund_new = FundInfo { status: FundStatus::RefundWithdrew, ..fund }; + Funds::::insert(index, Some(fund_new)); + } + + Self::deposit_event(Event::Withdrew(index, amount_withdrew)); + + Ok(()) + } + + #[pallet::call_index(15)] + #[pallet::weight(T::WeightInfo::refund())] + pub fn refund( + origin: OriginFor, + #[pallet::compact] index: ParaId, + #[pallet::compact] first_slot: LeasePeriod, + #[pallet::compact] last_slot: LeasePeriod, + #[pallet::compact] value: BalanceOf, + ) -> DispatchResult { + let who = ensure_signed(origin.clone())?; + + let mut fund = Self::find_fund(index, first_slot, last_slot) + .map_err(|_| Error::::InvalidFundNotExist)?; + ensure!( + fund.status == FundStatus::FailedToContinue || + fund.status == FundStatus::RefundWithdrew, + Error::::InvalidRefund + ); + ensure!( + fund.first_slot == first_slot && fund.last_slot == last_slot, + Error::::InvalidRefund + ); + ensure!(fund.raised >= value, Error::::NotEnoughBalanceInFund); + ensure!(RedeemPool::::get() >= value, Error::::NotEnoughBalanceInRefundPool); + + let vs_token = T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) + .map_err(|_| Error::::NotSupportTokenType)?; + let vs_bond = T::CurrencyIdConversion::convert_to_vsbond( + T::RelayChainToken::get(), + index, + fund.first_slot, + fund.last_slot, + ) + .map_err(|_| Error::::NotSupportTokenType)?; + T::MultiCurrency::ensure_can_withdraw(vs_token, &who, value) + .map_err(|_e| Error::::NotEnoughFreeAssetsToRedeem)?; + T::MultiCurrency::ensure_can_withdraw(vs_bond, &who, value) + .map_err(|_e| Error::::NotEnoughFreeAssetsToRedeem)?; + + T::MultiCurrency::withdraw(vs_token, &who, value)?; + T::MultiCurrency::withdraw(vs_bond, &who, value)?; + + RedeemPool::::set(RedeemPool::::get().saturating_sub(value)); + let mut fund_new = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + fund_new.raised = fund_new.raised.saturating_sub(value); + Funds::::insert(index, Some(fund_new)); + if fund.status == FundStatus::FailedToContinue { + fund.raised = fund.raised.saturating_sub(value); + FailedFundsToRefund::::insert( + (index, first_slot, last_slot), + Some(fund.clone()), + ); + } + + T::MultiCurrency::transfer( + T::RelayChainToken::get(), + &Self::fund_account_id(index), + &who, + value, + )?; + + Self::deposit_event(Event::Refunded( + who, + index, + fund.first_slot, + fund.last_slot, + value, + )); + + Ok(()) + } + + #[pallet::call_index(16)] + #[pallet::weight(T::WeightInfo::redeem())] + pub fn redeem( + origin: OriginFor, + #[pallet::compact] index: ParaId, + #[pallet::compact] value: BalanceOf, + ) -> DispatchResult { + let who = ensure_signed(origin.clone())?; + + let mut fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + ensure!(fund.status == FundStatus::RedeemWithdrew, Error::::InvalidFundStatus); + ensure!(fund.raised >= value, Error::::NotEnoughBalanceInRedeemPool); + + let vs_token = T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) + .map_err(|_| Error::::NotSupportTokenType)?; + let vs_bond = T::CurrencyIdConversion::convert_to_vsbond( + T::RelayChainToken::get(), + index, + fund.first_slot, + fund.last_slot, + ) + .map_err(|_| Error::::NotSupportTokenType)?; + + ensure!(RedeemPool::::get() >= value, Error::::NotEnoughBalanceInRedeemPool); + let cur_block = >::block_number(); + let expired = Self::is_expired(cur_block, fund.last_slot)?; + ensure!(!expired, Error::::VSBondExpired); + T::MultiCurrency::ensure_can_withdraw(vs_token, &who, value) + .map_err(|_e| Error::::NotEnoughFreeAssetsToRedeem)?; + T::MultiCurrency::ensure_can_withdraw(vs_bond, &who, value) + .map_err(|_e| Error::::NotEnoughFreeAssetsToRedeem)?; + + T::MultiCurrency::withdraw(vs_token, &who, value)?; + T::MultiCurrency::withdraw(vs_bond, &who, value)?; + RedeemPool::::set(RedeemPool::::get().saturating_sub(value)); + + fund.raised = fund.raised.saturating_sub(value); + Funds::::insert(index, Some(fund.clone())); + + T::MultiCurrency::transfer( + T::RelayChainToken::get(), + &Self::fund_account_id(index), + &who, + value, + )?; + Self::deposit_event(Event::Redeemed( + who, + index, + fund.first_slot, + fund.last_slot, + value, + )); + + Ok(()) + } + + /// Remove a fund after the retirement period has ended and all funds have been returned. + #[pallet::call_index(17)] + #[pallet::weight(T::WeightInfo::dissolve_refunded())] + pub fn dissolve_refunded( + origin: OriginFor, + #[pallet::compact] index: ParaId, + #[pallet::compact] first_slot: LeasePeriod, + #[pallet::compact] last_slot: LeasePeriod, + ) -> DispatchResult { + T::EnsureConfirmAsGovernance::ensure_origin(origin)?; + + let fund = FailedFundsToRefund::::get((index, first_slot, last_slot)) + .ok_or(Error::::InvalidRefund)?; + + ensure!(fund.status == FundStatus::FailedToContinue, Error::::InvalidFundStatus); + + FailedFundsToRefund::::remove((index, first_slot, last_slot)); + + Self::deposit_event(Event::::RefundedDissolved(index, first_slot, last_slot)); + + Ok(()) + } + + /// Remove a fund after the retirement period has ended and all funds have been returned. + #[pallet::call_index(18)] + #[pallet::weight(T::WeightInfo::dissolve())] + pub fn dissolve(origin: OriginFor, #[pallet::compact] index: ParaId) -> DispatchResult { + T::EnsureConfirmAsGovernance::ensure_origin(origin)?; + + let mut fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + ensure!(fund.status == FundStatus::End, Error::::InvalidFundStatus); + + let mut refund_count = 0u32; + // Try killing the crowdloan child trie and Assume everyone will be refunded. + let contributions = Self::contribution_iterator(fund.trie_index); + let mut all_refunded = true; + #[allow(clippy::explicit_counter_loop)] + for (who, (balance, _)) in contributions { + if refund_count >= T::RemoveKeysLimit::get() { + // Not everyone was able to be refunded this time around. + all_refunded = false; + break; + } + Self::kill_contribution(fund.trie_index, &who); + fund.raised = fund.raised.saturating_sub(balance); + refund_count += 1; + } + + if all_refunded { + let from = &Self::fund_account_id(index); + let relay_currency_id = T::RelayChainToken::get(); + let fund_account_balance = T::MultiCurrency::free_balance(relay_currency_id, from); + T::MultiCurrency::transfer( + relay_currency_id, + from, + &T::TreasuryAccount::get(), + Percent::from_percent(25) * fund_account_balance, + )?; + T::MultiCurrency::transfer( + relay_currency_id, + from, + &T::BuybackPalletId::get().into_account_truncating(), + Percent::from_percent(75) * fund_account_balance, + )?; + Funds::::remove(index); + Self::deposit_event(Event::::Dissolved(index)); + } + + Ok(()) + } + + #[pallet::call_index(19)] + #[pallet::weight(T::WeightInfo::buyback())] + pub fn buyback( + origin: OriginFor, + #[pallet::compact] value: BalanceOf, + ) -> DispatchResult { + let _who = ensure_signed(origin.clone())?; + + let relay_currency_id = T::RelayChainToken::get(); + let relay_vstoken_id = T::CurrencyIdConversion::convert_to_vstoken(relay_currency_id) + .map_err(|_| Error::::NotSupportTokenType)?; + let relay_asset_id: AssetId = + AssetId::try_convert_from(relay_currency_id, T::ParachainId::get().into()) + .map_err(|_| DispatchError::Other("Conversion Error."))?; + let relay_vstoken_asset_id: AssetId = + AssetId::try_convert_from(relay_vstoken_id, T::ParachainId::get().into()) + .map_err(|_| DispatchError::Other("Conversion Error."))?; + let path = vec![relay_asset_id, relay_vstoken_asset_id]; + + T::DexOperator::inner_swap_exact_assets_for_assets( + &T::BuybackPalletId::get().into_account_truncating(), + value.saturated_into(), + Percent::from_percent(50).saturating_reciprocal_mul(value).saturated_into(), + &path, + &T::TreasuryAccount::get(), + )?; + + Self::deposit_event(Event::::Buyback(value)); + + Ok(()) + } + + #[pallet::call_index(20)] + #[pallet::weight(T::WeightInfo::confirm_contribute())] + pub fn confirm_contribution( + origin: OriginFor, + query_id: QueryId, + response: Response, + ) -> DispatchResult { + let responder = ensure_response(::RuntimeOrigin::from(origin))?; + ensure!(responder == xcm::v4::Location::parent(), Error::::ResponderNotRelayChain); + + let (index, contributer, _amount) = QueryIdContributionInfo::::get(query_id) + .ok_or(Error::::NotFindContributionValue)?; + + let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + let can_confirm = fund.status == FundStatus::Ongoing || + fund.status == FundStatus::Failed || + fund.status == FundStatus::Success; + ensure!(can_confirm, Error::::InvalidFundStatus); + + let (contributed, status) = Self::contribution(fund.trie_index, &contributer); + ensure!(status.is_contributing(), Error::::InvalidContributionStatus); + let contributing = status.contributing(); + + let vs_token = T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) + .map_err(|_| Error::::NotSupportTokenType)?; + let vs_bond = T::CurrencyIdConversion::convert_to_vsbond( + T::RelayChainToken::get(), + index, + fund.first_slot, + fund.last_slot, + ) + .map_err(|_| Error::::NotSupportTokenType)?; + + if let Response::DispatchResult(MaybeErrorCode::Success) = response { + // Issue reserved vsToken/vsBond to contributor + T::MultiCurrency::deposit(vs_token, &contributer, contributing)?; + T::MultiCurrency::deposit(vs_bond, &contributer, contributing)?; + + // Update the raised of fund + let fund_new = + FundInfo { raised: fund.raised.saturating_add(contributing), ..fund }; + Funds::::insert(index, Some(fund_new)); + + T::MultiCurrency::unreserve(T::RelayChainToken::get(), &contributer, contributing); + T::MultiCurrency::transfer( + T::RelayChainToken::get(), + &contributer, + &Self::fund_account_id(index), + contributing, + )?; + + // Update the contribution of contributer + let contributed_new = contributed.saturating_add(contributing); + Self::put_contribution( + fund.trie_index, + &contributer, + contributed_new, + ContributionStatus::Idle, + ); + Self::deposit_event(Event::Contributed(contributer, index, contributing)); + } else { + // Update the contribution of contributer + Self::put_contribution( + fund.trie_index, + &contributer, + contributed, + ContributionStatus::Idle, + ); + T::MultiCurrency::unreserve(T::RelayChainToken::get(), &contributer, contributing); + Self::deposit_event(Event::ContributeFailed(contributer, index, contributing)); + } + QueryIdContributionInfo::::remove(query_id); + Ok(()) + } + + #[pallet::call_index(21)] + #[pallet::weight(T::WeightInfo::buyback_vstoken_by_stable_pool())] + pub fn buyback_vstoken_by_stable_pool( + origin: OriginFor, + pool_id: StableAssetPoolId, + currency_id_in: CurrencyId, + value: BalanceOf, + ) -> DispatchResult { + let _who = ensure_signed(origin)?; + + let relay_currency_id = T::RelayChainToken::get(); + let relay_vtoken_id = T::CurrencyIdConversion::convert_to_vtoken(relay_currency_id) + .map_err(|_| Error::::NotSupportTokenType)?; + let relay_vstoken_id = T::CurrencyIdConversion::convert_to_vstoken(relay_currency_id) + .map_err(|_| Error::::NotSupportTokenType)?; + + match currency_id_in { + cid if cid == relay_currency_id => { + T::StablePool::swap( + &T::BuybackPalletId::get().into_account_truncating(), + pool_id, + T::StablePool::get_pool_token_index(pool_id, relay_currency_id) + .ok_or(Error::::ArgumentsError)?, + T::StablePool::get_pool_token_index(pool_id, relay_vstoken_id) + .ok_or(Error::::ArgumentsError)?, + value.saturated_into(), + Percent::from_percent(50).saturating_reciprocal_mul(value).saturated_into(), + )?; + }, + cid if cid == relay_vtoken_id => { + let token_value = T::VtokenMinting::vtoken_to_token( + relay_currency_id, + relay_vtoken_id, + value, + )?; + T::StablePool::swap( + &T::BuybackPalletId::get().into_account_truncating(), + pool_id, + T::StablePool::get_pool_token_index(pool_id, relay_vtoken_id) + .ok_or(Error::::ArgumentsError)?, + T::StablePool::get_pool_token_index(pool_id, relay_vstoken_id) + .ok_or(Error::::ArgumentsError)?, + value.saturated_into(), + Percent::from_percent(50) + .saturating_reciprocal_mul(token_value) + .saturated_into(), + )?; + }, + _ => return Err(Error::::ArgumentsError.into()), + } + + Self::deposit_event(Event::::BuybackByStablePool { pool_id, currency_id_in, value }); + Ok(()) + } + + #[pallet::call_index(22)] + #[pallet::weight(T::WeightInfo::reserve())] + pub fn reserve( + origin: OriginFor, + index: ParaId, + value: BalanceOf, + if_mint: bool, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + + ensure!( + fund.status == FundStatus::Ongoing || fund.status == FundStatus::Success, + Error::::InvalidFundStatus + ); + + let vs_token = T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) + .map_err(|_| Error::::NotSupportTokenType)?; + let vs_bond = T::CurrencyIdConversion::convert_to_vsbond( + T::RelayChainToken::get(), + index, + fund.first_slot, + fund.last_slot, + ) + .map_err(|_| Error::::NotSupportTokenType)?; + + T::MultiCurrency::ensure_can_withdraw(vs_token, &who, value)?; + T::MultiCurrency::ensure_can_withdraw(vs_bond, &who, value)?; + let mut info = ReserveInfos::::get(index, &who); + info.value = info.value.checked_add(&value).ok_or(Error::::Overflow)?; + info.if_mint = if_mint; + T::MultiCurrency::extend_lock(T::LockId::get(), vs_token, &who, info.value)?; + T::MultiCurrency::extend_lock(T::LockId::get(), vs_bond, &who, info.value)?; + + ReserveInfos::::insert(index, &who, info); + + Self::deposit_event(Event::::Reserved { who, para_id: index, value, if_mint }); + Ok(()) + } + + #[pallet::call_index(23)] + #[pallet::weight(T::WeightInfo::batch_handle_reserve())] + pub fn batch_handle_reserve(origin: OriginFor, index: ParaId) -> DispatchResult { + let _who = ensure_signed(origin.clone())?; + + let mut fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + let vs_token = T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) + .map_err(|_| Error::::NotSupportTokenType)?; + let vs_bond = T::CurrencyIdConversion::convert_to_vsbond( + T::RelayChainToken::get(), + index, + fund.first_slot, + fund.last_slot, + ) + .map_err(|_| Error::::NotSupportTokenType)?; + + match fund.status { + FundStatus::RedeemWithdrew => { + ReserveInfos::::iter_prefix(index) + .take(T::BatchLimit::get() as usize) + .try_for_each(|(contributer, info)| -> DispatchResult { + T::MultiCurrency::remove_lock( + T::LockId::get(), + vs_token, + &contributer, + )?; + T::MultiCurrency::remove_lock(T::LockId::get(), vs_bond, &contributer)?; + Self::redeem_for_reserve( + contributer.clone(), + index, + info.value, + &mut fund, + vs_token, + vs_bond, + )?; + ReserveInfos::::remove(index, &contributer); + if info.if_mint { + T::VtokenMinting::mint( + contributer, + T::RelayChainToken::get(), + info.value, + BoundedVec::default(), + None, + ) + .map_err(|_| Error::::NotSupportTokenType)?; + } + Ok(()) + })?; + }, + FundStatus::RefundWithdrew => { + ReserveInfos::::iter_prefix(index) + .take(T::BatchLimit::get() as usize) + .try_for_each(|(contributer, info)| -> DispatchResult { + T::MultiCurrency::remove_lock( + T::LockId::get(), + vs_token, + &contributer, + )?; + T::MultiCurrency::remove_lock(T::LockId::get(), vs_bond, &contributer)?; + Self::refund_for_reserve( + contributer.clone(), + index, + fund.first_slot, + fund.last_slot, + info.value, + vs_token, + vs_bond, + )?; + ReserveInfos::::remove(index, &contributer); + if info.if_mint { + T::VtokenMinting::mint( + contributer, + T::RelayChainToken::get(), + info.value, + BoundedVec::default(), + None, + ) + .map_err(|_| Error::::NotSupportTokenType)?; + } + Ok(()) + })?; + }, + _ => return Err(Error::::InvalidFundStatus.into()), + } + + if ReserveInfos::::iter_prefix(index).count() != 0 { + Self::deposit_event(Event::::ReservationHandled { para_id: index }); + } else { + Self::deposit_event(Event::::ReservationFullyHandled { para_id: index }); + } + Ok(()) + } + + #[pallet::call_index(24)] + #[pallet::weight(T::WeightInfo::cancel_reservation())] + pub fn cancel_reservation(origin: OriginFor, index: ParaId) -> DispatchResult { + let who = ensure_signed(origin)?; + + let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + + let vs_token = T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) + .map_err(|_| Error::::NotSupportTokenType)?; + let vs_bond = T::CurrencyIdConversion::convert_to_vsbond( + T::RelayChainToken::get(), + index, + fund.first_slot, + fund.last_slot, + ) + .map_err(|_| Error::::NotSupportTokenType)?; + T::MultiCurrency::remove_lock(T::LockId::get(), vs_token, &who)?; + T::MultiCurrency::remove_lock(T::LockId::get(), vs_bond, &who)?; + ReserveInfos::::remove(index, &who); + + Self::deposit_event(Event::::ReservationCancelled { who, para_id: index }); + Ok(()) + } + } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_initialize(n: BlockNumberFor) -> Weight { + // Release x% KSM/DOT from redeem-pool to bancor-pool per cycle + if n != Zero::zero() && (n % T::ReleaseCycle::get()) == Zero::zero() { + if let Ok(rp_balance) = TryInto::::try_into(RedeemPool::::get()) { + // Calculate the release amount + let release_amount = T::ReleaseRatio::get() * rp_balance; + + // Must be ok + if let Ok(release_amount) = TryInto::>::try_into(release_amount) { + // Increase the balance of bancor-pool by release-amount + if let Ok(()) = + T::BancorPool::add_token(T::RelayChainToken::get(), release_amount) + { + RedeemPool::::set( + RedeemPool::::get().saturating_sub(release_amount), + ); + } + } else { + log::warn!("Overflow: The balance of redeem-pool exceeds u128."); + } + } + } + T::DbWeight::get().reads(1) + } + } + + impl Pallet { + /// set multisig account + pub fn set_multisig_account(account: AccountIdOf) { + MultisigConfirmAccount::::put(account); + } + /// Check if the vsBond is `past` the redeemable date + pub(crate) fn is_expired( + block: BlockNumberFor, + last_slot: LeasePeriod, + ) -> Result> { + let block_begin_redeem = Self::block_end_of_lease_period_index(last_slot); + let block_end_redeem = block_begin_redeem.saturating_add(T::VSBondValidPeriod::get()); + + Ok(block >= block_end_redeem) + } + + /// Check if the vsBond is `in` the redeemable date + #[allow(dead_code)] + pub(crate) fn can_redeem( + block: BlockNumberFor, + last_slot: LeasePeriod, + ) -> Result> { + let block_begin_redeem = Self::block_end_of_lease_period_index(last_slot); + let block_end_redeem = block_begin_redeem.saturating_add(T::VSBondValidPeriod::get()); + + Ok(block >= block_begin_redeem && block < block_end_redeem) + } + + pub(crate) fn block_end_of_lease_period_index(slot: LeasePeriod) -> BlockNumberFor { + (BlockNumberFor::::from(slot) + One::one()).saturating_mul(T::LeasePeriod::get()) + } + + pub fn find_fund( + index: ParaId, + first_slot: LeasePeriod, + last_slot: LeasePeriod, + ) -> Result, LeasePeriod>, Error> { + return match FailedFundsToRefund::::get((index, first_slot, last_slot)) { + Some(fund) => Ok(fund), + _ => match Funds::::get(index) { + Some(fund) => Ok(fund), + _ => Err(Error::::InvalidFundNotExist), + }, + }; + } + + pub fn fund_account_id(index: ParaId) -> T::AccountId { + T::PalletId::get().into_sub_account_truncating(index) + } + + pub(crate) fn id_from_index(index: TrieIndex) -> child::ChildInfo { + let mut buf = Vec::new(); + buf.extend_from_slice(&(T::PalletId::get().0)); + buf.extend_from_slice(&index.encode()[..]); + child::ChildInfo::new_default(T::Hashing::hash(&buf[..]).as_ref()) + } + + pub fn contribution( + index: TrieIndex, + who: &AccountIdOf, + ) -> (BalanceOf, ContributionStatus>) { + who.using_encoded(|b| { + child::get_or_default::<(BalanceOf, ContributionStatus>)>( + &Self::id_from_index(index), + b, + ) + }) + } + + pub fn contribution_by_fund( + index: ParaId, + who: &AccountIdOf, + ) -> Result<(BalanceOf, ContributionStatus>), Error> { + let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + let (contributed, status) = Self::contribution(fund.trie_index, who); + Ok((contributed, status)) + } + + pub(crate) fn contribution_iterator( + index: TrieIndex, + ) -> ChildTriePrefixIterator<( + AccountIdOf, + (BalanceOf, ContributionStatus>), + )> { + ChildTriePrefixIterator::<_>::with_prefix_over_key::( + &Self::id_from_index(index), + &[], + ) + } + + pub(crate) fn next_trie_index() -> Result> { + CurrentTrieIndex::::try_mutate(|ti| { + *ti = ti.checked_add(1).ok_or(Error::::Overflow)?; + Ok(*ti - 1) + }) + } + + fn put_contribution( + index: TrieIndex, + who: &AccountIdOf, + contributed: BalanceOf, + status: ContributionStatus>, + ) { + who.using_encoded(|b| { + child::put(&Self::id_from_index(index), b, &(contributed, status)) + }); + } + + fn kill_contribution(index: TrieIndex, who: &AccountIdOf) { + who.using_encoded(|b| child::kill(&Self::id_from_index(index), b)); + } + + #[allow(dead_code)] + pub(crate) fn set_balance(who: &AccountIdOf, value: BalanceOf) -> DispatchResult { + T::MultiCurrency::deposit(T::RelayChainToken::get(), who, value) + } + + pub fn redeem_for_reserve( + who: AccountIdOf, + index: ParaId, + value: BalanceOf, + fund: &mut FundInfo, LeasePeriod>, + vs_token: CurrencyId, + vs_bond: CurrencyId, + ) -> DispatchResult { + ensure!(fund.raised >= value, Error::::NotEnoughBalanceInRedeemPool); + + ensure!(RedeemPool::::get() >= value, Error::::NotEnoughBalanceInRedeemPool); + let cur_block = >::block_number(); + let expired = Self::is_expired(cur_block, fund.last_slot)?; + ensure!(!expired, Error::::VSBondExpired); + T::MultiCurrency::ensure_can_withdraw(vs_token, &who, value) + .map_err(|_e| Error::::NotEnoughFreeAssetsToRedeem)?; + T::MultiCurrency::ensure_can_withdraw(vs_bond, &who, value) + .map_err(|_e| Error::::NotEnoughFreeAssetsToRedeem)?; + + T::MultiCurrency::withdraw(vs_token, &who, value)?; + T::MultiCurrency::withdraw(vs_bond, &who, value)?; + RedeemPool::::set(RedeemPool::::get().saturating_sub(value)); + + fund.raised = fund.raised.saturating_sub(value); + Funds::::insert(index, Some(fund.clone())); + + T::MultiCurrency::transfer( + T::RelayChainToken::get(), + &Self::fund_account_id(index), + &who, + value, + )?; + Self::deposit_event(Event::Redeemed( + who, + index, + fund.first_slot, + fund.last_slot, + value, + )); + + Ok(()) + } + + pub fn refund_for_reserve( + who: AccountIdOf, + index: ParaId, + first_slot: LeasePeriod, + last_slot: LeasePeriod, + value: BalanceOf, + vs_token: CurrencyId, + vs_bond: CurrencyId, + ) -> DispatchResult { + let mut fund = Self::find_fund(index, first_slot, last_slot) + .map_err(|_| Error::::InvalidFundNotExist)?; + ensure!( + fund.status == FundStatus::FailedToContinue || + fund.status == FundStatus::RefundWithdrew, + Error::::InvalidRefund + ); + ensure!( + fund.first_slot == first_slot && fund.last_slot == last_slot, + Error::::InvalidRefund + ); + ensure!(fund.raised >= value, Error::::NotEnoughBalanceInFund); + ensure!(RedeemPool::::get() >= value, Error::::NotEnoughBalanceInRefundPool); + + T::MultiCurrency::ensure_can_withdraw(vs_token, &who, value) + .map_err(|_e| Error::::NotEnoughFreeAssetsToRedeem)?; + T::MultiCurrency::ensure_can_withdraw(vs_bond, &who, value) + .map_err(|_e| Error::::NotEnoughFreeAssetsToRedeem)?; + + T::MultiCurrency::withdraw(vs_token, &who, value)?; + T::MultiCurrency::withdraw(vs_bond, &who, value)?; + + RedeemPool::::set(RedeemPool::::get().saturating_sub(value)); + let mut fund_new = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + fund_new.raised = fund_new.raised.saturating_sub(value); + Funds::::insert(index, Some(fund_new)); + if fund.status == FundStatus::FailedToContinue { + fund.raised = fund.raised.saturating_sub(value); + FailedFundsToRefund::::insert( + (index, first_slot, last_slot), + Some(fund.clone()), + ); + } + + T::MultiCurrency::transfer( + T::RelayChainToken::get(), + &Self::fund_account_id(index), + &who, + value, + )?; + + Self::deposit_event(Event::Refunded( + who, + index, + fund.first_slot, + fund.last_slot, + value, + )); + + Ok(()) + } + } +} + +impl + bifrost_xcm_interface::SalpHelper, ::RuntimeCall, BalanceOf> + for Pallet +{ + fn confirm_contribute_call() -> ::RuntimeCall { + let call = Call::::confirm_contribution { query_id: 0, response: Default::default() }; + ::RuntimeCall::from(call) + } + + fn bind_query_id_and_contribution( + query_id: QueryId, + index: ChainId, + contributer: AccountIdOf, + amount: BalanceOf, + ) { + QueryIdContributionInfo::::insert(query_id, (index, contributer, amount)); + } +} diff --git a/pallets/deprecated/salp/src/mock.rs b/pallets/deprecated/salp/src/mock.rs new file mode 100644 index 000000000..4d1bf1435 --- /dev/null +++ b/pallets/deprecated/salp/src/mock.rs @@ -0,0 +1,641 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . + +// Ensure we're `no_std` when compiling for Wasm. + +#![cfg(test)] + +use crate::*; +use bifrost_asset_registry::AssetIdMaps; +use bifrost_primitives::{ + Amount, Balance, CurrencyId, CurrencyId::*, MessageId, MockXcmExecutor, ParaId, SlpOperator, + SlpxOperator, TokenSymbol, TokenSymbol::*, VKSM, +}; +use bifrost_xcm_interface::traits::XcmHelper; +use cumulus_primitives_core::ParaId as Pid; +use frame_support::{ + construct_runtime, derive_impl, ord_parameter_types, parameter_types, + sp_runtime::{DispatchError, DispatchResult, SaturatedConversion}, + traits::{ConstU128, ConstU64, EnsureOrigin, Everything, Get, Nothing}, + weights::Weight, + PalletId, +}; +use frame_system::{EnsureRoot, EnsureSignedBy, RawOrigin}; +use orml_traits::{location::RelativeReserveProvider, parameter_type_with_key, MultiCurrency}; +use sp_arithmetic::Percent; +use sp_core::ConstU32; +pub use sp_runtime::Perbill; +use sp_runtime::{ + traits::{Convert, IdentityLookup, UniqueSaturatedInto}, + BuildStorage, +}; +use sp_std::marker::PhantomData; +use xcm::prelude::*; +use xcm_builder::{FixedWeightBounds, FrameTransactionalProcessor}; +use xcm_executor::XcmExecutor; +use zenlink_protocol::{ + AssetBalance, AssetId as ZenlinkAssetId, LocalAssetHandler, PairLpGenerate, ZenlinkMultiAssets, +}; + +use crate as salp; +use bifrost_primitives::MoonbeamChainId; + +pub(crate) type AccountId = <::Signer as sp_runtime::traits::IdentifyAccount>::AccountId; +pub(crate) type Block = frame_system::mocking::MockBlock; +pub(crate) type BlockNumber = u32; +pub(crate) type Signature = sp_runtime::MultiSignature; + +construct_runtime!( + pub enum Test { + System: frame_system, + Sudo: pallet_sudo, + Balances: pallet_balances, + Currencies: bifrost_currencies, + Tokens: orml_tokens, + XTokens: orml_xtokens, + Multisig: pallet_multisig, + Salp: salp, + ZenlinkProtocol: zenlink_protocol, + AssetRegistry: bifrost_asset_registry, + PolkadotXcm: pallet_xcm, + StableAsset: bifrost_stable_asset, + StablePool: bifrost_stable_pool, + VtokenMinting: bifrost_vtoken_minting, + XcmInterface: bifrost_xcm_interface, + } +); + +parameter_types! { + pub const NativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::ASG); + pub const RelayCurrencyId: CurrencyId = CurrencyId::Token(TokenSymbol::KSM); + pub const StableCurrencyId: CurrencyId = CurrencyId::Stable(TokenSymbol::KUSD); +} + +parameter_types! { + pub const BlockHashCount: BlockNumber = 250; +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Test { + type AccountData = pallet_balances::AccountData; + type AccountId = AccountId; + type Block = Block; + type Lookup = IdentityLookup; +} + +parameter_types! { + pub const ExistentialDeposit: u128 = 1; + pub const TransferFee: u128 = 0; + pub const CreationFee: u128 = 0; + pub const TransactionByteFee: u128 = 0; + pub const MaxLocks: u32 = 999_999; + pub const MaxReserves: u32 = 999_999; +} + +impl pallet_balances::Config for Test { + type AccountStore = System; + /// The type for recording an account's balance. + type Balance = Balance; + type DustRemoval = (); + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ExistentialDeposit; + type MaxLocks = MaxLocks; + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type WeightInfo = pallet_balances::weights::SubstrateWeight; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; + type FreezeIdentifier = (); + type MaxFreezes = ConstU32<0>; +} + +parameter_types! { + pub const DepositBase: Balance = 0; + pub const DepositFactor: Balance = 0; + pub const MaxSignatories: u16 = 100; +} + +impl pallet_multisig::Config for Test { + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type DepositBase = DepositBase; + type DepositFactor = DepositFactor; + type RuntimeEvent = RuntimeEvent; + type MaxSignatories = MaxSignatories; + type WeightInfo = pallet_multisig::weights::SubstrateWeight; +} + +impl pallet_sudo::Config for Test { + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); +} + +orml_traits::parameter_type_with_key! { + pub ExistentialDeposits: |_currency_id: CurrencyId| -> Balance { + 0 + }; +} + +impl orml_tokens::Config for Test { + type Amount = Amount; + type Balance = Balance; + type CurrencyId = CurrencyId; + type DustRemovalWhitelist = Nothing; + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposits = ExistentialDeposits; + type MaxLocks = MaxLocks; + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type WeightInfo = (); + type CurrencyHooks = (); +} + +pub type BifrostToken = + bifrost_currencies::BasicCurrencyAdapter; + +impl bifrost_currencies::Config for Test { + type GetNativeCurrencyId = NativeCurrencyId; + type MultiCurrency = Tokens; + type NativeCurrency = BifrostToken; + type WeightInfo = (); +} + +parameter_types! { + pub const ZenlinkPalletId: PalletId = PalletId(*b"/zenlink"); + pub const GetExchangeFee: (u32, u32) = (3, 1000); // 0.3% + pub const SelfParaId: u32 = 2001; +} + +impl zenlink_protocol::Config for Test { + type RuntimeEvent = RuntimeEvent; + type MultiAssetsHandler = MultiAssets; + type PalletId = ZenlinkPalletId; + type SelfParaId = SelfParaId; + type TargetChains = (); + type WeightInfo = (); + type AssetId = ZenlinkAssetId; + type LpGenerate = PairLpGenerate; +} + +ord_parameter_types! { + pub const CouncilAccount: AccountId = AccountId::from([1u8; 32]); +} +impl bifrost_asset_registry::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type RegisterOrigin = EnsureSignedBy; + type WeightInfo = (); +} + +type MultiAssets = ZenlinkMultiAssets>; + +// Below is the implementation of tokens manipulation functions other than native token. +pub struct LocalAssetAdaptor(PhantomData); + +impl LocalAssetHandler for LocalAssetAdaptor +where + Local: MultiCurrency, +{ + fn local_balance_of(asset_id: ZenlinkAssetId, who: &AccountId) -> AssetBalance { + let currency_id: CurrencyId = asset_id.try_into().unwrap(); + Local::free_balance(currency_id, &who).saturated_into() + } + + fn local_total_supply(asset_id: ZenlinkAssetId) -> AssetBalance { + let currency_id: CurrencyId = asset_id.try_into().unwrap(); + Local::total_issuance(currency_id).saturated_into() + } + + fn local_is_exists(asset_id: ZenlinkAssetId) -> bool { + let rs: Result = asset_id.try_into(); + match rs { + Ok(_) => true, + Err(_) => false, + } + } + + fn local_transfer( + asset_id: ZenlinkAssetId, + origin: &AccountId, + target: &AccountId, + amount: AssetBalance, + ) -> DispatchResult { + let currency_id: CurrencyId = asset_id.try_into().unwrap(); + Local::transfer(currency_id, &origin, &target, amount.unique_saturated_into())?; + + Ok(()) + } + + fn local_deposit( + asset_id: ZenlinkAssetId, + origin: &AccountId, + amount: AssetBalance, + ) -> Result { + let currency_id: CurrencyId = asset_id.try_into().unwrap(); + Local::deposit(currency_id, &origin, amount.unique_saturated_into())?; + return Ok(amount); + } + + fn local_withdraw( + asset_id: ZenlinkAssetId, + origin: &AccountId, + amount: AssetBalance, + ) -> Result { + let currency_id: CurrencyId = asset_id.try_into().unwrap(); + Local::withdraw(currency_id, &origin, amount.unique_saturated_into())?; + + Ok(amount) + } +} + +pub const TREASURY_ACCOUNT: AccountId = AccountId::new([9u8; 32]); + +parameter_types! { + pub const MinContribution: Balance = 10; + pub const BifrostCrowdloanId: PalletId = PalletId(*b"bf/salp#"); + pub const RemoveKeysLimit: u32 = 50; + pub const SlotLength: BlockNumber = 8u32 as BlockNumber; + pub const LeasePeriod: BlockNumber = 6 * WEEKS; + pub const VSBondValidPeriod: BlockNumber = 30 * DAYS; + pub const ReleaseCycle: BlockNumber = 1 * DAYS; + pub const ReleaseRatio: Percent = Percent::from_percent(50); + pub ConfirmMuitiSigAccount: AccountId = Multisig::multi_account_id(&vec![ + ALICE, + BRUCE, + CATHI + ],2); + pub const TreasuryAccount: AccountId = TREASURY_ACCOUNT; + pub const BuybackPalletId: PalletId = PalletId(*b"bf/salpc"); + pub const BatchLimit: u32 = 50; +} + +pub struct EnsureConfirmAsGovernance; +impl EnsureOrigin for EnsureConfirmAsGovernance { + type Success = AccountId; + + fn try_origin(o: RuntimeOrigin) -> Result { + Into::, RuntimeOrigin>>::into(o).and_then(|o| match o { + RawOrigin::Signed(who) => Ok(who), + RawOrigin::Root => Ok(ConfirmMuitiSigAccount::get()), + r => Err(RuntimeOrigin::from(r)), + }) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(RuntimeOrigin::from(RawOrigin::Signed(ConfirmMuitiSigAccount::get()))) + } +} + +// To control the result returned by `MockXcmExecutor` +pub(crate) static mut MOCK_XCM_RESULT: (bool, bool) = (true, true); + +// Mock XcmExecutor +pub struct MockSalpXcmExecutor; + +impl XcmHelper, crate::BalanceOf> for MockSalpXcmExecutor { + fn contribute( + _contributer: AccountId, + _index: ParaId, + _value: Balance, + ) -> Result { + let result = unsafe { MOCK_XCM_RESULT.0 }; + + match result { + true => Ok([0; 32]), + false => Err(DispatchError::BadOrigin), + } + } +} + +pub struct EnsurePoolAssetId; +impl bifrost_stable_asset::traits::ValidateAssetId for EnsurePoolAssetId { + fn validate(_: CurrencyId) -> bool { + true + } +} +parameter_types! { + pub const StableAssetPalletId: PalletId = PalletId(*b"nuts/sta"); +} + +impl bifrost_stable_asset::Config for Test { + type RuntimeEvent = RuntimeEvent; + type AssetId = CurrencyId; + type Balance = Balance; + type Assets = Tokens; + type PalletId = StableAssetPalletId; + type AtLeast64BitUnsigned = u128; + type FeePrecision = ConstU128<10_000_000_000>; + type APrecision = ConstU128<100>; + type PoolAssetLimit = ConstU32<5>; + type SwapExactOverAmount = ConstU128<100>; + type WeightInfo = (); + type ListingOrigin = EnsureSignedBy; + type EnsurePoolAssetId = EnsurePoolAssetId; +} + +impl bifrost_stable_pool::Config for Test { + type WeightInfo = (); + type ControlOrigin = EnsureConfirmAsGovernance; + type CurrencyId = CurrencyId; + type MultiCurrency = Tokens; + type StableAsset = StableAsset; + type VtokenMinting = VtokenMinting; + type CurrencyIdConversion = AssetIdMaps; + type CurrencyIdRegister = AssetIdMaps; +} + +parameter_types! { + pub const MaximumUnlockIdOfUser: u32 = 1_000; + pub const MaximumUnlockIdOfTimeUnit: u32 = 1_000; + pub BifrostEntranceAccount: PalletId = PalletId(*b"bf/vtkin"); + pub BifrostExitAccount: PalletId = PalletId(*b"bf/vtout"); + pub IncentivePoolAccount: PalletId = PalletId(*b"bf/inpoo"); +} + +pub struct SlpxInterface; +impl SlpxOperator for SlpxInterface { + fn get_moonbeam_transfer_to_fee() -> Balance { + Default::default() + } +} + +parameter_type_with_key! { + pub ParachainMinFee: |_location: Location| -> Option { + Some(u128::MAX) + }; +} + +parameter_types! { + pub SelfRelativeLocation: Location = Location::here(); + pub const MaxAssetsForTransfer: usize = 2; +} + +impl orml_xtokens::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type CurrencyId = CurrencyId; + type CurrencyIdConvert = (); + type AccountIdToLocation = (); + type UniversalLocation = UniversalLocation; + type SelfLocation = SelfRelativeLocation; + type XcmExecutor = XcmExecutor; + type Weigher = FixedWeightBounds; + type BaseXcmWeight = (); + type MaxAssetsForTransfer = MaxAssetsForTransfer; + type MinXcmFee = ParachainMinFee; + type LocationsFilter = Everything; + type ReserveProvider = RelativeReserveProvider; + type RateLimiter = (); + type RateLimiterId = (); +} + +pub struct Slp; +// Functions to be called by other pallets. +impl SlpOperator for Slp { + fn all_delegation_requests_occupied(_currency_id: CurrencyId) -> bool { + true + } +} + +impl bifrost_vtoken_minting::Config for Test { + type RuntimeEvent = RuntimeEvent; + type MultiCurrency = Tokens; + type ControlOrigin = EnsureConfirmAsGovernance; + type MaximumUnlockIdOfUser = MaximumUnlockIdOfUser; + type MaximumUnlockIdOfTimeUnit = MaximumUnlockIdOfTimeUnit; + type EntranceAccount = BifrostEntranceAccount; + type ExitAccount = BifrostExitAccount; + type FeeAccount = CouncilAccount; + type RedeemFeeAccount = CouncilAccount; + type BifrostSlp = Slp; + type RelayChainToken = RelayCurrencyId; + type CurrencyIdConversion = AssetIdMaps; + type CurrencyIdRegister = AssetIdMaps; + type WeightInfo = (); + type OnRedeemSuccess = (); + type XcmTransfer = XTokens; + type MoonbeamChainId = MoonbeamChainId; + type BifrostSlpx = SlpxInterface; + type ChannelCommission = (); + type MaxLockRecords = ConstU32<100>; + type IncentivePoolAccount = IncentivePoolAccount; + type BbBNC = (); + type AssetIdMaps = AssetIdMaps; +} + +parameter_types! { + pub const SalpLockId: LockIdentifier = *b"salplock"; +} + +impl salp::Config for Test { + type BancorPool = (); + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type RuntimeOrigin = RuntimeOrigin; + type LeasePeriod = LeasePeriod; + type MinContribution = MinContribution; + type MultiCurrency = Tokens; + type PalletId = BifrostCrowdloanId; + type RelayChainToken = RelayCurrencyId; + type ReleaseCycle = ReleaseCycle; + type ReleaseRatio = ReleaseRatio; + type RemoveKeysLimit = RemoveKeysLimit; + type SlotLength = SlotLength; + type VSBondValidPeriod = VSBondValidPeriod; + type EnsureConfirmAsGovernance = EnsureConfirmAsGovernance; + type WeightInfo = (); + type XcmInterface = MockSalpXcmExecutor; + type TreasuryAccount = TreasuryAccount; + type BuybackPalletId = BuybackPalletId; + type DexOperator = ZenlinkProtocol; + type CurrencyIdConversion = AssetIdMaps; + type CurrencyIdRegister = AssetIdMaps; + type ParachainId = ParaInfo; + type StablePool = StablePool; + type VtokenMinting = VtokenMinting; + type LockId = SalpLockId; + type BatchLimit = BatchLimit; +} + +parameter_types! { + // One XCM operation is 200_000_000 XcmWeight, cross-chain transfer ~= 2x of transfer = 3_000_000_000 + pub UnitWeightCost: Weight = Weight::from_parts(200_000_000, 0); + pub const MaxInstructions: u32 = 100; + pub UniversalLocation: InteriorLocation = Parachain(2001).into(); + pub const RelayNetwork: NetworkId = NetworkId::Kusama; +} + +pub struct XcmConfig; +impl xcm_executor::Config for XcmConfig { + type AssetClaims = PolkadotXcm; + type AssetTransactor = (); + type AssetTrap = PolkadotXcm; + type Barrier = (); + type RuntimeCall = RuntimeCall; + type IsReserve = (); + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type OriginConverter = (); + type ResponseHandler = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type Trader = (); + type Weigher = FixedWeightBounds; + type XcmSender = (); + type PalletInstancesInfo = AllPalletsWithSystem; + type MaxAssetsIntoHolding = ConstU32<64>; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; + type AssetLocker = (); + type AssetExchanger = (); + type Aliasers = Nothing; + type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); + type XcmRecorder = (); +} + +#[cfg(feature = "runtime-benchmarks")] +parameter_types! { + pub ReachableDest: Option = Some(Parent.into()); +} + +impl pallet_xcm::Config for Test { + type RuntimeEvent = RuntimeEvent; + type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; + type UniversalLocation = UniversalLocation; + type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; + type Weigher = FixedWeightBounds; + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmReserveTransferFilter = Everything; + type XcmRouter = (); + type XcmTeleportFilter = Nothing; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = ConstU32<2>; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + type AdminOrigin = EnsureRoot; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); +} + +pub struct BifrostAccountIdToMultiLocation; +impl Convert for BifrostAccountIdToMultiLocation { + fn convert(account: AccountId) -> Location { + (AccountId32 { network: None, id: account.into() }).into() + } +} + +impl bifrost_xcm_interface::Config for Test { + type RuntimeEvent = RuntimeEvent; + type UpdateOrigin = EnsureRoot; + type MultiCurrency = Currencies; + type RelayNetwork = RelayNetwork; + type RelaychainCurrencyId = RelayCurrencyId; + type ParachainSovereignAccount = TreasuryAccount; + type XcmExecutor = MockXcmExecutor; + type AccountIdToLocation = BifrostAccountIdToMultiLocation; + type SalpHelper = Salp; + type ParachainId = ParaInfo; + type CallBackTimeOut = ConstU64<10>; + type CurrencyIdConvert = AssetIdMaps; +} + +pub struct ParaInfo; +impl Get for ParaInfo { + fn get() -> Pid { + Pid::from(2001) + } +} + +pub(crate) fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + pub const DOLLARS: Balance = 1_000_000_000_000; + + let currency = vec![ + (Native(BNC), DOLLARS / 100, None), + (Stable(KUSD), DOLLARS / 10_000, None), + (Token(KSM), DOLLARS / 10_000, None), + (Token(ZLK), DOLLARS / 1000_000, None), + (Token(KAR), DOLLARS / 10_000, None), + (Token(RMRK), DOLLARS / 1000_000, None), + (Token(PHA), 4 * DOLLARS / 100, None), + (Token(MOVR), DOLLARS / 1000_000, None), + (Token(DOT), DOLLARS / 1000_000, None), + ]; + let vcurrency = vec![Native(BNC), Token(KSM), Token(MOVR)]; + let vsbond = vec![]; + bifrost_asset_registry::GenesisConfig:: { + currency, + vcurrency, + vsbond, + phantom: Default::default(), + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_sudo::GenesisConfig:: { key: Some(ALICE) } + .assimilate_storage(&mut t) + .unwrap(); + + orml_tokens::GenesisConfig:: { + balances: vec![ + (ALICE, NativeCurrencyId::get(), INIT_BALANCE), + (ALICE, RelayCurrencyId::get(), INIT_BALANCE), + (ALICE, CurrencyId::VSToken(TokenSymbol::KSM), INIT_BALANCE), + (ALICE, VKSM, INIT_BALANCE), + (BRUCE, NativeCurrencyId::get(), INIT_BALANCE), + (BRUCE, RelayCurrencyId::get(), INIT_BALANCE), + (CATHI, NativeCurrencyId::get(), INIT_BALANCE), + (CATHI, RelayCurrencyId::get(), INIT_BALANCE), + ], + } + .assimilate_storage(&mut t) + .unwrap(); + + crate::GenesisConfig:: { initial_multisig_account: Some(ALICE) } + .assimilate_storage(&mut t) + .unwrap(); + + t.into() +} + +// These time units are defined in number of blocks. +pub const MINUTES: BlockNumber = 60 / (12 as BlockNumber); +pub const HOURS: BlockNumber = MINUTES * 60; +pub const DAYS: BlockNumber = HOURS * 24; +pub const WEEKS: BlockNumber = DAYS * 7; + +pub(crate) const ALICE: AccountId = AccountId::new([0u8; 32]); +pub(crate) const BRUCE: AccountId = AccountId::new([1u8; 32]); +pub(crate) const CATHI: AccountId = AccountId::new([2u8; 32]); + +pub(crate) const INIT_BALANCE: Balance = 100_000; diff --git a/pallets/deprecated/salp/src/tests.rs b/pallets/deprecated/salp/src/tests.rs new file mode 100644 index 000000000..31d5870cf --- /dev/null +++ b/pallets/deprecated/salp/src/tests.rs @@ -0,0 +1,1604 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . + +// Ensure we're `no_std` when compiling for Wasm. + +use crate::{mock::*, Error, FundStatus, *}; +use bifrost_primitives::{ContributionStatus, CurrencyId, TokenSymbol, KSM, VKSM, VSKSM}; +use bifrost_xcm_interface::SalpHelper; +use frame_support::{assert_noop, assert_ok}; +use frame_system::pallet_prelude::BlockNumberFor; +use orml_traits::{MultiCurrency, MultiReservableCurrency}; +use sp_runtime::{traits::AccountIdConversion, DispatchError}; +use zenlink_protocol::AssetId; + +#[test] +fn create_fund_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Funds::::get(3_000).ok_or(())); + assert_eq!(CurrentTrieIndex::::get(), 1); + }); +} + +#[test] +fn create_fund_with_wrong_origin_should_fail() { + new_test_ext().execute_with(|| { + assert_noop!( + Salp::create(RuntimeOrigin::none(), 3_000, 1_000, 1, SlotLength::get()), + DispatchError::BadOrigin, + ); + }); +} + +#[test] +fn create_fund_existed_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + + assert_noop!( + Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get()), + Error::::FundAlreadyCreated, + ); + }); +} + +#[test] +fn create_fund_exceed_slot_limit_should_fail() { + new_test_ext().execute_with(|| { + assert_noop!( + Salp::create(Some(ALICE).into(), 3_000, 1_000, 0, SlotLength::get()), + Error::::LastSlotTooFarInFuture, + ); + }); +} + +#[test] +fn create_fund_first_slot_bigger_than_last_slot_should_fail() { + new_test_ext().execute_with(|| { + assert_noop!( + Salp::create(Some(ALICE).into(), 3_000, 1_000, SlotLength::get(), 0), + Error::::LastSlotBeforeFirstSlot, + ); + }); +} + +#[test] +fn set_fund_success_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + + // Check status + let fund = Funds::::get(3_000).unwrap(); + assert_eq!(fund.status, FundStatus::Success); + }); +} + +#[test] +fn set_fund_success_with_wrong_origin_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_noop!(Salp::fund_success(RuntimeOrigin::none(), 3_000), DispatchError::BadOrigin); + }) +} + +#[test] +fn set_fund_success_with_wrong_para_id_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_noop!(Salp::fund_success(Some(ALICE).into(), 4_000), Error::::InvalidParaId); + }); +} + +#[test] +fn set_fund_success_with_wrong_fund_status_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::fund_fail(Some(ALICE).into(), 3_000)); + assert_noop!( + Salp::fund_success(Some(ALICE).into(), 3_000), + Error::::InvalidFundStatus + ); + }); +} + +#[test] +fn set_fund_fail_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::fund_fail(Some(ALICE).into(), 3_000)); + + // Check status + let fund = Funds::::get(3_000).unwrap(); + assert_eq!(fund.status, FundStatus::Failed); + }); +} + +#[test] +fn set_fund_fail_with_wrong_origin_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_noop!(Salp::fund_fail(RuntimeOrigin::none(), 3_000), DispatchError::BadOrigin); + }); +} + +#[test] +fn set_fund_fail_with_wrong_para_id_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_noop!(Salp::fund_fail(Some(ALICE).into(), 4_000), Error::::InvalidParaId); + }); +} + +#[test] +fn set_fund_fail_with_wrong_fund_status_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_noop!(Salp::fund_fail(Some(ALICE).into(), 3_000), Error::::InvalidFundStatus); + }); +} + +#[test] +fn set_fund_retire_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); + + // Check status + let fund = Funds::::get(3_000).unwrap(); + assert_eq!(fund.status, FundStatus::Retired); + }); +} + +#[test] +fn set_fund_retire_with_wrong_origin_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_noop!(Salp::fund_retire(RuntimeOrigin::none(), 3_000), DispatchError::BadOrigin); + }); +} + +#[test] +fn set_fund_retire_with_wrong_para_id_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_noop!(Salp::fund_retire(Some(ALICE).into(), 4_000), Error::::InvalidParaId); + }); +} + +#[test] +fn set_fund_retire_with_with_wrong_fund_status_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_noop!( + Salp::fund_retire(Some(ALICE).into(), 3_000), + Error::::InvalidFundStatus + ); + }); +} + +#[test] +fn set_fund_end_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::fund_end(Some(ALICE).into(), 3_000)); + + // Check storage + let fund = Funds::::get(3_000).unwrap(); + assert_eq!(fund.status, FundStatus::End); + }); +} + +#[test] +fn set_fund_end_with_wrong_origin_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + + assert_noop!(Salp::fund_end(RuntimeOrigin::none(), 3_000), DispatchError::BadOrigin); + }); +} + +#[test] +fn set_fund_end_with_wrong_wrong_para_id_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + + assert_noop!(Salp::fund_end(Some(ALICE).into(), 4_000), Error::::InvalidParaId); + }); +} + +#[test] +fn set_fund_end_with_wrong_fund_status_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + + assert_noop!(Salp::fund_end(Some(ALICE).into(), 3_000), Error::::InvalidFundStatus); + }); +} + +#[test] +fn unlock_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::unlock(Some(BRUCE).into(), BRUCE, 3_000)); + + let vs_token = + ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()) + .unwrap(); + let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( + RelayCurrencyId::get(), + 3_000, + 1, + SlotLength::get(), + ) + .unwrap(); + + assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 100); + assert_eq!(Tokens::accounts(BRUCE, vs_token).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_token).reserved, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 100); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).reserved, 0); + }); +} + +#[test] +fn unlock_by_vsbond_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + + let vs_token = + ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()) + .unwrap(); + let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( + RelayCurrencyId::get(), + 3_000, + 1, + SlotLength::get(), + ) + .unwrap(); + + assert_ok!(Salp::unlock_by_vsbond(Some(BRUCE).into(), BRUCE, vs_bond)); + assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 100); + assert_eq!(Tokens::accounts(BRUCE, vs_token).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_token).reserved, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 100); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).reserved, 0); + }); +} + +#[test] +fn unlock_vstoken_should_work() { + new_test_ext().execute_with(|| { + let vs_token = + ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()) + .unwrap(); + assert_ok!(::MultiCurrency::reserve(vs_token, &ALICE, 1)); + + assert_eq!(Tokens::accounts(ALICE, vs_token).free, 99999); + assert_eq!(Tokens::accounts(ALICE, vs_token).frozen, 0); + assert_eq!(Tokens::accounts(ALICE, vs_token).reserved, 1); + assert_ok!(Salp::unlock_vstoken(Some(BRUCE).into(), ALICE)); + assert_eq!(Tokens::accounts(ALICE, vs_token).free, 100000); + assert_eq!(Tokens::accounts(ALICE, vs_token).frozen, 0); + assert_eq!(Tokens::accounts(ALICE, vs_token).reserved, 0); + + assert_ok!(Salp::create(Some(ALICE).into(), 2_100, 1_000, 18, 25)); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 2_100, 100)); + Salp::bind_query_id_and_contribution(0, 2_100, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 2_100)); + let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( + RelayCurrencyId::get(), + 2_100, + 18, + 25, + ) + .unwrap(); + assert_ok!(::MultiCurrency::reserve(vs_bond, &BRUCE, 1)); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 99); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).reserved, 1); + assert_ok!(Salp::unlock_vstoken(Some(BRUCE).into(), BRUCE)); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 100); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).reserved, 0); + }); +} + +#[test] +fn contribute_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true)); + + let fund = Funds::::get(3_000).unwrap(); + let (contributed, status) = Salp::contribution(fund.trie_index, &BRUCE); + assert_eq!(fund.raised, 100); + assert_eq!(contributed, 100); + assert_eq!(status, ContributionStatus::Idle); + + let vs_token = + ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()) + .unwrap(); + let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( + RelayCurrencyId::get(), + 3_000, + 1, + SlotLength::get(), + ) + .unwrap(); + assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 100); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 100); + }); +} + +#[test] +fn double_contribute_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + + // Check the contribution + let fund = Funds::::get(3_000).unwrap(); + let (contributed, status) = Salp::contribution(fund.trie_index, &BRUCE); + assert_eq!(fund.raised, 200); + assert_eq!(contributed, 200); + assert_eq!(status, ContributionStatus::Idle); + + let vs_token = + ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()) + .unwrap(); + let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( + RelayCurrencyId::get(), + 3_000, + 1, + SlotLength::get(), + ) + .unwrap(); + assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 200); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 200); + }); +} + +#[test] +fn contribute_when_xcm_error_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, false,)); + + let fund = Funds::::get(3_000).unwrap(); + let (contributed, status) = Salp::contribution(fund.trie_index, &BRUCE); + assert_eq!(fund.raised, 0); + assert_eq!(contributed, 0); + assert_eq!(status, ContributionStatus::Idle); + + let vs_token = + ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()) + .unwrap(); + let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( + RelayCurrencyId::get(), + 3_000, + 1, + SlotLength::get(), + ) + .unwrap(); + assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_token).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_token).reserved, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).reserved, 0); + }); +} + +#[test] +fn confirm_contribute_later_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + + let fund = Funds::::get(3_000).unwrap(); + let (contributed, status) = Salp::contribution(fund.trie_index, &BRUCE); + assert_eq!(fund.raised, 100); + assert_eq!(contributed, 100); + assert_eq!(status, ContributionStatus::Idle); + + let vs_token = + ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()) + .unwrap(); + let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( + RelayCurrencyId::get(), + 3_000, + 1, + SlotLength::get(), + ) + .unwrap(); + assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 100); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 100); + }); +} + +#[test] +fn contribute_with_wrong_origin_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_noop!(Salp::contribute(RuntimeOrigin::none(), 3_000, 100), DispatchError::BadOrigin); + + assert_noop!( + Salp::confirm_contribute(RuntimeOrigin::none(), 0, true), + DispatchError::BadOrigin, + ); + }); +} + +#[test] +fn contribute_with_low_contribution_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_noop!( + Salp::contribute(Some(BRUCE).into(), 3_000, MinContribution::get() - 1), + Error::::ContributionTooSmall + ); + }); +} + +#[test] +fn contribute_with_wrong_para_id_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_noop!( + Salp::contribute(Some(BRUCE).into(), 4_000, 100), + Error::::InvalidParaId + ); + }); +} + +#[test] +fn contribute_with_wrong_fund_status_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000,)); + assert_noop!( + Salp::contribute(Some(BRUCE).into(), 3_000, 100), + Error::::InvalidFundStatus + ); + }); +} + +#[test] +fn contribute_exceed_cap_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_noop!( + Salp::contribute(Some(BRUCE).into(), 3_000, 1_001), + Error::::CapExceeded + ); + }); +} + +#[test] +fn contribute_when_contributing_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_noop!( + Salp::confirm_contribute(Some(ALICE).into(), 0, true), + Error::::NotFindContributionValue + ); + }); +} + +#[test] +fn confirm_contribute_when_not_in_contributing_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + + assert_noop!( + Salp::contribute(Some(BRUCE).into(), 3_000, 100), + Error::::InvalidContributionStatus + ); + }); +} + +#[test] +fn contribute_with_when_ump_wrong_should_fail() { + // TODO: Require an solution to settle with parallel test workflow +} + +#[test] +fn withdraw_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + + let fund = Funds::::get(3_000).unwrap(); + assert_eq!(fund.status, FundStatus::RedeemWithdrew); + + assert_ok!(Salp::create(Some(ALICE).into(), 4_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 4_000, 100)); + Salp::bind_query_id_and_contribution(0, 4_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_fail(Some(ALICE).into(), 4_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 4_000)); + + let fund = Funds::::get(4_000).unwrap(); + assert_eq!(fund.status, FundStatus::RefundWithdrew); + }); +} + +#[test] +fn withdraw_when_xcm_error_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + + let fund = Funds::::get(3_000).unwrap(); + assert_eq!(fund.status, FundStatus::RedeemWithdrew); + + assert_ok!(Salp::create(Some(ALICE).into(), 4_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 4_000, 100)); + Salp::bind_query_id_and_contribution(0, 4_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_fail(Some(ALICE).into(), 4_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 4_000)); + + let fund = Funds::::get(4_000).unwrap(); + assert_eq!(fund.status, FundStatus::RefundWithdrew); + }); +} + +#[test] +fn double_withdraw_same_fund_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + assert_noop!(Salp::withdraw(Some(ALICE).into(), 3_000), Error::::InvalidFundStatus); + + let fund = Funds::::get(3_000).unwrap(); + assert_eq!(fund.status, FundStatus::RedeemWithdrew); + + assert_ok!(Salp::create(Some(ALICE).into(), 4_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 4_000, 100)); + Salp::bind_query_id_and_contribution(0, 4_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_fail(Some(ALICE).into(), 4_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 4_000)); + assert_noop!(Salp::withdraw(Some(ALICE).into(), 4_000), Error::::InvalidFundStatus); + + let fund = Funds::::get(4_000).unwrap(); + assert_eq!(fund.status, FundStatus::RefundWithdrew); + }); +} + +#[test] +fn double_withdraw_same_fund_when_one_of_xcm_error_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + assert_noop!(Salp::withdraw(Some(ALICE).into(), 3_000), Error::::InvalidFundStatus); + }); +} + +#[test] +fn withdraw_with_wrong_origin_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); + + assert_noop!(Salp::withdraw(RuntimeOrigin::none(), 3_000), DispatchError::BadOrigin); + }); +} + +#[test] +fn withdraw_with_wrong_para_id_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); + + assert_noop!(Salp::withdraw(Some(ALICE).into(), 4_000), Error::::InvalidParaId); + }); +} + +#[test] +fn withdraw_with_wrong_fund_status_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + + assert_noop!(Salp::withdraw(Some(ALICE).into(), 3_000), Error::::InvalidFundStatus); + }); +} + +#[test] +fn withdraw_with_when_ump_wrong_should_fail() { + // TODO: Require an solution to settle with parallel test workflow +} + +#[test] +fn refund_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_fail(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::refund(Some(BRUCE).into(), 3_000, 1, SlotLength::get(), 100)); + + let vs_token = + ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()) + .unwrap(); + let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( + RelayCurrencyId::get(), + 3_000, + 1, + SlotLength::get(), + ) + .unwrap(); + assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_token).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_token).reserved, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).reserved, 0); + assert_eq!(Tokens::accounts(BRUCE, RelayCurrencyId::get()).free, INIT_BALANCE); + assert_eq!(Tokens::accounts(BRUCE, RelayCurrencyId::get()).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, RelayCurrencyId::get()).reserved, 0); + }); +} + +#[test] +fn refund_when_xcm_error_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_fail(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::refund(Some(BRUCE).into(), 3_000, 1, SlotLength::get(), 100)); + + let vs_token = + ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()) + .unwrap(); + let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( + RelayCurrencyId::get(), + 3_000, + 1, + SlotLength::get(), + ) + .unwrap(); + assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_token).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_token).reserved, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).reserved, 0); + }); +} + +#[test] +fn double_refund_when_one_of_xcm_error_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_fail(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::refund(Some(BRUCE).into(), 3_000, 1, SlotLength::get(), 100)); + assert_noop!( + Salp::refund(Some(BRUCE).into(), 3_000, 1, SlotLength::get(), 100), + Error::::NotEnoughBalanceInFund + ); + }); +} + +#[test] +fn refund_with_wrong_origin_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_fail(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + + assert_noop!( + Salp::refund(RuntimeOrigin::root(), 3_000, 1, SlotLength::get(), 100), + DispatchError::BadOrigin + ); + assert_noop!( + Salp::refund(RuntimeOrigin::none(), 3_000, 1, SlotLength::get(), 100), + DispatchError::BadOrigin + ); + + assert_ok!(Salp::refund(Some(BRUCE).into(), 3_000, 1, SlotLength::get(), 100)); + }); +} + +#[test] +fn refund_with_wrong_para_id_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::fund_fail(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + + assert_noop!( + Salp::refund(Some(BRUCE).into(), 4_000, 1, SlotLength::get(), 100), + Error::::InvalidFundNotExist + ); + }); +} + +#[test] +fn dissolve_should_work() { + new_test_ext().execute_with(|| { + let remove_times = 4; + let contribute_account_num = remove_times * RemoveKeysLimit::get(); + + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 10_000, 1, SlotLength::get())); + for i in 0..contribute_account_num { + let ract = AccountId::new([(i as u8); 32]); + assert_ok!(Tokens::deposit(RelayCurrencyId::get(), &ract, 10)); + assert_ok!(Salp::contribute(Some(ract.clone()).into(), 3_000, 10)); + Salp::bind_query_id_and_contribution(0, 3_000, ract, 10); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + } + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::fund_end(Some(ALICE).into(), 3_000)); + + for _ in 0..remove_times { + assert_ok!(Salp::dissolve(Some(ALICE).into(), 3_000)); + } + + assert!(Funds::::get(3_000).is_none()); + assert!(Salp::contribution_iterator(0).next().is_none()); + }); +} + +#[test] +fn dissolve_with_wrong_origin_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::fund_end(Some(ALICE).into(), 3_000)); + + assert_noop!(Salp::dissolve(RuntimeOrigin::none(), 3_000), DispatchError::BadOrigin); + }); +} + +#[test] +fn dissolve_with_wrong_para_id_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::fund_end(Some(ALICE).into(), 3_000)); + + assert_noop!(Salp::dissolve(Some(ALICE).into(), 4_000), Error::::InvalidParaId); + }); +} + +#[test] +fn dissolve_with_wrong_fund_status_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + + assert_noop!(Salp::dissolve(Some(ALICE).into(), 3_000), Error::::InvalidFundStatus); + }); +} + +#[test] +fn redeem_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + + assert_eq!(Tokens::accounts(BRUCE, RelayCurrencyId::get()).free, INIT_BALANCE - 100); + assert_eq!(Tokens::accounts(BRUCE, RelayCurrencyId::get()).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, RelayCurrencyId::get()).reserved, 0); + + assert_eq!( + Tokens::accounts(Salp::fund_account_id(3_000), RelayCurrencyId::get()).free, + 100 + ); + assert_eq!( + Tokens::accounts(Salp::fund_account_id(3_000), RelayCurrencyId::get()).frozen, + 0 + ); + assert_eq!( + Tokens::accounts(Salp::fund_account_id(3_000), RelayCurrencyId::get()).reserved, + 0 + ); + + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::unlock(Some(BRUCE).into(), BRUCE, 3_000)); + + // Mock the BlockNumber + let block_begin_redeem = (SlotLength::get() + 1) * LeasePeriod::get(); + System::set_block_number(block_begin_redeem.into()); + + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + + let vs_token = + ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()) + .unwrap(); + let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( + RelayCurrencyId::get(), + 3_000, + 1, + SlotLength::get(), + ) + .unwrap(); + + assert_ok!(>::transfer(vs_token, &BRUCE, &CATHI, 50)); + assert_ok!(>::transfer(vs_bond, &BRUCE, &CATHI, 50)); + + assert_ok!(Salp::redeem(Some(BRUCE).into(), 3_000, 50)); + + assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_token).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_token).reserved, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).reserved, 0); + assert_eq!(Tokens::accounts(BRUCE, RelayCurrencyId::get()).free, INIT_BALANCE - 50); + assert_eq!(Tokens::accounts(BRUCE, RelayCurrencyId::get()).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, RelayCurrencyId::get()).reserved, 0); + + assert_ok!(Salp::redeem(Some(CATHI).into(), 3_000, 50)); + + assert_eq!(Tokens::accounts(CATHI, vs_token).free, 0); + assert_eq!(Tokens::accounts(CATHI, vs_token).frozen, 0); + assert_eq!(Tokens::accounts(CATHI, vs_token).reserved, 0); + assert_eq!(Tokens::accounts(CATHI, vs_bond).free, 0); + assert_eq!(Tokens::accounts(CATHI, vs_bond).frozen, 0); + assert_eq!(Tokens::accounts(CATHI, vs_bond).reserved, 0); + assert_eq!(Tokens::accounts(CATHI, RelayCurrencyId::get()).free, INIT_BALANCE + 50); + assert_eq!(Tokens::accounts(CATHI, RelayCurrencyId::get()).frozen, 0); + assert_eq!(Tokens::accounts(CATHI, RelayCurrencyId::get()).reserved, 0); + }); +} + +#[test] +fn redeem_with_speical_vsbond_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 2001, 1_000, 13, 20)); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 2001, 100)); + Salp::bind_query_id_and_contribution(0, 2001, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + + assert_eq!(Tokens::accounts(BRUCE, RelayCurrencyId::get()).free, INIT_BALANCE - 100); + assert_eq!(Tokens::accounts(BRUCE, RelayCurrencyId::get()).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, RelayCurrencyId::get()).reserved, 0); + + assert_eq!(Tokens::accounts(Salp::fund_account_id(2001), RelayCurrencyId::get()).free, 100); + assert_eq!(Tokens::accounts(Salp::fund_account_id(2001), RelayCurrencyId::get()).frozen, 0); + assert_eq!( + Tokens::accounts(Salp::fund_account_id(2001), RelayCurrencyId::get()).reserved, + 0 + ); + + assert_ok!(Salp::fund_success(Some(ALICE).into(), 2001)); + assert_ok!(Salp::unlock(Some(BRUCE).into(), BRUCE, 2001)); + + // Mock the BlockNumber + let block_begin_redeem = (SlotLength::get() + 1) * LeasePeriod::get(); + System::set_block_number(block_begin_redeem.into()); + + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 2001)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 2001)); + + let vs_token = + ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()) + .unwrap(); + let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( + RelayCurrencyId::get(), + 2001, + 13, + 20, + ) + .unwrap(); + + assert_ok!(>::transfer(vs_token, &BRUCE, &CATHI, 50)); + assert_ok!(>::transfer(vs_bond, &BRUCE, &CATHI, 50)); + + assert_ok!(Salp::redeem(Some(BRUCE).into(), 2001, 50)); + + assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_token).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_token).reserved, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).reserved, 0); + assert_eq!(Tokens::accounts(BRUCE, RelayCurrencyId::get()).free, INIT_BALANCE - 50); + assert_eq!(Tokens::accounts(BRUCE, RelayCurrencyId::get()).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, RelayCurrencyId::get()).reserved, 0); + + assert_ok!(Salp::redeem(Some(CATHI).into(), 2001, 50)); + + assert_eq!(Tokens::accounts(CATHI, vs_token).free, 0); + assert_eq!(Tokens::accounts(CATHI, vs_token).frozen, 0); + assert_eq!(Tokens::accounts(CATHI, vs_token).reserved, 0); + assert_eq!(Tokens::accounts(CATHI, vs_bond).free, 0); + assert_eq!(Tokens::accounts(CATHI, vs_bond).frozen, 0); + assert_eq!(Tokens::accounts(CATHI, vs_bond).reserved, 0); + assert_eq!(Tokens::accounts(CATHI, RelayCurrencyId::get()).free, INIT_BALANCE + 50); + assert_eq!(Tokens::accounts(CATHI, RelayCurrencyId::get()).frozen, 0); + assert_eq!(Tokens::accounts(CATHI, RelayCurrencyId::get()).reserved, 0); + }); +} + +#[test] +fn redeem_with_wrong_origin_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::unlock(Some(BRUCE).into(), BRUCE, 3_000)); + + // Mock the BlockNumber + let block_begin_redeem = (SlotLength::get() + 1) * LeasePeriod::get(); + System::set_block_number(block_begin_redeem.into()); + + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + + assert_noop!(Salp::redeem(RuntimeOrigin::root(), 3_000, 50), DispatchError::BadOrigin); + assert_noop!(Salp::redeem(RuntimeOrigin::none(), 3_000, 50), DispatchError::BadOrigin); + }); +} + +#[test] +fn redeem_with_not_redeemable_vsbond_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::unlock(Some(BRUCE).into(), BRUCE, 3_000)); + + // Mock the BlockNumber + let block_not_redeemable = LeasePeriod::get(); + System::set_block_number(block_not_redeemable.into()); + + let vs_token = + ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()) + .unwrap(); + let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( + RelayCurrencyId::get(), + 3_000, + 1, + SlotLength::get(), + ) + .unwrap(); + + assert_ok!(>::transfer(vs_token, &BRUCE, &CATHI, 50)); + assert_ok!(>::transfer(vs_bond, &BRUCE, &CATHI, 50)); + + assert_noop!(Salp::redeem(Some(BRUCE).into(), 3_000, 50), Error::::InvalidFundStatus); + + assert_noop!(Salp::redeem(Some(CATHI).into(), 3_000, 50), Error::::InvalidFundStatus); + }); +} + +#[test] +fn redeem_without_enough_vsassets_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::unlock(Some(BRUCE).into(), BRUCE, 3_000)); + + // Mock the BlockNumber + let block_begin_redeem = (SlotLength::get() + 1) * LeasePeriod::get(); + System::set_block_number(block_begin_redeem.into()); + + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + + let vs_token = + ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()) + .unwrap(); + let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( + RelayCurrencyId::get(), + 3_000, + 1, + SlotLength::get(), + ) + .unwrap(); + + assert_ok!(>::transfer(vs_token, &BRUCE, &CATHI, 50)); + assert_ok!(>::transfer(vs_bond, &BRUCE, &CATHI, 50)); + + assert_noop!( + Salp::redeem(Some(BRUCE).into(), 3_000, 60), + Error::::NotEnoughFreeAssetsToRedeem + ); + + assert_noop!( + Salp::redeem(Some(CATHI).into(), 3_000, 60), + Error::::NotEnoughFreeAssetsToRedeem + ); + }); +} + +#[test] +fn redeem_without_enough_balance_in_pool_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::unlock(Some(BRUCE).into(), BRUCE, 3_000)); + + // Mock the BlockNumber + let block_begin_redeem = (SlotLength::get() + 1) * LeasePeriod::get(); + System::set_block_number(block_begin_redeem.into()); + + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + + // Before withdraw + assert_noop!( + Salp::redeem(Some(BRUCE).into(), 3_000, 200), + Error::::NotEnoughBalanceInRedeemPool + ); + }); +} + +#[test] +fn redeem_with_when_ump_wrong_should_fail() { + // TODO: Require an solution to settle with parallel test workflow +} + +#[test] +fn release_from_redeem_to_bancor_should_work() { + fn run_to_block(n: BlockNumber) { + use frame_support::traits::Hooks; + while System::block_number() <= n.into() { + Salp::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + Salp::on_initialize(System::block_number()); + } + } + + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::unlock(Some(BRUCE).into(), BRUCE, 3_000)); + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + + run_to_block(ReleaseCycle::get()); + + // TODO: Check the balance of bancor(Waiting Bancor to Support..) + }); +} + +// Utilities Test +#[test] +fn check_next_trie_index() { + new_test_ext().execute_with(|| { + for i in 0..100 { + assert_eq!(CurrentTrieIndex::::get(), i); + assert_ok!(Salp::next_trie_index()); + } + }); +} + +#[test] +fn batch_unlock_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::batch_unlock(Some(ALICE).into(), 3_000)); + }) +} + +#[test] +fn unlock_when_fund_ongoing_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::unlock(Some(BRUCE).into(), BRUCE, 3_000)); + + let vs_token = + ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()) + .unwrap(); + let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( + RelayCurrencyId::get(), + 3_000, + 1, + SlotLength::get(), + ) + .unwrap(); + + assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 100); + assert_eq!(Tokens::accounts(BRUCE, vs_token).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_token).reserved, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 100); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).reserved, 0); + }); +} + +#[test] +fn set_confirmor_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_noop!( + Salp::confirm_contribute(Some(BRUCE).into(), 0, true), + DispatchError::BadOrigin, + ); + assert_ok!(Salp::set_multisig_confirm_account(Some(ALICE).into(), BRUCE)); + assert_ok!(Salp::confirm_contribute(Some(BRUCE).into(), 0, true,)); + }); +} + +#[test] +fn refund_meanwhile_issue_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_fail(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + let vs_bond_old = ::CurrencyIdConversion::convert_to_vsbond( + RelayCurrencyId::get(), + 3_000, + 1, + SlotLength::get(), + ) + .unwrap(); + assert_eq!(Tokens::accounts(BRUCE, vs_bond_old).free, 100); + assert_eq!( + ::CurrencyIdRegister::check_vsbond_registered( + TokenSymbol::KSM, + 3_000, + 2, + SlotLength::get() + 1 + ), + false + ); + assert_ok!(Salp::continue_fund(Some(ALICE).into(), 3_000, 2, SlotLength::get() + 1)); + assert_eq!( + ::CurrencyIdRegister::check_vsbond_registered( + TokenSymbol::KSM, + 3_000, + 2, + SlotLength::get() + 1 + ), + true + ); + let old_fund = FailedFundsToRefund::::get((3_000, 1, SlotLength::get())).unwrap(); + assert_eq!(old_fund.first_slot, 1); + assert_eq!(old_fund.raised, 100); + let mut new_fund = Funds::::get(3_000).unwrap(); + assert_eq!(new_fund.first_slot, 2); + assert_eq!(new_fund.raised, 100); + let vs_bond_new = ::CurrencyIdConversion::convert_to_vsbond( + RelayCurrencyId::get(), + 3_000, + 2, + SlotLength::get() + 1, + ) + .unwrap(); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + new_fund = Funds::::get(3_000).unwrap(); + assert_eq!(new_fund.raised, 200); + assert_eq!(Tokens::accounts(BRUCE, vs_bond_new).free, 100); + // refund from old failed fund should success + assert_ok!(Salp::refund(Some(BRUCE).into(), 3_000, 1, SlotLength::get(), 50)); + assert_eq!(Tokens::accounts(BRUCE, vs_bond_old).free, 50); + // refund from new fund should failed + assert_noop!( + Salp::refund(Some(BRUCE).into(), 3_000, 2, SlotLength::get() + 1, 100), + Error::::InvalidRefund, + ); + // refund from not exist fund should failed + assert_noop!( + Salp::refund(Some(BRUCE).into(), 4_000, 2, SlotLength::get() + 1, 100), + Error::::InvalidFundNotExist, + ); + // after dissolve failed fund refund from old should fail + assert_ok!(Salp::dissolve_refunded(Some(ALICE).into(), 3_000, 1, SlotLength::get())); + assert_noop!( + Salp::refund(Some(BRUCE).into(), 3_000, 1, SlotLength::get(), 50), + Error::::InvalidRefund, + ); + // after new fund finally success redeem should success + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + assert_eq!( + Tokens::accounts(Salp::fund_account_id(3_000), RelayCurrencyId::get()).free, + 150 + ); + assert_ok!(Salp::redeem(Some(BRUCE).into(), 3_000, 50)); + assert_eq!(Tokens::accounts(BRUCE, vs_bond_new).free, 50); + // after fund dissolved redeem should fail + assert_ok!(Salp::fund_end(Some(ALICE).into(), 3_000)); + assert_eq!( + Tokens::accounts(Salp::fund_account_id(3_000), RelayCurrencyId::get()).free, + 100 + ); + assert_ok!(Salp::dissolve(Some(ALICE).into(), 3_000)); + assert_eq!(Tokens::accounts(Salp::fund_account_id(3_000), RelayCurrencyId::get()).free, 0); + let treasury_account: AccountId = TreasuryAccount::get(); + assert_eq!(Tokens::accounts(treasury_account, RelayCurrencyId::get()).free, 25); + let buyback_account: AccountId = BuybackPalletId::get().into_account_truncating(); + assert_eq!(Tokens::accounts(buyback_account.clone(), RelayCurrencyId::get()).free, 75); + assert_noop!(Salp::redeem(Some(BRUCE).into(), 3_000, 50), Error::::InvalidParaId); + + let para_id = 2001u32; + let asset_0_currency_id: AssetId = + AssetId::try_convert_from(RelayCurrencyId::get(), para_id).unwrap(); + let asset_1_currency_id: AssetId = + AssetId::try_convert_from(CurrencyId::VSToken(TokenSymbol::KSM), para_id).unwrap(); + assert_ok!(ZenlinkProtocol::create_pair( + RuntimeOrigin::root(), + asset_0_currency_id, + asset_1_currency_id, + ALICE + )); + let deadline: BlockNumberFor = + >::block_number() + BlockNumberFor::::from(100u32); + assert_ok!(ZenlinkProtocol::add_liquidity( + RuntimeOrigin::signed(ALICE), + asset_0_currency_id, + asset_1_currency_id, + 1000, + 2200, + 1, + 1, + deadline + )); + assert_noop!( + Salp::buyback(Some(ALICE).into(), 80), + orml_tokens::Error::::BalanceTooLow + ); + assert_ok!(Salp::buyback(Some(ALICE).into(), 70)); + assert_noop!( + Salp::buyback(Some(ALICE).into(), 10), + zenlink_protocol::Error::::InsufficientTargetAmount + ); + + let amounts = vec![1_000u128, 1_000u128]; + assert_ok!(StablePool::create_pool( + RuntimeOrigin::signed(ALICE), + vec![KSM, VKSM], + vec![1u128.into(), 1u128.into()], + 0u128.into(), + 0u128.into(), + 0u128.into(), + 220u128.into(), + ALICE, + ALICE, + 1000000000000u128.into() + )); + assert_ok!(StablePool::edit_token_rate( + RuntimeOrigin::signed(ALICE), + 0, + vec![(KSM, (1, 1)), (VKSM, (10, 11))] + )); + assert_ok!(StablePool::add_liquidity( + RuntimeOrigin::signed(ALICE).into(), + 0, + amounts.clone(), + 0 + )); + assert_ok!(StablePool::create_pool( + RuntimeOrigin::signed(ALICE), + vec![KSM, VSKSM], + vec![1u128.into(), 1u128.into()], + 0u128.into(), + 0u128.into(), + 0u128.into(), + 220u128.into(), + ALICE, + ALICE, + 1000000000000u128.into() + )); + assert_ok!(StablePool::edit_token_rate( + RuntimeOrigin::signed(ALICE), + 1, + vec![(VSKSM, (1, 1)), (KSM, (10, 30))] + )); + assert_ok!(StablePool::add_liquidity( + RuntimeOrigin::signed(ALICE).into(), + 1, + amounts.clone(), + 0 + )); + assert_ok!(StablePool::create_pool( + RuntimeOrigin::signed(ALICE), + vec![VSKSM, VKSM], + vec![1u128.into(), 1u128.into()], + 0u128.into(), + 0u128.into(), + 0u128.into(), + 220u128.into(), + ALICE, + ALICE, + 1000000000000u128.into() + )); + assert_ok!(StablePool::edit_token_rate( + RuntimeOrigin::signed(ALICE), + 2, + vec![(VSKSM, (1, 1)), (VKSM, (10, 11))] + )); + assert_ok!(StablePool::add_liquidity(RuntimeOrigin::signed(ALICE).into(), 2, amounts, 0)); + + assert_ok!(VtokenMinting::set_minimum_mint(RuntimeOrigin::signed(ALICE), KSM, 0)); + assert_ok!(VtokenMinting::mint( + Some(ALICE).into(), + KSM, + 2_000, + BoundedVec::default(), + None + )); + assert_ok!(Tokens::set_balance(RuntimeOrigin::root(), ALICE, VKSM, 0, 0)); + assert_noop!( + Salp::buyback_vstoken_by_stable_pool(Some(ALICE).into(), 0, VKSM, 70), + Error::::ArgumentsError + ); + assert_noop!( + Salp::buyback_vstoken_by_stable_pool(Some(ALICE).into(), 1, KSM, 100), + orml_tokens::Error::::BalanceTooLow + ); + let token_value = VtokenMinting::token_to_vtoken(KSM, VKSM, 100); + assert_eq!(token_value, Ok(100)); + assert_eq!(Tokens::free_balance(KSM, &ALICE), 95000); + assert_ok!(Tokens::set_balance(RuntimeOrigin::root(), buyback_account, KSM, 100, 0)); + + assert_ok!(Salp::buyback_vstoken_by_stable_pool(Some(BRUCE).into(), 1, KSM, 100)); + assert_eq!(Tokens::free_balance(VSKSM, &BRUCE), 100); + }); +} + +#[test] +fn edit_fund_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + assert_ok!(Salp::fund_fail(Some(ALICE).into(), 3_000)); + let mut fund = Funds::::get(3_000).unwrap(); + assert_eq!(fund.raised, 100); + + assert_ok!(Salp::edit( + Some(ALICE).into(), + 3_000, + 1_000, + 150, + 2, + SlotLength::get() + 1, + Some(FundStatus::Ongoing) + )); + fund = Funds::::get(3_000).unwrap(); + assert_eq!(fund.raised, 150); + assert_eq!(fund.status, FundStatus::Ongoing); + }); +} + +fn reserve_init() -> (CurrencyId, CurrencyId) { + assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); + assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); + Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); + assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); + + assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::unlock(Some(BRUCE).into(), BRUCE, 3_000)); + + // Mock the BlockNumber + let block_begin_redeem = (SlotLength::get() + 1) * LeasePeriod::get(); + System::set_block_number(block_begin_redeem.into()); + + let vs_token = + ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()).unwrap(); + let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( + RelayCurrencyId::get(), + 3_000, + 1, + SlotLength::get(), + ) + .unwrap(); + (vs_token, vs_bond) +} + +#[test] +fn batch_handle_reserve_should_work() { + new_test_ext().execute_with(|| { + let (vs_token, vs_bond) = reserve_init(); + + assert_ok!(Salp::reserve(Some(BRUCE).into(), 3_000, 50, false)); + assert_ok!(>::transfer(vs_token, &BRUCE, &CATHI, 50)); + assert_ok!(>::transfer(vs_bond, &BRUCE, &CATHI, 50)); + assert_ok!(Salp::reserve(Some(CATHI).into(), 3_000, 10, false)); + assert_ok!(Salp::reserve(Some(CATHI).into(), 3_000, 40, false)); + assert_eq!(Tokens::accounts(CATHI, vs_token).frozen, 50); + assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); + assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); + + assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 50); + assert_ok!(Salp::batch_handle_reserve(Some(BRUCE).into(), 3_000)); + assert_eq!(ReserveInfos::::get(3_000, BRUCE).value, 0); + + assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_token).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_token).reserved, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, vs_bond).reserved, 0); + assert_eq!(Tokens::accounts(BRUCE, RelayCurrencyId::get()).free, INIT_BALANCE - 50); + assert_eq!(Tokens::accounts(BRUCE, RelayCurrencyId::get()).frozen, 0); + assert_eq!(Tokens::accounts(BRUCE, RelayCurrencyId::get()).reserved, 0); + + assert_eq!(Tokens::accounts(CATHI, vs_token).free, 0); + assert_eq!(Tokens::accounts(CATHI, vs_token).frozen, 0); + assert_eq!(Tokens::accounts(CATHI, vs_token).reserved, 0); + assert_eq!(Tokens::accounts(CATHI, vs_bond).free, 0); + assert_eq!(Tokens::accounts(CATHI, vs_bond).frozen, 0); + assert_eq!(Tokens::accounts(CATHI, vs_bond).reserved, 0); + assert_eq!(Tokens::accounts(CATHI, RelayCurrencyId::get()).free, INIT_BALANCE + 50); + assert_eq!(Tokens::accounts(CATHI, RelayCurrencyId::get()).frozen, 0); + assert_eq!(Tokens::accounts(CATHI, RelayCurrencyId::get()).reserved, 0); + }); +} + +#[test] +fn batch_handle_reserve_should_fail() { + new_test_ext().execute_with(|| { + let (_vs_token, _vs_bond) = reserve_init(); + + assert_noop!( + Salp::batch_handle_reserve(Some(BRUCE).into(), 3_000), + Error::::InvalidFundStatus, + ); + assert_ok!(Salp::reserve(Some(BRUCE).into(), 3_000, 100, false)); + assert_noop!( + Salp::batch_handle_reserve(Some(BRUCE).into(), 3_000), + Error::::InvalidFundStatus, + ); + }); +} + +#[test] +fn reserve_should_fail() { + new_test_ext().execute_with(|| { + let (_vs_token, _vs_bond) = reserve_init(); + + assert_noop!( + Salp::reserve(Some(CATHI).into(), 3_000, 10, false), + orml_tokens::Error::::BalanceTooLow, + ); + }); +} + +#[test] +fn reserve_should_work() { + new_test_ext().execute_with(|| { + let (vs_token, _vs_bond) = reserve_init(); + + assert_eq!(Tokens::accounts(BRUCE, vs_token).frozen, 0); + assert_ok!(Salp::reserve(Some(BRUCE).into(), 3_000, 100, false)); + assert_eq!(Tokens::accounts(BRUCE, vs_token).frozen, 100); + assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 100); + assert_ok!(Salp::cancel_reservation(Some(BRUCE).into(), 3_000)); + assert_ok!(Salp::cancel_reservation(Some(BRUCE).into(), 3_000)); + assert_eq!(Tokens::accounts(BRUCE, vs_token).frozen, 0); + assert_ok!(Salp::reserve(Some(BRUCE).into(), 3_000, 50, false)); + assert_eq!(ReserveInfos::::get(3_000, BRUCE).value, 50); + assert_eq!(Tokens::accounts(BRUCE, vs_token).frozen, 50); + assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 100); + }); +} diff --git a/pallets/deprecated/salp/src/weights.rs b/pallets/deprecated/salp/src/weights.rs new file mode 100644 index 000000000..50abb1130 --- /dev/null +++ b/pallets/deprecated/salp/src/weights.rs @@ -0,0 +1,458 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for bifrost_salp +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-14, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bifrost-jenkins`, CPU: `Intel(R) Xeon(R) CPU E5-26xx v4` +//! WASM-EXECUTION: Compiled, CHAIN: Some("bifrost-kusama-local"), DB CACHE: 1024 + +// Executed Command: +// target/release/bifrost +// benchmark +// pallet +// --chain=bifrost-kusama-local +// --steps=50 +// --repeat=20 +// --pallet=bifrost_salp +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./pallets/salp/src/weights.rs +// --template=./weight-template/pallet-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for bifrost_salp. +pub trait WeightInfo { + fn contribute() -> Weight; + fn refund() -> Weight; + fn unlock() -> Weight; + fn batch_unlock() -> Weight; + fn redeem() -> Weight; + fn set_multisig_confirm_account() -> Weight; + fn fund_success() -> Weight; + fn fund_fail() -> Weight; + fn continue_fund() -> Weight; + fn fund_retire() -> Weight; + fn fund_end() -> Weight; + fn create() -> Weight; + fn edit() -> Weight; + fn confirm_contribute() -> Weight; + fn withdraw() -> Weight; + fn dissolve_refunded() -> Weight; + fn dissolve() -> Weight; + fn buyback() -> Weight; + fn buyback_vstoken_by_stable_pool() -> Weight; + fn reserve() -> Weight; + fn batch_handle_reserve() -> Weight; + fn cancel_reservation() -> Weight; +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: Salp Funds (r:1 w:0) + /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) + /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) + /// Storage: Tokens Accounts (r:1 w:1) + /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) + /// Storage: XcmInterface XcmWeightAndFee (r:1 w:0) + /// Proof Skipped: XcmInterface XcmWeightAndFee (max_values: None, max_size: None, mode: Measured) + /// Storage: PolkadotXcm QueryCounter (r:1 w:1) + /// Proof Skipped: PolkadotXcm QueryCounter (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainInfo ParachainId (r:1 w:0) + /// Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Salp QueryIdContributionInfo (r:0 w:1) + /// Proof Skipped: Salp QueryIdContributionInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: PolkadotXcm Queries (r:0 w:1) + /// Proof Skipped: PolkadotXcm Queries (max_values: None, max_size: None, mode: Measured) + /// Storage: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) + /// Proof Skipped: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) + fn contribute() -> Weight { + // Proof Size summary in bytes: + // Measured: `2252` + // Estimated: `5717` + // Minimum execution time: 175_000_000 picoseconds. + Weight::from_parts(177_879_000, 5717) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + } + /// Storage: Salp FailedFundsToRefund (r:1 w:0) + /// Proof Skipped: Salp FailedFundsToRefund (max_values: None, max_size: None, mode: Measured) + /// Storage: Salp Funds (r:1 w:1) + /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: Salp RedeemPool (r:1 w:1) + /// Proof Skipped: Salp RedeemPool (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Tokens Accounts (r:4 w:4) + /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) + /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) + /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) + /// Storage: Tokens TotalIssuance (r:2 w:2) + /// Proof: Tokens TotalIssuance (max_values: None, max_size: Some(38), added: 2513, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn refund() -> Weight { + // Proof Size summary in bytes: + // Measured: `2375` + // Estimated: `11362` + // Minimum execution time: 267_454_000 picoseconds. + Weight::from_parts(270_319_000, 11362) + .saturating_add(RocksDbWeight::get().reads(11_u64)) + .saturating_add(RocksDbWeight::get().writes(9_u64)) + } + /// Storage: Salp Funds (r:1 w:0) + /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: Tokens Accounts (r:2 w:2) + /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) + /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) + /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) + /// Storage: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:0) + /// Proof Skipped: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:0) + fn unlock() -> Weight { + // Proof Size summary in bytes: + // Measured: `1962` + // Estimated: `6176` + // Minimum execution time: 129_578_000 picoseconds. + Weight::from_parts(130_658_000, 6176) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Salp Funds (r:1 w:0) + /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: Tokens Accounts (r:2 w:2) + /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) + /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) + /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) + /// Storage: unknown `0x` (r:1 w:0) + /// Proof Skipped: unknown `0x` (r:1 w:0) + /// Storage: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:0) + /// Proof Skipped: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:0) + fn batch_unlock() -> Weight { + // Proof Size summary in bytes: + // Measured: `1995` + // Estimated: `6176` + // Minimum execution time: 143_054_000 picoseconds. + Weight::from_parts(146_914_000, 6176) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Salp Funds (r:1 w:1) + /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: Salp RedeemPool (r:1 w:1) + /// Proof Skipped: Salp RedeemPool (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Tokens Accounts (r:4 w:4) + /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) + /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) + /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) + /// Storage: Tokens TotalIssuance (r:2 w:2) + /// Proof: Tokens TotalIssuance (max_values: None, max_size: Some(38), added: 2513, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn redeem() -> Weight { + // Proof Size summary in bytes: + // Measured: `2356` + // Estimated: `11362` + // Minimum execution time: 255_416_000 picoseconds. + Weight::from_parts(257_010_000, 11362) + .saturating_add(RocksDbWeight::get().reads(10_u64)) + .saturating_add(RocksDbWeight::get().writes(9_u64)) + } + /// Storage: Salp MultisigConfirmAccount (r:0 w:1) + /// Proof Skipped: Salp MultisigConfirmAccount (max_values: Some(1), max_size: None, mode: Measured) + fn set_multisig_confirm_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_258_000 picoseconds. + Weight::from_parts(10_624_000, 0) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Salp Funds (r:1 w:1) + /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) + fn fund_success() -> Weight { + // Proof Size summary in bytes: + // Measured: `292` + // Estimated: `3757` + // Minimum execution time: 42_399_000 picoseconds. + Weight::from_parts(43_690_000, 3757) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Salp Funds (r:1 w:1) + /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) + fn fund_fail() -> Weight { + // Proof Size summary in bytes: + // Measured: `292` + // Estimated: `3757` + // Minimum execution time: 42_250_000 picoseconds. + Weight::from_parts(42_892_000, 3757) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Salp Funds (r:1 w:1) + /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: AssetRegistry CurrencyMetadatas (r:2 w:1) + /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) + /// Storage: Salp FailedFundsToRefund (r:0 w:1) + /// Proof Skipped: Salp FailedFundsToRefund (max_values: None, max_size: None, mode: Measured) + fn continue_fund() -> Weight { + // Proof Size summary in bytes: + // Measured: `1061` + // Estimated: `7001` + // Minimum execution time: 99_887_000 picoseconds. + Weight::from_parts(101_067_000, 7001) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Salp Funds (r:1 w:1) + /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) + fn fund_retire() -> Weight { + // Proof Size summary in bytes: + // Measured: `292` + // Estimated: `3757` + // Minimum execution time: 40_648_000 picoseconds. + Weight::from_parts(43_146_000, 3757) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Salp Funds (r:1 w:1) + /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) + fn fund_end() -> Weight { + // Proof Size summary in bytes: + // Measured: `325` + // Estimated: `3790` + // Minimum execution time: 41_871_000 picoseconds. + Weight::from_parts(42_961_000, 3790) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Salp Funds (r:1 w:1) + /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: Salp CurrentTrieIndex (r:1 w:1) + /// Proof Skipped: Salp CurrentTrieIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AssetRegistry CurrencyMetadatas (r:2 w:1) + /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) + fn create() -> Weight { + // Proof Size summary in bytes: + // Measured: `833` + // Estimated: `6773` + // Minimum execution time: 81_834_000 picoseconds. + Weight::from_parts(84_230_000, 6773) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Salp Funds (r:1 w:1) + /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) + fn edit() -> Weight { + // Proof Size summary in bytes: + // Measured: `292` + // Estimated: `3757` + // Minimum execution time: 39_217_000 picoseconds. + Weight::from_parts(39_954_000, 3757) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Salp MultisigConfirmAccount (r:1 w:0) + /// Proof Skipped: Salp MultisigConfirmAccount (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Salp QueryIdContributionInfo (r:1 w:1) + /// Proof Skipped: Salp QueryIdContributionInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: Salp Funds (r:1 w:1) + /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: Tokens Accounts (r:4 w:4) + /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) + /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) + /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) + /// Storage: Tokens TotalIssuance (r:2 w:2) + /// Proof: Tokens TotalIssuance (max_values: None, max_size: Some(38), added: 2513, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) + /// Proof Skipped: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) + fn confirm_contribute() -> Weight { + // Proof Size summary in bytes: + // Measured: `2556` + // Estimated: `11362` + // Minimum execution time: 278_991_000 picoseconds. + Weight::from_parts(282_446_000, 11362) + .saturating_add(RocksDbWeight::get().reads(12_u64)) + .saturating_add(RocksDbWeight::get().writes(10_u64)) + } + /// Storage: Salp Funds (r:1 w:1) + /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: Salp RedeemPool (r:1 w:1) + /// Proof Skipped: Salp RedeemPool (max_values: Some(1), max_size: None, mode: Measured) + fn withdraw() -> Weight { + // Proof Size summary in bytes: + // Measured: `325` + // Estimated: `3790` + // Minimum execution time: 40_979_000 picoseconds. + Weight::from_parts(46_708_000, 3790) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Salp FailedFundsToRefund (r:1 w:1) + /// Proof Skipped: Salp FailedFundsToRefund (max_values: None, max_size: None, mode: Measured) + fn dissolve_refunded() -> Weight { + // Proof Size summary in bytes: + // Measured: `403` + // Estimated: `3868` + // Minimum execution time: 53_494_000 picoseconds. + Weight::from_parts(54_236_000, 3868) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Salp Funds (r:1 w:1) + /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: Tokens Accounts (r:3 w:3) + /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) + /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) + /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) + /// Storage: System Account (r:3 w:3) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: unknown `0x` (r:1 w:0) + /// Proof Skipped: unknown `0x` (r:1 w:0) + /// Storage: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) + /// Proof Skipped: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) + fn dissolve() -> Weight { + // Proof Size summary in bytes: + // Measured: `2063` + // Estimated: `8799` + // Minimum execution time: 253_989_000 picoseconds. + Weight::from_parts(256_988_000, 8799) + .saturating_add(RocksDbWeight::get().reads(10_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) + } + /// Storage: ParachainInfo ParachainId (r:1 w:0) + /// Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Tokens Accounts (r:4 w:4) + /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) + /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) + /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) + /// Storage: System Account (r:3 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ZenlinkProtocol PairStatuses (r:1 w:0) + /// Proof Skipped: ZenlinkProtocol PairStatuses (max_values: None, max_size: None, mode: Measured) + fn buyback() -> Weight { + // Proof Size summary in bytes: + // Measured: `2284` + // Estimated: `11362` + // Minimum execution time: 241_398_000 picoseconds. + Weight::from_parts(244_975_000, 11362) + .saturating_add(RocksDbWeight::get().reads(10_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + } + /// Storage: StableAsset Pools (r:1 w:1) + /// Proof Skipped: StableAsset Pools (max_values: None, max_size: None, mode: Measured) + /// Storage: Tokens Accounts (r:4 w:4) + /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) + /// Storage: StableAsset TokenRateCaches (r:2 w:0) + /// Proof Skipped: StableAsset TokenRateCaches (max_values: None, max_size: None, mode: Measured) + /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) + /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) + /// Storage: System Account (r:2 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn buyback_vstoken_by_stable_pool() -> Weight { + // Proof Size summary in bytes: + // Measured: `2438` + // Estimated: `11362` + // Minimum execution time: 361_674_000 picoseconds. + Weight::from_parts(370_099_000, 11362) + .saturating_add(RocksDbWeight::get().reads(10_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + } + /// Storage: Salp Funds (r:1 w:0) + /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: Tokens Accounts (r:2 w:2) + /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) + /// Storage: Salp ReserveInfos (r:1 w:1) + /// Proof Skipped: Salp ReserveInfos (max_values: None, max_size: None, mode: Measured) + /// Storage: Tokens Locks (r:2 w:2) + /// Proof: Tokens Locks (max_values: None, max_size: Some(1271), added: 3746, mode: MaxEncodedLen) + /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) + /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) + fn reserve() -> Weight { + // Proof Size summary in bytes: + // Measured: `1737` + // Estimated: `8482` + // Minimum execution time: 807_976_000 picoseconds. + Weight::from_parts(814_218_000, 0) + .saturating_add(Weight::from_parts(0, 8482)) + .saturating_add(RocksDbWeight::get().reads(7)) + .saturating_add(RocksDbWeight::get().writes(5)) + } + /// Storage: Salp Funds (r:1 w:0) + /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: Tokens Locks (r:2 w:2) + /// Proof: Tokens Locks (max_values: None, max_size: Some(1271), added: 3746, mode: MaxEncodedLen) + /// Storage: Tokens Accounts (r:2 w:2) + /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) + /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) + /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) + /// Storage: Salp ReserveInfos (r:0 w:1) + /// Proof Skipped: Salp ReserveInfos (max_values: None, max_size: None, mode: Measured) + fn cancel_reservation() -> Weight { + // Proof Size summary in bytes: + // Measured: `1935` + // Estimated: `8482` + // Minimum execution time: 853_491_000 picoseconds. + Weight::from_parts(858_070_000, 0) + .saturating_add(Weight::from_parts(0, 8482)) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(5)) + } + /// Storage: Salp Funds (r:1 w:1) + /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: Salp ReserveInfos (r:2 w:1) + /// Proof Skipped: Salp ReserveInfos (max_values: None, max_size: None, mode: Measured) + /// Storage: Tokens Locks (r:2 w:2) + /// Proof: Tokens Locks (max_values: None, max_size: Some(1271), added: 3746, mode: MaxEncodedLen) + /// Storage: Tokens Accounts (r:4 w:4) + /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) + /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) + /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) + /// Storage: Salp RedeemPool (r:1 w:1) + /// Proof Skipped: Salp RedeemPool (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Tokens TotalIssuance (r:2 w:2) + /// Proof: Tokens TotalIssuance (max_values: None, max_size: Some(38), added: 2513, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn batch_handle_reserve() -> Weight { + // Proof Size summary in bytes: + // Measured: `2540` + // Estimated: `11362` + // Minimum execution time: 1_848_798_000 picoseconds. + Weight::from_parts(1_859_469_000, 0) + .saturating_add(Weight::from_parts(0, 11362)) + .saturating_add(RocksDbWeight::get().reads(14)) + .saturating_add(RocksDbWeight::get().writes(12)) + } +} diff --git a/pallets/flexible-fee/src/tests.rs b/pallets/flexible-fee/src/tests.rs index ce373e01e..a365b46d4 100644 --- a/pallets/flexible-fee/src/tests.rs +++ b/pallets/flexible-fee/src/tests.rs @@ -327,49 +327,6 @@ fn correct_and_deposit_fee_should_work() { }); } -#[test] -fn correct_and_deposit_fee_with_tip() { - new_test_ext().execute_with(|| { - basic_setup(); - - let corrected_fee = 5 * 10u128.pow(12); - let tip = 5 * 10u128.pow(12); - - assert_eq!(Currencies::free_balance(BNC, &ALICE), 1000 * 10u128.pow(12)); - - let already_withdrawn = Some(PaymentInfo::Native(10 * 10u128.pow(12))); - assert_ok!(FlexibleFee::correct_and_deposit_fee( - &ALICE, - &info(), - &post_info(), - corrected_fee, - tip, - already_withdrawn - )); - assert_eq!(Currencies::free_balance(BNC, &ALICE), 1005 * 10u128.pow(12)); - - let corrected_fee = 10 * 10u128.pow(12); - let tip = 10 * 10u128.pow(12); - assert_eq!(Currencies::free_balance(DOT, &ALICE), 1000 * 10u128.pow(10)); - - let already_withdrawn = Some(PaymentInfo::NonNative( - 1 * 10u128.pow(10), - DOT, - FixedU128::from_inner(200_000_000_000_000_000), - FixedU128::from(5), - )); - assert_ok!(FlexibleFee::correct_and_deposit_fee( - &ALICE, - &info(), - &post_info(), - corrected_fee, - tip, - already_withdrawn - )); - assert_eq!(Currencies::free_balance(DOT, &ALICE), 10006 * 10u128.pow(9)); - }); -} - #[test] fn get_currency_asset_id_should_work() { new_test_ext().execute_with(|| { diff --git a/pallets/salp/src/benchmarking.rs b/pallets/salp/src/benchmarking.rs index cbb3f249b..a5d987e16 100644 --- a/pallets/salp/src/benchmarking.rs +++ b/pallets/salp/src/benchmarking.rs @@ -24,12 +24,11 @@ use bifrost_stable_pool::AtLeast64BitUnsignedOf; use bifrost_xcm_interface::XcmWeightAndFee; use frame_benchmarking::v2::*; use frame_support::assert_ok; -use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; +use frame_system::RawOrigin; use sp_runtime::{ - traits::{AccountIdConversion, Bounded, StaticLookup, UniqueSaturatedFrom}, + traits::{AccountIdConversion, Bounded, UniqueSaturatedFrom}, SaturatedConversion, }; -use sp_std::prelude::*; fn assert_last_event(generic_event: ::RuntimeEvent) { let events = frame_system::Pallet::::events(); @@ -81,25 +80,7 @@ where T: Config + bifrost_stable_pool::Config + bifrost_stable_asset::Config + o )] mod benchmarks { use super::*; - - #[benchmark] - fn contribute() { - let fund_index = create_fund::(1); - let caller: T::AccountId = whitelisted_caller(); - let contribution = T::MinContribution::get(); - XcmWeightAndFee::::insert( - bifrost_xcm_interface::CurrencyIdOf::::from(KSM.into()), - XcmOperationType::UmpContributeTransact, - ( - Weight::from_parts(4000000000, 100000), - bifrost_xcm_interface::BalanceOf::::from(4000000000u32), - ), - ); - assert_ok!(Salp::::set_balance(&caller, contribution)); - - #[extrinsic_call] - _(RawOrigin::Signed(caller.clone()), fund_index, contribution); - } + use scale_info::prelude::vec; #[benchmark] fn refund() { @@ -134,41 +115,6 @@ mod benchmarks { ) } - #[benchmark] - fn unlock() { - let fund_index = create_fund::(1); - let (caller, _) = contribute_fund::(fund_index); - assert_ok!(Pallet::::confirm_contribute( - RawOrigin::Signed(caller.clone()).into(), - 0u64, - true - )); - - assert_ok!(Salp::::fund_success(RawOrigin::Root.into(), fund_index)); - - #[extrinsic_call] - _(RawOrigin::Signed(caller.clone()), caller.clone(), fund_index); - } - - #[benchmark] - fn batch_unlock() { - let fund_index = create_fund::(1); - let caller: T::AccountId = whitelisted_caller(); - for _ in 0..5 { - let (caller, _) = contribute_fund::(fund_index); - assert_ok!(Pallet::::confirm_contribute( - RawOrigin::Signed(caller.clone()).into(), - 0u64, - true - )); - } - - assert_ok!(Salp::::fund_success(RawOrigin::Root.into(), fund_index)); - - #[extrinsic_call] - _(RawOrigin::Signed(caller.clone()), fund_index); - } - #[benchmark] fn redeem() { let fund_index = create_fund::(1); @@ -195,56 +141,6 @@ mod benchmarks { assert_eq!(RedeemPool::::get(), 0_u32.saturated_into()); } - #[benchmark] - fn set_multisig_confirm_account() { - #[extrinsic_call] - _(RawOrigin::Root, whitelisted_caller()); - } - - #[benchmark] - fn fund_success() { - let fund_index = create_fund::(1); - let (caller, _) = contribute_fund::(fund_index); - assert_ok!(Pallet::::confirm_contribute( - RawOrigin::Signed(caller.clone()).into(), - 0u64, - true - )); - - #[extrinsic_call] - _(RawOrigin::Root, fund_index); - } - - #[benchmark] - fn fund_fail() { - let fund_index = create_fund::(1); - let (caller, _) = contribute_fund::(fund_index); - assert_ok!(Pallet::::confirm_contribute( - RawOrigin::Signed(caller.clone()).into(), - 0u64, - true - )); - - #[extrinsic_call] - _(RawOrigin::Root, fund_index); - } - - #[benchmark] - fn continue_fund() { - let fund_index = create_fund::(1); - let (caller, _) = contribute_fund::(fund_index); - assert_ok!(Pallet::::confirm_contribute( - RawOrigin::Signed(caller.clone()).into(), - 0u64, - true - )); - - assert_ok!(Salp::::fund_fail(RawOrigin::Root.into(), fund_index)); - assert_ok!(Salp::::withdraw(RawOrigin::Root.into(), fund_index)); - #[extrinsic_call] - _(RawOrigin::Root, fund_index, 0u32.into(), 3u32.into()); - } - #[benchmark] fn fund_retire() { let fund_index = create_fund::(1); @@ -281,12 +177,6 @@ mod benchmarks { _(RawOrigin::Root, fund_index); } - #[benchmark] - fn create() { - #[extrinsic_call] - _(RawOrigin::Root, 2001u32, BalanceOf::::max_value(), 0u32.into(), 3u32.into()); - } - #[benchmark] fn edit() { create_fund::(2001u32); @@ -302,15 +192,6 @@ mod benchmarks { ); } - #[benchmark] - fn confirm_contribute() { - let fund_index = create_fund::(1); - let (caller, _) = contribute_fund::(fund_index); - - #[extrinsic_call] - _(RawOrigin::Signed(caller), 0, true) - } - #[benchmark] fn withdraw() { let fund_index = create_fund::(1); @@ -361,49 +242,6 @@ mod benchmarks { _(RawOrigin::Root, fund_index) } - #[benchmark] - fn buyback() { - let caller: T::AccountId = whitelisted_caller(); - let relay_currency_id = ::RelayChainToken::get(); - let relay_vstoken_id = - ::CurrencyIdConversion::convert_to_vstoken(relay_currency_id).unwrap(); - - let caller_lookup: ::Source = - T::Lookup::unlookup(caller.clone()); - assert_ok!(zenlink_protocol::Pallet::::create_pair( - RawOrigin::Root.into(), - zenlink_protocol::AssetId { chain_id: 2001, asset_type: 2, asset_index: 516 }, - zenlink_protocol::AssetId { chain_id: 2001, asset_type: 2, asset_index: 1028 }, - caller_lookup - )); - - let buybck_caller = T::BuybackPalletId::get().into_account_truncating(); - assert_ok!(::MultiCurrency::deposit( - relay_currency_id, - &buybck_caller, - BalanceOf::::unique_saturated_from(1_000_000_000_000_000u128) - )); - assert_ok!(::MultiCurrency::deposit( - relay_vstoken_id, - &buybck_caller, - BalanceOf::::unique_saturated_from(1_000_000_000_000_000u128) - )); - - assert_ok!(zenlink_protocol::Pallet::::add_liquidity( - RawOrigin::Signed(buybck_caller).into(), - zenlink_protocol::AssetId { chain_id: 2001, asset_type: 2, asset_index: 516 }, - zenlink_protocol::AssetId { chain_id: 2001, asset_type: 2, asset_index: 1028 }, - 1_000_000_000_000u128, - 100_000_000_000_000u128, - 0u128, - 0u128, - BlockNumberFor::::from(10u32), - )); - - #[extrinsic_call] - _(RawOrigin::Signed(caller), BalanceOf::::unique_saturated_from(1000u128)) - } - #[benchmark] fn buyback_vstoken_by_stable_pool() { let caller: T::AccountId = whitelisted_caller(); @@ -475,84 +313,6 @@ mod benchmarks { _(RawOrigin::Signed(caller), 0, KSM, 1_000_000_000u32.into()) } - #[benchmark] - fn reserve() { - let fund_index = create_fund::(1); - let (caller, contribution) = contribute_fund::(fund_index); - assert_ok!(Pallet::::confirm_contribute( - RawOrigin::Signed(caller.clone()).into(), - 0u64, - true - )); - - assert_ok!(Salp::::fund_success(RawOrigin::Root.into(), fund_index)); - assert_ok!(Salp::::unlock( - RawOrigin::Signed(caller.clone()).into(), - caller.clone(), - fund_index - )); - - #[extrinsic_call] - _(RawOrigin::Signed(caller.clone()), fund_index, contribution, false); - } - - #[benchmark] - fn cancel_reservation() { - let fund_index = create_fund::(1); - let (caller, contribution) = contribute_fund::(fund_index); - assert_ok!(Pallet::::confirm_contribute( - RawOrigin::Signed(caller.clone()).into(), - 0u64, - true - )); - - assert_ok!(Salp::::fund_success(RawOrigin::Root.into(), fund_index)); - assert_ok!(Salp::::unlock( - RawOrigin::Signed(caller.clone()).into(), - caller.clone(), - fund_index - )); - assert_ok!(Salp::::reserve( - RawOrigin::Signed(caller.clone()).into(), - fund_index, - contribution, - false - )); - - #[extrinsic_call] - _(RawOrigin::Signed(caller.clone()), fund_index); - } - - #[benchmark] - fn batch_handle_reserve() { - let fund_index = create_fund::(1); - let (caller, contribution) = contribute_fund::(fund_index); - assert_ok!(Pallet::::confirm_contribute( - RawOrigin::Signed(caller.clone()).into(), - 0u64, - true - )); - - assert_ok!(Salp::::fund_success(RawOrigin::Root.into(), fund_index)); - assert_ok!(Salp::::unlock( - RawOrigin::Signed(caller.clone()).into(), - caller.clone(), - fund_index - )); - assert_ok!(Salp::::reserve( - RawOrigin::Signed(caller.clone()).into(), - fund_index, - contribution, - false - )); - assert_ok!(Salp::::fund_retire(RawOrigin::Root.into(), fund_index)); - assert_ok!(Salp::::withdraw(RawOrigin::Root.into(), fund_index)); - assert_eq!(RedeemPool::::get(), T::MinContribution::get()); - - #[extrinsic_call] - _(RawOrigin::Signed(caller.clone()), fund_index); - } - // `cargo test -p pallet-example-basic --all-features`, you will see one line per case: impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/pallets/salp/src/lib.rs b/pallets/salp/src/lib.rs index b2fae3ff3..a1a09090d 100644 --- a/pallets/salp/src/lib.rs +++ b/pallets/salp/src/lib.rs @@ -30,19 +30,17 @@ pub use weights::WeightInfo; // Re-export pallet items so that they can be accessed from the crate namespace. use bifrost_primitives::{ - ContributionStatus, CurrencyIdConversion, CurrencyIdRegister, TrieIndex, TryConvertFrom, - VtokenMintingInterface, + ContributionStatus, CurrencyIdConversion, CurrencyIdRegister, TrieIndex, VtokenMintingInterface, }; use bifrost_stable_pool::{traits::StablePoolHandler, StableAssetPoolId}; use bifrost_xcm_interface::ChainId; use cumulus_primitives_core::{QueryId, Response}; -use frame_support::{pallet_prelude::*, sp_runtime::SaturatedConversion, traits::LockIdentifier}; +use frame_support::{pallet_prelude::*, sp_runtime::SaturatedConversion}; use orml_traits::MultiCurrency; pub use pallet::*; use pallet_xcm::ensure_response; use scale_info::TypeInfo; use sp_runtime::traits::One; -use zenlink_protocol::{AssetId, ExportZenlink}; pub type AccountIdOf = ::AccountId; @@ -97,9 +95,7 @@ pub struct ReserveInfo { #[frame_support::pallet] pub mod pallet { // Import various types used to declare pallet in scope. - use bifrost_primitives::{ - BancorHandler, CurrencyId, CurrencyId::VSBond, LeasePeriod, MessageId, Nonce, ParaId, - }; + use bifrost_primitives::{CurrencyId, LeasePeriod, MessageId, Nonce, ParaId}; use bifrost_xcm_interface::traits::XcmHelper; use frame_support::{ pallet_prelude::{storage::child, *}, @@ -166,8 +162,6 @@ pub mod pallet { + MultiReservableCurrency, CurrencyId = CurrencyId> + MultiLockableCurrency>; - type BancorPool: BancorHandler>; - type EnsureConfirmAsGovernance: EnsureOrigin<::RuntimeOrigin>; type WeightInfo: WeightInfo; @@ -181,23 +175,13 @@ pub mod pallet { #[pallet::constant] type BuybackPalletId: Get; - type DexOperator: ExportZenlink; - type CurrencyIdConversion: CurrencyIdConversion; type CurrencyIdRegister: CurrencyIdRegister; - type ParachainId: Get; - type StablePool: StablePoolHandler, AccountId = Self::AccountId>; type VtokenMinting: VtokenMintingInterface>; - - #[pallet::constant] - type LockId: Get; - - #[pallet::constant] - type BatchLimit: Get; } #[pallet::pallet] @@ -387,115 +371,6 @@ pub mod pallet { #[pallet::call] impl Pallet { - #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::set_multisig_confirm_account())] - pub fn set_multisig_confirm_account( - origin: OriginFor, - account: AccountIdOf, - ) -> DispatchResult { - T::EnsureConfirmAsGovernance::ensure_origin(origin)?; - - Self::set_multisig_account(account); - - Ok(()) - } - - #[pallet::call_index(1)] - #[pallet::weight(T::WeightInfo::fund_success())] - pub fn fund_success( - origin: OriginFor, - #[pallet::compact] index: ParaId, - ) -> DispatchResult { - T::EnsureConfirmAsGovernance::ensure_origin(origin)?; - - let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; - ensure!(fund.status == FundStatus::Ongoing, Error::::InvalidFundStatus); - - let fund_new = FundInfo { status: FundStatus::Success, ..fund }; - Funds::::insert(index, Some(fund_new)); - Self::deposit_event(Event::::Success(index)); - - Ok(()) - } - - #[pallet::call_index(2)] - #[pallet::weight(T::WeightInfo::fund_fail())] - pub fn fund_fail(origin: OriginFor, #[pallet::compact] index: ParaId) -> DispatchResult { - T::EnsureConfirmAsGovernance::ensure_origin(origin)?; - - // crownload is failed, so enable the withdrawal function of vsToken/vsBond - let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; - ensure!(fund.status == FundStatus::Ongoing, Error::::InvalidFundStatus); - - let fund_new = FundInfo { status: FundStatus::Failed, ..fund }; - Funds::::insert(index, Some(fund_new)); - Self::deposit_event(Event::::Failed(index)); - - Ok(()) - } - - #[pallet::call_index(3)] - #[pallet::weight(T::WeightInfo::continue_fund())] - pub fn continue_fund( - origin: OriginFor, - #[pallet::compact] index: ParaId, - #[pallet::compact] first_slot: LeasePeriod, - #[pallet::compact] last_slot: LeasePeriod, - ) -> DispatchResult { - T::EnsureConfirmAsGovernance::ensure_origin(origin)?; - - // crownload is failed, so enable the withdrawal function of vsToken/vsBond - let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; - ensure!(fund.status == FundStatus::RefundWithdrew, Error::::InvalidFundStatus); - ensure!( - fund.first_slot != first_slot || fund.last_slot != last_slot, - Error::::InvalidFundSameSlot - ); - - let fund_old = FundInfo { status: FundStatus::FailedToContinue, ..fund }; - FailedFundsToRefund::::insert( - (index, fund.first_slot, fund.last_slot), - Some(fund_old.clone()), - ); - let fund_new = FundInfo { status: FundStatus::Ongoing, first_slot, last_slot, ..fund }; - Funds::::insert(index, Some(fund_new)); - - match T::RelayChainToken::get() { - CurrencyId::Token(token_symbol) => - if !T::CurrencyIdRegister::check_vsbond_registered( - token_symbol, - index, - first_slot, - last_slot, - ) { - T::CurrencyIdRegister::register_vsbond_metadata( - token_symbol, - index, - first_slot, - last_slot, - )?; - }, - CurrencyId::Token2(token_id) => { - if !T::CurrencyIdRegister::check_vsbond2_registered( - token_id, index, first_slot, last_slot, - ) { - T::CurrencyIdRegister::register_vsbond2_metadata( - token_id, index, first_slot, last_slot, - )?; - } - }, - _ => (), - } - - Self::deposit_event(Event::::Continued( - index, - fund_old.first_slot, - fund_old.last_slot, - )); - - Ok(()) - } - #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::fund_retire())] pub fn fund_retire( @@ -533,71 +408,6 @@ pub mod pallet { Ok(()) } - /// Create a new crowdloaning campaign for a parachain slot deposit for the current auction. - #[pallet::call_index(6)] - #[pallet::weight(T::WeightInfo::create())] - pub fn create( - origin: OriginFor, - #[pallet::compact] index: ParaId, - #[pallet::compact] cap: BalanceOf, - #[pallet::compact] first_slot: LeasePeriod, - #[pallet::compact] last_slot: LeasePeriod, - ) -> DispatchResult { - T::EnsureConfirmAsGovernance::ensure_origin(origin)?; - - ensure!(!Funds::::contains_key(index), Error::::FundAlreadyCreated); - - ensure!(first_slot <= last_slot, Error::::LastSlotBeforeFirstSlot); - - let last_slot_limit = first_slot - .checked_add(((T::SlotLength::get() as u32) - 1).into()) - .ok_or(Error::::FirstSlotTooFarInFuture)?; - ensure!(last_slot <= last_slot_limit, Error::::LastSlotTooFarInFuture); - - Funds::::insert( - index, - Some(FundInfo { - raised: Zero::zero(), - cap, - first_slot, - last_slot, - trie_index: Self::next_trie_index()?, - status: FundStatus::Ongoing, - }), - ); - - match T::RelayChainToken::get() { - CurrencyId::Token(token_symbol) => - if !T::CurrencyIdRegister::check_vsbond_registered( - token_symbol, - index, - first_slot, - last_slot, - ) { - T::CurrencyIdRegister::register_vsbond_metadata( - token_symbol, - index, - first_slot, - last_slot, - )?; - }, - CurrencyId::Token2(token_id) => { - if !T::CurrencyIdRegister::check_vsbond2_registered( - token_id, index, first_slot, last_slot, - ) { - T::CurrencyIdRegister::register_vsbond2_metadata( - token_id, index, first_slot, last_slot, - )?; - } - }, - _ => (), - } - - Self::deposit_event(Event::::Created(index)); - - Ok(()) - } - /// Edit the configuration for an in-progress crowdloan. /// /// Can only be called by Root origin. @@ -635,361 +445,60 @@ pub mod pallet { Ok(()) } - /// Contribute to a crowd sale. This will transfer some balance over to fund a parachain - /// slot. It will be withdrawable in two instances: the parachain becomes retired; or the - /// slot is unable to be purchased and the timeout expires. - #[pallet::call_index(8)] - #[pallet::weight(T::WeightInfo::contribute())] - pub fn contribute( - origin: OriginFor, - #[pallet::compact] index: ParaId, - #[pallet::compact] value: BalanceOf, - ) -> DispatchResult { - let who = ensure_signed(origin.clone())?; + /// Withdraw full balance of the parachain. + /// - `index`: The parachain to whose crowdloan the contribution was made. + #[pallet::call_index(14)] + #[pallet::weight(T::WeightInfo::withdraw())] + pub fn withdraw(origin: OriginFor, #[pallet::compact] index: ParaId) -> DispatchResult { + T::EnsureConfirmAsGovernance::ensure_origin(origin.clone())?; let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; - ensure!(fund.status == FundStatus::Ongoing, Error::::InvalidFundStatus); - - ensure!(value >= T::MinContribution::get(), Error::::ContributionTooSmall); - - let raised = fund.raised.checked_add(&value).ok_or(Error::::Overflow)?; - ensure!(raised <= fund.cap, Error::::CapExceeded); - - let (contributed, status) = Self::contribution(fund.trie_index, &who); - ensure!( - status == ContributionStatus::Idle || - status == ContributionStatus::Refunded || - status == ContributionStatus::Redeemed || - status == ContributionStatus::Unlocked, - Error::::InvalidContributionStatus - ); - - ensure!( - T::MultiCurrency::can_reserve(T::RelayChainToken::get(), &who, value), - Error::::NotEnoughBalanceToContribute - ); + let can = fund.status == FundStatus::Failed || fund.status == FundStatus::Retired; + ensure!(can, Error::::InvalidFundStatus); - T::MultiCurrency::reserve(T::RelayChainToken::get(), &who, value)?; + let amount_withdrew = fund.raised; + let total = RedeemPool::::get() + .checked_add(&amount_withdrew) + .ok_or(Error::::Overflow)?; + RedeemPool::::set(total); - Self::put_contribution( - fund.trie_index, - &who, - contributed, - ContributionStatus::Contributing(value), - ); + if fund.status == FundStatus::Retired { + let fund_new = FundInfo { status: FundStatus::RedeemWithdrew, ..fund }; + Funds::::insert(index, Some(fund_new)); + } else if fund.status == FundStatus::Failed { + let fund_new = FundInfo { status: FundStatus::RefundWithdrew, ..fund }; + Funds::::insert(index, Some(fund_new)); + } - let message_id = T::XcmInterface::contribute(who.clone(), index, value)?; + Self::deposit_event(Event::Withdrew(index, amount_withdrew)); - Self::deposit_event(Event::Contributing(who, index, value, message_id)); Ok(()) } - /// Confirm contribute - #[pallet::call_index(9)] - #[pallet::weight(T::WeightInfo::confirm_contribute())] - pub fn confirm_contribute( + #[pallet::call_index(15)] + #[pallet::weight(T::WeightInfo::refund())] + pub fn refund( origin: OriginFor, - query_id: QueryId, - is_success: bool, + #[pallet::compact] index: ParaId, + #[pallet::compact] first_slot: LeasePeriod, + #[pallet::compact] last_slot: LeasePeriod, + #[pallet::compact] value: BalanceOf, ) -> DispatchResult { - let confirmor = ensure_signed(origin.clone())?; - if Some(confirmor) != MultisigConfirmAccount::::get() { - return Err(DispatchError::BadOrigin.into()); - } + let who = ensure_signed(origin.clone())?; - let (index, contributer, _amount) = QueryIdContributionInfo::::get(query_id) - .ok_or(Error::::NotFindContributionValue)?; - - let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; - let can_confirm = fund.status == FundStatus::Ongoing || - fund.status == FundStatus::Failed || - fund.status == FundStatus::Success; - ensure!(can_confirm, Error::::InvalidFundStatus); - - let (contributed, status) = Self::contribution(fund.trie_index, &contributer); - ensure!(status.is_contributing(), Error::::InvalidContributionStatus); - let contributing = status.contributing(); - - let vs_token = T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) - .map_err(|_| Error::::NotSupportTokenType)?; - let vs_bond = T::CurrencyIdConversion::convert_to_vsbond( - T::RelayChainToken::get(), - index, - fund.first_slot, - fund.last_slot, - ) - .map_err(|_| Error::::NotSupportTokenType)?; - - if is_success { - // Issue reserved vsToken/vsBond to contributor - T::MultiCurrency::deposit(vs_token, &contributer, contributing)?; - T::MultiCurrency::deposit(vs_bond, &contributer, contributing)?; - - // Update the raised of fund - let fund_new = - FundInfo { raised: fund.raised.saturating_add(contributing), ..fund }; - Funds::::insert(index, Some(fund_new)); - - T::MultiCurrency::unreserve(T::RelayChainToken::get(), &contributer, contributing); - T::MultiCurrency::transfer( - T::RelayChainToken::get(), - &contributer, - &Self::fund_account_id(index), - contributing, - )?; - - // Update the contribution of contributer - let contributed_new = contributed.saturating_add(contributing); - Self::put_contribution( - fund.trie_index, - &contributer, - contributed_new, - ContributionStatus::Idle, - ); - Self::deposit_event(Event::Contributed(contributer, index, contributing)); - } else { - // Update the contribution of contributer - Self::put_contribution( - fund.trie_index, - &contributer, - contributed, - ContributionStatus::Idle, - ); - T::MultiCurrency::unreserve(T::RelayChainToken::get(), &contributer, contributing); - Self::deposit_event(Event::ContributeFailed(contributer, index, contributing)); - } - - QueryIdContributionInfo::::remove(query_id); - - Ok(()) - } - - /// Unlock the reserved vsToken/vsBond after fund success - #[pallet::call_index(10)] - #[pallet::weight(T::WeightInfo::unlock())] - pub fn unlock( - origin: OriginFor, - who: AccountIdOf, - #[pallet::compact] index: ParaId, - ) -> DispatchResult { - ensure_signed(origin)?; - let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; - - let (contributed, _) = Self::contribution(fund.trie_index, &who); - - let vs_token = T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) - .map_err(|_| Error::::NotSupportTokenType)?; - let vs_bond = T::CurrencyIdConversion::convert_to_vsbond( - T::RelayChainToken::get(), - index, - fund.first_slot, - fund.last_slot, - ) - .map_err(|_| Error::::NotSupportTokenType)?; - - T::MultiCurrency::unreserve(vs_token, &who, contributed); - T::MultiCurrency::unreserve(vs_bond, &who, contributed); - - Self::deposit_event(Event::::Unlocked(who, index, contributed)); - - Ok(()) - } - - #[pallet::call_index(11)] - #[pallet::weight(T::WeightInfo::unlock())] - pub fn unlock_by_vsbond( - origin: OriginFor, - who: AccountIdOf, - vsbond: CurrencyId, - ) -> DispatchResult { - ensure_signed(origin)?; - - let index = match vsbond { - CurrencyId::VSBond(token_symbol, paraid, first_slot, last_slot) => { - if !T::CurrencyIdRegister::check_vsbond_registered( - token_symbol, - paraid, - first_slot, - last_slot, - ) { - return Err(Error::::NotSupportTokenType.into()); - } - paraid - }, - CurrencyId::VSBond2(token_id, paraid, first_slot, last_slot) => { - if !T::CurrencyIdRegister::check_vsbond2_registered( - token_id, paraid, first_slot, last_slot, - ) { - return Err(Error::::NotSupportTokenType.into()); - } - paraid - }, - _ => return Err(Error::::NotSupportTokenType.into()), - }; - - let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; - - let (contributed, _) = Self::contribution(fund.trie_index, &who); - - let vs_token = T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) - .map_err(|_| Error::::NotSupportTokenType)?; - let vs_bond = T::CurrencyIdConversion::convert_to_vsbond( - T::RelayChainToken::get(), - index, - fund.first_slot, - fund.last_slot, - ) - .map_err(|_| Error::::NotSupportTokenType)?; - - T::MultiCurrency::unreserve(vs_token, &who, contributed); - T::MultiCurrency::unreserve(vs_bond, &who, contributed); - - Self::deposit_event(Event::::Unlocked(who, index, contributed)); - Ok(()) - } - - #[pallet::call_index(12)] - #[pallet::weight(T::WeightInfo::unlock())] - pub fn unlock_vstoken(origin: OriginFor, who: AccountIdOf) -> DispatchResult { - ensure_signed(origin)?; - - match T::RelayChainToken::get() { - CurrencyId::Token(token_symbol) => { - let vsbond_list = vec![ - VSBond(token_symbol, 2106, 19, 26), - VSBond(token_symbol, 2011, 19, 26), - VSBond(token_symbol, 2102, 18, 25), - VSBond(token_symbol, 2102, 19, 26), - VSBond(token_symbol, 2101, 18, 25), - VSBond(token_symbol, 2100, 18, 25), - VSBond(token_symbol, 2100, 17, 24), - VSBond(token_symbol, 2095, 17, 24), - VSBond(token_symbol, 2096, 17, 24), - VSBond(token_symbol, 2087, 17, 24), - VSBond(token_symbol, 2085, 15, 22), - VSBond(token_symbol, 2092, 15, 22), - VSBond(token_symbol, 2088, 15, 22), - VSBond(token_symbol, 2090, 15, 22), - ]; - - let vs_token = - T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) - .map_err(|_| Error::::NotSupportTokenType)?; - let reserved_vstoken = T::MultiCurrency::reserved_balance(vs_token, &who); - T::MultiCurrency::unreserve(vs_token, &who, reserved_vstoken); - vsbond_list.into_iter().for_each(|vs_bond| { - let reserved_vsbond = T::MultiCurrency::reserved_balance(vs_bond, &who); - T::MultiCurrency::unreserve(vs_bond, &who, reserved_vsbond); - }); - }, - _ => return Err(DispatchError::BadOrigin.into()), - } - - Self::deposit_event(Event::::VstokenUnlocked(who)); - Ok(()) - } - - /// Unlock the reserved vsToken/vsBond after fund success - #[pallet::call_index(13)] - #[pallet::weight(T::WeightInfo::batch_unlock())] - pub fn batch_unlock( - origin: OriginFor, - #[pallet::compact] index: ParaId, - ) -> DispatchResult { - ensure_signed(origin)?; - - let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; - - let mut unlock_count = 0u32; - let contributions = Self::contribution_iterator(fund.trie_index); - // Assume everyone will be refunded. - let mut all_unlocked = true; - - for (who, (contributed, status)) in contributions { - if unlock_count >= T::RemoveKeysLimit::get() { - // Not everyone was able to be refunded this time around. - all_unlocked = false; - break; - } - if status != ContributionStatus::Unlocked { - let vs_token = - T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) - .map_err(|_| Error::::NotSupportTokenType)?; - let vs_bond = T::CurrencyIdConversion::convert_to_vsbond( - T::RelayChainToken::get(), - index, - fund.first_slot, - fund.last_slot, - ) - .map_err(|_| Error::::NotSupportTokenType)?; - T::MultiCurrency::unreserve(vs_token, &who, contributed); - T::MultiCurrency::unreserve(vs_bond, &who, contributed); - - unlock_count += 1; - } - } - - if all_unlocked { - Self::deposit_event(Event::::AllUnlocked(index)); - } - - Ok(()) - } - - /// Withdraw full balance of the parachain. - /// - `index`: The parachain to whose crowdloan the contribution was made. - #[pallet::call_index(14)] - #[pallet::weight(T::WeightInfo::withdraw())] - pub fn withdraw(origin: OriginFor, #[pallet::compact] index: ParaId) -> DispatchResult { - T::EnsureConfirmAsGovernance::ensure_origin(origin.clone())?; - - let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; - let can = fund.status == FundStatus::Failed || fund.status == FundStatus::Retired; - ensure!(can, Error::::InvalidFundStatus); - - let amount_withdrew = fund.raised; - let total = RedeemPool::::get() - .checked_add(&amount_withdrew) - .ok_or(Error::::Overflow)?; - RedeemPool::::set(total); - - if fund.status == FundStatus::Retired { - let fund_new = FundInfo { status: FundStatus::RedeemWithdrew, ..fund }; - Funds::::insert(index, Some(fund_new)); - } else if fund.status == FundStatus::Failed { - let fund_new = FundInfo { status: FundStatus::RefundWithdrew, ..fund }; - Funds::::insert(index, Some(fund_new)); - } - - Self::deposit_event(Event::Withdrew(index, amount_withdrew)); - - Ok(()) - } - - #[pallet::call_index(15)] - #[pallet::weight(T::WeightInfo::refund())] - pub fn refund( - origin: OriginFor, - #[pallet::compact] index: ParaId, - #[pallet::compact] first_slot: LeasePeriod, - #[pallet::compact] last_slot: LeasePeriod, - #[pallet::compact] value: BalanceOf, - ) -> DispatchResult { - let who = ensure_signed(origin.clone())?; - - let mut fund = Self::find_fund(index, first_slot, last_slot) - .map_err(|_| Error::::InvalidFundNotExist)?; - ensure!( - fund.status == FundStatus::FailedToContinue || - fund.status == FundStatus::RefundWithdrew, - Error::::InvalidRefund - ); - ensure!( - fund.first_slot == first_slot && fund.last_slot == last_slot, - Error::::InvalidRefund - ); - ensure!(fund.raised >= value, Error::::NotEnoughBalanceInFund); - ensure!(RedeemPool::::get() >= value, Error::::NotEnoughBalanceInRefundPool); + let mut fund = Self::find_fund(index, first_slot, last_slot) + .map_err(|_| Error::::InvalidFundNotExist)?; + ensure!( + fund.status == FundStatus::FailedToContinue || + fund.status == FundStatus::RefundWithdrew, + Error::::InvalidRefund + ); + ensure!( + fund.first_slot == first_slot && fund.last_slot == last_slot, + Error::::InvalidRefund + ); + ensure!(fund.raised >= value, Error::::NotEnoughBalanceInFund); + ensure!(RedeemPool::::get() >= value, Error::::NotEnoughBalanceInRefundPool); let vs_token = T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) .map_err(|_| Error::::NotSupportTokenType)?; @@ -1165,38 +674,7 @@ pub mod pallet { Ok(()) } - #[pallet::call_index(19)] - #[pallet::weight(T::WeightInfo::buyback())] - pub fn buyback( - origin: OriginFor, - #[pallet::compact] value: BalanceOf, - ) -> DispatchResult { - let _who = ensure_signed(origin.clone())?; - - let relay_currency_id = T::RelayChainToken::get(); - let relay_vstoken_id = T::CurrencyIdConversion::convert_to_vstoken(relay_currency_id) - .map_err(|_| Error::::NotSupportTokenType)?; - let relay_asset_id: AssetId = - AssetId::try_convert_from(relay_currency_id, T::ParachainId::get().into()) - .map_err(|_| DispatchError::Other("Conversion Error."))?; - let relay_vstoken_asset_id: AssetId = - AssetId::try_convert_from(relay_vstoken_id, T::ParachainId::get().into()) - .map_err(|_| DispatchError::Other("Conversion Error."))?; - let path = vec![relay_asset_id, relay_vstoken_asset_id]; - - T::DexOperator::inner_swap_exact_assets_for_assets( - &T::BuybackPalletId::get().into_account_truncating(), - value.saturated_into(), - Percent::from_percent(50).saturating_reciprocal_mul(value).saturated_into(), - &path, - &T::TreasuryAccount::get(), - )?; - - Self::deposit_event(Event::::Buyback(value)); - - Ok(()) - } - + // unused but xcm-interface #[pallet::call_index(20)] #[pallet::weight(T::WeightInfo::confirm_contribute())] pub fn confirm_contribution( @@ -1326,53 +804,252 @@ pub mod pallet { Self::deposit_event(Event::::BuybackByStablePool { pool_id, currency_id_in, value }); Ok(()) } + } - #[pallet::call_index(22)] - #[pallet::weight(T::WeightInfo::reserve())] - pub fn reserve( - origin: OriginFor, - index: ParaId, - value: BalanceOf, - if_mint: bool, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_initialize(n: BlockNumberFor) -> Weight { + // Release x% KSM/DOT from redeem-pool to bancor-pool per cycle + if n != Zero::zero() && (n % T::ReleaseCycle::get()) == Zero::zero() { + if let Ok(rp_balance) = TryInto::::try_into(RedeemPool::::get()) { + // Calculate the release amount + let release_amount = T::ReleaseRatio::get() * rp_balance; - ensure!( - fund.status == FundStatus::Ongoing || fund.status == FundStatus::Success, - Error::::InvalidFundStatus - ); + // Must be ok + if let Err(_) = TryInto::>::try_into(release_amount) { + log::warn!("Overflow: The balance of redeem-pool exceeds u128."); + } + } + } + T::DbWeight::get().reads(1) + } + } - let vs_token = T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) - .map_err(|_| Error::::NotSupportTokenType)?; - let vs_bond = T::CurrencyIdConversion::convert_to_vsbond( - T::RelayChainToken::get(), + // These methods are no longer in use and are now only called for testing and benchmarking + // purposes. + impl Pallet { + pub(crate) fn fund_success(origin: OriginFor, index: ParaId) -> DispatchResult { + T::EnsureConfirmAsGovernance::ensure_origin(origin)?; + + let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + ensure!(fund.status == FundStatus::Ongoing, Error::::InvalidFundStatus); + + let fund_new = FundInfo { status: FundStatus::Success, ..fund }; + Funds::::insert(index, Some(fund_new)); + Self::deposit_event(Event::::Success(index)); + + Ok(()) + } + + pub(crate) fn fund_fail(origin: OriginFor, index: ParaId) -> DispatchResult { + T::EnsureConfirmAsGovernance::ensure_origin(origin)?; + + // crownload is failed, so enable the withdrawal function of vsToken/vsBond + let fund = crate::pallet::Funds::::get(index) + .ok_or(crate::pallet::Error::::InvalidParaId)?; + ensure!(fund.status == FundStatus::Ongoing, Error::::InvalidFundStatus); + + let fund_new = crate::FundInfo { status: crate::FundStatus::Failed, ..fund }; + crate::pallet::Funds::::insert(index, Some(fund_new)); + Self::deposit_event(crate::pallet::Event::::Failed(index)); + + Ok(()) + } + + pub(crate) fn continue_fund( + origin: OriginFor, + index: ParaId, + first_slot: LeasePeriod, + last_slot: LeasePeriod, + ) -> DispatchResult { + T::EnsureConfirmAsGovernance::ensure_origin(origin)?; + + // crownload is failed, so enable the withdrawal function of vsToken/vsBond + let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + ensure!(fund.status == FundStatus::RefundWithdrew, Error::::InvalidFundStatus); + ensure!( + fund.first_slot != first_slot || fund.last_slot != last_slot, + Error::::InvalidFundSameSlot + ); + + let fund_old = FundInfo { status: FundStatus::FailedToContinue, ..fund }; + FailedFundsToRefund::::insert( + (index, fund.first_slot, fund.last_slot), + Some(fund_old.clone()), + ); + let fund_new = FundInfo { status: FundStatus::Ongoing, first_slot, last_slot, ..fund }; + Funds::::insert(index, Some(fund_new)); + + match T::RelayChainToken::get() { + CurrencyId::Token(token_symbol) => + if !T::CurrencyIdRegister::check_vsbond_registered( + token_symbol, + index, + first_slot, + last_slot, + ) { + T::CurrencyIdRegister::register_vsbond_metadata( + token_symbol, + index, + first_slot, + last_slot, + )?; + }, + CurrencyId::Token2(token_id) => { + if !T::CurrencyIdRegister::check_vsbond2_registered( + token_id, index, first_slot, last_slot, + ) { + T::CurrencyIdRegister::register_vsbond2_metadata( + token_id, index, first_slot, last_slot, + )?; + } + }, + _ => (), + } + + Self::deposit_event(Event::::Continued( index, - fund.first_slot, - fund.last_slot, - ) - .map_err(|_| Error::::NotSupportTokenType)?; + fund_old.first_slot, + fund_old.last_slot, + )); + + Ok(()) + } + + /// Create a new crowdloaning campaign for a parachain slot deposit for the current auction. + pub(crate) fn create( + origin: OriginFor, + index: ParaId, + cap: BalanceOf, + first_slot: LeasePeriod, + last_slot: LeasePeriod, + ) -> DispatchResult { + T::EnsureConfirmAsGovernance::ensure_origin(origin)?; - T::MultiCurrency::ensure_can_withdraw(vs_token, &who, value)?; - T::MultiCurrency::ensure_can_withdraw(vs_bond, &who, value)?; - let mut info = ReserveInfos::::get(index, &who); - info.value = info.value.checked_add(&value).ok_or(Error::::Overflow)?; - info.if_mint = if_mint; - T::MultiCurrency::extend_lock(T::LockId::get(), vs_token, &who, info.value)?; - T::MultiCurrency::extend_lock(T::LockId::get(), vs_bond, &who, info.value)?; + ensure!(!Funds::::contains_key(index), Error::::FundAlreadyCreated); - ReserveInfos::::insert(index, &who, info); + ensure!(first_slot <= last_slot, Error::::LastSlotBeforeFirstSlot); + + let last_slot_limit = first_slot + .checked_add(((T::SlotLength::get() as u32) - 1).into()) + .ok_or(Error::::FirstSlotTooFarInFuture)?; + ensure!(last_slot <= last_slot_limit, Error::::LastSlotTooFarInFuture); + + Funds::::insert( + index, + Some(FundInfo { + raised: Zero::zero(), + cap, + first_slot, + last_slot, + trie_index: Self::next_trie_index()?, + status: FundStatus::Ongoing, + }), + ); + + match T::RelayChainToken::get() { + CurrencyId::Token(token_symbol) => + if !T::CurrencyIdRegister::check_vsbond_registered( + token_symbol, + index, + first_slot, + last_slot, + ) { + T::CurrencyIdRegister::register_vsbond_metadata( + token_symbol, + index, + first_slot, + last_slot, + )?; + }, + CurrencyId::Token2(token_id) => { + if !T::CurrencyIdRegister::check_vsbond2_registered( + token_id, index, first_slot, last_slot, + ) { + T::CurrencyIdRegister::register_vsbond2_metadata( + token_id, index, first_slot, last_slot, + )?; + } + }, + _ => (), + } + + Self::deposit_event(Event::::Created(index)); - Self::deposit_event(Event::::Reserved { who, para_id: index, value, if_mint }); Ok(()) } - #[pallet::call_index(23)] - #[pallet::weight(T::WeightInfo::batch_handle_reserve())] - pub fn batch_handle_reserve(origin: OriginFor, index: ParaId) -> DispatchResult { - let _who = ensure_signed(origin.clone())?; + /// Contribute to a crowd sale. This will transfer some balance over to fund a parachain + /// slot. It will be withdrawable in two instances: the parachain becomes retired; or the + /// slot is unable to be purchased and the timeout expires. + pub(crate) fn contribute( + origin: OriginFor, + index: ParaId, + value: BalanceOf, + ) -> DispatchResult { + let who = ensure_signed(origin.clone())?; + + let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + ensure!(fund.status == FundStatus::Ongoing, Error::::InvalidFundStatus); + + ensure!(value >= T::MinContribution::get(), Error::::ContributionTooSmall); + + let raised = fund.raised.checked_add(&value).ok_or(Error::::Overflow)?; + ensure!(raised <= fund.cap, Error::::CapExceeded); + + let (contributed, status) = Self::contribution(fund.trie_index, &who); + ensure!( + status == ContributionStatus::Idle || + status == ContributionStatus::Refunded || + status == ContributionStatus::Redeemed || + status == ContributionStatus::Unlocked, + Error::::InvalidContributionStatus + ); + + ensure!( + T::MultiCurrency::can_reserve(T::RelayChainToken::get(), &who, value), + Error::::NotEnoughBalanceToContribute + ); + + T::MultiCurrency::reserve(T::RelayChainToken::get(), &who, value)?; + + Self::put_contribution( + fund.trie_index, + &who, + contributed, + ContributionStatus::Contributing(value), + ); + + let message_id = T::XcmInterface::contribute(who.clone(), index, value)?; + + Self::deposit_event(Event::Contributing(who, index, value, message_id)); + Ok(()) + } + + /// Confirm contribute + pub(crate) fn confirm_contribute( + origin: OriginFor, + query_id: QueryId, + is_success: bool, + ) -> DispatchResult { + let confirmor = ensure_signed(origin.clone())?; + if Some(confirmor) != MultisigConfirmAccount::::get() { + return Err(DispatchError::BadOrigin.into()); + } + + let (index, contributer, _amount) = QueryIdContributionInfo::::get(query_id) + .ok_or(Error::::NotFindContributionValue)?; + + let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + let can_confirm = fund.status == FundStatus::Ongoing || + fund.status == FundStatus::Failed || + fund.status == FundStatus::Success; + ensure!(can_confirm, Error::::InvalidFundStatus); + + let (contributed, status) = Self::contribution(fund.trie_index, &contributer); + ensure!(status.is_contributing(), Error::::InvalidContributionStatus); + let contributing = status.contributing(); - let mut fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; let vs_token = T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) .map_err(|_| Error::::NotSupportTokenType)?; let vs_bond = T::CurrencyIdConversion::convert_to_vsbond( @@ -1383,90 +1060,61 @@ pub mod pallet { ) .map_err(|_| Error::::NotSupportTokenType)?; - match fund.status { - FundStatus::RedeemWithdrew => { - ReserveInfos::::iter_prefix(index) - .take(T::BatchLimit::get() as usize) - .try_for_each(|(contributer, info)| -> DispatchResult { - T::MultiCurrency::remove_lock( - T::LockId::get(), - vs_token, - &contributer, - )?; - T::MultiCurrency::remove_lock(T::LockId::get(), vs_bond, &contributer)?; - Self::redeem_for_reserve( - contributer.clone(), - index, - info.value, - &mut fund, - vs_token, - vs_bond, - )?; - ReserveInfos::::remove(index, &contributer); - if info.if_mint { - T::VtokenMinting::mint( - contributer, - T::RelayChainToken::get(), - info.value, - BoundedVec::default(), - None, - ) - .map_err(|_| Error::::NotSupportTokenType)?; - } - Ok(()) - })?; - }, - FundStatus::RefundWithdrew => { - ReserveInfos::::iter_prefix(index) - .take(T::BatchLimit::get() as usize) - .try_for_each(|(contributer, info)| -> DispatchResult { - T::MultiCurrency::remove_lock( - T::LockId::get(), - vs_token, - &contributer, - )?; - T::MultiCurrency::remove_lock(T::LockId::get(), vs_bond, &contributer)?; - Self::refund_for_reserve( - contributer.clone(), - index, - fund.first_slot, - fund.last_slot, - info.value, - vs_token, - vs_bond, - )?; - ReserveInfos::::remove(index, &contributer); - if info.if_mint { - T::VtokenMinting::mint( - contributer, - T::RelayChainToken::get(), - info.value, - BoundedVec::default(), - None, - ) - .map_err(|_| Error::::NotSupportTokenType)?; - } - Ok(()) - })?; - }, - _ => return Err(Error::::InvalidFundStatus.into()), - } + if is_success { + // Issue reserved vsToken/vsBond to contributor + T::MultiCurrency::deposit(vs_token, &contributer, contributing)?; + T::MultiCurrency::deposit(vs_bond, &contributer, contributing)?; + + // Update the raised of fund + let fund_new = + FundInfo { raised: fund.raised.saturating_add(contributing), ..fund }; + Funds::::insert(index, Some(fund_new)); + + T::MultiCurrency::unreserve(T::RelayChainToken::get(), &contributer, contributing); + T::MultiCurrency::transfer( + T::RelayChainToken::get(), + &contributer, + &Self::fund_account_id(index), + contributing, + )?; - if ReserveInfos::::iter_prefix(index).count() != 0 { - Self::deposit_event(Event::::ReservationHandled { para_id: index }); + // Update the contribution of contributer + let contributed_new = contributed.saturating_add(contributing); + Self::put_contribution( + fund.trie_index, + &contributer, + contributed_new, + ContributionStatus::Idle, + ); + Self::deposit_event(Event::Contributed(contributer, index, contributing)); } else { - Self::deposit_event(Event::::ReservationFullyHandled { para_id: index }); + // Update the contribution of contributer + Self::put_contribution( + fund.trie_index, + &contributer, + contributed, + ContributionStatus::Idle, + ); + T::MultiCurrency::unreserve(T::RelayChainToken::get(), &contributer, contributing); + Self::deposit_event(Event::ContributeFailed(contributer, index, contributing)); } + + QueryIdContributionInfo::::remove(query_id); + Ok(()) } - #[pallet::call_index(24)] - #[pallet::weight(T::WeightInfo::cancel_reservation())] - pub fn cancel_reservation(origin: OriginFor, index: ParaId) -> DispatchResult { - let who = ensure_signed(origin)?; - + /// Unlock the reserved vsToken/vsBond after fund success + pub(crate) fn unlock( + origin: OriginFor, + who: AccountIdOf, + index: ParaId, + ) -> DispatchResult { + ensure_signed(origin)?; let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; + let (contributed, _) = Self::contribution(fund.trie_index, &who); + let vs_token = T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) .map_err(|_| Error::::NotSupportTokenType)?; let vs_bond = T::CurrencyIdConversion::convert_to_vsbond( @@ -1476,48 +1124,17 @@ pub mod pallet { fund.last_slot, ) .map_err(|_| Error::::NotSupportTokenType)?; - T::MultiCurrency::remove_lock(T::LockId::get(), vs_token, &who)?; - T::MultiCurrency::remove_lock(T::LockId::get(), vs_bond, &who)?; - ReserveInfos::::remove(index, &who); - Self::deposit_event(Event::::ReservationCancelled { who, para_id: index }); - Ok(()) - } - } + T::MultiCurrency::unreserve(vs_token, &who, contributed); + T::MultiCurrency::unreserve(vs_bond, &who, contributed); - #[pallet::hooks] - impl Hooks> for Pallet { - fn on_initialize(n: BlockNumberFor) -> Weight { - // Release x% KSM/DOT from redeem-pool to bancor-pool per cycle - if n != Zero::zero() && (n % T::ReleaseCycle::get()) == Zero::zero() { - if let Ok(rp_balance) = TryInto::::try_into(RedeemPool::::get()) { - // Calculate the release amount - let release_amount = T::ReleaseRatio::get() * rp_balance; + Self::deposit_event(Event::::Unlocked(who, index, contributed)); - // Must be ok - if let Ok(release_amount) = TryInto::>::try_into(release_amount) { - // Increase the balance of bancor-pool by release-amount - if let Ok(()) = - T::BancorPool::add_token(T::RelayChainToken::get(), release_amount) - { - RedeemPool::::set( - RedeemPool::::get().saturating_sub(release_amount), - ); - } - } else { - log::warn!("Overflow: The balance of redeem-pool exceeds u128."); - } - } - } - T::DbWeight::get().reads(1) + Ok(()) } } impl Pallet { - /// set multisig account - pub fn set_multisig_account(account: AccountIdOf) { - MultisigConfirmAccount::::put(account); - } /// Check if the vsBond is `past` the redeemable date pub(crate) fn is_expired( block: BlockNumberFor, @@ -1529,18 +1146,6 @@ pub mod pallet { Ok(block >= block_end_redeem) } - /// Check if the vsBond is `in` the redeemable date - #[allow(dead_code)] - pub(crate) fn can_redeem( - block: BlockNumberFor, - last_slot: LeasePeriod, - ) -> Result> { - let block_begin_redeem = Self::block_end_of_lease_period_index(last_slot); - let block_end_redeem = block_begin_redeem.saturating_add(T::VSBondValidPeriod::get()); - - Ok(block >= block_begin_redeem && block < block_end_redeem) - } - pub(crate) fn block_end_of_lease_period_index(slot: LeasePeriod) -> BlockNumberFor { (BlockNumberFor::::from(slot) + One::one()).saturating_mul(T::LeasePeriod::get()) } @@ -1625,114 +1230,9 @@ pub mod pallet { who.using_encoded(|b| child::kill(&Self::id_from_index(index), b)); } - #[allow(dead_code)] pub(crate) fn set_balance(who: &AccountIdOf, value: BalanceOf) -> DispatchResult { T::MultiCurrency::deposit(T::RelayChainToken::get(), who, value) } - - pub fn redeem_for_reserve( - who: AccountIdOf, - index: ParaId, - value: BalanceOf, - fund: &mut FundInfo, LeasePeriod>, - vs_token: CurrencyId, - vs_bond: CurrencyId, - ) -> DispatchResult { - ensure!(fund.raised >= value, Error::::NotEnoughBalanceInRedeemPool); - - ensure!(RedeemPool::::get() >= value, Error::::NotEnoughBalanceInRedeemPool); - let cur_block = >::block_number(); - let expired = Self::is_expired(cur_block, fund.last_slot)?; - ensure!(!expired, Error::::VSBondExpired); - T::MultiCurrency::ensure_can_withdraw(vs_token, &who, value) - .map_err(|_e| Error::::NotEnoughFreeAssetsToRedeem)?; - T::MultiCurrency::ensure_can_withdraw(vs_bond, &who, value) - .map_err(|_e| Error::::NotEnoughFreeAssetsToRedeem)?; - - T::MultiCurrency::withdraw(vs_token, &who, value)?; - T::MultiCurrency::withdraw(vs_bond, &who, value)?; - RedeemPool::::set(RedeemPool::::get().saturating_sub(value)); - - fund.raised = fund.raised.saturating_sub(value); - Funds::::insert(index, Some(fund.clone())); - - T::MultiCurrency::transfer( - T::RelayChainToken::get(), - &Self::fund_account_id(index), - &who, - value, - )?; - Self::deposit_event(Event::Redeemed( - who, - index, - fund.first_slot, - fund.last_slot, - value, - )); - - Ok(()) - } - - pub fn refund_for_reserve( - who: AccountIdOf, - index: ParaId, - first_slot: LeasePeriod, - last_slot: LeasePeriod, - value: BalanceOf, - vs_token: CurrencyId, - vs_bond: CurrencyId, - ) -> DispatchResult { - let mut fund = Self::find_fund(index, first_slot, last_slot) - .map_err(|_| Error::::InvalidFundNotExist)?; - ensure!( - fund.status == FundStatus::FailedToContinue || - fund.status == FundStatus::RefundWithdrew, - Error::::InvalidRefund - ); - ensure!( - fund.first_slot == first_slot && fund.last_slot == last_slot, - Error::::InvalidRefund - ); - ensure!(fund.raised >= value, Error::::NotEnoughBalanceInFund); - ensure!(RedeemPool::::get() >= value, Error::::NotEnoughBalanceInRefundPool); - - T::MultiCurrency::ensure_can_withdraw(vs_token, &who, value) - .map_err(|_e| Error::::NotEnoughFreeAssetsToRedeem)?; - T::MultiCurrency::ensure_can_withdraw(vs_bond, &who, value) - .map_err(|_e| Error::::NotEnoughFreeAssetsToRedeem)?; - - T::MultiCurrency::withdraw(vs_token, &who, value)?; - T::MultiCurrency::withdraw(vs_bond, &who, value)?; - - RedeemPool::::set(RedeemPool::::get().saturating_sub(value)); - let mut fund_new = Funds::::get(index).ok_or(Error::::InvalidParaId)?; - fund_new.raised = fund_new.raised.saturating_sub(value); - Funds::::insert(index, Some(fund_new)); - if fund.status == FundStatus::FailedToContinue { - fund.raised = fund.raised.saturating_sub(value); - FailedFundsToRefund::::insert( - (index, first_slot, last_slot), - Some(fund.clone()), - ); - } - - T::MultiCurrency::transfer( - T::RelayChainToken::get(), - &Self::fund_account_id(index), - &who, - value, - )?; - - Self::deposit_event(Event::Refunded( - who, - index, - fund.first_slot, - fund.last_slot, - value, - )); - - Ok(()) - } } } diff --git a/pallets/salp/src/mock.rs b/pallets/salp/src/mock.rs index 4d1bf1435..e2138c859 100644 --- a/pallets/salp/src/mock.rs +++ b/pallets/salp/src/mock.rs @@ -20,7 +20,6 @@ #![cfg(test)] -use crate::*; use bifrost_asset_registry::AssetIdMaps; use bifrost_primitives::{ Amount, Balance, CurrencyId, CurrencyId::*, MessageId, MockXcmExecutor, ParaId, SlpOperator, @@ -31,7 +30,7 @@ use cumulus_primitives_core::ParaId as Pid; use frame_support::{ construct_runtime, derive_impl, ord_parameter_types, parameter_types, sp_runtime::{DispatchError, DispatchResult, SaturatedConversion}, - traits::{ConstU128, ConstU64, EnsureOrigin, Everything, Get, Nothing}, + traits::{ConstU128, ConstU64, EnsureOrigin, Everything, Get, LockIdentifier, Nothing}, weights::Weight, PalletId, }; @@ -446,7 +445,6 @@ parameter_types! { } impl salp::Config for Test { - type BancorPool = (); type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type RuntimeOrigin = RuntimeOrigin; @@ -465,14 +463,10 @@ impl salp::Config for Test { type XcmInterface = MockSalpXcmExecutor; type TreasuryAccount = TreasuryAccount; type BuybackPalletId = BuybackPalletId; - type DexOperator = ZenlinkProtocol; type CurrencyIdConversion = AssetIdMaps; type CurrencyIdRegister = AssetIdMaps; - type ParachainId = ParaInfo; type StablePool = StablePool; type VtokenMinting = VtokenMinting; - type LockId = SalpLockId; - type BatchLimit = BatchLimit; } parameter_types! { diff --git a/pallets/salp/src/tests.rs b/pallets/salp/src/tests.rs index 31d5870cf..40b486f12 100644 --- a/pallets/salp/src/tests.rs +++ b/pallets/salp/src/tests.rs @@ -19,142 +19,14 @@ // Ensure we're `no_std` when compiling for Wasm. use crate::{mock::*, Error, FundStatus, *}; -use bifrost_primitives::{ContributionStatus, CurrencyId, TokenSymbol, KSM, VKSM, VSKSM}; +use bifrost_primitives::{CurrencyId, TokenSymbol, TryConvertFrom, KSM, VKSM, VSKSM}; use bifrost_xcm_interface::SalpHelper; use frame_support::{assert_noop, assert_ok}; use frame_system::pallet_prelude::BlockNumberFor; -use orml_traits::{MultiCurrency, MultiReservableCurrency}; +use orml_traits::MultiCurrency; use sp_runtime::{traits::AccountIdConversion, DispatchError}; use zenlink_protocol::AssetId; -#[test] -fn create_fund_should_work() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_ok!(Funds::::get(3_000).ok_or(())); - assert_eq!(CurrentTrieIndex::::get(), 1); - }); -} - -#[test] -fn create_fund_with_wrong_origin_should_fail() { - new_test_ext().execute_with(|| { - assert_noop!( - Salp::create(RuntimeOrigin::none(), 3_000, 1_000, 1, SlotLength::get()), - DispatchError::BadOrigin, - ); - }); -} - -#[test] -fn create_fund_existed_should_fail() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - - assert_noop!( - Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get()), - Error::::FundAlreadyCreated, - ); - }); -} - -#[test] -fn create_fund_exceed_slot_limit_should_fail() { - new_test_ext().execute_with(|| { - assert_noop!( - Salp::create(Some(ALICE).into(), 3_000, 1_000, 0, SlotLength::get()), - Error::::LastSlotTooFarInFuture, - ); - }); -} - -#[test] -fn create_fund_first_slot_bigger_than_last_slot_should_fail() { - new_test_ext().execute_with(|| { - assert_noop!( - Salp::create(Some(ALICE).into(), 3_000, 1_000, SlotLength::get(), 0), - Error::::LastSlotBeforeFirstSlot, - ); - }); -} - -#[test] -fn set_fund_success_should_work() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); - - // Check status - let fund = Funds::::get(3_000).unwrap(); - assert_eq!(fund.status, FundStatus::Success); - }); -} - -#[test] -fn set_fund_success_with_wrong_origin_should_fail() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_noop!(Salp::fund_success(RuntimeOrigin::none(), 3_000), DispatchError::BadOrigin); - }) -} - -#[test] -fn set_fund_success_with_wrong_para_id_should_fail() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_noop!(Salp::fund_success(Some(ALICE).into(), 4_000), Error::::InvalidParaId); - }); -} - -#[test] -fn set_fund_success_with_wrong_fund_status_should_fail() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_ok!(Salp::fund_fail(Some(ALICE).into(), 3_000)); - assert_noop!( - Salp::fund_success(Some(ALICE).into(), 3_000), - Error::::InvalidFundStatus - ); - }); -} - -#[test] -fn set_fund_fail_should_work() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_ok!(Salp::fund_fail(Some(ALICE).into(), 3_000)); - - // Check status - let fund = Funds::::get(3_000).unwrap(); - assert_eq!(fund.status, FundStatus::Failed); - }); -} - -#[test] -fn set_fund_fail_with_wrong_origin_should_fail() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_noop!(Salp::fund_fail(RuntimeOrigin::none(), 3_000), DispatchError::BadOrigin); - }); -} - -#[test] -fn set_fund_fail_with_wrong_para_id_should_fail() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_noop!(Salp::fund_fail(Some(ALICE).into(), 4_000), Error::::InvalidParaId); - }); -} - -#[test] -fn set_fund_fail_with_wrong_fund_status_should_fail() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); - assert_noop!(Salp::fund_fail(Some(ALICE).into(), 3_000), Error::::InvalidFundStatus); - }); -} - #[test] fn set_fund_retire_should_work() { new_test_ext().execute_with(|| { @@ -246,317 +118,6 @@ fn set_fund_end_with_wrong_fund_status_should_fail() { }); } -#[test] -fn unlock_should_work() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); - Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); - assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); - assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); - assert_ok!(Salp::unlock(Some(BRUCE).into(), BRUCE, 3_000)); - - let vs_token = - ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()) - .unwrap(); - let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( - RelayCurrencyId::get(), - 3_000, - 1, - SlotLength::get(), - ) - .unwrap(); - - assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 100); - assert_eq!(Tokens::accounts(BRUCE, vs_token).frozen, 0); - assert_eq!(Tokens::accounts(BRUCE, vs_token).reserved, 0); - assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 100); - assert_eq!(Tokens::accounts(BRUCE, vs_bond).frozen, 0); - assert_eq!(Tokens::accounts(BRUCE, vs_bond).reserved, 0); - }); -} - -#[test] -fn unlock_by_vsbond_should_work() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); - Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); - assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); - assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); - - let vs_token = - ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()) - .unwrap(); - let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( - RelayCurrencyId::get(), - 3_000, - 1, - SlotLength::get(), - ) - .unwrap(); - - assert_ok!(Salp::unlock_by_vsbond(Some(BRUCE).into(), BRUCE, vs_bond)); - assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 100); - assert_eq!(Tokens::accounts(BRUCE, vs_token).frozen, 0); - assert_eq!(Tokens::accounts(BRUCE, vs_token).reserved, 0); - assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 100); - assert_eq!(Tokens::accounts(BRUCE, vs_bond).frozen, 0); - assert_eq!(Tokens::accounts(BRUCE, vs_bond).reserved, 0); - }); -} - -#[test] -fn unlock_vstoken_should_work() { - new_test_ext().execute_with(|| { - let vs_token = - ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()) - .unwrap(); - assert_ok!(::MultiCurrency::reserve(vs_token, &ALICE, 1)); - - assert_eq!(Tokens::accounts(ALICE, vs_token).free, 99999); - assert_eq!(Tokens::accounts(ALICE, vs_token).frozen, 0); - assert_eq!(Tokens::accounts(ALICE, vs_token).reserved, 1); - assert_ok!(Salp::unlock_vstoken(Some(BRUCE).into(), ALICE)); - assert_eq!(Tokens::accounts(ALICE, vs_token).free, 100000); - assert_eq!(Tokens::accounts(ALICE, vs_token).frozen, 0); - assert_eq!(Tokens::accounts(ALICE, vs_token).reserved, 0); - - assert_ok!(Salp::create(Some(ALICE).into(), 2_100, 1_000, 18, 25)); - assert_ok!(Salp::contribute(Some(BRUCE).into(), 2_100, 100)); - Salp::bind_query_id_and_contribution(0, 2_100, BRUCE, 100); - assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); - assert_ok!(Salp::fund_success(Some(ALICE).into(), 2_100)); - let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( - RelayCurrencyId::get(), - 2_100, - 18, - 25, - ) - .unwrap(); - assert_ok!(::MultiCurrency::reserve(vs_bond, &BRUCE, 1)); - assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 99); - assert_eq!(Tokens::accounts(BRUCE, vs_bond).frozen, 0); - assert_eq!(Tokens::accounts(BRUCE, vs_bond).reserved, 1); - assert_ok!(Salp::unlock_vstoken(Some(BRUCE).into(), BRUCE)); - assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 100); - assert_eq!(Tokens::accounts(BRUCE, vs_bond).frozen, 0); - assert_eq!(Tokens::accounts(BRUCE, vs_bond).reserved, 0); - }); -} - -#[test] -fn contribute_should_work() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); - Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); - assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true)); - - let fund = Funds::::get(3_000).unwrap(); - let (contributed, status) = Salp::contribution(fund.trie_index, &BRUCE); - assert_eq!(fund.raised, 100); - assert_eq!(contributed, 100); - assert_eq!(status, ContributionStatus::Idle); - - let vs_token = - ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()) - .unwrap(); - let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( - RelayCurrencyId::get(), - 3_000, - 1, - SlotLength::get(), - ) - .unwrap(); - assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 100); - assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 100); - }); -} - -#[test] -fn double_contribute_should_work() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); - Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); - assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); - assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); - Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); - assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); - - // Check the contribution - let fund = Funds::::get(3_000).unwrap(); - let (contributed, status) = Salp::contribution(fund.trie_index, &BRUCE); - assert_eq!(fund.raised, 200); - assert_eq!(contributed, 200); - assert_eq!(status, ContributionStatus::Idle); - - let vs_token = - ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()) - .unwrap(); - let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( - RelayCurrencyId::get(), - 3_000, - 1, - SlotLength::get(), - ) - .unwrap(); - assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 200); - assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 200); - }); -} - -#[test] -fn contribute_when_xcm_error_should_work() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); - Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); - assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, false,)); - - let fund = Funds::::get(3_000).unwrap(); - let (contributed, status) = Salp::contribution(fund.trie_index, &BRUCE); - assert_eq!(fund.raised, 0); - assert_eq!(contributed, 0); - assert_eq!(status, ContributionStatus::Idle); - - let vs_token = - ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()) - .unwrap(); - let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( - RelayCurrencyId::get(), - 3_000, - 1, - SlotLength::get(), - ) - .unwrap(); - assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 0); - assert_eq!(Tokens::accounts(BRUCE, vs_token).frozen, 0); - assert_eq!(Tokens::accounts(BRUCE, vs_token).reserved, 0); - assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 0); - assert_eq!(Tokens::accounts(BRUCE, vs_bond).frozen, 0); - assert_eq!(Tokens::accounts(BRUCE, vs_bond).reserved, 0); - }); -} - -#[test] -fn confirm_contribute_later_should_work() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); - Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); - assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); - assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); - - let fund = Funds::::get(3_000).unwrap(); - let (contributed, status) = Salp::contribution(fund.trie_index, &BRUCE); - assert_eq!(fund.raised, 100); - assert_eq!(contributed, 100); - assert_eq!(status, ContributionStatus::Idle); - - let vs_token = - ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()) - .unwrap(); - let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( - RelayCurrencyId::get(), - 3_000, - 1, - SlotLength::get(), - ) - .unwrap(); - assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 100); - assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 100); - }); -} - -#[test] -fn contribute_with_wrong_origin_should_fail() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_noop!(Salp::contribute(RuntimeOrigin::none(), 3_000, 100), DispatchError::BadOrigin); - - assert_noop!( - Salp::confirm_contribute(RuntimeOrigin::none(), 0, true), - DispatchError::BadOrigin, - ); - }); -} - -#[test] -fn contribute_with_low_contribution_should_fail() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_noop!( - Salp::contribute(Some(BRUCE).into(), 3_000, MinContribution::get() - 1), - Error::::ContributionTooSmall - ); - }); -} - -#[test] -fn contribute_with_wrong_para_id_should_fail() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_noop!( - Salp::contribute(Some(BRUCE).into(), 4_000, 100), - Error::::InvalidParaId - ); - }); -} - -#[test] -fn contribute_with_wrong_fund_status_should_fail() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000,)); - assert_noop!( - Salp::contribute(Some(BRUCE).into(), 3_000, 100), - Error::::InvalidFundStatus - ); - }); -} - -#[test] -fn contribute_exceed_cap_should_fail() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_noop!( - Salp::contribute(Some(BRUCE).into(), 3_000, 1_001), - Error::::CapExceeded - ); - }); -} - -#[test] -fn contribute_when_contributing_should_fail() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_noop!( - Salp::confirm_contribute(Some(ALICE).into(), 0, true), - Error::::NotFindContributionValue - ); - }); -} - -#[test] -fn confirm_contribute_when_not_in_contributing_should_fail() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); - - assert_noop!( - Salp::contribute(Some(BRUCE).into(), 3_000, 100), - Error::::InvalidContributionStatus - ); - }); -} - -#[test] -fn contribute_with_when_ump_wrong_should_fail() { - // TODO: Require an solution to settle with parallel test workflow -} - #[test] fn withdraw_should_work() { new_test_ext().execute_with(|| { @@ -1184,18 +745,6 @@ fn check_next_trie_index() { }); } -#[test] -fn batch_unlock_should_work() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); - Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); - assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); - assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); - assert_ok!(Salp::batch_unlock(Some(ALICE).into(), 3_000)); - }) -} - #[test] fn unlock_when_fund_ongoing_should_work() { new_test_ext().execute_with(|| { @@ -1225,21 +774,6 @@ fn unlock_when_fund_ongoing_should_work() { }); } -#[test] -fn set_confirmor_should_work() { - new_test_ext().execute_with(|| { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); - Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); - assert_noop!( - Salp::confirm_contribute(Some(BRUCE).into(), 0, true), - DispatchError::BadOrigin, - ); - assert_ok!(Salp::set_multisig_confirm_account(Some(ALICE).into(), BRUCE)); - assert_ok!(Salp::confirm_contribute(Some(BRUCE).into(), 0, true,)); - }); -} - #[test] fn refund_meanwhile_issue_should_work() { new_test_ext().execute_with(|| { @@ -1361,15 +895,6 @@ fn refund_meanwhile_issue_should_work() { 1, deadline )); - assert_noop!( - Salp::buyback(Some(ALICE).into(), 80), - orml_tokens::Error::::BalanceTooLow - ); - assert_ok!(Salp::buyback(Some(ALICE).into(), 70)); - assert_noop!( - Salp::buyback(Some(ALICE).into(), 10), - zenlink_protocol::Error::::InsufficientTargetAmount - ); let amounts = vec![1_000u128, 1_000u128]; assert_ok!(StablePool::create_pool( @@ -1489,116 +1014,3 @@ fn edit_fund_should_work() { assert_eq!(fund.status, FundStatus::Ongoing); }); } - -fn reserve_init() -> (CurrencyId, CurrencyId) { - assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get())); - assert_ok!(Salp::contribute(Some(BRUCE).into(), 3_000, 100)); - Salp::bind_query_id_and_contribution(0, 3_000, BRUCE, 100); - assert_ok!(Salp::confirm_contribute(Some(ALICE).into(), 0, true,)); - - assert_ok!(Salp::fund_success(Some(ALICE).into(), 3_000)); - assert_ok!(Salp::unlock(Some(BRUCE).into(), BRUCE, 3_000)); - - // Mock the BlockNumber - let block_begin_redeem = (SlotLength::get() + 1) * LeasePeriod::get(); - System::set_block_number(block_begin_redeem.into()); - - let vs_token = - ::CurrencyIdConversion::convert_to_vstoken(RelayCurrencyId::get()).unwrap(); - let vs_bond = ::CurrencyIdConversion::convert_to_vsbond( - RelayCurrencyId::get(), - 3_000, - 1, - SlotLength::get(), - ) - .unwrap(); - (vs_token, vs_bond) -} - -#[test] -fn batch_handle_reserve_should_work() { - new_test_ext().execute_with(|| { - let (vs_token, vs_bond) = reserve_init(); - - assert_ok!(Salp::reserve(Some(BRUCE).into(), 3_000, 50, false)); - assert_ok!(>::transfer(vs_token, &BRUCE, &CATHI, 50)); - assert_ok!(>::transfer(vs_bond, &BRUCE, &CATHI, 50)); - assert_ok!(Salp::reserve(Some(CATHI).into(), 3_000, 10, false)); - assert_ok!(Salp::reserve(Some(CATHI).into(), 3_000, 40, false)); - assert_eq!(Tokens::accounts(CATHI, vs_token).frozen, 50); - assert_ok!(Salp::fund_retire(Some(ALICE).into(), 3_000)); - assert_ok!(Salp::withdraw(Some(ALICE).into(), 3_000)); - - assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 50); - assert_ok!(Salp::batch_handle_reserve(Some(BRUCE).into(), 3_000)); - assert_eq!(ReserveInfos::::get(3_000, BRUCE).value, 0); - - assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 0); - assert_eq!(Tokens::accounts(BRUCE, vs_token).frozen, 0); - assert_eq!(Tokens::accounts(BRUCE, vs_token).reserved, 0); - assert_eq!(Tokens::accounts(BRUCE, vs_bond).free, 0); - assert_eq!(Tokens::accounts(BRUCE, vs_bond).frozen, 0); - assert_eq!(Tokens::accounts(BRUCE, vs_bond).reserved, 0); - assert_eq!(Tokens::accounts(BRUCE, RelayCurrencyId::get()).free, INIT_BALANCE - 50); - assert_eq!(Tokens::accounts(BRUCE, RelayCurrencyId::get()).frozen, 0); - assert_eq!(Tokens::accounts(BRUCE, RelayCurrencyId::get()).reserved, 0); - - assert_eq!(Tokens::accounts(CATHI, vs_token).free, 0); - assert_eq!(Tokens::accounts(CATHI, vs_token).frozen, 0); - assert_eq!(Tokens::accounts(CATHI, vs_token).reserved, 0); - assert_eq!(Tokens::accounts(CATHI, vs_bond).free, 0); - assert_eq!(Tokens::accounts(CATHI, vs_bond).frozen, 0); - assert_eq!(Tokens::accounts(CATHI, vs_bond).reserved, 0); - assert_eq!(Tokens::accounts(CATHI, RelayCurrencyId::get()).free, INIT_BALANCE + 50); - assert_eq!(Tokens::accounts(CATHI, RelayCurrencyId::get()).frozen, 0); - assert_eq!(Tokens::accounts(CATHI, RelayCurrencyId::get()).reserved, 0); - }); -} - -#[test] -fn batch_handle_reserve_should_fail() { - new_test_ext().execute_with(|| { - let (_vs_token, _vs_bond) = reserve_init(); - - assert_noop!( - Salp::batch_handle_reserve(Some(BRUCE).into(), 3_000), - Error::::InvalidFundStatus, - ); - assert_ok!(Salp::reserve(Some(BRUCE).into(), 3_000, 100, false)); - assert_noop!( - Salp::batch_handle_reserve(Some(BRUCE).into(), 3_000), - Error::::InvalidFundStatus, - ); - }); -} - -#[test] -fn reserve_should_fail() { - new_test_ext().execute_with(|| { - let (_vs_token, _vs_bond) = reserve_init(); - - assert_noop!( - Salp::reserve(Some(CATHI).into(), 3_000, 10, false), - orml_tokens::Error::::BalanceTooLow, - ); - }); -} - -#[test] -fn reserve_should_work() { - new_test_ext().execute_with(|| { - let (vs_token, _vs_bond) = reserve_init(); - - assert_eq!(Tokens::accounts(BRUCE, vs_token).frozen, 0); - assert_ok!(Salp::reserve(Some(BRUCE).into(), 3_000, 100, false)); - assert_eq!(Tokens::accounts(BRUCE, vs_token).frozen, 100); - assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 100); - assert_ok!(Salp::cancel_reservation(Some(BRUCE).into(), 3_000)); - assert_ok!(Salp::cancel_reservation(Some(BRUCE).into(), 3_000)); - assert_eq!(Tokens::accounts(BRUCE, vs_token).frozen, 0); - assert_ok!(Salp::reserve(Some(BRUCE).into(), 3_000, 50, false)); - assert_eq!(ReserveInfos::::get(3_000, BRUCE).value, 50); - assert_eq!(Tokens::accounts(BRUCE, vs_token).frozen, 50); - assert_eq!(Tokens::accounts(BRUCE, vs_token).free, 100); - }); -} diff --git a/pallets/salp/src/weights.rs b/pallets/salp/src/weights.rs index 50abb1130..c82206189 100644 --- a/pallets/salp/src/weights.rs +++ b/pallets/salp/src/weights.rs @@ -56,7 +56,6 @@ pub trait WeightInfo { fn contribute() -> Weight; fn refund() -> Weight; fn unlock() -> Weight; - fn batch_unlock() -> Weight; fn redeem() -> Weight; fn set_multisig_confirm_account() -> Weight; fn fund_success() -> Weight; @@ -72,9 +71,6 @@ pub trait WeightInfo { fn dissolve() -> Weight; fn buyback() -> Weight; fn buyback_vstoken_by_stable_pool() -> Weight; - fn reserve() -> Weight; - fn batch_handle_reserve() -> Weight; - fn cancel_reservation() -> Weight; } // For backwards compatibility and tests @@ -146,25 +142,6 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Salp Funds (r:1 w:0) - /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Tokens Accounts (r:2 w:2) - /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) - /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) - /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - /// Storage: unknown `0x` (r:1 w:0) - /// Proof Skipped: unknown `0x` (r:1 w:0) - /// Storage: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:0) - /// Proof Skipped: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:0) - fn batch_unlock() -> Weight { - // Proof Size summary in bytes: - // Measured: `1995` - // Estimated: `6176` - // Minimum execution time: 143_054_000 picoseconds. - Weight::from_parts(146_914_000, 6176) - .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - } /// Storage: Salp Funds (r:1 w:1) /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) /// Storage: Salp RedeemPool (r:1 w:1) @@ -389,70 +366,4 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(10_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// Storage: Salp Funds (r:1 w:0) - /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Tokens Accounts (r:2 w:2) - /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) - /// Storage: Salp ReserveInfos (r:1 w:1) - /// Proof Skipped: Salp ReserveInfos (max_values: None, max_size: None, mode: Measured) - /// Storage: Tokens Locks (r:2 w:2) - /// Proof: Tokens Locks (max_values: None, max_size: Some(1271), added: 3746, mode: MaxEncodedLen) - /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) - /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - fn reserve() -> Weight { - // Proof Size summary in bytes: - // Measured: `1737` - // Estimated: `8482` - // Minimum execution time: 807_976_000 picoseconds. - Weight::from_parts(814_218_000, 0) - .saturating_add(Weight::from_parts(0, 8482)) - .saturating_add(RocksDbWeight::get().reads(7)) - .saturating_add(RocksDbWeight::get().writes(5)) - } - /// Storage: Salp Funds (r:1 w:0) - /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Tokens Locks (r:2 w:2) - /// Proof: Tokens Locks (max_values: None, max_size: Some(1271), added: 3746, mode: MaxEncodedLen) - /// Storage: Tokens Accounts (r:2 w:2) - /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) - /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) - /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - /// Storage: Salp ReserveInfos (r:0 w:1) - /// Proof Skipped: Salp ReserveInfos (max_values: None, max_size: None, mode: Measured) - fn cancel_reservation() -> Weight { - // Proof Size summary in bytes: - // Measured: `1935` - // Estimated: `8482` - // Minimum execution time: 853_491_000 picoseconds. - Weight::from_parts(858_070_000, 0) - .saturating_add(Weight::from_parts(0, 8482)) - .saturating_add(RocksDbWeight::get().reads(6)) - .saturating_add(RocksDbWeight::get().writes(5)) - } - /// Storage: Salp Funds (r:1 w:1) - /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Salp ReserveInfos (r:2 w:1) - /// Proof Skipped: Salp ReserveInfos (max_values: None, max_size: None, mode: Measured) - /// Storage: Tokens Locks (r:2 w:2) - /// Proof: Tokens Locks (max_values: None, max_size: Some(1271), added: 3746, mode: MaxEncodedLen) - /// Storage: Tokens Accounts (r:4 w:4) - /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) - /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) - /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - /// Storage: Salp RedeemPool (r:1 w:1) - /// Proof Skipped: Salp RedeemPool (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Tokens TotalIssuance (r:2 w:2) - /// Proof: Tokens TotalIssuance (max_values: None, max_size: Some(38), added: 2513, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn batch_handle_reserve() -> Weight { - // Proof Size summary in bytes: - // Measured: `2540` - // Estimated: `11362` - // Minimum execution time: 1_848_798_000 picoseconds. - Weight::from_parts(1_859_469_000, 0) - .saturating_add(Weight::from_parts(0, 11362)) - .saturating_add(RocksDbWeight::get().reads(14)) - .saturating_add(RocksDbWeight::get().writes(12)) - } } diff --git a/primitives/src/traits.rs b/primitives/src/traits.rs index dc36f5fc1..a3423ec73 100644 --- a/primitives/src/traits.rs +++ b/primitives/src/traits.rs @@ -31,7 +31,7 @@ use sp_runtime::{ traits::{ AccountIdConversion, AtLeast32BitUnsigned, ConstU32, MaybeSerializeDeserialize, Zero, }, - BoundedVec, DispatchError, DispatchResult, TokenError, TypeId, + BoundedVec, DispatchError, DispatchResult, TypeId, }; use sp_std::{cmp::Ordering, fmt::Debug, vec::Vec}; @@ -81,16 +81,6 @@ pub trait MultiCurrencyExt { ) -> DispatchResult; } -pub trait BancorHandler { - fn add_token(currency_id: super::CurrencyId, amount: Balance) -> DispatchResult; -} - -impl BancorHandler for () { - fn add_token(_currency_id: super::CurrencyId, _amount: Balance) -> DispatchResult { - DispatchResult::from(DispatchError::Token(TokenError::FundsUnavailable)) - } -} - pub trait CheckSubAccount { fn check_sub_account(&self, account: &T) -> bool; } diff --git a/runtime/bifrost-kusama/src/lib.rs b/runtime/bifrost-kusama/src/lib.rs index 24fe2de75..130d63e80 100644 --- a/runtime/bifrost-kusama/src/lib.rs +++ b/runtime/bifrost-kusama/src/lib.rs @@ -1147,7 +1147,6 @@ parameter_types! { } impl bifrost_salp::Config for Runtime { - type BancorPool = (); type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; @@ -1166,14 +1165,10 @@ impl bifrost_salp::Config for Runtime { type XcmInterface = XcmInterface; type TreasuryAccount = BifrostTreasuryAccount; type BuybackPalletId = BuybackPalletId; - type DexOperator = ZenlinkProtocol; type CurrencyIdConversion = AssetIdMaps; type CurrencyIdRegister = AssetIdMaps; - type ParachainId = ParachainInfo; type StablePool = StablePool; type VtokenMinting = VtokenMinting; - type LockId = SalpLockId; - type BatchLimit = BatchLimit; } parameter_types! { diff --git a/runtime/bifrost-kusama/src/weights/bifrost_salp.rs b/runtime/bifrost-kusama/src/weights/bifrost_salp.rs index 754136ff7..79c1612f5 100644 --- a/runtime/bifrost-kusama/src/weights/bifrost_salp.rs +++ b/runtime/bifrost-kusama/src/weights/bifrost_salp.rs @@ -121,25 +121,6 @@ impl bifrost_salp::WeightInfo for BifrostWeight { .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Salp Funds (r:1 w:0) - // Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) - // Storage: Tokens Accounts (r:2 w:2) - // Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) - // Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) - // Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - // Storage: unknown `0x` (r:1 w:0) - // Proof Skipped: unknown `0x` (r:1 w:0) - // Storage: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:0) - // Proof Skipped: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:0) - fn batch_unlock() -> Weight { - // Proof Size summary in bytes: - // Measured: `1995` - // Estimated: `6176` - // Minimum execution time: 142_535 nanoseconds. - Weight::from_parts(144_730_000, 6176) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - } // Storage: Salp Funds (r:1 w:1) // Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) // Storage: Salp RedeemPool (r:1 w:1) @@ -364,70 +345,4 @@ impl bifrost_salp::WeightInfo for BifrostWeight { .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(6)) } - /// Storage: Salp Funds (r:1 w:0) - /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Tokens Accounts (r:2 w:2) - /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) - /// Storage: Salp ReserveInfos (r:1 w:1) - /// Proof Skipped: Salp ReserveInfos (max_values: None, max_size: None, mode: Measured) - /// Storage: Tokens Locks (r:2 w:2) - /// Proof: Tokens Locks (max_values: None, max_size: Some(1271), added: 3746, mode: MaxEncodedLen) - /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) - /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - fn reserve() -> Weight { - // Proof Size summary in bytes: - // Measured: `1737` - // Estimated: `8482` - // Minimum execution time: 807_976_000 picoseconds. - Weight::from_parts(814_218_000, 0) - .saturating_add(Weight::from_parts(0, 8482)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: Salp Funds (r:1 w:0) - /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Tokens Locks (r:2 w:2) - /// Proof: Tokens Locks (max_values: None, max_size: Some(1271), added: 3746, mode: MaxEncodedLen) - /// Storage: Tokens Accounts (r:2 w:2) - /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) - /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) - /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - /// Storage: Salp ReserveInfos (r:0 w:1) - /// Proof Skipped: Salp ReserveInfos (max_values: None, max_size: None, mode: Measured) - fn cancel_reservation() -> Weight { - // Proof Size summary in bytes: - // Measured: `1935` - // Estimated: `8482` - // Minimum execution time: 853_491_000 picoseconds. - Weight::from_parts(858_070_000, 0) - .saturating_add(Weight::from_parts(0, 8482)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: Salp Funds (r:1 w:1) - /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Salp ReserveInfos (r:2 w:1) - /// Proof Skipped: Salp ReserveInfos (max_values: None, max_size: None, mode: Measured) - /// Storage: Tokens Locks (r:2 w:2) - /// Proof: Tokens Locks (max_values: None, max_size: Some(1271), added: 3746, mode: MaxEncodedLen) - /// Storage: Tokens Accounts (r:4 w:4) - /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) - /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) - /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - /// Storage: Salp RedeemPool (r:1 w:1) - /// Proof Skipped: Salp RedeemPool (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Tokens TotalIssuance (r:2 w:2) - /// Proof: Tokens TotalIssuance (max_values: None, max_size: Some(38), added: 2513, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn batch_handle_reserve() -> Weight { - // Proof Size summary in bytes: - // Measured: `2540` - // Estimated: `11362` - // Minimum execution time: 1_848_798_000 picoseconds. - Weight::from_parts(1_859_469_000, 0) - .saturating_add(Weight::from_parts(0, 11362)) - .saturating_add(T::DbWeight::get().reads(14)) - .saturating_add(T::DbWeight::get().writes(12)) - } } diff --git a/runtime/bifrost-kusama/src/xcm_config.rs b/runtime/bifrost-kusama/src/xcm_config.rs index c56411628..612f2366c 100644 --- a/runtime/bifrost-kusama/src/xcm_config.rs +++ b/runtime/bifrost-kusama/src/xcm_config.rs @@ -351,12 +351,7 @@ impl Contains for SafeCallFilter { bifrost_farming::Call::withdraw_claim { .. } ) | RuntimeCall::Salp( - bifrost_salp::Call::contribute { .. } | - bifrost_salp::Call::batch_unlock { .. } | - bifrost_salp::Call::redeem { .. } | - bifrost_salp::Call::unlock { .. } | - bifrost_salp::Call::unlock_by_vsbond { .. } | - bifrost_salp::Call::unlock_vstoken { .. } + bifrost_salp::Call::redeem { .. } ) | RuntimeCall::VSBondAuction( bifrost_vsbond_auction::Call::clinch_order { .. } | diff --git a/runtime/bifrost-polkadot/src/lib.rs b/runtime/bifrost-polkadot/src/lib.rs index 778aad7b6..a823373e4 100644 --- a/runtime/bifrost-polkadot/src/lib.rs +++ b/runtime/bifrost-polkadot/src/lib.rs @@ -1031,7 +1031,6 @@ parameter_types! { } impl bifrost_salp::Config for Runtime { - type BancorPool = (); type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; @@ -1050,14 +1049,10 @@ impl bifrost_salp::Config for Runtime { type XcmInterface = XcmInterface; type TreasuryAccount = BifrostTreasuryAccount; type BuybackPalletId = BuybackPalletId; - type DexOperator = ZenlinkProtocol; type CurrencyIdConversion = AssetIdMaps; type CurrencyIdRegister = AssetIdMaps; - type ParachainId = ParachainInfo; type StablePool = StablePool; type VtokenMinting = VtokenMinting; - type LockId = SalpLockId; - type BatchLimit = BatchLimit; } impl bifrost_asset_registry::Config for Runtime { diff --git a/runtime/bifrost-polkadot/src/weights/bifrost_salp.rs b/runtime/bifrost-polkadot/src/weights/bifrost_salp.rs index 754136ff7..79c1612f5 100644 --- a/runtime/bifrost-polkadot/src/weights/bifrost_salp.rs +++ b/runtime/bifrost-polkadot/src/weights/bifrost_salp.rs @@ -121,25 +121,6 @@ impl bifrost_salp::WeightInfo for BifrostWeight { .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Salp Funds (r:1 w:0) - // Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) - // Storage: Tokens Accounts (r:2 w:2) - // Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) - // Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) - // Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - // Storage: unknown `0x` (r:1 w:0) - // Proof Skipped: unknown `0x` (r:1 w:0) - // Storage: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:0) - // Proof Skipped: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:0) - fn batch_unlock() -> Weight { - // Proof Size summary in bytes: - // Measured: `1995` - // Estimated: `6176` - // Minimum execution time: 142_535 nanoseconds. - Weight::from_parts(144_730_000, 6176) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - } // Storage: Salp Funds (r:1 w:1) // Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) // Storage: Salp RedeemPool (r:1 w:1) @@ -364,70 +345,4 @@ impl bifrost_salp::WeightInfo for BifrostWeight { .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(6)) } - /// Storage: Salp Funds (r:1 w:0) - /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Tokens Accounts (r:2 w:2) - /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) - /// Storage: Salp ReserveInfos (r:1 w:1) - /// Proof Skipped: Salp ReserveInfos (max_values: None, max_size: None, mode: Measured) - /// Storage: Tokens Locks (r:2 w:2) - /// Proof: Tokens Locks (max_values: None, max_size: Some(1271), added: 3746, mode: MaxEncodedLen) - /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) - /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - fn reserve() -> Weight { - // Proof Size summary in bytes: - // Measured: `1737` - // Estimated: `8482` - // Minimum execution time: 807_976_000 picoseconds. - Weight::from_parts(814_218_000, 0) - .saturating_add(Weight::from_parts(0, 8482)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: Salp Funds (r:1 w:0) - /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Tokens Locks (r:2 w:2) - /// Proof: Tokens Locks (max_values: None, max_size: Some(1271), added: 3746, mode: MaxEncodedLen) - /// Storage: Tokens Accounts (r:2 w:2) - /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) - /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) - /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - /// Storage: Salp ReserveInfos (r:0 w:1) - /// Proof Skipped: Salp ReserveInfos (max_values: None, max_size: None, mode: Measured) - fn cancel_reservation() -> Weight { - // Proof Size summary in bytes: - // Measured: `1935` - // Estimated: `8482` - // Minimum execution time: 853_491_000 picoseconds. - Weight::from_parts(858_070_000, 0) - .saturating_add(Weight::from_parts(0, 8482)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: Salp Funds (r:1 w:1) - /// Proof Skipped: Salp Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Salp ReserveInfos (r:2 w:1) - /// Proof Skipped: Salp ReserveInfos (max_values: None, max_size: None, mode: Measured) - /// Storage: Tokens Locks (r:2 w:2) - /// Proof: Tokens Locks (max_values: None, max_size: Some(1271), added: 3746, mode: MaxEncodedLen) - /// Storage: Tokens Accounts (r:4 w:4) - /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) - /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) - /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - /// Storage: Salp RedeemPool (r:1 w:1) - /// Proof Skipped: Salp RedeemPool (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Tokens TotalIssuance (r:2 w:2) - /// Proof: Tokens TotalIssuance (max_values: None, max_size: Some(38), added: 2513, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn batch_handle_reserve() -> Weight { - // Proof Size summary in bytes: - // Measured: `2540` - // Estimated: `11362` - // Minimum execution time: 1_848_798_000 picoseconds. - Weight::from_parts(1_859_469_000, 0) - .saturating_add(Weight::from_parts(0, 11362)) - .saturating_add(T::DbWeight::get().reads(14)) - .saturating_add(T::DbWeight::get().writes(12)) - } } diff --git a/runtime/bifrost-polkadot/src/xcm_config.rs b/runtime/bifrost-polkadot/src/xcm_config.rs index 9c43feb13..88d9b9db3 100644 --- a/runtime/bifrost-polkadot/src/xcm_config.rs +++ b/runtime/bifrost-polkadot/src/xcm_config.rs @@ -258,12 +258,7 @@ impl Contains for SafeCallFilter { bifrost_farming::Call::withdraw_claim { .. } ) | RuntimeCall::Salp( - bifrost_salp::Call::contribute { .. } | - bifrost_salp::Call::batch_unlock { .. } | - bifrost_salp::Call::redeem { .. } | - bifrost_salp::Call::unlock { .. } | - bifrost_salp::Call::unlock_by_vsbond { .. } | - bifrost_salp::Call::unlock_vstoken { .. } + bifrost_salp::Call::redeem { .. } ) | RuntimeCall::TokenConversion( bifrost_vstoken_conversion::Call::vsbond_convert_to_vstoken { .. } | From 394f7291226875ba911a4b7c71e627102e3d7c78 Mon Sep 17 00:00:00 2001 From: NingBo Wang <2536935847@qq.com> Date: Mon, 23 Sep 2024 13:24:50 +0800 Subject: [PATCH 03/30] Optimised calculation of evm fee (#1434) * Optimised calculation of evm fee * Update gas_fee_price to weth_price --- pallets/fee-share/src/lib.rs | 8 +- pallets/fee-share/src/mock.rs | 12 +- .../src/impls/on_charge_transaction.rs | 6 +- pallets/flexible-fee/src/lib.rs | 8 +- pallets/flexible-fee/src/mock.rs | 4 +- pallets/flexible-fee/src/mock_price.rs | 48 +++--- pallets/lend-market/src/lib.rs | 6 +- pallets/lend-market/src/mock.rs | 12 +- pallets/lend-market/src/tests.rs | 10 +- .../lend-market/src/tests/interest_rate.rs | 2 +- .../lend-market/src/tests/liquidate_borrow.rs | 19 ++- pallets/leverage-staking/src/mock.rs | 14 +- pallets/prices/src/lib.rs | 36 ++-- pallets/traits/src/lib.rs | 2 +- primitives/src/price.rs | 3 +- runtime/bifrost-kusama/src/lib.rs | 6 +- runtime/bifrost-polkadot/src/evm/evm_fee.rs | 129 ++++++--------- runtime/bifrost-polkadot/src/evm/mod.rs | 23 +-- runtime/bifrost-polkadot/src/evm/runner.rs | 60 ++++++- runtime/bifrost-polkadot/src/lib.rs | 6 +- runtime/common/src/lib.rs | 4 - runtime/common/src/price.rs | 116 ------------- runtime/common/src/ratio.rs | 154 ------------------ 23 files changed, 215 insertions(+), 473 deletions(-) delete mode 100644 runtime/common/src/price.rs delete mode 100644 runtime/common/src/ratio.rs diff --git a/pallets/fee-share/src/lib.rs b/pallets/fee-share/src/lib.rs index df6049865..cc1b45fd1 100644 --- a/pallets/fee-share/src/lib.rs +++ b/pallets/fee-share/src/lib.rs @@ -30,7 +30,7 @@ mod benchmarking; pub mod weights; -use bifrost_primitives::{CurrencyId, DistributionId, Price, PriceFeeder}; +use bifrost_primitives::{CurrencyId, DistributionId, OraclePriceProvider, Price}; use frame_support::{ pallet_prelude::*, sp_runtime::{ @@ -102,7 +102,7 @@ pub mod pallet { type FeeSharePalletId: Get; /// The oracle price feeder - type PriceFeeder: PriceFeeder; + type OraclePriceProvider: OraclePriceProvider; } #[pallet::event] @@ -492,8 +492,8 @@ pub mod pallet { } pub fn get_price(currency_id: CurrencyIdOf) -> Result { - let (price, _) = - T::PriceFeeder::get_price(¤cy_id).ok_or(Error::::PriceOracleNotReady)?; + let (price, _) = T::OraclePriceProvider::get_price(¤cy_id) + .ok_or(Error::::PriceOracleNotReady)?; log::trace!( target: "fee-share::get_price", "price: {:?}", price.into_inner() ); diff --git a/pallets/fee-share/src/mock.rs b/pallets/fee-share/src/mock.rs index 3e7060766..16945802b 100644 --- a/pallets/fee-share/src/mock.rs +++ b/pallets/fee-share/src/mock.rs @@ -182,7 +182,7 @@ impl bifrost_fee_share::Config for Runtime { type ControlOrigin = EnsureSignedBy; type WeightInfo = (); type FeeSharePalletId = FeeSharePalletId; - type PriceFeeder = MockPriceFeeder; + type OraclePriceProvider = MockOraclePriceProvider; } impl pallet_prices::Config for Runtime { @@ -224,7 +224,7 @@ impl DataFeeder for MockDataProvider { Ok(()) } } -pub struct MockPriceFeeder; +pub struct MockOraclePriceProvider; #[derive(Encode, Decode, Clone, Copy, RuntimeDebug)] pub struct CurrencyIdWrap(CurrencyId); @@ -242,7 +242,7 @@ impl PartialEq for CurrencyIdWrap { impl Eq for CurrencyIdWrap {} -impl MockPriceFeeder { +impl MockOraclePriceProvider { thread_local! { pub static PRICES: RefCell>> = { RefCell::new( @@ -269,15 +269,11 @@ impl MockPriceFeeder { } } -impl PriceFeeder for MockPriceFeeder { +impl OraclePriceProvider for MockOraclePriceProvider { fn get_price(asset_id: &CurrencyId) -> Option { Self::PRICES.with(|prices| *prices.borrow().get(&CurrencyIdWrap(*asset_id)).unwrap()) } - fn get_normal_price(_asset_id: &CurrencyId) -> Option { - todo!() - } - fn get_amount_by_prices( _currency_in: &CurrencyId, _amount_in: bifrost_primitives::Balance, diff --git a/pallets/flexible-fee/src/impls/on_charge_transaction.rs b/pallets/flexible-fee/src/impls/on_charge_transaction.rs index 0f217eed5..336605884 100644 --- a/pallets/flexible-fee/src/impls/on_charge_transaction.rs +++ b/pallets/flexible-fee/src/impls/on_charge_transaction.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use crate::{Config, ExtraFeeByCall, Pallet}; -use bifrost_primitives::{Balance, CurrencyId, Price, PriceFeeder, BNC}; +use bifrost_primitives::{Balance, CurrencyId, OraclePriceProvider, Price, BNC}; use orml_traits::MultiCurrency; use pallet_transaction_payment::OnChargeTransaction; use parity_scale_codec::Encode; @@ -124,7 +124,7 @@ where ), PaymentInfo::NonNative(paid_fee, fee_currency, bnc_price, fee_currency_price) => { // calculate corrected_fee in the non-native currency - let converted_corrected_fee = T::PriceFeeder::get_amount_by_prices( + let converted_corrected_fee = T::OraclePriceProvider::get_amount_by_prices( &BNC, corrected_fee, bnc_price, @@ -133,7 +133,7 @@ where ) .ok_or(TransactionValidityError::Invalid(InvalidTransaction::Payment))?; let refund = paid_fee.saturating_sub(converted_corrected_fee); - let converted_tip = T::PriceFeeder::get_amount_by_prices( + let converted_tip = T::OraclePriceProvider::get_amount_by_prices( &BNC, tip, bnc_price, diff --git a/pallets/flexible-fee/src/lib.rs b/pallets/flexible-fee/src/lib.rs index f0e76dec7..889b9f494 100644 --- a/pallets/flexible-fee/src/lib.rs +++ b/pallets/flexible-fee/src/lib.rs @@ -22,7 +22,7 @@ pub use crate::pallet::*; use bifrost_primitives::{ currency::{VGLMR, VMANTA, WETH}, traits::XcmDestWeightAndFeeHandler, - Balance, BalanceCmp, CurrencyId, DerivativeIndex, Price, PriceFeeder, TryConvertFrom, + Balance, BalanceCmp, CurrencyId, DerivativeIndex, OraclePriceProvider, Price, TryConvertFrom, XcmOperationType, BNC, DOT, GLMR, MANTA, VBNC, VDOT, }; use bifrost_xcm_interface::{polkadot::RelaychainCall, traits::parachains, PolkadotXcmCall}; @@ -74,7 +74,7 @@ pub enum TargetChain { #[frame_support::pallet] pub mod pallet { use super::*; - use bifrost_primitives::{Balance, PriceFeeder}; + use bifrost_primitives::{Balance, OraclePriceProvider}; use frame_support::traits::fungibles::Inspect; #[pallet::config] @@ -91,7 +91,7 @@ pub mod pallet { /// Zenlink interface type DexOperator: ExportZenlink; /// The oracle price feeder - type PriceFeeder: PriceFeeder; + type OraclePriceProvider: OraclePriceProvider; /// The only origin that can set universal fee currency order list type ControlOrigin: EnsureOrigin; /// Get the weight and fee for executing Xcm. @@ -389,7 +389,7 @@ impl Pallet { } } else { let (fee_amount, price_in, price_out) = - T::PriceFeeder::get_oracle_amount_by_currency_and_amount_in( + T::OraclePriceProvider::get_oracle_amount_by_currency_and_amount_in( &BNC, fee_amount, ¤cy_id, diff --git a/pallets/flexible-fee/src/mock.rs b/pallets/flexible-fee/src/mock.rs index 3dea71af4..d8ef4559d 100644 --- a/pallets/flexible-fee/src/mock.rs +++ b/pallets/flexible-fee/src/mock.rs @@ -19,7 +19,7 @@ #![cfg(test)] use super::*; -use crate::{self as flexible_fee, mock_price::MockPriceFeeder}; +use crate::{self as flexible_fee, mock_price::MockOraclePriceProvider}; use bifrost_currencies::BasicCurrencyAdapter; use bifrost_primitives::{Balance, CurrencyId, TokenSymbol}; use cumulus_primitives_core::ParaId as Pid; @@ -167,7 +167,7 @@ impl crate::Config for Test { type RelaychainCurrencyId = RelayCurrencyId; type XcmRouter = (); type PalletId = FlexibleFeePalletId; - type PriceFeeder = MockPriceFeeder; + type OraclePriceProvider = MockOraclePriceProvider; } pub struct XcmDestWeightAndFee; diff --git a/pallets/flexible-fee/src/mock_price.rs b/pallets/flexible-fee/src/mock_price.rs index 80e7d0bca..18374e46e 100644 --- a/pallets/flexible-fee/src/mock_price.rs +++ b/pallets/flexible-fee/src/mock_price.rs @@ -19,8 +19,8 @@ #![cfg(test)] use bifrost_primitives::{ - Balance, CurrencyId, Price, PriceDetail, PriceFeeder, BNC, DOT, DOT_U, KSM, MANTA, VDOT, VKSM, - WETH, + Balance, CurrencyId, OraclePriceProvider, Price, PriceDetail, BNC, DOT, DOT_U, KSM, MANTA, + VDOT, VKSM, WETH, }; use frame_support::parameter_types; use sp_runtime::FixedU128; @@ -39,8 +39,8 @@ parameter_types! { ]); } -pub struct MockPriceFeeder; -impl MockPriceFeeder { +pub struct MockOraclePriceProvider; +impl MockOraclePriceProvider { pub fn set_price(currency_id: CurrencyId, price: Price) { let mut storage_price = StoragePrice::get(); match storage_price.get(¤cy_id) { @@ -55,7 +55,7 @@ impl MockPriceFeeder { } } -impl PriceFeeder for MockPriceFeeder { +impl OraclePriceProvider for MockOraclePriceProvider { fn get_price(currency_id: &CurrencyId) -> Option { match StoragePrice::get().get(currency_id) { Some((price, _)) => Some((*price, 0)), @@ -63,10 +63,6 @@ impl PriceFeeder for MockPriceFeeder { } } - fn get_normal_price(_asset_id: &CurrencyId) -> Option { - todo!() - } - fn get_amount_by_prices( currency_in: &CurrencyId, amount_in: Balance, @@ -119,14 +115,14 @@ mod test { #[test] fn set_price() { assert_eq!( - MockPriceFeeder::get_price(&BNC), + MockOraclePriceProvider::get_price(&BNC), Some((FixedU128::from_inner(200_000_000_000_000_000), 0)) ); - MockPriceFeeder::set_price(BNC, FixedU128::from(100)); - assert_eq!(MockPriceFeeder::get_price(&BNC), Some((FixedU128::from(100), 0))); + MockOraclePriceProvider::set_price(BNC, FixedU128::from(100)); + assert_eq!(MockOraclePriceProvider::get_price(&BNC), Some((FixedU128::from(100), 0))); - MockPriceFeeder::set_price(DOT, FixedU128::from(100)); - assert_eq!(MockPriceFeeder::get_price(&DOT), Some((FixedU128::from(100), 0))); + MockOraclePriceProvider::set_price(DOT, FixedU128::from(100)); + assert_eq!(MockOraclePriceProvider::get_price(&DOT), Some((FixedU128::from(100), 0))); } #[test] @@ -137,19 +133,27 @@ mod test { let usdt_amount = 20 * 10u128.pow(6); let manta_amount = 25 * 10u128.pow(18); assert_eq!( - MockPriceFeeder::get_oracle_amount_by_currency_and_amount_in(&BNC, bnc_amount, &DOT), + MockOraclePriceProvider::get_oracle_amount_by_currency_and_amount_in( + &BNC, bnc_amount, &DOT + ), Some((dot_amount, FixedU128::from_inner(200_000_000_000_000_000), FixedU128::from(5))) ); assert_eq!( - MockPriceFeeder::get_oracle_amount_by_currency_and_amount_in(&BNC, bnc_amount, &DOT_U), + MockOraclePriceProvider::get_oracle_amount_by_currency_and_amount_in( + &BNC, bnc_amount, &DOT_U + ), Some((usdt_amount, FixedU128::from_inner(200_000_000_000_000_000), FixedU128::from(1))) ); assert_eq!( - MockPriceFeeder::get_oracle_amount_by_currency_and_amount_in(&BNC, bnc_amount, &KSM), + MockOraclePriceProvider::get_oracle_amount_by_currency_and_amount_in( + &BNC, bnc_amount, &KSM + ), Some((ksm_amount, FixedU128::from_inner(200_000_000_000_000_000), FixedU128::from(20))) ); assert_eq!( - MockPriceFeeder::get_oracle_amount_by_currency_and_amount_in(&BNC, bnc_amount, &MANTA), + MockOraclePriceProvider::get_oracle_amount_by_currency_and_amount_in( + &BNC, bnc_amount, &MANTA + ), Some(( manta_amount, FixedU128::from_inner(200_000_000_000_000_000), @@ -157,11 +161,15 @@ mod test { )) ); assert_eq!( - MockPriceFeeder::get_oracle_amount_by_currency_and_amount_in(&DOT, dot_amount, &DOT_U), + MockOraclePriceProvider::get_oracle_amount_by_currency_and_amount_in( + &DOT, dot_amount, &DOT_U + ), Some((usdt_amount, FixedU128::from(5), FixedU128::from(1))) ); assert_eq!( - MockPriceFeeder::get_oracle_amount_by_currency_and_amount_in(&DOT, dot_amount, &KSM), + MockOraclePriceProvider::get_oracle_amount_by_currency_and_amount_in( + &DOT, dot_amount, &KSM + ), Some((ksm_amount, FixedU128::from(5), FixedU128::from(20))) ); } diff --git a/pallets/lend-market/src/lib.rs b/pallets/lend-market/src/lib.rs index 45b0903be..743701a0e 100644 --- a/pallets/lend-market/src/lib.rs +++ b/pallets/lend-market/src/lib.rs @@ -26,7 +26,7 @@ use core::cmp::max; pub use crate::rate_model::*; use bifrost_primitives::{ - Balance, CurrencyId, Liquidity, Price, PriceFeeder, Rate, Ratio, Shortfall, Timestamp, + Balance, CurrencyId, Liquidity, OraclePriceProvider, Price, Rate, Ratio, Shortfall, Timestamp, }; use frame_support::{ pallet_prelude::*, @@ -103,7 +103,7 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The oracle price feeder - type PriceFeeder: PriceFeeder; + type OraclePriceProvider: OraclePriceProvider; /// The loan's module id, keep all collaterals of CDPs. #[pallet::constant] @@ -1959,7 +1959,7 @@ impl Pallet { // Returns `Err` if the oracle price not ready pub fn get_price(asset_id: AssetIdOf) -> Result { let (price, _) = - T::PriceFeeder::get_price(&asset_id).ok_or(Error::::PriceOracleNotReady)?; + T::OraclePriceProvider::get_price(&asset_id).ok_or(Error::::PriceOracleNotReady)?; if price.is_zero() { return Err(Error::::PriceIsZero.into()); } diff --git a/pallets/lend-market/src/mock.rs b/pallets/lend-market/src/mock.rs index 294c4e24e..eecf3f21d 100644 --- a/pallets/lend-market/src/mock.rs +++ b/pallets/lend-market/src/mock.rs @@ -205,7 +205,7 @@ impl SortedMembers for AliceCreatePoolOrigin { } } -pub struct MockPriceFeeder; +pub struct MockOraclePriceProvider; #[derive(Encode, Decode, Clone, Copy, RuntimeDebug)] pub struct CurrencyIdWrap(CurrencyId); @@ -223,7 +223,7 @@ impl PartialEq for CurrencyIdWrap { impl Eq for CurrencyIdWrap {} -impl MockPriceFeeder { +impl MockOraclePriceProvider { thread_local! { pub static PRICES: RefCell>> = { RefCell::new( @@ -250,15 +250,11 @@ impl MockPriceFeeder { } } -impl PriceFeeder for MockPriceFeeder { +impl OraclePriceProvider for MockOraclePriceProvider { fn get_price(asset_id: &CurrencyId) -> Option { Self::PRICES.with(|prices| *prices.borrow().get(&CurrencyIdWrap(*asset_id)).unwrap()) } - fn get_normal_price(_asset_id: &CurrencyId) -> Option { - todo!() - } - fn get_amount_by_prices( _currency_in: &CurrencyId, _amount_in: Balance, @@ -327,7 +323,7 @@ parameter_types! { impl Config for Test { type RuntimeEvent = RuntimeEvent; - type PriceFeeder = MockPriceFeeder; + type OraclePriceProvider = MockOraclePriceProvider; type PalletId = LendMarketPalletId; type ReserveOrigin = EnsureRoot; type UpdateOrigin = EnsureRoot; diff --git a/pallets/lend-market/src/tests.rs b/pallets/lend-market/src/tests.rs index f8e2aec9e..b17c7a9df 100644 --- a/pallets/lend-market/src/tests.rs +++ b/pallets/lend-market/src/tests.rs @@ -656,7 +656,7 @@ fn get_account_liquidation_threshold_liquidity_works() { assert_eq!(liquidity, FixedU128::from_inner(unit(20))); assert_eq!(lf_liquidity, FixedU128::from_inner(unit(10))); - MockPriceFeeder::set_price(KSM, 2.into()); + MockOraclePriceProvider::set_price(KSM, 2.into()); let (liquidity, shortfall, lf_liquidity, _) = LendMarket::get_account_liquidation_threshold_liquidity(&ALICE).unwrap(); @@ -1259,10 +1259,10 @@ fn get_price_works() { BNC, vec![DOT, BNC, KSM, DOT_U, PHA] )); - MockPriceFeeder::set_price(DOT, 0.into()); + MockOraclePriceProvider::set_price(DOT, 0.into()); assert_noop!(LendMarket::get_price(DOT), Error::::PriceIsZero); - MockPriceFeeder::set_price(DOT, 2.into()); + MockOraclePriceProvider::set_price(DOT, 2.into()); assert_eq!(LendMarket::get_price(DOT).unwrap(), Price::saturating_from_integer(2)); }) } @@ -1813,7 +1813,7 @@ fn reward_calculation_after_liquidate_borrow_works() { assert_eq!(almost_equal(RewardAccrued::::get(ALICE), unit(14)), true); assert_eq!(almost_equal(RewardAccrued::::get(BOB), unit(16)), true); - MockPriceFeeder::set_price(KSM, 2.into()); + MockOraclePriceProvider::set_price(KSM, 2.into()); // since we set liquidate_threshold more than collateral_factor,with KSM price as 2 alice // not shortfall yet. so we can not liquidate_borrow here assert_noop!( @@ -1828,7 +1828,7 @@ fn reward_calculation_after_liquidate_borrow_works() { // Bob KSM Deposit: 500 // Bob KSM Borrow: 75 // incentive_reward_account DOT Deposit: 75*0.03 = 2.25 - MockPriceFeeder::set_price(KSM, 3.into()); + MockOraclePriceProvider::set_price(KSM, 3.into()); assert_ok!(LendMarket::liquidate_borrow( RuntimeOrigin::signed(BOB), ALICE, diff --git a/pallets/lend-market/src/tests/interest_rate.rs b/pallets/lend-market/src/tests/interest_rate.rs index 8bd5a22ba..fa391ca8f 100644 --- a/pallets/lend-market/src/tests/interest_rate.rs +++ b/pallets/lend-market/src/tests/interest_rate.rs @@ -371,7 +371,7 @@ fn accrue_interest_works_after_liquidate_borrow() { assert_eq!(BorrowIndex::::get(KSM), Rate::one()); TimestampPallet::set_timestamp(12000); // Adjust KSM price to make shortfall - MockPriceFeeder::set_price(KSM, 2.into()); + MockOraclePriceProvider::set_price(KSM, 2.into()); // BOB repay the KSM loan and get DOT callateral from ALICE assert_ok!(LendMarket::liquidate_borrow( RuntimeOrigin::signed(BOB), diff --git a/pallets/lend-market/src/tests/liquidate_borrow.rs b/pallets/lend-market/src/tests/liquidate_borrow.rs index 9e04e4a1e..17cb806da 100644 --- a/pallets/lend-market/src/tests/liquidate_borrow.rs +++ b/pallets/lend-market/src/tests/liquidate_borrow.rs @@ -1,6 +1,7 @@ use crate::{ mock::{ - new_test_ext, LendMarket, MockPriceFeeder, RuntimeOrigin, ALICE, BOB, DOT, DOT_U, KSM, *, + new_test_ext, LendMarket, MockOraclePriceProvider, RuntimeOrigin, ALICE, BOB, DOT, DOT_U, + KSM, *, }, tests::unit, Error, MarketState, @@ -23,7 +24,7 @@ fn liquidate_borrow_allowed_works() { initial_setup(); alice_borrows_100_ksm(); // Adjust KSM price to make shortfall - MockPriceFeeder::set_price(KSM, 2.into()); + MockOraclePriceProvider::set_price(KSM, 2.into()); let ksm_market = LendMarket::market(KSM).unwrap(); // Here the balance sheet of Alice is: // Collateral LendMarket @@ -82,8 +83,8 @@ fn lf_liquidate_borrow_allowed_works() { // CDOT's price is highly relative to DOT's price in real runtime. Thus we must update them // at the same time. - MockPriceFeeder::set_price(DOT, 2.into()); - MockPriceFeeder::set_price(PHA, 2.into()); + MockOraclePriceProvider::set_price(DOT, 2.into()); + MockOraclePriceProvider::set_price(PHA, 2.into()); // ALICE // Collateral Borrowed // DOT_U $100 DOT $400 @@ -113,7 +114,7 @@ fn deposit_of_borrower_must_be_collateral() { initial_setup(); alice_borrows_100_ksm(); // Adjust KSM price to make shortfall - MockPriceFeeder::set_price(KSM, 2.into()); + MockOraclePriceProvider::set_price(KSM, 2.into()); let market = LendMarket::market(KSM).unwrap(); assert_noop!( LendMarket::liquidate_borrow_allowed(&ALICE, KSM, unit(51), &market), @@ -134,7 +135,7 @@ fn collateral_value_must_be_greater_than_liquidation_value() { assert_ok!(LendMarket::add_market_bond(RuntimeOrigin::root(), BNC, vec![DOT, BNC, KSM])); initial_setup(); alice_borrows_100_ksm(); - MockPriceFeeder::set_price(KSM, Rate::from_float(2000.0)); + MockOraclePriceProvider::set_price(KSM, Rate::from_float(2000.0)); LendMarket::mutate_market(KSM, |market| { market.liquidate_incentive = Rate::from_float(200.0); market.clone() @@ -156,7 +157,7 @@ fn full_workflow_works_as_expected() { initial_setup(); alice_borrows_100_ksm(); // adjust KSM price to make ALICE generate shortfall - MockPriceFeeder::set_price(KSM, 2.into()); + MockOraclePriceProvider::set_price(KSM, 2.into()); // BOB repay the KSM borrow balance and get DOT from ALICE assert_ok!(LendMarket::liquidate_borrow( RuntimeOrigin::signed(BOB), @@ -227,7 +228,7 @@ fn liquidator_cannot_take_inactive_market_currency() { initial_setup(); alice_borrows_100_ksm(); // Adjust KSM price to make shortfall - MockPriceFeeder::set_price(KSM, 2.into()); + MockOraclePriceProvider::set_price(KSM, 2.into()); assert_ok!(LendMarket::mutate_market(DOT, |stored_market| { stored_market.state = MarketState::Supervision; stored_market.clone() @@ -247,7 +248,7 @@ fn liquidator_can_not_repay_more_than_the_close_factor_pct_multiplier() { assert_ok!(LendMarket::add_market_bond(RuntimeOrigin::root(), BNC, vec![DOT, BNC, KSM])); initial_setup(); alice_borrows_100_ksm(); - MockPriceFeeder::set_price(KSM, 20.into()); + MockOraclePriceProvider::set_price(KSM, 20.into()); assert_noop!( LendMarket::liquidate_borrow(RuntimeOrigin::signed(BOB), ALICE, KSM, unit(51), DOT), Error::::TooMuchRepay diff --git a/pallets/leverage-staking/src/mock.rs b/pallets/leverage-staking/src/mock.rs index a7c9944cf..f7ab5dd74 100644 --- a/pallets/leverage-staking/src/mock.rs +++ b/pallets/leverage-staking/src/mock.rs @@ -22,7 +22,7 @@ use bifrost_asset_registry::AssetIdMaps; pub use bifrost_primitives::{ currency::*, Balance, CurrencyId, CurrencyIdMapping, SlpOperator, SlpxOperator, TokenSymbol, }; -use bifrost_primitives::{Moment, MoonbeamChainId, Price, PriceDetail, PriceFeeder, Ratio}; +use bifrost_primitives::{Moment, MoonbeamChainId, OraclePriceProvider, Price, PriceDetail, Ratio}; use bifrost_runtime_common::milli; use frame_support::{ derive_impl, ord_parameter_types, parameter_types, @@ -340,7 +340,7 @@ impl pallet_timestamp::Config for Test { type WeightInfo = (); } -pub struct MockPriceFeeder; +pub struct MockOraclePriceProvider; #[derive(Encode, Decode, Clone, Copy, RuntimeDebug)] pub struct CurrencyIdWrap(CurrencyId); @@ -387,7 +387,7 @@ impl DataFeeder for MockDataProvider { } } -impl MockPriceFeeder { +impl MockOraclePriceProvider { thread_local! { pub static PRICES: RefCell>> = { RefCell::new( @@ -414,15 +414,11 @@ impl MockPriceFeeder { } } -impl PriceFeeder for MockPriceFeeder { +impl OraclePriceProvider for MockOraclePriceProvider { fn get_price(asset_id: &CurrencyId) -> Option { Self::PRICES.with(|prices| *prices.borrow().get(&CurrencyIdWrap(*asset_id)).unwrap()) } - fn get_normal_price(_asset_id: &CurrencyId) -> Option { - todo!() - } - fn get_amount_by_prices( _currency_in: &CurrencyId, _amount_in: Balance, @@ -450,7 +446,7 @@ parameter_types! { impl lend_market::Config for Test { type RuntimeEvent = RuntimeEvent; - type PriceFeeder = MockPriceFeeder; + type OraclePriceProvider = MockOraclePriceProvider; type PalletId = LendMarketPalletId; type ReserveOrigin = EnsureRoot; type UpdateOrigin = EnsureRoot; diff --git a/pallets/prices/src/lib.rs b/pallets/prices/src/lib.rs index 859826e63..a65516974 100644 --- a/pallets/prices/src/lib.rs +++ b/pallets/prices/src/lib.rs @@ -17,15 +17,15 @@ //! ## Overview //! //! This pallet provides the price from Oracle Module by implementing the -//! `PriceFeeder` trait. In case of emergency, the price can be set directly +//! `OraclePriceProvider` trait. In case of emergency, the price can be set directly //! by Oracle Collective. #![cfg_attr(not(feature = "std"), no_std)] use bifrost_asset_registry::AssetMetadata; use bifrost_primitives::{ - Balance, CurrencyId, CurrencyIdMapping, Price, PriceDetail, PriceFeeder, TimeStampedPrice, - TokenInfo, + Balance, CurrencyId, CurrencyIdMapping, OraclePriceProvider, Price, PriceDetail, + TimeStampedPrice, TokenInfo, }; use frame_support::{dispatch::DispatchClass, pallet_prelude::*, transactional}; use frame_system::pallet_prelude::*; @@ -144,7 +144,7 @@ pub mod pallet { price: Price, ) -> DispatchResultWithPostInfo { T::FeederOrigin::ensure_origin(origin)?; - as EmergencyPriceFeeder>::set_emergency_price( + as EmergencyOraclePriceProvider>::set_emergency_price( asset_id, price, ); Ok(().into()) @@ -159,7 +159,9 @@ pub mod pallet { asset_id: CurrencyId, ) -> DispatchResultWithPostInfo { T::FeederOrigin::ensure_origin(origin)?; - as EmergencyPriceFeeder>::reset_emergency_price(asset_id); + as EmergencyOraclePriceProvider>::reset_emergency_price( + asset_id, + ); Ok(().into()) } @@ -226,7 +228,7 @@ impl Pallet { } } -impl PriceFeeder for Pallet { +impl OraclePriceProvider for Pallet { /// Returns the uniform format price and timestamp by asset id. /// Formula: `price = oracle_price * 10.pow(18 - asset_decimal)` /// We use `oracle_price.checked_div(&FixedU128::from_inner(mantissa))` represent that. @@ -245,16 +247,6 @@ impl PriceFeeder for Pallet { }) } - fn get_normal_price(asset_id: &CurrencyId) -> Option { - let decimals = Self::get_asset_mantissa(asset_id)?; - EmergencyPrice::::get(asset_id) - .and_then(|p| Some(p.into_inner().saturating_div(decimals))) - .or_else(|| { - T::Source::get(&asset_id) - .and_then(|price| Some(price.value.into_inner().saturating_div(decimals))) - }) - } - /// Get the amount of currencies according to the input price data. /// Parameters: /// - `currency_in`: The currency to be converted. @@ -296,13 +288,17 @@ impl PriceFeeder for Pallet { currency_out: &CurrencyId, ) -> Option<(Balance, Price, Price)> { let price_in = Self::get_storage_price(currency_in)?; - let price_out = Self::get_storage_price(currency_out)?; - Self::get_amount_by_prices(currency_in, amount_in, price_in, currency_out, price_out) - .map(|amount_out| (amount_out, price_in, price_out)) + if currency_in == currency_out { + Some((amount_in, price_in, price_in)) + } else { + let price_out = Self::get_storage_price(currency_out)?; + Self::get_amount_by_prices(currency_in, amount_in, price_in, currency_out, price_out) + .map(|amount_out| (amount_out, price_in, price_out)) + } } } -impl EmergencyPriceFeeder for Pallet { +impl EmergencyOraclePriceProvider for Pallet { /// Set emergency price fn set_emergency_price(asset_id: CurrencyId, price: Price) { // set price direct diff --git a/pallets/traits/src/lib.rs b/pallets/traits/src/lib.rs index b51ec1b7d..3de362e4a 100644 --- a/pallets/traits/src/lib.rs +++ b/pallets/traits/src/lib.rs @@ -11,7 +11,7 @@ pub trait EmergencyCallFilter { fn contains(call: &Call) -> bool; } -pub trait EmergencyPriceFeeder { +pub trait EmergencyOraclePriceProvider { fn set_emergency_price(asset_id: CurrencyId, price: Price); fn reset_emergency_price(asset_id: CurrencyId); } diff --git a/primitives/src/price.rs b/primitives/src/price.rs index 22e09d2a5..aaaebe435 100644 --- a/primitives/src/price.rs +++ b/primitives/src/price.rs @@ -18,9 +18,8 @@ use crate::{Balance, CurrencyId, Price, PriceDetail}; -pub trait PriceFeeder { +pub trait OraclePriceProvider { fn get_price(asset_id: &CurrencyId) -> Option; - fn get_normal_price(asset_id: &CurrencyId) -> Option; fn get_amount_by_prices( currency_in: &CurrencyId, amount_in: Balance, diff --git a/runtime/bifrost-kusama/src/lib.rs b/runtime/bifrost-kusama/src/lib.rs index 065d18b90..0e5bf5da9 100644 --- a/runtime/bifrost-kusama/src/lib.rs +++ b/runtime/bifrost-kusama/src/lib.rs @@ -1040,7 +1040,7 @@ impl bifrost_flexible_fee::Config for Runtime { type RelaychainCurrencyId = RelayCurrencyId; type XcmRouter = XcmRouter; type PalletId = FlexibleFeePalletId; - type PriceFeeder = Prices; + type OraclePriceProvider = Prices; } parameter_types! { @@ -1326,7 +1326,7 @@ impl bifrost_fee_share::Config for Runtime { type ControlOrigin = CoreAdminOrCouncil; type WeightInfo = weights::bifrost_fee_share::BifrostWeight; type FeeSharePalletId = FeeSharePalletId; - type PriceFeeder = Prices; + type OraclePriceProvider = Prices; } impl bifrost_cross_in_out::Config for Runtime { @@ -1621,7 +1621,7 @@ impl pallet_prices::Config for Runtime { impl lend_market::Config for Runtime { type RuntimeEvent = RuntimeEvent; type PalletId = LendMarketPalletId; - type PriceFeeder = Prices; + type OraclePriceProvider = Prices; type ReserveOrigin = TechAdminOrCouncil; type UpdateOrigin = TechAdminOrCouncil; type WeightInfo = lend_market::weights::BifrostWeight; diff --git a/runtime/bifrost-polkadot/src/evm/evm_fee.rs b/runtime/bifrost-polkadot/src/evm/evm_fee.rs index 01656d02b..ce0de8c0d 100644 --- a/runtime/bifrost-polkadot/src/evm/evm_fee.rs +++ b/runtime/bifrost-polkadot/src/evm/evm_fee.rs @@ -17,39 +17,38 @@ // along with this program. If not, see . use crate::Currencies; -use bifrost_primitives::{AccountFeeCurrency, Balance, CurrencyId}; -use bifrost_runtime_common::Ratio; -use frame_support::traits::{Get, OnUnbalanced, TryDrop}; +use bifrost_primitives::{ + AccountFeeCurrency, Balance, CurrencyId, OraclePriceProvider, Price, WETH, +}; +use frame_support::traits::TryDrop; use orml_traits::MultiCurrency; use pallet_evm::{AddressMapping, Error, OnChargeEVMTransaction}; use sp_core::{H160, U256}; -use sp_runtime::{ - helpers_128bit::multiply_by_rational_with_rounding, - traits::{Convert, UniqueSaturatedInto}, - Rounding, -}; +use sp_runtime::traits::UniqueSaturatedInto; use sp_std::marker::PhantomData; -#[derive(Copy, Clone, Default)] +#[derive(Copy, Debug, Clone, Default, PartialEq)] pub struct EvmPaymentInfo { - amount: Balance, - currency_id: CurrencyId, - price: Ratio, + fee_amount: Balance, + fee_currency: CurrencyId, + fee_currency_price: Price, + weth_price: Price, } impl EvmPaymentInfo { pub fn merge(self, other: Self) -> Self { EvmPaymentInfo { - amount: self.amount.saturating_add(other.amount), - currency_id: self.currency_id, - price: self.price, + fee_amount: self.fee_amount.saturating_add(other.fee_amount), + fee_currency: self.fee_currency, + fee_currency_price: self.fee_currency_price, + weth_price: self.weth_price, } } } impl TryDrop for EvmPaymentInfo { fn try_drop(self) -> Result<(), Self> { - if self.amount == 0 { + if self.fee_amount == 0 { Ok(()) } else { Err(self) @@ -58,27 +57,21 @@ impl TryDrop for EvmPaymentInfo { } /// Implements the transaction payment for EVM transactions. -/// Supports multi-currency fees based on what is provided by AC - account currency. -pub struct TransferEvmFees(PhantomData<(OU, AC, EC, C, MC)>); +/// Supports multi-currency fees based on what is provided by AccountFeeCurrency - account currency. +pub struct TransferEvmFees(PhantomData<(AC, MC, Price)>); -impl OnChargeEVMTransaction for TransferEvmFees +impl OnChargeEVMTransaction for TransferEvmFees where T: pallet_evm::Config, - OU: OnUnbalanced, - U256: UniqueSaturatedInto, AC: AccountFeeCurrency, // AccountCurrency - EC: Get, // Evm default fee asset - C: Convert<(CurrencyId, CurrencyId, Balance), Option<(Balance, Ratio)>>, /* Conversion from - * default fee - * asset to account - * currency */ - U256: UniqueSaturatedInto, + Price: OraclePriceProvider, // PriceProvider MC: MultiCurrency, + U256: UniqueSaturatedInto, sp_runtime::AccountId32: From<::AccountId>, { type LiquidityInfo = Option; - fn withdraw_fee(who: &H160, fee: U256) -> Result> { + fn withdraw_fee(who: &H160, fee: U256) -> Result> { if fee.is_zero() { return Ok(None); } @@ -87,14 +80,18 @@ where let fee_currency = AC::get_fee_currency(&account_id, fee).map_err(|_| Error::::BalanceLow)?; - let Some((converted, price)) = - C::convert((EC::get(), fee_currency, fee.unique_saturated_into())) + let Some((fee_amount, weth_price, fee_currency_price)) = + Price::get_oracle_amount_by_currency_and_amount_in( + &WETH, + fee.unique_saturated_into(), + &fee_currency, + ) else { return Err(Error::::WithdrawFailed); }; // Ensure that converted fee is not zero - if converted == 0 { + if fee_amount == 0 { return Err(Error::::WithdrawFailed); } @@ -103,13 +100,13 @@ where "Withdrew fee from account {:?} in currency {:?} amount {:?}", account_id, fee_currency, - converted + fee_amount ); - MC::withdraw(fee_currency, &account_id, converted) + MC::withdraw(fee_currency, &account_id, fee_amount) .map_err(|_| Error::::WithdrawFailed)?; - Ok(Some(EvmPaymentInfo { amount: converted, currency_id: fee_currency, price })) + Ok(Some(EvmPaymentInfo { fee_amount, fee_currency, fee_currency_price, weth_price })) } fn correct_and_deposit_fee( @@ -118,71 +115,51 @@ where _base_fee: U256, already_withdrawn: Self::LiquidityInfo, ) -> Self::LiquidityInfo { - if let Some(paid) = already_withdrawn { + if let Some(payment_info) = already_withdrawn { let account_id = T::AddressMapping::into_account_id(*who); - // fee / weth = amounts[1] / amounts[0] - // fee = weth * amounts[1] / amounts[0] - let adjusted_paid = if let Some(converted_corrected_fee) = - multiply_by_rational_with_rounding( - corrected_fee.unique_saturated_into(), - paid.price.n, - paid.price.d, - Rounding::Up, - ) { + let adjusted_paid = if let Some(converted_corrected_fee) = Price::get_amount_by_prices( + &WETH, + corrected_fee.unique_saturated_into(), + payment_info.weth_price, + &payment_info.fee_currency, + payment_info.fee_currency_price, + ) { // Calculate how much refund we should return - let refund_amount = paid.amount.saturating_sub(converted_corrected_fee); + let refund_amount = payment_info.fee_amount.saturating_sub(converted_corrected_fee); // refund to the account that paid the fees. If this fails, the // account might have dropped below the existential balance. In // that case we don't refund anything. let refund_imbalance = - match MC::deposit(paid.currency_id, &account_id, refund_amount) { + match MC::deposit(payment_info.fee_currency, &account_id, refund_amount) { Ok(_) => 0, Err(_) => refund_amount, }; // figure out how much is left to mint back // refund_amount already minted back to account, imbalance is what is left to mint // if any - paid.amount.saturating_sub(refund_amount).saturating_add(refund_imbalance) + payment_info + .fee_amount + .saturating_sub(refund_amount) + .saturating_add(refund_imbalance) } else { // if conversion failed for some reason, we refund the whole amount back to treasury - paid.amount + payment_info.fee_amount }; // We can simply refund all the remaining amount back to treasury - OU::on_unbalanced(EvmPaymentInfo { - amount: adjusted_paid, - currency_id: paid.currency_id, - price: paid.price, - }); - return None; + let result = Currencies::deposit( + payment_info.fee_currency, + &crate::BifrostTreasuryAccount::get(), + adjusted_paid, + ); + debug_assert_eq!(result, Ok(())); } None } fn pay_priority_fee(tip: Self::LiquidityInfo) { - if let Some(tip) = tip { - OU::on_unbalanced(tip); - } - } -} - -pub struct DepositEvmFeeToTreasury; -impl OnUnbalanced for DepositEvmFeeToTreasury { - // this is called for substrate-based transactions - fn on_unbalanceds(amounts: impl Iterator) { - Self::on_unbalanced(amounts.fold(EvmPaymentInfo::default(), |i, x| x.merge(i))) - } - - // this is called from pallet_evm for Ethereum-based transactions - // (technically, it calls on_unbalanced, which calls this when non-zero) - fn on_nonzero_unbalanced(payment_info: EvmPaymentInfo) { - let result = Currencies::deposit( - payment_info.currency_id, - &crate::BifrostTreasuryAccount::get(), - payment_info.amount, - ); - debug_assert_eq!(result, Ok(())); + debug_assert_eq!(tip, None); } } diff --git a/runtime/bifrost-polkadot/src/evm/mod.rs b/runtime/bifrost-polkadot/src/evm/mod.rs index db779492e..9b154e959 100644 --- a/runtime/bifrost-polkadot/src/evm/mod.rs +++ b/runtime/bifrost-polkadot/src/evm/mod.rs @@ -23,17 +23,14 @@ use pallet_evm::EnsureAddressTruncated; use pallet_transaction_payment::Multiplier; use primitive_types::U256; -use bifrost_primitives::{currency::WETH, CurrencyId}; -use bifrost_runtime_common::price::{ - ConvertAmount, FeeAssetBalanceInCurrency, OraclePriceProvider, -}; - pub use crate::evm::accounts_conversion::{ExtendedAddressMapping, FindAuthorTruncated}; use crate::{ - evm::runner::WrapRunner, governance::TechAdminOrCouncil, Aura, ConstU32, DynamicFee, - EVMChainId, Prices, Runtime, RuntimeEvent, Timestamp, Weight, EVM, MAXIMUM_BLOCK_WEIGHT, - NORMAL_DISPATCH_RATIO, WEIGHT_REF_TIME_PER_SECOND, + evm::runner::{FeeAssetBalanceInCurrency, WrapRunner}, + governance::TechAdminOrCouncil, + Aura, ConstU32, DynamicFee, EVMChainId, Runtime, RuntimeEvent, Timestamp, Weight, EVM, + MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, WEIGHT_REF_TIME_PER_SECOND, }; +use bifrost_primitives::{currency::WETH, CurrencyId}; mod accounts_conversion; mod evm_fee; @@ -107,18 +104,16 @@ impl pallet_evm::Config for Runtime { Self, pallet_evm::runner::stack::Runner, // Evm runner that we wrap FeeAssetBalanceInCurrency< - crate::Runtime, - ConvertAmount>, + Runtime, + crate::Prices, // Price provider crate::FlexibleFee, // Get account's fee payment asset crate::Currencies, // Account balance inspector >, >; type OnChargeTransaction = evm_fee::TransferEvmFees< - evm_fee::DepositEvmFeeToTreasury, crate::FlexibleFee, // Get account's fee payment asset - WethAssetId, - ConvertAmount>, - crate::Currencies, // Multi currency support + crate::Currencies, // Multi currency support + crate::Prices, // Price provider >; type OnCreate = (); type FindAuthor = FindAuthorTruncated; diff --git a/runtime/bifrost-polkadot/src/evm/runner.rs b/runtime/bifrost-polkadot/src/evm/runner.rs index 4e1e1058c..1bce82653 100644 --- a/runtime/bifrost-polkadot/src/evm/runner.rs +++ b/runtime/bifrost-polkadot/src/evm/runner.rs @@ -22,16 +22,68 @@ //! asset. //! //! Shamelessly copied from pallet-evm and modified to support multi-currency fees. + use crate::{evm::WethAssetId, Weight}; -use bifrost_primitives::{AccountFeeCurrencyBalanceInCurrency, Balance}; +use bifrost_primitives::{ + AccountFeeCurrency, AccountFeeCurrencyBalanceInCurrency, Balance, CurrencyId, + OraclePriceProvider, +}; use fp_evm::{Account, TransactionValidationError}; -use frame_support::traits::Get; +use frame_support::traits::{ + tokens::{Fortitude, Preservation}, + Get, +}; use pallet_evm::{ runner::Runner, AddressMapping, CallInfo, Config, CreateInfo, FeeCalculator, RunnerError, }; use primitive_types::{H160, H256, U256}; -use sp_runtime::traits::UniqueSaturatedInto; -use sp_std::vec::Vec; +use sp_runtime::{traits::UniqueSaturatedInto, DispatchError}; +use sp_std::{marker::PhantomData, vec::Vec}; + +/// AccountFeeCurrencyBalanceInCurrency implementation for the FeeAssetBalanceInCurrency. +/// Provides account's balance of fee asset currency in a given currency +pub struct FeeAssetBalanceInCurrency(PhantomData<(T, Price, AC, I)>); + +impl AccountFeeCurrencyBalanceInCurrency + for FeeAssetBalanceInCurrency +where + T: frame_system::Config, + Price: OraclePriceProvider, + AC: AccountFeeCurrency, + I: frame_support::traits::fungibles::Inspect< + T::AccountId, + AssetId = CurrencyId, + Balance = Balance, + >, +{ + type Output = (Balance, Weight); + type Error = DispatchError; + + fn get_balance_in_currency( + to_currency: CurrencyId, + account: &T::AccountId, + fee: U256, + ) -> Result { + let from_currency = AC::get_fee_currency(account, fee) + .map_err(|_| DispatchError::Other("Get Currency Error."))?; + let account_balance = + I::reducible_balance(from_currency, account, Preservation::Preserve, Fortitude::Polite); + let price_weight = T::DbWeight::get().reads(2); // 1 read to get currency and 1 read to get balance + + if from_currency == to_currency { + return Ok((account_balance, price_weight)); + } + + let Some((converted, _, _)) = Price::get_oracle_amount_by_currency_and_amount_in( + &from_currency, + account_balance, + &to_currency, + ) else { + return Ok((0, price_weight)); + }; + Ok((converted, price_weight)) + } +} pub struct WrapRunner(sp_std::marker::PhantomData<(T, R, B)>); diff --git a/runtime/bifrost-polkadot/src/lib.rs b/runtime/bifrost-polkadot/src/lib.rs index e95f50633..6560618d8 100644 --- a/runtime/bifrost-polkadot/src/lib.rs +++ b/runtime/bifrost-polkadot/src/lib.rs @@ -925,7 +925,7 @@ impl bifrost_flexible_fee::Config for Runtime { type RelaychainCurrencyId = RelayCurrencyId; type XcmRouter = XcmRouter; type PalletId = FlexibleFeePalletId; - type PriceFeeder = Prices; + type OraclePriceProvider = Prices; } parameter_types! { @@ -1187,7 +1187,7 @@ impl bifrost_fee_share::Config for Runtime { type ControlOrigin = CoreAdminOrCouncil; type WeightInfo = weights::bifrost_fee_share::BifrostWeight; type FeeSharePalletId = FeeSharePalletId; - type PriceFeeder = Prices; + type OraclePriceProvider = Prices; } impl bifrost_cross_in_out::Config for Runtime { @@ -1462,7 +1462,7 @@ impl pallet_prices::Config for Runtime { impl lend_market::Config for Runtime { type RuntimeEvent = RuntimeEvent; type PalletId = LendMarketPalletId; - type PriceFeeder = Prices; + type OraclePriceProvider = Prices; type ReserveOrigin = TechAdminOrCouncil; type UpdateOrigin = TechAdminOrCouncil; type WeightInfo = lend_market::weights::BifrostWeight; diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index 4b44c00e4..c7fccfce8 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -32,10 +32,6 @@ use sp_runtime::{traits::Bounded, FixedPointNumber, Perquintill}; pub mod constants; pub mod currency_adapter; pub mod currency_converter; -pub mod price; -pub mod ratio; - -pub use ratio::Ratio; #[cfg(test)] mod tests; diff --git a/runtime/common/src/price.rs b/runtime/common/src/price.rs deleted file mode 100644 index c4e628af7..000000000 --- a/runtime/common/src/price.rs +++ /dev/null @@ -1,116 +0,0 @@ -// This file is part of Bifrost. - -// Copyright (C) Liebi Technologies PTE. 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 frame_support::{ - pallet_prelude::Get, - traits::tokens::{Fortitude, Preservation}, -}; -use sp_core::U256; -use sp_runtime::{ - helpers_128bit::multiply_by_rational_with_rounding, traits::Convert, DispatchError, Rounding, -}; -use sp_std::marker::PhantomData; -use xcm::latest::Weight; - -use bifrost_primitives::{ - AccountFeeCurrency, AccountFeeCurrencyBalanceInCurrency, Balance, CurrencyId, PriceFeeder, - PriceProvider, -}; - -use crate::Ratio; - -pub struct OraclePriceProvider(PhantomData); - -impl PriceProvider for OraclePriceProvider -where - PF: PriceFeeder, -{ - type Price = Ratio; - - fn get_price(asset_a: CurrencyId, asset_b: CurrencyId) -> Option { - if let Some(a) = PF::get_normal_price(&asset_a) { - if let Some(b) = PF::get_normal_price(&asset_b) { - Some(Ratio::from((a, b))) - } else { - None - } - } else { - None - } - } -} - -pub struct FeeAssetBalanceInCurrency(PhantomData<(T, C, AC, I)>); - -impl AccountFeeCurrencyBalanceInCurrency - for FeeAssetBalanceInCurrency -where - T: frame_system::Config, - C: Convert<(CurrencyId, CurrencyId, Balance), Option<(Balance, Ratio)>>, - AC: AccountFeeCurrency, - I: frame_support::traits::fungibles::Inspect< - T::AccountId, - AssetId = CurrencyId, - Balance = Balance, - >, -{ - type Output = (Balance, Weight); - type Error = DispatchError; - - fn get_balance_in_currency( - to_currency: CurrencyId, - account: &T::AccountId, - fee: U256, - ) -> Result { - let from_currency = AC::get_fee_currency(account, fee) - .map_err(|_| DispatchError::Other("Get Currency Error."))?; - let account_balance = - I::reducible_balance(from_currency, account, Preservation::Preserve, Fortitude::Polite); - let price_weight = T::DbWeight::get().reads(2); // 1 read to get currency and 1 read to get balance - - if from_currency == to_currency { - return Ok((account_balance, price_weight)); - } - - let Some((converted, _)) = C::convert((from_currency, to_currency, account_balance)) else { - return Ok((0, price_weight)); - }; - Ok((converted, price_weight)) - } -} - -pub struct ConvertAmount

(PhantomData

); - -// Converts `amount` of `from_currency` to `to_currency` using given oracle -// Input: (from_currency, to_currency, amount) -// Output: Option<(converted_amount, price)> -impl

Convert<(CurrencyId, CurrencyId, Balance), Option<(Balance, Ratio)>> for ConvertAmount

-where - P: PriceProvider, -{ - fn convert( - (from_currency, to_currency, amount): (CurrencyId, CurrencyId, Balance), - ) -> Option<(Balance, Ratio)> { - if from_currency == to_currency { - return Some((amount, Ratio::one())); - } - let price = P::get_price(from_currency, to_currency)?; - let converted = multiply_by_rational_with_rounding(amount, price.n, price.d, Rounding::Up)?; - Some((converted, price)) - } -} diff --git a/runtime/common/src/ratio.rs b/runtime/common/src/ratio.rs deleted file mode 100644 index 01022e8e7..000000000 --- a/runtime/common/src/ratio.rs +++ /dev/null @@ -1,154 +0,0 @@ -// This file is part of Bifrost. - -// Copyright (C) Liebi Technologies PTE. 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 core::cmp::{Ord, Ordering, PartialOrd}; -use num_traits::Zero; -use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; -use serde::{Deserialize, Serialize}; -use sp_arithmetic::helpers_128bit; - -/// A rational number represented by a `n`umerator and `d`enominator. -#[derive( - Clone, - Copy, - Default, - PartialEq, - Eq, - Encode, - Decode, - Serialize, - Deserialize, - TypeInfo, - MaxEncodedLen, -)] -pub struct Ratio { - pub n: u128, - pub d: u128, -} - -impl Ratio { - /// Build from a raw `n/d`. Ensures that `d > 0`. - pub const fn new(n: u128, d: u128) -> Self { - // reimplement `.max(1)` so this can be `const` - let d = if d > 0 { d } else { 1 }; - Self { n, d } - } - - /// Build from a raw `n/d`. This could lead to / 0 if not properly handled. - pub const fn new_unchecked(n: u128, d: u128) -> Self { - Self { n, d } - } - - /// Return a representation of one. - /// - /// Note that more than one combination of `n` and `d` can be one. - pub const fn one() -> Self { - Self::new_unchecked(1, 1) - } - - /// Return whether `self` is one. - /// - /// Should a denominator of 0 happen, this function will return `false`. - /// - /// Note that more than one combination of `n` and `d` can be one. - pub const fn is_one(&self) -> bool { - self.d > 0 && self.n == self.d - } - - /// Return a representation of zero. - /// - /// Note that any combination of `n == 0` and `d` represents zero. - pub const fn zero() -> Self { - Self::new_unchecked(0, 1) - } - - /// Return whether `self` is zero. - /// - /// Note that any combination of `n == 0` and `d` represents zero. - pub const fn is_zero(&self) -> bool { - self.n == 0 - } - - /// Invert `n/d` to `d/n`. - /// - /// NOTE: Zero inverts to zero. - pub const fn inverted(self) -> Self { - if self.is_zero() { - self - } else { - Self { n: self.d, d: self.n } - } - } -} - -impl From for (u128, u128) { - fn from(ratio: Ratio) -> (u128, u128) { - (ratio.n, ratio.d) - } -} - -impl From for Ratio { - fn from(n: u128) -> Self { - Self::new(n, 1) - } -} - -impl From<(u128, u128)> for Ratio { - fn from((n, d): (u128, u128)) -> Self { - Self::new(n, d) - } -} - -impl PartialOrd for Ratio { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -// Taken from Substrate's `Rational128`. -impl Ord for Ratio { - fn cmp(&self, other: &Self) -> Ordering { - if self.d == other.d { - self.n.cmp(&other.n) - } else if self.d.is_zero() { - Ordering::Greater - } else if other.d.is_zero() { - Ordering::Less - } else { - let self_n = helpers_128bit::to_big_uint(self.n) * helpers_128bit::to_big_uint(other.d); - let other_n = - helpers_128bit::to_big_uint(other.n) * helpers_128bit::to_big_uint(self.d); - self_n.cmp(&other_n) - } - } -} - -#[cfg(feature = "std")] -impl sp_std::fmt::Debug for Ratio { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - write!(f, "Ratio({} / {} ≈ {:.8})", self.n, self.d, self.n as f64 / self.d as f64) - } -} - -#[cfg(not(feature = "std"))] -impl sp_std::fmt::Debug for Ratio { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - write!(f, "Ratio({} / {})", self.n, self.d) - } -} From 1a87eecda03607ecac5c8eaeb501bc5e29cf078e Mon Sep 17 00:00:00 2001 From: MJLNSN <96321798+MJLNSN@users.noreply.github.com> Date: Wed, 25 Sep 2024 10:20:52 +0800 Subject: [PATCH 04/30] Moved PalletId and AccountId to primitives. (#1437) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Bifrost v0.13.0 * Remove getter in buy-back. (#1354) * Bifrost v0.12.0 * remove old migrations * Fix vtokenVoting.removeDelegatorVote (#1288) * add PollClass type * add the calss parameter to the remove_delegator_vote method * Add metadata hash (#1299) * feat: 🎸 add buy-back * Bifrost v0.10.001 * feat: 🎸 benchmark * SLPx mint support commission id (#1261) * Add vtoken exchange rate rpc (#1260) * fix: 🐛 add event (#1263) * add update_currency_metadata function (#1259) * add update_currency_metadata function * fix: 🐛 correct update_currency_metadata weight * add the use of Vec (#1264) * Add vtoken exchange rate rpc * add the use of Vec * Upgrade to Polkadot-SDK v1.7.0 (#1262) * Bifrost v0.10.0 * fix: 🐛 clippy * Fix chain spec (#1243) * Upgrade to polkadot-v1.7.0 --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: Edwin Wang * Fix compile * feat: 🎸 add metadata-hash-extension (#1265) * feat: 🎸 add metadata-hash-extension * Fix compile (#1266) * Fix/fix vtoken voting unlock (#1267) * update the exchange rate of vtokenminting of vtokenvoting test * Resolve the frozen anomaly when unlocking * Revert "feat: 🎸 add metadata-hash-extension (#1265)" (#1268) This reverts commit 489fc9c6adeae44d23edf449e74fde3d6aa40bc3. * rename the version number to 0.11.0 * Slp supports XCMv4 and reconstruct integration tests (#1272) * Fix compile * Reconstruct integration tests and slp supports XCMv4 * Fix slp construct_xcm_message * Feat/slpx mint add commission (#1273) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * Feat/add vtoken exchange rate rpc (#1274) * Add vtoken exchange rate rpc * add the use of Vec * supplement the RPC logic && fix bugs * adjust the RPC exchange rate precision to three decimal places * fix clippy * fix bug: storage migration anomaly (#1276) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * fix bug: storage migration anomaly * Slp removes refund (#1275) * Slp removes refund * Fix clippy * Feat/add vtoken exchange rate rpc (#1277) * Add vtoken exchange rate rpc * add the use of Vec * supplement the RPC logic && fix bugs * adjust the RPC exchange rate precision to three decimal places * fix clippy * supplement omissions: adjust the RPC exchange rate precision to three decimal places * Remove dmp queue (#1279) * fix: 🐛 CheckMetadataHash to false * fix: 🐛 update sp-api * refactor: 💡 fmt * fix: 🐛 add metadata-hash * fix: 🐛 add feature metadata-hash * fix: 🐛 rm metadata-hash feature --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Co-authored-by: NingBo Wang <2536935847@qq.com> Co-authored-by: Edwin Wang * refactor: 💡 update MaxTurnout and whitelisted_caller track (#1304) * Allow to receive and send Ethereum assets (#1305) * feat: 🎸 add buy-back * Bifrost v0.10.001 * feat: 🎸 benchmark * SLPx mint support commission id (#1261) * Add vtoken exchange rate rpc (#1260) * fix: 🐛 add event (#1263) * add update_currency_metadata function (#1259) * add update_currency_metadata function * fix: 🐛 correct update_currency_metadata weight * add the use of Vec (#1264) * Add vtoken exchange rate rpc * add the use of Vec * Upgrade to Polkadot-SDK v1.7.0 (#1262) * Bifrost v0.10.0 * fix: 🐛 clippy * Fix chain spec (#1243) * Upgrade to polkadot-v1.7.0 --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: Edwin Wang * feat: 🎸 add metadata-hash-extension (#1265) * Fix compile (#1266) * Fix/fix vtoken voting unlock (#1267) * update the exchange rate of vtokenminting of vtokenvoting test * Resolve the frozen anomaly when unlocking * Revert "feat: 🎸 add metadata-hash-extension (#1265)" (#1268) This reverts commit 489fc9c6adeae44d23edf449e74fde3d6aa40bc3. * rename the version number to 0.11.0 * Slp supports XCMv4 and reconstruct integration tests (#1272) * Fix compile * Reconstruct integration tests and slp supports XCMv4 * Fix slp construct_xcm_message * Feat/slpx mint add commission (#1273) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * Feat/add vtoken exchange rate rpc (#1274) * Add vtoken exchange rate rpc * add the use of Vec * supplement the RPC logic && fix bugs * adjust the RPC exchange rate precision to three decimal places * fix clippy * fix bug: storage migration anomaly (#1276) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * fix bug: storage migration anomaly * Slp removes refund (#1275) * Slp removes refund * Fix clippy * Allow to receive and send Ethereum assets * Add constants --------- Co-authored-by: yooml Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Co-authored-by: Edwin Wang * Disable supplement_fee_reserve (#1306) * Remove call_switchgear and add tx_pause (#1308) * Remove call_switchgear and add tx_pause * Fix clippy * Optimize flexible fee (#1307) * Optimize flexible fee * Fix bug * Fix bug * Add PalletId * Add error handle * feat: 🎸 add market-bond * fix: 🐛 test-all * fix: 🐛 try-runtime * Add the channel_id field to the Minted event * Upgrade to polkadot-v1.13.0 (#1312) * Upgrade to polkadot-v1.13.0 * remove the warning * Fix dep issues * Upgrade to polkadot-v1.13.0 * supplement and upgrade the code * Upgrade the new parts from v0.12.0 * Fix dep issues * format Cargo.toml * Modify the AddOrigin type of the fellowship in bifrost-polkadot * Cancel the cross-in-out migration. * fix clippy --------- Co-authored-by: hqwangningbo <2536935847@qq.com> * Use github dependencies (#1314) * Fix flexible_fee TransferTo (#1315) * Fix generate_genesis_state (#1317) * Optimize oracle (#1318) * refactor: 💡 optimize orml-oracle * fix: 🐛 MinimumTimestampInterval * style: 💄 rename to MaximumValueInterval * Add some tests for ve-minting * Add some tests for ve-minting * Integrate evm (#1319) * Update dep * Ingrate EVM * Fix deps * Add precompiles.rs * Remove pallet-hotfix-sufficients * Add pallet-evm-accounts * Evm precompiles * EVM integration * Fix compile * Fix rpc * Fix `encode_evm_address` and `decode_evm_address` * Fix evm precompile multicurrency * Implementing Erc20Mapping using xc-20 standard * Compatible with BNC Decimal * Increase min_gas_price * feat: enable dev mode with manual seal & fix pending block problem * Add copyright and fix some bugs * Change native token to WETH * Support evm flexible fee * Add inner_swap_exact_assets_for_assets to evm withdraw fee * Remove swap * EVM migration from bifrost kusama to bifrost polkadot * Fix erc20 precompile * Use OraclePrice * Fix some errors * feat: add prices genesis config & optimize dev mode code * Fix conflicts * Fix some errors * Fix clippy * Format Cargo.toml * Remove unused code * Fix clippy * Fix some errors * Fix erc20 precompile --------- Co-authored-by: Edwin Wang Co-authored-by: Damian.lu * Fix try-runtime (#1323) * Fix manual seal * Fix manual seal (#1324) * fix: 🐛 fellowship collective data (#1325) * fix: add parachain mock inherent data provider * Fix ethereum transfer fee (#1328) * Add evm genesis migration (#1338) * Bifrost v0.12.0 (#1286) * Bifrost v0.12.0 * remove old migrations * Fix vtokenVoting.removeDelegatorVote (#1288) * add PollClass type * add the calss parameter to the remove_delegator_vote method * Add metadata hash (#1299) * feat: 🎸 add buy-back * Bifrost v0.10.001 * feat: 🎸 benchmark * SLPx mint support commission id (#1261) * Add vtoken exchange rate rpc (#1260) * fix: 🐛 add event (#1263) * add update_currency_metadata function (#1259) * add update_currency_metadata function * fix: 🐛 correct update_currency_metadata weight * add the use of Vec (#1264) * Add vtoken exchange rate rpc * add the use of Vec * Upgrade to Polkadot-SDK v1.7.0 (#1262) * Bifrost v0.10.0 * fix: 🐛 clippy * Fix chain spec (#1243) * Upgrade to polkadot-v1.7.0 --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: Edwin Wang * Fix compile * feat: 🎸 add metadata-hash-extension (#1265) * feat: 🎸 add metadata-hash-extension * Fix compile (#1266) * Fix/fix vtoken voting unlock (#1267) * update the exchange rate of vtokenminting of vtokenvoting test * Resolve the frozen anomaly when unlocking * Revert "feat: 🎸 add metadata-hash-extension (#1265)" (#1268) This reverts commit 489fc9c6adeae44d23edf449e74fde3d6aa40bc3. * rename the version number to 0.11.0 * Slp supports XCMv4 and reconstruct integration tests (#1272) * Fix compile * Reconstruct integration tests and slp supports XCMv4 * Fix slp construct_xcm_message * Feat/slpx mint add commission (#1273) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * Feat/add vtoken exchange rate rpc (#1274) * Add vtoken exchange rate rpc * add the use of Vec * supplement the RPC logic && fix bugs * adjust the RPC exchange rate precision to three decimal places * fix clippy * fix bug: storage migration anomaly (#1276) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * fix bug: storage migration anomaly * Slp removes refund (#1275) * Slp removes refund * Fix clippy * Feat/add vtoken exchange rate rpc (#1277) * Add vtoken exchange rate rpc * add the use of Vec * supplement the RPC logic && fix bugs * adjust the RPC exchange rate precision to three decimal places * fix clippy * supplement omissions: adjust the RPC exchange rate precision to three decimal places * Remove dmp queue (#1279) * fix: 🐛 CheckMetadataHash to false * fix: 🐛 update sp-api * refactor: 💡 fmt * fix: 🐛 add metadata-hash * fix: 🐛 add feature metadata-hash * fix: 🐛 rm metadata-hash feature --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Co-authored-by: NingBo Wang <2536935847@qq.com> Co-authored-by: Edwin Wang * refactor: 💡 update MaxTurnout and whitelisted_caller track (#1304) * Allow to receive and send Ethereum assets (#1305) * feat: 🎸 add buy-back * Bifrost v0.10.001 * feat: 🎸 benchmark * SLPx mint support commission id (#1261) * Add vtoken exchange rate rpc (#1260) * fix: 🐛 add event (#1263) * add update_currency_metadata function (#1259) * add update_currency_metadata function * fix: 🐛 correct update_currency_metadata weight * add the use of Vec (#1264) * Add vtoken exchange rate rpc * add the use of Vec * Upgrade to Polkadot-SDK v1.7.0 (#1262) * Bifrost v0.10.0 * fix: 🐛 clippy * Fix chain spec (#1243) * Upgrade to polkadot-v1.7.0 --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: Edwin Wang * feat: 🎸 add metadata-hash-extension (#1265) * Fix compile (#1266) * Fix/fix vtoken voting unlock (#1267) * update the exchange rate of vtokenminting of vtokenvoting test * Resolve the frozen anomaly when unlocking * Revert "feat: 🎸 add metadata-hash-extension (#1265)" (#1268) This reverts commit 489fc9c6adeae44d23edf449e74fde3d6aa40bc3. * rename the version number to 0.11.0 * Slp supports XCMv4 and reconstruct integration tests (#1272) * Fix compile * Reconstruct integration tests and slp supports XCMv4 * Fix slp construct_xcm_message * Feat/slpx mint add commission (#1273) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * Feat/add vtoken exchange rate rpc (#1274) * Add vtoken exchange rate rpc * add the use of Vec * supplement the RPC logic && fix bugs * adjust the RPC exchange rate precision to three decimal places * fix clippy * fix bug: storage migration anomaly (#1276) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * fix bug: storage migration anomaly * Slp removes refund (#1275) * Slp removes refund * Fix clippy * Allow to receive and send Ethereum assets * Add constants --------- Co-authored-by: yooml Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Co-authored-by: Edwin Wang * Disable supplement_fee_reserve (#1306) * Remove call_switchgear and add tx_pause (#1308) * Remove call_switchgear and add tx_pause * Fix clippy * Optimize flexible fee (#1307) * Optimize flexible fee * Fix bug * Fix bug * Add PalletId * Add error handle * feat: 🎸 add market-bond * fix: 🐛 test-all * fix: 🐛 try-runtime * Add the channel_id field to the Minted event * Upgrade to polkadot-v1.13.0 (#1312) * Upgrade to polkadot-v1.13.0 * remove the warning * Fix dep issues * Upgrade to polkadot-v1.13.0 * supplement and upgrade the code * Upgrade the new parts from v0.12.0 * Fix dep issues * format Cargo.toml * Modify the AddOrigin type of the fellowship in bifrost-polkadot * Cancel the cross-in-out migration. * fix clippy --------- Co-authored-by: hqwangningbo <2536935847@qq.com> * Use github dependencies (#1314) * Fix flexible_fee TransferTo (#1315) * Fix generate_genesis_state (#1317) * Optimize oracle (#1318) * refactor: 💡 optimize orml-oracle * fix: 🐛 MinimumTimestampInterval * style: 💄 rename to MaximumValueInterval * Add some tests for ve-minting * Add some tests for ve-minting * Integrate evm (#1319) * Update dep * Ingrate EVM * Fix deps * Add precompiles.rs * Remove pallet-hotfix-sufficients * Add pallet-evm-accounts * Evm precompiles * EVM integration * Fix compile * Fix rpc * Fix `encode_evm_address` and `decode_evm_address` * Fix evm precompile multicurrency * Implementing Erc20Mapping using xc-20 standard * Compatible with BNC Decimal * Increase min_gas_price * feat: enable dev mode with manual seal & fix pending block problem * Add copyright and fix some bugs * Change native token to WETH * Support evm flexible fee * Add inner_swap_exact_assets_for_assets to evm withdraw fee * Remove swap * EVM migration from bifrost kusama to bifrost polkadot * Fix erc20 precompile * Use OraclePrice * Fix some errors * feat: add prices genesis config & optimize dev mode code * Fix conflicts * Fix some errors * Fix clippy * Format Cargo.toml * Remove unused code * Fix clippy * Fix some errors * Fix erc20 precompile --------- Co-authored-by: Edwin Wang Co-authored-by: Damian.lu * Fix try-runtime (#1323) * Fix manual seal * Fix manual seal (#1324) * fix: 🐛 fellowship collective data (#1325) * fix: add parachain mock inherent data provider * Fix ethereum transfer fee (#1328) --------- Co-authored-by: Edwin Wang Co-authored-by: yooml Co-authored-by: NingBo Wang <2536935847@qq.com> Co-authored-by: Gemma Co-authored-by: Damian.lu * Add evm genesis storage * [skip ci] Add evmSince --------- Co-authored-by: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Co-authored-by: Edwin Wang Co-authored-by: yooml Co-authored-by: Gemma Co-authored-by: Damian.lu * Bump version to 0.12.1 * Update Cargo.lock * Fix migration (#1341) * Bifrost v0.12.0 (#1286) * Bifrost v0.12.0 * remove old migrations * Fix vtokenVoting.removeDelegatorVote (#1288) * add PollClass type * add the calss parameter to the remove_delegator_vote method * Add metadata hash (#1299) * feat: 🎸 add buy-back * Bifrost v0.10.001 * feat: 🎸 benchmark * SLPx mint support commission id (#1261) * Add vtoken exchange rate rpc (#1260) * fix: 🐛 add event (#1263) * add update_currency_metadata function (#1259) * add update_currency_metadata function * fix: 🐛 correct update_currency_metadata weight * add the use of Vec (#1264) * Add vtoken exchange rate rpc * add the use of Vec * Upgrade to Polkadot-SDK v1.7.0 (#1262) * Bifrost v0.10.0 * fix: 🐛 clippy * Fix chain spec (#1243) * Upgrade to polkadot-v1.7.0 --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: Edwin Wang * Fix compile * feat: 🎸 add metadata-hash-extension (#1265) * feat: 🎸 add metadata-hash-extension * Fix compile (#1266) * Fix/fix vtoken voting unlock (#1267) * update the exchange rate of vtokenminting of vtokenvoting test * Resolve the frozen anomaly when unlocking * Revert "feat: 🎸 add metadata-hash-extension (#1265)" (#1268) This reverts commit 489fc9c6adeae44d23edf449e74fde3d6aa40bc3. * rename the version number to 0.11.0 * Slp supports XCMv4 and reconstruct integration tests (#1272) * Fix compile * Reconstruct integration tests and slp supports XCMv4 * Fix slp construct_xcm_message * Feat/slpx mint add commission (#1273) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * Feat/add vtoken exchange rate rpc (#1274) * Add vtoken exchange rate rpc * add the use of Vec * supplement the RPC logic && fix bugs * adjust the RPC exchange rate precision to three decimal places * fix clippy * fix bug: storage migration anomaly (#1276) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * fix bug: storage migration anomaly * Slp removes refund (#1275) * Slp removes refund * Fix clippy * Feat/add vtoken exchange rate rpc (#1277) * Add vtoken exchange rate rpc * add the use of Vec * supplement the RPC logic && fix bugs * adjust the RPC exchange rate precision to three decimal places * fix clippy * supplement omissions: adjust the RPC exchange rate precision to three decimal places * Remove dmp queue (#1279) * fix: 🐛 CheckMetadataHash to false * fix: 🐛 update sp-api * refactor: 💡 fmt * fix: 🐛 add metadata-hash * fix: 🐛 add feature metadata-hash * fix: 🐛 rm metadata-hash feature --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Co-authored-by: NingBo Wang <2536935847@qq.com> Co-authored-by: Edwin Wang * refactor: 💡 update MaxTurnout and whitelisted_caller track (#1304) * Allow to receive and send Ethereum assets (#1305) * feat: 🎸 add buy-back * Bifrost v0.10.001 * feat: 🎸 benchmark * SLPx mint support commission id (#1261) * Add vtoken exchange rate rpc (#1260) * fix: 🐛 add event (#1263) * add update_currency_metadata function (#1259) * add update_currency_metadata function * fix: 🐛 correct update_currency_metadata weight * add the use of Vec (#1264) * Add vtoken exchange rate rpc * add the use of Vec * Upgrade to Polkadot-SDK v1.7.0 (#1262) * Bifrost v0.10.0 * fix: 🐛 clippy * Fix chain spec (#1243) * Upgrade to polkadot-v1.7.0 --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: Edwin Wang * feat: 🎸 add metadata-hash-extension (#1265) * Fix compile (#1266) * Fix/fix vtoken voting unlock (#1267) * update the exchange rate of vtokenminting of vtokenvoting test * Resolve the frozen anomaly when unlocking * Revert "feat: 🎸 add metadata-hash-extension (#1265)" (#1268) This reverts commit 489fc9c6adeae44d23edf449e74fde3d6aa40bc3. * rename the version number to 0.11.0 * Slp supports XCMv4 and reconstruct integration tests (#1272) * Fix compile * Reconstruct integration tests and slp supports XCMv4 * Fix slp construct_xcm_message * Feat/slpx mint add commission (#1273) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * Feat/add vtoken exchange rate rpc (#1274) * Add vtoken exchange rate rpc * add the use of Vec * supplement the RPC logic && fix bugs * adjust the RPC exchange rate precision to three decimal places * fix clippy * fix bug: storage migration anomaly (#1276) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * fix bug: storage migration anomaly * Slp removes refund (#1275) * Slp removes refund * Fix clippy * Allow to receive and send Ethereum assets * Add constants --------- Co-authored-by: yooml Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Co-authored-by: Edwin Wang * Disable supplement_fee_reserve (#1306) * Remove call_switchgear and add tx_pause (#1308) * Remove call_switchgear and add tx_pause * Fix clippy * Optimize flexible fee (#1307) * Optimize flexible fee * Fix bug * Fix bug * Add PalletId * Add error handle * feat: 🎸 add market-bond * fix: 🐛 test-all * fix: 🐛 try-runtime * Add the channel_id field to the Minted event * Upgrade to polkadot-v1.13.0 (#1312) * Upgrade to polkadot-v1.13.0 * remove the warning * Fix dep issues * Upgrade to polkadot-v1.13.0 * supplement and upgrade the code * Upgrade the new parts from v0.12.0 * Fix dep issues * format Cargo.toml * Modify the AddOrigin type of the fellowship in bifrost-polkadot * Cancel the cross-in-out migration. * fix clippy --------- Co-authored-by: hqwangningbo <2536935847@qq.com> * Use github dependencies (#1314) * Fix flexible_fee TransferTo (#1315) * Fix generate_genesis_state (#1317) * Optimize oracle (#1318) * refactor: 💡 optimize orml-oracle * fix: 🐛 MinimumTimestampInterval * style: 💄 rename to MaximumValueInterval * Add some tests for ve-minting * Add some tests for ve-minting * Integrate evm (#1319) * Update dep * Ingrate EVM * Fix deps * Add precompiles.rs * Remove pallet-hotfix-sufficients * Add pallet-evm-accounts * Evm precompiles * EVM integration * Fix compile * Fix rpc * Fix `encode_evm_address` and `decode_evm_address` * Fix evm precompile multicurrency * Implementing Erc20Mapping using xc-20 standard * Compatible with BNC Decimal * Increase min_gas_price * feat: enable dev mode with manual seal & fix pending block problem * Add copyright and fix some bugs * Change native token to WETH * Support evm flexible fee * Add inner_swap_exact_assets_for_assets to evm withdraw fee * Remove swap * EVM migration from bifrost kusama to bifrost polkadot * Fix erc20 precompile * Use OraclePrice * Fix some errors * feat: add prices genesis config & optimize dev mode code * Fix conflicts * Fix some errors * Fix clippy * Format Cargo.toml * Remove unused code * Fix clippy * Fix some errors * Fix erc20 precompile --------- Co-authored-by: Edwin Wang Co-authored-by: Damian.lu * Fix try-runtime (#1323) * Fix manual seal * Fix manual seal (#1324) * fix: 🐛 fellowship collective data (#1325) * fix: add parachain mock inherent data provider * Fix ethereum transfer fee (#1328) --------- Co-authored-by: Edwin Wang Co-authored-by: yooml Co-authored-by: NingBo Wang <2536935847@qq.com> Co-authored-by: Gemma Co-authored-by: Damian.lu * Add evm genesis storage * [skip ci] Add evmSince * Fix migration * Fix migration * Remove unused code --------- Co-authored-by: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Co-authored-by: Edwin Wang Co-authored-by: yooml Co-authored-by: Gemma Co-authored-by: Damian.lu * Remove getter in buy-back --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Co-authored-by: Edwin Wang Co-authored-by: yooml Co-authored-by: NingBo Wang <2536935847@qq.com> Co-authored-by: Damian.lu * Remove getters in xcm-interface (#1352) * Remove getters in salp. (#1351) * Remove getter in evm-accounts (#1350) * Remove getters in slp (#1353) * Remove getters in slpx (#1360) * Remove getters in vstoken-conversion. (#1362) * Remove getters in vtoken-minting. (#1363) * Remove getter in system-maker. (#1364) * Remove getter in fee-share (#1365) * Remove getters in prices (#1367) * Remove getters in lend-market (#1366) * Remove getters in ve-minting (#1368) * Optimize clippy (#1369) * Deprecated unused pallets (#1383) * Review format (#1386) * style: 💄 format * style: 💄 check-all * fix: 🐛 bench * Update buy back (#1387) * style: 💄 format * style: 💄 check-all * fix: 🐛 bench * feat: 🎸 add destruction_ratio * fix: 🐛 benchmark * EVM flexible fee logic optimization (#1370) * EVM flexible fee logic optimization * Add comments * Add support for handling different currency precisions & included error handling. * Adjust the gas_fee parameter in the get_balance_in_currency method to an exact value * fix clippy * add test code of flexiable-fee pallet * Update fee share (#1395) * feat: 🎸 add usd_cumulation * feat: 🎸 bench * fix: 🐛 fmt * docs: ✏️ add note * Feat/change evm address convert rule (#1396) * Change EVM Address convert rule * Change EVM Address convert rule * Remove the unused function:is_evm_account & rename truncated_account_id function to convert_account_id * fix clippy * refactor: 💡 move to TechAdmin (#1398) * refactor: 💡 transfer to BuyBackAccount (#1399) * Fix mint_with_channel_id weights (#1400) * Recoverd imgs of banner and logo (#1401) * feat: 🎸 add fn set_swap_out_min (#1389) * feat: 🎸 add fn set_swap_out_min * fix: 🐛 fmt * fix: 🐛 fmt * fix: 🐛 error * feat: 🎸 add bais * fix: 🐛 add test * fix: 🐛 rename field bias * Optimize the `channel-commission` code. (#1390) * Optimize the `channel-commission` code. * Replace the insert method with the mutate method * Added a result check for the clear_prefix method * Supplement the test code of `channel-commission`. * Handling Error cases in hooks. * Optimize the handling of the `check_removed_all` method. * Remove getters in cross-in-out (#1402) * Removed getters in channel-commission. (#1404) * Removed getters in flexible-fee. (#1405) * Removed getters in channel-commission. * Removed getters in flexible-fee. * Removed getters in parachain-staking. (#1406) * Removed getters in channel-commission. * Removed getters in flexible-fee. * Removed getterd in parachain-staking. * Update buy back (#1407) * fix: 🐛 add field last_buyback_cycle for accurate judgment * style: 💄 fmt * Update ve minting (#1408) * refactor: 💡 transfer to BuyBackAccount * feat: 🎸 add auto notify_reward * Removed getters in stable-asset and system-staking. (#1409) * Removed getters in channel-commission. * Removed getters in flexible-fee. * Removed getterd in parachain-staking. * Removed getters in stable-asset. * Removed getters in stable-asset. * Removed getters in token-issuer. (#1410) * Removed getters in channel-commission. * Removed getters in flexible-fee. * Removed getterd in parachain-staking. * Removed getters in stable-asset. * Removed getters in stable-asset. * Removed getters in token-issuer. --------- Co-authored-by: Edwin * Moved PrarachainId to primitives. (#1394) * Moved PrarachainId to primitives * updated * bug fixed * Moved parachain ids to primitives. * bug fixed * Fixed error. * Removed getters in vsbond-auction. (#1412) * Fix evm TransferEvmFees (#1411) * Add slp v2 (#1397) * Add slp v2 * Add slp v2 weights * Optimize slp v2 * Optimize slp v2 * Remove operator * Feat/vbnc convert (#1413) * Add vbnc-convert pallet * add weights.rs of vbnc-convert pallet * update token id of VBNC_P * update weight of vbnc-convert pallet * Supplement the comments of `vbnc-convert`. * update VBNCConvert index in Runtime enum * Optimize vbnc-convert pallet pallet. * Updated (#1416) * Add more slp v2 docs (#1419) * Optimize xcm config (#1417) * Optimize xcm config * Fix moonbeam chain id * Update fee share (#1418) * refactor: 💡 for review * fix: 🐛 mv storage * fix: 🐛 bench * refactor: 💡 fmt --------- Co-authored-by: Edwin * Moved PalletId and AccountId to primitives * Optimize slp v2 (#1423) * Optimize slp v2 * Optimize weights * fix: 🐛 redefine system pool id (#1421) * fix: 🐛 redefine system pool id * fix: 🐛 auto_notify_reward * refactor: 💡 rename to bb-bnc * style: 💄 clippy * fix: 🐛 rename error * refactor: 💡 rm BbBNCPalletId * fix: 🐛 UserFarmingPool bound limit * Moved CurrencyId to primitives. * Updated to the latest version. * change VBNC_P_TOKEN_ID to 5 (#1425) * updated * update * updated * updated --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Co-authored-by: Edwin Wang Co-authored-by: yooml Co-authored-by: NingBo Wang <2536935847@qq.com> Co-authored-by: Damian.lu --- Cargo.lock | 2 + pallets/bb-bnc/src/mock.rs | 26 +++++------- pallets/buy-back/src/mock.rs | 24 ++++------- pallets/buy-back/src/tests.rs | 1 + pallets/channel-commission/src/mock.rs | 8 ++-- pallets/clouds-convert/src/mock.rs | 14 ++----- pallets/cross-in-out/src/mock.rs | 7 ++-- .../deprecated/lightening-redeem/src/mock.rs | 4 -- .../deprecated/liquidity-mining/src/mock.rs | 1 - pallets/deprecated/salp-lite/src/mock.rs | 1 - pallets/deprecated/system-maker/src/mock.rs | 21 ++++------ pallets/farming/src/mock.rs | 19 +++++---- pallets/fee-share/src/mock.rs | 20 ++++------ pallets/flexible-fee/src/mock.rs | 6 +-- pallets/lend-market/src/mock.rs | 11 ----- pallets/leverage-staking/src/mock.rs | 17 +++----- pallets/parachain-staking/Cargo.toml | 1 + pallets/parachain-staking/src/mock.rs | 3 +- pallets/salp/src/mock.rs | 31 ++++++-------- pallets/salp/src/tests.rs | 4 +- pallets/slp-v2/src/mock.rs | 12 ++---- pallets/slp-v2/src/tests.rs | 2 +- pallets/slp/src/mocks/mock.rs | 10 ++--- pallets/slp/src/mocks/mock_kusama.rs | 14 ++----- pallets/slpx/src/mock.rs | 21 ++++------ pallets/stable-asset/src/mock.rs | 6 +-- pallets/stable-pool/src/mock.rs | 23 ++++------- pallets/stable-pool/src/tests.rs | 2 +- pallets/system-staking/src/mock.rs | 21 ++++------ pallets/token-issuer/src/mock.rs | 4 +- pallets/vbnc-convert/src/mock.rs | 10 ++--- pallets/vsbond-auction/src/mock.rs | 5 +-- pallets/vstoken-conversion/src/mock.rs | 14 ++++--- pallets/vstoken-conversion/src/tests.rs | 1 + pallets/vtoken-minting/src/mock.rs | 20 +++------- pallets/vtoken-voting/src/mock.rs | 4 +- primitives/Cargo.toml | 1 + primitives/src/currency.rs | 2 + primitives/src/lib.rs | 40 +++++++++++++++++++ 39 files changed, 181 insertions(+), 252 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 06a763e29..6476ca98b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1441,6 +1441,7 @@ dependencies = [ name = "bifrost-parachain-staking" version = "3.0.1" dependencies = [ + "bifrost-primitives", "frame-benchmarking", "frame-support", "frame-system", @@ -1620,6 +1621,7 @@ version = "0.8.0" dependencies = [ "bstringify", "frame-support", + "hex-literal 0.4.1", "orml-oracle", "orml-traits", "parity-scale-codec", diff --git a/pallets/bb-bnc/src/mock.rs b/pallets/bb-bnc/src/mock.rs index 0f5aff4bd..5bfd05d76 100644 --- a/pallets/bb-bnc/src/mock.rs +++ b/pallets/bb-bnc/src/mock.rs @@ -23,10 +23,13 @@ use crate as bb_bnc; use bifrost_asset_registry::AssetIdMaps; -use bifrost_primitives::MoonbeamChainId; pub use bifrost_primitives::{ currency::*, CurrencyId, CurrencyIdMapping, SlpxOperator, TokenSymbol, }; +use bifrost_primitives::{ + BifrostEntranceAccount, BifrostExitAccount, BifrostFeeAccount, BuyBackAccount, + IncentivePalletId, IncentivePoolAccount, MoonbeamChainId, +}; use bifrost_runtime_common::{micro, milli}; use bifrost_slp::{QueryId, QueryResponseManager}; pub use cumulus_primitives_core::ParaId; @@ -35,10 +38,8 @@ use frame_support::{ pallet_prelude::Get, parameter_types, traits::{Everything, Nothing}, - PalletId, }; use frame_system::{EnsureRoot, EnsureSignedBy}; -use hex_literal::hex; use orml_traits::{location::RelativeReserveProvider, parameter_type_with_key}; use sp_core::ConstU32; use sp_runtime::{ @@ -90,7 +91,7 @@ impl frame_system::Config for Runtime { } parameter_types! { - pub const NativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::BNC); + pub const NativeCurrencyId: CurrencyId = BNC; } pub type AdaptedBasicCurrency = @@ -105,11 +106,8 @@ impl bifrost_currencies::Config for Runtime { parameter_types! { pub const ExistentialDeposit: Balance = 1; - // pub const NativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::BNC); - // pub const RelayCurrencyId: CurrencyId = CurrencyId::Token(TokenSymbol::KSM); - pub const StableCurrencyId: CurrencyId = CurrencyId::Stable(TokenSymbol::KUSD); - // pub SelfParaId: u32 = ParachainInfo::parachain_id().into(); - pub const PolkadotCurrencyId: CurrencyId = CurrencyId::Token(TokenSymbol::DOT); + pub const StableCurrencyId: CurrencyId = KUSD; + pub const PolkadotCurrencyId: CurrencyId = DOT; } impl pallet_balances::Config for Runtime { @@ -192,15 +190,11 @@ impl orml_xtokens::Config for Runtime { parameter_types! { pub const MaximumUnlockIdOfUser: u32 = 1_000; pub const MaximumUnlockIdOfTimeUnit: u32 = 1_000; - pub BifrostEntranceAccount: PalletId = PalletId(*b"bf/vtkin"); - pub BifrostExitAccount: PalletId = PalletId(*b"bf/vtout"); - pub BifrostFeeAccount: AccountId = hex!["e4da05f08e89bf6c43260d96f26fffcfc7deae5b465da08669a9d008e64c2c63"].into(); - pub IncentivePoolAccount: PalletId = PalletId(*b"bf/inpoo"); } ord_parameter_types! { pub const One: AccountId = ALICE; - pub const RelayCurrencyId: CurrencyId = CurrencyId::Token(TokenSymbol::KSM); + pub const RelayCurrencyId: CurrencyId = KSM; } impl bifrost_vtoken_minting::Config for Runtime { @@ -240,9 +234,7 @@ impl bifrost_asset_registry::Config for Runtime { } parameter_types! { - pub const BbBNCTokenType: CurrencyId = CurrencyId::VToken(TokenSymbol::BNC); - pub IncentivePalletId: PalletId = PalletId(*b"bf/bbict"); - pub const BuyBackAccount: PalletId = PalletId(*b"bf/bybck"); + pub const BbBNCTokenType: CurrencyId = VBNC; pub const Week: BlockNumber = 50400; // a week pub const MaxBlock: BlockNumber = 10512000; // four years pub const Multiplier: Balance = 10_u128.pow(12); diff --git a/pallets/buy-back/src/mock.rs b/pallets/buy-back/src/mock.rs index ae4b9787a..ce98941ad 100644 --- a/pallets/buy-back/src/mock.rs +++ b/pallets/buy-back/src/mock.rs @@ -22,8 +22,11 @@ #![allow(non_upper_case_globals)] use bifrost_asset_registry::AssetIdMaps; -use bifrost_primitives::MoonbeamChainId; -pub use bifrost_primitives::{currency::*, CurrencyId, SlpxOperator, TokenSymbol}; +pub use bifrost_primitives::{currency::*, CurrencyId, SlpxOperator}; +use bifrost_primitives::{ + BifrostEntranceAccount, BifrostExitAccount, BifrostFeeAccount, BuyBackAccount, + IncentivePalletId, IncentivePoolAccount, LiquidityAccount, MoonbeamChainId, ZenlinkPalletId, +}; use bifrost_slp::{QueryId, QueryResponseManager}; pub use cumulus_primitives_core::ParaId; use frame_support::{ @@ -32,10 +35,8 @@ use frame_support::{ parameter_types, sp_runtime::{traits::ConvertInto, DispatchError, DispatchResult}, traits::{Everything, Nothing}, - PalletId, }; use frame_system::{EnsureRoot, EnsureSignedBy}; -use hex_literal::hex; use orml_traits::{location::RelativeReserveProvider, parameter_type_with_key, MultiCurrency}; use sp_core::ConstU32; use sp_runtime::{ @@ -104,7 +105,7 @@ impl frame_system::Config for Runtime { } parameter_types! { - pub const GetNativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::BNC); + pub const GetNativeCurrencyId: CurrencyId = BNC; } pub type AdaptedBasicCurrency = @@ -158,14 +159,11 @@ impl orml_tokens::Config for Runtime { parameter_types! { pub const TreasuryAccount: AccountId32 = TREASURY_ACCOUNT; - pub BifrostVsbondAccount: PalletId = PalletId(*b"bf/salpb"); - pub const BuyBackAccount: PalletId = PalletId(*b"bf/bybck"); - pub const LiquidityAccount: PalletId = PalletId(*b"bf/liqdt"); } ord_parameter_types! { pub const One: AccountId = ALICE; - pub const RelayCurrencyId: CurrencyId = CurrencyId::Token(TokenSymbol::KSM); + pub const RelayCurrencyId: CurrencyId = KSM; } impl bifrost_buy_back::Config for Runtime { @@ -283,10 +281,6 @@ impl orml_xtokens::Config for Runtime { parameter_types! { pub const MaximumUnlockIdOfUser: u32 = 10; pub const MaximumUnlockIdOfTimeUnit: u32 = 50; - pub BifrostEntranceAccount: PalletId = PalletId(*b"bf/vtkin"); - pub BifrostExitAccount: PalletId = PalletId(*b"bf/vtout"); - pub BifrostFeeAccount: AccountId = hex!["e4da05f08e89bf6c43260d96f26fffcfc7deae5b465da08669a9d008e64c2c63"].into(); - pub IncentivePoolAccount: PalletId = PalletId(*b"bf/inpoo"); } impl bifrost_vtoken_minting::Config for Runtime { @@ -316,7 +310,6 @@ impl bifrost_vtoken_minting::Config for Runtime { } parameter_types! { - pub const ZenlinkPalletId: PalletId = PalletId(*b"/zenlink"); pub const GetExchangeFee: (u32, u32) = (3, 1000); // 0.3% pub const SelfParaId: u32 = 2001; } @@ -465,8 +458,7 @@ impl pallet_xcm::Config for Runtime { } parameter_types! { - pub const BbBNCTokenType: CurrencyId = CurrencyId::VToken(TokenSymbol::BNC); - pub IncentivePalletId: PalletId = PalletId(*b"bf/bbict"); + pub const BbBNCTokenType: CurrencyId = VBNC; pub const Week: BlockNumber = 50400; // a week pub const MaxBlock: BlockNumber = 10512000; // four years pub const Multiplier: Balance = 10_u128.pow(12); diff --git a/pallets/buy-back/src/tests.rs b/pallets/buy-back/src/tests.rs index 485d80d52..864c9dfd9 100644 --- a/pallets/buy-back/src/tests.rs +++ b/pallets/buy-back/src/tests.rs @@ -21,6 +21,7 @@ #![cfg(test)] use crate::{mock::*, *}; +use bifrost_primitives::IncentivePalletId; use frame_support::{assert_noop, assert_ok}; use sp_arithmetic::per_things::Permill; diff --git a/pallets/channel-commission/src/mock.rs b/pallets/channel-commission/src/mock.rs index 69ef466b2..aa9c70ae6 100644 --- a/pallets/channel-commission/src/mock.rs +++ b/pallets/channel-commission/src/mock.rs @@ -21,8 +21,8 @@ use crate::mock::sp_api_hidden_includes_construct_runtime::hidden_include::traits::OnInitialize; use bifrost_primitives::{ - currency::{BNC, KSM}, - CurrencyId, TokenSymbol, + currency::{ASG, BNC, KSM}, + CommissionPalletId, CurrencyId, }; use frame_support::{derive_impl, ord_parameter_types, parameter_types, traits::Nothing, PalletId}; use frame_system::EnsureSignedBy; @@ -66,7 +66,7 @@ impl frame_system::Config for Runtime { } parameter_types! { - pub const GetNativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::ASG); + pub const GetNativeCurrencyId: CurrencyId = ASG; } pub type AdaptedBasicCurrency = @@ -127,10 +127,8 @@ ord_parameter_types! { } parameter_types! { - pub const CommissionPalletId: PalletId = PalletId(*b"bf/comms"); pub const ClearingDuration: u32 = 100; pub const NameLengthLimit: u32 = 20; - pub const FeeSharePalletId: PalletId = PalletId(*b"bf/feesh"); pub BifrostCommissionReceiver: AccountId = AccountId32::new([7u8; 32]); } diff --git a/pallets/clouds-convert/src/mock.rs b/pallets/clouds-convert/src/mock.rs index 72a89989b..b4b455135 100644 --- a/pallets/clouds-convert/src/mock.rs +++ b/pallets/clouds-convert/src/mock.rs @@ -24,9 +24,9 @@ use bifrost_asset_registry::AssetIdMaps; use bifrost_primitives::{ currency::{BNC, CLOUD, KSM, VBNC, VKSM}, - CurrencyId, CurrencyIdMapping, TokenSymbol, + BuyBackAccount, CloudsPalletId, CurrencyId, CurrencyIdMapping, IncentivePalletId, }; -use frame_support::{ord_parameter_types, parameter_types, traits::Nothing, PalletId}; +use frame_support::{ord_parameter_types, parameter_types, traits::Nothing}; use frame_system::EnsureSignedBy; use sp_core::H256; use sp_runtime::{ @@ -95,7 +95,7 @@ impl frame_system::Config for Runtime { } parameter_types! { - pub const NativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::BNC); + pub const NativeCurrencyId: CurrencyId = BNC; } pub type AdaptedBasicCurrency = @@ -166,10 +166,6 @@ impl bifrost_asset_registry::Config for Runtime { type WeightInfo = (); } -parameter_types! { - pub const CloudsPalletId: PalletId = PalletId(*b"bf/cloud"); -} - impl bifrost_clouds_convert::Config for Runtime { type RuntimeEvent = RuntimeEvent; type MultiCurrency = Currencies; @@ -180,9 +176,7 @@ impl bifrost_clouds_convert::Config for Runtime { } parameter_types! { - pub const BbBNCTokenType: CurrencyId = CurrencyId::VToken(TokenSymbol::BNC); - pub IncentivePalletId: PalletId = PalletId(*b"bf/bbict"); - pub const BuyBackAccount: PalletId = PalletId(*b"bf/bybck"); + pub const BbBNCTokenType: CurrencyId = VBNC; pub const Week: BlockNumber = 50400; // a week pub const MaxBlock: BlockNumber = 10512000; // four years pub const Multiplier: Balance = 10_u128.pow(12); diff --git a/pallets/cross-in-out/src/mock.rs b/pallets/cross-in-out/src/mock.rs index 527975bec..c76374cf3 100644 --- a/pallets/cross-in-out/src/mock.rs +++ b/pallets/cross-in-out/src/mock.rs @@ -20,8 +20,8 @@ #![allow(non_upper_case_globals)] use bifrost_primitives::{ - currency::{BNC, DOT, KSM, VDOT}, - CurrencyId, TokenSymbol, + currency::{ASG, BNC, DOT, KSM, VDOT}, + CurrencyId, SlpEntrancePalletId, }; use frame_support::{derive_impl, ord_parameter_types, parameter_types, traits::Nothing, PalletId}; use frame_system::EnsureSignedBy; @@ -65,7 +65,7 @@ impl frame_system::Config for Runtime { } parameter_types! { - pub const GetNativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::ASG); + pub const GetNativeCurrencyId: CurrencyId = ASG; } pub type AdaptedBasicCurrency = @@ -126,7 +126,6 @@ ord_parameter_types! { } parameter_types! { - pub const SlpEntrancePalletId: PalletId = PalletId(*b"bf/vtkin"); pub const MaxLengthLimit: u32 = 100; } diff --git a/pallets/deprecated/lightening-redeem/src/mock.rs b/pallets/deprecated/lightening-redeem/src/mock.rs index bdf14c461..a56b0d582 100644 --- a/pallets/deprecated/lightening-redeem/src/mock.rs +++ b/pallets/deprecated/lightening-redeem/src/mock.rs @@ -129,10 +129,6 @@ impl pallet_collective::Config for Runtime { type WeightInfo = pallet_collective::weights::SubstrateWeight; } -parameter_types! { - pub const LighteningRedeemPalletId: PalletId = PalletId(*b"lighten#"); -} - impl bifrost_lightening_redeem::Config for Runtime { type RuntimeEvent = RuntimeEvent; type MultiCurrency = Tokens; diff --git a/pallets/deprecated/liquidity-mining/src/mock.rs b/pallets/deprecated/liquidity-mining/src/mock.rs index bae62a103..8c9ac3b3f 100644 --- a/pallets/deprecated/liquidity-mining/src/mock.rs +++ b/pallets/deprecated/liquidity-mining/src/mock.rs @@ -180,7 +180,6 @@ parameter_types! { pub const MinimumDuration: BlockNumber = MINUTES; pub const MaximumApproved: u32 = 4; pub const MaximumOptionRewards: u32 = 7; - pub const LiquidityMiningPalletId: PalletId = PalletId(*b"mining##"); } impl lm::Config for Test { diff --git a/pallets/deprecated/salp-lite/src/mock.rs b/pallets/deprecated/salp-lite/src/mock.rs index 962f5232d..04a8bdafb 100644 --- a/pallets/deprecated/salp-lite/src/mock.rs +++ b/pallets/deprecated/salp-lite/src/mock.rs @@ -161,7 +161,6 @@ impl bifrost_currencies::Config for Test { parameter_types! { pub const MinContribution: Balance = 10; - pub const BifrostCrowdloanId: PalletId = PalletId(*b"bf/salp#"); pub const RemoveKeysLimit: u32 = 50; pub const SlotLength: BlockNumber = 8u32 as BlockNumber; pub const LeasePeriod: BlockNumber = 6 * WEEKS; diff --git a/pallets/deprecated/system-maker/src/mock.rs b/pallets/deprecated/system-maker/src/mock.rs index 756815e07..33f85fb4f 100644 --- a/pallets/deprecated/system-maker/src/mock.rs +++ b/pallets/deprecated/system-maker/src/mock.rs @@ -22,8 +22,11 @@ #![allow(non_upper_case_globals)] use bifrost_asset_registry::AssetIdMaps; -use bifrost_primitives::MoonbeamChainId; -pub use bifrost_primitives::{currency::*, CurrencyId, SlpxOperator, TokenSymbol}; +pub use bifrost_primitives::{currency::*, CurrencyId, SlpxOperator}; +use bifrost_primitives::{ + BifrostEntranceAccount, BifrostExitAccount, BifrostFeeAccount, IncentivePoolAccount, + MoonbeamChainId, SystemMakerPalletId, ZenlinkPalletId, +}; use bifrost_slp::{QueryId, QueryResponseManager}; pub use cumulus_primitives_core::ParaId; use frame_support::{ @@ -32,10 +35,8 @@ use frame_support::{ parameter_types, sp_runtime::{DispatchError, DispatchResult}, traits::{Everything, Nothing}, - PalletId, }; use frame_system::{EnsureRoot, EnsureSignedBy}; -use hex_literal::hex; use orml_traits::{location::RelativeReserveProvider, parameter_type_with_key, MultiCurrency}; use sp_core::ConstU32; use sp_runtime::{ @@ -103,7 +104,7 @@ impl frame_system::Config for Runtime { } parameter_types! { - pub const GetNativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::ASG); + pub const GetNativeCurrencyId: CurrencyId = ASG; } pub type AdaptedBasicCurrency = @@ -157,14 +158,11 @@ impl orml_tokens::Config for Runtime { parameter_types! { pub const TreasuryAccount: AccountId32 = TREASURY_ACCOUNT; - pub BifrostVsbondAccount: PalletId = PalletId(*b"bf/salpb"); - pub const SystemMakerPalletId: PalletId = PalletId(*b"bf/sysmk"); } ord_parameter_types! { pub const One: AccountId = ALICE; - // pub const RelayChainTokenSymbolKSM: TokenSymbol = TokenSymbol::KSM; - pub const RelayCurrencyId: CurrencyId = CurrencyId::Token(TokenSymbol::KSM); + pub const RelayCurrencyId: CurrencyId = KSM; } impl bifrost_system_maker::Config for Runtime { @@ -282,10 +280,6 @@ impl orml_xtokens::Config for Runtime { parameter_types! { pub const MaximumUnlockIdOfUser: u32 = 10; pub const MaximumUnlockIdOfTimeUnit: u32 = 50; - pub BifrostEntranceAccount: PalletId = PalletId(*b"bf/vtkin"); - pub BifrostExitAccount: PalletId = PalletId(*b"bf/vtout"); - pub BifrostFeeAccount: AccountId = hex!["e4da05f08e89bf6c43260d96f26fffcfc7deae5b465da08669a9d008e64c2c63"].into(); - pub IncentivePoolAccount: PalletId = PalletId(*b"bf/inpoo"); } impl bifrost_vtoken_minting::Config for Runtime { @@ -315,7 +309,6 @@ impl bifrost_vtoken_minting::Config for Runtime { } parameter_types! { - pub const ZenlinkPalletId: PalletId = PalletId(*b"/zenlink"); pub const GetExchangeFee: (u32, u32) = (3, 1000); // 0.3% pub const SelfParaId: u32 = 2001; } diff --git a/pallets/farming/src/mock.rs b/pallets/farming/src/mock.rs index fe91ffb78..28a443f84 100644 --- a/pallets/farming/src/mock.rs +++ b/pallets/farming/src/mock.rs @@ -21,8 +21,13 @@ #![cfg(test)] #![allow(non_upper_case_globals)] -pub use bifrost_primitives::{currency::*, CurrencyId, TokenSymbol}; -use frame_support::{derive_impl, ord_parameter_types, parameter_types, traits::Nothing, PalletId}; +pub use bifrost_primitives::{currency::*, CurrencyId}; +use bifrost_primitives::{ + currency::{ASG, VBNC}, + BuyBackAccount, FarmingBoostPalletId, FarmingGaugeRewardIssuerPalletId, FarmingKeeperPalletId, + FarmingRewardIssuerPalletId, IncentivePalletId, +}; +use frame_support::{derive_impl, ord_parameter_types, parameter_types, traits::Nothing}; use frame_system::EnsureSignedBy; use sp_core::ConstU32; use sp_runtime::{ @@ -69,7 +74,7 @@ impl frame_system::Config for Runtime { } parameter_types! { - pub const GetNativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::ASG); + pub const GetNativeCurrencyId: CurrencyId = ASG; } pub type AdaptedBasicCurrency = @@ -123,12 +128,8 @@ impl orml_tokens::Config for Runtime { } parameter_types! { - pub const FarmingKeeperPalletId: PalletId = PalletId(*b"bf/fmkpr"); - pub const FarmingRewardIssuerPalletId: PalletId = PalletId(*b"bf/fmrir"); - pub const FarmingBoostPalletId: PalletId = PalletId(*b"bf/fmbst"); pub const TreasuryAccount: AccountId32 = TREASURY_ACCOUNT; pub const WhitelistMaximumLimit: u32 = 10; - pub const FarmingGaugeRewardIssuerPalletId: PalletId = PalletId(*b"bf/fmgar"); } ord_parameter_types! { @@ -152,9 +153,7 @@ impl bifrost_farming::Config for Runtime { } parameter_types! { - pub const BbBNCTokenType: CurrencyId = CurrencyId::VToken(TokenSymbol::BNC); - pub IncentivePalletId: PalletId = PalletId(*b"bf/bbict"); - pub const BuyBackAccount: PalletId = PalletId(*b"bf/bybck"); + pub const BbBNCTokenType: CurrencyId = VBNC; pub const Week: BlockNumber = 50400; // a week pub const MaxBlock: BlockNumber = 10512000; // four years pub const Multiplier: Balance = 10_u128.pow(12); diff --git a/pallets/fee-share/src/mock.rs b/pallets/fee-share/src/mock.rs index 16945802b..5b404135b 100644 --- a/pallets/fee-share/src/mock.rs +++ b/pallets/fee-share/src/mock.rs @@ -23,8 +23,11 @@ pub use super::*; use bifrost_asset_registry::AssetIdMaps; -pub use bifrost_primitives::{currency::*, CurrencyId, Moment, SlpxOperator, TokenSymbol}; -use bifrost_primitives::{MoonbeamChainId, PriceDetail}; +pub use bifrost_primitives::{currency::*, CurrencyId, Moment, SlpxOperator}; +use bifrost_primitives::{ + BifrostEntranceAccount, BifrostExitAccount, BifrostFeeAccount, FeeSharePalletId, + IncentivePoolAccount, MoonbeamChainId, PriceDetail, ZenlinkPalletId, +}; use bifrost_slp::{QueryId, QueryResponseManager}; pub use cumulus_primitives_core::ParaId; use frame_support::{ @@ -33,10 +36,8 @@ use frame_support::{ parameter_types, sp_runtime::{DispatchError, DispatchResult, FixedPointNumber}, traits::{Everything, Nothing}, - PalletId, }; use frame_system::{EnsureRoot, EnsureSignedBy}; -use hex_literal::hex; use orml_traits::{ location::RelativeReserveProvider, parameter_type_with_key, DataFeeder, DataProvider, DataProviderExtended, MultiCurrency, @@ -113,7 +114,7 @@ impl frame_system::Config for Runtime { } parameter_types! { - pub const GetNativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::ASG); + pub const GetNativeCurrencyId: CurrencyId = ASG; } pub type AdaptedBasicCurrency = @@ -167,13 +168,11 @@ impl orml_tokens::Config for Runtime { parameter_types! { pub const TreasuryAccount: AccountId32 = TREASURY_ACCOUNT; - pub BifrostVsbondAccount: PalletId = PalletId(*b"bf/salpb"); - pub const FeeSharePalletId: PalletId = PalletId(*b"bf/feesh"); } ord_parameter_types! { pub const One: AccountId = ALICE; - pub const RelayCurrencyId: CurrencyId = CurrencyId::Token(TokenSymbol::KSM); + pub const RelayCurrencyId: CurrencyId = KSM; } impl bifrost_fee_share::Config for Runtime { @@ -394,10 +393,6 @@ impl orml_xtokens::Config for Runtime { parameter_types! { pub const MaximumUnlockIdOfUser: u32 = 10; pub const MaximumUnlockIdOfTimeUnit: u32 = 50; - pub BifrostEntranceAccount: PalletId = PalletId(*b"bf/vtkin"); - pub BifrostExitAccount: PalletId = PalletId(*b"bf/vtout"); - pub BifrostFeeAccount: AccountId = hex!["e4da05f08e89bf6c43260d96f26fffcfc7deae5b465da08669a9d008e64c2c63"].into(); - pub IncentivePoolAccount: PalletId = PalletId(*b"bf/inpoo"); } impl bifrost_vtoken_minting::Config for Runtime { @@ -427,7 +422,6 @@ impl bifrost_vtoken_minting::Config for Runtime { } parameter_types! { - pub const ZenlinkPalletId: PalletId = PalletId(*b"/zenlink"); pub const GetExchangeFee: (u32, u32) = (3, 1000); // 0.3% pub const SelfParaId: u32 = 2001; } diff --git a/pallets/flexible-fee/src/mock.rs b/pallets/flexible-fee/src/mock.rs index d8ef4559d..7e061dcb0 100644 --- a/pallets/flexible-fee/src/mock.rs +++ b/pallets/flexible-fee/src/mock.rs @@ -21,7 +21,7 @@ use super::*; use crate::{self as flexible_fee, mock_price::MockOraclePriceProvider}; use bifrost_currencies::BasicCurrencyAdapter; -use bifrost_primitives::{Balance, CurrencyId, TokenSymbol}; +use bifrost_primitives::{Balance, CurrencyId, FlexibleFeePalletId, TokenSymbol, ZenlinkPalletId}; use cumulus_primitives_core::ParaId as Pid; use frame_support::{ derive_impl, parameter_types, @@ -149,7 +149,6 @@ impl orml_tokens::Config for Test { parameter_types! { pub const TreasuryAccount: AccountId32 = TREASURY_ACCOUNT; pub const MaxFeeCurrencyOrderListLen: u32 = 50; - pub const FlexibleFeePalletId: PalletId = PalletId(*b"bf/flexi"); } impl crate::Config for Test { @@ -196,7 +195,7 @@ impl Get for ParaInfo { } parameter_types! { - pub const GetNativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::BNC); + pub const GetNativeCurrencyId: CurrencyId = BNC; } impl bifrost_currencies::Config for Test { @@ -207,7 +206,6 @@ impl bifrost_currencies::Config for Test { } parameter_types! { - pub const ZenlinkPalletId: PalletId = PalletId(*b"/zenlink"); pub const GetExchangeFee: (u32, u32) = (3, 1000); // 0.3% pub const SelfParaId: u32 = 2001; } diff --git a/pallets/lend-market/src/mock.rs b/pallets/lend-market/src/mock.rs index eecf3f21d..9e2ba4bb1 100644 --- a/pallets/lend-market/src/mock.rs +++ b/pallets/lend-market/src/mock.rs @@ -22,7 +22,6 @@ pub use bifrost_primitives::{currency::*, *}; use frame_support::{ construct_runtime, derive_impl, parameter_types, traits::{AsEnsureOriginWithArg, Nothing, SortedMembers}, - PalletId, }; use frame_system::{EnsureRoot, EnsureSigned, EnsureSignedBy}; use orml_traits::{DataFeeder, DataProvider, DataProviderExtended}; @@ -88,11 +87,6 @@ parameter_types! { pub const MaxLocks: u32 = 50; } -parameter_types! { - pub const StableCurrencyId: CurrencyId = CurrencyId::Stable(TokenSymbol::KUSD); - pub const PolkadotCurrencyId: CurrencyId = CurrencyId::Token(TokenSymbol::DOT); -} - impl pallet_balances::Config for Test { type AccountStore = frame_system::Pallet; type Balance = Balance; @@ -116,10 +110,6 @@ impl bifrost_asset_registry::Config for Test { type WeightInfo = (); } -parameter_types! { - pub const NativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::BNC); -} - orml_traits::parameter_type_with_key! { pub ExistentialDeposits: |currency_id: CurrencyId| -> Balance { match currency_id { @@ -316,7 +306,6 @@ impl pallet_prices::Config for Test { } parameter_types! { - pub const LendMarketPalletId: PalletId = PalletId(*b"bf/ldmkt"); pub const RewardAssetId: CurrencyId = BNC; pub const LiquidationFreeAssetId: CurrencyId = DOT; } diff --git a/pallets/leverage-staking/src/mock.rs b/pallets/leverage-staking/src/mock.rs index f7ab5dd74..dc76e26b3 100644 --- a/pallets/leverage-staking/src/mock.rs +++ b/pallets/leverage-staking/src/mock.rs @@ -22,12 +22,14 @@ use bifrost_asset_registry::AssetIdMaps; pub use bifrost_primitives::{ currency::*, Balance, CurrencyId, CurrencyIdMapping, SlpOperator, SlpxOperator, TokenSymbol, }; -use bifrost_primitives::{Moment, MoonbeamChainId, OraclePriceProvider, Price, PriceDetail, Ratio}; +use bifrost_primitives::{ + BifrostEntranceAccount, BifrostExitAccount, IncentivePoolAccount, LendMarketPalletId, Moment, + MoonbeamChainId, OraclePriceProvider, Price, PriceDetail, Ratio, StableAssetPalletId, +}; use bifrost_runtime_common::milli; use frame_support::{ derive_impl, ord_parameter_types, parameter_types, traits::{ConstU128, ConstU32, Everything, Nothing}, - PalletId, }; use frame_system::{EnsureRoot, EnsureSignedBy}; use lend_market::{InterestRateModel, JumpModel, Market, MarketState}; @@ -77,7 +79,7 @@ impl frame_system::Config for Test { } parameter_types! { - pub const NativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::BNC); + pub const NativeCurrencyId: CurrencyId = BNC; } orml_traits::parameter_type_with_key! { @@ -235,9 +237,6 @@ impl bifrost_stable_asset::traits::ValidateAssetId for EnsurePoolAss true } } -parameter_types! { - pub const StableAssetPalletId: PalletId = PalletId(*b"nuts/sta"); -} impl bifrost_stable_asset::Config for Test { type RuntimeEvent = RuntimeEvent; @@ -279,9 +278,6 @@ impl leverage_staking::Config for Test { parameter_types! { pub const MaximumUnlockIdOfUser: u32 = 1_000; pub const MaximumUnlockIdOfTimeUnit: u32 = 1_000; - pub BifrostEntranceAccount: PalletId = PalletId(*b"bf/vtkin"); - pub BifrostExitAccount: PalletId = PalletId(*b"bf/vtout"); - pub IncentivePoolAccount: PalletId = PalletId(*b"bf/inpoo"); } pub struct SlpxInterface; @@ -292,7 +288,7 @@ impl SlpxOperator for SlpxInterface { } ord_parameter_types! { - pub const RelayCurrencyId: CurrencyId = CurrencyId::Token(TokenSymbol::KSM); + pub const RelayCurrencyId: CurrencyId = KSM; } impl bifrost_vtoken_minting::Config for Test { @@ -439,7 +435,6 @@ impl OraclePriceProvider for MockOraclePriceProvider { } parameter_types! { - pub const LendMarketPalletId: PalletId = PalletId(*b"bf/ldmkt"); pub const RewardAssetId: CurrencyId = BNC; pub const LiquidationFreeAssetId: CurrencyId = DOT; } diff --git a/pallets/parachain-staking/Cargo.toml b/pallets/parachain-staking/Cargo.toml index c3e5089c3..c9a7d34b9 100644 --- a/pallets/parachain-staking/Cargo.toml +++ b/pallets/parachain-staking/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" version = "3.0.1" [dependencies] +bifrost-primitives = { workspace = true } log = { workspace = true } serde = { workspace = true, features = ["derive"] } diff --git a/pallets/parachain-staking/src/mock.rs b/pallets/parachain-staking/src/mock.rs index 29303a027..45acfb13b 100644 --- a/pallets/parachain-staking/src/mock.rs +++ b/pallets/parachain-staking/src/mock.rs @@ -18,7 +18,6 @@ use frame_support::{ construct_runtime, derive_impl, parameter_types, traits::{LockIdentifier, LockableCurrency, OnFinalize, OnInitialize, ReservableCurrency}, - PalletId, }; use sp_core::ConstU32; use sp_runtime::{traits::IdentityLookup, Perbill, Percent}; @@ -29,6 +28,7 @@ use crate::{ DelegatorReserveToLockMigrations, DelegatorState, InflationInfo, Points, Range, COLLATOR_LOCK_ID, DELEGATOR_LOCK_ID, }; +use bifrost_primitives::ParachainStakingPalletId; use sp_runtime::BuildStorage; pub type AccountId = u64; @@ -96,7 +96,6 @@ parameter_types! { pub const MinDelegation: u128 = 3; pub AllowInflation: bool = true; pub PaymentInRound: u128 = 10; - pub const ParachainStakingPalletId: PalletId = PalletId(*b"bf/stake"); pub ToMigrateInvulnables: Vec = vec![ 0,1 ]; diff --git a/pallets/salp/src/mock.rs b/pallets/salp/src/mock.rs index e2138c859..f377cbab3 100644 --- a/pallets/salp/src/mock.rs +++ b/pallets/salp/src/mock.rs @@ -22,8 +22,13 @@ use bifrost_asset_registry::AssetIdMaps; use bifrost_primitives::{ - Amount, Balance, CurrencyId, CurrencyId::*, MessageId, MockXcmExecutor, ParaId, SlpOperator, - SlpxOperator, TokenSymbol, TokenSymbol::*, VKSM, + Amount, Balance, BifrostCrowdloanId, BifrostEntranceAccount, BifrostExitAccount, + BuybackPalletId, + CurrencyId::{self, *}, + IncentivePoolAccount, MessageId, MockXcmExecutor, ParaId, SlpOperator, SlpxOperator, + StableAssetPalletId, + TokenSymbol::{self, *}, + ZenlinkPalletId, ASG, KSM, KUSD, VKSM, }; use bifrost_xcm_interface::traits::XcmHelper; use cumulus_primitives_core::ParaId as Pid; @@ -32,7 +37,6 @@ use frame_support::{ sp_runtime::{DispatchError, DispatchResult, SaturatedConversion}, traits::{ConstU128, ConstU64, EnsureOrigin, Everything, Get, LockIdentifier, Nothing}, weights::Weight, - PalletId, }; use frame_system::{EnsureRoot, EnsureSignedBy, RawOrigin}; use orml_traits::{location::RelativeReserveProvider, parameter_type_with_key, MultiCurrency}; @@ -80,9 +84,9 @@ construct_runtime!( ); parameter_types! { - pub const NativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::ASG); - pub const RelayCurrencyId: CurrencyId = CurrencyId::Token(TokenSymbol::KSM); - pub const StableCurrencyId: CurrencyId = CurrencyId::Stable(TokenSymbol::KUSD); + pub const NativeCurrencyId: CurrencyId = ASG; + pub const RelayCurrencyId: CurrencyId = KSM; + pub const StableCurrencyId: CurrencyId = KUSD; } parameter_types! { @@ -177,7 +181,6 @@ impl bifrost_currencies::Config for Test { } parameter_types! { - pub const ZenlinkPalletId: PalletId = PalletId(*b"/zenlink"); pub const GetExchangeFee: (u32, u32) = (3, 1000); // 0.3% pub const SelfParaId: u32 = 2001; } @@ -268,7 +271,6 @@ pub const TREASURY_ACCOUNT: AccountId = AccountId::new([9u8; 32]); parameter_types! { pub const MinContribution: Balance = 10; - pub const BifrostCrowdloanId: PalletId = PalletId(*b"bf/salp#"); pub const RemoveKeysLimit: u32 = 50; pub const SlotLength: BlockNumber = 8u32 as BlockNumber; pub const LeasePeriod: BlockNumber = 6 * WEEKS; @@ -281,7 +283,6 @@ parameter_types! { CATHI ],2); pub const TreasuryAccount: AccountId = TREASURY_ACCOUNT; - pub const BuybackPalletId: PalletId = PalletId(*b"bf/salpc"); pub const BatchLimit: u32 = 50; } @@ -330,9 +331,6 @@ impl bifrost_stable_asset::traits::ValidateAssetId for EnsurePoolAss true } } -parameter_types! { - pub const StableAssetPalletId: PalletId = PalletId(*b"nuts/sta"); -} impl bifrost_stable_asset::Config for Test { type RuntimeEvent = RuntimeEvent; @@ -364,9 +362,6 @@ impl bifrost_stable_pool::Config for Test { parameter_types! { pub const MaximumUnlockIdOfUser: u32 = 1_000; pub const MaximumUnlockIdOfTimeUnit: u32 = 1_000; - pub BifrostEntranceAccount: PalletId = PalletId(*b"bf/vtkin"); - pub BifrostExitAccount: PalletId = PalletId(*b"bf/vtout"); - pub IncentivePoolAccount: PalletId = PalletId(*b"bf/inpoo"); } pub struct SlpxInterface; @@ -576,8 +571,8 @@ pub(crate) fn new_test_ext() -> sp_io::TestExternalities { let currency = vec![ (Native(BNC), DOLLARS / 100, None), - (Stable(KUSD), DOLLARS / 10_000, None), - (Token(KSM), DOLLARS / 10_000, None), + (Stable(TokenSymbol::KUSD), DOLLARS / 10_000, None), + (Token(TokenSymbol::KSM), DOLLARS / 10_000, None), (Token(ZLK), DOLLARS / 1000_000, None), (Token(KAR), DOLLARS / 10_000, None), (Token(RMRK), DOLLARS / 1000_000, None), @@ -585,7 +580,7 @@ pub(crate) fn new_test_ext() -> sp_io::TestExternalities { (Token(MOVR), DOLLARS / 1000_000, None), (Token(DOT), DOLLARS / 1000_000, None), ]; - let vcurrency = vec![Native(BNC), Token(KSM), Token(MOVR)]; + let vcurrency = vec![Native(BNC), Token(TokenSymbol::KSM), Token(MOVR)]; let vsbond = vec![]; bifrost_asset_registry::GenesisConfig:: { currency, diff --git a/pallets/salp/src/tests.rs b/pallets/salp/src/tests.rs index 40b486f12..b30fb0d16 100644 --- a/pallets/salp/src/tests.rs +++ b/pallets/salp/src/tests.rs @@ -19,7 +19,9 @@ // Ensure we're `no_std` when compiling for Wasm. use crate::{mock::*, Error, FundStatus, *}; -use bifrost_primitives::{CurrencyId, TokenSymbol, TryConvertFrom, KSM, VKSM, VSKSM}; +use bifrost_primitives::{ + BuybackPalletId, CurrencyId, TokenSymbol, TryConvertFrom, KSM, VKSM, VSKSM, +}; use bifrost_xcm_interface::SalpHelper; use frame_support::{assert_noop, assert_ok}; use frame_system::pallet_prelude::BlockNumberFor; diff --git a/pallets/slp-v2/src/mock.rs b/pallets/slp-v2/src/mock.rs index 8104a81e8..c4f8990eb 100644 --- a/pallets/slp-v2/src/mock.rs +++ b/pallets/slp-v2/src/mock.rs @@ -19,19 +19,18 @@ use crate as slp_v2; use bifrost_asset_registry::AssetIdMaps; use bifrost_primitives::{ - Amount, Balance, BlockNumber, CurrencyId, MockXcmRouter, MockXcmTransfer, SlpOperator, - SlpxOperator, BNC, DOT, + currency::DOT, Amount, Balance, BifrostEntranceAccount, BifrostExitAccount, BifrostFeeAccount, + BlockNumber, CommissionPalletId, CurrencyId, IncentivePoolAccount, MockXcmRouter, + MockXcmTransfer, SlpOperator, SlpxOperator, BNC, }; use frame_support::{ derive_impl, pallet_prelude::{ConstU32, Get}, parameter_types, traits::{Everything, Nothing}, - PalletId, }; use frame_system as system; use frame_system::EnsureRoot; -use hex_literal::hex; use pallet_xcm::EnsureResponse; use polkadot_parachain_primitives::primitives::Id as ParaId; use sp_core::{crypto::AccountId32, ConstU64}; @@ -142,7 +141,6 @@ parameter_types! { pub UnitWeightCost: Weight = Weight::from_parts(200_000_000, 0); pub const MaxInstructions: u32 = 100; pub UniversalLocation: InteriorLocation = Parachain(2030).into(); - pub CommissionPalletId: PalletId = PalletId(*b"bf/comms"); } pub struct XcmConfig; @@ -215,11 +213,7 @@ impl Get for ParachainId { parameter_types! { pub const MaximumUnlockIdOfUser: u32 = 10; pub const MaximumUnlockIdOfTimeUnit: u32 = 50; - pub BifrostEntranceAccount: PalletId = PalletId(*b"bf/vtkin"); - pub BifrostExitAccount: PalletId = PalletId(*b"bf/vtout"); - pub BifrostFeeAccount: AccountId = hex!["e4da05f08e89bf6c43260d96f26fffcfc7deae5b465da08669a9d008e64c2c63"].into(); pub const RelayCurrencyId: CurrencyId = DOT; - pub IncentivePoolAccount: PalletId = PalletId(*b"bf/inpoo"); } pub struct SlpxInterface; diff --git a/pallets/slp-v2/src/tests.rs b/pallets/slp-v2/src/tests.rs index d2649ecf2..2140d2364 100644 --- a/pallets/slp-v2/src/tests.rs +++ b/pallets/slp-v2/src/tests.rs @@ -31,7 +31,7 @@ use crate::{ LedgerByStakingProtocolAndDelegator, NextDelegatorIndexByStakingProtocol, ValidatorsByStakingProtocolAndDelegator, }; -use bifrost_primitives::{TimeUnit, VtokenMintingOperator, VASTR}; +use bifrost_primitives::{CommissionPalletId, TimeUnit, VtokenMintingOperator, VASTR}; use cumulus_primitives_core::Weight; use frame_support::{assert_noop, assert_ok, traits::fungibles::Mutate}; use orml_traits::MultiCurrency; diff --git a/pallets/slp/src/mocks/mock.rs b/pallets/slp/src/mocks/mock.rs index a5f893b27..4495ad6be 100644 --- a/pallets/slp/src/mocks/mock.rs +++ b/pallets/slp/src/mocks/mock.rs @@ -25,7 +25,9 @@ use crate::{Config, DispatchResult, QueryResponseManager, XcmDestWeightAndFeeHan use bifrost_asset_registry::AssetIdMaps; use bifrost_primitives::{ currency::{BNC, KSM}, - Amount, Balance, CurrencyId, MoonbeamChainId, SlpxOperator, TokenSymbol, XcmOperationType, + Amount, Balance, BifrostEntranceAccount, BifrostExitAccount, BifrostFeeAccount, CurrencyId, + IncentivePoolAccount, MoonbeamChainId, ParachainStakingPalletId, SlpxOperator, TokenSymbol, + XcmOperationType, }; pub use cumulus_primitives_core::ParaId; use frame_support::{ @@ -36,7 +38,6 @@ use frame_support::{ PalletId, }; use frame_system::{EnsureRoot, EnsureSignedBy}; -use hex_literal::hex; use orml_traits::{location::RelativeReserveProvider, parameter_type_with_key}; use parity_scale_codec::{Decode, Encode}; use sp_core::{bounded::BoundedVec, hashing::blake2_256, ConstU32}; @@ -185,10 +186,6 @@ impl orml_xtokens::Config for Runtime { parameter_types! { pub const MaximumUnlockIdOfUser: u32 = 10; pub const MaximumUnlockIdOfTimeUnit: u32 = 50; - pub BifrostEntranceAccount: PalletId = PalletId(*b"bf/vtkin"); - pub BifrostExitAccount: PalletId = PalletId(*b"bf/vtout"); - pub BifrostFeeAccount: AccountId = hex!["e4da05f08e89bf6c43260d96f26fffcfc7deae5b465da08669a9d008e64c2c63"].into(); - pub IncentivePoolAccount: PalletId = PalletId(*b"bf/inpoo"); } impl bifrost_vtoken_minting::Config for Runtime { @@ -237,7 +234,6 @@ parameter_types! { pub const MinDelegation: u128 = 3; pub AllowInflation: bool = true; pub PaymentInRound: u128 = 10; - pub const ParachainStakingPalletId: PalletId = PalletId(*b"bf/stake"); pub ToMigrateInvulnables: Vec = vec![AccountId32::new([1u8; 32])]; pub InitSeedStk: u128 = 10; } diff --git a/pallets/slp/src/mocks/mock_kusama.rs b/pallets/slp/src/mocks/mock_kusama.rs index 6aeafbf7c..adb01aa24 100644 --- a/pallets/slp/src/mocks/mock_kusama.rs +++ b/pallets/slp/src/mocks/mock_kusama.rs @@ -25,8 +25,10 @@ use crate::{Config, DispatchResult, QueryResponseManager}; use bifrost_asset_registry::AssetIdMaps; use bifrost_primitives::{ currency::{BNC, KSM, MANTA}, - Amount, Balance, CurrencyId, MockXcmExecutor, MockXcmRouter, MoonbeamChainId, SlpxOperator, - TokenSymbol, XcmDestWeightAndFeeHandler, XcmOperationType, + Amount, Balance, BifrostEntranceAccount, BifrostExitAccount, BifrostFeeAccount, CurrencyId, + IncentivePoolAccount, MockXcmExecutor, MockXcmRouter, MoonbeamChainId, + ParachainStakingPalletId, SlpxOperator, StableAssetPalletId, TokenSymbol, + XcmDestWeightAndFeeHandler, XcmOperationType, }; pub use cumulus_primitives_core::ParaId; use frame_support::{ @@ -93,9 +95,6 @@ impl bifrost_stable_asset::traits::ValidateAssetId for EnsurePoolAss true } } -parameter_types! { - pub const StableAssetPalletId: PalletId = PalletId(*b"nuts/sta"); -} impl bifrost_stable_asset::Config for Runtime { type RuntimeEvent = RuntimeEvent; @@ -236,10 +235,6 @@ impl orml_xtokens::Config for Runtime { parameter_types! { pub const MaximumUnlockIdOfUser: u32 = 10; pub const MaximumUnlockIdOfTimeUnit: u32 = 50; - pub BifrostEntranceAccount: PalletId = PalletId(*b"bf/vtkin"); - pub BifrostExitAccount: PalletId = PalletId(*b"bf/vtout"); - pub BifrostFeeAccount: AccountId = hex!["e4da05f08e89bf6c43260d96f26fffcfc7deae5b465da08669a9d008e64c2c63"].into(); - pub IncentivePoolAccount: PalletId = PalletId(*b"bf/inpoo"); } pub struct SlpxInterface; @@ -295,7 +290,6 @@ parameter_types! { pub const MinDelegation: u128 = 3; pub AllowInflation: bool = true; pub PaymentInRound: u128 = 10; - pub const ParachainStakingPalletId: PalletId = PalletId(*b"bf/stake"); pub ToMigrateInvulnables: Vec = vec![AccountId32::new([1u8; 32])]; pub InitSeedStk: u128 = 10; } diff --git a/pallets/slpx/src/mock.rs b/pallets/slpx/src/mock.rs index ea6eaf1e8..13e32baf7 100644 --- a/pallets/slpx/src/mock.rs +++ b/pallets/slpx/src/mock.rs @@ -19,9 +19,12 @@ use crate as slpx; use bifrost_asset_registry::AssetIdMaps; -use bifrost_primitives::MoonbeamChainId; +use bifrost_primitives::{ + BifrostEntranceAccount, BifrostExitAccount, BifrostFeeAccount, IncentivePoolAccount, + MoonbeamChainId, StableAssetPalletId, ZenlinkPalletId, +}; pub use bifrost_primitives::{ - CurrencyId, CurrencyIdMapping, MockXcmExecutor, SlpxOperator, TokenSymbol, BNC, KSM, + CurrencyId, CurrencyIdMapping, MockXcmExecutor, SlpxOperator, BNC, KSM, }; use bifrost_slp::{QueryId, QueryResponseManager}; use cumulus_primitives_core::ParaId; @@ -30,10 +33,8 @@ use frame_support::{ pallet_prelude::*, parameter_types, traits::{Everything, Nothing}, - PalletId, }; use frame_system::{EnsureRoot, EnsureSignedBy}; -use hex_literal::hex; use orml_traits::{ location::RelativeReserveProvider, parameter_type_with_key, xcm_transfer::Transferred, MultiCurrency, XcmTransfer, @@ -119,7 +120,7 @@ impl pallet_balances::Config for Test { } parameter_types! { - pub const GetNativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::BNC); + pub const GetNativeCurrencyId: CurrencyId = BNC; } pub type AdaptedBasicCurrency = @@ -161,11 +162,7 @@ impl orml_tokens::Config for Test { parameter_types! { pub const MaximumUnlockIdOfUser: u32 = 10; pub const MaximumUnlockIdOfTimeUnit: u32 = 50; - pub BifrostEntranceAccount: PalletId = PalletId(*b"bf/vtkin"); - pub BifrostExitAccount: PalletId = PalletId(*b"bf/vtout"); - pub BifrostFeeAccount: AccountId = hex!["e4da05f08e89bf6c43260d96f26fffcfc7deae5b465da08669a9d008e64c2c63"].into(); pub const RelayCurrencyId: CurrencyId = KSM; - pub IncentivePoolAccount: PalletId = PalletId(*b"bf/inpoo"); } ord_parameter_types! { @@ -266,7 +263,6 @@ where type MultiAssets = ZenlinkMultiAssets>; parameter_types! { - pub const ZenlinkPalletId: PalletId = PalletId(*b"/zenlink"); pub const GetExchangeFee: (u32, u32) = (3, 1000); // 0.3% pub const SelfParaId: u32 = 2001; } @@ -476,9 +472,6 @@ impl bifrost_stable_asset::traits::ValidateAssetId for EnsurePoolAss true } } -parameter_types! { - pub const StableAssetPalletId: PalletId = PalletId(*b"nuts/sta"); -} impl bifrost_stable_asset::Config for Test { type RuntimeEvent = RuntimeEvent; @@ -509,7 +502,7 @@ impl bifrost_stable_pool::Config for Test { // Pallet slpx configuration parameter_types! { - pub const NativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::BNC); + pub const NativeCurrencyId: CurrencyId = BNC; } pub struct XTokensMock; diff --git a/pallets/stable-asset/src/mock.rs b/pallets/stable-asset/src/mock.rs index ef1811eff..da1c64a1b 100644 --- a/pallets/stable-asset/src/mock.rs +++ b/pallets/stable-asset/src/mock.rs @@ -17,12 +17,12 @@ // along with this program. If not, see . use crate as stable_asset; +use bifrost_primitives::StableAssetPalletId; use frame_support::{ derive_impl, dispatch::DispatchResult, parameter_types, traits::{ConstU128, ConstU32, Currency, EnsureOrigin, Nothing, OnUnbalanced}, - PalletId, }; use frame_system::RawOrigin; use orml_traits::MultiCurrency; @@ -266,10 +266,6 @@ impl crate::traits::ValidateAssetId for EnsurePoolAssetId { } } -parameter_types! { - pub const StableAssetPalletId: PalletId = PalletId(*b"nuts/sta"); -} - impl stable_asset::Config for Test { type RuntimeEvent = RuntimeEvent; type AssetId = i64; diff --git a/pallets/stable-pool/src/mock.rs b/pallets/stable-pool/src/mock.rs index d63321de7..5dd4d6798 100644 --- a/pallets/stable-pool/src/mock.rs +++ b/pallets/stable-pool/src/mock.rs @@ -17,17 +17,19 @@ // along with this program. If not, see . use crate as bifrost_stable_pool; use bifrost_asset_registry::AssetIdMaps; -use bifrost_primitives::MoonbeamChainId; pub use bifrost_primitives::{ currency::{MOVR, VMOVR}, Balance, CurrencyId, CurrencyIdMapping, SlpOperator, SlpxOperator, TokenSymbol, ASTR, BNC, DOT, GLMR, VBNC, VDOT, }; +use bifrost_primitives::{ + BifrostEntranceAccount, BifrostExitAccount, IncentivePoolAccount, MoonbeamChainId, + StableAssetPalletId, KSM, KUSD, +}; use bifrost_runtime_common::milli; use frame_support::{ derive_impl, ord_parameter_types, parameter_types, traits::{ConstU128, ConstU32, Everything, Nothing}, - PalletId, }; use frame_system::{EnsureRoot, EnsureSignedBy}; use orml_traits::{location::RelativeReserveProvider, parameter_type_with_key}; @@ -63,7 +65,7 @@ impl frame_system::Config for Test { } parameter_types! { - pub const NativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::BNC); + pub const NativeCurrencyId: CurrencyId = BNC; } orml_traits::parameter_type_with_key! { @@ -187,11 +189,8 @@ impl orml_xtokens::Config for Test { parameter_types! { pub const ExistentialDeposit: Balance = 1; - // pub const NativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::BNC); - // pub const RelayCurrencyId: CurrencyId = CurrencyId::Token(TokenSymbol::KSM); - pub const StableCurrencyId: CurrencyId = CurrencyId::Stable(TokenSymbol::KUSD); - // pub SelfParaId: u32 = ParachainInfo::parachain_id().into(); - pub const PolkadotCurrencyId: CurrencyId = CurrencyId::Token(TokenSymbol::DOT); + pub const StableCurrencyId: CurrencyId = KUSD; + pub const PolkadotCurrencyId: CurrencyId = DOT; } impl pallet_balances::Config for Test { @@ -226,9 +225,6 @@ impl bifrost_stable_asset::traits::ValidateAssetId for EnsurePoolAss true } } -parameter_types! { - pub const StableAssetPalletId: PalletId = PalletId(*b"nuts/sta"); -} impl bifrost_stable_asset::Config for Test { type RuntimeEvent = RuntimeEvent; @@ -260,9 +256,6 @@ impl bifrost_stable_pool::Config for Test { parameter_types! { pub const MaximumUnlockIdOfUser: u32 = 1_000; pub const MaximumUnlockIdOfTimeUnit: u32 = 1_000; - pub BifrostEntranceAccount: PalletId = PalletId(*b"bf/vtkin"); - pub BifrostExitAccount: PalletId = PalletId(*b"bf/vtout"); - pub IncentivePoolAccount: PalletId = PalletId(*b"bf/inpoo"); } pub struct SlpxInterface; @@ -273,7 +266,7 @@ impl SlpxOperator for SlpxInterface { } ord_parameter_types! { - pub const RelayCurrencyId: CurrencyId = CurrencyId::Token(TokenSymbol::KSM); + pub const RelayCurrencyId: CurrencyId = KSM; } impl bifrost_vtoken_minting::Config for Test { diff --git a/pallets/stable-pool/src/tests.rs b/pallets/stable-pool/src/tests.rs index 807f32fde..a6277a30a 100644 --- a/pallets/stable-pool/src/tests.rs +++ b/pallets/stable-pool/src/tests.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . use crate::{mock::*, AssetIdOf, AtLeast64BitUnsignedOf, Error}; -use bifrost_primitives::VtokenMintingOperator; +use bifrost_primitives::{StableAssetPalletId, VtokenMintingOperator}; use bifrost_stable_asset::{PoolCount, Pools, StableAssetPoolInfo}; use frame_support::{assert_noop, assert_ok, BoundedVec}; use orml_traits::MultiCurrency; diff --git a/pallets/system-staking/src/mock.rs b/pallets/system-staking/src/mock.rs index a450972d1..a50e2f26a 100644 --- a/pallets/system-staking/src/mock.rs +++ b/pallets/system-staking/src/mock.rs @@ -19,8 +19,12 @@ #![allow(non_upper_case_globals)] use bifrost_asset_registry::AssetIdMaps; -use bifrost_primitives::MoonbeamChainId; -pub use bifrost_primitives::{currency::*, CurrencyId, SlpxOperator, TokenSymbol}; +pub use bifrost_primitives::{currency::*, CurrencyId, SlpxOperator}; +use bifrost_primitives::{ + BifrostEntranceAccount, BifrostExitAccount, BifrostFeeAccount, FarmingBoostPalletId, + FarmingGaugeRewardIssuerPalletId, FarmingKeeperPalletId, FarmingRewardIssuerPalletId, + IncentivePoolAccount, MoonbeamChainId, SystemStakingPalletId, +}; use bifrost_slp::{QueryId, QueryResponseManager}; pub use cumulus_primitives_core::ParaId; use cumulus_primitives_core::*; @@ -29,10 +33,8 @@ use frame_support::{ pallet_prelude::Get, parameter_types, traits::{Everything, Nothing, OnFinalize, OnInitialize}, - PalletId, }; use frame_system::{EnsureRoot, EnsureSignedBy}; -use hex_literal::hex; use orml_traits::{location::RelativeReserveProvider, parameter_type_with_key}; use sp_core::ConstU32; use sp_runtime::{ @@ -87,7 +89,7 @@ impl frame_system::Config for Runtime { } parameter_types! { - pub const GetNativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::ASG); + pub const GetNativeCurrencyId: CurrencyId = ASG; } pub type AdaptedBasicCurrency = @@ -173,11 +175,7 @@ impl orml_xtokens::Config for Runtime { parameter_types! { pub const MaximumUnlockIdOfUser: u32 = 10; pub const MaximumUnlockIdOfTimeUnit: u32 = 50; - pub BifrostEntranceAccount: PalletId = PalletId(*b"bf/vtkin"); - pub BifrostExitAccount: PalletId = PalletId(*b"bf/vtout"); - pub BifrostFeeAccount: AccountId = hex!["e4da05f08e89bf6c43260d96f26fffcfc7deae5b465da08669a9d008e64c2c63"].into(); pub const RelayCurrencyId: CurrencyId = KSM; - pub IncentivePoolAccount: PalletId = PalletId(*b"bf/inpoo"); } impl bifrost_vtoken_minting::Config for Runtime { @@ -277,11 +275,7 @@ impl bifrost_slp::Config for Runtime { } parameter_types! { - pub const FarmingKeeperPalletId: PalletId = PalletId(*b"bf/fmkpr"); - pub const FarmingRewardIssuerPalletId: PalletId = PalletId(*b"bf/fmrir"); - pub const FarmingBoostPalletId: PalletId = PalletId(*b"bf/fmbst"); pub const WhitelistMaximumLimit: u32 = 10; - pub const FarmingGaugeRewardIssuerPalletId: PalletId = PalletId(*b"bf/fmgar"); } ord_parameter_types! { @@ -309,7 +303,6 @@ parameter_types! { pub const BlocksPerRound: u32 = 5; pub const MaxTokenLen: u32 = 50; pub const MaxFarmingPoolIdLen: u32 = 100; - pub const SystemStakingPalletId: PalletId = PalletId(*b"bf/sysst"); } impl system_staking::Config for Runtime { diff --git a/pallets/token-issuer/src/mock.rs b/pallets/token-issuer/src/mock.rs index b110b7b22..4764c9e60 100644 --- a/pallets/token-issuer/src/mock.rs +++ b/pallets/token-issuer/src/mock.rs @@ -22,7 +22,7 @@ use crate::Weight; use bifrost_primitives::{ currency::{BNC, DOT, KSM, VDOT}, - CurrencyId, TokenSymbol, + CurrencyId, ASG, }; use frame_support::{derive_impl, parameter_types, traits::Nothing, PalletId}; use frame_system::EnsureRoot; @@ -70,7 +70,7 @@ impl frame_system::Config for Runtime { } parameter_types! { - pub const GetNativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::ASG); + pub const GetNativeCurrencyId: CurrencyId = ASG; } pub type AdaptedBasicCurrency = diff --git a/pallets/vbnc-convert/src/mock.rs b/pallets/vbnc-convert/src/mock.rs index ce3b49e9f..88d8cc86e 100644 --- a/pallets/vbnc-convert/src/mock.rs +++ b/pallets/vbnc-convert/src/mock.rs @@ -24,9 +24,9 @@ use bifrost_asset_registry::AssetIdMaps; use bifrost_primitives::{ currency::{BNC, KSM, VBNC, VBNC_P, VKSM}, - CurrencyId, CurrencyIdMapping, TokenSymbol, + CurrencyId, CurrencyIdMapping, VBNCConvertPalletId, }; -use frame_support::{ord_parameter_types, parameter_types, traits::Nothing, PalletId}; +use frame_support::{ord_parameter_types, parameter_types, traits::Nothing}; use frame_system::EnsureSignedBy; use sp_core::H256; use sp_runtime::{ @@ -94,7 +94,7 @@ impl frame_system::Config for Runtime { } parameter_types! { - pub const NativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::BNC); + pub const NativeCurrencyId: CurrencyId = BNC; } pub type AdaptedBasicCurrency = @@ -165,10 +165,6 @@ impl bifrost_asset_registry::Config for Runtime { type WeightInfo = (); } -parameter_types! { - pub const VBNCConvertPalletId: PalletId = PalletId(*b"bf/vbncc"); -} - impl bifrost_vbnc_convert::Config for Runtime { type RuntimeEvent = RuntimeEvent; type MultiCurrency = Currencies; diff --git a/pallets/vsbond-auction/src/mock.rs b/pallets/vsbond-auction/src/mock.rs index 2e4c9088e..a7ade8803 100644 --- a/pallets/vsbond-auction/src/mock.rs +++ b/pallets/vsbond-auction/src/mock.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use bifrost_primitives::{Amount, Balance, CurrencyId, TokenSymbol}; +use bifrost_primitives::{Amount, Balance, CurrencyId, TokenSymbol, VsbondAuctionPalletId, KSM}; #[cfg(feature = "runtime-benchmarks")] use frame_benchmarking::{account, whitelisted_caller}; use frame_support::{ @@ -111,10 +111,9 @@ impl orml_tokens::Config for Test { } parameter_types! { - pub const InvoicingCurrency: CurrencyId = CurrencyId::Token(TokenSymbol::KSM); + pub const InvoicingCurrency: CurrencyId = KSM; pub const MaximumOrderInTrade: u32 = 5; pub const MinimumSupply: Balance = 0; - pub const VsbondAuctionPalletId: PalletId = PalletId(*b"bf/vsbnd"); pub BifrostTreasuryAccount: AccountId = PalletId(*b"bf/trsry").into_account_truncating(); } diff --git a/pallets/vstoken-conversion/src/mock.rs b/pallets/vstoken-conversion/src/mock.rs index 0e9fa07d8..46e56b292 100644 --- a/pallets/vstoken-conversion/src/mock.rs +++ b/pallets/vstoken-conversion/src/mock.rs @@ -21,8 +21,12 @@ #![cfg(test)] #![allow(non_upper_case_globals)] -pub use bifrost_primitives::{currency::*, CurrencyId, TokenSymbol}; -use frame_support::{derive_impl, ord_parameter_types, parameter_types, traits::Nothing, PalletId}; +pub use bifrost_primitives::{currency::*, CurrencyId}; +use bifrost_primitives::{ + currency::{ASG, KSM}, + BifrostVsbondAccount, +}; +use frame_support::{derive_impl, ord_parameter_types, parameter_types, traits::Nothing}; use frame_system::EnsureSignedBy; use sp_core::ConstU32; use sp_runtime::{traits::IdentityLookup, AccountId32, BuildStorage}; @@ -66,7 +70,7 @@ impl frame_system::Config for Runtime { } parameter_types! { - pub const GetNativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::ASG); + pub const GetNativeCurrencyId: CurrencyId = ASG; } pub type AdaptedBasicCurrency = @@ -120,13 +124,11 @@ impl orml_tokens::Config for Runtime { parameter_types! { pub const TreasuryAccount: AccountId32 = TREASURY_ACCOUNT; - pub BifrostVsbondAccount: PalletId = PalletId(*b"bf/salpb"); } ord_parameter_types! { pub const One: AccountId = ALICE; - // pub const RelayCurrencyId: CurrencyId = CurrencyId::Token2(DOT_TOKEN_ID); - pub const RelayCurrencyId: CurrencyId = CurrencyId::Token(TokenSymbol::KSM); + pub const RelayCurrencyId: CurrencyId = KSM; } impl bifrost_vstoken_conversion::Config for Runtime { diff --git a/pallets/vstoken-conversion/src/tests.rs b/pallets/vstoken-conversion/src/tests.rs index d997229fd..c1eb850ad 100644 --- a/pallets/vstoken-conversion/src/tests.rs +++ b/pallets/vstoken-conversion/src/tests.rs @@ -20,6 +20,7 @@ #![cfg(test)] +use bifrost_primitives::currency::KSM; use frame_support::{assert_noop, assert_ok}; pub use primitives::{VstokenConversionExchangeFee, VstokenConversionExchangeRate}; use sp_arithmetic::per_things::Percent; diff --git a/pallets/vtoken-minting/src/mock.rs b/pallets/vtoken-minting/src/mock.rs index f04aa0e80..3a7bb38ad 100644 --- a/pallets/vtoken-minting/src/mock.rs +++ b/pallets/vtoken-minting/src/mock.rs @@ -25,7 +25,8 @@ use bb_bnc::{BbBNCInterface, Point}; use bifrost_asset_registry::AssetIdMaps; use bifrost_primitives::{ currency::{BNC, DOT, FIL, KSM, MOVR, VBNC, VFIL, VKSM, VMOVR}, - CurrencyId, CurrencyIdMapping, MoonbeamChainId, SlpxOperator, TokenSymbol, + BifrostEntranceAccount, BifrostExitAccount, BifrostFeeAccount, CurrencyId, CurrencyIdMapping, + IncentivePoolAccount, MoonbeamChainId, SlpxOperator, KUSD, }; use bifrost_runtime_common::{micro, milli}; use bifrost_slp::{QueryId, QueryResponseManager}; @@ -35,10 +36,8 @@ use frame_support::{ pallet_prelude::Get, parameter_types, traits::{Everything, Nothing}, - PalletId, }; use frame_system::{EnsureRoot, EnsureSignedBy}; -use hex_literal::hex; use orml_traits::{location::RelativeReserveProvider, parameter_type_with_key}; use sp_runtime::{ traits::{ConstU32, IdentityLookup}, @@ -89,7 +88,7 @@ impl frame_system::Config for Runtime { } parameter_types! { - pub const NativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::BNC); + pub const NativeCurrencyId: CurrencyId = BNC; } pub type AdaptedBasicCurrency = @@ -104,11 +103,8 @@ impl bifrost_currencies::Config for Runtime { parameter_types! { pub const ExistentialDeposit: Balance = 1; - // pub const NativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::BNC); - // pub const RelayCurrencyId: CurrencyId = CurrencyId::Token(TokenSymbol::KSM); - pub const StableCurrencyId: CurrencyId = CurrencyId::Stable(TokenSymbol::KUSD); - // pub SelfParaId: u32 = ParachainInfo::parachain_id().into(); - pub const PolkadotCurrencyId: CurrencyId = CurrencyId::Token(TokenSymbol::DOT); + pub const StableCurrencyId: CurrencyId = KUSD; + pub const PolkadotCurrencyId: CurrencyId = DOT; } impl pallet_balances::Config for Runtime { @@ -197,15 +193,11 @@ parameter_types! { pub const MaximumUnlockIdOfUser: u32 = 1_000; pub const MaximumUnlockIdOfTimeUnit: u32 = 1_000; pub const MaxLockRecords: u32 = 64; - pub BifrostEntranceAccount: PalletId = PalletId(*b"bf/vtkin"); - pub BifrostExitAccount: PalletId = PalletId(*b"bf/vtout"); - pub IncentivePoolAccount: PalletId = PalletId(*b"bf/inpoo"); - pub BifrostFeeAccount: AccountId = hex!["e4da05f08e89bf6c43260d96f26fffcfc7deae5b465da08669a9d008e64c2c63"].into(); } ord_parameter_types! { pub const One: AccountId = ALICE; - pub const RelayCurrencyId: CurrencyId = CurrencyId::Token(TokenSymbol::KSM); + pub const RelayCurrencyId: CurrencyId = KSM; } impl vtoken_minting::Config for Runtime { diff --git a/pallets/vtoken-voting/src/mock.rs b/pallets/vtoken-voting/src/mock.rs index a9bada263..16a6adfc6 100644 --- a/pallets/vtoken-voting/src/mock.rs +++ b/pallets/vtoken-voting/src/mock.rs @@ -23,7 +23,7 @@ use crate::{BalanceOf, DerivativeAccountHandler, DerivativeIndex, DispatchResult use bifrost_primitives::{ currency::{KSM, VBNC, VKSM}, traits::XcmDestWeightAndFeeHandler, - CurrencyId, MockXcmRouter, TokenSymbol, VTokenSupplyProvider, XcmOperationType, + CurrencyId, MockXcmRouter, VTokenSupplyProvider, XcmOperationType, BNC, }; use cumulus_primitives_core::ParaId; use frame_support::{ @@ -80,7 +80,7 @@ impl frame_system::Config for Runtime { } parameter_types! { - pub const NativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::BNC); + pub const NativeCurrencyId: CurrencyId = BNC; } pub type AdaptedBasicCurrency = diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index c7081880c..93e60be9f 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -11,6 +11,7 @@ scale-info = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] } frame-support = { workspace = true } +hex-literal = { workspace = true } sp-core = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } diff --git a/primitives/src/currency.rs b/primitives/src/currency.rs index 3709c2598..e6d1e67f4 100644 --- a/primitives/src/currency.rs +++ b/primitives/src/currency.rs @@ -44,6 +44,8 @@ pub const VSKSM: CurrencyId = CurrencyId::VSToken(TokenSymbol::KSM); pub const PHA: CurrencyId = CurrencyId::Token(TokenSymbol::PHA); pub const VPHA: CurrencyId = CurrencyId::VToken(TokenSymbol::PHA); pub const ZLK: CurrencyId = CurrencyId::Token(TokenSymbol::ZLK); +pub const KUSD: CurrencyId = CurrencyId::Stable(TokenSymbol::KUSD); +pub const ASG: CurrencyId = CurrencyId::Native(TokenSymbol::ASG); pub const DOT_TOKEN_ID: u8 = 0u8; pub const DOT: CurrencyId = CurrencyId::Token2(DOT_TOKEN_ID); diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 0040e851d..b711cb02d 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -20,6 +20,8 @@ #![cfg_attr(not(feature = "std"), no_std)] +use frame_support::{parameter_types, PalletId}; +use hex_literal::hex; use parity_scale_codec::MaxEncodedLen; use scale_info::TypeInfo; use sp_core::{Decode, Encode, RuntimeDebug, H160}; @@ -156,6 +158,44 @@ pub type DerivativeIndex = u16; pub type TimeStampedPrice = orml_oracle::TimestampedValue; +// Pallet Id +parameter_types! { + pub const BifrostCrowdloanId: PalletId = PalletId(*b"bf/salp#"); + pub BifrostEntranceAccount: PalletId = PalletId(*b"bf/vtkin"); + pub BifrostExitAccount: PalletId = PalletId(*b"bf/vtout"); + pub BifrostVsbondAccount: PalletId = PalletId(*b"bf/salpb"); + pub const BuyBackAccount: PalletId = PalletId(*b"bf/bybck"); + pub const BuybackPalletId: PalletId = PalletId(*b"bf/salpc"); + pub const CloudsPalletId: PalletId = PalletId(*b"bf/cloud"); + pub const CommissionPalletId: PalletId = PalletId(*b"bf/comms"); + pub const FarmingBoostPalletId: PalletId = PalletId(*b"bf/fmbst"); + pub const FarmingGaugeRewardIssuerPalletId: PalletId = PalletId(*b"bf/fmgar"); + pub const FarmingKeeperPalletId: PalletId = PalletId(*b"bf/fmkpr"); + pub const FarmingRewardIssuerPalletId: PalletId = PalletId(*b"bf/fmrir"); + pub const FeeSharePalletId: PalletId = PalletId(*b"bf/feesh"); + pub const FlexibleFeePalletId: PalletId = PalletId(*b"bf/flexi"); + pub IncentivePoolAccount: PalletId = PalletId(*b"bf/inpoo"); + pub IncentivePalletId: PalletId = PalletId(*b"bf/bbict"); + pub const LendMarketPalletId: PalletId = PalletId(*b"bf/ldmkt"); + pub const LighteningRedeemPalletId: PalletId = PalletId(*b"lighten#"); + pub const LiquidityAccount: PalletId = PalletId(*b"bf/liqdt"); + pub const LiquidityMiningPalletId: PalletId = PalletId(*b"mining##"); + pub const ParachainStakingPalletId: PalletId = PalletId(*b"bf/stake"); + pub const SlpEntrancePalletId: PalletId = PalletId(*b"bf/vtkin"); + pub const StableAssetPalletId: PalletId = PalletId(*b"nuts/sta"); + pub const SystemMakerPalletId: PalletId = PalletId(*b"bf/sysmk"); + pub const SystemStakingPalletId: PalletId = PalletId(*b"bf/sysst"); + pub const VBNCConvertPalletId: PalletId = PalletId(*b"bf/vbncc"); + pub const VeMintingPalletId: PalletId = PalletId(*b"bf/vemnt"); + pub const VsbondAuctionPalletId: PalletId = PalletId(*b"bf/vsbnd"); + pub const ZenlinkPalletId: PalletId = PalletId(*b"/zenlink"); +} + +// Account Id +parameter_types! { + pub BifrostFeeAccount: AccountId = hex!["e4da05f08e89bf6c43260d96f26fffcfc7deae5b465da08669a9d008e64c2c63"].into(); +} + // For vtoken-minting #[derive( PartialEq, Eq, Clone, Encode, Decode, MaxEncodedLen, RuntimeDebug, scale_info::TypeInfo, From 0e8f755cddcd9f85de87a44d7c023ec511b00605 Mon Sep 17 00:00:00 2001 From: NingBo Wang <2536935847@qq.com> Date: Wed, 25 Sep 2024 15:03:48 +0800 Subject: [PATCH 05/30] Optimize xcm interface (#1439) * Optimize xcm-interface pallet * Add weights * Add weights * Add weights * Optimize xcm-interface pallet --- Cargo.lock | 2 + pallets/flexible-fee/src/lib.rs | 44 +- pallets/flexible-fee/src/tests.rs | 43 ++ pallets/salp/src/lib.rs | 446 +----------------- pallets/slp/src/agents/utils.rs | 42 +- pallets/xcm-interface/Cargo.toml | 5 +- pallets/xcm-interface/src/benchmarking.rs | 43 ++ pallets/xcm-interface/src/calls.rs | 128 +---- pallets/xcm-interface/src/lib.rs | 330 +++---------- pallets/xcm-interface/src/mock.rs | 157 ++++++ pallets/xcm-interface/src/tests.rs | 50 ++ pallets/xcm-interface/src/traits.rs | 159 ------- pallets/xcm-interface/src/weights.rs | 82 ++++ primitives/src/xcm.rs | 2 + runtime/bifrost-kusama/Cargo.toml | 1 + runtime/bifrost-kusama/src/lib.rs | 9 +- runtime/bifrost-kusama/src/migration.rs | 3 - .../src/weights/bifrost_xcm_interface.rs | 78 +++ runtime/bifrost-kusama/src/weights/mod.rs | 1 + runtime/bifrost-kusama/src/xcm_config.rs | 33 +- runtime/bifrost-polkadot/Cargo.toml | 1 + runtime/bifrost-polkadot/src/lib.rs | 6 +- .../src/weights/bifrost_xcm_interface.rs | 78 +++ runtime/bifrost-polkadot/src/weights/mod.rs | 1 + runtime/bifrost-polkadot/src/xcm_config.rs | 12 +- 25 files changed, 665 insertions(+), 1091 deletions(-) create mode 100644 pallets/xcm-interface/src/benchmarking.rs create mode 100644 pallets/xcm-interface/src/mock.rs create mode 100644 pallets/xcm-interface/src/tests.rs delete mode 100644 pallets/xcm-interface/src/traits.rs create mode 100644 pallets/xcm-interface/src/weights.rs create mode 100644 runtime/bifrost-kusama/src/weights/bifrost_xcm_interface.rs create mode 100644 runtime/bifrost-polkadot/src/weights/bifrost_xcm_interface.rs diff --git a/Cargo.lock b/Cargo.lock index 6476ca98b..8c990f909 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2376,11 +2376,13 @@ name = "bifrost-xcm-interface" version = "0.8.0" dependencies = [ "bifrost-asset-registry", + "bifrost-currencies", "bifrost-primitives", "cumulus-primitives-core", "frame-benchmarking", "frame-support", "frame-system", + "orml-tokens", "orml-traits", "pallet-balances", "pallet-xcm", diff --git a/pallets/flexible-fee/src/lib.rs b/pallets/flexible-fee/src/lib.rs index 889b9f494..2b585be1f 100644 --- a/pallets/flexible-fee/src/lib.rs +++ b/pallets/flexible-fee/src/lib.rs @@ -22,10 +22,10 @@ pub use crate::pallet::*; use bifrost_primitives::{ currency::{VGLMR, VMANTA, WETH}, traits::XcmDestWeightAndFeeHandler, - Balance, BalanceCmp, CurrencyId, DerivativeIndex, OraclePriceProvider, Price, TryConvertFrom, - XcmOperationType, BNC, DOT, GLMR, MANTA, VBNC, VDOT, + AssetHubChainId, Balance, BalanceCmp, CurrencyId, DerivativeIndex, OraclePriceProvider, Price, + TryConvertFrom, XcmOperationType, BNC, DOT, GLMR, MANTA, VBNC, VDOT, }; -use bifrost_xcm_interface::{polkadot::RelaychainCall, traits::parachains, PolkadotXcmCall}; +use bifrost_xcm_interface::calls::{PolkadotXcmCall, RelaychainCall}; use core::convert::Into; use cumulus_primitives_core::ParaId; use frame_support::{ @@ -274,28 +274,24 @@ impl Pallet { )), }; - let remote_call = - RelaychainCall::, AccountIdOf, BlockNumberFor>::XcmPallet( - PolkadotXcmCall::LimitedTeleportAssets( - Box::new(Location::new(0, [Parachain(parachains::Statemine::ID)]).into()), - Box::new( - Location::new( - 0, - [AccountId32 { - network: None, - id: Sibling::from(T::ParachainId::get()) - .into_account_truncating(), - }], - ) - .into(), - ), - Box::new(asset.into()), + let remote_call = RelaychainCall::XcmPallet(PolkadotXcmCall::LimitedTeleportAssets( + Box::new(Location::new(0, [Parachain(AssetHubChainId::get())]).into()), + Box::new( + Location::new( 0, - Unlimited, - ), - ) - .encode() - .into(); + [AccountId32 { + network: None, + id: Sibling::from(T::ParachainId::get()).into_account_truncating(), + }], + ) + .into(), + ), + Box::new(asset.into()), + 0, + Unlimited, + )) + .encode() + .into(); let (require_weight_at_most, xcm_fee) = T::XcmWeightAndFeeHandler::get_operation_weight_and_fee( diff --git a/pallets/flexible-fee/src/tests.rs b/pallets/flexible-fee/src/tests.rs index a365b46d4..ce373e01e 100644 --- a/pallets/flexible-fee/src/tests.rs +++ b/pallets/flexible-fee/src/tests.rs @@ -327,6 +327,49 @@ fn correct_and_deposit_fee_should_work() { }); } +#[test] +fn correct_and_deposit_fee_with_tip() { + new_test_ext().execute_with(|| { + basic_setup(); + + let corrected_fee = 5 * 10u128.pow(12); + let tip = 5 * 10u128.pow(12); + + assert_eq!(Currencies::free_balance(BNC, &ALICE), 1000 * 10u128.pow(12)); + + let already_withdrawn = Some(PaymentInfo::Native(10 * 10u128.pow(12))); + assert_ok!(FlexibleFee::correct_and_deposit_fee( + &ALICE, + &info(), + &post_info(), + corrected_fee, + tip, + already_withdrawn + )); + assert_eq!(Currencies::free_balance(BNC, &ALICE), 1005 * 10u128.pow(12)); + + let corrected_fee = 10 * 10u128.pow(12); + let tip = 10 * 10u128.pow(12); + assert_eq!(Currencies::free_balance(DOT, &ALICE), 1000 * 10u128.pow(10)); + + let already_withdrawn = Some(PaymentInfo::NonNative( + 1 * 10u128.pow(10), + DOT, + FixedU128::from_inner(200_000_000_000_000_000), + FixedU128::from(5), + )); + assert_ok!(FlexibleFee::correct_and_deposit_fee( + &ALICE, + &info(), + &post_info(), + corrected_fee, + tip, + already_withdrawn + )); + assert_eq!(Currencies::free_balance(DOT, &ALICE), 10006 * 10u128.pow(9)); + }); +} + #[test] fn get_currency_asset_id_should_work() { new_test_ext().execute_with(|| { diff --git a/pallets/salp/src/lib.rs b/pallets/salp/src/lib.rs index a1a09090d..d4943958e 100644 --- a/pallets/salp/src/lib.rs +++ b/pallets/salp/src/lib.rs @@ -19,12 +19,6 @@ // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] -#[cfg(feature = "runtime-benchmarks")] -pub mod benchmarking; -#[cfg(test)] -pub mod mock; -#[cfg(test)] -mod tests; pub mod weights; pub use weights::WeightInfo; @@ -33,12 +27,10 @@ use bifrost_primitives::{ ContributionStatus, CurrencyIdConversion, CurrencyIdRegister, TrieIndex, VtokenMintingInterface, }; use bifrost_stable_pool::{traits::StablePoolHandler, StableAssetPoolId}; -use bifrost_xcm_interface::ChainId; -use cumulus_primitives_core::{QueryId, Response}; +use cumulus_primitives_core::QueryId; use frame_support::{pallet_prelude::*, sp_runtime::SaturatedConversion}; use orml_traits::MultiCurrency; pub use pallet::*; -use pallet_xcm::ensure_response; use scale_info::TypeInfo; use sp_runtime::traits::One; @@ -95,10 +87,10 @@ pub struct ReserveInfo { #[frame_support::pallet] pub mod pallet { // Import various types used to declare pallet in scope. + use super::*; use bifrost_primitives::{CurrencyId, LeasePeriod, MessageId, Nonce, ParaId}; - use bifrost_xcm_interface::traits::XcmHelper; use frame_support::{ - pallet_prelude::{storage::child, *}, + pallet_prelude::storage::child, sp_runtime::traits::{AccountIdConversion, CheckedAdd, Hash, Saturating, Zero}, storage::ChildTriePrefixIterator, PalletId, @@ -109,9 +101,6 @@ pub mod pallet { }; use sp_arithmetic::Percent; use sp_std::{convert::TryInto, prelude::*}; - use xcm::v3::MaybeErrorCode; - - use super::*; #[pallet::config] pub trait Config: frame_system::Config { @@ -166,9 +155,6 @@ pub mod pallet { type WeightInfo: WeightInfo; - /// The XcmInterface to manage the staking of sub-account on relaychain. - type XcmInterface: XcmHelper, BalanceOf>; - #[pallet::constant] type TreasuryAccount: Get; @@ -674,82 +660,6 @@ pub mod pallet { Ok(()) } - // unused but xcm-interface - #[pallet::call_index(20)] - #[pallet::weight(T::WeightInfo::confirm_contribute())] - pub fn confirm_contribution( - origin: OriginFor, - query_id: QueryId, - response: Response, - ) -> DispatchResult { - let responder = ensure_response(::RuntimeOrigin::from(origin))?; - ensure!(responder == xcm::v4::Location::parent(), Error::::ResponderNotRelayChain); - - let (index, contributer, _amount) = QueryIdContributionInfo::::get(query_id) - .ok_or(Error::::NotFindContributionValue)?; - - let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; - let can_confirm = fund.status == FundStatus::Ongoing || - fund.status == FundStatus::Failed || - fund.status == FundStatus::Success; - ensure!(can_confirm, Error::::InvalidFundStatus); - - let (contributed, status) = Self::contribution(fund.trie_index, &contributer); - ensure!(status.is_contributing(), Error::::InvalidContributionStatus); - let contributing = status.contributing(); - - let vs_token = T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) - .map_err(|_| Error::::NotSupportTokenType)?; - let vs_bond = T::CurrencyIdConversion::convert_to_vsbond( - T::RelayChainToken::get(), - index, - fund.first_slot, - fund.last_slot, - ) - .map_err(|_| Error::::NotSupportTokenType)?; - - if let Response::DispatchResult(MaybeErrorCode::Success) = response { - // Issue reserved vsToken/vsBond to contributor - T::MultiCurrency::deposit(vs_token, &contributer, contributing)?; - T::MultiCurrency::deposit(vs_bond, &contributer, contributing)?; - - // Update the raised of fund - let fund_new = - FundInfo { raised: fund.raised.saturating_add(contributing), ..fund }; - Funds::::insert(index, Some(fund_new)); - - T::MultiCurrency::unreserve(T::RelayChainToken::get(), &contributer, contributing); - T::MultiCurrency::transfer( - T::RelayChainToken::get(), - &contributer, - &Self::fund_account_id(index), - contributing, - )?; - - // Update the contribution of contributer - let contributed_new = contributed.saturating_add(contributing); - Self::put_contribution( - fund.trie_index, - &contributer, - contributed_new, - ContributionStatus::Idle, - ); - Self::deposit_event(Event::Contributed(contributer, index, contributing)); - } else { - // Update the contribution of contributer - Self::put_contribution( - fund.trie_index, - &contributer, - contributed, - ContributionStatus::Idle, - ); - T::MultiCurrency::unreserve(T::RelayChainToken::get(), &contributer, contributing); - Self::deposit_event(Event::ContributeFailed(contributer, index, contributing)); - } - QueryIdContributionInfo::::remove(query_id); - Ok(()) - } - #[pallet::call_index(21)] #[pallet::weight(T::WeightInfo::buyback_vstoken_by_stable_pool())] pub fn buyback_vstoken_by_stable_pool( @@ -825,315 +735,6 @@ pub mod pallet { } } - // These methods are no longer in use and are now only called for testing and benchmarking - // purposes. - impl Pallet { - pub(crate) fn fund_success(origin: OriginFor, index: ParaId) -> DispatchResult { - T::EnsureConfirmAsGovernance::ensure_origin(origin)?; - - let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; - ensure!(fund.status == FundStatus::Ongoing, Error::::InvalidFundStatus); - - let fund_new = FundInfo { status: FundStatus::Success, ..fund }; - Funds::::insert(index, Some(fund_new)); - Self::deposit_event(Event::::Success(index)); - - Ok(()) - } - - pub(crate) fn fund_fail(origin: OriginFor, index: ParaId) -> DispatchResult { - T::EnsureConfirmAsGovernance::ensure_origin(origin)?; - - // crownload is failed, so enable the withdrawal function of vsToken/vsBond - let fund = crate::pallet::Funds::::get(index) - .ok_or(crate::pallet::Error::::InvalidParaId)?; - ensure!(fund.status == FundStatus::Ongoing, Error::::InvalidFundStatus); - - let fund_new = crate::FundInfo { status: crate::FundStatus::Failed, ..fund }; - crate::pallet::Funds::::insert(index, Some(fund_new)); - Self::deposit_event(crate::pallet::Event::::Failed(index)); - - Ok(()) - } - - pub(crate) fn continue_fund( - origin: OriginFor, - index: ParaId, - first_slot: LeasePeriod, - last_slot: LeasePeriod, - ) -> DispatchResult { - T::EnsureConfirmAsGovernance::ensure_origin(origin)?; - - // crownload is failed, so enable the withdrawal function of vsToken/vsBond - let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; - ensure!(fund.status == FundStatus::RefundWithdrew, Error::::InvalidFundStatus); - ensure!( - fund.first_slot != first_slot || fund.last_slot != last_slot, - Error::::InvalidFundSameSlot - ); - - let fund_old = FundInfo { status: FundStatus::FailedToContinue, ..fund }; - FailedFundsToRefund::::insert( - (index, fund.first_slot, fund.last_slot), - Some(fund_old.clone()), - ); - let fund_new = FundInfo { status: FundStatus::Ongoing, first_slot, last_slot, ..fund }; - Funds::::insert(index, Some(fund_new)); - - match T::RelayChainToken::get() { - CurrencyId::Token(token_symbol) => - if !T::CurrencyIdRegister::check_vsbond_registered( - token_symbol, - index, - first_slot, - last_slot, - ) { - T::CurrencyIdRegister::register_vsbond_metadata( - token_symbol, - index, - first_slot, - last_slot, - )?; - }, - CurrencyId::Token2(token_id) => { - if !T::CurrencyIdRegister::check_vsbond2_registered( - token_id, index, first_slot, last_slot, - ) { - T::CurrencyIdRegister::register_vsbond2_metadata( - token_id, index, first_slot, last_slot, - )?; - } - }, - _ => (), - } - - Self::deposit_event(Event::::Continued( - index, - fund_old.first_slot, - fund_old.last_slot, - )); - - Ok(()) - } - - /// Create a new crowdloaning campaign for a parachain slot deposit for the current auction. - pub(crate) fn create( - origin: OriginFor, - index: ParaId, - cap: BalanceOf, - first_slot: LeasePeriod, - last_slot: LeasePeriod, - ) -> DispatchResult { - T::EnsureConfirmAsGovernance::ensure_origin(origin)?; - - ensure!(!Funds::::contains_key(index), Error::::FundAlreadyCreated); - - ensure!(first_slot <= last_slot, Error::::LastSlotBeforeFirstSlot); - - let last_slot_limit = first_slot - .checked_add(((T::SlotLength::get() as u32) - 1).into()) - .ok_or(Error::::FirstSlotTooFarInFuture)?; - ensure!(last_slot <= last_slot_limit, Error::::LastSlotTooFarInFuture); - - Funds::::insert( - index, - Some(FundInfo { - raised: Zero::zero(), - cap, - first_slot, - last_slot, - trie_index: Self::next_trie_index()?, - status: FundStatus::Ongoing, - }), - ); - - match T::RelayChainToken::get() { - CurrencyId::Token(token_symbol) => - if !T::CurrencyIdRegister::check_vsbond_registered( - token_symbol, - index, - first_slot, - last_slot, - ) { - T::CurrencyIdRegister::register_vsbond_metadata( - token_symbol, - index, - first_slot, - last_slot, - )?; - }, - CurrencyId::Token2(token_id) => { - if !T::CurrencyIdRegister::check_vsbond2_registered( - token_id, index, first_slot, last_slot, - ) { - T::CurrencyIdRegister::register_vsbond2_metadata( - token_id, index, first_slot, last_slot, - )?; - } - }, - _ => (), - } - - Self::deposit_event(Event::::Created(index)); - - Ok(()) - } - - /// Contribute to a crowd sale. This will transfer some balance over to fund a parachain - /// slot. It will be withdrawable in two instances: the parachain becomes retired; or the - /// slot is unable to be purchased and the timeout expires. - pub(crate) fn contribute( - origin: OriginFor, - index: ParaId, - value: BalanceOf, - ) -> DispatchResult { - let who = ensure_signed(origin.clone())?; - - let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; - ensure!(fund.status == FundStatus::Ongoing, Error::::InvalidFundStatus); - - ensure!(value >= T::MinContribution::get(), Error::::ContributionTooSmall); - - let raised = fund.raised.checked_add(&value).ok_or(Error::::Overflow)?; - ensure!(raised <= fund.cap, Error::::CapExceeded); - - let (contributed, status) = Self::contribution(fund.trie_index, &who); - ensure!( - status == ContributionStatus::Idle || - status == ContributionStatus::Refunded || - status == ContributionStatus::Redeemed || - status == ContributionStatus::Unlocked, - Error::::InvalidContributionStatus - ); - - ensure!( - T::MultiCurrency::can_reserve(T::RelayChainToken::get(), &who, value), - Error::::NotEnoughBalanceToContribute - ); - - T::MultiCurrency::reserve(T::RelayChainToken::get(), &who, value)?; - - Self::put_contribution( - fund.trie_index, - &who, - contributed, - ContributionStatus::Contributing(value), - ); - - let message_id = T::XcmInterface::contribute(who.clone(), index, value)?; - - Self::deposit_event(Event::Contributing(who, index, value, message_id)); - Ok(()) - } - - /// Confirm contribute - pub(crate) fn confirm_contribute( - origin: OriginFor, - query_id: QueryId, - is_success: bool, - ) -> DispatchResult { - let confirmor = ensure_signed(origin.clone())?; - if Some(confirmor) != MultisigConfirmAccount::::get() { - return Err(DispatchError::BadOrigin.into()); - } - - let (index, contributer, _amount) = QueryIdContributionInfo::::get(query_id) - .ok_or(Error::::NotFindContributionValue)?; - - let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; - let can_confirm = fund.status == FundStatus::Ongoing || - fund.status == FundStatus::Failed || - fund.status == FundStatus::Success; - ensure!(can_confirm, Error::::InvalidFundStatus); - - let (contributed, status) = Self::contribution(fund.trie_index, &contributer); - ensure!(status.is_contributing(), Error::::InvalidContributionStatus); - let contributing = status.contributing(); - - let vs_token = T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) - .map_err(|_| Error::::NotSupportTokenType)?; - let vs_bond = T::CurrencyIdConversion::convert_to_vsbond( - T::RelayChainToken::get(), - index, - fund.first_slot, - fund.last_slot, - ) - .map_err(|_| Error::::NotSupportTokenType)?; - - if is_success { - // Issue reserved vsToken/vsBond to contributor - T::MultiCurrency::deposit(vs_token, &contributer, contributing)?; - T::MultiCurrency::deposit(vs_bond, &contributer, contributing)?; - - // Update the raised of fund - let fund_new = - FundInfo { raised: fund.raised.saturating_add(contributing), ..fund }; - Funds::::insert(index, Some(fund_new)); - - T::MultiCurrency::unreserve(T::RelayChainToken::get(), &contributer, contributing); - T::MultiCurrency::transfer( - T::RelayChainToken::get(), - &contributer, - &Self::fund_account_id(index), - contributing, - )?; - - // Update the contribution of contributer - let contributed_new = contributed.saturating_add(contributing); - Self::put_contribution( - fund.trie_index, - &contributer, - contributed_new, - ContributionStatus::Idle, - ); - Self::deposit_event(Event::Contributed(contributer, index, contributing)); - } else { - // Update the contribution of contributer - Self::put_contribution( - fund.trie_index, - &contributer, - contributed, - ContributionStatus::Idle, - ); - T::MultiCurrency::unreserve(T::RelayChainToken::get(), &contributer, contributing); - Self::deposit_event(Event::ContributeFailed(contributer, index, contributing)); - } - - QueryIdContributionInfo::::remove(query_id); - - Ok(()) - } - - /// Unlock the reserved vsToken/vsBond after fund success - pub(crate) fn unlock( - origin: OriginFor, - who: AccountIdOf, - index: ParaId, - ) -> DispatchResult { - ensure_signed(origin)?; - let fund = Funds::::get(index).ok_or(Error::::InvalidParaId)?; - - let (contributed, _) = Self::contribution(fund.trie_index, &who); - - let vs_token = T::CurrencyIdConversion::convert_to_vstoken(T::RelayChainToken::get()) - .map_err(|_| Error::::NotSupportTokenType)?; - let vs_bond = T::CurrencyIdConversion::convert_to_vsbond( - T::RelayChainToken::get(), - index, - fund.first_slot, - fund.last_slot, - ) - .map_err(|_| Error::::NotSupportTokenType)?; - - T::MultiCurrency::unreserve(vs_token, &who, contributed); - T::MultiCurrency::unreserve(vs_bond, &who, contributed); - - Self::deposit_event(Event::::Unlocked(who, index, contributed)); - - Ok(()) - } - } - impl Pallet { /// Check if the vsBond is `past` the redeemable date pub(crate) fn is_expired( @@ -1208,49 +809,8 @@ pub mod pallet { ) } - pub(crate) fn next_trie_index() -> Result> { - CurrentTrieIndex::::try_mutate(|ti| { - *ti = ti.checked_add(1).ok_or(Error::::Overflow)?; - Ok(*ti - 1) - }) - } - - fn put_contribution( - index: TrieIndex, - who: &AccountIdOf, - contributed: BalanceOf, - status: ContributionStatus>, - ) { - who.using_encoded(|b| { - child::put(&Self::id_from_index(index), b, &(contributed, status)) - }); - } - fn kill_contribution(index: TrieIndex, who: &AccountIdOf) { who.using_encoded(|b| child::kill(&Self::id_from_index(index), b)); } - - pub(crate) fn set_balance(who: &AccountIdOf, value: BalanceOf) -> DispatchResult { - T::MultiCurrency::deposit(T::RelayChainToken::get(), who, value) - } - } -} - -impl - bifrost_xcm_interface::SalpHelper, ::RuntimeCall, BalanceOf> - for Pallet -{ - fn confirm_contribute_call() -> ::RuntimeCall { - let call = Call::::confirm_contribution { query_id: 0, response: Default::default() }; - ::RuntimeCall::from(call) - } - - fn bind_query_id_and_contribution( - query_id: QueryId, - index: ChainId, - contributer: AccountIdOf, - amount: BalanceOf, - ) { - QueryIdContributionInfo::::insert(query_id, (index, contributer, amount)); } } diff --git a/pallets/slp/src/agents/utils.rs b/pallets/slp/src/agents/utils.rs index c2cb60474..2c970f99e 100644 --- a/pallets/slp/src/agents/utils.rs +++ b/pallets/slp/src/agents/utils.rs @@ -21,8 +21,9 @@ use crate::{ ValidatorsByDelegatorUpdateEntry, ValidatorsByDelegatorXcmUpdateQueue, ASTR, DOT, GLMR, H160, KSM, MANTA, MOVR, PHA, }; -use bifrost_primitives::CurrencyId; -use bifrost_xcm_interface::traits::parachains; +use bifrost_primitives::{ + AstarChainId, CurrencyId, MantaChainId, MoonbeamChainId, MoonriverChainId, PhalaChainId, +}; use frame_support::ensure; use parity_scale_codec::Encode; use sp_core::Get; @@ -323,18 +324,16 @@ impl Pallet { KSM | DOT => Ok(xcm::v4::Location::parent()), MOVR => Ok(xcm::v4::Location::new( 1, - [xcm::v4::prelude::Parachain(parachains::moonriver::ID)], - )), - GLMR => Ok(xcm::v4::Location::new( - 1, - [xcm::v4::prelude::Parachain(parachains::moonbeam::ID)], + [xcm::v4::prelude::Parachain(MoonriverChainId::get())], )), + GLMR => + Ok(xcm::v4::Location::new(1, [xcm::v4::prelude::Parachain(MoonbeamChainId::get())])), ASTR => - Ok(xcm::v4::Location::new(1, [xcm::v4::prelude::Parachain(parachains::astar::ID)])), + Ok(xcm::v4::Location::new(1, [xcm::v4::prelude::Parachain(AstarChainId::get())])), MANTA => - Ok(xcm::v4::Location::new(1, [xcm::v4::prelude::Parachain(parachains::manta::ID)])), + Ok(xcm::v4::Location::new(1, [xcm::v4::prelude::Parachain(MantaChainId::get())])), PHA => - Ok(xcm::v4::Location::new(1, [xcm::v4::prelude::Parachain(parachains::phala::ID)])), + Ok(xcm::v4::Location::new(1, [xcm::v4::prelude::Parachain(PhalaChainId::get())])), _ => Err(Error::::NotSupportedCurrencyId), } } @@ -345,34 +344,21 @@ impl Pallet { match currency_id { MOVR => Ok(MultiLocation { parents: 1, - interior: X2( - Parachain(parachains::moonriver::ID), - PalletInstance(parachains::moonriver::PALLET_ID), - ), + interior: X2(Parachain(MoonriverChainId::get()), PalletInstance(10)), }), GLMR => Ok(MultiLocation { parents: 1, - interior: X2( - Parachain(parachains::moonbeam::ID), - PalletInstance(parachains::moonbeam::PALLET_ID), - ), + interior: X2(Parachain(MoonbeamChainId::get()), PalletInstance(10)), }), - MANTA => - Ok(MultiLocation { parents: 1, interior: X1(Parachain(parachains::manta::ID)) }), + MANTA => Ok(MultiLocation { parents: 1, interior: X1(Parachain(MantaChainId::get())) }), _ => Err(Error::::NotSupportedCurrencyId), } } pub fn convert_currency_to_remote_fee_location(currency_id: CurrencyId) -> xcm::v4::Location { match currency_id { - MOVR => xcm::v4::Location::new( - 0, - [xcm::v4::prelude::PalletInstance(parachains::moonriver::PALLET_ID)], - ), - GLMR => xcm::v4::Location::new( - 0, - [xcm::v4::prelude::PalletInstance(parachains::moonbeam::PALLET_ID)], - ), + MOVR => xcm::v4::Location::new(0, [xcm::v4::prelude::PalletInstance(10)]), + GLMR => xcm::v4::Location::new(0, [xcm::v4::prelude::PalletInstance(10)]), _ => xcm::v4::Location::here(), } } diff --git a/pallets/xcm-interface/Cargo.toml b/pallets/xcm-interface/Cargo.toml index 821e63e22..4ee81ed99 100644 --- a/pallets/xcm-interface/Cargo.toml +++ b/pallets/xcm-interface/Cargo.toml @@ -22,6 +22,8 @@ bifrost-primitives = { workspace = true } bifrost-asset-registry = { workspace = true } [dev-dependencies] +bifrost-currencies = { workspace = true } +orml-tokens = { workspace = true } sp-io = { workspace = true } pallet-balances = { workspace = true } xcm-executor = { workspace = true } @@ -43,9 +45,10 @@ std = [ "orml-traits/std", "cumulus-primitives-core/std", "bifrost-primitives/std", + "bifrost-asset-registry/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", diff --git a/pallets/xcm-interface/src/benchmarking.rs b/pallets/xcm-interface/src/benchmarking.rs new file mode 100644 index 000000000..9e4e40261 --- /dev/null +++ b/pallets/xcm-interface/src/benchmarking.rs @@ -0,0 +1,43 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . + +#![cfg(feature = "runtime-benchmarks")] +use super::*; +use bifrost_primitives::{XcmOperationType, BNC}; +use frame_benchmarking::v2::*; +use frame_system::RawOrigin; + +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn update_xcm_dest_weight_and_fee() { + let updates = vec![ + (BNC, XcmOperationType::Bond, Weight::zero(), 0u32.into()), + (BNC, XcmOperationType::Bond, Weight::zero(), 0u32.into()), + (BNC, XcmOperationType::Bond, Weight::zero(), 0u32.into()), + (BNC, XcmOperationType::Bond, Weight::zero(), 0u32.into()), + (BNC, XcmOperationType::Bond, Weight::zero(), 0u32.into()), + ]; + #[extrinsic_call] + _(RawOrigin::Root, updates); + } + + impl_benchmark_test_suite!(Pallet, mock::new_test_ext(), mock::Test); +} diff --git a/pallets/xcm-interface/src/calls.rs b/pallets/xcm-interface/src/calls.rs index 8c1cbf002..fc9cc3152 100644 --- a/pallets/xcm-interface/src/calls.rs +++ b/pallets/xcm-interface/src/calls.rs @@ -16,28 +16,11 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use frame_support::sp_runtime::MultiSignature; use parity_scale_codec::{Decode, Encode}; use sp_runtime::RuntimeDebug; -use sp_std::{boxed::Box, vec::Vec}; +use sp_std::boxed::Box; use xcm::{v4::WeightLimit, VersionedAssets, VersionedLocation}; -use crate::ChainId; - -#[derive(Encode, Decode, RuntimeDebug)] -pub enum UtilityCall { - #[codec(index = 1)] - AsDerivative(u16, RelayChainCall), - #[codec(index = 2)] - BatchAll(Vec), -} - -#[derive(Encode, Decode, RuntimeDebug)] -pub enum StakingCall { - #[codec(index = 3)] - WithdrawUnbonded(u32), -} - #[derive(Encode, Decode, RuntimeDebug, Clone)] pub enum PolkadotXcmCall { #[codec(index = 2)] @@ -65,111 +48,14 @@ pub enum PolkadotXcmCall { ), } -#[derive(Encode, Decode, RuntimeDebug, Clone)] -pub enum SystemCall { - #[codec(index = 7)] - RemarkWithEvent(Vec), -} - -pub mod kusama { - - pub use crate::calls::*; - - #[derive(Encode, Decode, RuntimeDebug)] - pub enum RelaychainCall { - #[codec(index = 73)] - Crowdloan(ContributeCall), - #[codec(index = 30)] - Proxy(ProxyCall), - } - - #[derive(Encode, Decode, RuntimeDebug)] - pub enum AssetHubCall { - #[codec(index = 31)] - PolkadotXcm(PolkadotXcmCall), - } -} - -pub mod polkadot { - pub use crate::calls::*; - - #[derive(Encode, Decode, RuntimeDebug)] - pub enum RelaychainCall { - #[codec(index = 73)] - Crowdloan(ContributeCall), - #[codec(index = 29)] - Proxy(ProxyCall), - #[codec(index = 99)] - XcmPallet(PolkadotXcmCall), - } - - #[derive(Encode, Decode, RuntimeDebug)] - pub enum AssetHubCall { - #[codec(index = 31)] - PolkadotXcm(PolkadotXcmCall), - } -} - #[derive(Encode, Decode, RuntimeDebug)] -pub enum ContributeCall { - #[codec(index = 1)] - Contribute(Contribution), - #[codec(index = 2)] - Withdraw(Withdraw), - #[codec(index = 6)] - AddMemo(AddMemo), -} - -#[derive(PartialEq, Encode, Decode, RuntimeDebug)] -pub struct Contribution { - #[codec(compact)] - pub index: ChainId, - #[codec(compact)] - pub value: BalanceOf, - pub signature: Option, -} - -#[derive(PartialEq, Encode, Decode, RuntimeDebug)] -pub struct Withdraw { - pub who: AccountIdOf, - #[codec(compact)] - pub index: ChainId, -} - -#[derive(PartialEq, Encode, Decode, RuntimeDebug)] -pub struct AddMemo { - pub index: ChainId, - pub memo: Vec, -} - -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug)] -pub enum ProxyType { - Any, - NonTransfer, - Governance, - Staking, - IdentityJudgement, - CancelProxy, +pub enum RelaychainCall { + #[codec(index = 99)] + XcmPallet(PolkadotXcmCall), } #[derive(Encode, Decode, RuntimeDebug)] -pub enum ProxyCall { - #[codec(index = 1)] - Add(AddProxy), - #[codec(index = 2)] - Remove(RemoveProxy), -} - -#[derive(PartialEq, Encode, Decode, RuntimeDebug)] -pub struct AddProxy { - pub delegate: AccountIdOf, - pub proxy_type: ProxyType, - pub delay: BlockNumberOf, -} - -#[derive(PartialEq, Encode, Decode, RuntimeDebug)] -pub struct RemoveProxy { - pub delegate: AccountIdOf, - pub proxy_type: ProxyType, - pub delay: BlockNumberOf, +pub enum AssetHubCall { + #[codec(index = 31)] + PolkadotXcm(PolkadotXcmCall), } diff --git a/pallets/xcm-interface/src/lib.rs b/pallets/xcm-interface/src/lib.rs index ee096d51e..1a9b609ca 100644 --- a/pallets/xcm-interface/src/lib.rs +++ b/pallets/xcm-interface/src/lib.rs @@ -17,130 +17,93 @@ // along with this program. If not, see . #![cfg_attr(not(feature = "std"), no_std)] -#![allow(unused_imports)] + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; pub mod calls; -pub mod traits; +pub mod weights; +pub use weights::WeightInfo; +mod mock; +mod tests; + +use crate::calls::{AssetHubCall, PolkadotXcmCall}; use bifrost_asset_registry::AssetMetadata; -use bifrost_primitives::{traits::XcmDestWeightAndFeeHandler, CurrencyIdMapping, XcmOperationType}; -pub use calls::*; +use bifrost_primitives::{ + traits::XcmDestWeightAndFeeHandler, AssetHubLocation, CurrencyId, CurrencyIdMapping, + EthereumLocation, XcmOperationType, +}; +use cumulus_primitives_core::ParaId; +use frame_support::pallet_prelude::*; +use frame_system::pallet_prelude::*; use orml_traits::MultiCurrency; pub use pallet::*; -use sp_runtime::traits::UniqueSaturatedInto; -pub use traits::{ChainId, MessageId, Nonce, SalpHelper}; - -macro_rules! use_relay { - ({ $( $code:tt )* }) => { - if T::RelayNetwork::get() == NetworkId::Polkadot { - use polkadot::RelaychainCall; - use polkadot::AssetHubCall; - - $( $code )* - } else if T::RelayNetwork::get() == NetworkId::Kusama { - use kusama::RelaychainCall; - use kusama::AssetHubCall; - - $( $code )* - } else { - unreachable!() - } - } -} - -pub(crate) type AccountIdOf = ::AccountId; - -pub type CurrencyIdOf = - <::MultiCurrency as MultiCurrency>>::CurrencyId; - -pub type BalanceOf = <::MultiCurrency as MultiCurrency>>::Balance; +use sp_core::H160; +use sp_runtime::traits::{Convert, UniqueSaturatedInto}; +use sp_std::{convert::From, prelude::*, vec, vec::Vec}; +use xcm::{ + v4::{prelude::*, Asset, Location}, + DoubleEncoded, +}; + +type BalanceOf = <::MultiCurrency as MultiCurrency< + ::AccountId, +>>::Balance; #[frame_support::pallet] pub mod pallet { - use cumulus_primitives_core::ParaId; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; - use orml_traits::{currency::TransferAll, MultiCurrency, MultiReservableCurrency}; - use sp_runtime::{traits::Convert, DispatchError}; - use sp_std::{convert::From, prelude::*, vec, vec::Vec}; - use xcm::{ - v4::{prelude::*, Asset, ExecuteXcm, Location}, - DoubleEncoded, VersionedXcm, - }; - use super::*; - use crate::traits::*; #[pallet::config] - pub trait Config: frame_system::Config + pallet_xcm::Config { + pub trait Config: frame_system::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; - type MultiCurrency: TransferAll> - + MultiCurrency> - + MultiReservableCurrency>; + type MultiCurrency: MultiCurrency; + + // Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; /// Origin represented Governance type UpdateOrigin: EnsureOrigin<::RuntimeOrigin>; - /// The currency id of the RelayChain - #[pallet::constant] - type RelaychainCurrencyId: Get>; - - /// The account of parachain on the relaychain. - #[pallet::constant] - type ParachainSovereignAccount: Get>; - - /// XCM executor. - type XcmExecutor: ExecuteXcm<::RuntimeCall>; + /// Xcm transfer interface + type XcmRouter: SendXcm; /// Convert `T::AccountId` to `Location`. - type AccountIdToLocation: Convert, Location>; - - /// Salp call encode - type SalpHelper: SalpHelper< - AccountIdOf, - ::RuntimeCall, - BalanceOf, - >; + type AccountIdToLocation: Convert; /// Convert Location to `T::CurrencyId`. type CurrencyIdConvert: CurrencyIdMapping< - CurrencyIdOf, + CurrencyId, xcm::v3::MultiLocation, AssetMetadata>, >; - #[pallet::constant] - type RelayNetwork: Get; - #[pallet::constant] type ParachainId: Get; - - #[pallet::constant] - type CallBackTimeOut: Get>; } #[pallet::error] pub enum Error { - FeeConvertFailed, - XcmExecutionFailed, + /// Failed to send XCM message. XcmSendFailed, + /// The weight and fee for the operation does not exist. OperationWeightAndFeeNotExist, + /// Failed to convert currency id. FailToConvert, + /// The message is unweighable. UnweighableMessage, - LocalExecutionIncomplete, } #[pallet::event] #[pallet::generate_deposit(pub(crate) fn deposit_event)] pub enum Event { - XcmDestWeightAndFeeUpdated(XcmOperationType, CurrencyIdOf, Weight, BalanceOf), - TransferredStatemineMultiAsset(AccountIdOf, BalanceOf), - TransferredEthereumAssets(AccountIdOf, sp_core::H160, BalanceOf), + XcmDestWeightAndFeeUpdated(XcmOperationType, CurrencyId, Weight, BalanceOf), + TransferredEthereumAssets(T::AccountId, H160, BalanceOf), } /// The current storage version, we set to 2 our new version(after migrate stroage /// XcmWeightAndFee from SLP module). - #[allow(unused)] const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); /// The dest weight limit and fee for execution XCM msg sent by XcmInterface. Must be @@ -151,18 +114,13 @@ pub mod pallet { pub type XcmWeightAndFee = StorageDoubleMap< _, Blake2_128Concat, - CurrencyIdOf, + CurrencyId, Blake2_128Concat, XcmOperationType, (Weight, BalanceOf), OptionQuery, >; - // Tracker for the next nonce index - #[pallet::storage] - pub(super) type CurrentNonce = - StorageMap<_, Blake2_128Concat, ChainId, Nonce, ValueQuery>; - #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] #[pallet::without_storage_info] @@ -178,10 +136,10 @@ pub mod pallet { /// Parameters: /// - `updates`: vec of tuple: (XcmOperationType, WeightChange, FeeChange). #[pallet::call_index(0)] - #[pallet::weight({16_690_000})] + #[pallet::weight(T::WeightInfo::update_xcm_dest_weight_and_fee())] pub fn update_xcm_dest_weight_and_fee( origin: OriginFor, - updates: Vec<(CurrencyIdOf, XcmOperationType, Weight, BalanceOf)>, + updates: Vec<(CurrencyId, XcmOperationType, Weight, BalanceOf)>, ) -> DispatchResult { T::UpdateOrigin::ensure_origin(origin)?; @@ -202,89 +160,14 @@ pub mod pallet { Ok(()) } - #[pallet::call_index(1)] - #[pallet::weight({2_000_000_000})] - pub fn transfer_statemine_assets( - origin: OriginFor, - amount: BalanceOf, - asset_id: u32, - dest: Option>, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - let dest = match dest { - Some(account) => account, - None => who.clone(), - }; - - let amount_u128 = - TryInto::::try_into(amount).map_err(|_| Error::::FeeConvertFailed)?; - - // get currency_id from asset_id - let asset_location = Location::new( - 1, - [ - 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::AccountIdToLocation::convert(dest.clone()); - - let (dest_weight, xcm_fee) = XcmWeightAndFee::::get( - T::RelaychainCurrencyId::get(), - XcmOperationType::StatemineTransfer, - ) - .ok_or(Error::::OperationWeightAndFeeNotExist)?; - - let xcm_fee_u128 = - TryInto::::try_into(xcm_fee).map_err(|_| Error::::FeeConvertFailed)?; - - let mut assets = Assets::new(); - let statemine_asset = Asset { - id: AssetId(Location::new( - 0, - [ - PalletInstance(parachains::Statemine::PALLET_ID), - GeneralIndex(asset_id.into()), - ], - )), - fun: Fungible(amount_u128), - }; - let fee_asset = - Asset { id: AssetId(Location::new(1, Here)), fun: Fungible(xcm_fee_u128) }; - assets.push(statemine_asset.clone()); - assets.push(fee_asset.clone()); - let msg = Xcm(vec![ - WithdrawAsset(assets), - BuyExecution { fees: fee_asset, weight_limit: Limited(dest_weight) }, - DepositAsset { assets: AllCounted(2).into(), beneficiary: dst_location }, - ]); - - pallet_xcm::Pallet::::send_xcm( - Here, - Location::new(1, Parachain(parachains::Statemine::ID)), - msg, - ) - .map_err(|_| Error::::XcmExecutionFailed)?; - - Self::deposit_event(Event::::TransferredStatemineMultiAsset(dest, amount)); - - Ok(()) - } #[pallet::call_index(2)] #[pallet::weight({2_000_000_000})] pub fn transfer_ethereum_assets( origin: OriginFor, - currency_id: CurrencyIdOf, + currency_id: CurrencyId, amount: BalanceOf, - to: sp_core::H160, + to: H160, ) -> DispatchResult { let who = ensure_signed(origin.clone())?; let asset_location = @@ -306,9 +189,9 @@ pub mod pallet { T::MultiCurrency::withdraw(currency_id, &who, amount)?; - let remote_call: DoubleEncoded<()> = use_relay!({ + let remote_call: DoubleEncoded<()> = AssetHubCall::PolkadotXcm(PolkadotXcmCall::LimitedReserveTransferAssets( - Box::new(Location::new(2, [GlobalConsensus(Ethereum { chain_id: 1 })]).into()), + Box::new(EthereumLocation::get().into()), Box::new( Location::new( 0, @@ -321,8 +204,7 @@ pub mod pallet { Unlimited, )) .encode() - .into() - }); + .into(); let remote_xcm = Xcm(vec![ WithdrawAsset(fee.clone().into()), @@ -332,73 +214,31 @@ pub mod pallet { require_weight_at_most, call: remote_call, }, + RefundSurplus, DepositAsset { assets: All.into(), beneficiary: Location::new(1, [Parachain(T::ParachainId::get().into())]), }, ]); - let (ticket, _) = ::XcmRouter::validate( - &mut Some(Location::new(1, [Parachain(parachains::Statemine::ID)])), - &mut Some(remote_xcm), - ) - .map_err(|_| Error::::UnweighableMessage)?; - ::XcmRouter::deliver(ticket) - .map_err(|_| Error::::XcmExecutionFailed)?; + let (ticket, _) = + T::XcmRouter::validate(&mut Some(AssetHubLocation::get()), &mut Some(remote_xcm)) + .map_err(|_| Error::::UnweighableMessage)?; + T::XcmRouter::deliver(ticket).map_err(|_| Error::::XcmSendFailed)?; Self::deposit_event(Event::::TransferredEthereumAssets(who, to, amount)); Ok(()) } } - impl XcmHelper, BalanceOf> for Pallet { - fn contribute( - contributor: AccountIdOf, - index: ChainId, - amount: BalanceOf, - ) -> Result { - // Construct contribute call data - let contribute_call = Self::build_ump_crowdloan_contribute(index, amount); - let (dest_weight, xcm_fee) = XcmWeightAndFee::::get( - T::RelaychainCurrencyId::get(), - XcmOperationType::UmpContributeTransact, - ) - .ok_or(Error::::OperationWeightAndFeeNotExist)?; - - // Construct confirm_contribute_call - let confirm_contribute_call = T::SalpHelper::confirm_contribute_call(); - // Generate query_id - let query_id = pallet_xcm::Pallet::::new_notify_query( - Location::parent(), - confirm_contribute_call, - T::CallBackTimeOut::get(), - xcm::v4::Junctions::Here, - ); - - // Bind query_id and contribution - T::SalpHelper::bind_query_id_and_contribution(query_id, index, contributor, amount); - - let (msg_id, msg) = - Self::build_ump_transact(query_id, contribute_call, dest_weight, xcm_fee)?; - - let result = pallet_xcm::Pallet::::send_xcm( - xcm::v4::Junctions::Here, - xcm::v4::Parent, - xcm::v4::Xcm::try_from(msg).unwrap(), - ); - ensure!(result.is_ok(), Error::::XcmSendFailed); - Ok(msg_id) - } - } - - impl XcmDestWeightAndFeeHandler, BalanceOf> for Pallet { + impl XcmDestWeightAndFeeHandler> for Pallet { fn get_operation_weight_and_fee( - token: CurrencyIdOf, + token: CurrencyId, operation: XcmOperationType, ) -> Option<(Weight, BalanceOf)> { XcmWeightAndFee::::get(token, operation) } fn set_xcm_dest_weight_and_fee( - currency_id: CurrencyIdOf, + currency_id: CurrencyId, operation: XcmOperationType, weight_and_fee: Option<(Weight, BalanceOf)>, ) -> DispatchResult { @@ -411,58 +251,4 @@ pub mod pallet { Ok(()) } } - - impl Pallet { - pub(crate) fn transact_id(data: &[u8]) -> MessageId { - return sp_io::hashing::blake2_256(data); - } - - pub(crate) fn build_ump_transact( - query_id: QueryId, - call: DoubleEncoded<()>, - weight: Weight, - fee: BalanceOf, - ) -> Result<(MessageId, Xcm<()>), Error> { - let sovereign_account: AccountIdOf = T::ParachainSovereignAccount::get(); - let sovereign_location: Location = T::AccountIdToLocation::convert(sovereign_account); - let fee_amount = - TryInto::::try_into(fee).map_err(|_| Error::::FeeConvertFailed)?; - let asset: Asset = - Asset { id: AssetId(Location::here()), fun: Fungibility::from(fee_amount) }; - let message = Xcm(vec![ - WithdrawAsset(asset.clone().into()), - BuyExecution { fees: asset, weight_limit: Unlimited }, - Transact { - origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: weight, - call, - }, - ReportTransactStatus(QueryResponseInfo { - destination: Location::from([Parachain(u32::from(T::ParachainId::get()))]), - query_id, - max_weight: weight, - }), - RefundSurplus, - DepositAsset { assets: AllCounted(1).into(), beneficiary: sovereign_location }, - ]); - let data = VersionedXcm::<()>::from(message.clone()).encode(); - let id = Self::transact_id(&data[..]); - Ok((id, message)) - } - - pub(crate) fn build_ump_crowdloan_contribute( - index: ChainId, - value: BalanceOf, - ) -> DoubleEncoded<()> { - use_relay!({ - let contribute_call = - RelaychainCall::Crowdloan::, AccountIdOf, BlockNumberFor>( - ContributeCall::Contribute(Contribution { index, value, signature: None }), - ) - .encode() - .into(); - contribute_call - }) - } - } } diff --git a/pallets/xcm-interface/src/mock.rs b/pallets/xcm-interface/src/mock.rs new file mode 100644 index 000000000..34c94cfcf --- /dev/null +++ b/pallets/xcm-interface/src/mock.rs @@ -0,0 +1,157 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . + +#![cfg(test)] + +use crate as xcm_interface; +use bifrost_asset_registry::AssetIdMaps; +use bifrost_primitives::{Amount, Balance, BlockNumber, CurrencyId, MockXcmRouter, BNC}; +use cumulus_primitives_core::ParaId; +use frame_support::{ + __private::Get, + derive_impl, parameter_types, + traits::{Everything, Nothing}, +}; +use frame_system as system; +use frame_system::EnsureRoot; +use sp_core::{crypto::AccountId32, ConstU32, H256}; +use sp_runtime::{ + traits::{BlakeTwo256, IdentityLookup}, + BuildStorage, +}; + +pub type AccountId = AccountId32; +type Block = frame_system::mocking::MockBlock; + +// Configure a mock runtime to test the pallet. +frame_support::construct_runtime!( + pub enum Test + { + System: frame_system, + XcmInterface: xcm_interface, + Balances: pallet_balances, + Currencies: bifrost_currencies, + Tokens: orml_tokens, + AssetRegistry: bifrost_asset_registry, + } +); + +parameter_types! { + pub const SS58Prefix: u8 = 42; +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl system::Config for Test { + type BaseCallFilter = Everything; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type AccountData = pallet_balances::AccountData; + type Lookup = IdentityLookup; + type Block = Block; + type RuntimeEvent = RuntimeEvent; + type PalletInfo = PalletInfo; + type SS58Prefix = SS58Prefix; + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +orml_traits::parameter_type_with_key! { + pub ExistentialDeposits: |_currency_id: CurrencyId| -> Balance { + 0 + }; +} +impl orml_tokens::Config for Test { + type Amount = i128; + type Balance = Balance; + type CurrencyId = CurrencyId; + type DustRemovalWhitelist = Nothing; + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposits = ExistentialDeposits; + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type WeightInfo = (); + type CurrencyHooks = (); +} + +parameter_types! { + pub const ExistentialDeposit: Balance = 1; +} + +impl pallet_balances::Config for Test { + type AccountStore = System; + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ExistentialDeposit; + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type WeightInfo = (); + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; + type FreezeIdentifier = (); + type MaxFreezes = ConstU32<0>; +} + +impl bifrost_asset_registry::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type RegisterOrigin = EnsureRoot; + type WeightInfo = (); +} + +parameter_types! { + pub const NativeCurrencyId: CurrencyId = BNC; +} + +pub type AdaptedBasicCurrency = + bifrost_currencies::BasicCurrencyAdapter; + +impl bifrost_currencies::Config for Test { + type GetNativeCurrencyId = NativeCurrencyId; + type MultiCurrency = Tokens; + type NativeCurrency = AdaptedBasicCurrency; + type WeightInfo = (); +} + +pub struct ParachainId; +impl Get for ParachainId { + fn get() -> ParaId { + 2030.into() + } +} + +impl xcm_interface::Config for Test { + type RuntimeEvent = RuntimeEvent; + type MultiCurrency = Currencies; + type WeightInfo = (); + type UpdateOrigin = EnsureRoot; + type XcmRouter = MockXcmRouter; + type AccountIdToLocation = (); + type CurrencyIdConvert = AssetIdMaps; + type ParachainId = ParachainId; +} + +// Build genesis storage according to the mock runtime. +pub fn new_test_ext() -> sp_io::TestExternalities { + system::GenesisConfig::::default().build_storage().unwrap().into() +} diff --git a/pallets/xcm-interface/src/tests.rs b/pallets/xcm-interface/src/tests.rs new file mode 100644 index 000000000..ec3d2a54c --- /dev/null +++ b/pallets/xcm-interface/src/tests.rs @@ -0,0 +1,50 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . + +#![cfg(test)] + +use crate::{ + mock::{new_test_ext, RuntimeOrigin, Test}, + Pallet as XcmInterface, XcmWeightAndFee, +}; +use bifrost_primitives::{XcmOperationType, BNC}; +use frame_support::assert_ok; +use xcm::v4::Weight; + +#[test] +fn update_xcm_dest_weight_and_fee() { + new_test_ext().execute_with(|| { + let updates = vec![ + (BNC, XcmOperationType::Bond, Weight::zero(), 0u128), + (BNC, XcmOperationType::Bond, Weight::zero(), 0u128), + (BNC, XcmOperationType::Bond, Weight::zero(), 0u128), + (BNC, XcmOperationType::Bond, Weight::zero(), 0u128), + (BNC, XcmOperationType::Bond, Weight::zero(), 0u128), + ]; + + assert_ok!(XcmInterface::::update_xcm_dest_weight_and_fee( + RuntimeOrigin::root(), + updates + )); + + assert_eq!( + XcmWeightAndFee::::get(BNC, XcmOperationType::Bond), + Some((Weight::zero(), 0u128)) + ); + }) +} diff --git a/pallets/xcm-interface/src/traits.rs b/pallets/xcm-interface/src/traits.rs deleted file mode 100644 index 190dedf12..000000000 --- a/pallets/xcm-interface/src/traits.rs +++ /dev/null @@ -1,159 +0,0 @@ -// This file is part of Bifrost. - -// Copyright (C) Liebi Technologies PTE. 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 core::ops::{Add, Mul}; - -use parity_scale_codec::{Decode, Encode}; -use scale_info::TypeInfo; -use sp_runtime::DispatchError; -use sp_std::prelude::*; -use xcm::v3::QueryId; - -pub type MessageId = [u8; 32]; - -pub type ChainId = u32; - -pub type Nonce = u32; - -/// The type used to represent the xcmp transfer direction -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] -pub enum TransferOriginType { - FromSelf = 0, - FromRelayChain = 1, - FromSiblingParaChain = 2, -} - -pub struct XcmBaseWeight(u64); - -impl XcmBaseWeight { - pub fn new(x: u64) -> Self { - XcmBaseWeight(x) - } -} - -impl From for XcmBaseWeight { - fn from(u: u64) -> Self { - XcmBaseWeight(u) - } -} - -impl From for u64 { - fn from(x: XcmBaseWeight) -> Self { - x.0.into() - } -} - -impl Add for XcmBaseWeight { - type Output = Self; - fn add(self, other: Self) -> Self::Output { - (self.0 + other.0).into() - } -} - -impl Mul for XcmBaseWeight { - type Output = Self; - - fn mul(self, rhs: u64) -> Self { - XcmBaseWeight::new(self.0 * rhs) - } -} - -/// represent the transact type -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] -pub enum ParachainTransactType { - Xcm = 0, - Proxy = 1, -} - -/// represent the proxy type -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] -pub enum ParachainTransactProxyType { - Primary = 0, - Derived = 1, -} - -/// represent the derived proxy account type -#[repr(u16)] -pub enum ParachainDerivedProxyAccountType { - Salp = 0, - Staking = 1, -} - -#[allow(non_snake_case)] -pub mod parachains { - // ********************* - // Kusama parachains** - // ********************* - - pub mod karura { - pub const ID: u32 = 2000; - pub const KAR_KEY: &[u8] = &[0, 128]; - pub const KUSD_KEY: &[u8] = &[0, 129]; - } - - pub mod Statemine { - pub const ID: u32 = 1000; - pub const PALLET_ID: u8 = 50; - pub const RMRK_ID: u32 = 8; - } - - pub mod phala { - pub const ID: u32 = 2004; - } - - pub mod moonriver { - pub const ID: u32 = 2023; - pub const PALLET_ID: u8 = 10; - } - - //********************* - // Polkadot parachains - //********************* - pub mod moonbeam { - pub const ID: u32 = 2004; - pub const PALLET_ID: u8 = 10; - } - - pub mod astar { - pub const ID: u32 = 2006; - pub const PALLET_ID: u8 = 34; - } - - pub mod manta { - pub const ID: u32 = 2104; - pub const PALLET_ID: u8 = 10; - } -} - -pub trait XcmHelper { - fn contribute( - contributer: AccountId, - index: ChainId, - value: Balance, - ) -> Result; -} - -pub trait SalpHelper { - fn confirm_contribute_call() -> RuntimeCall; - fn bind_query_id_and_contribution( - query_id: QueryId, - index: ChainId, - contributer: AccountId, - amount: Balance, - ); -} diff --git a/pallets/xcm-interface/src/weights.rs b/pallets/xcm-interface/src/weights.rs new file mode 100644 index 000000000..a37027c90 --- /dev/null +++ b/pallets/xcm-interface/src/weights.rs @@ -0,0 +1,82 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for bifrost_xcm_interface +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bifrost-jenkins`, CPU: `Intel(R) Xeon(R) CPU E5-26xx v4` +//! WASM-EXECUTION: Compiled, CHAIN: Some("bifrost-polkadot-local"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/bifrost +// benchmark +// pallet +// --chain=bifrost-polkadot-local +// --steps=50 +// --repeat=20 +// --pallet=bifrost_xcm_interface +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --header=./HEADER-GPL3 +// --output=./weight.rs +// --template +// ./weight-template/pallet-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for bifrost_xcm_interface. +pub trait WeightInfo { + fn update_xcm_dest_weight_and_fee() -> Weight; +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: `XcmInterface::XcmWeightAndFee` (r:1 w:1) + /// Proof: `XcmInterface::XcmWeightAndFee` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Number` (r:1 w:0) + /// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::ExecutionPhase` (r:1 w:0) + /// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `System::EventCount` (r:1 w:1) + /// Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Events` (r:1 w:1) + /// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn update_xcm_dest_weight_and_fee() -> Weight { + // Proof Size summary in bytes: + // Measured: `134` + // Estimated: `3599` + // Minimum execution time: 58_775_000 picoseconds. + Weight::from_parts(60_153_000, 3599) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } +} \ No newline at end of file diff --git a/primitives/src/xcm.rs b/primitives/src/xcm.rs index dd3a742ac..b6d59929c 100644 --- a/primitives/src/xcm.rs +++ b/primitives/src/xcm.rs @@ -41,6 +41,8 @@ parameter_types! { pub const MantaChainId: u32 = 2104; pub const MoonbeamChainId: u32 = 2004; pub const MoonriverChainId: u32 = 2023; + pub const PhalaChainId: u32 = 2035; + pub const KaruraChainId: u32 = 2000; pub const EthereumChainId: u64 = 1; } diff --git a/runtime/bifrost-kusama/Cargo.toml b/runtime/bifrost-kusama/Cargo.toml index 0f18e7357..2d123a6fa 100644 --- a/runtime/bifrost-kusama/Cargo.toml +++ b/runtime/bifrost-kusama/Cargo.toml @@ -322,6 +322,7 @@ runtime-benchmarks = [ "bifrost-slpx/runtime-benchmarks", "bifrost-stable-pool/runtime-benchmarks", "bifrost-vtoken-voting/runtime-benchmarks", + "bifrost-xcm-interface/runtime-benchmarks", "lend-market/runtime-benchmarks", "leverage-staking/runtime-benchmarks", "bifrost-channel-commission/runtime-benchmarks", diff --git a/runtime/bifrost-kusama/src/lib.rs b/runtime/bifrost-kusama/src/lib.rs index 0e5bf5da9..b5820a869 100644 --- a/runtime/bifrost-kusama/src/lib.rs +++ b/runtime/bifrost-kusama/src/lib.rs @@ -128,8 +128,8 @@ use pallet_xcm::{EnsureResponse, QueryStatus}; use sp_runtime::traits::{IdentityLookup, Verify}; use xcm::{v3::MultiLocation, v4::prelude::*}; pub use xcm_config::{ - parachains, AccountId32Aliases, BifrostTreasuryAccount, ExistentialDeposits, MultiCurrency, - Sibling, SiblingParachainConvertsVia, XcmConfig, XcmRouter, + AccountId32Aliases, BifrostTreasuryAccount, ExistentialDeposits, MultiCurrency, Sibling, + SiblingParachainConvertsVia, XcmConfig, XcmRouter, }; use xcm_executor::{traits::QueryHandler, XcmExecutor}; @@ -1053,7 +1053,7 @@ pub fn create_x2_multilocation(index: u16, currency_id: CurrencyId) -> xcm::v3:: CurrencyId::Token(TokenSymbol::MOVR) => xcm::v3::Location::new( 1, xcm::v3::Junctions::X2( - xcm::v3::Junction::Parachain(parachains::moonriver::ID.into()), + xcm::v3::Junction::Parachain(MoonriverChainId::get()), xcm::v3::Junction::AccountKey20 { network: None, key: Slp::derivative_account_id_20( @@ -1162,7 +1162,6 @@ impl bifrost_salp::Config for Runtime { type VSBondValidPeriod = VSBondValidPeriod; type WeightInfo = weights::bifrost_salp::BifrostWeight; type EnsureConfirmAsGovernance = EitherOfDiverse; - type XcmInterface = XcmInterface; type TreasuryAccount = BifrostTreasuryAccount; type BuybackPalletId = BuybackPalletId; type CurrencyIdConversion = AssetIdMaps; @@ -1960,7 +1959,6 @@ mod benches { [bifrost_farming, Farming] [bifrost_fee_share, FeeShare] [bifrost_flexible_fee, FlexibleFee] - [bifrost_salp, Salp] [bifrost_slp, Slp] [bifrost_slpx, Slpx] [bifrost_stable_pool, StablePool] @@ -1973,6 +1971,7 @@ mod benches { [lend_market, LendMarket] [leverage_staking, LeverageStaking] [bifrost_vbnc_convert, VBNCConvert] + [bifrost_xcm_interface, XcmInterface] // [bifrost_channel_commission, ChannelCommission] ); } diff --git a/runtime/bifrost-kusama/src/migration.rs b/runtime/bifrost-kusama/src/migration.rs index 0f9cc76bb..c6209c79c 100644 --- a/runtime/bifrost-kusama/src/migration.rs +++ b/runtime/bifrost-kusama/src/migration.rs @@ -376,7 +376,6 @@ pub mod system_maker { pub use bifrost_primitives::currency::{KSM, VKSM}; use frame_support::{pallet_prelude::PhantomData, traits::OnRuntimeUpgrade}; use sp_core::Get; - use sp_runtime::traits::Zero; pub struct SystemMakerClearPalletId(PhantomData); impl OnRuntimeUpgrade for SystemMakerClearPalletId { #[cfg(feature = "try-runtime")] @@ -418,8 +417,6 @@ pub mod system_maker { #[cfg(feature = "try-runtime")] fn post_upgrade(_: sp_std::prelude::Vec) -> Result<(), sp_runtime::DispatchError> { - #[allow(unused_imports)] - use frame_support::PalletId; log::info!("Bifrost `post_upgrade`..."); let account_id = SystemMakerPalletId::get().into_account_truncating(); let ksm_balance = T::MultiCurrency::free_balance(KSM, &account_id); diff --git a/runtime/bifrost-kusama/src/weights/bifrost_xcm_interface.rs b/runtime/bifrost-kusama/src/weights/bifrost_xcm_interface.rs new file mode 100644 index 000000000..1682d2414 --- /dev/null +++ b/runtime/bifrost-kusama/src/weights/bifrost_xcm_interface.rs @@ -0,0 +1,78 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for bifrost_xcm_interface +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bifrost-jenkins`, CPU: `Intel(R) Xeon(R) CPU E5-26xx v4` +//! WASM-EXECUTION: Compiled, CHAIN: Some("bifrost-polkadot-local"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/bifrost +// benchmark +// pallet +// --chain=bifrost-polkadot-local +// --steps=50 +// --repeat=20 +// --pallet=bifrost_xcm_interface +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --header=./HEADER-GPL3 +// --output=./weight.rs +// --template +// ./weight-template/runtime-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions for bifrost_xcm_interface. +pub struct BifrostWeight(PhantomData); +impl bifrost_xcm_interface::WeightInfo for BifrostWeight { + // Storage: `XcmInterface::XcmWeightAndFee` (r:1 w:1) + // Proof: `XcmInterface::XcmWeightAndFee` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `System::Number` (r:1 w:0) + // Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `System::ExecutionPhase` (r:1 w:0) + // Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + // Storage: `System::EventCount` (r:1 w:1) + // Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `System::Events` (r:1 w:1) + // Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn update_xcm_dest_weight_and_fee() -> Weight { + // Proof Size summary in bytes: + // Measured: `134` + // Estimated: `3599` + // Minimum execution time: 56_793 nanoseconds. + Weight::from_parts(58_130_000, 3599) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} \ No newline at end of file diff --git a/runtime/bifrost-kusama/src/weights/mod.rs b/runtime/bifrost-kusama/src/weights/mod.rs index 41bea25e1..5de22ec76 100644 --- a/runtime/bifrost-kusama/src/weights/mod.rs +++ b/runtime/bifrost-kusama/src/weights/mod.rs @@ -40,6 +40,7 @@ pub mod bifrost_vsbond_auction; pub mod bifrost_vstoken_conversion; pub mod bifrost_vtoken_minting; pub mod bifrost_vtoken_voting; +pub mod bifrost_xcm_interface; pub mod orml_oracle; pub mod orml_tokens; pub mod pallet_xcm; diff --git a/runtime/bifrost-kusama/src/xcm_config.rs b/runtime/bifrost-kusama/src/xcm_config.rs index 612f2366c..8222f6b28 100644 --- a/runtime/bifrost-kusama/src/xcm_config.rs +++ b/runtime/bifrost-kusama/src/xcm_config.rs @@ -19,11 +19,10 @@ use super::*; use bifrost_asset_registry::{AssetIdMaps, FixedRateOfAsset}; use bifrost_primitives::{ - AccountId, AccountIdToLocation, AssetHubLocation, AssetPrefixFrom, CurrencyId, - CurrencyIdMapping, EthereumLocation, KusamaNetwork, KusamaUniversalLocation, NativeAssetFrom, - SelfLocation, TokenSymbol, + AccountId, AccountIdToLocation, AssetHubChainId, AssetHubLocation, AssetPrefixFrom, CurrencyId, + CurrencyIdMapping, EthereumLocation, KaruraChainId, KusamaNetwork, KusamaUniversalLocation, + NativeAssetFrom, PhalaChainId, SelfLocation, TokenSymbol, }; -pub use bifrost_xcm_interface::traits::{parachains, XcmBaseWeight}; pub use cumulus_primitives_core::ParaId; use frame_support::{parameter_types, sp_runtime::traits::Convert, traits::Get}; use parity_scale_codec::Encode; @@ -206,7 +205,7 @@ parameter_types! { pub KarPerSecond: (AssetId, u128,u128) = ( Location::new( 1, - [Parachain(parachains::karura::ID), Junction::from(BoundedVec::try_from(parachains::karura::KAR_KEY.to_vec()).unwrap())] + [Parachain(KaruraChainId::get()), Junction::from(BoundedVec::try_from(vec![0,128u8]).unwrap())] ).into(), // KAR:KSM = 100:1 ksm_per_second::() * 100, @@ -215,7 +214,7 @@ parameter_types! { pub KusdPerSecond: (AssetId, u128,u128) = ( Location::new( 1, - [Parachain(parachains::karura::ID), Junction::from(BoundedVec::try_from(parachains::karura::KUSD_KEY.to_vec()).unwrap())] + [Parachain(KaruraChainId::get()), Junction::from(BoundedVec::try_from(vec![0,129u8]).unwrap())] ).into(), // kUSD:KSM = 400:1 ksm_per_second::() * 400, @@ -224,7 +223,7 @@ parameter_types! { pub PhaPerSecond: (AssetId, u128,u128) = ( Location::new( 1, - [Parachain(parachains::phala::ID)], + [Parachain(PhalaChainId::get())], ).into(), // PHA:KSM = 400:1 ksm_per_second::() * 400, @@ -233,7 +232,7 @@ parameter_types! { pub RmrkPerSecond: (AssetId, u128,u128) = ( Location::new( 1, - [Parachain(parachains::Statemine::ID), GeneralIndex(parachains::Statemine::RMRK_ID.into())] + [Parachain(AssetHubChainId::get()), GeneralIndex(50)] ).into(), // rmrk:KSM = 10:1 ksm_per_second::() * 10 / 100, //rmrk currency decimal as 10 @@ -242,7 +241,7 @@ parameter_types! { pub RmrkNewPerSecond: (AssetId, u128,u128) = ( Location::new( 1, - [Parachain(parachains::Statemine::ID), PalletInstance(parachains::Statemine::PALLET_ID),GeneralIndex(parachains::Statemine::RMRK_ID.into())] + [Parachain(AssetHubChainId::get()), PalletInstance(50), GeneralIndex(8)] ).into(), // rmrk:KSM = 10:1 ksm_per_second::() * 10 / 100, //rmrk currency decimal as 10 @@ -251,7 +250,7 @@ parameter_types! { pub MovrPerSecond: (AssetId, u128,u128) = ( Location::new( 1, - [Parachain(parachains::moonriver::ID), PalletInstance(parachains::moonriver::PALLET_ID.into())] + [Parachain(MoonriverChainId::get()), PalletInstance(10)] ).into(), // MOVR:KSM = 2.67:1 ksm_per_second::() * 267 * 10_000, //movr currency decimal as 18 @@ -369,9 +368,6 @@ impl Contains for SafeCallFilter { bifrost_vtoken_minting::Call::rebond_by_unlock_id { .. } | bifrost_vtoken_minting::Call::redeem { .. } ) | - RuntimeCall::XcmInterface( - bifrost_xcm_interface::Call::transfer_statemine_assets { .. } - ) | RuntimeCall::Slpx(..) | RuntimeCall::ZenlinkProtocol( zenlink_protocol::Call::add_liquidity { .. } | @@ -660,16 +656,9 @@ impl bifrost_xcm_interface::Config for Runtime { type RuntimeEvent = RuntimeEvent; type UpdateOrigin = TechAdminOrCouncil; type MultiCurrency = Currencies; - type RelayNetwork = KusamaNetwork; - type RelaychainCurrencyId = RelayCurrencyId; - type ParachainSovereignAccount = ParachainAccount; - #[cfg(feature = "runtime-benchmarks")] - type XcmExecutor = bifrost_primitives::MockXcmExecutor; - #[cfg(not(feature = "runtime-benchmarks"))] - type XcmExecutor = XcmExecutor; type AccountIdToLocation = AccountIdToLocation; - type SalpHelper = Salp; type ParachainId = ParachainInfo; - type CallBackTimeOut = ConstU32<10>; type CurrencyIdConvert = AssetIdMaps; + type WeightInfo = weights::bifrost_xcm_interface::BifrostWeight; + type XcmRouter = XcmRouter; } diff --git a/runtime/bifrost-polkadot/Cargo.toml b/runtime/bifrost-polkadot/Cargo.toml index e79e6fef5..0888dda20 100644 --- a/runtime/bifrost-polkadot/Cargo.toml +++ b/runtime/bifrost-polkadot/Cargo.toml @@ -343,6 +343,7 @@ runtime-benchmarks = [ "bifrost-slpx/runtime-benchmarks", "bifrost-stable-pool/runtime-benchmarks", "bifrost-vtoken-voting/runtime-benchmarks", + "bifrost-xcm-interface/runtime-benchmarks", "sp-api/disable-logging", "lend-market/runtime-benchmarks", "bifrost-channel-commission/runtime-benchmarks", diff --git a/runtime/bifrost-polkadot/src/lib.rs b/runtime/bifrost-polkadot/src/lib.rs index 6560618d8..51238fd02 100644 --- a/runtime/bifrost-polkadot/src/lib.rs +++ b/runtime/bifrost-polkadot/src/lib.rs @@ -121,7 +121,7 @@ use sp_runtime::{ }; use static_assertions::const_assert; use xcm::{v3::MultiLocation, v4::prelude::*}; -pub use xcm_config::{parachains, BifrostTreasuryAccount, MultiCurrency}; +pub use xcm_config::{BifrostTreasuryAccount, MultiCurrency}; use xcm_executor::{traits::QueryHandler, XcmExecutor}; pub mod governance; @@ -937,7 +937,7 @@ pub fn create_x2_multilocation(index: u16, currency_id: CurrencyId) -> MultiLoca CurrencyId::Token2(GLMR_TOKEN_ID) => MultiLocation::new( 1, xcm::v3::Junctions::X2( - xcm::v3::Junction::Parachain(parachains::moonbeam::ID.into()), + xcm::v3::Junction::Parachain(MoonbeamChainId::get()), xcm::v3::Junction::AccountKey20 { network: None, key: Slp::derivative_account_id_20( @@ -1046,7 +1046,6 @@ impl bifrost_salp::Config for Runtime { type VSBondValidPeriod = VSBondValidPeriod; type WeightInfo = weights::bifrost_salp::BifrostWeight; type EnsureConfirmAsGovernance = EitherOfDiverse; - type XcmInterface = XcmInterface; type TreasuryAccount = BifrostTreasuryAccount; type BuybackPalletId = BuybackPalletId; type CurrencyIdConversion = AssetIdMaps; @@ -1926,6 +1925,7 @@ mod benches { [bb_bnc, BbBNC] [bifrost_buy_back, BuyBack] [bifrost_slp_v2, SlpV2] + [bifrost_xcm_interface, XcmInterface] ); } diff --git a/runtime/bifrost-polkadot/src/weights/bifrost_xcm_interface.rs b/runtime/bifrost-polkadot/src/weights/bifrost_xcm_interface.rs new file mode 100644 index 000000000..1682d2414 --- /dev/null +++ b/runtime/bifrost-polkadot/src/weights/bifrost_xcm_interface.rs @@ -0,0 +1,78 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for bifrost_xcm_interface +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bifrost-jenkins`, CPU: `Intel(R) Xeon(R) CPU E5-26xx v4` +//! WASM-EXECUTION: Compiled, CHAIN: Some("bifrost-polkadot-local"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/bifrost +// benchmark +// pallet +// --chain=bifrost-polkadot-local +// --steps=50 +// --repeat=20 +// --pallet=bifrost_xcm_interface +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --header=./HEADER-GPL3 +// --output=./weight.rs +// --template +// ./weight-template/runtime-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions for bifrost_xcm_interface. +pub struct BifrostWeight(PhantomData); +impl bifrost_xcm_interface::WeightInfo for BifrostWeight { + // Storage: `XcmInterface::XcmWeightAndFee` (r:1 w:1) + // Proof: `XcmInterface::XcmWeightAndFee` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `System::Number` (r:1 w:0) + // Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `System::ExecutionPhase` (r:1 w:0) + // Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + // Storage: `System::EventCount` (r:1 w:1) + // Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `System::Events` (r:1 w:1) + // Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn update_xcm_dest_weight_and_fee() -> Weight { + // Proof Size summary in bytes: + // Measured: `134` + // Estimated: `3599` + // Minimum execution time: 56_793 nanoseconds. + Weight::from_parts(58_130_000, 3599) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} \ No newline at end of file diff --git a/runtime/bifrost-polkadot/src/weights/mod.rs b/runtime/bifrost-polkadot/src/weights/mod.rs index 5ba0dd1b6..c2ecca9ad 100644 --- a/runtime/bifrost-polkadot/src/weights/mod.rs +++ b/runtime/bifrost-polkadot/src/weights/mod.rs @@ -41,6 +41,7 @@ pub mod bifrost_vesting; pub mod bifrost_vstoken_conversion; pub mod bifrost_vtoken_minting; pub mod bifrost_vtoken_voting; +pub mod bifrost_xcm_interface; pub mod orml_oracle; pub mod orml_tokens; pub mod pallet_xcm; diff --git a/runtime/bifrost-polkadot/src/xcm_config.rs b/runtime/bifrost-polkadot/src/xcm_config.rs index 88d9b9db3..ede51c1ca 100644 --- a/runtime/bifrost-polkadot/src/xcm_config.rs +++ b/runtime/bifrost-polkadot/src/xcm_config.rs @@ -27,7 +27,6 @@ use bifrost_primitives::{ use bifrost_runtime_common::currency_adapter::{ BifrostDropAssets, DepositToAlternative, MultiCurrencyAdapter, }; -pub use bifrost_xcm_interface::traits::{parachains, XcmBaseWeight}; use cumulus_primitives_core::AggregateMessageOrigin; pub use cumulus_primitives_core::ParaId; use frame_support::{ @@ -276,9 +275,6 @@ impl Contains for SafeCallFilter { bifrost_vtoken_minting::Call::rebond_by_unlock_id { .. } | bifrost_vtoken_minting::Call::redeem { .. } ) | - RuntimeCall::XcmInterface( - bifrost_xcm_interface::Call::transfer_statemine_assets { .. } - ) | RuntimeCall::Slpx(..) | RuntimeCall::ZenlinkProtocol( zenlink_protocol::Call::add_liquidity { .. } | @@ -536,13 +532,9 @@ impl bifrost_xcm_interface::Config for Runtime { type RuntimeEvent = RuntimeEvent; type UpdateOrigin = TechAdminOrCouncil; type MultiCurrency = Currencies; - type RelayNetwork = PolkadotNetwork; - type RelaychainCurrencyId = RelayCurrencyId; - type ParachainSovereignAccount = ParachainAccount; - type XcmExecutor = XcmExecutor; type AccountIdToLocation = AccountIdToLocation; - type SalpHelper = Salp; type ParachainId = ParachainInfo; - type CallBackTimeOut = ConstU32<10>; type CurrencyIdConvert = AssetIdMaps; + type XcmRouter = XcmRouter; + type WeightInfo = weights::bifrost_xcm_interface::BifrostWeight; } From c6e240c7b0d7b4a9a4908246ded71a8a1cc3d5cd Mon Sep 17 00:00:00 2001 From: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Date: Wed, 25 Sep 2024 22:33:40 +0800 Subject: [PATCH 06/30] remove unnecessary call method of cross-in-out (#1440) && optimize cross-in-out pallet --- pallets/cross-in-out/src/benchmarking.rs | 48 +--- pallets/cross-in-out/src/lib.rs | 219 ++++-------------- pallets/cross-in-out/src/migrations/mod.rs | 1 + pallets/cross-in-out/src/migrations/v3.rs | 92 ++++++++ pallets/cross-in-out/src/mock.rs | 1 + pallets/cross-in-out/src/tests.rs | 112 +-------- pallets/cross-in-out/src/weights.rs | 60 ----- runtime/bifrost-kusama/src/lib.rs | 1 + .../src/weights/bifrost_cross_in_out.rs | 56 ----- runtime/bifrost-polkadot/src/lib.rs | 1 + .../src/weights/bifrost_cross_in_out.rs | 56 ----- 11 files changed, 150 insertions(+), 497 deletions(-) create mode 100644 pallets/cross-in-out/src/migrations/v3.rs diff --git a/pallets/cross-in-out/src/benchmarking.rs b/pallets/cross-in-out/src/benchmarking.rs index 31d102378..b769ba1c3 100644 --- a/pallets/cross-in-out/src/benchmarking.rs +++ b/pallets/cross-in-out/src/benchmarking.rs @@ -25,7 +25,7 @@ use bifrost_primitives::{CurrencyId, TokenSymbol}; use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller, BenchmarkError}; use frame_support::assert_ok; use frame_system::RawOrigin; -use sp_runtime::traits::UniqueSaturatedFrom; +use sp_runtime::traits::{AccountIdConversion, UniqueSaturatedFrom}; use xcm::v2::prelude::*; use super::*; @@ -33,10 +33,6 @@ use super::*; use crate::Pallet as CrossInOut; benchmarks! { - register_currency_for_cross_in_out { - let origin = T::ControlOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - }: _(origin,CurrencyId::Token(TokenSymbol::DOT)) - deregister_currency_for_cross_in_out { let origin = T::ControlOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; assert_ok!(CrossInOut::::register_currency_for_cross_in_out( @@ -49,21 +45,6 @@ benchmarks! { let origin = T::ControlOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _(origin,CurrencyId::Token(TokenSymbol::DOT),100u32.into(),100u32.into()) - add_to_issue_whitelist { - let origin = T::ControlOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - let caller = whitelisted_caller(); - }: _(origin,CurrencyId::Token(TokenSymbol::DOT),caller) - - remove_from_issue_whitelist { - let origin = T::ControlOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - let test_account: T::AccountId = account("seed",1,1); - assert_ok!(CrossInOut::::add_to_issue_whitelist( - T::ControlOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, - CurrencyId::Token(TokenSymbol::DOT), - test_account.clone() - )); - }: _(origin,CurrencyId::Token(TokenSymbol::DOT),test_account) - add_to_register_whitelist { let origin = T::ControlOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let caller = whitelisted_caller(); @@ -79,33 +60,6 @@ benchmarks! { )); }: _(origin,CurrencyId::Token(TokenSymbol::DOT),test_account) - cross_in { - let test_account: T::AccountId = account("seed",1,1); - assert_ok!(CrossInOut::::register_currency_for_cross_in_out( - T::ControlOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, - CurrencyId::Token(TokenSymbol::DOT) - )); - - assert_ok!(CrossInOut::::set_crossing_minimum_amount( - T::ControlOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, - CurrencyId::Token(TokenSymbol::DOT),100u32.into(),100u32.into() - )); - - assert_ok!(CrossInOut::::add_to_issue_whitelist( - T::ControlOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, - CurrencyId::Token(TokenSymbol::DOT), - test_account.clone() - )); - - let location = Box::new(MultiLocation { - parents: 0, - interior: X1(AccountId32 { - network: Any, - id: T::EntrancePalletId::get().into_account_truncating(), - }), - }); - }: _(RawOrigin::Signed(test_account),location,CurrencyId::Token(TokenSymbol::DOT),100u32.into(),None) - register_linked_account { let test_account: T::AccountId = account("seed",1,1); assert_ok!(CrossInOut::::add_to_register_whitelist( diff --git a/pallets/cross-in-out/src/lib.rs b/pallets/cross-in-out/src/lib.rs index 9cf42a272..f41653467 100644 --- a/pallets/cross-in-out/src/lib.rs +++ b/pallets/cross-in-out/src/lib.rs @@ -19,21 +19,17 @@ // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] -// pub use crate::imbalances::{NegativeImbalance, PositiveImbalance}; extern crate alloc; -use alloc::{vec, vec::Vec}; +use alloc::vec; use bifrost_primitives::CurrencyId; -use frame_support::{ensure, pallet_prelude::*, sp_runtime::traits::AccountIdConversion, PalletId}; +use frame_support::{ensure, pallet_prelude::*, PalletId}; use frame_system::pallet_prelude::*; use orml_traits::MultiCurrency; use sp_std::boxed::Box; pub use weights::WeightInfo; #[allow(deprecated)] -use xcm::{ - opaque::v2::{Junction::AccountId32, Junctions::X1, NetworkId::Any}, - v2::MultiLocation, -}; +use xcm::v2::MultiLocation; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; @@ -75,62 +71,49 @@ pub mod pallet { #[pallet::error] pub enum Error { + /// Indicates that the balance is not sufficient for the requested operation. NotEnoughBalance, + /// Indicates that the specified item does not exist. NotExist, + /// Indicates that the operation is not allowed for the current context. NotAllowed, + /// Indicates that the currency does not support crossing in and out. CurrencyNotSupportCrossInAndOut, + /// Indicates that there is no mapping for the specified multilocation. NoMultilocationMapping, - NoAccountIdMapping, + /// Indicates that the item already exists. AlreadyExist, + /// Indicates that there is no minimum crossing amount set for the operation. NoCrossingMinimumSet, + /// Indicates that the specified amount is lower than the required minimum. AmountLowerThanMinimum, - ExceedMaxLengthLimit, - FailedToConvert, + /// Indicates that the list has reached its maximum capacity. + ListOverflow, } #[pallet::event] #[pallet::generate_deposit(pub(crate) fn deposit_event)] pub enum Event { + /// Event emitted when a currency is successfully crossed out from a location. CrossedOut { currency_id: CurrencyId, crosser: AccountIdOf, location: MultiLocation, amount: BalanceOf, }, - CrossedIn { - currency_id: CurrencyId, - dest: AccountIdOf, - location: MultiLocation, - amount: BalanceOf, - remark: Option>, - }, - CurrencyRegistered { - currency_id: CurrencyId, - }, - CurrencyDeregistered { - currency_id: CurrencyId, - }, - AddedToIssueList { - account: AccountIdOf, - currency_id: CurrencyId, - }, - RemovedFromIssueList { - account: AccountIdOf, - currency_id: CurrencyId, - }, + /// Event emitted when a currency is deregistered. + CurrencyDeregistered { currency_id: CurrencyId }, + /// Event emitted when a linked account is successfully registered. LinkedAccountRegistered { currency_id: CurrencyId, who: AccountIdOf, foreign_location: MultiLocation, }, - AddedToRegisterList { - account: AccountIdOf, - currency_id: CurrencyId, - }, - RemovedFromRegisterList { - account: AccountIdOf, - currency_id: CurrencyId, - }, + /// Event emitted when an account is added to the register list. + AddedToRegisterList { account: AccountIdOf, currency_id: CurrencyId }, + /// Event emitted when an account is removed from the register list. + RemovedFromRegisterList { account: AccountIdOf, currency_id: CurrencyId }, + /// Event emitted when the crossing minimum amounts are set for a currency. CrossingMinimumAmountSet { currency_id: CurrencyId, cross_in_minimum: BalanceOf, @@ -140,7 +123,7 @@ pub mod pallet { /// The current storage version, we set to 2 our new version(after migrate stroage from vec t /// boundedVec). - const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(3); /// To store currencies that support indirect cross-in and cross-out. #[pallet::storage] @@ -153,8 +136,8 @@ pub mod pallet { /// Accounts in the whitelist can register the mapping between a multilocation and an accountId. #[pallet::storage] - pub type RegisterWhiteList = - StorageMap<_, Blake2_128Concat, CurrencyId, Vec>>; + pub type RegisterWhiteList = + StorageMap<_, Blake2_128Concat, CurrencyId, BoundedVec, T::MaxLengthLimit>>; /// Mapping a Bifrost account to a multilocation of a outer chain #[pallet::storage] @@ -195,58 +178,6 @@ pub mod pallet { #[pallet::call] impl Pallet { - #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::cross_in())] - pub fn cross_in( - origin: OriginFor, - location: Box, - currency_id: CurrencyId, - #[pallet::compact] amount: BalanceOf, - remark: Option>, - ) -> DispatchResult { - let issuer = ensure_signed(origin)?; - - ensure!( - CrossCurrencyRegistry::::contains_key(currency_id), - Error::::CurrencyNotSupportCrossInAndOut - ); - - let crossing_minimum_amount = CrossingMinimumAmount::::get(currency_id) - .ok_or(Error::::NoCrossingMinimumSet)?; - ensure!(amount >= crossing_minimum_amount.0, Error::::AmountLowerThanMinimum); - - let issue_whitelist = - IssueWhiteList::::get(currency_id).ok_or(Error::::NotAllowed)?; - ensure!(issue_whitelist.contains(&issuer), Error::::NotAllowed); - - let entrance_account_mutlilcaition = Box::new(MultiLocation { - parents: 0, - interior: X1(AccountId32 { - network: Any, - id: T::EntrancePalletId::get().into_account_truncating(), - }), - }); - - // If the cross_in destination is entrance account, it is not required to be registered. - let dest = if entrance_account_mutlilcaition == location { - T::EntrancePalletId::get().into_account_truncating() - } else { - OuterMultilocationToAccount::::get(currency_id, location.clone()) - .ok_or(Error::::NoAccountIdMapping)? - }; - - T::MultiCurrency::deposit(currency_id, &dest, amount)?; - - Self::deposit_event(Event::CrossedIn { - dest, - currency_id, - location: *location, - amount, - remark, - }); - Ok(()) - } - /// Destroy some balance from an account and issue cross-out event. #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::cross_out())] @@ -364,25 +295,6 @@ pub mod pallet { Ok(()) } - #[pallet::call_index(4)] - #[pallet::weight(T::WeightInfo::register_currency_for_cross_in_out())] - pub fn register_currency_for_cross_in_out( - origin: OriginFor, - currency_id: CurrencyId, - ) -> DispatchResult { - T::ControlOrigin::ensure_origin(origin)?; - - CrossCurrencyRegistry::::mutate_exists(currency_id, |registration| { - if registration.is_none() { - *registration = Some(()); - - Self::deposit_event(Event::CurrencyRegistered { currency_id }); - } - }); - - Ok(()) - } - #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::deregister_currency_for_cross_in_out())] pub fn deregister_currency_for_cross_in_out( @@ -398,63 +310,6 @@ pub mod pallet { Ok(()) } - #[pallet::call_index(6)] - #[pallet::weight(T::WeightInfo::add_to_issue_whitelist())] - pub fn add_to_issue_whitelist( - origin: OriginFor, - currency_id: CurrencyId, - account: AccountIdOf, - ) -> DispatchResult { - T::ControlOrigin::ensure_origin(origin)?; - - let rs = IssueWhiteList::::get(currency_id); - let mut issue_whitelist; - if let Some(bounded_vec) = rs { - issue_whitelist = bounded_vec.to_vec(); - ensure!( - issue_whitelist.len() < T::MaxLengthLimit::get() as usize, - Error::::ExceedMaxLengthLimit - ); - ensure!(!issue_whitelist.contains(&account), Error::::AlreadyExist); - - issue_whitelist.push(account.clone()); - } else { - issue_whitelist = vec![account.clone()]; - } - - let bounded_issue_whitelist = - BoundedVec::try_from(issue_whitelist).map_err(|_| Error::::FailedToConvert)?; - - IssueWhiteList::::insert(currency_id, bounded_issue_whitelist); - - Self::deposit_event(Event::AddedToIssueList { account, currency_id }); - - Ok(()) - } - - #[pallet::call_index(7)] - #[pallet::weight(T::WeightInfo::remove_from_issue_whitelist())] - pub fn remove_from_issue_whitelist( - origin: OriginFor, - currency_id: CurrencyId, - account: AccountIdOf, - ) -> DispatchResult { - T::ControlOrigin::ensure_origin(origin)?; - - IssueWhiteList::::mutate(currency_id, |issue_whitelist| -> Result<(), Error> { - match issue_whitelist { - Some(issue_list) if issue_list.contains(&account) => { - issue_list.retain(|x| x.clone() != account); - Self::deposit_event(Event::RemovedFromIssueList { account, currency_id }); - Ok(()) - }, - _ => Err(Error::::NotExist), - } - })?; - - Ok(()) - } - #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::add_to_register_whitelist())] pub fn add_to_register_whitelist( @@ -464,9 +319,8 @@ pub mod pallet { ) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; - let empty_vec: Vec> = Vec::new(); if RegisterWhiteList::::get(currency_id) == None { - RegisterWhiteList::::insert(currency_id, empty_vec); + RegisterWhiteList::::insert(currency_id, BoundedVec::default()); } RegisterWhiteList::::mutate( @@ -474,7 +328,9 @@ pub mod pallet { |register_whitelist| -> Result<(), Error> { match register_whitelist { Some(register_list) if !register_list.contains(&account) => { - register_list.push(account.clone()); + register_list + .try_push(account.clone()) + .map_err(|_| Error::::ListOverflow)?; Self::deposit_event(Event::AddedToRegisterList { account, currency_id, @@ -539,4 +395,21 @@ pub mod pallet { Ok(()) } } + + impl Pallet { + pub fn register_currency_for_cross_in_out( + origin: OriginFor, + currency_id: CurrencyId, + ) -> DispatchResult { + T::ControlOrigin::ensure_origin(origin)?; + + CrossCurrencyRegistry::::mutate_exists(currency_id, |registration| { + if registration.is_none() { + *registration = Some(()); + } + }); + + Ok(()) + } + } } diff --git a/pallets/cross-in-out/src/migrations/mod.rs b/pallets/cross-in-out/src/migrations/mod.rs index 504be9301..f5231cb7b 100644 --- a/pallets/cross-in-out/src/migrations/mod.rs +++ b/pallets/cross-in-out/src/migrations/mod.rs @@ -18,3 +18,4 @@ /// Version 2. pub mod v2; +pub mod v3; diff --git a/pallets/cross-in-out/src/migrations/v3.rs b/pallets/cross-in-out/src/migrations/v3.rs new file mode 100644 index 000000000..b2d44e09a --- /dev/null +++ b/pallets/cross-in-out/src/migrations/v3.rs @@ -0,0 +1,92 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 crate::*; +use alloc::vec::Vec; +use frame_support::traits::OnRuntimeUpgrade; +#[cfg(feature = "try-runtime")] +use sp_runtime::TryRuntimeError; + +const LOG_TARGET: &str = "cross-in-out::migration"; + +pub struct MigrateToV2(sp_std::marker::PhantomData); +impl OnRuntimeUpgrade for MigrateToV2 { + fn on_runtime_upgrade() -> frame_support::weights::Weight { + // Check the storage version + let onchain_version = Pallet::::on_chain_storage_version(); + if onchain_version < 3 { + // Transform storage values + // We transform the storage values from the old into the new format. + log::info!(target: LOG_TARGET, "Start to migrate RegisterWhiteList storage..."); + RegisterWhiteList::::translate::>, _>( + |k: CurrencyId, value: Vec>| { + log::info!(target: LOG_TARGET, "Migrated to boundedvec for {:?}...", k); + + let target_bounded_vec: BoundedVec, T::MaxLengthLimit>; + + if value.len() != 0 { + target_bounded_vec = BoundedVec::try_from(value).unwrap(); + } else { + target_bounded_vec = + BoundedVec::, T::MaxLengthLimit>::default(); + } + + Some(target_bounded_vec) + }, + ); + + // Update the storage version + StorageVersion::new(3).put::>(); + + // Return the consumed weight + let count = RegisterWhiteList::::iter().count(); + Weight::from(T::DbWeight::get().reads_writes(count as u64 + 1, count as u64 + 1)) + } else { + // We don't do anything here. + Weight::zero() + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + let cnt = RegisterWhiteList::::iter().count(); + log::info!(target: LOG_TARGET, "RegisterWhiteList pre-migrate storage count: {:?}", cnt); + Ok((cnt as u64).encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(cnt: Vec) -> Result<(), TryRuntimeError> { + let new_count = RegisterWhiteList::::iter().count(); + + let old_count: u64 = Decode::decode(&mut cnt.as_slice()) + .expect("the state parameter should be something that was generated by pre_upgrade"); + + log::info!( + target: LOG_TARGET, + "RegisterWhiteList post-migrate storage count: {:?}", + new_count + ); + + ensure!( + new_count as u64 == old_count, + "Post-migration storage count does not match pre-migration count" + ); + + Ok(()) + } +} diff --git a/pallets/cross-in-out/src/mock.rs b/pallets/cross-in-out/src/mock.rs index c76374cf3..043bf05f4 100644 --- a/pallets/cross-in-out/src/mock.rs +++ b/pallets/cross-in-out/src/mock.rs @@ -161,6 +161,7 @@ impl ExtBuilder { (CHARLIE, BNC, 100), (ALICE, DOT, 100), (ALICE, VDOT, 400), + (ALICE, KSM, 100), (BOB, DOT, 100), (BOB, KSM, 100), ]) diff --git a/pallets/cross-in-out/src/tests.rs b/pallets/cross-in-out/src/tests.rs index 0e60781cb..dd549ff6b 100644 --- a/pallets/cross-in-out/src/tests.rs +++ b/pallets/cross-in-out/src/tests.rs @@ -33,82 +33,10 @@ fn cross_in_and_cross_out_should_work() { parents: 100, interior: X1(Junction::GeneralKey(WeakBoundedVec::default())), }; - - assert_noop!( - CrossInOut::cross_in( - RuntimeOrigin::signed(ALICE), - Box::new(location.clone()), - KSM, - 100, - None - ), - Error::::CurrencyNotSupportCrossInAndOut - ); - CrossCurrencyRegistry::::insert(KSM, ()); - - assert_noop!( - CrossInOut::cross_in( - RuntimeOrigin::signed(ALICE), - Box::new(location.clone()), - KSM, - 100, - None - ), - Error::::NoCrossingMinimumSet - ); - - CrossingMinimumAmount::::insert(KSM, (1000, 1000)); - - assert_noop!( - CrossInOut::cross_in( - RuntimeOrigin::signed(ALICE), - Box::new(location.clone()), - KSM, - 100, - None - ), - Error::::AmountLowerThanMinimum - ); - CrossingMinimumAmount::::insert(KSM, (1, 1)); - - assert_noop!( - CrossInOut::cross_in( - RuntimeOrigin::signed(ALICE), - Box::new(location.clone()), - KSM, - 100, - None - ), - Error::::NotAllowed - ); - - let bounded_vector = BoundedVec::try_from(vec![ALICE]).unwrap(); - IssueWhiteList::::insert(KSM, bounded_vector); - - assert_noop!( - CrossInOut::cross_in( - RuntimeOrigin::signed(ALICE), - Box::new(location.clone()), - KSM, - 100, - None - ), - Error::::NoAccountIdMapping - ); - AccountToOuterMultilocation::::insert(KSM, ALICE, location.clone()); OuterMultilocationToAccount::::insert(KSM, location.clone(), ALICE); - - assert_eq!(Tokens::free_balance(KSM, &ALICE), 0); - assert_ok!(CrossInOut::cross_in( - RuntimeOrigin::signed(ALICE), - Box::new(location), - KSM, - 100, - None - )); assert_eq!(Tokens::free_balance(KSM, &ALICE), 100); assert_ok!(CrossInOut::cross_out(RuntimeOrigin::signed(ALICE), KSM, 50)); @@ -116,37 +44,16 @@ fn cross_in_and_cross_out_should_work() { }); } -#[test] -fn add_to_and_remove_from_issue_whitelist_should_work() { - ExtBuilder::default().one_hundred_for_alice_n_bob().build().execute_with(|| { - assert_eq!(IssueWhiteList::::get(KSM), None); - - assert_ok!(CrossInOut::add_to_issue_whitelist(RuntimeOrigin::signed(ALICE), KSM, ALICE)); - let bounded_vector = BoundedVec::try_from(vec![ALICE]).unwrap(); - assert_eq!(IssueWhiteList::::get(KSM), Some(bounded_vector)); - - assert_noop!( - CrossInOut::remove_from_issue_whitelist(RuntimeOrigin::signed(ALICE), KSM, BOB), - Error::::NotExist - ); - - assert_ok!(CrossInOut::remove_from_issue_whitelist( - RuntimeOrigin::signed(ALICE), - KSM, - ALICE - )); - let empty_vec = BoundedVec::default(); - assert_eq!(IssueWhiteList::::get(KSM), Some(empty_vec)); - }); -} - #[test] fn add_to_and_remove_from_register_whitelist_should_work() { ExtBuilder::default().one_hundred_for_alice_n_bob().build().execute_with(|| { assert_eq!(RegisterWhiteList::::get(KSM), None); assert_ok!(CrossInOut::add_to_register_whitelist(RuntimeOrigin::signed(ALICE), KSM, ALICE)); - assert_eq!(RegisterWhiteList::::get(KSM), Some(vec![ALICE])); + assert_eq!( + RegisterWhiteList::::get(KSM), + Some(BoundedVec::try_from(vec![ALICE]).unwrap()) + ); assert_noop!( CrossInOut::remove_from_register_whitelist(RuntimeOrigin::signed(ALICE), KSM, BOB), @@ -158,7 +65,7 @@ fn add_to_and_remove_from_register_whitelist_should_work() { KSM, ALICE )); - assert_eq!(RegisterWhiteList::::get(KSM), Some(vec![])); + assert_eq!(RegisterWhiteList::::get(KSM), Some(BoundedVec::default())); }); } @@ -186,7 +93,7 @@ fn register_linked_account_should_work() { Error::::NotAllowed ); - RegisterWhiteList::::insert(KSM, vec![ALICE]); + RegisterWhiteList::::insert(KSM, BoundedVec::try_from(vec![ALICE]).unwrap()); assert_noop!( CrossInOut::register_linked_account( @@ -222,12 +129,7 @@ fn register_linked_account_should_work() { #[test] fn register_and_deregister_currency_for_cross_in_out_should_work() { ExtBuilder::default().one_hundred_for_alice_n_bob().build().execute_with(|| { - assert_ok!(CrossInOut::register_currency_for_cross_in_out( - RuntimeOrigin::signed(ALICE), - KSM, - )); - - assert_eq!(CrossCurrencyRegistry::::get(KSM), Some(())); + CrossCurrencyRegistry::::insert(KSM, ()); assert_ok!(CrossInOut::deregister_currency_for_cross_in_out( RuntimeOrigin::signed(ALICE), diff --git a/pallets/cross-in-out/src/weights.rs b/pallets/cross-in-out/src/weights.rs index bb190417d..d75f2deea 100644 --- a/pallets/cross-in-out/src/weights.rs +++ b/pallets/cross-in-out/src/weights.rs @@ -53,14 +53,10 @@ use sp_std::marker::PhantomData; /// Weight functions needed for bifrost_cross_in_out. pub trait WeightInfo { - fn register_currency_for_cross_in_out() -> Weight; fn deregister_currency_for_cross_in_out() -> Weight; fn set_crossing_minimum_amount() -> Weight; - fn add_to_issue_whitelist() -> Weight; - fn remove_from_issue_whitelist() -> Weight; fn add_to_register_whitelist() -> Weight; fn remove_from_register_whitelist() -> Weight; - fn cross_in() -> Weight; fn register_linked_account() -> Weight; fn cross_out() -> Weight; fn change_outer_linked_account() -> Weight; @@ -68,17 +64,6 @@ pub trait WeightInfo { // For backwards compatibility and tests impl WeightInfo for () { - /// Storage: CrossInOut CrossCurrencyRegistry (r:1 w:1) - /// Proof Skipped: CrossInOut CrossCurrencyRegistry (max_values: None, max_size: None, mode: Measured) - fn register_currency_for_cross_in_out() -> Weight { - // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `3541` - // Minimum execution time: 29_633_000 picoseconds. - Weight::from_parts(30_578_000, 3541) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } /// Storage: CrossInOut CrossCurrencyRegistry (r:1 w:1) /// Proof Skipped: CrossInOut CrossCurrencyRegistry (max_values: None, max_size: None, mode: Measured) fn deregister_currency_for_cross_in_out() -> Weight { @@ -100,28 +85,6 @@ impl WeightInfo for () { Weight::from_parts(24_439_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: CrossInOut IssueWhiteList (r:1 w:1) - /// Proof Skipped: CrossInOut IssueWhiteList (max_values: None, max_size: None, mode: Measured) - fn add_to_issue_whitelist() -> Weight { - // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `3541` - // Minimum execution time: 34_191_000 picoseconds. - Weight::from_parts(35_236_000, 3541) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - /// Storage: CrossInOut IssueWhiteList (r:1 w:1) - /// Proof Skipped: CrossInOut IssueWhiteList (max_values: None, max_size: None, mode: Measured) - fn remove_from_issue_whitelist() -> Weight { - // Proof Size summary in bytes: - // Measured: `154` - // Estimated: `3619` - // Minimum execution time: 35_934_000 picoseconds. - Weight::from_parts(37_252_000, 3619) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } /// Storage: CrossInOut RegisterWhiteList (r:1 w:1) /// Proof Skipped: CrossInOut RegisterWhiteList (max_values: None, max_size: None, mode: Measured) fn add_to_register_whitelist() -> Weight { @@ -144,29 +107,6 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: CrossInOut CrossCurrencyRegistry (r:1 w:0) - /// Proof Skipped: CrossInOut CrossCurrencyRegistry (max_values: None, max_size: None, mode: Measured) - /// Storage: CrossInOut CrossingMinimumAmount (r:1 w:0) - /// Proof Skipped: CrossInOut CrossingMinimumAmount (max_values: None, max_size: None, mode: Measured) - /// Storage: CrossInOut IssueWhiteList (r:1 w:0) - /// Proof Skipped: CrossInOut IssueWhiteList (max_values: None, max_size: None, mode: Measured) - /// Storage: Tokens Accounts (r:1 w:1) - /// Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) - /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) - /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - /// Storage: Tokens TotalIssuance (r:1 w:1) - /// Proof: Tokens TotalIssuance (max_values: None, max_size: Some(38), added: 2513, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn cross_in() -> Weight { - // Proof Size summary in bytes: - // Measured: `1758` - // Estimated: `5223` - // Minimum execution time: 146_488_000 picoseconds. - Weight::from_parts(150_867_000, 5223) - .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) - } /// Storage: CrossInOut RegisterWhiteList (r:1 w:0) /// Proof Skipped: CrossInOut RegisterWhiteList (max_values: None, max_size: None, mode: Measured) /// Storage: CrossInOut CrossCurrencyRegistry (r:1 w:0) diff --git a/runtime/bifrost-kusama/src/lib.rs b/runtime/bifrost-kusama/src/lib.rs index b5820a869..5095e5a50 100644 --- a/runtime/bifrost-kusama/src/lib.rs +++ b/runtime/bifrost-kusama/src/lib.rs @@ -1932,6 +1932,7 @@ pub mod migrations { pub type Unreleased = ( // permanent migration, do not remove pallet_xcm::migration::MigrateToLatestXcmVersion, + bifrost_cross_in_out::migrations::v3::MigrateToV2, SystemMakerClearPalletId, frame_support::migrations::RemovePallet, ); diff --git a/runtime/bifrost-kusama/src/weights/bifrost_cross_in_out.rs b/runtime/bifrost-kusama/src/weights/bifrost_cross_in_out.rs index 870af08ca..eaf91c404 100644 --- a/runtime/bifrost-kusama/src/weights/bifrost_cross_in_out.rs +++ b/runtime/bifrost-kusama/src/weights/bifrost_cross_in_out.rs @@ -54,17 +54,6 @@ use sp_std::marker::PhantomData; /// Weight functions for bifrost_cross_in_out. pub struct BifrostWeight(PhantomData); impl bifrost_cross_in_out::WeightInfo for BifrostWeight { - // Storage: CrossInOut CrossCurrencyRegistry (r:1 w:1) - // Proof Skipped: CrossInOut CrossCurrencyRegistry (max_values: None, max_size: None, mode: Measured) - fn register_currency_for_cross_in_out() -> Weight { - // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `3541` - // Minimum execution time: 30_069 nanoseconds. - Weight::from_parts(30_714_000, 3541) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } // Storage: CrossInOut CrossCurrencyRegistry (r:1 w:1) // Proof Skipped: CrossInOut CrossCurrencyRegistry (max_values: None, max_size: None, mode: Measured) fn deregister_currency_for_cross_in_out() -> Weight { @@ -86,28 +75,6 @@ impl bifrost_cross_in_out::WeightInfo for BifrostWeight Weight::from_parts(25_172_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CrossInOut IssueWhiteList (r:1 w:1) - // Proof Skipped: CrossInOut IssueWhiteList (max_values: None, max_size: None, mode: Measured) - fn add_to_issue_whitelist() -> Weight { - // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `3541` - // Minimum execution time: 34_593 nanoseconds. - Weight::from_parts(35_760_000, 3541) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: CrossInOut IssueWhiteList (r:1 w:1) - // Proof Skipped: CrossInOut IssueWhiteList (max_values: None, max_size: None, mode: Measured) - fn remove_from_issue_whitelist() -> Weight { - // Proof Size summary in bytes: - // Measured: `154` - // Estimated: `3619` - // Minimum execution time: 35_748 nanoseconds. - Weight::from_parts(36_569_000, 3619) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } // Storage: CrossInOut RegisterWhiteList (r:1 w:1) // Proof Skipped: CrossInOut RegisterWhiteList (max_values: None, max_size: None, mode: Measured) fn add_to_register_whitelist() -> Weight { @@ -130,29 +97,6 @@ impl bifrost_cross_in_out::WeightInfo for BifrostWeight .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CrossInOut CrossCurrencyRegistry (r:1 w:0) - // Proof Skipped: CrossInOut CrossCurrencyRegistry (max_values: None, max_size: None, mode: Measured) - // Storage: CrossInOut CrossingMinimumAmount (r:1 w:0) - // Proof Skipped: CrossInOut CrossingMinimumAmount (max_values: None, max_size: None, mode: Measured) - // Storage: CrossInOut IssueWhiteList (r:1 w:0) - // Proof Skipped: CrossInOut IssueWhiteList (max_values: None, max_size: None, mode: Measured) - // Storage: Tokens Accounts (r:1 w:1) - // Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) - // Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) - // Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - // Storage: Tokens TotalIssuance (r:1 w:1) - // Proof: Tokens TotalIssuance (max_values: None, max_size: Some(38), added: 2513, mode: MaxEncodedLen) - // Storage: System Account (r:1 w:1) - // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn cross_in() -> Weight { - // Proof Size summary in bytes: - // Measured: `1758` - // Estimated: `5223` - // Minimum execution time: 146_344 nanoseconds. - Weight::from_parts(147_835_000, 5223) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(3)) - } // Storage: CrossInOut RegisterWhiteList (r:1 w:0) // Proof Skipped: CrossInOut RegisterWhiteList (max_values: None, max_size: None, mode: Measured) // Storage: CrossInOut CrossCurrencyRegistry (r:1 w:0) diff --git a/runtime/bifrost-polkadot/src/lib.rs b/runtime/bifrost-polkadot/src/lib.rs index 51238fd02..579a05809 100644 --- a/runtime/bifrost-polkadot/src/lib.rs +++ b/runtime/bifrost-polkadot/src/lib.rs @@ -1845,6 +1845,7 @@ pub mod migrations { pub type Unreleased = ( // permanent migration, do not remove pallet_xcm::migration::MigrateToLatestXcmVersion, + bifrost_cross_in_out::migrations::v3::MigrateToV2, frame_support::migrations::RemovePallet, ); } diff --git a/runtime/bifrost-polkadot/src/weights/bifrost_cross_in_out.rs b/runtime/bifrost-polkadot/src/weights/bifrost_cross_in_out.rs index 870af08ca..eaf91c404 100644 --- a/runtime/bifrost-polkadot/src/weights/bifrost_cross_in_out.rs +++ b/runtime/bifrost-polkadot/src/weights/bifrost_cross_in_out.rs @@ -54,17 +54,6 @@ use sp_std::marker::PhantomData; /// Weight functions for bifrost_cross_in_out. pub struct BifrostWeight(PhantomData); impl bifrost_cross_in_out::WeightInfo for BifrostWeight { - // Storage: CrossInOut CrossCurrencyRegistry (r:1 w:1) - // Proof Skipped: CrossInOut CrossCurrencyRegistry (max_values: None, max_size: None, mode: Measured) - fn register_currency_for_cross_in_out() -> Weight { - // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `3541` - // Minimum execution time: 30_069 nanoseconds. - Weight::from_parts(30_714_000, 3541) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } // Storage: CrossInOut CrossCurrencyRegistry (r:1 w:1) // Proof Skipped: CrossInOut CrossCurrencyRegistry (max_values: None, max_size: None, mode: Measured) fn deregister_currency_for_cross_in_out() -> Weight { @@ -86,28 +75,6 @@ impl bifrost_cross_in_out::WeightInfo for BifrostWeight Weight::from_parts(25_172_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CrossInOut IssueWhiteList (r:1 w:1) - // Proof Skipped: CrossInOut IssueWhiteList (max_values: None, max_size: None, mode: Measured) - fn add_to_issue_whitelist() -> Weight { - // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `3541` - // Minimum execution time: 34_593 nanoseconds. - Weight::from_parts(35_760_000, 3541) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: CrossInOut IssueWhiteList (r:1 w:1) - // Proof Skipped: CrossInOut IssueWhiteList (max_values: None, max_size: None, mode: Measured) - fn remove_from_issue_whitelist() -> Weight { - // Proof Size summary in bytes: - // Measured: `154` - // Estimated: `3619` - // Minimum execution time: 35_748 nanoseconds. - Weight::from_parts(36_569_000, 3619) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } // Storage: CrossInOut RegisterWhiteList (r:1 w:1) // Proof Skipped: CrossInOut RegisterWhiteList (max_values: None, max_size: None, mode: Measured) fn add_to_register_whitelist() -> Weight { @@ -130,29 +97,6 @@ impl bifrost_cross_in_out::WeightInfo for BifrostWeight .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CrossInOut CrossCurrencyRegistry (r:1 w:0) - // Proof Skipped: CrossInOut CrossCurrencyRegistry (max_values: None, max_size: None, mode: Measured) - // Storage: CrossInOut CrossingMinimumAmount (r:1 w:0) - // Proof Skipped: CrossInOut CrossingMinimumAmount (max_values: None, max_size: None, mode: Measured) - // Storage: CrossInOut IssueWhiteList (r:1 w:0) - // Proof Skipped: CrossInOut IssueWhiteList (max_values: None, max_size: None, mode: Measured) - // Storage: Tokens Accounts (r:1 w:1) - // Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) - // Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) - // Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - // Storage: Tokens TotalIssuance (r:1 w:1) - // Proof: Tokens TotalIssuance (max_values: None, max_size: Some(38), added: 2513, mode: MaxEncodedLen) - // Storage: System Account (r:1 w:1) - // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn cross_in() -> Weight { - // Proof Size summary in bytes: - // Measured: `1758` - // Estimated: `5223` - // Minimum execution time: 146_344 nanoseconds. - Weight::from_parts(147_835_000, 5223) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(3)) - } // Storage: CrossInOut RegisterWhiteList (r:1 w:0) // Proof Skipped: CrossInOut RegisterWhiteList (max_values: None, max_size: None, mode: Measured) // Storage: CrossInOut CrossCurrencyRegistry (r:1 w:0) From 9237c35ec862d744496d84682e077195694614b1 Mon Sep 17 00:00:00 2001 From: yooml Date: Wed, 25 Sep 2024 22:45:41 +0800 Subject: [PATCH 07/30] Update bb bnc (#1436) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 💡 for review * docs: ✏️ add docs * fix: 🐛 docs * fix: 🐛 add event && addr rename --- pallets/bb-bnc/src/incentive.rs | 68 ++--- pallets/bb-bnc/src/lib.rs | 426 +++++++++++++++++++++----------- pallets/bb-bnc/src/tests.rs | 14 +- pallets/bb-bnc/src/traits.rs | 78 +++--- 4 files changed, 367 insertions(+), 219 deletions(-) diff --git a/pallets/bb-bnc/src/incentive.rs b/pallets/bb-bnc/src/incentive.rs index 4edfcb1eb..ec082aedd 100644 --- a/pallets/bb-bnc/src/incentive.rs +++ b/pallets/bb-bnc/src/incentive.rs @@ -23,12 +23,20 @@ use sp_std::collections::btree_map::BTreeMap; #[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo)] pub struct IncentiveConfig { + /// Reward per block number per currency_id, which will change at notify_reward. pub reward_rate: BTreeMap, + /// Each currency_id is rewarded against each TokenType and grows with user actions. pub reward_per_token_stored: BTreeMap, + /// Round duration. pub rewards_duration: BlockNumber, + /// The time when this round ends. pub period_finish: BlockNumber, + /// Last time rewards were updated, any user action will update this field. pub last_update_time: BlockNumber, + /// When a round is started, the corresponding value will be transferred from this account to + /// the system account. pub incentive_controller: Option, + /// When a round is started, the value to be transferred will be obtained from this field. pub last_reward: Vec<(CurrencyId, Balance)>, } @@ -103,22 +111,22 @@ impl Pallet { /// Calculates the reward earned by an account from a specific reward pool pub fn earned( pool_id: PoolId, - addr: &AccountIdOf, + who: &AccountIdOf, share_info: Option<(BalanceOf, BalanceOf)>, ) -> Result, BalanceOf>, DispatchError> { let reward_per_token = Self::reward_per_token(pool_id)?; - let vetoken_balance = Self::balance_of_current_block(addr)?; - let mut rewards = if let Some(rewards) = Rewards::::get(addr) { + let bbbnc_balance = Self::balance_of_current_block(who)?; + let mut rewards = if let Some(rewards) = Rewards::::get(who) { rewards } else { BTreeMap::, BalanceOf>::default() }; reward_per_token.iter().try_for_each(|(currency, reward)| -> DispatchResult { - let increment = U256::from(vetoken_balance.saturated_into::()) + let increment = U256::from(bbbnc_balance.saturated_into::()) .checked_mul(U256::from( reward .saturating_sub( - *UserRewardPerTokenPaid::::get(addr) + *UserRewardPerTokenPaid::::get(who) .get(currency) .unwrap_or(&BalanceOf::::zero()), ) @@ -136,7 +144,7 @@ impl Pallet { // and total share. match share_info { Some((share, total_share)) => { - let mut pools = UserFarmingPool::::get(addr); + let mut pools = UserFarmingPool::::get(who); if share.is_zero() { if let Some(pos) = pools.iter().position(|&x| x == pool_id) { pools.remove(pos); @@ -144,7 +152,7 @@ impl Pallet { } else { pools.try_push(pool_id).map_err(|_| Error::::UserFarmingPoolOverflow)?; } - UserFarmingPool::::insert(addr, pools); + UserFarmingPool::::insert(who, pools); let reward = increment .checked_mul(U256::from(share.saturated_into::())) .ok_or(ArithmeticError::Overflow)? @@ -182,7 +190,7 @@ impl Pallet { // create_lock/increase_amount/increase_unlock_time/withdraw/get_rewards pub fn update_reward( pool_id: PoolId, - addr: Option<&AccountIdOf>, + who: Option<&AccountIdOf>, share_info: Option<(BalanceOf, BalanceOf)>, ) -> DispatchResult { let reward_per_token_stored = Self::reward_per_token(pool_id)?; @@ -191,51 +199,51 @@ impl Pallet { item.reward_per_token_stored = reward_per_token_stored.clone(); item.last_update_time = Self::last_time_reward_applicable(pool_id); }); - // If an account address is provided, update the rewards - if let Some(address) = addr { - let earned = Self::earned(pool_id, address, share_info)?; + // If an account is provided, update the rewards + if let Some(account) = who { + let earned = Self::earned(pool_id, account, share_info)?; // If the account has earned rewards, update the rewards storage if earned != BTreeMap::, BalanceOf>::default() { - Rewards::::insert(address, earned); + Rewards::::insert(account, earned); } - UserRewardPerTokenPaid::::insert(address, reward_per_token_stored.clone()); + UserRewardPerTokenPaid::::insert(account, reward_per_token_stored.clone()); } Ok(()) } /// Update reward for all pools - pub fn update_reward_all(addr: &AccountIdOf) -> DispatchResult { - UserFarmingPool::::get(addr) + pub fn update_reward_all(who: &AccountIdOf) -> DispatchResult { + UserFarmingPool::::get(who) .iter() .try_for_each(|&pool_id| -> DispatchResult { - Self::update_reward(pool_id, Some(addr), None) + Self::update_reward(pool_id, Some(who), None) })?; - Self::update_reward(VE_MINTING_SYSTEM_POOL_ID, Some(addr), None)?; + Self::update_reward(BB_BNC_SYSTEM_POOL_ID, Some(who), None)?; Ok(()) } ///Transfer rewards into an account pub fn get_rewards_inner( pool_id: PoolId, - addr: &AccountIdOf, + who: &AccountIdOf, share_info: Option<(BalanceOf, BalanceOf)>, ) -> DispatchResult { - Self::update_reward(pool_id, Some(addr), share_info)?; - if Self::balance_of_current_block(addr)? == BalanceOf::::zero() { + Self::update_reward(pool_id, Some(who), share_info)?; + if Self::balance_of_current_block(who)? == BalanceOf::::zero() { return Ok(()); } // Excit earlier if balance of token is zero - if let Some(rewards) = Rewards::::get(addr) { + if let Some(rewards) = Rewards::::get(who) { rewards.iter().try_for_each(|(currency, &reward)| -> DispatchResult { T::MultiCurrency::transfer( *currency, &T::IncentivePalletId::get().into_account_truncating(), - addr, + who, reward, ) })?; - Rewards::::remove(addr); + Rewards::::remove(who); Self::deposit_event(Event::Rewarded { - addr: addr.to_owned(), + who: who.to_owned(), rewards: rewards.into_iter().collect(), }); } @@ -245,11 +253,11 @@ impl Pallet { // Motion pub fn notify_reward_amount( pool_id: PoolId, - addr: &Option>, + who: &Option>, rewards: Vec<(CurrencyIdOf, BalanceOf)>, ) -> DispatchResult { - let who = match addr { - Some(addr) => addr, + let account = match who { + Some(who) => who, None => return Err(Error::::NoController.into()), }; Self::update_reward(pool_id, None, None)?; @@ -257,17 +265,17 @@ impl Pallet { let current_block_number: BlockNumberFor = frame_system::Pallet::::block_number(); if current_block_number >= conf.period_finish { - Self::add_reward(who, &mut conf, &rewards, Zero::zero())?; + Self::add_reward(&account, &mut conf, &rewards, Zero::zero())?; } else { let remaining = T::BlockNumberToBalance::convert( conf.period_finish.saturating_sub(current_block_number), ); - Self::add_reward(who, &mut conf, &rewards, remaining)?; + Self::add_reward(&account, &mut conf, &rewards, remaining)?; }; conf.last_update_time = current_block_number; conf.period_finish = current_block_number.saturating_add(conf.rewards_duration); - conf.incentive_controller = Some(who.clone()); + conf.incentive_controller = Some(account.clone()); conf.last_reward = rewards.clone(); IncentiveConfigs::::set(pool_id, conf); diff --git a/pallets/bb-bnc/src/lib.rs b/pallets/bb-bnc/src/lib.rs index 3e0728af3..e88290f02 100644 --- a/pallets/bb-bnc/src/lib.rs +++ b/pallets/bb-bnc/src/lib.rs @@ -60,13 +60,14 @@ pub type CurrencyIdOf = <::MultiCurrency as MultiCurrency< ::AccountId, >>::CurrencyId; -const VE_LOCK_ID: LockIdentifier = *b"vebnclck"; -const MARKUP_LOCK_ID: LockIdentifier = *b"vebncmkp"; -const VE_MINTING_SYSTEM_POOL_ID: PoolId = u32::MAX; +const BB_LOCK_ID: LockIdentifier = *b"bbbnclck"; +const MARKUP_LOCK_ID: LockIdentifier = *b"bbbncmkp"; +const BB_BNC_SYSTEM_POOL_ID: PoolId = u32::MAX; #[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Default)] -pub struct VeConfig { - amount: Balance, +pub struct BbConfig { + /// Minimum number of TokenType that users can lock min_mint: Balance, + /// Minimum time that users can lock min_block: BlockNumber, } @@ -131,6 +132,7 @@ pub mod pallet { #[pallet::constant] type MaxPositions: Get; + /// Maximum number of users per refresh. #[pallet::constant] type MarkupRefreshLimit: Get; } @@ -138,82 +140,132 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - ConfigSet { - config: VeConfig, BlockNumberFor>, - }, + /// The minimum number of TokenType and minimum time that users can lock has been set. + ConfigSet { config: BbConfig, BlockNumberFor> }, + /// A successful call of the `create_lock` function. Minted { - addr: u128, + /// the user who mint + who: AccountIdOf, + /// the position of this minting + position: u128, + /// the value of this minting value: BalanceOf, + /// total mint value for this user + total_value: BalanceOf, + /// withdrawable time end: BlockNumberFor, + /// current time now: BlockNumberFor, }, + /// Change in TokenType locked after calling. Supply { + /// The balance before the change. supply_before: BalanceOf, + /// The balance after the change. supply: BalanceOf, }, + /// A position was created. LockCreated { - addr: AccountIdOf, + /// Position owner + who: AccountIdOf, + /// Position ID + position: u128, + /// Locked value value: BalanceOf, + /// withdrawable time unlock_time: BlockNumberFor, }, + /// A position was extended. UnlockTimeIncreased { - addr: u128, + /// Position owner + who: AccountIdOf, + /// Position ID + position: u128, + /// New withdrawable time unlock_time: BlockNumberFor, }, + /// A position was increased. AmountIncreased { + /// Position owner who: AccountIdOf, + /// Position ID position: u128, + /// Increased value, not new locked value value: BalanceOf, }, + /// A position was withdrawn. Withdrawn { - addr: u128, + /// Position owner + who: AccountIdOf, + /// Position ID + position: u128, + /// Withdrawn value value: BalanceOf, }, + /// Incentive config set. IncentiveSet { incentive_config: IncentiveConfig, BalanceOf, BlockNumberFor, AccountIdOf>, }, - RewardAdded { - rewards: Vec<(CurrencyIdOf, BalanceOf)>, - }, - Rewarded { - addr: AccountIdOf, - rewards: Vec<(CurrencyIdOf, BalanceOf)>, - }, - AllRefreshed { - asset_id: CurrencyIdOf, - }, - PartiallyRefreshed { - asset_id: CurrencyIdOf, - }, - NotifyRewardFailed { - rewards: Vec<(CurrencyIdOf, BalanceOf)>, + /// The rewards for this round have been added to the system account. + RewardAdded { rewards: Vec<(CurrencyIdOf, BalanceOf)> }, + /// The user has received the reward. + Rewarded { who: AccountIdOf, rewards: Vec<(CurrencyIdOf, BalanceOf)> }, + /// This currency_id has been refreshed. + AllRefreshed { currency_id: CurrencyIdOf }, + /// This currency_id has been partially refreshed. + PartiallyRefreshed { currency_id: CurrencyIdOf }, + /// Notify reward failed. + NotifyRewardFailed { rewards: Vec<(CurrencyIdOf, BalanceOf)> }, + /// Markup has been deposited. + MarkupDeposited { + /// The user who deposited + who: AccountIdOf, + /// The token type of the deposit + currency_id: CurrencyIdOf, + /// The amount of currency_id to be deposited this time + value: BalanceOf, }, + /// Markup has been withdrawn. + MarkupWithdrawn { who: AccountIdOf, currency_id: CurrencyIdOf }, } #[pallet::error] pub enum Error { + /// Not enough balance NotEnoughBalance, + /// Block number is expired Expired, + /// Below minimum mint BelowMinimumMint, + /// Lock does not exist LockNotExist, + /// Lock already exists LockExist, + /// Arguments error ArgumentsError, + /// Exceeds max positions ExceedsMaxPositions, + /// No controller NoController, + /// User farming pool overflow UserFarmingPoolOverflow, } + /// Total supply of locked tokens #[pallet::storage] pub type Supply = StorageValue<_, BalanceOf, ValueQuery>; + /// Configurations #[pallet::storage] - pub type VeConfigs = - StorageValue<_, VeConfig, BlockNumberFor>, ValueQuery>; + pub type BbConfigs = + StorageValue<_, BbConfig, BlockNumberFor>, ValueQuery>; + /// Global epoch #[pallet::storage] pub type Epoch = StorageValue<_, U256, ValueQuery>; + /// Locked tokens. [position => LockedBalance] #[pallet::storage] pub type Locked = StorageMap< _, @@ -223,15 +275,17 @@ pub mod pallet { ValueQuery, >; + /// User locked tokens. [who => value] #[pallet::storage] pub type UserLocked = StorageMap<_, Blake2_128Concat, AccountIdOf, BalanceOf, ValueQuery>; - // Each week has a Point struct stored in PointHistory. + /// Each week has a Point struct stored in PointHistory. #[pallet::storage] pub type PointHistory = StorageMap<_, Twox64Concat, U256, Point, BlockNumberFor>, ValueQuery>; + /// User point history. [(who, epoch) => Point] #[pallet::storage] pub type UserPointHistory = StorageDoubleMap< _, @@ -243,14 +297,16 @@ pub mod pallet { ValueQuery, >; + /// User point epoch. [who => epoch] #[pallet::storage] pub type UserPointEpoch = StorageMap<_, Blake2_128Concat, u128, U256, ValueQuery>; + /// Slope changes. [block => slope] #[pallet::storage] pub type SlopeChanges = StorageMap<_, Twox64Concat, BlockNumberFor, i128, ValueQuery>; - // Incentive + /// Farming pool incentive configurations.[pool_id => IncentiveConfig] #[pallet::storage] pub type IncentiveConfigs = StorageMap< _, @@ -260,6 +316,7 @@ pub mod pallet { ValueQuery, >; + /// User reward per token paid. [who => reward per token] #[pallet::storage] pub type UserRewardPerTokenPaid = StorageMap< _, @@ -269,14 +326,17 @@ pub mod pallet { ValueQuery, >; + /// User rewards. [who => rewards] #[pallet::storage] pub type Rewards = StorageMap<_, Blake2_128Concat, AccountIdOf, BTreeMap, BalanceOf>>; + /// User markup infos. [who => UserMarkupInfo] #[pallet::storage] pub type UserMarkupInfos = StorageMap<_, Blake2_128Concat, AccountIdOf, UserMarkupInfo>; + /// Locked tokens for markup. [(token, who) => value] #[pallet::storage] pub type LockedTokens = StorageDoubleMap< _, @@ -287,17 +347,21 @@ pub mod pallet { LockedToken, BlockNumberFor>, >; + /// Total locked tokens for markup. [token => value] #[pallet::storage] pub type TotalLock = StorageMap<_, Twox64Concat, CurrencyIdOf, BalanceOf, ValueQuery>; + /// Markup coefficient. [token => MarkupCoefficientInfo] #[pallet::storage] pub type MarkupCoefficient = StorageMap<_, Twox64Concat, CurrencyIdOf, MarkupCoefficientInfo>>; + /// The last position of all. #[pallet::storage] pub type Position = StorageValue<_, u128, ValueQuery>; + /// Positions owned by the user. [who => positions] #[pallet::storage] pub type UserPositions = StorageMap< _, @@ -320,10 +384,10 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { fn on_initialize(n: BlockNumberFor) -> Weight { - let conf = IncentiveConfigs::::get(VE_MINTING_SYSTEM_POOL_ID); + let conf = IncentiveConfigs::::get(BB_BNC_SYSTEM_POOL_ID); if n == conf.period_finish { if let Some(e) = Self::notify_reward_amount( - VE_MINTING_SYSTEM_POOL_ID, + BB_BNC_SYSTEM_POOL_ID, &conf.incentive_controller, conf.last_reward.clone(), ) @@ -344,28 +408,41 @@ pub mod pallet { #[pallet::call] impl Pallet { + /// Set configuration. + /// + /// Set the minimum number of tokens and minimum time that users can lock. + /// + /// - `min_mint`: The minimum mint balance + /// - `min_block`: The minimum lockup time #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::set_config())] pub fn set_config( origin: OriginFor, - min_mint: Option>, // Minimum mint balance - min_block: Option>, // Minimum lockup time + min_mint: Option>, + min_block: Option>, ) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; - let mut ve_config = VeConfigs::::get(); + let mut bb_config = BbConfigs::::get(); if let Some(min_mint) = min_mint { - ve_config.min_mint = min_mint; + bb_config.min_mint = min_mint; }; if let Some(min_block) = min_block { - ve_config.min_block = min_block; + bb_config.min_block = min_block; }; - VeConfigs::::set(ve_config.clone()); + BbConfigs::::set(bb_config.clone()); - Self::deposit_event(Event::ConfigSet { config: ve_config }); + Self::deposit_event(Event::ConfigSet { config: bb_config }); Ok(()) } + /// Create a lock. + /// + /// If the signer already has a position, the position will not be extended. it will be + /// created a new position until the maximum number of positions is reached. + /// + /// - `value`: The amount of tokens to lock + /// - `unlock_time`: The lockup time #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::create_lock())] pub fn create_lock( @@ -377,6 +454,14 @@ pub mod pallet { Self::create_lock_inner(&exchanger, value, unlock_time) } + /// Increase the lock amount. + /// + /// If the signer does not have the position, it doesn't work and the position will not be + /// created. Only the position existed and owned by the signer, the locking amount will be + /// increased. + /// + /// - `position`: The lock position + /// - `value`: The amount of tokens to increase #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::increase_amount())] pub fn increase_amount( @@ -385,12 +470,19 @@ pub mod pallet { value: BalanceOf, ) -> DispatchResult { let exchanger = ensure_signed(origin)?; - // TODO: ensure postion is owned by exchanger let user_positions = UserPositions::::get(&exchanger); ensure!(user_positions.contains(&position), Error::::LockNotExist); Self::increase_amount_inner(&exchanger, position, value) } + /// Increase the unlock time. + /// + /// If the signer does not have the position, it doesn't work and the position will not be + /// created. Only the position existed and owned by the signer, the locking time will be + /// increased. + /// + /// - `position`: The lock position + /// - `time`: Additional lock time #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::increase_unlock_time())] pub fn increase_unlock_time( @@ -404,6 +496,9 @@ pub mod pallet { Self::increase_unlock_time_inner(&exchanger, position, time) } + /// Withdraw the locked tokens after unlock time. + /// + /// - `position`: The lock position #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::withdraw())] pub fn withdraw(origin: OriginFor, position: u128) -> DispatchResult { @@ -413,6 +508,16 @@ pub mod pallet { Self::withdraw_inner(&exchanger, position) } + /// Notify rewards. + /// + /// Set the incentive controller and rewards token type for future round. Reward duration + /// should be one round interval. It will notify the rewards from incentive controller to + /// the system account and start a new round immediately, and the next round will auto start + /// at now + rewards_duration. + /// + /// - `incentive_from`: The incentive controller + /// - `rewards_duration`: The rewards duration + /// - `rewards`: The rewards #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::notify_rewards())] pub fn notify_rewards( @@ -423,20 +528,26 @@ pub mod pallet { ) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; Self::set_incentive( - VE_MINTING_SYSTEM_POOL_ID, + BB_BNC_SYSTEM_POOL_ID, rewards_duration, Some(incentive_from.clone()), ); - Self::notify_reward_amount(VE_MINTING_SYSTEM_POOL_ID, &Some(incentive_from), rewards) + Self::notify_reward_amount(BB_BNC_SYSTEM_POOL_ID, &Some(incentive_from), rewards) } + /// Get rewards for the signer. #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::get_rewards())] pub fn get_rewards(origin: OriginFor) -> DispatchResult { let exchanger = ensure_signed(origin)?; - Self::get_rewards_inner(VE_MINTING_SYSTEM_POOL_ID, &exchanger, None) + Self::get_rewards_inner(BB_BNC_SYSTEM_POOL_ID, &exchanger, None) } + /// Fast unlocking, handling fee applies + /// + /// When users want to redeem early regardless of cost, they can use this call. + /// + /// - `position`: The lock position #[pallet::call_index(7)] #[pallet::weight(T::WeightInfo::redeem_unlock())] pub fn redeem_unlock(origin: OriginFor, position: u128) -> DispatchResult { @@ -444,22 +555,27 @@ pub mod pallet { Self::redeem_unlock_inner(&exchanger, position) } + /// Set markup configurations. + /// + /// - `currency_id`: The token type + /// - `markup`: The markup coefficient + /// - `hardcap`: The markup hardcap #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::set_markup_coefficient())] pub fn set_markup_coefficient( origin: OriginFor, - asset_id: CurrencyId, // token类型 - markup: FixedU128, // 单位token的加成系数 - hardcap: FixedU128, // token对应加成硬顶 + currency_id: CurrencyId, + markup: FixedU128, + hardcap: FixedU128, ) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; - if !TotalLock::::contains_key(asset_id) { - TotalLock::::insert(asset_id, BalanceOf::::zero()); + if !TotalLock::::contains_key(currency_id) { + TotalLock::::insert(currency_id, BalanceOf::::zero()); } let current_block_number: BlockNumberFor = frame_system::Pallet::::block_number(); MarkupCoefficient::::insert( - asset_id, + currency_id, MarkupCoefficientInfo { markup_coefficient: markup, hardcap, @@ -469,33 +585,56 @@ pub mod pallet { Ok(()) } + /// Deposit markup. + /// + /// Deposit the token to the system account for the markup. + /// + /// - `currency_id`: The token type + /// - `value`: The amount of tokens to deposit #[pallet::call_index(9)] #[pallet::weight(T::WeightInfo::deposit_markup())] pub fn deposit_markup( origin: OriginFor, - asset_id: CurrencyIdOf, + currency_id: CurrencyIdOf, value: BalanceOf, ) -> DispatchResult { - Self::deposit_markup_inner(origin, asset_id, value) + let exchanger = ensure_signed(origin)?; + Self::deposit_markup_inner(&exchanger, currency_id, value) } + /// Withdraw markup. + /// + /// Withdraw the token from the system account for the markup. + /// + /// - `currency_id`: The token type #[pallet::call_index(10)] #[pallet::weight(T::WeightInfo::withdraw_markup())] - pub fn withdraw_markup(origin: OriginFor, asset_id: CurrencyIdOf) -> DispatchResult { - Self::withdraw_markup_inner(origin, asset_id) + pub fn withdraw_markup( + origin: OriginFor, + currency_id: CurrencyIdOf, + ) -> DispatchResult { + let exchanger = ensure_signed(origin)?; + Self::withdraw_markup_inner(&exchanger, currency_id) } + /// Refresh the markup. + /// + /// Any user can call this function to refresh the markup coefficient. The maximum number of + /// accounts that can be refreshed in one execution is MarkupRefreshLimit. + /// + /// - `currency_id`: The token type #[pallet::call_index(11)] #[pallet::weight(T::WeightInfo::refresh())] - pub fn refresh(origin: OriginFor, asset_id: CurrencyIdOf) -> DispatchResult { - Self::refresh_inner(origin, asset_id) + pub fn refresh(origin: OriginFor, currency_id: CurrencyIdOf) -> DispatchResult { + let _exchanger = ensure_signed(origin)?; + Self::refresh_inner(currency_id) } } impl Pallet { pub fn _checkpoint( who: &AccountIdOf, - addr: u128, + position: u128, old_locked: LockedBalance, BlockNumberFor>, new_locked: LockedBalance, BlockNumberFor>, ) -> DispatchResult { @@ -652,21 +791,20 @@ pub mod pallet { } // Now handle user history - let user_epoch = UserPointEpoch::::get(addr) + let user_epoch = UserPointEpoch::::get(position) .checked_add(U256::one()) .ok_or(ArithmeticError::Overflow)?; - UserPointEpoch::::insert(addr, user_epoch); + UserPointEpoch::::insert(position, user_epoch); u_new.block = current_block_number; - // u_new.amount = Locked::::get(addr).amount; u_new.amount = new_locked.amount; - UserPointHistory::::insert(addr, user_epoch, u_new); + UserPointHistory::::insert(position, user_epoch, u_new); Ok(()) } pub fn _deposit_for( who: &AccountIdOf, - addr: u128, + position: u128, value: BalanceOf, unlock_time: BlockNumberFor, locked_balance: LockedBalance, BlockNumberFor>, @@ -674,14 +812,15 @@ pub mod pallet { let current_block_number: BlockNumberFor = frame_system::Pallet::::block_number(); let mut _locked = locked_balance; let supply_before = Supply::::get(); - Supply::::set(supply_before.checked_add(value).ok_or(ArithmeticError::Overflow)?); + let supply_after = supply_before.checked_add(value).ok_or(ArithmeticError::Overflow)?; + Supply::::set(supply_after); let old_locked = _locked.clone(); _locked.amount = _locked.amount.checked_add(value).ok_or(ArithmeticError::Overflow)?; if unlock_time != Zero::zero() { _locked.end = unlock_time } - Locked::::insert(addr, _locked.clone()); + Locked::::insert(position, _locked.clone()); let free_balance = T::MultiCurrency::free_balance(T::TokenType::get(), &who); if value != BalanceOf::::zero() { @@ -694,36 +833,35 @@ pub mod pallet { Self::markup_calc( who, - addr, + position, old_locked, _locked.clone(), UserMarkupInfos::::get(who).as_ref(), )?; Self::deposit_event(Event::Minted { - addr, + who: who.clone(), + position, value, + total_value: _locked.amount, end: _locked.end, now: current_block_number, }); - Self::deposit_event(Event::Supply { - supply_before, - supply: supply_before.checked_add(value).ok_or(ArithmeticError::Overflow)?, - }); + Self::deposit_event(Event::Supply { supply_before, supply: supply_after }); Ok(()) } - // Get the current voting power for `addr` + // Get the current voting power for `position` pub(crate) fn balance_of_position_current_block( - addr: u128, + position: u128, ) -> Result, DispatchError> { let current_block_number: BlockNumberFor = frame_system::Pallet::::block_number(); - let u_epoch = UserPointEpoch::::get(addr); + let u_epoch = UserPointEpoch::::get(position); if u_epoch == U256::zero() { return Ok(Zero::zero()); } else { let mut last_point: Point, BlockNumberFor> = - UserPointHistory::::get(addr, u_epoch); + UserPointHistory::::get(position, u_epoch); last_point.bias = last_point .bias @@ -749,9 +887,9 @@ pub mod pallet { } } - // Measure voting power of `addr` at block height `block` + // Measure voting power of `position` at block height `block` pub(crate) fn balance_of_position_at( - addr: u128, + position: u128, block: BlockNumberFor, ) -> Result, DispatchError> { let current_block_number: BlockNumberFor = frame_system::Pallet::::block_number(); @@ -759,7 +897,7 @@ pub mod pallet { // Binary search let mut _min = U256::zero(); - let mut _max = UserPointEpoch::::get(addr); + let mut _max = UserPointEpoch::::get(position); for _i in 0..128 { if _min >= _max { break; @@ -772,7 +910,7 @@ pub mod pallet { .checked_div(U256::from(2_u128)) .ok_or(ArithmeticError::Overflow)?; - if UserPointHistory::::get(addr, _mid).block <= block { + if UserPointHistory::::get(position, _mid).block <= block { _min = _mid } else { _max = _mid.checked_sub(U256::one()).ok_or(ArithmeticError::Overflow)? @@ -780,7 +918,7 @@ pub mod pallet { } let mut upoint: Point, BlockNumberFor> = - UserPointHistory::::get(addr, _min); + UserPointHistory::::get(position, _min); upoint.bias = upoint .bias .checked_sub( @@ -804,11 +942,11 @@ pub mod pallet { } pub(crate) fn balance_of_at( - addr: &AccountIdOf, + who: &AccountIdOf, block: BlockNumberFor, ) -> Result, DispatchError> { let mut balance = BalanceOf::::zero(); - UserPositions::::get(addr).into_iter().try_for_each( + UserPositions::::get(who).into_iter().try_for_each( |position| -> DispatchResult { balance = balance .checked_add(Self::balance_of_position_at(position, block)?) @@ -820,10 +958,10 @@ pub mod pallet { } pub(crate) fn balance_of_current_block( - addr: &AccountIdOf, + who: &AccountIdOf, ) -> Result, DispatchError> { let mut balance = BalanceOf::::zero(); - UserPositions::::get(addr).into_iter().try_for_each( + UserPositions::::get(who).into_iter().try_for_each( |position| -> DispatchResult { balance = balance .checked_add(Self::balance_of_position_current_block(position)?) @@ -835,7 +973,7 @@ pub mod pallet { } pub fn markup_calc( - addr: &AccountIdOf, + who: &AccountIdOf, position: u128, mut old_locked: LockedBalance, BlockNumberFor>, mut new_locked: LockedBalance, BlockNumberFor>, @@ -854,57 +992,59 @@ pub mod pallet { .ok_or(ArithmeticError::Overflow)?; } - Self::_checkpoint(addr, position, old_locked.clone(), new_locked.clone())?; + Self::_checkpoint(who, position, old_locked.clone(), new_locked.clone())?; Ok(()) } pub fn deposit_markup_inner( - origin: OriginFor, - asset_id: CurrencyIdOf, + who: &AccountIdOf, + currency_id: CurrencyIdOf, value: BalanceOf, ) -> DispatchResult { - let addr = ensure_signed(origin)?; let markup_coefficient = - MarkupCoefficient::::get(asset_id).ok_or(Error::::ArgumentsError)?; // Ensure it is the correct token type. + MarkupCoefficient::::get(currency_id).ok_or(Error::::ArgumentsError)?; // Ensure it is the correct token type. ensure!(!value.is_zero(), Error::::ArgumentsError); - TotalLock::::try_mutate(asset_id, |total_lock| -> DispatchResult { + TotalLock::::try_mutate(currency_id, |total_lock| -> DispatchResult { *total_lock = total_lock.checked_add(value).ok_or(ArithmeticError::Overflow)?; Ok(()) })?; let current_block_number: BlockNumberFor = frame_system::Pallet::::block_number(); - let mut user_markup_info = UserMarkupInfos::::get(&addr).unwrap_or_default(); - let mut locked_token = LockedTokens::::get(asset_id, &addr).unwrap_or(LockedToken { - amount: Zero::zero(), - markup_coefficient: Zero::zero(), - refresh_block: current_block_number, - }); + let mut user_markup_info = UserMarkupInfos::::get(&who).unwrap_or_default(); + let mut locked_token = + LockedTokens::::get(currency_id, &who).unwrap_or(LockedToken { + amount: Zero::zero(), + markup_coefficient: Zero::zero(), + refresh_block: current_block_number, + }); locked_token.amount = locked_token.amount.saturating_add(value); let left: FixedU128 = FixedU128::checked_from_integer(locked_token.amount) .and_then(|x| x.checked_mul(&markup_coefficient.markup_coefficient)) .and_then(|x| { - x.checked_div(&FixedU128::checked_from_integer(TotalLock::::get(asset_id))?) + x.checked_div(&FixedU128::checked_from_integer(TotalLock::::get( + currency_id, + ))?) }) .ok_or(ArithmeticError::Overflow)?; - let total_issuance = T::MultiCurrency::total_issuance(asset_id); + let total_issuance = T::MultiCurrency::total_issuance(currency_id); let right: FixedU128 = FixedU128::checked_from_integer(locked_token.amount) .and_then(|x| x.checked_mul(&markup_coefficient.markup_coefficient)) .and_then(|x| x.checked_div(&FixedU128::checked_from_integer(total_issuance)?)) .ok_or(ArithmeticError::Overflow)?; - let asset_id_markup_coefficient: FixedU128 = + let currency_id_markup_coefficient: FixedU128 = left.checked_add(&right).ok_or(ArithmeticError::Overflow)?; let new_markup_coefficient = - match markup_coefficient.hardcap.cmp(&asset_id_markup_coefficient) { + match markup_coefficient.hardcap.cmp(¤cy_id_markup_coefficient) { Ordering::Less => markup_coefficient.hardcap, - Ordering::Equal | Ordering::Greater => asset_id_markup_coefficient, + Ordering::Equal | Ordering::Greater => currency_id_markup_coefficient, }; Self::update_markup_info( - &addr, + &who, user_markup_info .markup_coefficient .saturating_sub(locked_token.markup_coefficient) @@ -914,15 +1054,15 @@ pub mod pallet { locked_token.markup_coefficient = new_markup_coefficient; locked_token.refresh_block = current_block_number; - T::MultiCurrency::set_lock(MARKUP_LOCK_ID, asset_id, &addr, locked_token.amount)?; - LockedTokens::::insert(&asset_id, &addr, locked_token); - UserPositions::::get(&addr).into_iter().try_for_each( + T::MultiCurrency::set_lock(MARKUP_LOCK_ID, currency_id, &who, locked_token.amount)?; + LockedTokens::::insert(¤cy_id, &who, locked_token); + UserPositions::::get(&who).into_iter().try_for_each( |position| -> DispatchResult { let _locked: LockedBalance, BlockNumberFor> = Locked::::get(position); ensure!(!_locked.amount.is_zero(), Error::::ArgumentsError); Self::markup_calc( - &addr, + &who, position, _locked.clone(), _locked, @@ -932,42 +1072,42 @@ pub mod pallet { )?; // Locked cannot be updated because it is markup, not a lock vBNC + Self::deposit_event(Event::MarkupDeposited { who: who.clone(), currency_id, value }); Ok(()) } pub fn withdraw_markup_inner( - origin: OriginFor, - asset_id: CurrencyIdOf, + who: &AccountIdOf, + currency_id: CurrencyIdOf, ) -> DispatchResult { - let addr = ensure_signed(origin)?; - let _ = MarkupCoefficient::::get(asset_id).ok_or(Error::::ArgumentsError)?; // Ensure it is the correct token type. + let _ = MarkupCoefficient::::get(currency_id).ok_or(Error::::ArgumentsError)?; // Ensure it is the correct token type. - let mut user_markup_info = UserMarkupInfos::::get(&addr).unwrap_or_default(); + let mut user_markup_info = UserMarkupInfos::::get(&who).unwrap_or_default(); let locked_token = - LockedTokens::::get(&asset_id, &addr).ok_or(Error::::LockNotExist)?; + LockedTokens::::get(¤cy_id, &who).ok_or(Error::::LockNotExist)?; Self::update_markup_info( - &addr, + &who, user_markup_info .markup_coefficient .saturating_sub(locked_token.markup_coefficient), &mut user_markup_info, ); - TotalLock::::try_mutate(asset_id, |total_lock| -> DispatchResult { + TotalLock::::try_mutate(currency_id, |total_lock| -> DispatchResult { *total_lock = total_lock.checked_sub(locked_token.amount).ok_or(ArithmeticError::Overflow)?; Ok(()) })?; - T::MultiCurrency::remove_lock(MARKUP_LOCK_ID, asset_id, &addr)?; + T::MultiCurrency::remove_lock(MARKUP_LOCK_ID, currency_id, &who)?; - LockedTokens::::remove(&asset_id, &addr); - UserPositions::::get(&addr).into_iter().try_for_each( + LockedTokens::::remove(¤cy_id, &who); + UserPositions::::get(&who).into_iter().try_for_each( |position| -> DispatchResult { let _locked: LockedBalance, BlockNumberFor> = Locked::::get(position); ensure!(!_locked.amount.is_zero(), Error::::ArgumentsError); // TODO Self::markup_calc( - &addr, + &who, position, _locked.clone(), _locked, @@ -975,21 +1115,21 @@ pub mod pallet { ) }, )?; + + Self::deposit_event(Event::MarkupWithdrawn { who: who.clone(), currency_id }); Ok(()) } - pub fn refresh_inner(origin: OriginFor, asset_id: CurrencyIdOf) -> DispatchResult { - let _who = ensure_signed(origin)?; - + pub fn refresh_inner(currency_id: CurrencyIdOf) -> DispatchResult { let markup_coefficient = - MarkupCoefficient::::get(asset_id).ok_or(Error::::ArgumentsError)?; + MarkupCoefficient::::get(currency_id).ok_or(Error::::ArgumentsError)?; let current_block_number: BlockNumberFor = frame_system::Pallet::::block_number(); let limit = T::MarkupRefreshLimit::get(); let mut all_refreshed = true; let mut refresh_count = 0; - let locked_tokens = LockedTokens::::iter_prefix(&asset_id); + let locked_tokens = LockedTokens::::iter_prefix(¤cy_id); - for (addr, mut locked_token) in locked_tokens { + for (who, mut locked_token) in locked_tokens { if refresh_count >= limit { all_refreshed = false; break; @@ -1002,31 +1142,31 @@ pub mod pallet { .and_then(|x| x.checked_mul(&markup_coefficient.markup_coefficient)) .and_then(|x| { x.checked_div(&FixedU128::checked_from_integer(TotalLock::::get( - asset_id, + currency_id, ))?) }) .ok_or(ArithmeticError::Overflow)?; - let total_issuance = T::MultiCurrency::total_issuance(asset_id); + let total_issuance = T::MultiCurrency::total_issuance(currency_id); let right: FixedU128 = FixedU128::checked_from_integer(locked_token.amount) .and_then(|x| x.checked_mul(&markup_coefficient.markup_coefficient)) .and_then(|x| { x.checked_div(&FixedU128::checked_from_integer(total_issuance)?) }) .ok_or(ArithmeticError::Overflow)?; - let asset_id_markup_coefficient: FixedU128 = + let currency_id_markup_coefficient: FixedU128 = left.checked_add(&right).ok_or(ArithmeticError::Overflow)?; let mut user_markup_info = - UserMarkupInfos::::get(&addr).ok_or(Error::::LockNotExist)?; + UserMarkupInfos::::get(&who).ok_or(Error::::LockNotExist)?; let new_markup_coefficient = - match markup_coefficient.hardcap.cmp(&asset_id_markup_coefficient) { + match markup_coefficient.hardcap.cmp(¤cy_id_markup_coefficient) { Ordering::Less => markup_coefficient.hardcap, - Ordering::Equal | Ordering::Greater => asset_id_markup_coefficient, + Ordering::Equal | Ordering::Greater => currency_id_markup_coefficient, }; Self::update_markup_info( - &addr, + &who, user_markup_info .markup_coefficient .saturating_sub(locked_token.markup_coefficient) @@ -1034,14 +1174,14 @@ pub mod pallet { &mut user_markup_info, ); locked_token.markup_coefficient = new_markup_coefficient; - LockedTokens::::insert(&asset_id, &addr, locked_token); - UserPositions::::get(&addr).into_iter().try_for_each( + LockedTokens::::insert(¤cy_id, &who, locked_token); + UserPositions::::get(&who).into_iter().try_for_each( |position| -> DispatchResult { let _locked: LockedBalance, BlockNumberFor> = Locked::::get(position); ensure!(!_locked.amount.is_zero(), Error::::ArgumentsError); // TODO Self::markup_calc( - &addr, + &who, position, _locked.clone(), _locked, @@ -1055,9 +1195,9 @@ pub mod pallet { } if all_refreshed { - Self::deposit_event(Event::AllRefreshed { asset_id }); + Self::deposit_event(Event::AllRefreshed { currency_id }); } else { - Self::deposit_event(Event::PartiallyRefreshed { asset_id }); + Self::deposit_event(Event::PartiallyRefreshed { currency_id }); } Ok(()) } @@ -1084,7 +1224,8 @@ pub mod pallet { Locked::::insert(position, _locked.clone()); let supply_before = Supply::::get(); - Supply::::set(supply_before.saturating_sub(value)); + let supply_after = supply_before.checked_sub(value).ok_or(ArithmeticError::Overflow)?; + Supply::::set(supply_after); // BNC should be transferred before checkpoint UserPositions::::mutate(who, |positions| { @@ -1107,11 +1248,8 @@ pub mod pallet { Self::_checkpoint(who, position, old_locked, _locked.clone())?; - Self::deposit_event(Event::Withdrawn { addr: position, value }); - Self::deposit_event(Event::Supply { - supply_before, - supply: supply_before.saturating_sub(value), - }); + Self::deposit_event(Event::Withdrawn { who: who.clone(), position, value }); + Self::deposit_event(Event::Supply { supply_before, supply: supply_after }); Ok(()) } @@ -1146,11 +1284,11 @@ pub mod pallet { match new_locked_balance { 0 => { // Can not set lock to zero, should remove it. - T::MultiCurrency::remove_lock(VE_LOCK_ID, T::TokenType::get(), who)?; + T::MultiCurrency::remove_lock(BB_LOCK_ID, T::TokenType::get(), who)?; }, _ => { T::MultiCurrency::set_lock( - VE_LOCK_ID, + BB_LOCK_ID, T::TokenType::get(), who, new_locked_balance, diff --git a/pallets/bb-bnc/src/tests.rs b/pallets/bb-bnc/src/tests.rs index 45a80b53f..2948290d3 100644 --- a/pallets/bb-bnc/src/tests.rs +++ b/pallets/bb-bnc/src/tests.rs @@ -196,7 +196,7 @@ fn update_reward() { assert_eq!(BbBNC::balance_of(&BOB, None), Ok(25407883680)); assert_eq!(BbBNC::balance_of_position_current_block(0), Ok(25407883680)); assert_ok!(BbBNC::deposit_for(&BOB, 0, 100_000_000_000)); - assert_ok!(BbBNC::update_reward(VE_MINTING_SYSTEM_POOL_ID, Some(&BOB), None)); // TODO + assert_ok!(BbBNC::update_reward(BB_BNC_SYSTEM_POOL_ID, Some(&BOB), None)); // TODO assert_eq!(BbBNC::balance_of(&BOB, None), Ok(50818438500)); assert_eq!(BbBNC::balance_of(&BOB, Some(System::block_number())), Ok(50818438500)); @@ -253,7 +253,7 @@ fn notify_reward_amount() { assert_ok!(BbBNC::get_rewards(RuntimeOrigin::signed(BOB))); assert_eq!(Tokens::free_balance(KSM, &BOB), 396819); System::set_block_number(System::block_number() + 7 * 86400 / 12); - assert_ok!(BbBNC::get_rewards_inner(VE_MINTING_SYSTEM_POOL_ID, &BOB, None)); + assert_ok!(BbBNC::get_rewards_inner(BB_BNC_SYSTEM_POOL_ID, &BOB, None)); assert_eq!(Tokens::free_balance(KSM, &BOB), 999986398); assert_ok!(BbBNC::notify_rewards( RuntimeOrigin::root(), @@ -267,14 +267,14 @@ fn notify_reward_amount() { (4 * 365 * 86400 - 7 * 86400) / 12 )); System::set_block_number(System::block_number() + 1 * 86400 / 12); - assert_ok!(BbBNC::get_rewards_inner(VE_MINTING_SYSTEM_POOL_ID, &BOB, None)); + assert_ok!(BbBNC::get_rewards_inner(BB_BNC_SYSTEM_POOL_ID, &BOB, None)); assert_eq!(Tokens::free_balance(KSM, &BOB), 1071241763); - assert_ok!(BbBNC::get_rewards_inner(VE_MINTING_SYSTEM_POOL_ID, &CHARLIE, None)); + assert_ok!(BbBNC::get_rewards_inner(BB_BNC_SYSTEM_POOL_ID, &CHARLIE, None)); assert_eq!(Tokens::free_balance(KSM, &CHARLIE), 71599834); System::set_block_number(System::block_number() + 7 * 86400 / 12); - assert_ok!(BbBNC::get_rewards_inner(VE_MINTING_SYSTEM_POOL_ID, &CHARLIE, None)); + assert_ok!(BbBNC::get_rewards_inner(BB_BNC_SYSTEM_POOL_ID, &CHARLIE, None)); assert_eq!(Tokens::free_balance(KSM, &CHARLIE), 501203849); - assert_ok!(BbBNC::get_rewards_inner(VE_MINTING_SYSTEM_POOL_ID, &BOB, None)); + assert_ok!(BbBNC::get_rewards_inner(BB_BNC_SYSTEM_POOL_ID, &BOB, None)); assert_eq!(Tokens::free_balance(KSM, &BOB), 1498768947); }); } @@ -780,7 +780,7 @@ fn refresh_should_work() { UserPointHistory::::get(POSITIONID0, U256::from(2)), Point { bias: 0, slope: 0, block: 0, amount: 0 } ); - assert_ok!(BbBNC::refresh_inner(RuntimeOrigin::signed(BOB), VBNC)); + assert_ok!(BbBNC::refresh_inner(VBNC)); assert_eq!( UserPointHistory::::get(POSITIONID0, U256::one()), Point { bias: 2796030953200, slope: 1046740, block: 20, amount: 11003333333333 } diff --git a/pallets/bb-bnc/src/traits.rs b/pallets/bb-bnc/src/traits.rs index 3c705aa0e..8f6ac48a0 100644 --- a/pallets/bb-bnc/src/traits.rs +++ b/pallets/bb-bnc/src/traits.rs @@ -24,7 +24,7 @@ use crate::*; pub trait BbBNCInterface { fn deposit_for(_who: &AccountId, position: u128, value: Balance) -> DispatchResult; fn withdraw_inner(who: &AccountId, position: u128) -> DispatchResult; - fn balance_of(addr: &AccountId, time: Option) -> Result; + fn balance_of(who: &AccountId, time: Option) -> Result; fn total_supply(t: BlockNumber) -> Result; fn supply_at( point: Point, @@ -35,13 +35,13 @@ pub trait BbBNCInterface { who: &AccountId, _value: Balance, _unlock_time: BlockNumber, - ) -> DispatchResult; // Deposit `_value` BNC for `addr` and lock until `_unlock_time` - fn increase_amount_inner(who: &AccountId, position: u128, value: Balance) -> DispatchResult; // Deposit `_value` additional BNC for `addr` without modifying the unlock time + ) -> DispatchResult; // Deposit `_value` BNC for `who` and lock until `_unlock_time` + fn increase_amount_inner(who: &AccountId, position: u128, value: Balance) -> DispatchResult; // Deposit `_value` additional BNC for `who` without modifying the unlock time fn increase_unlock_time_inner( who: &AccountId, position: u128, _unlock_time: BlockNumber, - ) -> DispatchResult; // Extend the unlock time for `addr` to `_unlock_time` + ) -> DispatchResult; // Extend the unlock time for `who` to `_unlock_time` fn auto_notify_reward( pool_id: PoolId, n: BlockNumber, @@ -49,12 +49,12 @@ pub trait BbBNCInterface { ) -> DispatchResult; fn update_reward( pool_id: PoolId, - addr: Option<&AccountId>, + who: Option<&AccountId>, share_info: Option<(Balance, Balance)>, ) -> DispatchResult; fn get_rewards( pool_id: PoolId, - addr: &AccountId, + who: &AccountId, share_info: Option<(Balance, Balance)>, ) -> DispatchResult; fn set_incentive( @@ -63,14 +63,14 @@ pub trait BbBNCInterface { controller: Option, ); fn add_reward( - addr: &AccountId, + who: &AccountId, conf: &mut IncentiveConfig, rewards: &Vec<(CurrencyId, Balance)>, remaining: Balance, ) -> DispatchResult; fn notify_reward( pool_id: PoolId, - addr: &Option, + who: &Option, rewards: Vec<(CurrencyId, Balance)>, ) -> DispatchResult; } @@ -91,8 +91,8 @@ impl BbBNCInterface, CurrencyIdOf, BalanceOf, Bl UserPositions::::insert(who, user_positions); Position::::set(new_position + 1); - let ve_config = VeConfigs::::get(); - ensure!(_value >= ve_config.min_mint, Error::::BelowMinimumMint); + let bb_config = BbConfigs::::get(); + ensure!(_value >= bb_config.min_mint, Error::::BelowMinimumMint); let current_block_number: BlockNumberFor = frame_system::Pallet::::block_number(); let _locked: LockedBalance, BlockNumberFor> = @@ -106,7 +106,7 @@ impl BbBNCInterface, CurrencyIdOf, BalanceOf, Bl .ok_or(ArithmeticError::Overflow)?; ensure!( - unlock_time >= ve_config.min_block.saturating_add(current_block_number), + unlock_time >= bb_config.min_block.saturating_add(current_block_number), Error::::ArgumentsError ); let max_block = T::MaxBlock::get() @@ -121,7 +121,8 @@ impl BbBNCInterface, CurrencyIdOf, BalanceOf, Bl Self::_deposit_for(who, new_position, _value, unlock_time, _locked)?; Self::deposit_event(Event::LockCreated { - addr: who.to_owned(), + who: who.to_owned(), + position: new_position, value: _value, unlock_time: _unlock_time, }); @@ -133,7 +134,7 @@ impl BbBNCInterface, CurrencyIdOf, BalanceOf, Bl position: u128, _unlock_time: BlockNumberFor, ) -> DispatchResult { - let ve_config = VeConfigs::::get(); + let bb_config = BbConfigs::::get(); let _locked: LockedBalance, BlockNumberFor> = Locked::::get(position); let current_block_number: BlockNumberFor = frame_system::Pallet::::block_number(); @@ -146,7 +147,7 @@ impl BbBNCInterface, CurrencyIdOf, BalanceOf, Bl .ok_or(ArithmeticError::Overflow)?; ensure!( - unlock_time >= ve_config.min_block.saturating_add(current_block_number), + unlock_time >= bb_config.min_block.saturating_add(current_block_number), Error::::ArgumentsError ); let max_block = T::MaxBlock::get() @@ -162,8 +163,9 @@ impl BbBNCInterface, CurrencyIdOf, BalanceOf, Bl Self::_deposit_for(who, position, BalanceOf::::zero(), unlock_time, _locked)?; Self::deposit_event(Event::UnlockTimeIncreased { - addr: position.to_owned(), - unlock_time: _unlock_time, + who: who.to_owned(), + position, + unlock_time, }); Ok(()) } @@ -173,8 +175,8 @@ impl BbBNCInterface, CurrencyIdOf, BalanceOf, Bl position: u128, value: BalanceOf, ) -> DispatchResult { - let ve_config = VeConfigs::::get(); - ensure!(value >= ve_config.min_mint, Error::::BelowMinimumMint); + let bb_config = BbConfigs::::get(); + ensure!(value >= bb_config.min_mint, Error::::BelowMinimumMint); let _locked: LockedBalance, BlockNumberFor> = Locked::::get(position); ensure!(_locked.amount > BalanceOf::::zero(), Error::::LockNotExist); // Need to be executed after create_lock let current_block_number: BlockNumberFor = frame_system::Pallet::::block_number(); @@ -197,12 +199,12 @@ impl BbBNCInterface, CurrencyIdOf, BalanceOf, Bl } fn balance_of( - addr: &AccountIdOf, + who: &AccountIdOf, time: Option>, ) -> Result, DispatchError> { match time { - Some(_t) => Self::balance_of_at(addr, _t), - None => Self::balance_of_current_block(addr), + Some(_t) => Self::balance_of_at(who, _t), + None => Self::balance_of_current_block(who), } } @@ -294,18 +296,18 @@ impl BbBNCInterface, CurrencyIdOf, BalanceOf, Bl fn update_reward( pool_id: PoolId, - addr: Option<&AccountIdOf>, + who: Option<&AccountIdOf>, share_info: Option<(BalanceOf, BalanceOf)>, ) -> DispatchResult { - Self::update_reward(pool_id, addr, share_info) + Self::update_reward(pool_id, who, share_info) } fn get_rewards( pool_id: PoolId, - addr: &AccountIdOf, + who: &AccountIdOf, share_info: Option<(BalanceOf, BalanceOf)>, ) -> DispatchResult { - Self::get_rewards_inner(pool_id, addr, share_info) + Self::get_rewards_inner(pool_id, who, share_info) } fn set_incentive( @@ -326,7 +328,7 @@ impl BbBNCInterface, CurrencyIdOf, BalanceOf, Bl } fn add_reward( - addr: &AccountIdOf, + who: &AccountIdOf, conf: &mut IncentiveConfig< CurrencyIdOf, BalanceOf, @@ -368,7 +370,7 @@ impl BbBNCInterface, CurrencyIdOf, BalanceOf, Bl .or_insert(new_reward); T::MultiCurrency::transfer( *currency, - addr, + who, &T::IncentivePalletId::get().into_account_truncating(), *reward, ) @@ -377,10 +379,10 @@ impl BbBNCInterface, CurrencyIdOf, BalanceOf, Bl fn notify_reward( pool_id: PoolId, - addr: &Option>, + who: &Option>, rewards: Vec<(CurrencyIdOf, BalanceOf)>, ) -> DispatchResult { - Self::notify_reward_amount(pool_id, addr, rewards) + Self::notify_reward_amount(pool_id, who, rewards) } } @@ -417,7 +419,7 @@ where Ok(()) } - fn balance_of(_addr: &AccountId, _time: Option) -> Result { + fn balance_of(_who: &AccountId, _time: Option) -> Result { Ok(Zero::zero()) } @@ -446,7 +448,7 @@ where fn update_reward( _pool_id: PoolId, - _addr: Option<&AccountId>, + _who: Option<&AccountId>, _share_info: Option<(Balance, Balance)>, ) -> DispatchResult { Ok(()) @@ -454,7 +456,7 @@ where fn get_rewards( _pool_id: PoolId, - _addr: &AccountId, + _who: &AccountId, _share_info: Option<(Balance, Balance)>, ) -> DispatchResult { Ok(()) @@ -467,7 +469,7 @@ where ) { } fn add_reward( - _addr: &AccountId, + _who: &AccountId, _conf: &mut IncentiveConfig, _rewards: &Vec<(CurrencyId, Balance)>, _remaining: Balance, @@ -476,7 +478,7 @@ where } fn notify_reward( _pool_id: PoolId, - _addr: &Option, + _who: &Option, _rewards: Vec<(CurrencyId, Balance)>, ) -> DispatchResult { Ok(()) @@ -492,7 +494,7 @@ pub struct UserMarkupInfo { #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, MaxEncodedLen, TypeInfo)] pub struct LockedToken { - // pub asset_id: CurrencyId, + // pub currency_id: CurrencyId, pub amount: Balance, pub markup_coefficient: FixedU128, pub refresh_block: BlockNumber, @@ -507,7 +509,7 @@ pub struct MarkupCoefficientInfo { pub trait MarkupInfo { fn update_markup_info( - addr: &AccountId, + who: &AccountId, new_markup_coefficient: FixedU128, user_markup_info: &mut UserMarkupInfo, ); @@ -515,12 +517,12 @@ pub trait MarkupInfo { impl MarkupInfo> for Pallet { fn update_markup_info( - addr: &AccountIdOf, + who: &AccountIdOf, new_markup_coefficient: FixedU128, user_markup_info: &mut UserMarkupInfo, ) { user_markup_info.old_markup_coefficient = user_markup_info.markup_coefficient; user_markup_info.markup_coefficient = new_markup_coefficient; - UserMarkupInfos::::insert(addr, user_markup_info); + UserMarkupInfos::::insert(who, user_markup_info); } } From 766e60fa47b1845c427fddf2acadea1ac9c0198a Mon Sep 17 00:00:00 2001 From: NingBo Wang <2536935847@qq.com> Date: Sun, 29 Sep 2024 15:17:11 +0800 Subject: [PATCH 08/30] Optimize slpx pallet (#1444) --- Cargo.lock | 2 + pallets/slpx/Cargo.toml | 17 +- pallets/slpx/src/benchmarking.rs | 30 +- pallets/slpx/src/lib.rs | 966 ++++++++++++--------- pallets/slpx/src/migration.rs | 2 +- pallets/slpx/src/mock.rs | 333 +------ pallets/slpx/src/tests.rs | 269 +++--- pallets/slpx/src/types.rs | 12 + runtime/bifrost-kusama/src/lib.rs | 4 +- runtime/bifrost-polkadot/src/lib.rs | 4 +- runtime/bifrost-polkadot/src/xcm_config.rs | 2 + 11 files changed, 765 insertions(+), 876 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8c990f909..dbf222895 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2014,9 +2014,11 @@ dependencies = [ "orml-xtokens", "pallet-balances", "pallet-collective", + "pallet-staking", "pallet-xcm", "parity-scale-codec", "polkadot-parachain-primitives", + "polkadot-primitives", "scale-info", "serde", "sp-core", diff --git a/pallets/slpx/Cargo.toml b/pallets/slpx/Cargo.toml index ba5ed8a6b..ff9bf3ee6 100644 --- a/pallets/slpx/Cargo.toml +++ b/pallets/slpx/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bifrost-slpx" description = "A pallet to manage the execution of XCM messages" -authors = ["hqwangningbo <2536935847@qq.com>"] +authors = ["Liebi Technologies "] edition = "2021" version = "0.8.0" @@ -29,7 +29,6 @@ tiny-keccak = { workspace = true } orml-traits = { workspace = true } orml-xtokens = { workspace = true } zenlink-protocol = { workspace = true } - bifrost-primitives = { workspace = true } bifrost-xcm-interface = { workspace = true } bifrost-asset-registry = { workspace = true } @@ -37,6 +36,11 @@ bifrost-stable-pool = { workspace = true } bifrost-stable-asset = { workspace = true } orml-tokens = { workspace = true } log = { workspace = true } +pallet-xcm = { workspace = true } +xcm-executor = { workspace = true } +xcm-builder = { workspace = true } +polkadot-primitives = { workspace = true } +pallet-staking = { workspace = true } [dev-dependencies] hex = { workspace = true } @@ -46,9 +50,6 @@ bifrost-vtoken-minting = { workspace = true } bifrost-slp = { workspace = true } cumulus-primitives-core = { workspace = true } bifrost-currencies = { workspace = true } -xcm-executor = { workspace = true } -xcm-builder = { workspace = true } -pallet-xcm = { workspace = true } xcm-simulator = { workspace = true } bifrost-runtime-common = { workspace = true } pallet-collective = { workspace = true } @@ -75,10 +76,15 @@ std = [ "cumulus-pallet-xcm/std", "sp-core/std", "sp-runtime/std", + "pallet-xcm/std", "bifrost-asset-registry/std", "bifrost-stable-pool/std", "bifrost-stable-asset/std", "log/std", + "xcm-executor/std", + "xcm-builder/std", + "polkadot-primitives/std", + "pallet-staking/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", @@ -87,6 +93,7 @@ runtime-benchmarks = [ "pallet-xcm/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "pallet-collective/runtime-benchmarks", + "pallet-staking/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] with-bifrost-polkadot-runtime = [] diff --git a/pallets/slpx/src/benchmarking.rs b/pallets/slpx/src/benchmarking.rs index 1b914af4d..2c77e7f99 100644 --- a/pallets/slpx/src/benchmarking.rs +++ b/pallets/slpx/src/benchmarking.rs @@ -19,21 +19,20 @@ use crate::*; use bifrost_asset_registry::CurrencyIdToLocations; -use bifrost_primitives::{CurrencyId, KSM, VKSM}; +use bifrost_primitives::{KSM, VKSM}; use frame_benchmarking::v2::*; use frame_support::{assert_ok, sp_runtime::traits::UniqueSaturatedFrom, BoundedVec}; use frame_system::RawOrigin; fn init_whitelist() -> (T::AccountId, H160) { let caller: T::AccountId = whitelisted_caller(); - assert_ok!(Pallet::::add_whitelist( - RawOrigin::Root.into(), + WhitelistAccountId::::insert( SupportChain::Astar, - caller.clone() - )); + BoundedVec::try_from(vec![caller.clone()]).unwrap(), + ); let addr: [u8; 20] = hex_literal::hex!["3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0"].into(); let receiver = H160::from(addr); - let evm_caller_account_id = Pallet::::h160_to_account_id(receiver); + let evm_caller_account_id = Pallet::::h160_to_account_id(&receiver); assert_ok!(::MultiCurrency::deposit( KSM, &evm_caller_account_id, @@ -52,29 +51,30 @@ fn init_whitelist() -> (T::AccountId (caller, receiver) } -#[benchmarks(where T: Config + bifrost_asset_registry::Config + bifrost_stable_pool::Config + bifrost_stable_asset::Config + orml_tokens::Config)] +#[benchmarks(where T: Config + bifrost_asset_registry::Config + orml_tokens::Config)] mod benchmarks { use super::*; + use hex_literal::hex; #[benchmark] fn add_whitelist() { - let contract: T::AccountId = whitelisted_caller(); + let addr: [u8; 20] = hex_literal::hex!["3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0"].into(); + let receiver = H160::from(addr); #[extrinsic_call] - _(RawOrigin::Root, SupportChain::Astar, contract.clone()); - - assert_eq!(WhitelistAccountId::::get(SupportChain::Astar).first(), Some(&contract)); + _(RawOrigin::Root, SupportChain::Astar, receiver); } #[benchmark] fn remove_whitelist() { - let contract: T::AccountId = whitelisted_caller(); - let whitelist = BoundedVec::try_from(vec![contract.clone()]).unwrap(); + let address: [u8; 20] = hex!["c6bf0C5C78686f1D0E2E54b97D6de6e2cEFAe9fD"]; + let address = H160::from_slice(&address); - WhitelistAccountId::::insert(SupportChain::Astar, whitelist); + let _ = + crate::Pallet::::add_whitelist(RawOrigin::Root.into(), SupportChain::Astar, address); #[extrinsic_call] - _(RawOrigin::Root, SupportChain::Astar, contract.clone()); + _(RawOrigin::Root, SupportChain::Astar, address); assert_eq!(WhitelistAccountId::::get(SupportChain::Astar).first(), None); } diff --git a/pallets/slpx/src/lib.rs b/pallets/slpx/src/lib.rs index 37da11083..a51e96c89 100644 --- a/pallets/slpx/src/lib.rs +++ b/pallets/slpx/src/lib.rs @@ -24,9 +24,10 @@ use crate::types::{ }; use bifrost_asset_registry::AssetMetadata; use bifrost_primitives::{ - currency::{BNC, VFIL}, - AstarChainId, CurrencyId, CurrencyIdMapping, HydrationChainId, InterlayChainId, MantaChainId, - RedeemType, SlpxOperator, TokenInfo, VtokenMintingInterface, + currency::{BNC, MOVR, VFIL}, + AstarChainId, Balance, BifrostKusamaChainId, CurrencyId, CurrencyIdMapping, HydrationChainId, + InterlayChainId, MantaChainId, RedeemType, SlpxOperator, TokenInfo, VtokenMintingInterface, + GLMR, }; use cumulus_primitives_core::ParaId; use ethereum::TransactionAction; @@ -53,7 +54,8 @@ use sp_runtime::{ }; use sp_std::{vec, vec::Vec}; use xcm::v4::{prelude::*, Location}; -use zenlink_protocol::AssetBalance; +use xcm_builder::{DescribeAllTerminal, DescribeFamily, HashedDescription}; +use xcm_executor::traits::ConvertLocation; pub mod migration; pub mod types; @@ -73,15 +75,12 @@ mod benchmarking; #[frame_support::pallet] pub mod pallet { use super::*; - use crate::types::{Order, OrderType}; - use bifrost_primitives::{currency::MOVR, BifrostKusamaChainId, GLMR}; - use bifrost_stable_pool::{traits::StablePoolHandler, PoolTokenIndex, StableAssetPoolId}; + use crate::types::Order; use frame_support::{ pallet_prelude::{ValueQuery, *}, weights::WeightMeter, }; use frame_system::ensure_root; - use zenlink_protocol::{AssetId, ExportZenlink}; const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); @@ -92,11 +91,13 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type RuntimeOrigin: From + + From<::RuntimeOrigin> + + Into::RuntimeOrigin>>; + type WeightInfo: WeightInfo; type ControlOrigin: EnsureOrigin<::RuntimeOrigin>; type MultiCurrency: MultiCurrency, CurrencyId = CurrencyId>; - type DexOperator: ExportZenlink; - /// The interface to call VtokenMinting module functions. type VtokenMintingInterface: VtokenMintingInterface< AccountIdOf, @@ -104,163 +105,152 @@ pub mod pallet { BalanceOf, >; - /// The interface to call StablePool module functions. - type StablePoolHandler: StablePoolHandler< - Balance = BalanceOf, - AccountId = AccountIdOf, - CurrencyId = CurrencyIdOf, - >; - /// xtokens xcm transfer interface type XcmTransfer: XcmTransfer, BalanceOf, CurrencyIdOf>; - - /// + /// Send Xcm type XcmSender: SendXcm; - /// Convert Location to `T::CurrencyId`. type CurrencyIdConvert: CurrencyIdMapping< CurrencyId, xcm::v3::MultiLocation, AssetMetadata>, >; - /// TreasuryAccount #[pallet::constant] type TreasuryAccount: Get>; - + /// ParaId of the parachain #[pallet::constant] type ParachainId: Get; - - type WeightInfo: WeightInfo; + /// The maximum number of order is 500 + #[pallet::constant] + type MaxOrderSize: Get; } #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { + /// Add the contract account to the whitelist AddWhitelistAccountId { + /// The support chain of Slpx support_chain: SupportChain, + /// The contract address of the contract + contract_address: H160, + /// Xcm derivative account id evm_contract_account_id: AccountIdOf, }, + /// Remove the contract account from the whitelist RemoveWhitelistAccountId { + /// The support chain of Slpx support_chain: SupportChain, + /// The contract address of the contract + contract_address: H160, + /// Xcm derivative account id evm_contract_account_id: AccountIdOf, }, - XcmMint { - evm_caller: H160, - currency_id: CurrencyIdOf, - token_amount: BalanceOf, - target_chain: TargetChain>, - }, - XcmMintFailed { - evm_caller: H160, - currency_id: CurrencyIdOf, - token_amount: BalanceOf, - target_chain: TargetChain>, - }, - XcmZenlinkSwap { - evm_caller: H160, - currency_id_in: CurrencyIdOf, - currency_id_out: CurrencyIdOf, - currency_id_out_amount: BalanceOf, - target_chain: TargetChain>, - }, - XcmZenlinkSwapFailed { - evm_caller: H160, - currency_id_in: CurrencyIdOf, - currency_id_out: CurrencyIdOf, - currency_id_in_amount: BalanceOf, - target_chain: TargetChain>, - }, - XcmStablePoolSwap { - evm_caller: H160, - pool_token_index_in: PoolTokenIndex, - pool_token_index_out: PoolTokenIndex, - currency_id_out_amount: BalanceOf, - target_chain: TargetChain>, - }, - XcmStablePoolSwapFailed { - evm_caller: H160, - pool_token_index_in: PoolTokenIndex, - pool_token_index_out: PoolTokenIndex, - currency_id_in_amount: BalanceOf, - target_chain: TargetChain>, - }, - XcmRedeem { - evm_caller: H160, - vtoken_id: CurrencyIdOf, - vtoken_amount: BalanceOf, - target_chain: TargetChain>, - }, - XcmRedeemFailed { - evm_caller: H160, - vtoken_id: CurrencyIdOf, - vtoken_amount: BalanceOf, - target_chain: TargetChain>, - }, + /// Set the transfer fee for the currency, only for Moonbeam SetTransferToFee { + /// The support chain of Slpx support_chain: SupportChain, + /// The transfer fee of the token transfer_to_fee: BalanceOf, }, + /// Set the execution fee for the order SetExecutionFee { + /// The currency id of the token currency_id: CurrencyId, + /// The execution fee of the order execution_fee: BalanceOf, }, - SetCurrencyEthereumCallSwitch { + /// Support currency to xcm oracle + SupportXcmOracle { + /// The currency id of the token currency_id: CurrencyId, + /// Whether to support the xcm oracle is_support: bool, }, - SetEthereumCallConfiguration { - xcm_fee: u128, + /// Set the xcm oracle configuration + SetXcmOracleConfiguration { + /// The XCM fee of Sending Xcm + xcm_fee: Balance, + /// The XCM weight of Sending Xcm xcm_weight: Weight, + /// The period of Sending Xcm period: BlockNumberFor, + /// The address of XcmOracle contract: H160, }, - XcmSetTokenAmount { + /// Send Xcm message + XcmOracle { + /// The currency id of the token currency_id: CurrencyId, - token_amount: BalanceOf, - vcurrency_id: CurrencyId, - vtoken_amount: BalanceOf, + /// The currency amount of staking + staking_currency_amount: BalanceOf, + /// The currency id of the vtoken + v_currency_id: CurrencyId, + /// The currency total supply of vtoken + v_currency_total_supply: BalanceOf, }, + /// Set the currency to support the XCM fee SetCurrencyToSupportXcmFee { + /// The currency id of the token currency_id: CurrencyId, + /// Whether to support the XCM fee is_support: bool, }, + /// Set the delay block SetDelayBlock { + /// The delay block delay_block: BlockNumberFor, }, + /// Create order CreateOrder { order: Order, CurrencyIdOf, BalanceOf, BlockNumberFor>, }, + /// Order handled OrderHandled { order: Order, CurrencyIdOf, BalanceOf, BlockNumberFor>, }, + /// Order failed OrderFailed { order: Order, CurrencyIdOf, BalanceOf, BlockNumberFor>, }, + /// Xcm oracle failed + XcmOracleFailed { error: DispatchError }, + /// Withdraw xcm fee InsufficientAssets, } #[pallet::error] + #[derive(Clone, PartialEq)] pub enum Error { - /// Token not found in vtoken minting - TokenNotFoundInVtokenMinting, - /// Token not found in zenlink - TokenNotFoundInZenlink, /// Contract Account already exists in the whitelist - AccountIdAlreadyInWhitelist, + AccountAlreadyExists, + /// Currency already exists in the whitelist + CurrencyAlreadyExists, /// Contract Account is not in the whitelist - AccountIdNotInWhitelist, + AccountNotFound, + /// Currency is not in the whitelist + CurrencyNotFound, /// The maximum number of whitelist addresses is 10 - ExceededWhitelistMaxNumber, + WhitelistOverflow, /// Execution fee not set NotSetExecutionFee, /// Insufficient balance to execute the fee FreeBalanceTooLow, - /// ArgumentsError - ArgumentsError, + /// The maximum number of order is 500 + OrderQueueOverflow, + /// The maximum number of currency id is 10 + CurrencyListOverflow, + /// Convert vtoken error ErrorConvertVtoken, + /// Error encode + ErrorEncode, ErrorValidating, ErrorDelivering, + ErrorVtokenMiting, + ErrorTransferTo, + ErrorChargeFee, + ErrorArguments, Unsupported, } @@ -284,28 +274,33 @@ pub mod pallet { pub type TransferToFee = StorageMap<_, Blake2_128Concat, SupportChain, BalanceOf, OptionQuery>; + /// Xcm Oracle configuration #[pallet::storage] pub type XcmEthereumCallConfiguration = StorageValue<_, EthereumCallConfiguration>>; + /// Currency to support xcm oracle #[pallet::storage] pub type CurrencyIdList = StorageValue<_, BoundedVec>, ValueQuery>; + /// Currency to support xcm fee #[pallet::storage] pub type SupportXcmFeeList = StorageValue<_, BoundedVec>, ValueQuery>; + /// Order queue #[pallet::storage] pub type OrderQueue = StorageValue< _, BoundedVec< Order, CurrencyIdOf, BalanceOf, BlockNumberFor>, - ConstU32<1000>, + T::MaxOrderSize, >, ValueQuery, >; + /// Delay block #[pallet::storage] pub type DelayBlock = StorageValue<_, BlockNumberFor, ValueQuery>; @@ -315,7 +310,7 @@ pub mod pallet { let mut weight = Weight::default(); if WeightMeter::with_limit(limit) - .try_consume(T::DbWeight::get().reads_writes(4, 2)) + .try_consume(T::DbWeight::get().reads_writes(14, 8)) .is_err() { return weight; @@ -323,105 +318,12 @@ pub mod pallet { let mut is_handle_xcm_oracle = false; - let mut currency_list = CurrencyIdList::::get().to_vec(); - if currency_list.len() < 1 { - weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 0)); - } else { - let configuration = XcmEthereumCallConfiguration::::get(); - match configuration { - Some(mut configuration) => { - let currency_id = currency_list[0]; - let token_amount = T::VtokenMintingInterface::get_token_pool(currency_id); - // It's impossible to go wrong. - let vcurrency_id = T::VtokenMintingInterface::vtoken_id(currency_id) - .expect("Error convert vcurrency_id"); - let vtoken_amount = T::MultiCurrency::total_issuance(vcurrency_id); - - if configuration.last_block + configuration.period < n { - let encoded_call = Self::encode_transact_call( - configuration.contract, - currency_id, - token_amount, - vtoken_amount, - ); - - let result = Self::send_xcm_to_set_token_amount( - encoded_call, - configuration.xcm_weight, - configuration.xcm_fee, - ); - - if result.is_err() { - return weight - .saturating_add(T::DbWeight::get().reads_writes(4, 0)); - } - Self::deposit_event(Event::XcmSetTokenAmount { - currency_id, - token_amount, - vcurrency_id, - vtoken_amount, - }); - - let mut target_fee_currency_id = GLMR; - if T::ParachainId::get() == Id::from(BifrostKusamaChainId::get()) { - target_fee_currency_id = MOVR; - } - - // Will not check results and will be sent regardless of the success of - // the burning - let result = T::MultiCurrency::withdraw( - target_fee_currency_id, - &T::TreasuryAccount::get(), - BalanceOf::::unique_saturated_from(configuration.xcm_fee), - ); - if result.is_err() { - Self::deposit_event(Event::InsufficientAssets); - } - - configuration.last_block = n; - XcmEthereumCallConfiguration::::put(configuration); - currency_list.rotate_left(1); - CurrencyIdList::::put(BoundedVec::try_from(currency_list).unwrap()); - - weight = weight.saturating_add(T::DbWeight::get().reads_writes(4, 2)); - - is_handle_xcm_oracle = true; - } - }, - None => { - weight = weight.saturating_add(T::DbWeight::get().reads_writes(2, 0)); - }, - }; + if let Err(error) = Self::handle_xcm_oracle(n, &mut is_handle_xcm_oracle, &mut weight) { + Self::deposit_event(Event::::XcmOracleFailed { error }); } if !is_handle_xcm_oracle { - OrderQueue::::mutate(|order_queue| -> DispatchResult { - if let Some(order) = order_queue.get(0) { - if n - order.create_block_number >= DelayBlock::::get() { - let mut order = order_queue.remove(0); - let balance = T::MultiCurrency::free_balance( - order.currency_id, - &order.derivative_account, - ); - if balance > T::MultiCurrency::minimum_balance(order.currency_id) { - order.currency_amount = balance; - Self::handle_order(&order) - .map_err(|_| Error::::ArgumentsError)?; - Self::deposit_event(Event::::OrderHandled { - order: order.clone(), - }); - weight = - weight.saturating_add(T::DbWeight::get().reads_writes(14, 8)); - } else { - Self::deposit_event(Event::::OrderFailed { order }); - weight = - weight.saturating_add(T::DbWeight::get().reads_writes(4, 1)); - } - }; - }; - Ok(()) - }) - .ok(); + let _ = Self::handle_order_queue(n, &mut weight); } weight } @@ -430,6 +332,11 @@ pub mod pallet { #[pallet::call] impl Pallet { /// vtoken mint and transfer to target chain + /// Parameters: + /// - `evm_caller`: The caller of the EVM contract + /// - `currency_id`: The currency id of the token to be minted + /// - `target_chain`: The target chain to transfer the token to + /// - `remark`: The remark of the order #[pallet::call_index(0)] #[pallet::weight(::WeightInfo::mint())] pub fn mint( @@ -439,47 +346,26 @@ pub mod pallet { target_chain: TargetChain>, remark: BoundedVec>, ) -> DispatchResultWithPostInfo { - let (source_chain_caller, derivative_account, bifrost_chain_caller) = + let (source_chain_caller, _, bifrost_chain_caller) = Self::ensure_singer_on_whitelist(origin.clone(), evm_caller, &target_chain)?; - let order = Order { - create_block_number: >::block_number(), - order_type: OrderType::Mint, - currency_amount: Default::default(), + Self::do_create_order( source_chain_caller, bifrost_chain_caller, - derivative_account, currency_id, + Default::default(), remark, + 0u32, target_chain, - // default to 0 - channel_id: 0u32, - }; - - OrderQueue::::mutate(|order_queue| -> DispatchResultWithPostInfo { - order_queue.try_push(order.clone()).map_err(|_| Error::::ArgumentsError)?; - Self::deposit_event(Event::::CreateOrder { order }); - Ok(().into()) - }) - } - - /// Swap and transfer to target chain - #[pallet::call_index(1)] - #[pallet::weight(::WeightInfo::zenlink_swap())] - pub fn zenlink_swap( - origin: OriginFor, - _evm_caller: H160, - _currency_id_in: CurrencyIdOf, - _currency_id_out: CurrencyIdOf, - _currency_id_out_min: AssetBalance, - _target_chain: TargetChain>, - ) -> DispatchResultWithPostInfo { - ensure_signed(origin)?; - ensure!(false, Error::::Unsupported); - Ok(().into()) + ) } - /// Redeem + /// vtoken redeem and transfer to target chain + /// Parameters: + /// - `evm_caller`: The caller of the EVM contract + /// - `vtoken_id`: The currency id of the vtoken to be redeemed + /// - `target_chain`: The target chain to transfer the token to + /// - `remark`: The remark of the order #[pallet::call_index(2)] #[pallet::weight(::WeightInfo::redeem())] pub fn redeem( @@ -489,110 +375,96 @@ pub mod pallet { target_chain: TargetChain>, ) -> DispatchResultWithPostInfo { let evm_contract_account_id = ensure_signed(origin.clone())?; - let (source_chain_caller, derivative_account, bifrost_chain_caller) = + let (source_chain_caller, frontier_derivative_account, bifrost_chain_caller) = Self::ensure_singer_on_whitelist(origin, evm_caller, &target_chain)?; if vtoken_id == VFIL { - let fee_amount = TransferToFee::::get(SupportChain::Moonbeam) - .unwrap_or_else(|| Self::get_default_fee(BNC)); + let fee_amount = Self::get_moonbeam_transfer_to_fee(); T::MultiCurrency::transfer( BNC, &evm_contract_account_id, - &derivative_account, + &frontier_derivative_account, fee_amount, )?; } - let order = Order { - create_block_number: >::block_number(), - order_type: OrderType::Redeem, - currency_id: vtoken_id, - currency_amount: Default::default(), - remark: Default::default(), + Self::do_create_order( source_chain_caller, bifrost_chain_caller, - derivative_account, + vtoken_id, + Default::default(), + Default::default(), + 0u32, target_chain, - // default to 0 - channel_id: 0u32, - }; - - OrderQueue::::mutate(|order_queue| -> DispatchResultWithPostInfo { - order_queue.try_push(order.clone()).map_err(|_| Error::::ArgumentsError)?; - Self::deposit_event(Event::::CreateOrder { order }); - Ok(().into()) - }) - } - - /// Stable pool swap - #[pallet::call_index(3)] - #[pallet::weight(::WeightInfo::stable_pool_swap())] - pub fn stable_pool_swap( - origin: OriginFor, - _evm_caller: H160, - _pool_id: StableAssetPoolId, - _currency_id_in: CurrencyIdOf, - _currency_id_out: CurrencyIdOf, - _min_dy: BalanceOf, - _target_chain: TargetChain>, - ) -> DispatchResult { - ensure_signed(origin)?; - ensure!(false, Error::::Unsupported); - Ok(()) + ) } + /// Add the contract account to the whitelist + /// Parameters: + /// - `support_chain`: The support chain of Slpx + /// - `contract_address`: The contract address of the contract #[pallet::call_index(4)] #[pallet::weight(::WeightInfo::add_whitelist())] pub fn add_whitelist( origin: OriginFor, support_chain: SupportChain, - evm_contract_account_id: T::AccountId, + contract_address: H160, ) -> DispatchResultWithPostInfo { // Check the validity of origin T::ControlOrigin::ensure_origin(origin)?; - let mut whitelist_account_ids = WhitelistAccountId::::get(&support_chain); - - ensure!( - !whitelist_account_ids.contains(&evm_contract_account_id), - Error::::AccountIdAlreadyInWhitelist - ); - whitelist_account_ids - .try_push(evm_contract_account_id.clone()) - .map_err(|_| Error::::ExceededWhitelistMaxNumber)?; - WhitelistAccountId::::insert(support_chain, whitelist_account_ids); - Self::deposit_event(Event::AddWhitelistAccountId { + WhitelistAccountId::::mutate( support_chain, - evm_contract_account_id, - }); - Ok(().into()) + |whitelist| -> DispatchResultWithPostInfo { + let account = Self::xcm_derivative_account(support_chain, contract_address)?; + ensure!(!whitelist.contains(&account), Error::::AccountAlreadyExists); + whitelist + .try_push(account.clone()) + .map_err(|_| Error::::WhitelistOverflow)?; + Self::deposit_event(Event::::AddWhitelistAccountId { + support_chain, + contract_address, + evm_contract_account_id: account, + }); + Ok(().into()) + }, + ) } + /// Remove the contract account from the whitelist + /// Parameters: + /// - `support_chain`: The support chain of Slpx + /// - `contract_address`: The contract address of the contract #[pallet::call_index(5)] #[pallet::weight(::WeightInfo::remove_whitelist())] pub fn remove_whitelist( origin: OriginFor, support_chain: SupportChain, - evm_contract_account_id: T::AccountId, + contract_address: H160, ) -> DispatchResultWithPostInfo { // Check the validity of origin T::ControlOrigin::ensure_origin(origin)?; - let mut whitelist_account_ids = WhitelistAccountId::::get(&support_chain); - - ensure!( - whitelist_account_ids.contains(&evm_contract_account_id), - Error::::AccountIdNotInWhitelist - ); - whitelist_account_ids.retain(|x| *x != evm_contract_account_id); - WhitelistAccountId::::insert(support_chain, whitelist_account_ids); - Self::deposit_event(Event::RemoveWhitelistAccountId { + WhitelistAccountId::::mutate( support_chain, - evm_contract_account_id, - }); - Ok(().into()) + |whitelist| -> DispatchResultWithPostInfo { + let account = Self::xcm_derivative_account(support_chain, contract_address)?; + ensure!(whitelist.contains(&account), Error::::AccountNotFound); + whitelist.retain(|x| *x != account); + Self::deposit_event(Event::::RemoveWhitelistAccountId { + support_chain, + contract_address, + evm_contract_account_id: account, + }); + Ok(().into()) + }, + ) } + /// Set the execution fee for the currency + /// Parameters: + /// - `currency_id`: The currency id of the token + /// - `execution_fee`: The execution fee of the token #[pallet::call_index(6)] #[pallet::weight(::WeightInfo::set_execution_fee())] pub fn set_execution_fee( @@ -607,6 +479,10 @@ pub mod pallet { Ok(().into()) } + /// Set the transfer fee for the currency + /// Parameters: + /// - `support_chain`: The support chain of Slpx + /// - `transfer_to_fee`: The transfer fee of the token #[pallet::call_index(7)] #[pallet::weight(::WeightInfo::set_transfer_to_fee())] pub fn set_transfer_to_fee( @@ -621,9 +497,13 @@ pub mod pallet { Ok(().into()) } + /// Set the currency to support the Ethereum call switch + /// Parameters: + /// - `currency_id`: The currency id of the token + /// - `is_support`: Whether to support the Ethereum call switch #[pallet::call_index(8)] #[pallet::weight(::WeightInfo::set_transfer_to_fee())] - pub fn set_currency_ethereum_call_switch( + pub fn support_xcm_oracle( origin: OriginFor, currency_id: CurrencyId, is_support: bool, @@ -634,28 +514,31 @@ pub mod pallet { T::VtokenMintingInterface::vtoken_id(currency_id) .ok_or(Error::::ErrorConvertVtoken)?; let mut currency_list = CurrencyIdList::::get(); - match is_support { - true => { - ensure!(!currency_list.contains(¤cy_id), Error::::ArgumentsError); - currency_list - .try_push(currency_id) - .map_err(|_| Error::::ExceededWhitelistMaxNumber)?; - }, - false => { - ensure!(currency_list.contains(¤cy_id), Error::::ArgumentsError); - currency_list.retain(|&x| x != currency_id); - }, - }; + if is_support { + ensure!(!currency_list.contains(¤cy_id), Error::::CurrencyAlreadyExists); + currency_list + .try_push(currency_id) + .map_err(|_| Error::::CurrencyListOverflow)?; + } else { + ensure!(currency_list.contains(¤cy_id), Error::::CurrencyNotFound); + currency_list.retain(|&x| x != currency_id); + } CurrencyIdList::::put(currency_list); - Self::deposit_event(Event::SetCurrencyEthereumCallSwitch { currency_id, is_support }); + Self::deposit_event(Event::SupportXcmOracle { currency_id, is_support }); Ok(().into()) } + /// Set the Ethereum call configuration + /// Parameters: + /// - `xcm_fee`: The XCM fee of Sending Xcm + /// - `xcm_weight`: The XCM weight of Sending Xcm + /// - `period`: The period of Sending Xcm + /// - `contract`: The address of XcmOracle #[pallet::call_index(9)] #[pallet::weight(::WeightInfo::set_transfer_to_fee())] - pub fn set_ethereum_call_configration( + pub fn set_xcm_oracle_configuration( origin: OriginFor, - xcm_fee: u128, + xcm_fee: Balance, xcm_weight: Weight, period: BlockNumberFor, contract: H160, @@ -668,7 +551,7 @@ pub mod pallet { last_block: frame_system::Pallet::::block_number(), contract, }); - Self::deposit_event(Event::SetEthereumCallConfiguration { + Self::deposit_event(Event::SetXcmOracleConfiguration { xcm_fee, xcm_weight, period, @@ -677,6 +560,10 @@ pub mod pallet { Ok(().into()) } + /// Set the currency to support the XCM fee + /// Parameters: + /// - `currency_id`: The currency id of the token + /// - `is_support`: Whether to support the XCM fee #[pallet::call_index(10)] #[pallet::weight(T::DbWeight::get().reads(1) + T::DbWeight::get().writes(1))] pub fn set_currency_support_xcm_fee( @@ -688,21 +575,23 @@ pub mod pallet { T::ControlOrigin::ensure_origin(origin)?; let mut currency_list = SupportXcmFeeList::::get(); - match is_support { - true => { - ensure!(!currency_list.contains(¤cy_id), Error::::ArgumentsError); - currency_list.try_push(currency_id).map_err(|_| Error::::ArgumentsError)?; - }, - false => { - ensure!(currency_list.contains(¤cy_id), Error::::ArgumentsError); - currency_list.retain(|&x| x != currency_id); - }, - }; + if is_support { + ensure!(!currency_list.contains(¤cy_id), Error::::CurrencyAlreadyExists); + currency_list + .try_push(currency_id) + .map_err(|_| Error::::CurrencyListOverflow)?; + } else { + ensure!(currency_list.contains(¤cy_id), Error::::CurrencyNotFound); + currency_list.retain(|&x| x != currency_id); + } SupportXcmFeeList::::put(currency_list); Self::deposit_event(Event::SetCurrencyToSupportXcmFee { currency_id, is_support }); Ok(().into()) } + /// Set the delay block, Order will be executed after the delay block. + /// Parameters: + /// - `delay_block`: The delay block #[pallet::call_index(11)] #[pallet::weight(T::DbWeight::get().reads(1) + T::DbWeight::get().writes(1))] pub fn set_delay_block( @@ -716,39 +605,44 @@ pub mod pallet { Ok(().into()) } + /// Force add order + /// Parameters: + /// - `source_chain_caller`: The caller of the source chain + /// - `bifrost_chain_caller`: The caller of the bifrost chain + /// - `currency_id`: The currency id of the token + /// - `target_chain`: The target chain to transfer the token to + /// - `remark`: The remark of the order + /// - `channel_id`: The channel id of the order #[pallet::call_index(12)] #[pallet::weight(T::DbWeight::get().reads(1) + T::DbWeight::get().writes(1))] pub fn force_add_order( origin: OriginFor, - slpx_contract_derivative_account: AccountIdOf, - evm_caller: H160, + source_chain_caller: OrderCaller, + bifrost_chain_caller: T::AccountId, currency_id: CurrencyIdOf, target_chain: TargetChain>, remark: BoundedVec>, - order_type: OrderType, + channel_id: u32, ) -> DispatchResultWithPostInfo { ensure_root(origin)?; - let order = Order { - create_block_number: >::block_number(), - currency_amount: Default::default(), - source_chain_caller: OrderCaller::Evm(evm_caller), - bifrost_chain_caller: slpx_contract_derivative_account, - derivative_account: Self::h160_to_account_id(evm_caller), - order_type, + Self::do_create_order( + source_chain_caller, + bifrost_chain_caller, currency_id, + Default::default(), remark, + channel_id, target_chain, - // default to 0 - channel_id: 0u32, - }; - - OrderQueue::::mutate(|order_queue| -> DispatchResultWithPostInfo { - order_queue.try_push(order.clone()).map_err(|_| Error::::ArgumentsError)?; - Self::deposit_event(Event::::CreateOrder { order }); - Ok(().into()) - }) + ) } + /// vtoken mint and transfer to target chain + /// Parameters: + /// - `evm_caller`: The caller of the EVM contract + /// - `currency_id`: The currency id of the token to be minted + /// - `target_chain`: The target chain to transfer the token to + /// - `remark`: The remark of the order + /// - `channel_id`: The channel id of the order #[pallet::call_index(13)] #[pallet::weight(::WeightInfo::mint_with_channel_id())] pub fn mint_with_channel_id( @@ -759,32 +653,137 @@ pub mod pallet { remark: BoundedVec>, channel_id: u32, ) -> DispatchResultWithPostInfo { - let (source_chain_caller, derivative_account, bifrost_chain_caller) = + let (source_chain_caller, _, bifrost_chain_caller) = Self::ensure_singer_on_whitelist(origin.clone(), evm_caller, &target_chain)?; - let order = Order { - create_block_number: >::block_number(), - order_type: OrderType::Mint, - currency_amount: Default::default(), + Self::do_create_order( source_chain_caller, bifrost_chain_caller, - derivative_account, currency_id, + Default::default(), remark, - target_chain, channel_id, - }; - - OrderQueue::::mutate(|order_queue| -> DispatchResultWithPostInfo { - order_queue.try_push(order.clone()).map_err(|_| Error::::ArgumentsError)?; - Self::deposit_event(Event::::CreateOrder { order }); - Ok(().into()) - }) + target_chain, + ) } + + // TODO: Substrate user create order + // #[pallet::call_index(14)] + // #[pallet::weight(::WeightInfo::mint())] + // pub fn substrate_create_order( + // origin: OriginFor, + // currency_id: CurrencyId, + // amount: BalanceOf, + // target_chain: TargetChain, + // remark: BoundedVec>, + // channel_id: u32, + // ) -> DispatchResultWithPostInfo { + // // let who = ensure_signed(origin)?; + // let location = ensure_xcm(::RuntimeOrigin::from(origin))?; + // + // let account_id = match location.unpack() { + // (1, [Parachain(para_id), AccountId32 { network: _, id }]) => { + // let account_id = T::AccountId::decode(&mut &id[..]).map_err(|_| + // Error::::Unsupported)?; Ok(account_id) + // }, + // _ => { + // Err(Error::::Unsupported) + // }, + // }; + // Ok(().into()) + // } } } impl Pallet { + /// According to currency_id, return the order type + fn order_type(currency_id: CurrencyId) -> Result> { + match currency_id { + CurrencyId::Native(_) | CurrencyId::Token(_) | CurrencyId::Token2(_) => + Ok(OrderType::Mint), + CurrencyId::VToken(_) | CurrencyId::VToken2(_) => Ok(OrderType::Redeem), + _ => Err(Error::::Unsupported), + } + } + + /// According to frontier, return the derivative account + fn frontier_derivative_account(order_caller: &OrderCaller) -> T::AccountId { + match order_caller { + OrderCaller::Substrate(account_id) => account_id.clone(), + OrderCaller::Evm(h160) => Self::h160_to_account_id(h160), + } + } + + /// According to Xcm, return the account id + fn xcm_derivative_account( + support_chain: SupportChain, + contract_address: H160, + ) -> Result> { + let location = match support_chain { + SupportChain::Astar => { + let account_id = Self::h160_to_account_id(&contract_address); + let id: [u8; 32] = + account_id.encode().try_into().map_err(|_| Error::::ErrorEncode)?; + Location::new( + 1, + [Parachain(AstarChainId::get()), AccountId32 { network: None, id }], + ) + }, + SupportChain::Moonbeam => Location::new( + 1, + [ + Parachain(T::VtokenMintingInterface::get_moonbeam_parachain_id()), + AccountKey20 { network: None, key: contract_address.to_fixed_bytes() }, + ], + ), + _ => { + ensure!(false, Error::::Unsupported); + Location::default() + }, + }; + let raw_account = + HashedDescription::<[u8; 32], DescribeFamily>::convert_location( + &location, + ) + .ok_or(Error::::Unsupported)?; + let account = + T::AccountId::decode(&mut &raw_account[..]).map_err(|_| Error::::ErrorEncode)?; + Ok(account) + } + + fn do_create_order( + source_chain_caller: OrderCaller, + bifrost_chain_caller: T::AccountId, + currency_id: CurrencyId, + currency_amount: BalanceOf, + remark: BoundedVec>, + channel_id: u32, + target_chain: TargetChain, + ) -> DispatchResultWithPostInfo { + let order_type = Self::order_type(currency_id)?; + let derivative_account = Self::frontier_derivative_account(&source_chain_caller); + let order = Order { + create_block_number: >::block_number(), + order_type, + currency_id, + currency_amount, + remark, + source_chain_caller, + bifrost_chain_caller, + derivative_account, + target_chain, + channel_id, + }; + + OrderQueue::::mutate(|order_queue| -> DispatchResultWithPostInfo { + order_queue + .try_push(order.clone()) + .map_err(|_| Error::::OrderQueueOverflow)?; + Self::deposit_event(Event::::CreateOrder { order }); + Ok(().into()) + }) + } + fn send_xcm_to_set_token_amount( call: Vec, xcm_weight: Weight, @@ -853,16 +852,16 @@ impl Pallet { currency_id: CurrencyId, token_amount: BalanceOf, vtoken_amount: BalanceOf, - ) -> Vec { + ) -> Result, Error> { let ethereum_call = Self::encode_ethereum_call(currency_id, token_amount, vtoken_amount); let transaction = EthereumXcmTransaction::V2(EthereumXcmTransactionV2 { gas_limit: U256::from(MAX_GAS_LIMIT), action: TransactionAction::Call(contract), value: U256::zero(), - input: BoundedVec::try_from(ethereum_call).unwrap(), + input: BoundedVec::try_from(ethereum_call).map_err(|_| Error::::ErrorEncode)?, access_list: None, }); - return MoonbeamCall::EthereumXcm(EthereumXcmCall::Transact(transaction)).encode(); + Ok(MoonbeamCall::EthereumXcm(EthereumXcmCall::Transact(transaction)).encode()) } /// Check if the signer is in the whitelist @@ -872,13 +871,6 @@ impl Pallet { target_chain: &TargetChain>, ) -> Result<(OrderCaller>, AccountIdOf, AccountIdOf), DispatchError> { let bifrost_chain_caller = ensure_signed(origin)?; - let support_chain = match target_chain { - TargetChain::Astar(_) => SupportChain::Astar, - TargetChain::Moonbeam(_) => SupportChain::Moonbeam, - TargetChain::Hydradx(_) => SupportChain::Hydradx, - TargetChain::Interlay(_) => SupportChain::Interlay, - TargetChain::Manta(_) => SupportChain::Manta, - }; match target_chain { TargetChain::Hydradx(_) | TargetChain::Manta(_) | TargetChain::Interlay(_) => Ok(( @@ -887,14 +879,15 @@ impl Pallet { bifrost_chain_caller, )), _ => { - let whitelist_account_ids = WhitelistAccountId::::get(&support_chain); + let whitelist_account_ids = + WhitelistAccountId::::get(target_chain.support_chain()); ensure!( whitelist_account_ids.contains(&bifrost_chain_caller), - Error::::AccountIdNotInWhitelist + Error::::AccountNotFound ); Ok(( OrderCaller::Evm(evm_caller), - Self::h160_to_account_id(evm_caller), + Self::h160_to_account_id(&evm_caller), bifrost_chain_caller, )) }, @@ -929,76 +922,75 @@ impl Pallet { amount: BalanceOf, target_chain: &TargetChain>, ) -> DispatchResult { - match target_chain { - TargetChain::Astar(receiver) => { - let receiver = Self::h160_to_account_id(*receiver); - let dest = Location::new( - 1, - [ - Parachain(AstarChainId::get()), - AccountId32 { network: None, id: receiver.encode().try_into().unwrap() }, - ], - ); - - T::XcmTransfer::transfer(caller, currency_id, amount, dest, Unlimited)?; - }, - TargetChain::Hydradx(receiver) => { - let dest = Location::new( - 1, - [ - Parachain(HydrationChainId::get()), - AccountId32 { network: None, id: receiver.encode().try_into().unwrap() }, - ], - ); - - T::XcmTransfer::transfer(caller, currency_id, amount, dest, Unlimited)?; - }, - TargetChain::Interlay(receiver) => { - let dest = Location::new( - 1, - [ - Parachain(InterlayChainId::get()), - AccountId32 { network: None, id: receiver.encode().try_into().unwrap() }, - ], - ); - - T::XcmTransfer::transfer(caller, currency_id, amount, dest, Unlimited)?; - }, - TargetChain::Manta(receiver) => { - let dest = Location::new( - 1, - [ - Parachain(MantaChainId::get()), - AccountId32 { network: None, id: receiver.encode().try_into().unwrap() }, - ], - ); + let dest = match target_chain { + TargetChain::Astar(receiver) => Location::new( + 1, + [ + Parachain(AstarChainId::get()), + AccountId32 { + network: None, + id: Self::h160_to_account_id(receiver) + .encode() + .try_into() + .map_err(|_| Error::::ErrorEncode)?, + }, + ], + ), + TargetChain::Moonbeam(receiver) => Location::new( + 1, + [ + Parachain(T::VtokenMintingInterface::get_moonbeam_parachain_id()), + AccountKey20 { network: None, key: receiver.to_fixed_bytes() }, + ], + ), + TargetChain::Hydradx(receiver) => Location::new( + 1, + [ + Parachain(HydrationChainId::get()), + AccountId32 { + network: None, + id: receiver.encode().try_into().map_err(|_| Error::::ErrorEncode)?, + }, + ], + ), + TargetChain::Interlay(receiver) => Location::new( + 1, + [ + Parachain(InterlayChainId::get()), + AccountId32 { + network: None, + id: receiver.encode().try_into().map_err(|_| Error::::ErrorEncode)?, + }, + ], + ), + TargetChain::Manta(receiver) => Location::new( + 1, + [ + Parachain(MantaChainId::get()), + AccountId32 { + network: None, + id: receiver.encode().try_into().map_err(|_| Error::::ErrorEncode)?, + }, + ], + ), + }; + if let TargetChain::Moonbeam(_) = target_chain { + if SupportXcmFeeList::::get().contains(¤cy_id) { T::XcmTransfer::transfer(caller, currency_id, amount, dest, Unlimited)?; - }, - TargetChain::Moonbeam(receiver) => { - let dest = Location::new( - 1, - [ - Parachain(T::VtokenMintingInterface::get_moonbeam_parachain_id()), - AccountKey20 { network: None, key: receiver.to_fixed_bytes() }, - ], - ); - if SupportXcmFeeList::::get().contains(¤cy_id) { - T::XcmTransfer::transfer(caller, currency_id, amount, dest, Unlimited)?; - } else { - let fee_amount = TransferToFee::::get(SupportChain::Moonbeam) - .unwrap_or_else(|| Self::get_default_fee(BNC)); - T::MultiCurrency::transfer(BNC, evm_contract_account_id, &caller, fee_amount)?; - let assets = vec![(currency_id, amount), (BNC, fee_amount)]; - - T::XcmTransfer::transfer_multicurrencies(caller, assets, 1, dest, Unlimited)?; - } - }, - }; + } else { + let fee_amount = Self::get_moonbeam_transfer_to_fee(); + T::MultiCurrency::transfer(BNC, evm_contract_account_id, &caller, fee_amount)?; + let assets = vec![(currency_id, amount), (BNC, fee_amount)]; + T::XcmTransfer::transfer_multicurrencies(caller, assets, 1, dest, Unlimited)?; + } + } else { + T::XcmTransfer::transfer(caller, currency_id, amount, dest, Unlimited)?; + } Ok(()) } - fn h160_to_account_id(address: H160) -> AccountIdOf { + fn h160_to_account_id(address: &H160) -> AccountIdOf { let mut data = [0u8; 24]; data[0..4].copy_from_slice(b"evm:"); data[4..24].copy_from_slice(&address[..]); @@ -1025,7 +1017,8 @@ impl Pallet { order: &Order, CurrencyIdOf, BalanceOf, BlockNumberFor>, ) -> DispatchResult { let currency_amount = - Self::charge_execution_fee(order.currency_id, &order.derivative_account).unwrap(); + Self::charge_execution_fee(order.currency_id, &order.derivative_account) + .map_err(|_| Error::::ErrorChargeFee)?; match order.order_type { OrderType::Mint => { T::VtokenMintingInterface::mint( @@ -1035,9 +1028,9 @@ impl Pallet { order.remark.clone(), Some(order.channel_id), ) - .map_err(|_| Error::::ArgumentsError)?; - let vtoken_id = T::VtokenMintingInterface::vtoken_id(order.currency_id) - .ok_or(Error::::ArgumentsError)?; + .map_err(|_| Error::::ErrorVtokenMiting)?; + let vtoken_id = + order.currency_id.to_vtoken().map_err(|_| Error::::ErrorConvertVtoken)?; let vtoken_amount = T::MultiCurrency::free_balance(vtoken_id, &order.derivative_account); @@ -1048,12 +1041,12 @@ impl Pallet { vtoken_amount, &order.target_chain, ) - .map_err(|_| Error::::ArgumentsError)?; + .map_err(|_| Error::::ErrorTransferTo)?; }, OrderType::Redeem => { let redeem_type = match order.target_chain.clone() { TargetChain::Astar(receiver) => { - let receiver = Self::h160_to_account_id(receiver); + let receiver = Self::h160_to_account_id(&receiver); RedeemType::Astar(receiver) }, TargetChain::Moonbeam(receiver) => RedeemType::Moonbeam(receiver), @@ -1067,11 +1060,120 @@ impl Pallet { currency_amount, redeem_type, ) - .map_err(|_| Error::::ArgumentsError)?; + .map_err(|_| Error::::ErrorVtokenMiting)?; }, }; Ok(()) } + + #[transactional] + pub fn handle_order_queue( + current_block_number: BlockNumberFor, + weight: &mut Weight, + ) -> DispatchResult { + OrderQueue::::mutate(|order_queue| -> DispatchResult { + if order_queue.is_empty() { + *weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 0)); + return Ok(()); + }; + + if current_block_number - order_queue[0].create_block_number >= DelayBlock::::get() { + let mut order = order_queue.remove(0); + if order.currency_amount == Default::default() { + order.currency_amount = T::MultiCurrency::free_balance( + order.currency_id, + &order.derivative_account, + ); + } + match Self::handle_order(&order) { + Ok(_) => { + Self::deposit_event(Event::::OrderHandled { order: order.clone() }); + }, + Err(_) => { + Self::deposit_event(Event::::OrderFailed { order }); + }, + }; + *weight = weight.saturating_add(T::DbWeight::get().reads_writes(12, 8)); + }; + *weight = weight.saturating_add(T::DbWeight::get().reads_writes(2, 0)); + Ok(()) + }) + } + + #[transactional] + pub fn handle_xcm_oracle( + current_block_number: BlockNumberFor, + is_handle_xcm_oracle: &mut bool, + weight: &mut Weight, + ) -> DispatchResult { + let mut currency_list = CurrencyIdList::::get().to_vec(); + if currency_list.is_empty() { + *weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 0)); + return Ok(()); + }; + + let configuration = XcmEthereumCallConfiguration::::get(); + if let Some(mut config) = configuration { + let currency_id = currency_list[0]; + let staking_currency_amount = T::VtokenMintingInterface::get_token_pool(currency_id); + let v_currency_id = + currency_id.to_vtoken().map_err(|_| Error::::ErrorConvertVtoken)?; + let v_currency_total_supply = T::MultiCurrency::total_issuance(v_currency_id); + + if config.last_block + config.period < current_block_number { + let encoded_call = Self::encode_transact_call( + config.contract, + currency_id, + staking_currency_amount, + v_currency_total_supply, + ) + .map_err(|_| Error::::ErrorEncode)?; + + Self::send_xcm_to_set_token_amount(encoded_call, config.xcm_weight, config.xcm_fee) + .map_err(|_| Error::::ErrorDelivering)?; + + Self::deposit_event(Event::XcmOracle { + currency_id, + staking_currency_amount, + v_currency_id, + v_currency_total_supply, + }); + + let mut target_fee_currency_id = GLMR; + if T::ParachainId::get() == Id::from(BifrostKusamaChainId::get()) { + target_fee_currency_id = MOVR; + } + + // Will not check results and will be sent regardless of the success of + // the burning + if T::MultiCurrency::withdraw( + target_fee_currency_id, + &T::TreasuryAccount::get(), + BalanceOf::::unique_saturated_from(config.xcm_fee), + ) + .is_err() + { + Self::deposit_event(Event::InsufficientAssets); + } + + config.last_block = current_block_number; + XcmEthereumCallConfiguration::::put(config); + currency_list.rotate_left(1); + CurrencyIdList::::put( + BoundedVec::try_from(currency_list).map_err(|_| Error::::ErrorEncode)?, + ); + + *weight = weight.saturating_add(T::DbWeight::get().reads_writes(4, 2)); + + *is_handle_xcm_oracle = true; + } + + return Ok(()); + } else { + *weight = weight.saturating_add(T::DbWeight::get().reads_writes(2, 0)); + return Ok(()); + } + } } // Functions to be called by other pallets. diff --git a/pallets/slpx/src/migration.rs b/pallets/slpx/src/migration.rs index a0c5945b2..3fabbbf81 100644 --- a/pallets/slpx/src/migration.rs +++ b/pallets/slpx/src/migration.rs @@ -162,7 +162,7 @@ pub fn migrate_to_v1() -> Weight { }; OrderQueue::::mutate(|order_queue| -> DispatchResultWithPostInfo { - order_queue.try_push(order.clone()).map_err(|_| Error::::ArgumentsError)?; + order_queue.try_push(order.clone()).map_err(|_| Error::::ErrorArguments)?; Ok(().into()) }) .expect("BoundedVec should not overflow"); diff --git a/pallets/slpx/src/mock.rs b/pallets/slpx/src/mock.rs index 13e32baf7..0abbbe43d 100644 --- a/pallets/slpx/src/mock.rs +++ b/pallets/slpx/src/mock.rs @@ -19,42 +19,30 @@ use crate as slpx; use bifrost_asset_registry::AssetIdMaps; -use bifrost_primitives::{ - BifrostEntranceAccount, BifrostExitAccount, BifrostFeeAccount, IncentivePoolAccount, - MoonbeamChainId, StableAssetPalletId, ZenlinkPalletId, -}; pub use bifrost_primitives::{ - CurrencyId, CurrencyIdMapping, MockXcmExecutor, SlpxOperator, BNC, KSM, + CurrencyId, CurrencyIdMapping, MockXcmExecutor, SlpxOperator, TokenSymbol, BNC, KSM, }; -use bifrost_slp::{QueryId, QueryResponseManager}; +use bifrost_primitives::{MockXcmTransfer, MoonbeamChainId, SlpOperator}; use cumulus_primitives_core::ParaId; use frame_support::{ construct_runtime, derive_impl, ord_parameter_types, pallet_prelude::*, parameter_types, traits::{Everything, Nothing}, + PalletId, }; use frame_system::{EnsureRoot, EnsureSignedBy}; -use orml_traits::{ - location::RelativeReserveProvider, parameter_type_with_key, xcm_transfer::Transferred, - MultiCurrency, XcmTransfer, -}; -use sp_core::ConstU128; +use hex_literal::hex; +use orml_traits::parameter_type_with_key; use sp_runtime::{ - traits::{Convert, IdentityLookup, UniqueSaturatedInto}, - AccountId32, SaturatedConversion, + traits::{Convert, IdentityLookup}, + AccountId32, BuildStorage, }; use sp_std::vec; pub use xcm::latest::prelude::*; -use xcm::{ - latest::{Junction, Location}, - opaque::latest::Junction::Parachain, -}; +use xcm::{latest::Location, opaque::latest::Junction::Parachain}; use xcm_builder::FrameTransactionalProcessor; pub use xcm_builder::{EnsureXcmOrigin, FixedWeightBounds}; -use zenlink_protocol::{ - AssetBalance, AssetId as ZenlinkAssetId, LocalAssetHandler, PairLpGenerate, ZenlinkMultiAssets, -}; pub type Balance = u128; pub type Amount = i128; @@ -73,15 +61,10 @@ construct_runtime!( Tokens: orml_tokens, Currencies: bifrost_currencies, AssetRegistry: bifrost_asset_registry, - Slp: bifrost_slp, VtokenMinting: bifrost_vtoken_minting, - ZenlinkProtocol: zenlink_protocol, - XTokens: orml_xtokens, Slpx: slpx, - PolkadotXcm: pallet_xcm, - ParachainInfo: parachain_info, - StableAsset: bifrost_stable_asset, - StablePool: bifrost_stable_pool + PolkadotXcm: pallet_xcm, + ParachainInfo: parachain_info, } ); @@ -120,7 +103,7 @@ impl pallet_balances::Config for Test { } parameter_types! { - pub const GetNativeCurrencyId: CurrencyId = BNC; + pub const GetNativeCurrencyId: CurrencyId = CurrencyId::Native(TokenSymbol::BNC); } pub type AdaptedBasicCurrency = @@ -162,7 +145,11 @@ impl orml_tokens::Config for Test { parameter_types! { pub const MaximumUnlockIdOfUser: u32 = 10; pub const MaximumUnlockIdOfTimeUnit: u32 = 50; + pub BifrostEntranceAccount: PalletId = PalletId(*b"bf/vtkin"); + pub BifrostExitAccount: PalletId = PalletId(*b"bf/vtout"); + pub BifrostFeeAccount: AccountId = hex!["e4da05f08e89bf6c43260d96f26fffcfc7deae5b465da08669a9d008e64c2c63"].into(); pub const RelayCurrencyId: CurrencyId = KSM; + pub IncentivePoolAccount: PalletId = PalletId(*b"bf/inpoo"); } ord_parameter_types! { @@ -176,6 +163,14 @@ impl SlpxOperator for SlpxInterface { } } +pub struct MockSlp; + +impl SlpOperator for MockSlp { + fn all_delegation_requests_occupied(_: CurrencyId) -> bool { + false + } +} + impl bifrost_vtoken_minting::Config for Test { type RuntimeEvent = RuntimeEvent; type MultiCurrency = Currencies; @@ -189,11 +184,11 @@ impl bifrost_vtoken_minting::Config for Test { type RelayChainToken = RelayCurrencyId; type CurrencyIdConversion = AssetIdMaps; type CurrencyIdRegister = AssetIdMaps; - type BifrostSlp = Slp; + type BifrostSlp = MockSlp; type BifrostSlpx = SlpxInterface; type WeightInfo = (); type OnRedeemSuccess = (); - type XcmTransfer = XTokens; + type XcmTransfer = MockXcmTransfer; type MoonbeamChainId = MoonbeamChainId; type ChannelCommission = (); type MaxLockRecords = ConstU32<100>; @@ -201,90 +196,6 @@ impl bifrost_vtoken_minting::Config for Test { type BbBNC = (); type AssetIdMaps = AssetIdMaps; } -// Below is the implementation of tokens manipulation functions other than native token. -pub struct LocalAssetAdaptor(PhantomData); - -impl LocalAssetHandler for LocalAssetAdaptor -where - Local: MultiCurrency, -{ - fn local_balance_of(asset_id: ZenlinkAssetId, who: &AccountId) -> AssetBalance { - let currency_id: CurrencyId = asset_id.try_into().unwrap(); - Local::free_balance(currency_id, &who).saturated_into() - } - - fn local_total_supply(asset_id: ZenlinkAssetId) -> AssetBalance { - let currency_id: CurrencyId = asset_id.try_into().unwrap(); - Local::total_issuance(currency_id).saturated_into() - } - - fn local_is_exists(asset_id: ZenlinkAssetId) -> bool { - let rs: Result = asset_id.try_into(); - match rs { - Ok(_) => true, - Err(_) => false, - } - } - - fn local_transfer( - asset_id: ZenlinkAssetId, - origin: &AccountId, - target: &AccountId, - amount: AssetBalance, - ) -> DispatchResult { - let currency_id: CurrencyId = asset_id.try_into().unwrap(); - Local::transfer(currency_id, &origin, &target, amount.unique_saturated_into())?; - - Ok(()) - } - - fn local_deposit( - asset_id: ZenlinkAssetId, - origin: &AccountId, - amount: AssetBalance, - ) -> Result { - let currency_id: CurrencyId = asset_id.try_into().unwrap(); - Local::deposit(currency_id, &origin, amount.unique_saturated_into())?; - return Ok(amount); - } - - fn local_withdraw( - asset_id: ZenlinkAssetId, - origin: &AccountId, - amount: AssetBalance, - ) -> Result { - let currency_id: CurrencyId = asset_id.try_into().unwrap(); - Local::withdraw(currency_id, &origin, amount.unique_saturated_into())?; - - Ok(amount) - } -} - -type MultiAssets = ZenlinkMultiAssets>; - -parameter_types! { - pub const GetExchangeFee: (u32, u32) = (3, 1000); // 0.3% - pub const SelfParaId: u32 = 2001; -} - -impl zenlink_protocol::Config for Test { - type RuntimeEvent = RuntimeEvent; - type MultiAssetsHandler = MultiAssets; - type PalletId = ZenlinkPalletId; - type SelfParaId = SelfParaId; - - type TargetChains = (); - type WeightInfo = (); - type AssetId = ZenlinkAssetId; - type LpGenerate = PairLpGenerate; -} - -pub struct AccountIdToLocation; -impl Convert for AccountIdToLocation { - fn convert(account_id: AccountId) -> Location { - Location::from(Junction::AccountId32 { network: None, id: account_id.into() }) - } -} parameter_types! { // One XCM operation is 200_000_000 XcmWeight, cross-chain transfer ~= 2x of transfer = 3_000_000_000 @@ -353,32 +264,10 @@ impl> Convert> for CurrencyIdConvert impl parachain_info::Config for Test {} -impl orml_xtokens::Config for Test { - type RuntimeEvent = RuntimeEvent; - type Balance = Balance; - type CurrencyId = CurrencyId; - type CurrencyIdConvert = CurrencyIdConvert; - type AccountIdToLocation = (); - type UniversalLocation = UniversalLocation; - type SelfLocation = SelfRelativeLocation; - type XcmExecutor = MockXcmExecutor; - type Weigher = FixedWeightBounds; - type BaseXcmWeight = BaseXcmWeight; - type MaxAssetsForTransfer = MaxAssetsForTransfer; - type MinXcmFee = ParachainMinFee; - type LocationsFilter = Everything; - type ReserveProvider = RelativeReserveProvider; - type RateLimiter = (); - type RateLimiterId = (); -} - -ord_parameter_types! { - pub const CouncilAccount: AccountId = AccountId::from([1u8; 32]); -} impl bifrost_asset_registry::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type RegisterOrigin = EnsureSignedBy; + type RegisterOrigin = EnsureRoot; type WeightInfo = (); } @@ -389,52 +278,6 @@ impl Get for ParachainId { } } -parameter_types! { - pub const MaxTypeEntryPerBlock: u32 = 10; - pub const MaxRefundPerBlock: u32 = 10; - pub const MaxLengthLimit: u32 = 100; -} - -pub struct SubstrateResponseManager; -impl QueryResponseManager for SubstrateResponseManager { - fn get_query_response_record(_query_id: QueryId) -> bool { - Default::default() - } - fn create_query_record( - _responder: Location, - _call_back: Option, - _timeout: u64, - ) -> u64 { - Default::default() - } - fn remove_query_record(_query_id: QueryId) -> bool { - Default::default() - } -} - -impl bifrost_slp::Config for Test { - type RuntimeEvent = RuntimeEvent; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type MultiCurrency = Currencies; - type ControlOrigin = EnsureSignedBy; - type WeightInfo = (); - type VtokenMinting = VtokenMinting; - type AccountConverter = (); - type ParachainId = ParachainId; - type SubstrateResponseManager = SubstrateResponseManager; - type MaxTypeEntryPerBlock = MaxTypeEntryPerBlock; - type MaxRefundPerBlock = MaxRefundPerBlock; - type ParachainStaking = (); - type XcmTransfer = XTokens; - type MaxLengthLimit = MaxLengthLimit; - type XcmWeightAndFeeHandler = (); - type ChannelCommission = (); - type StablePoolHandler = (); - type AssetIdMaps = AssetIdMaps; - type TreasuryAccount = BifrostFeeAccount; -} - #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(Parent.into()); @@ -466,133 +309,25 @@ impl pallet_xcm::Config for Test { type RemoteLockConsumerIdentifier = (); } -pub struct EnsurePoolAssetId; -impl bifrost_stable_asset::traits::ValidateAssetId for EnsurePoolAssetId { - fn validate(_: CurrencyId) -> bool { - true - } -} - -impl bifrost_stable_asset::Config for Test { - type RuntimeEvent = RuntimeEvent; - type AssetId = CurrencyId; - type Balance = Balance; - type Assets = Tokens; - type PalletId = StableAssetPalletId; - type AtLeast64BitUnsigned = u128; - type FeePrecision = ConstU128<10_000_000_000>; - type APrecision = ConstU128<100>; - type PoolAssetLimit = ConstU32<5>; - type SwapExactOverAmount = ConstU128<100>; - type WeightInfo = (); - type ListingOrigin = EnsureSignedBy; - type EnsurePoolAssetId = EnsurePoolAssetId; -} - -impl bifrost_stable_pool::Config for Test { - type WeightInfo = (); - type ControlOrigin = EnsureRoot; - type CurrencyId = CurrencyId; - type MultiCurrency = Tokens; - type StableAsset = StableAsset; - type VtokenMinting = VtokenMinting; - type CurrencyIdConversion = AssetIdMaps; - type CurrencyIdRegister = AssetIdMaps; -} - -// Pallet slpx configuration -parameter_types! { - pub const NativeCurrencyId: CurrencyId = BNC; -} - -pub struct XTokensMock; - -impl XcmTransfer for XTokensMock { - fn transfer( - who: AccountId, - currency_id: CurrencyId, - amount: Balance, - dest: Location, - _dest_weight_limit: WeightLimit, - ) -> Result, DispatchError> { - Currencies::withdraw(currency_id, &who, amount).ok(); - Currencies::deposit(currency_id, &BOB, amount).ok(); - Ok(Transferred { - sender: who, - assets: Default::default(), - fee: Asset { id: AssetId(Location::new(1, Here)), fun: Fungible(0u128) }, - dest, - }) - } - - fn transfer_multiasset( - _who: AccountId, - _asset: Asset, - _dest: Location, - _dest_weight_limit: WeightLimit, - ) -> Result, DispatchError> { - todo!() - } - - fn transfer_with_fee( - _who: AccountId, - _currency_id: CurrencyId, - _amount: Balance, - _fee: Balance, - _dest: Location, - _dest_weight_limit: WeightLimit, - ) -> Result, DispatchError> { - todo!() - } - - fn transfer_multiasset_with_fee( - _who: AccountId, - _asset: Asset, - _fee: Asset, - _dest: Location, - _dest_weight_limit: WeightLimit, - ) -> Result, DispatchError> { - todo!() - } - - fn transfer_multicurrencies( - _who: AccountId, - _currencies: Vec<(CurrencyId, Balance)>, - _fee_item: u32, - _dest: Location, - _dest_weight_limit: WeightLimit, - ) -> Result, DispatchError> { - todo!() - } - - fn transfer_multiassets( - _who: AccountId, - _assets: Assets, - _fee: Asset, - _dest: Location, - _dest_weight_limit: WeightLimit, - ) -> Result, DispatchError> { - todo!() - } -} - impl slpx::Config for Test { type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; type ControlOrigin = EnsureRoot; type MultiCurrency = Currencies; - type DexOperator = ZenlinkProtocol; type VtokenMintingInterface = VtokenMinting; - type StablePoolHandler = StablePool; - type XcmTransfer = XTokensMock; + type XcmTransfer = MockXcmTransfer; type XcmSender = (); type CurrencyIdConvert = AssetIdMaps; type TreasuryAccount = BifrostFeeAccount; type ParachainId = ParachainId; type WeightInfo = (); + type MaxOrderSize = ConstU32<500>; } -#[cfg(feature = "runtime-benchmarks")] +// Build genesis storage according to the mock runtime. pub fn new_test_ext() -> sp_io::TestExternalities { - use sp_runtime::BuildStorage; - frame_system::GenesisConfig::::default().build_storage().unwrap().into() + let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(0)); + ext } diff --git a/pallets/slpx/src/tests.rs b/pallets/slpx/src/tests.rs index aa58302dc..0f4e8c824 100644 --- a/pallets/slpx/src/tests.rs +++ b/pallets/slpx/src/tests.rs @@ -22,22 +22,22 @@ use crate::{ types::{EthereumXcmCall, EthereumXcmTransaction, EthereumXcmTransactionV2, MoonbeamCall}, *, }; -use bifrost_primitives::{TokenSymbol, TryConvertFrom, DOT, VDOT}; +use bifrost_primitives::{TokenSymbol, DOT, VDOT}; use ethereum::TransactionAction; -use frame_support::{assert_noop, assert_ok, dispatch::RawOrigin, traits::Hooks}; +use frame_support::{assert_noop, assert_ok, dispatch::RawOrigin, traits::OnIdle}; use hex_literal::hex; -use sp_core::{bounded::BoundedVec, ConstU32, U256}; -use sp_io; +use sp_core::{bounded::BoundedVec, crypto::Ss58Codec, U256}; use tiny_keccak::Hasher; -use zenlink_protocol::AssetId; const EVM_ADDR: [u8; 20] = hex!["573394b77fC17F91E9E67F147A9ECe24d67C5073"]; +const ASTAR_SLPX_ADDR: [u8; 20] = hex!["c6bf0C5C78686f1D0E2E54b97D6de6e2cEFAe9fD"]; +const MOONBEAM_SLPX_ADDR: [u8; 20] = hex!["F1d4797E51a4640a76769A50b57abE7479ADd3d8"]; #[test] fn test_account_convert_work() { - sp_io::TestExternalities::default().execute_with(|| { + new_test_ext().execute_with(|| { let address = H160::from_slice(&EVM_ADDR); - let account_id: AccountId = Slpx::h160_to_account_id(address); + let account_id: AccountId = Slpx::h160_to_account_id(&address); assert_eq!( account_id, sp_runtime::AccountId32::new(hex!( @@ -53,57 +53,133 @@ fn test_account_convert_work() { } #[test] -fn test_whitelist_work() { - sp_io::TestExternalities::default().execute_with(|| { - assert_ok!(Slpx::add_whitelist(RuntimeOrigin::root(), SupportChain::Astar, ALICE)); - assert_ok!(Slpx::add_whitelist(RuntimeOrigin::root(), SupportChain::Astar, BOB)); +fn xcm_derivative_account() { + new_test_ext().execute_with(|| { + let address = H160::from_slice(&ASTAR_SLPX_ADDR); + let derivative_account = + Slpx::xcm_derivative_account(SupportChain::Astar, address).unwrap(); assert_eq!( - WhitelistAccountId::::get(SupportChain::Astar), - BoundedVec::>::try_from(vec![ALICE, BOB]).unwrap() + derivative_account, + sp_runtime::AccountId32::from_ss58check( + "g96o4GVpsAop1MJiArnmUYtXUjEisfkbfcpsuqmXrS28MEr" + ) + .unwrap() ); - assert_noop!( - Slpx::add_whitelist(RuntimeOrigin::root(), SupportChain::Astar, ALICE), - Error::::AccountIdAlreadyInWhitelist + + let address = H160::from_slice(&MOONBEAM_SLPX_ADDR); + let derivative_account = + Slpx::xcm_derivative_account(SupportChain::Moonbeam, address).unwrap(); + assert_eq!( + derivative_account, + sp_runtime::AccountId32::from_ss58check( + "gWEvf2EDMzxR7JHyrEHXf3nqxKLGvHaFbk7HUkJnNPUxDts" + ) + .unwrap() ); - assert_ok!(Slpx::remove_whitelist(RuntimeOrigin::root(), SupportChain::Astar, ALICE)); + }); +} + +#[test] +fn add_whitelist() { + new_test_ext().execute_with(|| { + let astar_slpx_addr = H160::from_slice(&ASTAR_SLPX_ADDR); + let moonbeam_slpx_addr = H160::from_slice(&MOONBEAM_SLPX_ADDR); + let astar_slpx_account_id = sp_runtime::AccountId32::from_ss58check( + "g96o4GVpsAop1MJiArnmUYtXUjEisfkbfcpsuqmXrS28MEr", + ) + .unwrap(); + let moonbeam_slpx_account_id = sp_runtime::AccountId32::from_ss58check( + "gWEvf2EDMzxR7JHyrEHXf3nqxKLGvHaFbk7HUkJnNPUxDts", + ) + .unwrap(); + assert_ok!(Slpx::add_whitelist( + RuntimeOrigin::root(), + SupportChain::Astar, + astar_slpx_addr + )); + assert_eq!( + WhitelistAccountId::::get(SupportChain::Astar).to_vec(), + vec![astar_slpx_account_id] + ); + + assert_ok!(Slpx::add_whitelist( + RuntimeOrigin::root(), + SupportChain::Moonbeam, + moonbeam_slpx_addr + )); assert_eq!( - WhitelistAccountId::::get(SupportChain::Astar), - BoundedVec::>::try_from(vec![BOB]).unwrap() + WhitelistAccountId::::get(SupportChain::Moonbeam).to_vec(), + vec![moonbeam_slpx_account_id] + ); + }); +} + +#[test] +fn add_whitelist_account_id_already_in_whitelist() { + new_test_ext().execute_with(|| { + let astar_slpx_addr = H160::from_slice(&ASTAR_SLPX_ADDR); + let astar_slpx_account_id = sp_runtime::AccountId32::from_ss58check( + "g96o4GVpsAop1MJiArnmUYtXUjEisfkbfcpsuqmXrS28MEr", + ) + .unwrap(); + assert_ok!(Slpx::add_whitelist( + RuntimeOrigin::root(), + SupportChain::Astar, + astar_slpx_addr + )); + assert_eq!( + WhitelistAccountId::::get(SupportChain::Astar).to_vec(), + vec![astar_slpx_account_id] ); - // Astar && Moonbeam - let evm_caller = H160::from_slice(&EVM_ADDR); - let target_chain = TargetChain::Astar(evm_caller); - let (order_caller, derivative_account, _) = - Slpx::ensure_singer_on_whitelist(RuntimeOrigin::signed(BOB), evm_caller, &target_chain) - .unwrap(); assert_noop!( - Slpx::ensure_singer_on_whitelist( - RuntimeOrigin::signed(ALICE), - evm_caller, - &target_chain - ), - Error::::AccountIdNotInWhitelist + Slpx::add_whitelist(RuntimeOrigin::root(), SupportChain::Astar, astar_slpx_addr), + Error::::AccountAlreadyExists ); - assert_eq!(order_caller, OrderCaller::Evm(evm_caller)); - assert_eq!(derivative_account, Slpx::h160_to_account_id(evm_caller)); + }); +} - // Hydradx No whitelist checking - let target_chain = TargetChain::Hydradx(ALICE); - let (order_caller, derivative_account, _) = Slpx::ensure_singer_on_whitelist( - RuntimeOrigin::signed(ALICE), - evm_caller, - &target_chain, +#[test] +fn remove_whitelist() { + new_test_ext().execute_with(|| { + let astar_slpx_addr = H160::from_slice(&ASTAR_SLPX_ADDR); + let astar_slpx_account_id = sp_runtime::AccountId32::from_ss58check( + "g96o4GVpsAop1MJiArnmUYtXUjEisfkbfcpsuqmXrS28MEr", ) .unwrap(); - assert_eq!(order_caller, OrderCaller::Substrate(ALICE)); - assert_eq!(derivative_account, ALICE); + assert_ok!(Slpx::add_whitelist( + RuntimeOrigin::root(), + SupportChain::Astar, + astar_slpx_addr + )); + assert_eq!( + WhitelistAccountId::::get(SupportChain::Astar).to_vec(), + vec![astar_slpx_account_id] + ); + + assert_ok!(Slpx::remove_whitelist( + RuntimeOrigin::root(), + SupportChain::Astar, + astar_slpx_addr + )); + assert_eq!(WhitelistAccountId::::get(SupportChain::Astar).to_vec(), vec![]); + }); +} + +#[test] +fn remove_whitelist_account_id_not_in_whitelist() { + new_test_ext().execute_with(|| { + let astar_slpx_addr = H160::from_slice(&ASTAR_SLPX_ADDR); + assert_noop!( + Slpx::remove_whitelist(RuntimeOrigin::root(), SupportChain::Astar, astar_slpx_addr), + Error::::AccountNotFound + ); }); } #[test] fn test_execution_fee_work() { - sp_io::TestExternalities::default().execute_with(|| { + new_test_ext().execute_with(|| { assert_ok!(Currencies::deposit(CurrencyId::Token2(0), &ALICE, 50 * 1_000_000_000)); assert_ok!(Slpx::set_execution_fee( @@ -126,67 +202,9 @@ fn test_execution_fee_work() { }); } -#[test] -fn test_zenlink() { - 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 - )); - - let bnc_token: AssetId = - AssetId::try_convert_from(CurrencyId::Native(TokenSymbol::BNC), 2001).unwrap(); - let ksm_token: AssetId = - AssetId::try_convert_from(CurrencyId::Token(TokenSymbol::KSM), 2001).unwrap(); - - assert_ok!(ZenlinkProtocol::create_pair( - RawOrigin::Root.into(), - bnc_token, - ksm_token, - ALICE - )); - assert_ok!(ZenlinkProtocol::add_liquidity( - RawOrigin::Signed(ALICE).into(), - bnc_token, - ksm_token, - 20u128 * 1_000_000_000, - 20u128 * 1_000_000_000, - 0, - 0, - 100 - )); - 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); - let minimum_balance = Currencies::minimum_balance(CurrencyId::Native(TokenSymbol::BNC)); - assert_ok!(ZenlinkProtocol::swap_exact_assets_for_assets( - RawOrigin::Signed(ALICE).into(), - balance - minimum_balance, - 0, - path, - ALICE, - 100 - )); - }); -} - #[test] fn test_get_default_fee() { - sp_io::TestExternalities::default().execute_with(|| { + new_test_ext().execute_with(|| { assert_eq!(Slpx::get_default_fee(BNC), 10_000_000_000u128); assert_eq!(Slpx::get_default_fee(CurrencyId::Token(TokenSymbol::KSM)), 10_000_000_000u128); assert_eq!( @@ -203,7 +221,7 @@ fn test_get_default_fee() { #[test] fn test_ed() { - sp_io::TestExternalities::default().execute_with(|| { + new_test_ext().execute_with(|| { assert_ok!(Currencies::deposit( CurrencyId::Native(TokenSymbol::BNC), &ALICE, @@ -254,7 +272,7 @@ fn test_selector() { #[test] fn test_ethereum_call() { - sp_io::TestExternalities::default().execute_with(|| { + new_test_ext().execute_with(|| { // b"setTokenAmount(bytes2,uint256,bytes2,uint256)" assert_eq!("9a41b9240001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b00000000000000000000000000000000000000000000000000000000000001c8", hex::encode(Slpx::encode_ethereum_call(BNC, 123u128, 456u128))); @@ -269,28 +287,28 @@ fn test_ethereum_call() { }); let call = MoonbeamCall::EthereumXcm(EthereumXcmCall::Transact(r)); println!("{}", hex::encode(call.encode())); - assert_eq!("6d000180fc0a000000000000000000000000000000000000000000000000000000000000ae0daa9bfc50f03ce23d30c796709a58470b5f42000000000000000000000000000000000000000000000000000000000000000091019a41b9240001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b00000000000000000000000000000000000000000000000000000000000001c800", hex::encode(Slpx::encode_transact_call(H160::from(addr), BNC, 123u128, 456u128))); + assert_eq!("6d000180fc0a000000000000000000000000000000000000000000000000000000000000ae0daa9bfc50f03ce23d30c796709a58470b5f42000000000000000000000000000000000000000000000000000000000000000091019a41b9240001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b00000000000000000000000000000000000000000000000000000000000001c800", hex::encode(Slpx::encode_transact_call(H160::from(addr), BNC, 123u128, 456u128).unwrap())); }) } #[test] fn test_set_currency_ethereum_call_switch() { - sp_io::TestExternalities::default().execute_with(|| { - assert_ok!(Slpx::set_currency_ethereum_call_switch(RuntimeOrigin::root(), BNC, true)); + new_test_ext().execute_with(|| { + assert_ok!(Slpx::support_xcm_oracle(RuntimeOrigin::root(), BNC, true)); assert_eq!(CurrencyIdList::::get().to_vec(), vec![BNC]); - assert_ok!(Slpx::set_currency_ethereum_call_switch(RuntimeOrigin::root(), KSM, true)); + assert_ok!(Slpx::support_xcm_oracle(RuntimeOrigin::root(), KSM, true)); assert_eq!(CurrencyIdList::::get().to_vec(), vec![BNC, KSM]); - assert_ok!(Slpx::set_currency_ethereum_call_switch(RuntimeOrigin::root(), BNC, false)); + assert_ok!(Slpx::support_xcm_oracle(RuntimeOrigin::root(), BNC, false)); assert_eq!(CurrencyIdList::::get().to_vec(), vec![KSM]); }) } #[test] fn test_set_ethereum_call_configration() { - sp_io::TestExternalities::default().execute_with(|| { - assert_ok!(Slpx::set_ethereum_call_configration( + new_test_ext().execute_with(|| { + assert_ok!(Slpx::set_xcm_oracle_configuration( RuntimeOrigin::root(), 1_000_000_000_000_000_000u128, Weight::default(), @@ -309,7 +327,7 @@ fn test_set_ethereum_call_configration() { } ); - assert_ok!(Slpx::set_ethereum_call_configration( + assert_ok!(Slpx::set_xcm_oracle_configuration( RuntimeOrigin::root(), 1u128, Weight::default(), @@ -332,7 +350,7 @@ fn test_set_ethereum_call_configration() { #[test] fn test_set_currency_to_support_xcm_fee() { - sp_io::TestExternalities::default().execute_with(|| { + new_test_ext().execute_with(|| { assert_ok!(Slpx::set_currency_support_xcm_fee(RuntimeOrigin::root(), BNC, true)); assert_eq!(SupportXcmFeeList::::get().to_vec(), vec![BNC]); @@ -346,8 +364,12 @@ fn test_set_currency_to_support_xcm_fee() { #[test] fn test_add_order() { - sp_io::TestExternalities::default().execute_with(|| { - assert_ok!(Slpx::add_whitelist(RuntimeOrigin::root(), SupportChain::Astar, ALICE)); + new_test_ext().execute_with(|| { + WhitelistAccountId::::insert( + SupportChain::Astar, + BoundedVec::try_from(vec![ALICE]).unwrap(), + ); + let source_chain_caller = H160::default(); assert_ok!(Slpx::mint( RuntimeOrigin::signed(ALICE), @@ -366,12 +388,12 @@ fn test_add_order() { assert_eq!(OrderQueue::::get().len(), 2usize); assert_ok!(Slpx::force_add_order( RuntimeOrigin::root(), + OrderCaller::Evm(source_chain_caller), ALICE, - source_chain_caller, VDOT, TargetChain::Astar(source_chain_caller), BoundedVec::default(), - OrderType::Mint + 0 )); assert_eq!(OrderQueue::::get().len(), 3usize); @@ -381,8 +403,12 @@ fn test_add_order() { #[test] fn test_mint_with_channel_id() { - sp_io::TestExternalities::default().execute_with(|| { - assert_ok!(Slpx::add_whitelist(RuntimeOrigin::root(), SupportChain::Astar, ALICE)); + new_test_ext().execute_with(|| { + WhitelistAccountId::::insert( + SupportChain::Astar, + BoundedVec::try_from(vec![ALICE]).unwrap(), + ); + let source_chain_caller = H160::default(); assert_ok!(Slpx::mint_with_channel_id( RuntimeOrigin::signed(ALICE), @@ -405,8 +431,11 @@ fn test_mint_with_channel_id() { #[test] fn test_hook() { - sp_io::TestExternalities::default().execute_with(|| { - assert_ok!(Slpx::add_whitelist(RuntimeOrigin::root(), SupportChain::Astar, ALICE)); + new_test_ext().execute_with(|| { + WhitelistAccountId::::insert( + SupportChain::Astar, + BoundedVec::try_from(vec![ALICE]).unwrap(), + ); let source_chain_caller = H160::default(); assert_ok!(Slpx::mint( RuntimeOrigin::signed(ALICE), diff --git a/pallets/slpx/src/types.rs b/pallets/slpx/src/types.rs index 5290126d5..e38e0568a 100644 --- a/pallets/slpx/src/types.rs +++ b/pallets/slpx/src/types.rs @@ -60,6 +60,18 @@ pub enum TargetChain { Manta(AccountId), } +impl TargetChain { + pub fn support_chain(self: &TargetChain) -> SupportChain { + match self { + TargetChain::Astar(_) => SupportChain::Astar, + TargetChain::Moonbeam(_) => SupportChain::Moonbeam, + TargetChain::Hydradx(_) => SupportChain::Hydradx, + TargetChain::Interlay(_) => SupportChain::Interlay, + TargetChain::Manta(_) => SupportChain::Manta, + } + } +} + #[derive(Clone, Debug, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen)] pub struct EthereumCallConfiguration { /// XCM message execution costs to be consumed diff --git a/runtime/bifrost-kusama/src/lib.rs b/runtime/bifrost-kusama/src/lib.rs index 5095e5a50..aa98fd219 100644 --- a/runtime/bifrost-kusama/src/lib.rs +++ b/runtime/bifrost-kusama/src/lib.rs @@ -1502,17 +1502,17 @@ impl bifrost_vtoken_minting::Config for Runtime { impl bifrost_slpx::Config for Runtime { type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; type ControlOrigin = TechAdminOrCouncil; type MultiCurrency = Currencies; - type DexOperator = ZenlinkProtocol; type VtokenMintingInterface = VtokenMinting; - type StablePoolHandler = StablePool; type XcmTransfer = XTokens; type XcmSender = XcmRouter; type CurrencyIdConvert = AssetIdMaps; type TreasuryAccount = BifrostTreasuryAccount; type ParachainId = ParachainInfo; type WeightInfo = weights::bifrost_slpx::BifrostWeight; + type MaxOrderSize = ConstU32<500>; } pub struct EnsurePoolAssetId; diff --git a/runtime/bifrost-polkadot/src/lib.rs b/runtime/bifrost-polkadot/src/lib.rs index 579a05809..409b4b72c 100644 --- a/runtime/bifrost-polkadot/src/lib.rs +++ b/runtime/bifrost-polkadot/src/lib.rs @@ -1200,17 +1200,17 @@ impl bifrost_cross_in_out::Config for Runtime { impl bifrost_slpx::Config for Runtime { type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; type ControlOrigin = TechAdminOrCouncil; type MultiCurrency = Currencies; - type DexOperator = ZenlinkProtocol; type VtokenMintingInterface = VtokenMinting; - type StablePoolHandler = StablePool; type XcmTransfer = XTokens; type XcmSender = XcmRouter; type CurrencyIdConvert = AssetIdMaps; type TreasuryAccount = BifrostTreasuryAccount; type ParachainId = ParachainInfo; type WeightInfo = weights::bifrost_slpx::BifrostWeight; + type MaxOrderSize = ConstU32<500>; } pub struct EnsurePoolAssetId; diff --git a/runtime/bifrost-polkadot/src/xcm_config.rs b/runtime/bifrost-polkadot/src/xcm_config.rs index ede51c1ca..f9577776c 100644 --- a/runtime/bifrost-polkadot/src/xcm_config.rs +++ b/runtime/bifrost-polkadot/src/xcm_config.rs @@ -118,6 +118,8 @@ pub type Barrier = TrailingSetTopicAsId<( ( // If the message is one that immediately attemps to pay for execution, then allow it. AllowTopLevelPaidExecutionFrom, + // TODO: Messages coming from system parachains need not pay for execution. + // AllowExplicitUnpaidExecutionFrom, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, ), From 0aaf2cdd32047d4c4ddbc996a7f46e4f94081728 Mon Sep 17 00:00:00 2001 From: MJLNSN <96321798+MJLNSN@users.noreply.github.com> Date: Sun, 29 Sep 2024 15:30:06 +0800 Subject: [PATCH 09/30] Moved palletId in runtime to primitives (#1443) --- primitives/src/lib.rs | 16 ++++++---- runtime/bifrost-kusama/src/lib.rs | 34 ++++++---------------- runtime/bifrost-kusama/src/xcm_config.rs | 2 +- runtime/bifrost-polkadot/src/lib.rs | 33 ++++++--------------- runtime/bifrost-polkadot/src/xcm_config.rs | 2 +- 5 files changed, 31 insertions(+), 56 deletions(-) diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index b711cb02d..6b58e7f04 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -161,9 +161,10 @@ pub type TimeStampedPrice = orml_oracle::TimestampedValue; // Pallet Id parameter_types! { pub const BifrostCrowdloanId: PalletId = PalletId(*b"bf/salp#"); - pub BifrostEntranceAccount: PalletId = PalletId(*b"bf/vtkin"); - pub BifrostExitAccount: PalletId = PalletId(*b"bf/vtout"); - pub BifrostVsbondAccount: PalletId = PalletId(*b"bf/salpb"); + pub const BifrostEntranceAccount: PalletId = PalletId(*b"bf/vtkin"); + pub const BifrostExitAccount: PalletId = PalletId(*b"bf/vtout"); + pub const BifrostSalpLiteCrowdloanId: PalletId = PalletId(*b"bf/salpl"); + pub const BifrostVsbondAccount: PalletId = PalletId(*b"bf/salpb"); pub const BuyBackAccount: PalletId = PalletId(*b"bf/bybck"); pub const BuybackPalletId: PalletId = PalletId(*b"bf/salpc"); pub const CloudsPalletId: PalletId = PalletId(*b"bf/cloud"); @@ -174,17 +175,22 @@ parameter_types! { pub const FarmingRewardIssuerPalletId: PalletId = PalletId(*b"bf/fmrir"); pub const FeeSharePalletId: PalletId = PalletId(*b"bf/feesh"); pub const FlexibleFeePalletId: PalletId = PalletId(*b"bf/flexi"); - pub IncentivePoolAccount: PalletId = PalletId(*b"bf/inpoo"); - pub IncentivePalletId: PalletId = PalletId(*b"bf/bbict"); + pub const IncentivePoolAccount: PalletId = PalletId(*b"bf/inpoo"); + pub const IncentivePalletId: PalletId = PalletId(*b"bf/bbict"); pub const LendMarketPalletId: PalletId = PalletId(*b"bf/ldmkt"); pub const LighteningRedeemPalletId: PalletId = PalletId(*b"lighten#"); pub const LiquidityAccount: PalletId = PalletId(*b"bf/liqdt"); + pub const LiquidityMiningDOTPalletId: PalletId = PalletId(*b"bf/lmdot"); pub const LiquidityMiningPalletId: PalletId = PalletId(*b"mining##"); + pub const MerkleDirtributorPalletId: PalletId = PalletId(*b"bf/mklds"); + pub const OraclePalletId: PalletId = PalletId(*b"bf/oracl"); pub const ParachainStakingPalletId: PalletId = PalletId(*b"bf/stake"); pub const SlpEntrancePalletId: PalletId = PalletId(*b"bf/vtkin"); + pub const SlpExitPalletId: PalletId = PalletId(*b"bf/vtout"); pub const StableAssetPalletId: PalletId = PalletId(*b"nuts/sta"); pub const SystemMakerPalletId: PalletId = PalletId(*b"bf/sysmk"); pub const SystemStakingPalletId: PalletId = PalletId(*b"bf/sysst"); + pub const TreasuryPalletId: PalletId = PalletId(*b"bf/trsry"); pub const VBNCConvertPalletId: PalletId = PalletId(*b"bf/vbncc"); pub const VeMintingPalletId: PalletId = PalletId(*b"bf/vemnt"); pub const VsbondAuctionPalletId: PalletId = PalletId(*b"bf/vsbnd"); diff --git a/runtime/bifrost-kusama/src/lib.rs b/runtime/bifrost-kusama/src/lib.rs index aa98fd219..2a71076ee 100644 --- a/runtime/bifrost-kusama/src/lib.rs +++ b/runtime/bifrost-kusama/src/lib.rs @@ -30,6 +30,14 @@ use bifrost_slp::{DerivativeAccountProvider, QueryResponseManager}; use core::convert::TryInto; // A few exports that help ease life for downstream crates. pub use bifrost_parachain_staking::{InflationInfo, Range}; +use bifrost_primitives::{ + BifrostCrowdloanId, BifrostVsbondAccount, BuybackPalletId, CommissionPalletId, + FarmingBoostPalletId, FarmingGaugeRewardIssuerPalletId, FarmingKeeperPalletId, + FarmingRewardIssuerPalletId, FeeSharePalletId, FlexibleFeePalletId, IncentivePoolAccount, + LendMarketPalletId, MerkleDirtributorPalletId, OraclePalletId, ParachainStakingPalletId, + SlpEntrancePalletId, SlpExitPalletId, SystemMakerPalletId, SystemStakingPalletId, + TreasuryPalletId, VBNCConvertPalletId, VsbondAuctionPalletId, +}; pub use frame_support::{ construct_runtime, match_types, parameter_types, traits::{ @@ -205,35 +213,11 @@ parameter_types! { } parameter_types! { - pub const TreasuryPalletId: PalletId = PalletId(*b"bf/trsry"); - pub const BifrostCrowdloanId: PalletId = PalletId(*b"bf/salp#"); - pub const BifrostSalpLiteCrowdloanId: PalletId = PalletId(*b"bf/salpl"); pub const LiquidityMiningPalletId: PalletId = PalletId(*b"bf/lm###"); - pub const LiquidityMiningDOTPalletId: PalletId = PalletId(*b"bf/lmdot"); pub const LighteningRedeemPalletId: PalletId = PalletId(*b"bf/ltnrd"); - pub const MerkleDirtributorPalletId: PalletId = PalletId(*b"bf/mklds"); - pub const VsbondAuctionPalletId: PalletId = PalletId(*b"bf/vsbnd"); - pub const ParachainStakingPalletId: PalletId = PalletId(*b"bf/stake"); - pub const BifrostVsbondPalletId: PalletId = PalletId(*b"bf/salpb"); - pub const SlpEntrancePalletId: PalletId = PalletId(*b"bf/vtkin"); - pub const SlpExitPalletId: PalletId = PalletId(*b"bf/vtout"); pub const StableAmmPalletId: PalletId = PalletId(*b"bf/stamm"); - pub const FarmingKeeperPalletId: PalletId = PalletId(*b"bf/fmkpr"); - pub const FarmingRewardIssuerPalletId: PalletId = PalletId(*b"bf/fmrir"); - pub const SystemStakingPalletId: PalletId = PalletId(*b"bf/sysst"); - pub const BuybackPalletId: PalletId = PalletId(*b"bf/salpc"); - pub const SystemMakerPalletId: PalletId = PalletId(*b"bf/sysmk"); - pub const FeeSharePalletId: PalletId = PalletId(*b"bf/feesh"); pub CheckingAccount: AccountId = PolkadotXcm::check_account(); - pub const FarmingBoostPalletId: PalletId = PalletId(*b"bf/fmbst"); - pub const LendMarketPalletId: PalletId = PalletId(*b"bf/ldmkt"); - pub const OraclePalletId: PalletId = PalletId(*b"bf/oracl"); pub const StableAssetPalletId: PalletId = PalletId(*b"bf/stabl"); - pub const CommissionPalletId: PalletId = PalletId(*b"bf/comms"); - pub IncentivePoolAccount: PalletId = PalletId(*b"bf/inpoo"); - pub const FarmingGaugeRewardIssuerPalletId: PalletId = PalletId(*b"bf/fmgar"); - pub const FlexibleFeePalletId: PalletId = PalletId(*b"bf/flexi"); - pub const VBNCConvertPalletId: PalletId = PalletId(*b"bf/vbncc"); } impl frame_system::Config for Runtime { @@ -1274,7 +1258,7 @@ impl bifrost_vstoken_conversion::Config for Runtime { type RelayCurrencyId = RelayCurrencyId; type TreasuryAccount = BifrostTreasuryAccount; type ControlOrigin = CoreAdminOrCouncil; - type VsbondAccount = BifrostVsbondPalletId; + type VsbondAccount = BifrostVsbondAccount; type CurrencyIdConversion = AssetIdMaps; type WeightInfo = weights::bifrost_vstoken_conversion::BifrostWeight; } diff --git a/runtime/bifrost-kusama/src/xcm_config.rs b/runtime/bifrost-kusama/src/xcm_config.rs index 8222f6b28..414600305 100644 --- a/runtime/bifrost-kusama/src/xcm_config.rs +++ b/runtime/bifrost-kusama/src/xcm_config.rs @@ -559,7 +559,7 @@ impl Contains for DustRemovalWhitelist { let whitelist: Vec = vec![ TreasuryPalletId::get().into_account_truncating(), BifrostCrowdloanId::get().into_account_truncating(), - BifrostVsbondPalletId::get().into_account_truncating(), + BifrostVsbondAccount::get().into_account_truncating(), SlpEntrancePalletId::get().into_account_truncating(), SlpExitPalletId::get().into_account_truncating(), BuybackPalletId::get().into_account_truncating(), diff --git a/runtime/bifrost-polkadot/src/lib.rs b/runtime/bifrost-polkadot/src/lib.rs index 409b4b72c..f63de4618 100644 --- a/runtime/bifrost-polkadot/src/lib.rs +++ b/runtime/bifrost-polkadot/src/lib.rs @@ -30,6 +30,14 @@ use bifrost_slp::{DerivativeAccountProvider, QueryResponseManager}; use core::convert::TryInto; use pallet_traits::evm::InspectEvmAccounts; // A few exports that help ease life for downstream crates. +use bifrost_primitives::{ + BifrostCrowdloanId, BifrostVsbondAccount, BuyBackAccount, BuybackPalletId, CloudsPalletId, + CommissionPalletId, FarmingBoostPalletId, FarmingGaugeRewardIssuerPalletId, + FarmingKeeperPalletId, FarmingRewardIssuerPalletId, FeeSharePalletId, FlexibleFeePalletId, + IncentivePalletId, IncentivePoolAccount, LendMarketPalletId, LiquidityAccount, + MerkleDirtributorPalletId, OraclePalletId, SlpEntrancePalletId, SlpExitPalletId, + SystemMakerPalletId, SystemStakingPalletId, TreasuryPalletId, +}; use cumulus_pallet_parachain_system::{RelayNumberStrictlyIncreases, RelaychainDataProvider}; pub use frame_support::{ construct_runtime, match_types, parameter_types, @@ -226,31 +234,8 @@ parameter_types! { } parameter_types! { - pub const TreasuryPalletId: PalletId = PalletId(*b"bf/trsry"); - pub const BifrostCrowdloanId: PalletId = PalletId(*b"bf/salp#"); - pub const MerkleDirtributorPalletId: PalletId = PalletId(*b"bf/mklds"); - pub const BifrostVsbondPalletId: PalletId = PalletId(*b"bf/salpb"); - pub const SlpEntrancePalletId: PalletId = PalletId(*b"bf/vtkin"); - pub const SlpExitPalletId: PalletId = PalletId(*b"bf/vtout"); - pub const FarmingKeeperPalletId: PalletId = PalletId(*b"bf/fmkpr"); - pub const FarmingRewardIssuerPalletId: PalletId = PalletId(*b"bf/fmrir"); - pub const SystemStakingPalletId: PalletId = PalletId(*b"bf/sysst"); - pub const BuybackPalletId: PalletId = PalletId(*b"bf/salpc"); - pub const SystemMakerPalletId: PalletId = PalletId(*b"bf/sysmk"); - pub const FeeSharePalletId: PalletId = PalletId(*b"bf/feesh"); pub CheckingAccount: AccountId = PolkadotXcm::check_account(); - pub const IncentivePalletId: PalletId = PalletId(*b"bf/bbict"); - pub const FarmingBoostPalletId: PalletId = PalletId(*b"bf/fmbst"); - pub const LendMarketPalletId: PalletId = PalletId(*b"bf/ldmkt"); - pub const OraclePalletId: PalletId = PalletId(*b"bf/oracl"); pub const StableAssetPalletId: PalletId = PalletId(*b"bf/stabl"); - pub const CommissionPalletId: PalletId = PalletId(*b"bf/comms"); - pub const CloudsPalletId: PalletId = PalletId(*b"bf/cloud"); - pub IncentivePoolAccount: PalletId = PalletId(*b"bf/inpoo"); - pub const FarmingGaugeRewardIssuerPalletId: PalletId = PalletId(*b"bf/fmgar"); - pub const BuyBackAccount: PalletId = PalletId(*b"bf/bybck"); - pub const LiquidityAccount: PalletId = PalletId(*b"bf/liqdt"); - pub const FlexibleFeePalletId: PalletId = PalletId(*b"bf/flexi"); } impl frame_system::Config for Runtime { @@ -1135,7 +1120,7 @@ impl bifrost_vstoken_conversion::Config for Runtime { type RelayCurrencyId = RelayCurrencyId; type TreasuryAccount = BifrostTreasuryAccount; type ControlOrigin = CoreAdminOrCouncil; - type VsbondAccount = BifrostVsbondPalletId; + type VsbondAccount = BifrostVsbondAccount; type CurrencyIdConversion = AssetIdMaps; type WeightInfo = weights::bifrost_vstoken_conversion::BifrostWeight; } diff --git a/runtime/bifrost-polkadot/src/xcm_config.rs b/runtime/bifrost-polkadot/src/xcm_config.rs index f9577776c..69ab3fa92 100644 --- a/runtime/bifrost-polkadot/src/xcm_config.rs +++ b/runtime/bifrost-polkadot/src/xcm_config.rs @@ -443,7 +443,7 @@ impl Contains for DustRemovalWhitelist { let whitelist: Vec = vec![ TreasuryPalletId::get().into_account_truncating(), BifrostCrowdloanId::get().into_account_truncating(), - BifrostVsbondPalletId::get().into_account_truncating(), + BifrostVsbondAccount::get().into_account_truncating(), SlpEntrancePalletId::get().into_account_truncating(), SlpExitPalletId::get().into_account_truncating(), BuybackPalletId::get().into_account_truncating(), From c081548ef504abf3fd7b5329b138547fa62d5c32 Mon Sep 17 00:00:00 2001 From: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Date: Sun, 29 Sep 2024 16:14:00 +0800 Subject: [PATCH 10/30] Optimize asset registry (#1445) * optimize asset-registry & remove unused call * backup asset-registry pallet --- pallets/asset-registry/src/benchmarking.rs | 140 +-- pallets/asset-registry/src/lib.rs | 355 +----- pallets/asset-registry/src/migrations/mod.rs | 19 + pallets/asset-registry/src/migrations/v0.rs | 131 +++ pallets/asset-registry/src/migrations/v1.rs | 118 ++ pallets/asset-registry/src/tests.rs | 208 +--- pallets/asset-registry/src/weights.rs | 56 - pallets/deprecated/asset-registry/Cargo.toml | 51 + .../asset-registry/src/benchmarking.rs | 309 +++++ pallets/deprecated/asset-registry/src/lib.rs | 1013 +++++++++++++++++ .../asset-registry/src/migration.rs | 0 pallets/deprecated/asset-registry/src/mock.rs | 109 ++ .../deprecated/asset-registry/src/tests.rs | 519 +++++++++ .../deprecated/asset-registry/src/weights.rs | 190 ++++ pallets/slpx/src/benchmarking.rs | 4 +- primitives/src/traits.rs | 60 - .../src/weights/bifrost_asset_registry.rs | 52 - .../src/weights/bifrost_asset_registry.rs | 52 - 18 files changed, 2496 insertions(+), 890 deletions(-) create mode 100644 pallets/asset-registry/src/migrations/mod.rs create mode 100644 pallets/asset-registry/src/migrations/v0.rs create mode 100644 pallets/asset-registry/src/migrations/v1.rs create mode 100644 pallets/deprecated/asset-registry/Cargo.toml create mode 100644 pallets/deprecated/asset-registry/src/benchmarking.rs create mode 100644 pallets/deprecated/asset-registry/src/lib.rs rename pallets/{ => deprecated}/asset-registry/src/migration.rs (100%) create mode 100644 pallets/deprecated/asset-registry/src/mock.rs create mode 100644 pallets/deprecated/asset-registry/src/tests.rs create mode 100644 pallets/deprecated/asset-registry/src/weights.rs diff --git a/pallets/asset-registry/src/benchmarking.rs b/pallets/asset-registry/src/benchmarking.rs index bb7b63b13..5c5555516 100644 --- a/pallets/asset-registry/src/benchmarking.rs +++ b/pallets/asset-registry/src/benchmarking.rs @@ -20,82 +20,12 @@ use super::*; use crate::Pallet as AssetRegistry; -use bifrost_primitives::{CurrencyId, TokenSymbol}; +use bifrost_primitives::CurrencyId; use frame_benchmarking::{benchmarks, v1::BenchmarkError}; use frame_support::{assert_ok, traits::UnfilteredDispatchable}; use sp_runtime::traits::UniqueSaturatedFrom; benchmarks! { - register_native_asset { - let origin = T::RegisterOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - let versioned_location = VersionedLocation::V4(Location::from([Parachain(1000)])); - - let call = Call::::register_native_asset { - currency_id: Token(TokenSymbol::DOT), - location: Box::new(versioned_location.clone()), - metadata: Box::new(AssetMetadata { - name: b"Token Name".to_vec(), - symbol: b"TN".to_vec(), - decimals: 12, - minimal_balance: BalanceOf::::unique_saturated_from(1u128), - }) - }; - }: {call.dispatch_bypass_filter(origin)?} - verify { - assert_eq!( - AssetMetadatas::::get(AssetIds::NativeAssetId(Token( - TokenSymbol::DOT - ))), - Some(AssetMetadata { - name: b"Token Name".to_vec(), - symbol: b"TN".to_vec(), - decimals: 12, - minimal_balance: BalanceOf::::unique_saturated_from(1u128), - }) - ); - } - - update_native_asset { - let origin = T::RegisterOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - let versioned_location = VersionedLocation::V4(Location::from([Parachain(1000)])); - - assert_ok!(AssetRegistry::::register_native_asset( - origin.clone(), - Token(TokenSymbol::DOT), - Box::new(versioned_location.clone()), - Box::new(AssetMetadata { - name: b"Token Name".to_vec(), - symbol: b"TN".to_vec(), - decimals: 12, - minimal_balance: BalanceOf::::unique_saturated_from(1u128), - }) - )); - - let call = Call::::update_native_asset { - currency_id: Token(TokenSymbol::DOT), - location: Box::new(versioned_location.clone()), - metadata: Box::new(AssetMetadata { - name: b"Token Name".to_vec(), - symbol: b"TN".to_vec(), - decimals: 13, - minimal_balance: BalanceOf::::unique_saturated_from(2u128), - }) - }; - }: {call.dispatch_bypass_filter(origin)?} - verify { - assert_eq!( - AssetMetadatas::::get(AssetIds::NativeAssetId(Token( - TokenSymbol::DOT - ))), - Some(AssetMetadata { - name: b"Token Name".to_vec(), - symbol: b"TN".to_vec(), - decimals: 13, - minimal_balance: BalanceOf::::unique_saturated_from(2u128), - }) - ); - } - register_token_metadata { let origin = T::RegisterOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let metadata = AssetMetadata { @@ -143,70 +73,6 @@ benchmarks! { ) } - register_vstoken_metadata { - let origin = T::RegisterOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - let metadata = AssetMetadata { - name: b"KSM Native Token".to_vec(), - symbol: b"KSM".to_vec(), - decimals: 12, - minimal_balance: BalanceOf::::unique_saturated_from(0u128), - }; - let v_metadata = AssetMetadata { - name: b"Voucher Slot KSM".to_vec(), - symbol: b"vsKSM".to_vec(), - decimals: 12, - minimal_balance: BalanceOf::::unique_saturated_from(0u128), - }; - assert_ok!(AssetRegistry::::register_token_metadata( - origin.clone(), - Box::new(metadata.clone()) - )); - - let call = Call::::register_vstoken_metadata { - token_id: 0 - }; - }: {call.dispatch_bypass_filter(origin)?} - verify { - assert_eq!( - CurrencyMetadatas::::get(CurrencyId::VSToken2(0)), - Some(v_metadata.clone()) - ) - } - - register_vsbond_metadata { - let origin = T::RegisterOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - let metadata = AssetMetadata { - name: b"KSM Native Token".to_vec(), - symbol: b"KSM".to_vec(), - decimals: 12, - minimal_balance: BalanceOf::::unique_saturated_from(0u128), - }; - let name = "vsBOND-KSM-2001-10-20".as_bytes().to_vec(); - let v_metadata = AssetMetadata { - name: name.clone(), - symbol: name, - decimals: 12, - minimal_balance: BalanceOf::::unique_saturated_from(0u128), - }; - assert_ok!(AssetRegistry::::register_token_metadata( - origin.clone(), - Box::new(metadata.clone()) - )); - - let call = Call::::register_vsbond_metadata { - token_id: 0, - para_id:2001, - first_slot:10, - last_slot:20 - }; - }: {call.dispatch_bypass_filter(origin)?} - verify { - assert_eq!( - CurrencyMetadatas::::get(CurrencyId::VSBond2(0, 2001, 10, 20)), - Some(v_metadata.clone()) - ) - } - register_location { let origin = T::RegisterOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let metadata = AssetMetadata { @@ -217,7 +83,7 @@ benchmarks! { }; let versioned_location = VersionedLocation::V4(Location::new(1, [Parachain(2001)])); - let location: xcm::v3::Location = versioned_location.clone().try_into().unwrap(); + let location: xcm::v4::Location = versioned_location.clone().try_into().unwrap(); assert_ok!(AssetRegistry::::register_token_metadata( origin.clone(), @@ -232,7 +98,7 @@ benchmarks! { }: {call.dispatch_bypass_filter(origin)?} verify { assert_eq!( - LocationToCurrencyIds::::get(location), + LocationToCurrencyIds::::get(location.clone()), Some(Token2(0)) ); assert_eq!( diff --git a/pallets/asset-registry/src/lib.rs b/pallets/asset-registry/src/lib.rs index c35d14481..edf1ca0e4 100644 --- a/pallets/asset-registry/src/lib.rs +++ b/pallets/asset-registry/src/lib.rs @@ -51,7 +51,7 @@ use xcm::{ use xcm_builder::TakeRevenue; use xcm_executor::{traits::WeightTrader, AssetsInHolding}; -pub mod migration; +pub mod migrations; mod mock; mod tests; pub mod weights; @@ -66,6 +66,14 @@ pub use weights::WeightInfo; pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; +#[derive(Clone, Eq, PartialEq, RuntimeDebug, Encode, Decode, TypeInfo)] +pub struct AssetMetadata { + pub name: Vec, + pub symbol: Vec, + pub decimals: u8, + pub minimal_balance: Balance, +} + #[frame_support::pallet] pub mod pallet { use super::*; @@ -85,14 +93,6 @@ pub mod pallet { type WeightInfo: WeightInfo; } - #[derive(Clone, Eq, PartialEq, RuntimeDebug, Encode, Decode, TypeInfo)] - pub struct AssetMetadata { - pub name: Vec, - pub symbol: Vec, - pub decimals: u8, - pub minimal_balance: Balance, - } - #[pallet::error] pub enum Error { /// The given location could not be used (e.g. because it cannot be expressed in the @@ -142,14 +142,14 @@ pub mod pallet { /// CurrencyIdToLocations: map CurrencyId => Option #[pallet::storage] pub type CurrencyIdToLocations = - StorageMap<_, Twox64Concat, CurrencyId, xcm::v3::Location, OptionQuery>; + StorageMap<_, Twox64Concat, CurrencyId, Location, OptionQuery>; /// The storages for CurrencyIds. /// /// LocationToCurrencyIds: map Location => Option #[pallet::storage] pub type LocationToCurrencyIds = - StorageMap<_, Twox64Concat, xcm::v3::Location, CurrencyId, OptionQuery>; + StorageMap<_, Twox64Concat, Location, CurrencyId, OptionQuery>; #[pallet::storage] pub type CurrencyIdToWeights = @@ -213,30 +213,6 @@ pub mod pallet { Pallet::::do_register_metadata(*currency_id, &metadata).expect("Token register"); } - for (currency, para_id, first_slot, last_slot) in self.vsbond.iter() { - match currency { - Token(symbol) | Native(symbol) => { - AssetIdMaps::::register_vsbond_metadata( - *symbol, - *para_id, - *first_slot, - *last_slot, - ) - .expect("VSBond register"); - }, - Token2(token_id) => { - AssetIdMaps::::register_vsbond2_metadata( - *token_id, - *para_id, - *first_slot, - *last_slot, - ) - .expect("VToken register"); - }, - _ => (), - } - } - for ¤cy in self.vcurrency.iter() { match currency { CurrencyId::VToken(symbol) => { @@ -247,68 +223,21 @@ pub mod pallet { AssetIdMaps::::register_vtoken2_metadata(token_id) .expect("VToken register"); }, - CurrencyId::VSToken(symbol) => { - AssetIdMaps::::register_vstoken_metadata(symbol) - .expect("VSToken register"); - }, - CurrencyId::VSToken2(token_id) => { - AssetIdMaps::::register_vstoken2_metadata(token_id) - .expect("VSToken register"); - }, _ => (), } } } } + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] #[pallet::without_storage_info] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); #[pallet::call] impl Pallet { - #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::register_native_asset())] - pub fn register_native_asset( - origin: OriginFor, - currency_id: CurrencyId, - location: Box, - metadata: Box>>, - ) -> DispatchResult { - T::RegisterOrigin::ensure_origin(origin)?; - - let location: Location = - (*location).try_into().map_err(|()| Error::::BadLocation)?; - Self::do_register_native_asset(currency_id, &location, &metadata)?; - - Self::deposit_event(Event::::AssetRegistered { - asset_id: AssetIds::NativeAssetId(currency_id), - metadata: *metadata, - }); - Ok(()) - } - - #[pallet::call_index(1)] - #[pallet::weight(T::WeightInfo::update_native_asset())] - pub fn update_native_asset( - origin: OriginFor, - currency_id: CurrencyId, - location: Box, - metadata: Box>>, - ) -> DispatchResult { - T::RegisterOrigin::ensure_origin(origin)?; - - let location: Location = - (*location).try_into().map_err(|()| Error::::BadLocation)?; - Self::do_update_native_asset(currency_id, &location, &metadata)?; - - Self::deposit_event(Event::::AssetUpdated { - asset_id: AssetIds::NativeAssetId(currency_id), - metadata: *metadata, - }); - Ok(()) - } - #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::register_token_metadata())] pub fn register_token_metadata( @@ -339,55 +268,6 @@ pub mod pallet { } } - #[pallet::call_index(4)] - #[pallet::weight(T::WeightInfo::register_vstoken_metadata())] - pub fn register_vstoken_metadata( - origin: OriginFor, - token_id: TokenId, - ) -> DispatchResult { - T::RegisterOrigin::ensure_origin(origin)?; - - if let Some(token_metadata) = CurrencyMetadatas::::get(CurrencyId::Token2(token_id)) - { - let vstoken_metadata = Self::convert_to_vstoken_metadata(token_metadata); - Self::do_register_metadata(CurrencyId::VSToken2(token_id), &vstoken_metadata)?; - - return Ok(()); - } else { - return Err(Error::::CurrencyIdNotExists)?; - } - } - - #[pallet::call_index(5)] - #[pallet::weight(T::WeightInfo::register_vsbond_metadata())] - pub fn register_vsbond_metadata( - origin: OriginFor, - token_id: TokenId, - para_id: ParaId, - first_slot: LeasePeriod, - last_slot: LeasePeriod, - ) -> DispatchResult { - T::RegisterOrigin::ensure_origin(origin)?; - - if let Some(token_metadata) = CurrencyMetadatas::::get(CurrencyId::Token2(token_id)) - { - let vsbond_metadata = Self::convert_to_vsbond_metadata( - token_metadata, - para_id, - first_slot, - last_slot, - ); - Self::do_register_metadata( - CurrencyId::VSBond2(token_id, para_id, first_slot, last_slot), - &vsbond_metadata, - )?; - - return Ok(()); - } else { - return Err(Error::::CurrencyIdNotExists)?; - } - } - #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::register_location())] pub fn register_location( @@ -419,16 +299,16 @@ pub mod pallet { let location: Location = (*location).try_into().map_err(|()| Error::::BadLocation)?; - let v3_location = xcm::v3::Location::try_from(location.clone()) - .map_err(|()| Error::::BadLocation)?; + let v4_location = + Location::try_from(location.clone()).map_err(|_| Error::::BadLocation)?; ensure!( CurrencyMetadatas::::get(currency_id).is_some(), Error::::CurrencyIdNotExists ); - LocationToCurrencyIds::::insert(v3_location, currency_id); - CurrencyIdToLocations::::insert(currency_id, v3_location); + LocationToCurrencyIds::::insert(v4_location.clone(), currency_id); + CurrencyIdToLocations::::insert(currency_id, v4_location); CurrencyIdToWeights::::insert(currency_id, weight); Pallet::::deposit_event(Event::::LocationSet { currency_id, location, weight }); @@ -484,31 +364,6 @@ impl Pallet { }) } - pub fn do_register_native_asset( - currency_id: CurrencyId, - location: &Location, - metadata: &AssetMetadata>, - ) -> DispatchResult { - let v3_location = - xcm::v3::Location::try_from(location.clone()).map_err(|()| Error::::BadLocation)?; - - ensure!(LocationToCurrencyIds::::get(v3_location).is_none(), Error::::AssetIdExisted); - ensure!( - CurrencyIdToLocations::::get(currency_id).is_none(), - Error::::LocationExisted - ); - ensure!( - AssetMetadatas::::get(AssetIds::NativeAssetId(currency_id)).is_none(), - Error::::AssetIdExisted - ); - - LocationToCurrencyIds::::insert(v3_location, currency_id); - CurrencyIdToLocations::::insert(currency_id, v3_location); - AssetMetadatas::::insert(AssetIds::NativeAssetId(currency_id), metadata); - - Ok(()) - } - pub fn convert_to_vtoken_metadata( token_metadata: AssetMetadata>, ) -> AssetMetadata> { @@ -519,34 +374,6 @@ impl Pallet { AssetMetadata { name, symbol, ..token_metadata } } - pub fn convert_to_vstoken_metadata( - token_metadata: AssetMetadata>, - ) -> AssetMetadata> { - let mut name = "Voucher Slot ".as_bytes().to_vec(); - name.extend_from_slice(&token_metadata.symbol); - let mut symbol = "vs".as_bytes().to_vec(); - symbol.extend_from_slice(&token_metadata.symbol); - AssetMetadata { name, symbol, ..token_metadata } - } - - pub fn convert_to_vsbond_metadata( - token_metadata: AssetMetadata>, - para_id: ParaId, - first_slot: LeasePeriod, - last_slot: LeasePeriod, - ) -> AssetMetadata> { - let name = scale_info::prelude::format!( - "vsBOND-{}-{}-{}-{}", - core::str::from_utf8(&token_metadata.symbol).unwrap_or(""), - para_id, - first_slot, - last_slot - ) - .as_bytes() - .to_vec(); - AssetMetadata { name: name.clone(), symbol: name, ..token_metadata } - } - pub fn do_register_metadata( currency_id: CurrencyId, metadata: &AssetMetadata>, @@ -564,15 +391,15 @@ impl Pallet { } pub fn do_register_location(currency_id: CurrencyId, location: &Location) -> DispatchResult { - let v3_location = - xcm::v3::Location::try_from(location.clone()).map_err(|()| Error::::BadLocation)?; + let v4_location = + Location::try_from(location.clone()).map_err(|_| Error::::BadLocation)?; ensure!( CurrencyMetadatas::::get(currency_id).is_some(), Error::::CurrencyIdNotExists ); ensure!( - LocationToCurrencyIds::::get(v3_location).is_none(), + LocationToCurrencyIds::::get(v4_location.clone()).is_none(), Error::::CurrencyIdExisted ); ensure!( @@ -580,8 +407,8 @@ impl Pallet { Error::::LocationExisted ); - LocationToCurrencyIds::::insert(v3_location, currency_id); - CurrencyIdToLocations::::insert(currency_id, v3_location); + LocationToCurrencyIds::::insert(v4_location.clone(), currency_id); + CurrencyIdToLocations::::insert(currency_id, v4_location); Ok(()) } @@ -596,34 +423,6 @@ impl Pallet { Ok(()) } - - fn do_update_native_asset( - currency_id: CurrencyId, - location: &Location, - metadata: &AssetMetadata>, - ) -> DispatchResult { - let v3_location = - xcm::v3::Location::try_from(location.clone()).map_err(|()| Error::::BadLocation)?; - - ensure!( - LocationToCurrencyIds::::get(v3_location).is_some(), - Error::::AssetIdNotExists - ); - ensure!( - CurrencyIdToLocations::::get(currency_id).is_some(), - Error::::LocationExisted - ); - ensure!( - AssetMetadatas::::get(AssetIds::NativeAssetId(currency_id)).is_some(), - Error::::AssetIdNotExists - ); - - LocationToCurrencyIds::::insert(v3_location, currency_id); - CurrencyIdToLocations::::insert(currency_id, v3_location); - AssetMetadatas::::insert(AssetIds::NativeAssetId(currency_id), metadata); - - Ok(()) - } } pub struct AssetIdMaps(sp_std::marker::PhantomData); @@ -648,8 +447,8 @@ impl CurrencyIdMapping Option { - let v3_location = xcm::v3::Location::try_from(multi_location).ok()?; - LocationToCurrencyIds::::get(v3_location) + let v4_location = Location::try_from(multi_location).ok()?; + LocationToCurrencyIds::::get(v4_location) } } @@ -752,55 +551,6 @@ impl CurrencyIdRegister for AssetIdMaps { } } - fn register_vstoken_metadata(token_symbol: TokenSymbol) -> sp_runtime::DispatchResult { - if let Some(token_metadata) = CurrencyMetadatas::::get(CurrencyId::Token(token_symbol)) { - let vstoken_metadata = Pallet::::convert_to_vstoken_metadata(token_metadata); - Pallet::::do_register_metadata( - CurrencyId::VSToken(token_symbol), - &vstoken_metadata, - )?; - - return Ok(()); - } else { - return Err(Error::::CurrencyIdNotExists.into()); - } - } - - fn register_vsbond_metadata( - token_symbol: TokenSymbol, - para_id: ParaId, - first_slot: LeasePeriod, - last_slot: LeasePeriod, - ) -> sp_runtime::DispatchResult { - let option_token_metadata = - if CurrencyMetadatas::::contains_key(CurrencyId::Token(token_symbol)) { - CurrencyMetadatas::::get(CurrencyId::Token(token_symbol)) - } else if token_symbol == TokenSymbol::BNC && - CurrencyMetadatas::::contains_key(CurrencyId::Native(token_symbol)) - { - CurrencyMetadatas::::get(CurrencyId::Native(token_symbol)) - } else { - None - }; - - if let Some(token_metadata) = option_token_metadata { - let vsbond_metadata = Pallet::::convert_to_vsbond_metadata( - token_metadata, - para_id, - first_slot, - last_slot, - ); - Pallet::::do_register_metadata( - CurrencyId::VSBond(token_symbol, para_id, first_slot, last_slot), - &vsbond_metadata, - )?; - - return Ok(()); - } else { - return Err(Error::::CurrencyIdNotExists.into()); - } - } - fn check_token2_registered(token_id: TokenId) -> bool { CurrencyMetadatas::::get(CurrencyId::Token2(token_id)).is_some() } @@ -809,20 +559,6 @@ impl CurrencyIdRegister for AssetIdMaps { CurrencyMetadatas::::get(CurrencyId::VToken2(token_id)).is_some() } - fn check_vstoken2_registered(token_id: TokenId) -> bool { - CurrencyMetadatas::::get(CurrencyId::VSToken2(token_id)).is_some() - } - - fn check_vsbond2_registered( - token_id: TokenId, - para_id: ParaId, - first_slot: LeasePeriod, - last_slot: LeasePeriod, - ) -> bool { - CurrencyMetadatas::::get(CurrencyId::VSBond2(token_id, para_id, first_slot, last_slot)) - .is_some() - } - fn register_vtoken2_metadata(token_id: TokenId) -> DispatchResult { if let Some(token_metadata) = CurrencyMetadatas::::get(CurrencyId::Token2(token_id)) { let vtoken_metadata = Pallet::::convert_to_vtoken_metadata(token_metadata); @@ -834,41 +570,6 @@ impl CurrencyIdRegister for AssetIdMaps { } } - fn register_vstoken2_metadata(token_id: TokenId) -> DispatchResult { - if let Some(token_metadata) = CurrencyMetadatas::::get(CurrencyId::Token2(token_id)) { - let vstoken_metadata = Pallet::::convert_to_vstoken_metadata(token_metadata); - Pallet::::do_register_metadata(CurrencyId::VSToken2(token_id), &vstoken_metadata)?; - - return Ok(()); - } else { - return Err(Error::::CurrencyIdNotExists.into()); - } - } - - fn register_vsbond2_metadata( - token_id: TokenId, - para_id: ParaId, - first_slot: LeasePeriod, - last_slot: LeasePeriod, - ) -> DispatchResult { - if let Some(token_metadata) = CurrencyMetadatas::::get(CurrencyId::Token2(token_id)) { - let vsbond_metadata = Pallet::::convert_to_vsbond_metadata( - token_metadata, - para_id, - first_slot, - last_slot, - ); - Pallet::::do_register_metadata( - CurrencyId::VSBond2(token_id, para_id, first_slot, last_slot), - &vsbond_metadata, - )?; - - return Ok(()); - } else { - return Err(Error::::CurrencyIdNotExists.into()); - } - } - fn register_blp_metadata(pool_id: PoolId, decimals: u8) -> DispatchResult { let name = scale_info::prelude::format!("Bifrost Stable Pool Token {}", pool_id) .as_bytes() @@ -931,10 +632,10 @@ where let AssetId(ref location) = asset_id.clone(); log::debug!(target: "asset-registry::weight", "buy_weight location: {:?}", location); - let v3_location = - xcm::v3::Location::try_from(location.clone()).map_err(|_| XcmError::InvalidLocation)?; + let v4_location = + Location::try_from(location.clone()).map_err(|_| XcmError::InvalidLocation)?; - if let Some(currency_id) = LocationToCurrencyIds::::get(v3_location) { + if let Some(currency_id) = LocationToCurrencyIds::::get(v4_location) { if let Some(currency_metadatas) = CurrencyMetadatas::::get(currency_id) { // The integration tests can ensure the ed is non-zero. let ed_ratio = FixedU128::saturating_from_rational( diff --git a/pallets/asset-registry/src/migrations/mod.rs b/pallets/asset-registry/src/migrations/mod.rs new file mode 100644 index 000000000..306e9e560 --- /dev/null +++ b/pallets/asset-registry/src/migrations/mod.rs @@ -0,0 +1,19 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . +pub mod v0; +pub mod v1; diff --git a/pallets/asset-registry/src/migrations/v0.rs b/pallets/asset-registry/src/migrations/v0.rs new file mode 100644 index 000000000..e194e5eef --- /dev/null +++ b/pallets/asset-registry/src/migrations/v0.rs @@ -0,0 +1,131 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 crate::*; +use bifrost_primitives::{CurrencyId, BNC}; +use frame_support::traits::{Get, OnRuntimeUpgrade}; +#[cfg(feature = "try-runtime")] +use sp_runtime::TryRuntimeError; +use xcm::opaque::v3::Junctions::X1; + +const LOG_TARGET: &str = "asset-registry::migration"; + +pub fn update_blp_metadata(pool_count: u32) -> Weight { + for pool_id in 0..pool_count { + if let Some(old_metadata) = CurrencyMetadatas::::get(CurrencyId::BLP(pool_id)) { + let name = scale_info::prelude::format!("Bifrost Stable Pool Token {}", pool_id) + .as_bytes() + .to_vec(); + let symbol = scale_info::prelude::format!("BLP{}", pool_id).as_bytes().to_vec(); + CurrencyMetadatas::::insert( + CurrencyId::BLP(pool_id), + &AssetMetadata { name, symbol, ..old_metadata }, + ) + } + } + + T::DbWeight::get().reads(pool_count.into()) + T::DbWeight::get().writes(pool_count.into()) +} + +const BNC_LOCATION: xcm::v3::Location = xcm::v3::Location { + parents: 0, + interior: X1(xcm::v3::Junction::GeneralKey { + length: 2, + data: [ + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ], + }), +}; + +pub struct InsertBNCMetadata(PhantomData); +impl OnRuntimeUpgrade for InsertBNCMetadata { + fn on_runtime_upgrade() -> Weight { + log::info!(target: LOG_TARGET, "Start to insert BNC Metadata..."); + CurrencyMetadatas::::insert( + BNC, + &AssetMetadata { + name: b"Bifrost Native Token".to_vec(), + symbol: b"BNC".to_vec(), + decimals: 12, + minimal_balance: BalanceOf::::unique_saturated_from(10_000_000_000u128), + }, + ); + + match Location::try_from(BNC_LOCATION) { + Ok(location) => { + CurrencyIdToLocations::::insert(BNC, location.clone()); + LocationToCurrencyIds::::insert(location, BNC); + + Weight::from(T::DbWeight::get().reads_writes(3 as u64 + 1, 3 as u64 + 1)) + }, + Err(_) => { + log::error!(target: LOG_TARGET, "Conversion failed from BNC_LOCATION to v4_bnc_location."); + Weight::from(T::DbWeight::get().reads_writes(1 as u64 + 1, 1 as u64 + 1)) + }, + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + let bnc_location = Location::try_from(BNC_LOCATION).unwrap(); + assert!(LocationToCurrencyIds::::get(bnc_location).is_none()); + + Ok(sp_std::vec![]) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_cnt: Vec) -> Result<(), TryRuntimeError> { + let metadata = CurrencyMetadatas::::get(BNC); + assert_eq!( + metadata, + Some(AssetMetadata { + name: b"Bifrost Native Token".to_vec(), + symbol: b"BNC".to_vec(), + decimals: 12, + minimal_balance: BalanceOf::::unique_saturated_from(10_000_000_000u128), + }) + ); + log::info!( + target: LOG_TARGET, + "InsertBNCMetadata post-migrate storage: {:?}", + metadata + ); + + let bnc_location = Location::try_from(BNC_LOCATION).unwrap(); + + let location = CurrencyIdToLocations::::get(BNC); + assert_eq!(location, Some(bnc_location.clone())); + + log::info!( + target: LOG_TARGET, + "InsertBNCMetadata post-migrate storage: {:?}", + location + ); + + let currency = LocationToCurrencyIds::::get(bnc_location); + assert_eq!(currency, Some(BNC)); + log::info!( + target: LOG_TARGET, + "InsertBNCMetadata post-migrate storage: {:?}", + currency + ); + + Ok(()) + } +} diff --git a/pallets/asset-registry/src/migrations/v1.rs b/pallets/asset-registry/src/migrations/v1.rs new file mode 100644 index 000000000..99a7481a2 --- /dev/null +++ b/pallets/asset-registry/src/migrations/v1.rs @@ -0,0 +1,118 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 crate::*; +use frame_support::traits::OnRuntimeUpgrade; +#[cfg(feature = "try-runtime")] +use sp_runtime::TryRuntimeError; + +const LOG_TARGET: &str = "asset-registry::migration"; + +pub struct MigrateToV1(sp_std::marker::PhantomData); +impl OnRuntimeUpgrade for MigrateToV1 { + fn on_runtime_upgrade() -> frame_support::weights::Weight { + // Check the storage version + let onchain_version = Pallet::::on_chain_storage_version(); + // Transform storage values + // We transform the storage values from the old into the new format. + if onchain_version < 1 { + let mut count = 0; + + log::info!(target: LOG_TARGET, "Start to migrate RegisterWhiteList storage..."); + CurrencyIdToLocations::::translate::( + |k: CurrencyId, value: xcm::v3::Location| { + log::info!(target: LOG_TARGET, "CurrencyIdToLocations Migrated to xcm::v4::Location for {:?}...", k); + let v4_location = xcm::v4::Location::try_from(value).unwrap(); + + count += 1; + Some(v4_location) + }, + ); + + log::info!(target: LOG_TARGET, "Start to migrate LocationToCurrencyIds storage..."); + let migrated_items: Vec<_> = LocationToCurrencyIds::::drain() + .map(|(v3_location, value)| { + log::info!(target: LOG_TARGET, "LocationToCurrencyIds Migrated to xcm::v4::Location for {:?}...", value); + let v4_location = xcm::v4::Location::try_from(v3_location).unwrap(); + + count += 1; + (v4_location, value) + }) + .collect(); + for (v4_location, value) in migrated_items { + LocationToCurrencyIds::::insert(v4_location, value); + } + + // Update the storage version + StorageVersion::new(1).put::>(); + + // Return the consumed weight + Weight::from(T::DbWeight::get().reads_writes(count as u64 + 1, count as u64 + 1)) + } else { + // We don't do anything here. + Weight::zero() + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + let currency_id_to_locations_count = CurrencyIdToLocations::::iter().count(); + log::info!(target: LOG_TARGET, "CurrencyIdToLocations pre-migrate storage count: {:?}", currency_id_to_locations_count); + + let location_to_currency_ids_count = LocationToCurrencyIds::::iter().count(); + log::info!(target: LOG_TARGET, "LocationToCurrencyIds pre-migrate storage count: {:?}", location_to_currency_ids_count); + + let combined_data = + (currency_id_to_locations_count as u64, location_to_currency_ids_count as u64); + + Ok(combined_data.encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(cnt: Vec) -> Result<(), TryRuntimeError> { + let (old_currency_id_to_locations_count, old_location_to_currency_ids_count): (u64, u64) = + Decode::decode(&mut cnt.as_slice()).expect( + "the state parameter should be something that was generated by pre_upgrade", + ); + + let new_currency_id_to_locations_count = CurrencyIdToLocations::::iter().count(); + log::info!( + target: LOG_TARGET, + "CurrencyIdToLocations post-migrate storage count: {:?}", + new_currency_id_to_locations_count + ); + + let new_location_to_currency_ids_count = LocationToCurrencyIds::::iter().count(); + log::info!( + target: LOG_TARGET, + "LocationToCurrencyIds post-migrate storage count: {:?}", + new_location_to_currency_ids_count + ); + + ensure!( + new_currency_id_to_locations_count as u64 == old_currency_id_to_locations_count, + "Post-migration CurrencyIdToLocations count does not match pre-migration count" + ); + ensure!( + new_location_to_currency_ids_count as u64 == old_location_to_currency_ids_count, + "Post-migration LocationToCurrencyIds count does not match pre-migration count" + ); + + Ok(()) + } +} diff --git a/pallets/asset-registry/src/tests.rs b/pallets/asset-registry/src/tests.rs index 470a22438..f16a42416 100644 --- a/pallets/asset-registry/src/tests.rs +++ b/pallets/asset-registry/src/tests.rs @@ -21,7 +21,6 @@ #![cfg(test)] use super::*; -use bifrost_primitives::TokenSymbol; use frame_support::{assert_noop, assert_ok}; use mock::{ AssetRegistry, CouncilAccount, ExtBuilder, Runtime, RuntimeEvent, RuntimeOrigin, System, @@ -36,125 +35,6 @@ fn versioned_multi_location_convert_work() { }); } -#[test] -fn register_native_asset_works() { - ExtBuilder::default().build().execute_with(|| { - let versioned_location = VersionedLocation::V4(Location::from([Parachain(1000)])); - - assert_ok!(AssetRegistry::register_native_asset( - RuntimeOrigin::signed(CouncilAccount::get()), - Token(TokenSymbol::DOT), - Box::new(versioned_location.clone()), - Box::new(AssetMetadata { - name: b"Token Name".to_vec(), - symbol: b"TN".to_vec(), - decimals: 12, - minimal_balance: 1, - }) - )); - System::assert_last_event(RuntimeEvent::AssetRegistry(Event::AssetRegistered { - asset_id: AssetIds::NativeAssetId(Token(TokenSymbol::DOT)), - metadata: AssetMetadata { - name: b"Token Name".to_vec(), - symbol: b"TN".to_vec(), - decimals: 12, - minimal_balance: 1, - }, - })); - - assert_eq!( - AssetMetadatas::::get(AssetIds::NativeAssetId(Token(TokenSymbol::DOT))), - Some(AssetMetadata { - name: b"Token Name".to_vec(), - symbol: b"TN".to_vec(), - decimals: 12, - minimal_balance: 1, - }) - ); - // Can't duplicate - assert_noop!( - AssetRegistry::register_native_asset( - RuntimeOrigin::signed(CouncilAccount::get()), - Token(TokenSymbol::DOT), - Box::new(versioned_location), - Box::new(AssetMetadata { - name: b"Token Name".to_vec(), - symbol: b"TN".to_vec(), - decimals: 12, - minimal_balance: 1, - }) - ), - Error::::AssetIdExisted - ); - }); -} - -#[test] -fn update_native_asset_works() { - let versioned_location = VersionedLocation::V4(Location::from([Parachain(1000)])); - - ExtBuilder::default().build().execute_with(|| { - assert_noop!( - AssetRegistry::update_native_asset( - RuntimeOrigin::signed(CouncilAccount::get()), - Token(TokenSymbol::DOT), - Box::new(versioned_location.clone()), - Box::new(AssetMetadata { - name: b"New Token Name".to_vec(), - symbol: b"NTN".to_vec(), - decimals: 13, - minimal_balance: 2, - }) - ), - Error::::AssetIdNotExists - ); - - assert_ok!(AssetRegistry::register_native_asset( - RuntimeOrigin::signed(CouncilAccount::get()), - Token(TokenSymbol::DOT), - Box::new(versioned_location.clone()), - Box::new(AssetMetadata { - name: b"Token Name".to_vec(), - symbol: b"TN".to_vec(), - decimals: 12, - minimal_balance: 1, - }) - )); - - assert_ok!(AssetRegistry::update_native_asset( - RuntimeOrigin::signed(CouncilAccount::get()), - Token(TokenSymbol::DOT), - Box::new(versioned_location.clone()), - Box::new(AssetMetadata { - name: b"New Token Name".to_vec(), - symbol: b"NTN".to_vec(), - decimals: 13, - minimal_balance: 2, - }) - )); - - System::assert_last_event(RuntimeEvent::AssetRegistry(Event::AssetUpdated { - asset_id: AssetIds::NativeAssetId(Token(TokenSymbol::DOT)), - metadata: AssetMetadata { - name: b"New Token Name".to_vec(), - symbol: b"NTN".to_vec(), - decimals: 13, - minimal_balance: 2, - }, - })); - - assert_eq!( - AssetMetadatas::::get(AssetIds::NativeAssetId(Token(TokenSymbol::DOT))), - Some(AssetMetadata { - name: b"New Token Name".to_vec(), - symbol: b"NTN".to_vec(), - decimals: 13, - minimal_balance: 2, - }) - ); - }); -} - #[test] fn register_token_metadata_should_work() { ExtBuilder::default().build().execute_with(|| { @@ -214,86 +94,6 @@ fn register_vtoken_metadata_should_work() { }) } -#[test] -fn register_vstoken_metadata_should_work() { - ExtBuilder::default().build().execute_with(|| { - let metadata = AssetMetadata { - name: b"KSM Native Token".to_vec(), - symbol: b"KSM".to_vec(), - decimals: 12, - minimal_balance: 0, - }; - let v_metadata = AssetMetadata { - name: b"Voucher Slot KSM".to_vec(), - symbol: b"vsKSM".to_vec(), - decimals: 12, - minimal_balance: 0, - }; - assert_noop!( - AssetRegistry::register_vtoken_metadata( - RuntimeOrigin::signed(CouncilAccount::get()), - 1 - ), - Error::::CurrencyIdNotExists - ); - - assert_ok!(AssetRegistry::register_token_metadata( - RuntimeOrigin::signed(CouncilAccount::get()), - Box::new(metadata.clone()) - )); - - assert_ok!(AssetRegistry::register_vstoken_metadata( - RuntimeOrigin::signed(CouncilAccount::get()), - 0 - )); - - assert_eq!( - CurrencyMetadatas::::get(CurrencyId::VSToken2(0)), - Some(v_metadata.clone()) - ) - }) -} - -#[test] -fn register_vsbond_metadata_should_work() { - ExtBuilder::default().build().execute_with(|| { - let metadata = AssetMetadata { - name: b"KSM Native Token".to_vec(), - symbol: b"KSM".to_vec(), - decimals: 12, - minimal_balance: 0, - }; - let name = "vsBOND-KSM-2001-10-20".as_bytes().to_vec(); - let v_metadata = - AssetMetadata { name: name.clone(), symbol: name, decimals: 12, minimal_balance: 0 }; - assert_noop!( - AssetRegistry::register_vtoken_metadata( - RuntimeOrigin::signed(CouncilAccount::get()), - 1 - ), - Error::::CurrencyIdNotExists - ); - - assert_ok!(AssetRegistry::register_token_metadata( - RuntimeOrigin::signed(CouncilAccount::get()), - Box::new(metadata.clone()) - )); - - assert_ok!(AssetRegistry::register_vsbond_metadata( - RuntimeOrigin::signed(CouncilAccount::get()), - 0, - 2001, - 10, - 20 - )); - - assert_eq!( - CurrencyMetadatas::::get(CurrencyId::VSBond2(0, 2001, 10, 20)), - Some(v_metadata.clone()) - ) - }) -} - #[test] fn register_multilocation_should_work() { ExtBuilder::default().build().execute_with(|| { @@ -305,7 +105,7 @@ fn register_multilocation_should_work() { }; let versioned_location = VersionedLocation::V4(Location::new(1, [Parachain(2001)])); - let location: xcm::v3::Location = versioned_location.clone().try_into().unwrap(); + let location: Location = versioned_location.clone().try_into().unwrap(); assert_noop!( AssetRegistry::register_location( @@ -339,7 +139,7 @@ fn register_multilocation_should_work() { Error::::CurrencyIdExisted ); - assert_eq!(LocationToCurrencyIds::::get(location), Some(Token2(0))); + assert_eq!(LocationToCurrencyIds::::get(location.clone()), Some(Token2(0))); assert_eq!(CurrencyIdToLocations::::get(Token2(0)), Some(location)); assert_eq!( CurrencyIdToWeights::::get(Token2(0)), @@ -358,7 +158,7 @@ fn force_set_multilocation_should_work() { minimal_balance: 0, }; let versioned_location = VersionedLocation::V4(Location::new(1, [Parachain(2001)])); - let location: xcm::v3::Location = versioned_location.clone().try_into().unwrap(); + let location: Location = versioned_location.clone().try_into().unwrap(); assert_noop!( AssetRegistry::force_set_location( @@ -389,7 +189,7 @@ fn force_set_multilocation_should_work() { Weight::from_parts(2000_000_000, 0) )); - assert_eq!(LocationToCurrencyIds::::get(location), Some(Token2(0))); + assert_eq!(LocationToCurrencyIds::::get(location.clone()), Some(Token2(0))); assert_eq!(CurrencyIdToLocations::::get(Token2(0)), Some(location)); assert_eq!( CurrencyIdToWeights::::get(Token2(0)), diff --git a/pallets/asset-registry/src/weights.rs b/pallets/asset-registry/src/weights.rs index 162c6fad6..b16619e2e 100644 --- a/pallets/asset-registry/src/weights.rs +++ b/pallets/asset-registry/src/weights.rs @@ -53,12 +53,8 @@ use sp_std::marker::PhantomData; /// Weight functions needed for bifrost_asset_registry. pub trait WeightInfo { - fn register_native_asset() -> Weight; - fn update_native_asset() -> Weight; fn register_token_metadata() -> Weight; fn register_vtoken_metadata() -> Weight; - fn register_vstoken_metadata() -> Weight; - fn register_vsbond_metadata() -> Weight; fn register_location() -> Weight; fn force_set_location() -> Weight; fn update_currency_metadata() -> Weight; @@ -66,36 +62,6 @@ pub trait WeightInfo { // For backwards compatibility and tests impl WeightInfo for () { - /// Storage: AssetRegistry LocationToCurrencyIds (r:1 w:1) - /// Proof Skipped: AssetRegistry LocationToCurrencyIds (max_values: None, max_size: None, mode: Measured) - /// Storage: AssetRegistry CurrencyIdToLocations (r:1 w:1) - /// Proof Skipped: AssetRegistry CurrencyIdToLocations (max_values: None, max_size: None, mode: Measured) - /// Storage: AssetRegistry AssetMetadatas (r:1 w:1) - /// Proof Skipped: AssetRegistry AssetMetadatas (max_values: None, max_size: None, mode: Measured) - fn register_native_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `118` - // Estimated: `3583` - // Minimum execution time: 52_056_000 picoseconds. - Weight::from_parts(53_012_000, 3583) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) - } - /// Storage: AssetRegistry LocationToCurrencyIds (r:1 w:1) - /// Proof Skipped: AssetRegistry LocationToCurrencyIds (max_values: None, max_size: None, mode: Measured) - /// Storage: AssetRegistry CurrencyIdToLocations (r:1 w:1) - /// Proof Skipped: AssetRegistry CurrencyIdToLocations (max_values: None, max_size: None, mode: Measured) - /// Storage: AssetRegistry AssetMetadatas (r:1 w:1) - /// Proof Skipped: AssetRegistry AssetMetadatas (max_values: None, max_size: None, mode: Measured) - fn update_native_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `250` - // Estimated: `3715` - // Minimum execution time: 59_891_000 picoseconds. - Weight::from_parts(60_869_000, 3715) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) - } /// Storage: AssetRegistry NextTokenId (r:1 w:1) /// Proof Skipped: AssetRegistry NextTokenId (max_values: Some(1), max_size: None, mode: Measured) /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:1) @@ -120,28 +86,6 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: AssetRegistry CurrencyMetadatas (r:2 w:1) - /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - fn register_vstoken_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `705` - // Estimated: `6645` - // Minimum execution time: 52_491_000 picoseconds. - Weight::from_parts(53_682_000, 6645) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - /// Storage: AssetRegistry CurrencyMetadatas (r:2 w:1) - /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - fn register_vsbond_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `763` - // Estimated: `6703` - // Minimum execution time: 55_589_000 picoseconds. - Weight::from_parts(56_804_000, 6703) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) /// Storage: AssetRegistry LocationToCurrencyIds (r:1 w:1) diff --git a/pallets/deprecated/asset-registry/Cargo.toml b/pallets/deprecated/asset-registry/Cargo.toml new file mode 100644 index 000000000..c6e22cd68 --- /dev/null +++ b/pallets/deprecated/asset-registry/Cargo.toml @@ -0,0 +1,51 @@ +[package] +name = "bifrost-asset-registry" +version = "0.8.0" +authors = ["Edwin Wang "] +edition = "2021" + +[dependencies] +log = { workspace = true } +serde = { workspace = true } +scale-info = { workspace = true, features = ["derive"] } +parity-scale-codec = { workspace = true, features = ["derive"] } +sp-runtime = { workspace = true } +sp-std = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-benchmarking = { workspace = true, optional = true } +bifrost-primitives = { workspace = true } + +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } + +[dev-dependencies] +sp-io = { workspace = true } +pallet-balances = { workspace = true } + +[features] +default = ["std"] +std = [ + "serde/std", + "log/std", + "parity-scale-codec/std", + "scale-info/std", + "sp-runtime/std", + "sp-std/std", + "frame-support/std", + "frame-system/std", + "frame-benchmarking?/std", + "bifrost-primitives/std", + "xcm/std", + "xcm-builder/std", + "xcm-executor/std", +] +try-runtime = ["frame-support/try-runtime"] + +runtime-benchmarks = [ + "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", +] diff --git a/pallets/deprecated/asset-registry/src/benchmarking.rs b/pallets/deprecated/asset-registry/src/benchmarking.rs new file mode 100644 index 000000000..bb7b63b13 --- /dev/null +++ b/pallets/deprecated/asset-registry/src/benchmarking.rs @@ -0,0 +1,309 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . + +#![cfg(feature = "runtime-benchmarks")] + +use super::*; +use crate::Pallet as AssetRegistry; +use bifrost_primitives::{CurrencyId, TokenSymbol}; +use frame_benchmarking::{benchmarks, v1::BenchmarkError}; +use frame_support::{assert_ok, traits::UnfilteredDispatchable}; +use sp_runtime::traits::UniqueSaturatedFrom; + +benchmarks! { + register_native_asset { + let origin = T::RegisterOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let versioned_location = VersionedLocation::V4(Location::from([Parachain(1000)])); + + let call = Call::::register_native_asset { + currency_id: Token(TokenSymbol::DOT), + location: Box::new(versioned_location.clone()), + metadata: Box::new(AssetMetadata { + name: b"Token Name".to_vec(), + symbol: b"TN".to_vec(), + decimals: 12, + minimal_balance: BalanceOf::::unique_saturated_from(1u128), + }) + }; + }: {call.dispatch_bypass_filter(origin)?} + verify { + assert_eq!( + AssetMetadatas::::get(AssetIds::NativeAssetId(Token( + TokenSymbol::DOT + ))), + Some(AssetMetadata { + name: b"Token Name".to_vec(), + symbol: b"TN".to_vec(), + decimals: 12, + minimal_balance: BalanceOf::::unique_saturated_from(1u128), + }) + ); + } + + update_native_asset { + let origin = T::RegisterOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let versioned_location = VersionedLocation::V4(Location::from([Parachain(1000)])); + + assert_ok!(AssetRegistry::::register_native_asset( + origin.clone(), + Token(TokenSymbol::DOT), + Box::new(versioned_location.clone()), + Box::new(AssetMetadata { + name: b"Token Name".to_vec(), + symbol: b"TN".to_vec(), + decimals: 12, + minimal_balance: BalanceOf::::unique_saturated_from(1u128), + }) + )); + + let call = Call::::update_native_asset { + currency_id: Token(TokenSymbol::DOT), + location: Box::new(versioned_location.clone()), + metadata: Box::new(AssetMetadata { + name: b"Token Name".to_vec(), + symbol: b"TN".to_vec(), + decimals: 13, + minimal_balance: BalanceOf::::unique_saturated_from(2u128), + }) + }; + }: {call.dispatch_bypass_filter(origin)?} + verify { + assert_eq!( + AssetMetadatas::::get(AssetIds::NativeAssetId(Token( + TokenSymbol::DOT + ))), + Some(AssetMetadata { + name: b"Token Name".to_vec(), + symbol: b"TN".to_vec(), + decimals: 13, + minimal_balance: BalanceOf::::unique_saturated_from(2u128), + }) + ); + } + + register_token_metadata { + let origin = T::RegisterOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let metadata = AssetMetadata { + name: b"Bifrost Native Coin".to_vec(), + symbol: b"BNC".to_vec(), + decimals: 12, + minimal_balance: BalanceOf::::unique_saturated_from(0u128), + }; + + let call = Call::::register_token_metadata { + metadata: Box::new(metadata.clone()) + }; + }: {call.dispatch_bypass_filter(origin)?} + verify { + assert_eq!(CurrencyMetadatas::::get(Token2(0)), Some(metadata.clone())) + } + + register_vtoken_metadata { + let origin = T::RegisterOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let metadata = AssetMetadata { + name: b"Bifrost Native Coin".to_vec(), + symbol: b"BNC".to_vec(), + decimals: 12, + minimal_balance: BalanceOf::::unique_saturated_from(0u128), + }; + let v_metadata = AssetMetadata { + name: b"Voucher BNC".to_vec(), + symbol: b"vBNC".to_vec(), + decimals: 12, + minimal_balance: BalanceOf::::unique_saturated_from(0u128), + }; + assert_ok!(AssetRegistry::::register_token_metadata( + origin.clone(), + Box::new(metadata.clone()) + )); + + let call = Call::::register_vtoken_metadata { + token_id: 0 + }; + }: {call.dispatch_bypass_filter(origin)?} + verify { + assert_eq!( + CurrencyMetadatas::::get(CurrencyId::VToken2(0)), + Some(v_metadata.clone()) + ) + } + + register_vstoken_metadata { + let origin = T::RegisterOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let metadata = AssetMetadata { + name: b"KSM Native Token".to_vec(), + symbol: b"KSM".to_vec(), + decimals: 12, + minimal_balance: BalanceOf::::unique_saturated_from(0u128), + }; + let v_metadata = AssetMetadata { + name: b"Voucher Slot KSM".to_vec(), + symbol: b"vsKSM".to_vec(), + decimals: 12, + minimal_balance: BalanceOf::::unique_saturated_from(0u128), + }; + assert_ok!(AssetRegistry::::register_token_metadata( + origin.clone(), + Box::new(metadata.clone()) + )); + + let call = Call::::register_vstoken_metadata { + token_id: 0 + }; + }: {call.dispatch_bypass_filter(origin)?} + verify { + assert_eq!( + CurrencyMetadatas::::get(CurrencyId::VSToken2(0)), + Some(v_metadata.clone()) + ) + } + + register_vsbond_metadata { + let origin = T::RegisterOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let metadata = AssetMetadata { + name: b"KSM Native Token".to_vec(), + symbol: b"KSM".to_vec(), + decimals: 12, + minimal_balance: BalanceOf::::unique_saturated_from(0u128), + }; + let name = "vsBOND-KSM-2001-10-20".as_bytes().to_vec(); + let v_metadata = AssetMetadata { + name: name.clone(), + symbol: name, + decimals: 12, + minimal_balance: BalanceOf::::unique_saturated_from(0u128), + }; + assert_ok!(AssetRegistry::::register_token_metadata( + origin.clone(), + Box::new(metadata.clone()) + )); + + let call = Call::::register_vsbond_metadata { + token_id: 0, + para_id:2001, + first_slot:10, + last_slot:20 + }; + }: {call.dispatch_bypass_filter(origin)?} + verify { + assert_eq!( + CurrencyMetadatas::::get(CurrencyId::VSBond2(0, 2001, 10, 20)), + Some(v_metadata.clone()) + ) + } + + register_location { + let origin = T::RegisterOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let metadata = AssetMetadata { + name: b"Bifrost Native Coin".to_vec(), + symbol: b"BNC".to_vec(), + decimals: 12, + minimal_balance: BalanceOf::::unique_saturated_from(0u128), + }; + let versioned_location = VersionedLocation::V4(Location::new(1, [Parachain(2001)])); + + let location: xcm::v3::Location = versioned_location.clone().try_into().unwrap(); + + assert_ok!(AssetRegistry::::register_token_metadata( + origin.clone(), + Box::new(metadata.clone()) + )); + + let call = Call::::register_location { + currency_id: Token2(0), + location:Box::new(versioned_location.clone()), + weight:Weight::from_parts(2000_000_000, u64::MAX), + }; + }: {call.dispatch_bypass_filter(origin)?} + verify { + assert_eq!( + LocationToCurrencyIds::::get(location), + Some(Token2(0)) + ); + assert_eq!( + CurrencyIdToLocations::::get(Token2(0)), + Some(location) + ); + assert_eq!(CurrencyIdToWeights::::get(Token2(0)), Some(Weight::from_parts(2000_000_000, u64::MAX))); + } + + force_set_location { + let origin = T::RegisterOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let metadata = AssetMetadata { + name: b"Bifrost Native Coin".to_vec(), + symbol: b"BNC".to_vec(), + decimals: 12, + minimal_balance: BalanceOf::::unique_saturated_from(0u128), + }; + let versioned_location = VersionedLocation::V4(Location::new(1, [Parachain(2001)])); + + let location: xcm::v3::Location = versioned_location.clone().try_into().unwrap(); + + assert_ok!(AssetRegistry::::register_token_metadata( + origin.clone(), + Box::new(metadata.clone()) + )); + + let call = Call::::force_set_location { + currency_id: Token2(0), + location:Box::new(versioned_location.clone()), + weight:Weight::from_parts(2000_000_000, u64::MAX), + }; + }: {call.dispatch_bypass_filter(origin)?} + + update_currency_metadata { + let origin = T::RegisterOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + + assert_ok!(AssetRegistry::::register_token_metadata( + origin.clone(), + Box::new(AssetMetadata { + name: b"Old Token Name".to_vec(), + symbol: b"OTN".to_vec(), + decimals: 10, + minimal_balance: BalanceOf::::unique_saturated_from(1u128), + }) + )); + + let call = Call::::update_currency_metadata { + currency_id: CurrencyId::Token2(0), + asset_name: Some(b"Token Name".to_vec()), + asset_symbol: Some(b"TN".to_vec()), + asset_decimals : Some(12), + asset_minimal_balance : Some(BalanceOf::::unique_saturated_from(1000u128)), + }; + + }: {call.dispatch_bypass_filter(origin)?} + verify { + assert_eq!( + CurrencyMetadatas::::get(CurrencyId::Token2(0)), + Some(AssetMetadata { + name: b"Token Name".to_vec(), + symbol: b"TN".to_vec(), + decimals: 12, + minimal_balance: BalanceOf::::unique_saturated_from(1000u128), + }) + ); + } + + impl_benchmark_test_suite!( + AssetRegistry, + crate::mock::ExtBuilder::default().build(), + crate::mock::Runtime +); + +} diff --git a/pallets/deprecated/asset-registry/src/lib.rs b/pallets/deprecated/asset-registry/src/lib.rs new file mode 100644 index 000000000..c35d14481 --- /dev/null +++ b/pallets/deprecated/asset-registry/src/lib.rs @@ -0,0 +1,1013 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . + +//! # Asset Registry Module +//! +//! Local and foreign assets management. The foreign assets can be updated without runtime upgrade. + +#![cfg_attr(not(feature = "std"), no_std)] + +pub use bifrost_primitives::{ + AssetIds, CurrencyId, + CurrencyId::{Native, Token, Token2}, + CurrencyIdConversion, CurrencyIdMapping, CurrencyIdRegister, ForeignAssetId, LeasePeriod, + ParaId, PoolId, TokenId, TokenInfo, TokenSymbol, +}; +use frame_support::{ + dispatch::DispatchResult, + ensure, + pallet_prelude::*, + traits::{Currency, EnsureOrigin}, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, +}; +use frame_system::pallet_prelude::*; +use scale_info::{prelude::string::String, TypeInfo}; +use sp_runtime::{ + traits::{One, UniqueSaturatedFrom}, + ArithmeticError, FixedPointNumber, FixedU128, RuntimeDebug, +}; +use sp_std::{boxed::Box, vec::Vec}; +use xcm::{ + opaque::lts::XcmContext, + v3::MultiLocation, + v4::{prelude::*, Asset, Location}, + VersionedLocation, +}; +use xcm_builder::TakeRevenue; +use xcm_executor::{traits::WeightTrader, AssetsInHolding}; + +pub mod migration; +mod mock; +mod tests; +pub mod weights; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + +pub use pallet::*; +pub use weights::WeightInfo; + +/// Type alias for currency balance. +pub type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// Currency type for withdraw and balance storage. + type Currency: Currency; + + /// Required origin for registering asset. + type RegisterOrigin: EnsureOrigin; + + /// Weight information for the extrinsics in this module. + type WeightInfo: WeightInfo; + } + + #[derive(Clone, Eq, PartialEq, RuntimeDebug, Encode, Decode, TypeInfo)] + pub struct AssetMetadata { + pub name: Vec, + pub symbol: Vec, + pub decimals: u8, + pub minimal_balance: Balance, + } + + #[pallet::error] + pub enum Error { + /// The given location could not be used (e.g. because it cannot be expressed in the + /// desired version of XCM). + BadLocation, + /// Location existed + LocationExisted, + /// AssetId not exists + AssetIdNotExists, + /// AssetId exists + AssetIdExisted, + /// CurrencyId not exists + CurrencyIdNotExists, + /// CurrencyId exists + CurrencyIdExisted, + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// The asset registered. + AssetRegistered { asset_id: AssetIds, metadata: AssetMetadata> }, + /// The asset updated. + AssetUpdated { asset_id: AssetIds, metadata: AssetMetadata> }, + /// The CurrencyId registered. + CurrencyIdRegistered { currency_id: CurrencyId, metadata: AssetMetadata> }, + /// Location Force set. + LocationSet { currency_id: CurrencyId, location: Location, weight: Weight }, + /// The CurrencyId updated. + CurrencyIdUpdated { currency_id: CurrencyId, metadata: AssetMetadata> }, + } + + /// Next available Foreign AssetId ID. + /// + /// NextForeignAssetId: ForeignAssetId + #[pallet::storage] + pub type NextForeignAssetId = StorageValue<_, ForeignAssetId, ValueQuery>; + + /// Next available TokenId ID. + /// + /// NextTokenId: TokenId + #[pallet::storage] + pub type NextTokenId = StorageValue<_, TokenId, ValueQuery>; + + /// The storages for Locations. + /// + /// CurrencyIdToLocations: map CurrencyId => Option + #[pallet::storage] + pub type CurrencyIdToLocations = + StorageMap<_, Twox64Concat, CurrencyId, xcm::v3::Location, OptionQuery>; + + /// The storages for CurrencyIds. + /// + /// LocationToCurrencyIds: map Location => Option + #[pallet::storage] + pub type LocationToCurrencyIds = + StorageMap<_, Twox64Concat, xcm::v3::Location, CurrencyId, OptionQuery>; + + #[pallet::storage] + pub type CurrencyIdToWeights = + StorageMap<_, Twox64Concat, CurrencyId, Weight, OptionQuery>; + + /// The storages for AssetMetadatas. + /// + /// AssetMetadatas: map AssetIds => Option + #[pallet::storage] + pub type AssetMetadatas = + StorageMap<_, Twox64Concat, AssetIds, AssetMetadata>, OptionQuery>; + + /// The storages for AssetMetadata. + /// + /// CurrencyMetadatas: map CurrencyId => Option + #[pallet::storage] + pub type CurrencyMetadatas = + StorageMap<_, Twox64Concat, CurrencyId, AssetMetadata>, OptionQuery>; + + #[pallet::genesis_config] + #[derive(frame_support::DefaultNoBound)] + pub struct GenesisConfig { + pub currency: Vec<(CurrencyId, BalanceOf, Option<(String, String, u8)>)>, + pub vcurrency: Vec, + pub vsbond: Vec<(CurrencyId, u32, u32, u32)>, + pub phantom: PhantomData, + } + + #[pallet::genesis_build] + impl BuildGenesisConfig for GenesisConfig { + fn build(&self) { + for (currency_id, metadata) in + self.currency.iter().map(|(currency_id, minimal_balance, metadata)| { + ( + currency_id, + match &metadata { + None => AssetMetadata { + name: currency_id + .name() + .map(|s| s.as_bytes().to_vec()) + .unwrap_or_default(), + symbol: currency_id + .symbol() + .map(|s| s.as_bytes().to_vec()) + .unwrap_or_default(), + decimals: currency_id.decimals().unwrap_or_default(), + minimal_balance: *minimal_balance, + }, + Some(metadata) => AssetMetadata { + name: metadata.0.as_bytes().to_vec(), + symbol: metadata.1.as_bytes().to_vec(), + decimals: metadata.2, + minimal_balance: *minimal_balance, + }, + }, + ) + }) { + if let CurrencyId::Token2(_token_id) = *currency_id { + Pallet::::get_next_token_id().expect("Token register"); + } + Pallet::::do_register_metadata(*currency_id, &metadata).expect("Token register"); + } + + for (currency, para_id, first_slot, last_slot) in self.vsbond.iter() { + match currency { + Token(symbol) | Native(symbol) => { + AssetIdMaps::::register_vsbond_metadata( + *symbol, + *para_id, + *first_slot, + *last_slot, + ) + .expect("VSBond register"); + }, + Token2(token_id) => { + AssetIdMaps::::register_vsbond2_metadata( + *token_id, + *para_id, + *first_slot, + *last_slot, + ) + .expect("VToken register"); + }, + _ => (), + } + } + + for ¤cy in self.vcurrency.iter() { + match currency { + CurrencyId::VToken(symbol) => { + AssetIdMaps::::register_vtoken_metadata(symbol) + .expect("VToken register"); + }, + CurrencyId::VToken2(token_id) => { + AssetIdMaps::::register_vtoken2_metadata(token_id) + .expect("VToken register"); + }, + CurrencyId::VSToken(symbol) => { + AssetIdMaps::::register_vstoken_metadata(symbol) + .expect("VSToken register"); + }, + CurrencyId::VSToken2(token_id) => { + AssetIdMaps::::register_vstoken2_metadata(token_id) + .expect("VSToken register"); + }, + _ => (), + } + } + } + } + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight(T::WeightInfo::register_native_asset())] + pub fn register_native_asset( + origin: OriginFor, + currency_id: CurrencyId, + location: Box, + metadata: Box>>, + ) -> DispatchResult { + T::RegisterOrigin::ensure_origin(origin)?; + + let location: Location = + (*location).try_into().map_err(|()| Error::::BadLocation)?; + Self::do_register_native_asset(currency_id, &location, &metadata)?; + + Self::deposit_event(Event::::AssetRegistered { + asset_id: AssetIds::NativeAssetId(currency_id), + metadata: *metadata, + }); + Ok(()) + } + + #[pallet::call_index(1)] + #[pallet::weight(T::WeightInfo::update_native_asset())] + pub fn update_native_asset( + origin: OriginFor, + currency_id: CurrencyId, + location: Box, + metadata: Box>>, + ) -> DispatchResult { + T::RegisterOrigin::ensure_origin(origin)?; + + let location: Location = + (*location).try_into().map_err(|()| Error::::BadLocation)?; + Self::do_update_native_asset(currency_id, &location, &metadata)?; + + Self::deposit_event(Event::::AssetUpdated { + asset_id: AssetIds::NativeAssetId(currency_id), + metadata: *metadata, + }); + Ok(()) + } + + #[pallet::call_index(2)] + #[pallet::weight(T::WeightInfo::register_token_metadata())] + pub fn register_token_metadata( + origin: OriginFor, + metadata: Box>>, + ) -> DispatchResult { + T::RegisterOrigin::ensure_origin(origin)?; + + let token_id = Self::get_next_token_id()?; + let currency_id = Token2(token_id); + Self::do_register_metadata(currency_id, &metadata)?; + + Ok(()) + } + + #[pallet::call_index(3)] + #[pallet::weight(T::WeightInfo::register_vtoken_metadata())] + pub fn register_vtoken_metadata(origin: OriginFor, token_id: TokenId) -> DispatchResult { + T::RegisterOrigin::ensure_origin(origin)?; + + if let Some(token_metadata) = CurrencyMetadatas::::get(Token2(token_id)) { + let vtoken_metadata = Self::convert_to_vtoken_metadata(token_metadata); + Self::do_register_metadata(CurrencyId::VToken2(token_id), &vtoken_metadata)?; + + return Ok(()); + } else { + return Err(Error::::CurrencyIdNotExists)?; + } + } + + #[pallet::call_index(4)] + #[pallet::weight(T::WeightInfo::register_vstoken_metadata())] + pub fn register_vstoken_metadata( + origin: OriginFor, + token_id: TokenId, + ) -> DispatchResult { + T::RegisterOrigin::ensure_origin(origin)?; + + if let Some(token_metadata) = CurrencyMetadatas::::get(CurrencyId::Token2(token_id)) + { + let vstoken_metadata = Self::convert_to_vstoken_metadata(token_metadata); + Self::do_register_metadata(CurrencyId::VSToken2(token_id), &vstoken_metadata)?; + + return Ok(()); + } else { + return Err(Error::::CurrencyIdNotExists)?; + } + } + + #[pallet::call_index(5)] + #[pallet::weight(T::WeightInfo::register_vsbond_metadata())] + pub fn register_vsbond_metadata( + origin: OriginFor, + token_id: TokenId, + para_id: ParaId, + first_slot: LeasePeriod, + last_slot: LeasePeriod, + ) -> DispatchResult { + T::RegisterOrigin::ensure_origin(origin)?; + + if let Some(token_metadata) = CurrencyMetadatas::::get(CurrencyId::Token2(token_id)) + { + let vsbond_metadata = Self::convert_to_vsbond_metadata( + token_metadata, + para_id, + first_slot, + last_slot, + ); + Self::do_register_metadata( + CurrencyId::VSBond2(token_id, para_id, first_slot, last_slot), + &vsbond_metadata, + )?; + + return Ok(()); + } else { + return Err(Error::::CurrencyIdNotExists)?; + } + } + + #[pallet::call_index(6)] + #[pallet::weight(T::WeightInfo::register_location())] + pub fn register_location( + origin: OriginFor, + currency_id: CurrencyId, + location: Box, + weight: Weight, + ) -> DispatchResult { + T::RegisterOrigin::ensure_origin(origin)?; + + let location: Location = + (*location).try_into().map_err(|()| Error::::BadLocation)?; + Self::do_register_location(currency_id, &location)?; + Self::do_register_weight(currency_id, weight)?; + + Ok(()) + } + + #[pallet::call_index(7)] + #[pallet::weight(T::WeightInfo::force_set_location())] + pub fn force_set_location( + origin: OriginFor, + currency_id: CurrencyId, + location: Box, + weight: Weight, + ) -> DispatchResult { + T::RegisterOrigin::ensure_origin(origin)?; + + let location: Location = + (*location).try_into().map_err(|()| Error::::BadLocation)?; + + let v3_location = xcm::v3::Location::try_from(location.clone()) + .map_err(|()| Error::::BadLocation)?; + + ensure!( + CurrencyMetadatas::::get(currency_id).is_some(), + Error::::CurrencyIdNotExists + ); + + LocationToCurrencyIds::::insert(v3_location, currency_id); + CurrencyIdToLocations::::insert(currency_id, v3_location); + CurrencyIdToWeights::::insert(currency_id, weight); + + Pallet::::deposit_event(Event::::LocationSet { currency_id, location, weight }); + + Ok(()) + } + + #[pallet::call_index(8)] + #[pallet::weight(T::WeightInfo::update_currency_metadata())] + pub fn update_currency_metadata( + origin: OriginFor, + currency_id: CurrencyId, + asset_name: Option>, + asset_symbol: Option>, + asset_decimals: Option, + asset_minimal_balance: Option>, + ) -> DispatchResult { + T::RegisterOrigin::ensure_origin(origin)?; + + // Check if the currency metadata exists + let mut metadata = + CurrencyMetadatas::::get(currency_id).ok_or(Error::::CurrencyIdNotExists)?; + + // Update the metadata fields based on the provided options + if let Some(name) = asset_name { + metadata.name = name; + } + if let Some(symbol) = asset_symbol { + metadata.symbol = symbol; + } + if let Some(decimals) = asset_decimals { + metadata.decimals = decimals; + } + if let Some(minimal_balance) = asset_minimal_balance { + metadata.minimal_balance = minimal_balance; + } + + // Store the updated metadata + CurrencyMetadatas::::insert(currency_id, metadata.clone()); + Self::deposit_event(Event::::CurrencyIdUpdated { currency_id, metadata }); + + Ok(()) + } + } +} + +impl Pallet { + pub fn get_next_token_id() -> Result { + NextTokenId::::try_mutate(|current| -> Result { + let id = *current; + *current = current.checked_add(One::one()).ok_or(ArithmeticError::Overflow)?; + Ok(id) + }) + } + + pub fn do_register_native_asset( + currency_id: CurrencyId, + location: &Location, + metadata: &AssetMetadata>, + ) -> DispatchResult { + let v3_location = + xcm::v3::Location::try_from(location.clone()).map_err(|()| Error::::BadLocation)?; + + ensure!(LocationToCurrencyIds::::get(v3_location).is_none(), Error::::AssetIdExisted); + ensure!( + CurrencyIdToLocations::::get(currency_id).is_none(), + Error::::LocationExisted + ); + ensure!( + AssetMetadatas::::get(AssetIds::NativeAssetId(currency_id)).is_none(), + Error::::AssetIdExisted + ); + + LocationToCurrencyIds::::insert(v3_location, currency_id); + CurrencyIdToLocations::::insert(currency_id, v3_location); + AssetMetadatas::::insert(AssetIds::NativeAssetId(currency_id), metadata); + + Ok(()) + } + + pub fn convert_to_vtoken_metadata( + token_metadata: AssetMetadata>, + ) -> AssetMetadata> { + let mut name = "Voucher ".as_bytes().to_vec(); + name.extend_from_slice(&token_metadata.symbol); + let mut symbol = "v".as_bytes().to_vec(); + symbol.extend_from_slice(&token_metadata.symbol); + AssetMetadata { name, symbol, ..token_metadata } + } + + pub fn convert_to_vstoken_metadata( + token_metadata: AssetMetadata>, + ) -> AssetMetadata> { + let mut name = "Voucher Slot ".as_bytes().to_vec(); + name.extend_from_slice(&token_metadata.symbol); + let mut symbol = "vs".as_bytes().to_vec(); + symbol.extend_from_slice(&token_metadata.symbol); + AssetMetadata { name, symbol, ..token_metadata } + } + + pub fn convert_to_vsbond_metadata( + token_metadata: AssetMetadata>, + para_id: ParaId, + first_slot: LeasePeriod, + last_slot: LeasePeriod, + ) -> AssetMetadata> { + let name = scale_info::prelude::format!( + "vsBOND-{}-{}-{}-{}", + core::str::from_utf8(&token_metadata.symbol).unwrap_or(""), + para_id, + first_slot, + last_slot + ) + .as_bytes() + .to_vec(); + AssetMetadata { name: name.clone(), symbol: name, ..token_metadata } + } + + pub fn do_register_metadata( + currency_id: CurrencyId, + metadata: &AssetMetadata>, + ) -> DispatchResult { + ensure!(CurrencyMetadatas::::get(currency_id).is_none(), Error::::CurrencyIdExisted); + + CurrencyMetadatas::::insert(currency_id, metadata.clone()); + + Pallet::::deposit_event(Event::::CurrencyIdRegistered { + currency_id, + metadata: metadata.clone(), + }); + + Ok(()) + } + + pub fn do_register_location(currency_id: CurrencyId, location: &Location) -> DispatchResult { + let v3_location = + xcm::v3::Location::try_from(location.clone()).map_err(|()| Error::::BadLocation)?; + + ensure!( + CurrencyMetadatas::::get(currency_id).is_some(), + Error::::CurrencyIdNotExists + ); + ensure!( + LocationToCurrencyIds::::get(v3_location).is_none(), + Error::::CurrencyIdExisted + ); + ensure!( + CurrencyIdToLocations::::get(currency_id).is_none(), + Error::::LocationExisted + ); + + LocationToCurrencyIds::::insert(v3_location, currency_id); + CurrencyIdToLocations::::insert(currency_id, v3_location); + + Ok(()) + } + + pub fn do_register_weight(currency_id: CurrencyId, weight: Weight) -> DispatchResult { + ensure!( + CurrencyMetadatas::::get(currency_id).is_some(), + Error::::CurrencyIdNotExists + ); + + CurrencyIdToWeights::::insert(currency_id, weight); + + Ok(()) + } + + fn do_update_native_asset( + currency_id: CurrencyId, + location: &Location, + metadata: &AssetMetadata>, + ) -> DispatchResult { + let v3_location = + xcm::v3::Location::try_from(location.clone()).map_err(|()| Error::::BadLocation)?; + + ensure!( + LocationToCurrencyIds::::get(v3_location).is_some(), + Error::::AssetIdNotExists + ); + ensure!( + CurrencyIdToLocations::::get(currency_id).is_some(), + Error::::LocationExisted + ); + ensure!( + AssetMetadatas::::get(AssetIds::NativeAssetId(currency_id)).is_some(), + Error::::AssetIdNotExists + ); + + LocationToCurrencyIds::::insert(v3_location, currency_id); + CurrencyIdToLocations::::insert(currency_id, v3_location); + AssetMetadatas::::insert(AssetIds::NativeAssetId(currency_id), metadata); + + Ok(()) + } +} + +pub struct AssetIdMaps(sp_std::marker::PhantomData); + +impl CurrencyIdMapping>> + for AssetIdMaps +{ + fn get_asset_metadata(asset_ids: AssetIds) -> Option>> { + AssetMetadatas::::get(asset_ids) + } + + fn get_currency_metadata(currency_id: CurrencyId) -> Option>> { + CurrencyMetadatas::::get(currency_id) + } + + fn get_all_currency() -> Vec { + CurrencyMetadatas::::iter_keys().collect() + } + + fn get_location(currency_id: CurrencyId) -> Option { + CurrencyIdToLocations::::get(currency_id).map(|location| location.try_into().ok())? + } + + fn get_currency_id(multi_location: Location) -> Option { + let v3_location = xcm::v3::Location::try_from(multi_location).ok()?; + LocationToCurrencyIds::::get(v3_location) + } +} + +impl CurrencyIdConversion for AssetIdMaps { + fn convert_to_token(currency_id: CurrencyId) -> Result { + match currency_id { + CurrencyId::VSBond(TokenSymbol::BNC, 2001, 13, 20) => + Ok(CurrencyId::Token(TokenSymbol::KSM)), + CurrencyId::VToken(TokenSymbol::BNC) => Ok(CurrencyId::Native(TokenSymbol::BNC)), + CurrencyId::VToken(token_symbol) | + CurrencyId::VSToken(token_symbol) | + CurrencyId::VSBond(token_symbol, ..) => Ok(CurrencyId::Token(token_symbol)), + CurrencyId::VToken2(token_id) | + CurrencyId::VSToken2(token_id) | + CurrencyId::VSBond2(token_id, ..) => Ok(CurrencyId::Token2(token_id)), + _ => Err(()), + } + } + + fn convert_to_vtoken(currency_id: CurrencyId) -> Result { + match currency_id { + CurrencyId::Token(token_symbol) | CurrencyId::Native(token_symbol) => + Ok(CurrencyId::VToken(token_symbol)), + CurrencyId::Token2(token_id) => Ok(CurrencyId::VToken2(token_id)), + _ => Err(()), + } + } + + fn convert_to_vstoken(currency_id: CurrencyId) -> Result { + match currency_id { + CurrencyId::Token(token_symbol) => Ok(CurrencyId::VSToken(token_symbol)), + CurrencyId::Token2(token_id) => Ok(CurrencyId::VSToken2(token_id)), + _ => Err(()), + } + } + + fn convert_to_vsbond( + currency_id: CurrencyId, + index: ParaId, + first_slot: LeasePeriod, + last_slot: LeasePeriod, + ) -> Result { + match currency_id { + CurrencyId::Token(token_symbol) => { + let mut vs_bond = CurrencyId::VSBond(token_symbol, index, first_slot, last_slot); + if vs_bond == CurrencyId::VSBond(TokenSymbol::KSM, 2001, 13, 20) { + // fix vsBOND::BNC + vs_bond = CurrencyId::VSBond(TokenSymbol::BNC, 2001, 13, 20); + } + Ok(vs_bond) + }, + CurrencyId::Token2(token_id) => + Ok(CurrencyId::VSBond2(token_id, index, first_slot, last_slot)), + _ => Err(()), + } + } +} + +impl CurrencyIdRegister for AssetIdMaps { + fn check_token_registered(token_symbol: TokenSymbol) -> bool { + CurrencyMetadatas::::get(CurrencyId::Token(token_symbol)).is_some() + } + + fn check_vtoken_registered(token_symbol: TokenSymbol) -> bool { + CurrencyMetadatas::::get(CurrencyId::VToken(token_symbol)).is_some() + } + + fn check_vstoken_registered(token_symbol: TokenSymbol) -> bool { + CurrencyMetadatas::::get(CurrencyId::VSToken(token_symbol)).is_some() + } + + fn check_vsbond_registered( + token_symbol: TokenSymbol, + para_id: ParaId, + first_slot: LeasePeriod, + last_slot: LeasePeriod, + ) -> bool { + CurrencyMetadatas::::get(CurrencyId::VSBond( + token_symbol, + para_id, + first_slot, + last_slot, + )) + .is_some() + } + + fn register_vtoken_metadata(token_symbol: TokenSymbol) -> sp_runtime::DispatchResult { + if let Some(token_metadata) = CurrencyMetadatas::::get(CurrencyId::Token(token_symbol)) { + let vtoken_metadata = Pallet::::convert_to_vtoken_metadata(token_metadata); + Pallet::::do_register_metadata(CurrencyId::VToken(token_symbol), &vtoken_metadata)?; + return Ok(()); + } else if let Some(token_metadata) = + CurrencyMetadatas::::get(CurrencyId::Native(token_symbol)) + { + let vtoken_metadata = Pallet::::convert_to_vtoken_metadata(token_metadata); + Pallet::::do_register_metadata(CurrencyId::VToken(token_symbol), &vtoken_metadata)?; + return Ok(()); + } else { + return Err(Error::::CurrencyIdNotExists.into()); + } + } + + fn register_vstoken_metadata(token_symbol: TokenSymbol) -> sp_runtime::DispatchResult { + if let Some(token_metadata) = CurrencyMetadatas::::get(CurrencyId::Token(token_symbol)) { + let vstoken_metadata = Pallet::::convert_to_vstoken_metadata(token_metadata); + Pallet::::do_register_metadata( + CurrencyId::VSToken(token_symbol), + &vstoken_metadata, + )?; + + return Ok(()); + } else { + return Err(Error::::CurrencyIdNotExists.into()); + } + } + + fn register_vsbond_metadata( + token_symbol: TokenSymbol, + para_id: ParaId, + first_slot: LeasePeriod, + last_slot: LeasePeriod, + ) -> sp_runtime::DispatchResult { + let option_token_metadata = + if CurrencyMetadatas::::contains_key(CurrencyId::Token(token_symbol)) { + CurrencyMetadatas::::get(CurrencyId::Token(token_symbol)) + } else if token_symbol == TokenSymbol::BNC && + CurrencyMetadatas::::contains_key(CurrencyId::Native(token_symbol)) + { + CurrencyMetadatas::::get(CurrencyId::Native(token_symbol)) + } else { + None + }; + + if let Some(token_metadata) = option_token_metadata { + let vsbond_metadata = Pallet::::convert_to_vsbond_metadata( + token_metadata, + para_id, + first_slot, + last_slot, + ); + Pallet::::do_register_metadata( + CurrencyId::VSBond(token_symbol, para_id, first_slot, last_slot), + &vsbond_metadata, + )?; + + return Ok(()); + } else { + return Err(Error::::CurrencyIdNotExists.into()); + } + } + + fn check_token2_registered(token_id: TokenId) -> bool { + CurrencyMetadatas::::get(CurrencyId::Token2(token_id)).is_some() + } + + fn check_vtoken2_registered(token_id: TokenId) -> bool { + CurrencyMetadatas::::get(CurrencyId::VToken2(token_id)).is_some() + } + + fn check_vstoken2_registered(token_id: TokenId) -> bool { + CurrencyMetadatas::::get(CurrencyId::VSToken2(token_id)).is_some() + } + + fn check_vsbond2_registered( + token_id: TokenId, + para_id: ParaId, + first_slot: LeasePeriod, + last_slot: LeasePeriod, + ) -> bool { + CurrencyMetadatas::::get(CurrencyId::VSBond2(token_id, para_id, first_slot, last_slot)) + .is_some() + } + + fn register_vtoken2_metadata(token_id: TokenId) -> DispatchResult { + if let Some(token_metadata) = CurrencyMetadatas::::get(CurrencyId::Token2(token_id)) { + let vtoken_metadata = Pallet::::convert_to_vtoken_metadata(token_metadata); + Pallet::::do_register_metadata(CurrencyId::VToken2(token_id), &vtoken_metadata)?; + + return Ok(()); + } else { + return Err(Error::::CurrencyIdNotExists.into()); + } + } + + fn register_vstoken2_metadata(token_id: TokenId) -> DispatchResult { + if let Some(token_metadata) = CurrencyMetadatas::::get(CurrencyId::Token2(token_id)) { + let vstoken_metadata = Pallet::::convert_to_vstoken_metadata(token_metadata); + Pallet::::do_register_metadata(CurrencyId::VSToken2(token_id), &vstoken_metadata)?; + + return Ok(()); + } else { + return Err(Error::::CurrencyIdNotExists.into()); + } + } + + fn register_vsbond2_metadata( + token_id: TokenId, + para_id: ParaId, + first_slot: LeasePeriod, + last_slot: LeasePeriod, + ) -> DispatchResult { + if let Some(token_metadata) = CurrencyMetadatas::::get(CurrencyId::Token2(token_id)) { + let vsbond_metadata = Pallet::::convert_to_vsbond_metadata( + token_metadata, + para_id, + first_slot, + last_slot, + ); + Pallet::::do_register_metadata( + CurrencyId::VSBond2(token_id, para_id, first_slot, last_slot), + &vsbond_metadata, + )?; + + return Ok(()); + } else { + return Err(Error::::CurrencyIdNotExists.into()); + } + } + + fn register_blp_metadata(pool_id: PoolId, decimals: u8) -> DispatchResult { + let name = scale_info::prelude::format!("Bifrost Stable Pool Token {}", pool_id) + .as_bytes() + .to_vec(); + let symbol = scale_info::prelude::format!("BLP{}", pool_id).as_bytes().to_vec(); + Pallet::::do_register_metadata( + CurrencyId::BLP(pool_id), + &AssetMetadata { + name, + symbol, + decimals, + minimal_balance: BalanceOf::::unique_saturated_from(1_000_000u128), + }, + ) + } +} + +/// Simple fee calculator that requires payment in a single fungible at a fixed rate. +/// +/// The constant `FixedRate` type parameter should be the concrete fungible ID and the amount of it +/// required for one second of weight. +pub struct FixedRateOfAsset, R: TakeRevenue> { + weight: u64, + amount: u128, + ed_ratio: FixedU128, + location: Option, + _marker: PhantomData<(T, FixedRate, R)>, +} + +impl, R: TakeRevenue> WeightTrader + for FixedRateOfAsset +where + BalanceOf: Into, +{ + fn new() -> Self { + Self { + weight: 0, + amount: 0, + ed_ratio: Default::default(), + location: None, + _marker: PhantomData, + } + } + + fn buy_weight( + &mut self, + weight: Weight, + payment: AssetsInHolding, + _context: &XcmContext, + ) -> Result { + log::trace!(target: "asset-registry::weight", "buy_weight weight: {:?}, payment: {:?}", weight, payment); + + // only support first fungible assets now. + let asset_id = payment + .fungible + .iter() + .next() + .map_or(Err(XcmError::TooExpensive), |v| Ok(v.0))?; + + let AssetId(ref location) = asset_id.clone(); + log::debug!(target: "asset-registry::weight", "buy_weight location: {:?}", location); + + let v3_location = + xcm::v3::Location::try_from(location.clone()).map_err(|_| XcmError::InvalidLocation)?; + + if let Some(currency_id) = LocationToCurrencyIds::::get(v3_location) { + if let Some(currency_metadatas) = CurrencyMetadatas::::get(currency_id) { + // The integration tests can ensure the ed is non-zero. + let ed_ratio = FixedU128::saturating_from_rational( + currency_metadatas.minimal_balance.into(), + T::Currency::minimum_balance().into(), + ); + // The WEIGHT_REF_TIME_PER_SECOND is non-zero. + let weight_ratio = FixedU128::saturating_from_rational( + weight.ref_time(), + WEIGHT_REF_TIME_PER_SECOND, + ); + let amount = + ed_ratio.saturating_mul_int(weight_ratio.saturating_mul_int(FixedRate::get())); + + let required = Asset { id: asset_id.clone(), fun: Fungible(amount) }; + + log::trace!( + target: "asset-registry::weight", "buy_weight payment: {:?}, required: {:?}, fixed_rate: {:?}, ed_ratio: {:?}, weight_ratio: {:?}", + payment, required, FixedRate::get(), ed_ratio, weight_ratio + ); + let unused = + payment.clone().checked_sub(required).map_err(|_| XcmError::TooExpensive)?; + self.weight = self.weight.saturating_add(weight.ref_time()); + self.amount = self.amount.saturating_add(amount); + self.ed_ratio = ed_ratio; + self.location = Some(location.clone()); + return Ok(unused); + } + }; + + log::trace!(target: "asset-registry::weight", "no concrete fungible asset"); + Err(XcmError::TooExpensive) + } + + fn refund_weight(&mut self, weight: Weight, _context: &XcmContext) -> Option { + log::trace!( + target: "asset-registry::weight", "refund_weight weight: {:?}, weight: {:?}, amount: {:?}, ed_ratio: {:?}, location: {:?}", + weight, self.weight, self.amount, self.ed_ratio, self.location + ); + let weight = weight.min(Weight::from_parts(self.weight, 0)); + let weight_ratio = + FixedU128::saturating_from_rational(weight.ref_time(), WEIGHT_REF_TIME_PER_SECOND); + let amount = self + .ed_ratio + .saturating_mul_int(weight_ratio.saturating_mul_int(FixedRate::get())); + + self.weight = self.weight.saturating_sub(weight.ref_time()); + self.amount = self.amount.saturating_sub(amount); + + log::trace!(target: "asset-registry::weight", "refund_weight amount: {:?}", amount); + if amount > 0 && self.location.is_some() { + Some(Asset { + fun: Fungible(amount), + id: AssetId( + self.location.clone().expect("checked is non-empty; qed").try_into().unwrap(), + ), + }) + } else { + None + } + } +} + +impl, R: TakeRevenue> Drop for FixedRateOfAsset { + fn drop(&mut self) { + log::trace!(target: "asset-registry::weight", "take revenue, weight: {:?}, amount: {:?}, location: {:?}", self.weight, self.amount, self.location); + if self.amount > 0 && self.location.is_some() { + R::take_revenue(Asset { + fun: Fungible(self.amount), + id: AssetId( + self.location.clone().expect("checked is non-empty; qed").try_into().unwrap(), + ), + }); + } + } +} diff --git a/pallets/asset-registry/src/migration.rs b/pallets/deprecated/asset-registry/src/migration.rs similarity index 100% rename from pallets/asset-registry/src/migration.rs rename to pallets/deprecated/asset-registry/src/migration.rs diff --git a/pallets/deprecated/asset-registry/src/mock.rs b/pallets/deprecated/asset-registry/src/mock.rs new file mode 100644 index 000000000..a948e290c --- /dev/null +++ b/pallets/deprecated/asset-registry/src/mock.rs @@ -0,0 +1,109 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . + +//! Mocks for asset registry module. + +#![cfg(test)] + +use bifrost_primitives::{AccountId, Balance}; +use frame_support::{ + construct_runtime, derive_impl, ord_parameter_types, pallet_prelude::ConstU32, parameter_types, +}; +use frame_system::EnsureSignedBy; +use sp_runtime::BuildStorage; + +use crate as asset_registry; + +parameter_types!( + pub const BlockHashCount: u32 = 250; +); + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type AccountId = AccountId; + type AccountData = pallet_balances::AccountData; + type Block = Block; + type Lookup = sp_runtime::traits::IdentityLookup; +} + +parameter_types! { + pub const ExistentialDeposit: u64 = 1; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type MaxLocks = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type WeightInfo = (); + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; + type FreezeIdentifier = (); + type MaxFreezes = ConstU32<0>; +} + +ord_parameter_types! { + pub const CouncilAccount: AccountId = AccountId::from([1u8; 32]); +} +impl asset_registry::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type RegisterOrigin = EnsureSignedBy; + type WeightInfo = (); +} + +type Block = frame_system::mocking::MockBlock; + +construct_runtime!( + pub enum Runtime { + System: frame_system, + Balances: pallet_balances, + AssetRegistry: asset_registry, + } +); + +pub struct ExtBuilder { + balances: Vec<(AccountId, Balance)>, +} + +impl Default for ExtBuilder { + fn default() -> Self { + Self { balances: vec![] } + } +} + +impl ExtBuilder { + pub fn build(self) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + pallet_balances::GenesisConfig:: { + balances: self.balances.into_iter().collect::>(), + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext + } +} diff --git a/pallets/deprecated/asset-registry/src/tests.rs b/pallets/deprecated/asset-registry/src/tests.rs new file mode 100644 index 000000000..470a22438 --- /dev/null +++ b/pallets/deprecated/asset-registry/src/tests.rs @@ -0,0 +1,519 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . + +//! Unit tests for asset registry module. + +#![cfg(test)] + +use super::*; +use bifrost_primitives::TokenSymbol; +use frame_support::{assert_noop, assert_ok}; +use mock::{ + AssetRegistry, CouncilAccount, ExtBuilder, Runtime, RuntimeEvent, RuntimeOrigin, System, +}; + +#[test] +fn versioned_multi_location_convert_work() { + ExtBuilder::default().build().execute_with(|| { + let versioned_location = VersionedLocation::V4(Location::from([Parachain(1000)])); + let location: Location = versioned_location.try_into().unwrap(); + assert_eq!(location, Location::new(0, [Parachain(1000)])); + }); +} + +#[test] +fn register_native_asset_works() { + ExtBuilder::default().build().execute_with(|| { + let versioned_location = VersionedLocation::V4(Location::from([Parachain(1000)])); + + assert_ok!(AssetRegistry::register_native_asset( + RuntimeOrigin::signed(CouncilAccount::get()), + Token(TokenSymbol::DOT), + Box::new(versioned_location.clone()), + Box::new(AssetMetadata { + name: b"Token Name".to_vec(), + symbol: b"TN".to_vec(), + decimals: 12, + minimal_balance: 1, + }) + )); + System::assert_last_event(RuntimeEvent::AssetRegistry(Event::AssetRegistered { + asset_id: AssetIds::NativeAssetId(Token(TokenSymbol::DOT)), + metadata: AssetMetadata { + name: b"Token Name".to_vec(), + symbol: b"TN".to_vec(), + decimals: 12, + minimal_balance: 1, + }, + })); + + assert_eq!( + AssetMetadatas::::get(AssetIds::NativeAssetId(Token(TokenSymbol::DOT))), + Some(AssetMetadata { + name: b"Token Name".to_vec(), + symbol: b"TN".to_vec(), + decimals: 12, + minimal_balance: 1, + }) + ); + // Can't duplicate + assert_noop!( + AssetRegistry::register_native_asset( + RuntimeOrigin::signed(CouncilAccount::get()), + Token(TokenSymbol::DOT), + Box::new(versioned_location), + Box::new(AssetMetadata { + name: b"Token Name".to_vec(), + symbol: b"TN".to_vec(), + decimals: 12, + minimal_balance: 1, + }) + ), + Error::::AssetIdExisted + ); + }); +} + +#[test] +fn update_native_asset_works() { + let versioned_location = VersionedLocation::V4(Location::from([Parachain(1000)])); + + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + AssetRegistry::update_native_asset( + RuntimeOrigin::signed(CouncilAccount::get()), + Token(TokenSymbol::DOT), + Box::new(versioned_location.clone()), + Box::new(AssetMetadata { + name: b"New Token Name".to_vec(), + symbol: b"NTN".to_vec(), + decimals: 13, + minimal_balance: 2, + }) + ), + Error::::AssetIdNotExists + ); + + assert_ok!(AssetRegistry::register_native_asset( + RuntimeOrigin::signed(CouncilAccount::get()), + Token(TokenSymbol::DOT), + Box::new(versioned_location.clone()), + Box::new(AssetMetadata { + name: b"Token Name".to_vec(), + symbol: b"TN".to_vec(), + decimals: 12, + minimal_balance: 1, + }) + )); + + assert_ok!(AssetRegistry::update_native_asset( + RuntimeOrigin::signed(CouncilAccount::get()), + Token(TokenSymbol::DOT), + Box::new(versioned_location.clone()), + Box::new(AssetMetadata { + name: b"New Token Name".to_vec(), + symbol: b"NTN".to_vec(), + decimals: 13, + minimal_balance: 2, + }) + )); + + System::assert_last_event(RuntimeEvent::AssetRegistry(Event::AssetUpdated { + asset_id: AssetIds::NativeAssetId(Token(TokenSymbol::DOT)), + metadata: AssetMetadata { + name: b"New Token Name".to_vec(), + symbol: b"NTN".to_vec(), + decimals: 13, + minimal_balance: 2, + }, + })); + + assert_eq!( + AssetMetadatas::::get(AssetIds::NativeAssetId(Token(TokenSymbol::DOT))), + Some(AssetMetadata { + name: b"New Token Name".to_vec(), + symbol: b"NTN".to_vec(), + decimals: 13, + minimal_balance: 2, + }) + ); + }); +} + +#[test] +fn register_token_metadata_should_work() { + ExtBuilder::default().build().execute_with(|| { + let metadata = AssetMetadata { + name: b"Bifrost Native Coin".to_vec(), + symbol: b"BNC".to_vec(), + decimals: 12, + minimal_balance: 0, + }; + + assert_ok!(AssetRegistry::register_token_metadata( + RuntimeOrigin::signed(CouncilAccount::get()), + Box::new(metadata.clone()) + )); + + assert_eq!(CurrencyMetadatas::::get(Token2(0)), Some(metadata.clone())) + }) +} + +#[test] +fn register_vtoken_metadata_should_work() { + ExtBuilder::default().build().execute_with(|| { + let metadata = AssetMetadata { + name: b"Bifrost Native Coin".to_vec(), + symbol: b"BNC".to_vec(), + decimals: 12, + minimal_balance: 0, + }; + let v_metadata = AssetMetadata { + name: b"Voucher BNC".to_vec(), + symbol: b"vBNC".to_vec(), + decimals: 12, + minimal_balance: 0, + }; + assert_noop!( + AssetRegistry::register_vtoken_metadata( + RuntimeOrigin::signed(CouncilAccount::get()), + 1 + ), + Error::::CurrencyIdNotExists + ); + + assert_ok!(AssetRegistry::register_token_metadata( + RuntimeOrigin::signed(CouncilAccount::get()), + Box::new(metadata.clone()) + )); + + assert_ok!(AssetRegistry::register_vtoken_metadata( + RuntimeOrigin::signed(CouncilAccount::get()), + 0 + )); + + assert_eq!( + CurrencyMetadatas::::get(CurrencyId::VToken2(0)), + Some(v_metadata.clone()) + ) + }) +} + +#[test] +fn register_vstoken_metadata_should_work() { + ExtBuilder::default().build().execute_with(|| { + let metadata = AssetMetadata { + name: b"KSM Native Token".to_vec(), + symbol: b"KSM".to_vec(), + decimals: 12, + minimal_balance: 0, + }; + let v_metadata = AssetMetadata { + name: b"Voucher Slot KSM".to_vec(), + symbol: b"vsKSM".to_vec(), + decimals: 12, + minimal_balance: 0, + }; + assert_noop!( + AssetRegistry::register_vtoken_metadata( + RuntimeOrigin::signed(CouncilAccount::get()), + 1 + ), + Error::::CurrencyIdNotExists + ); + + assert_ok!(AssetRegistry::register_token_metadata( + RuntimeOrigin::signed(CouncilAccount::get()), + Box::new(metadata.clone()) + )); + + assert_ok!(AssetRegistry::register_vstoken_metadata( + RuntimeOrigin::signed(CouncilAccount::get()), + 0 + )); + + assert_eq!( + CurrencyMetadatas::::get(CurrencyId::VSToken2(0)), + Some(v_metadata.clone()) + ) + }) +} + +#[test] +fn register_vsbond_metadata_should_work() { + ExtBuilder::default().build().execute_with(|| { + let metadata = AssetMetadata { + name: b"KSM Native Token".to_vec(), + symbol: b"KSM".to_vec(), + decimals: 12, + minimal_balance: 0, + }; + let name = "vsBOND-KSM-2001-10-20".as_bytes().to_vec(); + let v_metadata = + AssetMetadata { name: name.clone(), symbol: name, decimals: 12, minimal_balance: 0 }; + assert_noop!( + AssetRegistry::register_vtoken_metadata( + RuntimeOrigin::signed(CouncilAccount::get()), + 1 + ), + Error::::CurrencyIdNotExists + ); + + assert_ok!(AssetRegistry::register_token_metadata( + RuntimeOrigin::signed(CouncilAccount::get()), + Box::new(metadata.clone()) + )); + + assert_ok!(AssetRegistry::register_vsbond_metadata( + RuntimeOrigin::signed(CouncilAccount::get()), + 0, + 2001, + 10, + 20 + )); + + assert_eq!( + CurrencyMetadatas::::get(CurrencyId::VSBond2(0, 2001, 10, 20)), + Some(v_metadata.clone()) + ) + }) +} + +#[test] +fn register_multilocation_should_work() { + ExtBuilder::default().build().execute_with(|| { + let metadata = AssetMetadata { + name: b"Bifrost Native Coin".to_vec(), + symbol: b"BNC".to_vec(), + decimals: 12, + minimal_balance: 0, + }; + + let versioned_location = VersionedLocation::V4(Location::new(1, [Parachain(2001)])); + let location: xcm::v3::Location = versioned_location.clone().try_into().unwrap(); + + assert_noop!( + AssetRegistry::register_location( + RuntimeOrigin::signed(CouncilAccount::get()), + Token2(0), + Box::new(versioned_location.clone()), + Weight::from_parts(2000_000_000, 0) + ), + Error::::CurrencyIdNotExists + ); + + assert_ok!(AssetRegistry::register_token_metadata( + RuntimeOrigin::signed(CouncilAccount::get()), + Box::new(metadata.clone()) + )); + + assert_ok!(AssetRegistry::register_location( + RuntimeOrigin::signed(CouncilAccount::get()), + Token2(0), + Box::new(versioned_location.clone()), + Weight::from_parts(2000_000_000, 0) + )); + + assert_noop!( + AssetRegistry::register_location( + RuntimeOrigin::signed(CouncilAccount::get()), + Token2(0), + Box::new(versioned_location.clone()), + Weight::from_parts(2000_000_000, 0) + ), + Error::::CurrencyIdExisted + ); + + assert_eq!(LocationToCurrencyIds::::get(location), Some(Token2(0))); + assert_eq!(CurrencyIdToLocations::::get(Token2(0)), Some(location)); + assert_eq!( + CurrencyIdToWeights::::get(Token2(0)), + Some(Weight::from_parts(2000_000_000, 0)) + ); + }) +} + +#[test] +fn force_set_multilocation_should_work() { + ExtBuilder::default().build().execute_with(|| { + let metadata = AssetMetadata { + name: b"Bifrost Native Coin".to_vec(), + symbol: b"BNC".to_vec(), + decimals: 12, + minimal_balance: 0, + }; + let versioned_location = VersionedLocation::V4(Location::new(1, [Parachain(2001)])); + let location: xcm::v3::Location = versioned_location.clone().try_into().unwrap(); + + assert_noop!( + AssetRegistry::force_set_location( + RuntimeOrigin::signed(CouncilAccount::get()), + Token2(0), + Box::new(versioned_location.clone()), + Weight::from_parts(2000_000_000, 0) + ), + Error::::CurrencyIdNotExists + ); + + assert_ok!(AssetRegistry::register_token_metadata( + RuntimeOrigin::signed(CouncilAccount::get()), + Box::new(metadata.clone()) + )); + + assert_ok!(AssetRegistry::force_set_location( + RuntimeOrigin::signed(CouncilAccount::get()), + Token2(0), + Box::new(versioned_location.clone()), + Weight::from_parts(2000_000_000, 0) + )); + + assert_ok!(AssetRegistry::force_set_location( + RuntimeOrigin::signed(CouncilAccount::get()), + Token2(0), + Box::new(versioned_location.clone()), + Weight::from_parts(2000_000_000, 0) + )); + + assert_eq!(LocationToCurrencyIds::::get(location), Some(Token2(0))); + assert_eq!(CurrencyIdToLocations::::get(Token2(0)), Some(location)); + assert_eq!( + CurrencyIdToWeights::::get(Token2(0)), + Some(Weight::from_parts(2000_000_000, 0)) + ); + }) +} + +#[test] +fn update_currency_metadata_should_work() { + ExtBuilder::default().build().execute_with(|| { + let caller = CouncilAccount::get(); + let currency_id = CurrencyId::Token2(0); + let name = b"Updated Name".to_vec(); + let symbol = b"UN".to_vec(); + let decimals: u8 = 10; + let minimal_balance = 1000u32.into(); + + // Pre-insert a currency_metadata to update + CurrencyMetadatas::::insert( + currency_id, + AssetMetadata { + name: b"Old Name".to_vec(), + symbol: b"ON".to_vec(), + decimals: 8, + minimal_balance: 1u32.into(), + }, + ); + + // Ensure the origin has the required permissions + let origin = RuntimeOrigin::signed(caller); + assert_ok!(AssetRegistry::update_currency_metadata( + origin, + currency_id, + Some(name.clone()), + Some(symbol.clone()), + Some(decimals), + Some(minimal_balance) + )); + + System::assert_last_event(RuntimeEvent::AssetRegistry(crate::Event::CurrencyIdUpdated { + currency_id, + metadata: AssetMetadata { + name: name.clone(), + symbol: symbol.clone(), + decimals, + minimal_balance, + }, + })); + + // Verify the updated metadata + let updated_metadata = CurrencyMetadatas::::get(currency_id).unwrap(); + assert_eq!(updated_metadata.name, name); + assert_eq!(updated_metadata.symbol, symbol); + assert_eq!(updated_metadata.decimals, decimals); + assert_eq!(updated_metadata.minimal_balance, minimal_balance); + }) +} + +#[test] +fn update_currency_metadata_should_work_no_change() { + ExtBuilder::default().build().execute_with(|| { + let caller = CouncilAccount::get(); + let currency_id = CurrencyId::Token2(0); + let name = None; + let symbol = None; + let decimals = None; + let minimal_balance = None; + + let old_metadata = AssetMetadata { + name: b"Old Name".to_vec(), + symbol: b"ON".to_vec(), + decimals: 8, + minimal_balance: 1u32.into(), + }; + + // Pre-insert a currency_metadata to update + CurrencyMetadatas::::insert(currency_id, old_metadata.clone()); + + // Ensure the origin has the required permissions + let origin = RuntimeOrigin::signed(caller); + assert_ok!(AssetRegistry::update_currency_metadata( + origin, + currency_id, + name, + symbol, + decimals, + minimal_balance + )); + + // Verify the event + System::assert_last_event(RuntimeEvent::AssetRegistry(crate::Event::CurrencyIdUpdated { + currency_id, + metadata: old_metadata.clone(), + })); + + // Verify the updated metadata + let updated_metadata = CurrencyMetadatas::::get(currency_id).unwrap(); + assert_eq!(updated_metadata, old_metadata); + }); +} + +#[test] +fn update_currency_metadata_nonexistent_currency_id() { + ExtBuilder::default().build().execute_with(|| { + let caller = CouncilAccount::get(); + let currency_id = CurrencyId::Token2(1); // Non-existent currency ID + let name = Some(b"Updated Name".to_vec()); + let symbol = Some(b"UN".to_vec()); + let decimals = Some(10); + let minimal_balance = Some(1000u32.into()); + + // Ensure the origin has the required permissions + let origin = RuntimeOrigin::signed(caller); + assert_noop!( + AssetRegistry::update_currency_metadata( + origin, + currency_id, + name, + symbol, + decimals, + minimal_balance + ), + Error::::CurrencyIdNotExists + ); + }); +} diff --git a/pallets/deprecated/asset-registry/src/weights.rs b/pallets/deprecated/asset-registry/src/weights.rs new file mode 100644 index 000000000..162c6fad6 --- /dev/null +++ b/pallets/deprecated/asset-registry/src/weights.rs @@ -0,0 +1,190 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for bifrost_asset_registry +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-14, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bifrost-jenkins`, CPU: `Intel(R) Xeon(R) CPU E5-26xx v4` +//! WASM-EXECUTION: Compiled, CHAIN: Some("bifrost-kusama-local"), DB CACHE: 1024 + +// Executed Command: +// target/release/bifrost +// benchmark +// pallet +// --chain=bifrost-kusama-local +// --steps=50 +// --repeat=20 +// --pallet=bifrost_asset_registry +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./pallets/asset-registry/src/weights.rs +// --template=./weight-template/pallet-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for bifrost_asset_registry. +pub trait WeightInfo { + fn register_native_asset() -> Weight; + fn update_native_asset() -> Weight; + fn register_token_metadata() -> Weight; + fn register_vtoken_metadata() -> Weight; + fn register_vstoken_metadata() -> Weight; + fn register_vsbond_metadata() -> Weight; + fn register_location() -> Weight; + fn force_set_location() -> Weight; + fn update_currency_metadata() -> Weight; +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: AssetRegistry LocationToCurrencyIds (r:1 w:1) + /// Proof Skipped: AssetRegistry LocationToCurrencyIds (max_values: None, max_size: None, mode: Measured) + /// Storage: AssetRegistry CurrencyIdToLocations (r:1 w:1) + /// Proof Skipped: AssetRegistry CurrencyIdToLocations (max_values: None, max_size: None, mode: Measured) + /// Storage: AssetRegistry AssetMetadatas (r:1 w:1) + /// Proof Skipped: AssetRegistry AssetMetadatas (max_values: None, max_size: None, mode: Measured) + fn register_native_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `118` + // Estimated: `3583` + // Minimum execution time: 52_056_000 picoseconds. + Weight::from_parts(53_012_000, 3583) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: AssetRegistry LocationToCurrencyIds (r:1 w:1) + /// Proof Skipped: AssetRegistry LocationToCurrencyIds (max_values: None, max_size: None, mode: Measured) + /// Storage: AssetRegistry CurrencyIdToLocations (r:1 w:1) + /// Proof Skipped: AssetRegistry CurrencyIdToLocations (max_values: None, max_size: None, mode: Measured) + /// Storage: AssetRegistry AssetMetadatas (r:1 w:1) + /// Proof Skipped: AssetRegistry AssetMetadatas (max_values: None, max_size: None, mode: Measured) + fn update_native_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `250` + // Estimated: `3715` + // Minimum execution time: 59_891_000 picoseconds. + Weight::from_parts(60_869_000, 3715) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: AssetRegistry NextTokenId (r:1 w:1) + /// Proof Skipped: AssetRegistry NextTokenId (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:1) + /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) + fn register_token_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `607` + // Estimated: `4072` + // Minimum execution time: 46_860_000 picoseconds. + Weight::from_parts(48_151_000, 4072) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: AssetRegistry CurrencyMetadatas (r:2 w:1) + /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) + fn register_vtoken_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `779` + // Estimated: `6719` + // Minimum execution time: 53_699_000 picoseconds. + Weight::from_parts(54_646_000, 6719) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: AssetRegistry CurrencyMetadatas (r:2 w:1) + /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) + fn register_vstoken_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `705` + // Estimated: `6645` + // Minimum execution time: 52_491_000 picoseconds. + Weight::from_parts(53_682_000, 6645) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: AssetRegistry CurrencyMetadatas (r:2 w:1) + /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) + fn register_vsbond_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `763` + // Estimated: `6703` + // Minimum execution time: 55_589_000 picoseconds. + Weight::from_parts(56_804_000, 6703) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) + /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) + /// Storage: AssetRegistry LocationToCurrencyIds (r:1 w:1) + /// Proof Skipped: AssetRegistry LocationToCurrencyIds (max_values: None, max_size: None, mode: Measured) + /// Storage: AssetRegistry CurrencyIdToLocations (r:1 w:1) + /// Proof Skipped: AssetRegistry CurrencyIdToLocations (max_values: None, max_size: None, mode: Measured) + /// Storage: AssetRegistry CurrencyIdToWeights (r:0 w:1) + /// Proof Skipped: AssetRegistry CurrencyIdToWeights (max_values: None, max_size: None, mode: Measured) + fn register_location() -> Weight { + // Proof Size summary in bytes: + // Measured: `683` + // Estimated: `4148` + // Minimum execution time: 45_469_000 picoseconds. + Weight::from_parts(48_623_000, 4148) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) + /// Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) + /// Storage: AssetRegistry LocationToCurrencyIds (r:0 w:1) + /// Proof Skipped: AssetRegistry LocationToCurrencyIds (max_values: None, max_size: None, mode: Measured) + /// Storage: AssetRegistry CurrencyIdToWeights (r:0 w:1) + /// Proof Skipped: AssetRegistry CurrencyIdToWeights (max_values: None, max_size: None, mode: Measured) + /// Storage: AssetRegistry CurrencyIdToLocations (r:0 w:1) + /// Proof Skipped: AssetRegistry CurrencyIdToLocations (max_values: None, max_size: None, mode: Measured) + fn force_set_location() -> Weight { + // Proof Size summary in bytes: + // Measured: `683` + // Estimated: `4148` + // Minimum execution time: 52_878_000 picoseconds. + Weight::from_parts(55_012_000, 4148) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: `AssetRegistry::CurrencyMetadatas` (r:1 w:1) + /// Proof: `AssetRegistry::CurrencyMetadatas` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn update_currency_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `409` + // Estimated: `3874` + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3874) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } +} diff --git a/pallets/slpx/src/benchmarking.rs b/pallets/slpx/src/benchmarking.rs index 2c77e7f99..8a43cd007 100644 --- a/pallets/slpx/src/benchmarking.rs +++ b/pallets/slpx/src/benchmarking.rs @@ -45,8 +45,8 @@ fn init_whitelist() -> (T::AccountId BalanceOf::::unique_saturated_from(100_000_000_000_000u128), )); - CurrencyIdToLocations::::insert(KSM, xcm::v3::Location::default()); - CurrencyIdToLocations::::insert(VKSM, xcm::v3::Location::default()); + CurrencyIdToLocations::::insert(KSM, xcm::v4::Location::default()); + CurrencyIdToLocations::::insert(VKSM, xcm::v4::Location::default()); (caller, receiver) } diff --git a/primitives/src/traits.rs b/primitives/src/traits.rs index a3423ec73..c6cf28de0 100644 --- a/primitives/src/traits.rs +++ b/primitives/src/traits.rs @@ -186,30 +186,9 @@ pub trait CurrencyIdRegister { last_slot: crate::LeasePeriod, ) -> bool; fn register_vtoken_metadata(token_symbol: TokenSymbol) -> DispatchResult; - fn register_vstoken_metadata(token_symbol: TokenSymbol) -> DispatchResult; - fn register_vsbond_metadata( - token_symbol: TokenSymbol, - para_id: crate::ParaId, - first_slot: crate::LeasePeriod, - last_slot: crate::LeasePeriod, - ) -> DispatchResult; fn check_token2_registered(token_id: TokenId) -> bool; fn check_vtoken2_registered(token_id: TokenId) -> bool; - fn check_vstoken2_registered(token_id: TokenId) -> bool; - fn check_vsbond2_registered( - token_id: TokenId, - para_id: crate::ParaId, - first_slot: crate::LeasePeriod, - last_slot: crate::LeasePeriod, - ) -> bool; fn register_vtoken2_metadata(token_id: TokenId) -> DispatchResult; - fn register_vstoken2_metadata(token_id: TokenId) -> DispatchResult; - fn register_vsbond2_metadata( - token_id: TokenId, - para_id: crate::ParaId, - first_slot: crate::LeasePeriod, - last_slot: crate::LeasePeriod, - ) -> DispatchResult; fn register_blp_metadata(pool_id: PoolId, decimals: u8) -> DispatchResult; } @@ -239,19 +218,6 @@ impl CurrencyIdRegister for () { Ok(()) } - fn register_vstoken_metadata(_token_symbol: TokenSymbol) -> DispatchResult { - Ok(()) - } - - fn register_vsbond_metadata( - _token_symbol: TokenSymbol, - _para_id: ParaId, - _first_slot: LeasePeriod, - _last_slot: LeasePeriod, - ) -> DispatchResult { - Ok(()) - } - fn check_token2_registered(_token_id: TokenId) -> bool { false } @@ -260,36 +226,10 @@ impl CurrencyIdRegister for () { false } - fn check_vstoken2_registered(_token_id: TokenId) -> bool { - false - } - - fn check_vsbond2_registered( - _token_id: TokenId, - _para_id: ParaId, - _first_slot: LeasePeriod, - _last_slot: LeasePeriod, - ) -> bool { - false - } - fn register_vtoken2_metadata(_token_id: TokenId) -> DispatchResult { Ok(()) } - fn register_vstoken2_metadata(_token_id: TokenId) -> DispatchResult { - Ok(()) - } - - fn register_vsbond2_metadata( - _token_id: TokenId, - _para_id: ParaId, - _first_slot: LeasePeriod, - _last_slot: LeasePeriod, - ) -> DispatchResult { - Ok(()) - } - fn register_blp_metadata(_pool_id: PoolId, _decimals: u8) -> DispatchResult { Ok(()) } diff --git a/runtime/bifrost-kusama/src/weights/bifrost_asset_registry.rs b/runtime/bifrost-kusama/src/weights/bifrost_asset_registry.rs index 927135cec..cbc3b0ac0 100644 --- a/runtime/bifrost-kusama/src/weights/bifrost_asset_registry.rs +++ b/runtime/bifrost-kusama/src/weights/bifrost_asset_registry.rs @@ -54,36 +54,6 @@ use sp_std::marker::PhantomData; /// Weight functions for bifrost_asset_registry. pub struct BifrostWeight(PhantomData); impl bifrost_asset_registry::WeightInfo for BifrostWeight { - // Storage: AssetRegistry LocationToCurrencyIds (r:1 w:1) - // Proof Skipped: AssetRegistry LocationToCurrencyIds (max_values: None, max_size: None, mode: Measured) - // Storage: AssetRegistry CurrencyIdToLocations (r:1 w:1) - // Proof Skipped: AssetRegistry CurrencyIdToLocations (max_values: None, max_size: None, mode: Measured) - // Storage: AssetRegistry AssetMetadatas (r:1 w:1) - // Proof Skipped: AssetRegistry AssetMetadatas (max_values: None, max_size: None, mode: Measured) - fn register_native_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `118` - // Estimated: `3583` - // Minimum execution time: 49_553 nanoseconds. - Weight::from_parts(50_599_000, 3583) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - // Storage: AssetRegistry LocationToCurrencyIds (r:1 w:1) - // Proof Skipped: AssetRegistry LocationToCurrencyIds (max_values: None, max_size: None, mode: Measured) - // Storage: AssetRegistry CurrencyIdToLocations (r:1 w:1) - // Proof Skipped: AssetRegistry CurrencyIdToLocations (max_values: None, max_size: None, mode: Measured) - // Storage: AssetRegistry AssetMetadatas (r:1 w:1) - // Proof Skipped: AssetRegistry AssetMetadatas (max_values: None, max_size: None, mode: Measured) - fn update_native_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `250` - // Estimated: `3715` - // Minimum execution time: 56_917 nanoseconds. - Weight::from_parts(57_419_000, 3715) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } // Storage: AssetRegistry NextTokenId (r:1 w:1) // Proof Skipped: AssetRegistry NextTokenId (max_values: Some(1), max_size: None, mode: Measured) // Storage: AssetRegistry CurrencyMetadatas (r:1 w:1) @@ -108,28 +78,6 @@ impl bifrost_asset_registry::WeightInfo for BifrostWeig .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: AssetRegistry CurrencyMetadatas (r:2 w:1) - // Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - fn register_vstoken_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `705` - // Estimated: `6645` - // Minimum execution time: 49_492 nanoseconds. - Weight::from_parts(50_943_000, 6645) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: AssetRegistry CurrencyMetadatas (r:2 w:1) - // Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - fn register_vsbond_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `763` - // Estimated: `6703` - // Minimum execution time: 52_709 nanoseconds. - Weight::from_parts(54_285_000, 6703) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } // Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) // Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) // Storage: AssetRegistry LocationToCurrencyIds (r:1 w:1) diff --git a/runtime/bifrost-polkadot/src/weights/bifrost_asset_registry.rs b/runtime/bifrost-polkadot/src/weights/bifrost_asset_registry.rs index 927135cec..cbc3b0ac0 100644 --- a/runtime/bifrost-polkadot/src/weights/bifrost_asset_registry.rs +++ b/runtime/bifrost-polkadot/src/weights/bifrost_asset_registry.rs @@ -54,36 +54,6 @@ use sp_std::marker::PhantomData; /// Weight functions for bifrost_asset_registry. pub struct BifrostWeight(PhantomData); impl bifrost_asset_registry::WeightInfo for BifrostWeight { - // Storage: AssetRegistry LocationToCurrencyIds (r:1 w:1) - // Proof Skipped: AssetRegistry LocationToCurrencyIds (max_values: None, max_size: None, mode: Measured) - // Storage: AssetRegistry CurrencyIdToLocations (r:1 w:1) - // Proof Skipped: AssetRegistry CurrencyIdToLocations (max_values: None, max_size: None, mode: Measured) - // Storage: AssetRegistry AssetMetadatas (r:1 w:1) - // Proof Skipped: AssetRegistry AssetMetadatas (max_values: None, max_size: None, mode: Measured) - fn register_native_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `118` - // Estimated: `3583` - // Minimum execution time: 49_553 nanoseconds. - Weight::from_parts(50_599_000, 3583) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - // Storage: AssetRegistry LocationToCurrencyIds (r:1 w:1) - // Proof Skipped: AssetRegistry LocationToCurrencyIds (max_values: None, max_size: None, mode: Measured) - // Storage: AssetRegistry CurrencyIdToLocations (r:1 w:1) - // Proof Skipped: AssetRegistry CurrencyIdToLocations (max_values: None, max_size: None, mode: Measured) - // Storage: AssetRegistry AssetMetadatas (r:1 w:1) - // Proof Skipped: AssetRegistry AssetMetadatas (max_values: None, max_size: None, mode: Measured) - fn update_native_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `250` - // Estimated: `3715` - // Minimum execution time: 56_917 nanoseconds. - Weight::from_parts(57_419_000, 3715) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } // Storage: AssetRegistry NextTokenId (r:1 w:1) // Proof Skipped: AssetRegistry NextTokenId (max_values: Some(1), max_size: None, mode: Measured) // Storage: AssetRegistry CurrencyMetadatas (r:1 w:1) @@ -108,28 +78,6 @@ impl bifrost_asset_registry::WeightInfo for BifrostWeig .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: AssetRegistry CurrencyMetadatas (r:2 w:1) - // Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - fn register_vstoken_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `705` - // Estimated: `6645` - // Minimum execution time: 49_492 nanoseconds. - Weight::from_parts(50_943_000, 6645) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: AssetRegistry CurrencyMetadatas (r:2 w:1) - // Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - fn register_vsbond_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `763` - // Estimated: `6703` - // Minimum execution time: 52_709 nanoseconds. - Weight::from_parts(54_285_000, 6703) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } // Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) // Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) // Storage: AssetRegistry LocationToCurrencyIds (r:1 w:1) From f372dfd70fce3f425553eeb6f28e07fd2f5b86fb Mon Sep 17 00:00:00 2001 From: MJLNSN <96321798+MJLNSN@users.noreply.github.com> Date: Sun, 29 Sep 2024 21:29:44 +0800 Subject: [PATCH 11/30] Removed getters in farming (#1446) --- pallets/farming/src/boost.rs | 18 +++++++------- pallets/farming/src/lib.rs | 47 +++++++++++++----------------------- pallets/farming/src/tests.rs | 24 +++++++++--------- 3 files changed, 38 insertions(+), 51 deletions(-) diff --git a/pallets/farming/src/boost.rs b/pallets/farming/src/boost.rs index a31e28966..50ada6193 100644 --- a/pallets/farming/src/boost.rs +++ b/pallets/farming/src/boost.rs @@ -43,10 +43,10 @@ impl BoostInterface, CurrencyIdOf, BalanceOf, Bl for Pallet { fn refresh_vebnc_farming(who: &AccountIdOf) -> DispatchResult { - let mut boost_pool_info = Self::boost_pool_infos(); + let mut boost_pool_info = BoostPoolInfos::::get(); let new_vote_amount = T::BbBNC::balance_of(who, None)?; - if let Some(mut user_boost_info) = Self::user_boost_infos(who) { + if let Some(mut user_boost_info) = UserBoostInfos::::get(who) { // If the user's last voting block height is greater than or equal to the block height // at the beginning of this round, refresh. if user_boost_info.last_vote >= boost_pool_info.start_round { @@ -89,7 +89,7 @@ impl Pallet { // the next round. pub(crate) fn start_boost_round_inner(round_length: BlockNumberFor) -> DispatchResult { ensure!(round_length != Zero::zero(), Error::::RoundLengthNotSet); - let mut boost_pool_info = Self::boost_pool_infos(); + let mut boost_pool_info = BoostPoolInfos::::get(); ensure!(boost_pool_info.end_round == Zero::zero(), Error::::RoundNotOver); // Update whitelist @@ -118,7 +118,7 @@ impl Pallet { // Clear boost_basic_rewards and boost_pool_info.end_round to eliminate the influence of boost // in hook pub(crate) fn end_boost_round_inner() { - let mut boost_pool_info = Self::boost_pool_infos(); + let mut boost_pool_info = BoostPoolInfos::::get(); let _ = BoostBasicRewards::::clear(u32::max_value(), None); Self::deposit_event(Event::RoundEnd { total_votes: boost_pool_info.total_votes, @@ -132,7 +132,7 @@ impl Pallet { // Only used in hook pub(crate) fn auto_start_boost_round() { - let mut boost_pool_info = Self::boost_pool_infos(); + let mut boost_pool_info = BoostPoolInfos::::get(); let whitelist_iter = BoostWhitelist::::iter_keys(); // Update whitelist if BoostNextRoundWhitelist::::iter().count() != 0 { @@ -164,7 +164,7 @@ impl Pallet { boost_pool_info: &BoostPoolInfo, BlockNumberFor>, ) -> DispatchResult { BoostVotingPools::::iter() - .filter_map(|(pid, value)| match Self::pool_infos(pid) { + .filter_map(|(pid, value)| match PoolInfos::::get(pid) { Some(pool_info) => Some((pid, value, pool_info)), None => None, }) @@ -201,9 +201,9 @@ impl Pallet { vote_list: Vec<(PoolId, Percent)>, ) -> DispatchResult { let current_block_number = frame_system::Pallet::::block_number(); - let mut boost_pool_info = Self::boost_pool_infos(); + let mut boost_pool_info = BoostPoolInfos::::get(); - if let Some(user_boost_info) = Self::user_boost_infos(who) { + if let Some(user_boost_info) = UserBoostInfos::::get(who) { // If the user's last voting block height is greater than or equal to the block height // at the beginning of this round, subtract. if user_boost_info.last_vote >= boost_pool_info.start_round { @@ -230,7 +230,7 @@ impl Pallet { let new_vote_amount = T::BbBNC::balance_of(who, None)?; let mut percent_check = Percent::from_percent(0); vote_list.iter().try_for_each(|(pid, proportion)| -> DispatchResult { - ensure!(Self::boost_whitelist(pid) != None, Error::::NotInWhitelist); + ensure!(BoostWhitelist::::get(pid) != None, Error::::NotInWhitelist); let increace = *proportion * new_vote_amount; percent_check = percent_check.checked_add(proportion).ok_or(Error::::PercentOverflow)?; diff --git a/pallets/farming/src/lib.rs b/pallets/farming/src/lib.rs index 16d71fa2b..73d4badfd 100644 --- a/pallets/farming/src/lib.rs +++ b/pallets/farming/src/lib.rs @@ -236,22 +236,18 @@ pub mod pallet { } #[pallet::storage] - #[pallet::getter(fn pool_next_id)] pub type PoolNextId = StorageValue<_, PoolId, ValueQuery>; #[pallet::storage] - #[pallet::getter(fn gauge_pool_next_id)] pub type GaugePoolNextId = StorageValue<_, PoolId, ValueQuery>; #[pallet::storage] - #[pallet::getter(fn retire_limit)] pub type RetireLimit = StorageValue<_, u32, ValueQuery>; /// Record reward pool info. /// /// map PoolId => PoolInfo #[pallet::storage] - #[pallet::getter(fn pool_infos)] pub type PoolInfos = StorageMap< _, Twox64Concat, @@ -263,7 +259,6 @@ pub mod pallet { /// /// map PoolId => GaugePoolInfo #[pallet::storage] - #[pallet::getter(fn gauge_pool_infos)] pub type GaugePoolInfos = StorageMap< _, Twox64Concat, @@ -272,7 +267,6 @@ pub mod pallet { >; #[pallet::storage] - #[pallet::getter(fn gauge_infos)] pub type GaugeInfos = StorageDoubleMap< _, Twox64Concat, @@ -287,7 +281,6 @@ pub mod pallet { /// /// double_map (PoolId, AccountId) => ShareInfo #[pallet::storage] - #[pallet::getter(fn shares_and_withdrawn_rewards)] pub type SharesAndWithdrawnRewards = StorageDoubleMap< _, Twox64Concat, @@ -298,29 +291,23 @@ pub mod pallet { >; #[pallet::storage] - #[pallet::getter(fn boost_pool_infos)] pub type BoostPoolInfos = StorageValue<_, BoostPoolInfo, BlockNumberFor>, ValueQuery>; #[pallet::storage] - #[pallet::getter(fn user_boost_infos)] pub type UserBoostInfos = StorageMap<_, Blake2_128Concat, T::AccountId, UserBoostInfo>; #[pallet::storage] - #[pallet::getter(fn boost_whitelist)] pub type BoostWhitelist = StorageMap<_, Twox64Concat, PoolId, ()>; #[pallet::storage] - #[pallet::getter(fn boost_next_round_whitelist)] pub type BoostNextRoundWhitelist = StorageMap<_, Twox64Concat, PoolId, ()>; #[pallet::storage] - #[pallet::getter(fn boost_voting_pools)] pub type BoostVotingPools = StorageMap<_, Twox64Concat, PoolId, BalanceOf>; #[pallet::storage] - #[pallet::getter(fn boost_basic_rewards)] pub type BoostBasicRewards = StorageDoubleMap<_, Twox64Concat, PoolId, Twox64Concat, CurrencyIdOf, BalanceOf>; @@ -332,7 +319,7 @@ pub mod pallet { pool_info.basic_rewards.clone().iter_mut().for_each( |(reward_currency_id, reward_amount)| { if let Some(boost_basic_reward) = - Self::boost_basic_rewards(pid, reward_currency_id) + BoostBasicRewards::::get(pid, reward_currency_id) { *reward_amount = reward_amount.saturating_add(boost_basic_reward); } @@ -369,7 +356,7 @@ pub mod pallet { } }); - if n == Self::boost_pool_infos().end_round { + if n == BoostPoolInfos::::get().end_round { Self::end_boost_round_inner(); Self::auto_start_boost_round(); } @@ -399,7 +386,7 @@ pub mod pallet { ) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; - let pid = Self::pool_next_id(); + let pid = PoolNextId::::get(); let keeper = T::Keeper::get().into_sub_account_truncating(pid); let reward_issuer = T::RewardIssuer::get().into_sub_account_truncating(pid); let basic_token = *tokens_proportion.get(0).ok_or(Error::::NotNullable)?; @@ -449,7 +436,7 @@ pub mod pallet { ) -> DispatchResult { let exchanger = ensure_signed(origin)?; - let mut pool_info = Self::pool_infos(&pid).ok_or(Error::::PoolDoesNotExist)?; + let mut pool_info = PoolInfos::::get(&pid).ok_or(Error::::PoolDoesNotExist)?; match if_gauge { true => { @@ -500,7 +487,7 @@ pub mod pallet { // Check origin let exchanger = ensure_signed(origin)?; - let mut pool_info = Self::pool_infos(&pid).ok_or(Error::::PoolDoesNotExist)?; + let mut pool_info = PoolInfos::::get(&pid).ok_or(Error::::PoolDoesNotExist)?; ensure!( pool_info.state == PoolState::Ongoing || pool_info.state == PoolState::Charged, Error::::InvalidPoolState @@ -543,14 +530,14 @@ pub mod pallet { // Check origin let exchanger = ensure_signed(origin)?; - let pool_info = Self::pool_infos(&pid).ok_or(Error::::PoolDoesNotExist)?; + let pool_info = PoolInfos::::get(&pid).ok_or(Error::::PoolDoesNotExist)?; ensure!( pool_info.state == PoolState::Ongoing || pool_info.state == PoolState::Charged || pool_info.state == PoolState::Dead, Error::::InvalidPoolState ); - let share_info = Self::shares_and_withdrawn_rewards(&pid, &exchanger) + let share_info = SharesAndWithdrawnRewards::::get(&pid, &exchanger) .ok_or(Error::::ShareInfoNotExists)?; ensure!( share_info.withdraw_list.len() < pool_info.withdraw_limit_count.into(), @@ -570,14 +557,14 @@ pub mod pallet { // Check origin let exchanger = ensure_signed(origin)?; - let pool_info = Self::pool_infos(&pid).ok_or(Error::::PoolDoesNotExist)?; + let pool_info = PoolInfos::::get(&pid).ok_or(Error::::PoolDoesNotExist)?; ensure!( pool_info.state == PoolState::Ongoing || pool_info.state == PoolState::Dead, Error::::InvalidPoolState ); let current_block_number: BlockNumberFor = frame_system::Pallet::::block_number(); - let share_info = Self::shares_and_withdrawn_rewards(&pid, &exchanger) + let share_info = SharesAndWithdrawnRewards::::get(&pid, &exchanger) .ok_or(Error::::ShareInfoNotExists)?; ensure!( share_info.claim_last_block.saturating_add(pool_info.claim_limit_time) <= @@ -598,7 +585,7 @@ pub mod pallet { // Check origin let exchanger = ensure_signed(origin)?; - let pool_info = Self::pool_infos(&pid).ok_or(Error::::PoolDoesNotExist)?; + let pool_info = PoolInfos::::get(&pid).ok_or(Error::::PoolDoesNotExist)?; Self::process_withdraw_list(&exchanger, pid, &pool_info, false)?; Self::deposit_event(Event::WithdrawClaimed { who: exchanger, pid }); @@ -610,7 +597,7 @@ pub mod pallet { pub fn force_retire_pool(origin: OriginFor, pid: PoolId) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; - let mut pool_info = Self::pool_infos(&pid).ok_or(Error::::PoolDoesNotExist)?; + let mut pool_info = PoolInfos::::get(&pid).ok_or(Error::::PoolDoesNotExist)?; ensure!(pool_info.state == PoolState::Dead, Error::::InvalidPoolState); let withdraw_limit_time = BlockNumberFor::::default(); let retire_limit = RetireLimit::::get(); @@ -629,7 +616,7 @@ pub mod pallet { if all_retired { if let Some(ref gid) = pool_info.gauge { let mut gauge_pool_info = - Self::gauge_pool_infos(gid).ok_or(Error::::GaugePoolNotExist)?; + GaugePoolInfos::::get(gid).ok_or(Error::::GaugePoolNotExist)?; gauge_pool_info.gauge_state = GaugeState::Unbond; GaugePoolInfos::::insert(&gid, gauge_pool_info); } @@ -661,7 +648,7 @@ pub mod pallet { pub fn close_pool(origin: OriginFor, pid: PoolId) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; - let mut pool_info = Self::pool_infos(&pid).ok_or(Error::::PoolDoesNotExist)?; + let mut pool_info = PoolInfos::::get(&pid).ok_or(Error::::PoolDoesNotExist)?; ensure!(pool_info.state == PoolState::Ongoing, Error::::InvalidPoolState); pool_info.state = PoolState::Dead; PoolInfos::::insert(&pid, pool_info); @@ -685,7 +672,7 @@ pub mod pallet { ) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; - let mut pool_info = Self::pool_infos(&pid).ok_or(Error::::PoolDoesNotExist)?; + let mut pool_info = PoolInfos::::get(&pid).ok_or(Error::::PoolDoesNotExist)?; ensure!(pool_info.state == PoolState::Retired, Error::::InvalidPoolState); if let Some(basic_rewards) = basic_rewards { let basic_rewards_map: BTreeMap, BalanceOf> = @@ -728,7 +715,7 @@ pub mod pallet { pub fn kill_pool(origin: OriginFor, pid: PoolId) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; - let pool_info = Self::pool_infos(&pid).ok_or(Error::::PoolDoesNotExist)?; + let pool_info = PoolInfos::::get(&pid).ok_or(Error::::PoolDoesNotExist)?; ensure!( pool_info.state == PoolState::Retired || pool_info.state == PoolState::UnCharged, Error::::InvalidPoolState @@ -754,7 +741,7 @@ pub mod pallet { ) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; - let mut pool_info = Self::pool_infos(&pid).ok_or(Error::::PoolDoesNotExist)?; + let mut pool_info = PoolInfos::::get(&pid).ok_or(Error::::PoolDoesNotExist)?; ensure!( pool_info.state == PoolState::Retired || pool_info.state == PoolState::Ongoing || @@ -922,7 +909,7 @@ pub mod pallet { impl FarmingInfo, CurrencyIdOf> for Pallet { fn get_token_shares(pool_id: PoolId, currency_id: CurrencyIdOf) -> BalanceOf { - if let Some(pool_info) = Self::pool_infos(&pool_id) { + if let Some(pool_info) = PoolInfos::::get(&pool_id) { if let Some(token_proportion_value) = pool_info.tokens_proportion.get(¤cy_id) { let native_amount = pool_info.basic_token.1.saturating_reciprocal_mul(pool_info.total_shares); diff --git a/pallets/farming/src/tests.rs b/pallets/farming/src/tests.rs index a114c4467..7c6a9e765 100644 --- a/pallets/farming/src/tests.rs +++ b/pallets/farming/src/tests.rs @@ -28,7 +28,7 @@ use frame_support::{assert_err, assert_ok}; fn claim() { ExtBuilder::default().one_hundred_for_alice_n_bob().build().execute_with(|| { let (pid, _tokens) = init_no_gauge(); - // assert_eq!(Farming::shares_and_withdrawn_rewards(pid, &ALICE), ShareInfo::default()); + // assert_eq!(SharesAndWithdrawnRewards::::get(pid, &ALICE), ShareInfo::default()); assert_ok!(Farming::set_retire_limit(RuntimeOrigin::signed(ALICE), 10)); assert_err!( Farming::claim(RuntimeOrigin::signed(ALICE), pid), @@ -85,7 +85,7 @@ fn deposit() { gauge_last_block: 0, gauge_state: GaugeState::Bonded, }; - assert_eq!(Farming::gauge_pool_infos(0), Some(gauge_pool_info2)); + assert_eq!(GaugePoolInfos::::get(0), Some(gauge_pool_info2)); Farming::on_initialize(0); Farming::on_initialize(0); System::set_block_number(System::block_number() + 1000); @@ -118,7 +118,7 @@ fn withdraw() { assert_ok!(Farming::withdraw_claim(RuntimeOrigin::signed(ALICE), pid)); assert_eq!(Tokens::free_balance(KSM, &ALICE), 4166); assert_ok!(Farming::claim(RuntimeOrigin::signed(ALICE), pid)); - assert_eq!(Farming::shares_and_withdrawn_rewards(pid, &ALICE), None); + assert_eq!(SharesAndWithdrawnRewards::::get(pid, &ALICE), None); assert_eq!(Tokens::free_balance(KSM, &ALICE), 4166); let ed = ::MultiCurrency::minimum_balance(KSM); assert_eq!(Tokens::free_balance(KSM, &TREASURY_ACCOUNT), ed); @@ -130,7 +130,7 @@ fn gauge() { ExtBuilder::default().one_hundred_for_alice_n_bob().build().execute_with(|| { let (pid, tokens) = init_gauge(); assert_eq!(Tokens::free_balance(KSM, &ALICE), 2000); - if let Some(gauge_pool_infos) = Farming::gauge_pool_infos(0) { + if let Some(gauge_pool_infos) = GaugePoolInfos::::get(0) { assert_eq!( gauge_pool_infos.rewards, BTreeMap::< @@ -170,7 +170,7 @@ fn gauge_withdraw() { ExtBuilder::default().one_hundred_for_alice_n_bob().build().execute_with(|| { let (pid, _tokens) = init_gauge(); assert_eq!(Tokens::free_balance(KSM, &ALICE), 2000); - if let Some(gauge_pool_infos) = Farming::gauge_pool_infos(0) { + if let Some(gauge_pool_infos) = GaugePoolInfos::::get(0) { assert_eq!(gauge_pool_infos.gauge_amount, 0) }; Farming::on_initialize(0); @@ -181,7 +181,7 @@ fn gauge_withdraw() { System::set_block_number(System::block_number() + 1000); assert_ok!(Farming::gauge_withdraw(RuntimeOrigin::signed(ALICE), pid)); assert_eq!(Tokens::free_balance(KSM, &ALICE), 21017); - if let Some(gauge_pool_infos) = Farming::gauge_pool_infos(0) { + if let Some(gauge_pool_infos) = GaugePoolInfos::::get(0) { assert_eq!(gauge_pool_infos.gauge_amount, 0) }; }) @@ -202,7 +202,7 @@ fn retire() { System::set_block_number(System::block_number() + 1000); assert_ok!(Farming::force_retire_pool(RuntimeOrigin::signed(ALICE), pid)); assert_eq!(Tokens::free_balance(KSM, &ALICE), 3000); - assert_eq!(Farming::shares_and_withdrawn_rewards(pid, &ALICE), None); + assert_eq!(SharesAndWithdrawnRewards::::get(pid, &ALICE), None); }) } @@ -255,8 +255,8 @@ fn reset() { claim_limit_time: Default::default(), withdraw_limit_count: 5, }; - assert_eq!(Farming::pool_infos(0), Some(pool_infos)); - assert_eq!(Farming::gauge_pool_infos(1), None); + assert_eq!(PoolInfos::::get(0), Some(pool_infos)); + assert_eq!(GaugePoolInfos::::get(1), None); assert_eq!(Tokens::free_balance(KSM, &ALICE), 4018); let charge_rewards = vec![(KSM, 300000)]; assert_ok!(Farming::charge(RuntimeOrigin::signed(BOB), pid, charge_rewards, false)); @@ -377,7 +377,7 @@ fn create_farming_pool() { 6, 5 )); - if let Some(pool_infos) = Farming::pool_infos(0) { + if let Some(pool_infos) = PoolInfos::::get(0) { assert_eq!(pool_infos.state, PoolState::UnCharged) }; assert_ok!(Farming::kill_pool(RuntimeOrigin::signed(ALICE), 0)); @@ -385,7 +385,7 @@ fn create_farming_pool() { let pid = 1; let charge_rewards = vec![(KSM, 300000)]; assert_ok!(Farming::charge(RuntimeOrigin::signed(BOB), pid, charge_rewards, false)); - if let Some(pool_infos) = Farming::pool_infos(0) { + if let Some(pool_infos) = PoolInfos::::get(0) { assert_eq!(pool_infos.total_shares, 0); assert_eq!(pool_infos.min_deposit_to_start, 2); assert_eq!(pool_infos.state, PoolState::Charged) @@ -398,7 +398,7 @@ fn create_farming_pool() { assert_ok!(Farming::deposit(RuntimeOrigin::signed(ALICE), pid, tokens, Some((100, 100)))); Farming::on_initialize(System::block_number() + 3); Farming::on_initialize(0); - if let Some(pool_infos) = Farming::pool_infos(0) { + if let Some(pool_infos) = PoolInfos::::get(0) { assert_eq!(pool_infos.total_shares, 1000); assert_eq!(pool_infos.min_deposit_to_start, 2); assert_eq!(pool_infos.state, PoolState::Ongoing) From 72b00f4e4e1fef61db8ab5cce4d8036ed89b8bfd Mon Sep 17 00:00:00 2001 From: MJLNSN <96321798+MJLNSN@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:40:58 +0800 Subject: [PATCH 12/30] Removed getters in vesting. (#1447) * Removed getters in vesting * updated * updated --- pallets/vesting/src/lib.rs | 29 ++++++------ pallets/vesting/src/tests.rs | 89 +++++++++++++++++++----------------- 2 files changed, 59 insertions(+), 59 deletions(-) diff --git a/pallets/vesting/src/lib.rs b/pallets/vesting/src/lib.rs index cc2d4001d..c70f2754a 100644 --- a/pallets/vesting/src/lib.rs +++ b/pallets/vesting/src/lib.rs @@ -198,18 +198,15 @@ pub mod pallet { /// Start at #[pallet::storage] - #[pallet::getter(fn vesting_start_at)] pub(super) type VestingStartAt = StorageValue<_, BlockNumberFor>; /// Cliff vesting #[pallet::storage] - #[pallet::getter(fn cliffs)] pub(super) type Cliff = StorageMap<_, Blake2_128Concat, T::AccountId, BlockNumberFor>; /// Information regarding the vesting of a given account. #[pallet::storage] - #[pallet::getter(fn vesting)] pub type Vesting = StorageMap< _, Blake2_128Concat, @@ -425,7 +422,7 @@ pub mod pallet { let target = T::Lookup::lookup(target)?; let index = index as usize; Self::do_vest(target.clone())?; - let schedules = Self::vesting(&target).ok_or(Error::::NotVesting)?; + let schedules = Vesting::::get(&target).ok_or(Error::::NotVesting)?; ensure!(schedules.len() > index, Error::::ScheduleIndexOutOfBounds); ensure!(schedules[index].per_block() != per_block, Error::::SamePerBlock); @@ -509,7 +506,7 @@ pub mod pallet { let schedule1_index = schedule1_index as usize; let schedule2_index = schedule2_index as usize; - let schedules = Self::vesting(&who).ok_or(Error::::NotVesting)?; + let schedules = Vesting::::get(&who).ok_or(Error::::NotVesting)?; let merge_action = VestingAction::Merge { index1: schedule1_index, index2: schedule2_index }; @@ -542,9 +539,9 @@ impl Pallet { schedule2: VestingInfo, BlockNumberFor>, ) -> Option, BlockNumberFor>> { let schedule1_start_at = - Self::vesting_start_at().map(|st| st.saturating_add(schedule1.starting_block())); + VestingStartAt::::get().map(|st| st.saturating_add(schedule1.starting_block())); let schedule2_start_at = - Self::vesting_start_at().map(|st| st.saturating_add(schedule2.starting_block())); + VestingStartAt::::get().map(|st| st.saturating_add(schedule2.starting_block())); let schedule1_ending_block = schedule1.ending_block_as_balance::(); let schedule2_ending_block = schedule2.ending_block_as_balance::(); let now_as_balance = T::BlockNumberToBalance::convert(now); @@ -650,8 +647,8 @@ impl Pallet { let filtered_schedules = action .pick_schedules::(schedules) .filter(|schedule| { - let start_at = - Self::vesting_start_at().map(|st| st.saturating_add(schedule.starting_block())); + let start_at = VestingStartAt::::get() + .map(|st| st.saturating_add(schedule.starting_block())); let locked_now = schedule.locked_at::(now, start_at); let keep = !locked_now.is_zero(); if keep { @@ -700,7 +697,7 @@ impl Pallet { /// Unlock any vested funds of `who`. fn do_vest(who: T::AccountId) -> DispatchResult { - let schedules = Self::vesting(&who).ok_or(Error::::NotVesting)?; + let schedules = Vesting::::get(&who).ok_or(Error::::NotVesting)?; let (schedules, locked_now) = Self::exec_action(schedules.to_vec(), VestingAction::Passive)?; @@ -736,7 +733,7 @@ impl Pallet { // 1) need to add it to the accounts vesting schedule collection, schedules.push(new_schedule); // (we use `locked_at` in case this is a schedule that started in the past) - let start_at = Self::vesting_start_at() + let start_at = VestingStartAt::::get() .map(|st| st.saturating_add(new_schedule.starting_block())); let new_schedule_locked = new_schedule.locked_at::(now, start_at); @@ -767,11 +764,11 @@ where /// Get the amount that is currently being vested and cannot be transferred out of this account. fn vesting_balance(who: &T::AccountId) -> Option> { - if let Some(v) = Self::vesting(who) { + if let Some(v) = Vesting::::get(who) { let now = >::block_number(); let total_locked_now = v.iter().fold(Zero::zero(), |total, schedule| { - let start_at = - Self::vesting_start_at().map(|st| st.saturating_add(schedule.starting_block())); + let start_at = VestingStartAt::::get() + .map(|st| st.saturating_add(schedule.starting_block())); schedule .locked_at::(now, start_at) .saturating_add(total) @@ -810,7 +807,7 @@ where return Err(Error::::InvalidScheduleParams.into()); }; - let mut schedules = Self::vesting(who).unwrap_or_default(); + let mut schedules = Vesting::::get(who).unwrap_or_default(); // NOTE: we must push the new schedule so that `exec_action` // will give the correct new locked amount. @@ -848,7 +845,7 @@ where /// Remove a vesting schedule for a given account. fn remove_vesting_schedule(who: &T::AccountId, schedule_index: u32) -> DispatchResult { - let schedules = Self::vesting(who).ok_or(Error::::NotVesting)?; + let schedules = Vesting::::get(who).ok_or(Error::::NotVesting)?; let remove_action = VestingAction::Remove { index: schedule_index as usize }; let (schedules, locked_now) = Self::exec_action(schedules.to_vec(), remove_action)?; diff --git a/pallets/vesting/src/tests.rs b/pallets/vesting/src/tests.rs index 29aad6a74..ce02da117 100644 --- a/pallets/vesting/src/tests.rs +++ b/pallets/vesting/src/tests.rs @@ -21,7 +21,10 @@ use frame_system::RawOrigin; use sp_runtime::{traits::Identity, TokenError}; use super::{Vesting as VestingStorage, *}; -use crate::mock::{Balances, ExtBuilder, System, Test, Vesting}; +use crate::{ + mock::{Balances, ExtBuilder, System, Test, Vesting}, + Vesting as vesting, +}; const ED: u64 = 1000; @@ -71,9 +74,9 @@ fn check_vesting_status() { CHAR_PER_BLOCK, // Vesting over 20 blocks 10u64, ); - assert_eq!(Vesting::vesting(&ALICE).unwrap().to_vec(), vec![user1_vesting_schedule]); - assert_eq!(Vesting::vesting(&BOB).unwrap().to_vec(), vec![user2_vesting_schedule]); - assert_eq!(Vesting::vesting(&CHAR).unwrap().to_vec(), vec![user3_vesting_schedule]); + assert_eq!(vesting::::get(&ALICE).unwrap().to_vec(), vec![user1_vesting_schedule]); + assert_eq!(vesting::::get(&BOB).unwrap().to_vec(), vec![user2_vesting_schedule]); + assert_eq!(vesting::::get(&CHAR).unwrap().to_vec(), vec![user3_vesting_schedule]); }); } @@ -160,7 +163,7 @@ fn vested_transfer_should_work() { user1_vesting_schedule_2 )); assert_eq!( - Vesting::vesting(&ALICE).unwrap().to_vec(), + vesting::::get(&ALICE).unwrap().to_vec(), vec![user1_vesting_schedule_1, user1_vesting_schedule_2] ); }) @@ -208,7 +211,7 @@ fn do_vest_with_cliff_should_work() { //set start_at to 0 assert_ok!(Vesting::init_vesting_start_at(RawOrigin::Root.into(), 0)); assert_ok!(Vesting::force_set_cliff(RawOrigin::Root.into(), ALICE, 4)); - assert_eq!(Vesting::cliffs(ALICE), Some(4)); + assert_eq!(Cliff::::get(ALICE), Some(4)); //set block to 4 System::set_block_number(4); @@ -283,7 +286,7 @@ fn set_vesting_per_block_should_work() { //check result start_at 10 > now 5 => 10 start_at let user_vesting_schedule_1 = VestingInfo::new(20000, 100, 10); - assert_eq!(Vesting::vesting(&BOB).unwrap().to_vec(), vec![user_vesting_schedule_1]); + assert_eq!(vesting::::get(&BOB).unwrap().to_vec(), vec![user_vesting_schedule_1]); //set block to 15 System::set_block_number(15); @@ -298,7 +301,7 @@ fn set_vesting_per_block_should_work() { //old_start_at = old_start_block 10 + absolute_start 0 //remained_vesting = 20000 - 5 * 100 let user_vesting_schedule_2 = VestingInfo::new(20000 - 5 * 100, 10, 15); - assert_eq!(Vesting::vesting(&BOB).unwrap().to_vec(), vec![user_vesting_schedule_2]); + assert_eq!(vesting::::get(&BOB).unwrap().to_vec(), vec![user_vesting_schedule_2]); let bob_locked_2 = Balances::locks(BOB).to_vec()[0].amount; assert_eq!(bob_locked_1 - 5 * 100, bob_locked_2); }) @@ -323,7 +326,7 @@ fn set_vesting_per_block_with_start_at_should_work() { //check result old_start_at 12 > now 5 => 10 start_at let user_vesting_schedule_1 = VestingInfo::new(20000, 100, 10); - assert_eq!(Vesting::vesting(&BOB).unwrap().to_vec(), vec![user_vesting_schedule_1]); + assert_eq!(vesting::::get(&BOB).unwrap().to_vec(), vec![user_vesting_schedule_1]); //set block to 15 System::set_block_number(15); @@ -338,7 +341,7 @@ fn set_vesting_per_block_with_start_at_should_work() { //old_start_at 12 < now 15 => now 15 - absolute_start 2 = 13 //remained_vesting = 20000 - 3 * 100 let user_vesting_schedule_2 = VestingInfo::new(20000 - 3 * 100, 10, 13); - assert_eq!(Vesting::vesting(&BOB).unwrap().to_vec(), vec![user_vesting_schedule_2]); + assert_eq!(vesting::::get(&BOB).unwrap().to_vec(), vec![user_vesting_schedule_2]); let bob_locked_2 = Balances::locks(BOB).to_vec()[0].amount; assert_eq!(bob_locked_1 - 3 * 100, bob_locked_2); }) @@ -365,7 +368,7 @@ fn repeatedly_set_vesting_per_block_should_work() { user_vesting_schedule_3 )); assert_eq!( - Vesting::vesting(&BOB).unwrap().to_vec(), + vesting::::get(&BOB).unwrap().to_vec(), vec![user_vesting_schedule_1, user_vesting_schedule_2, user_vesting_schedule_3] ); @@ -388,7 +391,7 @@ fn repeatedly_set_vesting_per_block_should_work() { //check result old_start_at 12 > now 5 => 12 start_at let new_user_vesting_schedule_1 = VestingInfo::new(10000, 100, 12); assert_eq!( - Vesting::vesting(&BOB).unwrap().to_vec(), + vesting::::get(&BOB).unwrap().to_vec(), vec![user_vesting_schedule_1, new_user_vesting_schedule_1, user_vesting_schedule_3] ); @@ -406,7 +409,7 @@ fn repeatedly_set_vesting_per_block_should_work() { //remained_vesting = 20000 - 3 * 1000 let new_user_vesting_schedule_2 = VestingInfo::new(20000 - 3 * 1000, 10, 13); assert_eq!( - Vesting::vesting(&BOB).unwrap().to_vec(), + vesting::::get(&BOB).unwrap().to_vec(), vec![new_user_vesting_schedule_2, new_user_vesting_schedule_1, user_vesting_schedule_3] ); @@ -445,7 +448,7 @@ fn merge_schedules_has_not_started_should_work() { user_vesting_schedule_2 )); assert_eq!( - Vesting::vesting(&BOB).unwrap().to_vec(), + vesting::::get(&BOB).unwrap().to_vec(), vec![user_vesting_schedule_1, user_vesting_schedule_2] ); @@ -460,7 +463,7 @@ fn merge_schedules_has_not_started_should_work() { assert_ok!(Vesting::merge_schedules(RawOrigin::Signed(BOB).into(), 0, 1)); assert_eq!( - Vesting::vesting(&BOB).unwrap().to_vec(), + vesting::::get(&BOB).unwrap().to_vec(), vec![VestingInfo::new(BOB_INIT_LOCKED * 2, 2000, 12)] ); assert_eq!(40000, Balances::locks(BOB).to_vec()[0].amount); @@ -482,7 +485,7 @@ fn merge_ongoing_schedules_should_work() { user_vesting_schedule_2 )); assert_eq!( - Vesting::vesting(&BOB).unwrap().to_vec(), + vesting::::get(&BOB).unwrap().to_vec(), vec![user_vesting_schedule_1, user_vesting_schedule_2] ); @@ -497,7 +500,7 @@ fn merge_ongoing_schedules_should_work() { assert_ok!(Vesting::merge_schedules(RawOrigin::Signed(BOB).into(), 0, 1)); assert_eq!( - Vesting::vesting(&BOB).unwrap().to_vec(), + vesting::::get(&BOB).unwrap().to_vec(), vec![VestingInfo::new(BOB_INIT_LOCKED, 1000, 40)] ); assert_eq!(12000, Balances::locks(BOB).to_vec()[0].amount); @@ -519,7 +522,7 @@ fn merge_finished_schedules_should_work() { user_vesting_schedule_2 )); assert_eq!( - Vesting::vesting(&BOB).unwrap().to_vec(), + vesting::::get(&BOB).unwrap().to_vec(), vec![user_vesting_schedule_1, user_vesting_schedule_2] ); @@ -530,7 +533,7 @@ fn merge_finished_schedules_should_work() { //None assert_ok!(Vesting::merge_schedules(RawOrigin::Signed(BOB).into(), 0, 1)); - assert_eq!(Vesting::vesting(&BOB), None); + assert_eq!(vesting::::get(&BOB), None); assert_eq!(0, Balances::locks(BOB).to_vec().len()); }) } @@ -544,12 +547,12 @@ fn merge_schedules_that_have_not_started() { ED, // Vest over 20 blocks. 10, ); - assert_eq!(Vesting::vesting(&2).unwrap(), vec![sched0]); + assert_eq!(vesting::::get(&2).unwrap(), vec![sched0]); assert_eq!(Balances::usable_balance(&2), 0); // Add a schedule that is identical to the one that already exists. assert_ok!(Vesting::vested_transfer(Some(4).into(), 2, sched0)); - assert_eq!(Vesting::vesting(&2).unwrap(), vec![sched0, sched0]); + assert_eq!(vesting::::get(&2).unwrap(), vec![sched0, sched0]); assert_eq!(Balances::usable_balance(&2), 0); assert_ok!(Vesting::merge_schedules(Some(2).into(), 0, 1)); @@ -560,7 +563,7 @@ fn merge_schedules_that_have_not_started() { sched0.per_block() * 2, 10, // Starts at the block the schedules are merged/ ); - assert_eq!(Vesting::vesting(&2).unwrap(), vec![sched1]); + assert_eq!(vesting::::get(&2).unwrap(), vec![sched1]); assert_eq!(Balances::usable_balance(&2), 0); }); @@ -577,7 +580,7 @@ fn merge_ongoing_schedules() { ED, // Vest over 20 blocks. 10, ); - assert_eq!(Vesting::vesting(&2).unwrap(), vec![sched0]); + assert_eq!(vesting::::get(&2).unwrap(), vec![sched0]); let sched1 = VestingInfo::new( ED * 10, @@ -585,10 +588,10 @@ fn merge_ongoing_schedules() { sched0.starting_block() + 5, // Start at block 15. ); assert_ok!(Vesting::vested_transfer(Some(4).into(), 2, sched1)); - assert_eq!(Vesting::vesting(&2).unwrap(), vec![sched0, sched1]); + assert_eq!(vesting::::get(&2).unwrap(), vec![sched0, sched1]); // assert_ok!(Vesting::merge_schedules(Some(2).into(), 0, 1)); - // assert_eq!(Vesting::vesting(&2).unwrap(), vec![]); + // assert_eq!(vesting::::get(&2).unwrap(), vec![]); // Got to half way through the second schedule where both schedules are actively vesting. let cur_block = 20; @@ -620,7 +623,7 @@ fn merge_ongoing_schedules() { let sched2_per_block = sched2_locked / sched2_duration; let sched2 = VestingInfo::new(sched2_locked, sched2_per_block, cur_block); - assert_eq!(Vesting::vesting(&2).unwrap(), vec![sched2]); + assert_eq!(vesting::::get(&2).unwrap(), vec![sched2]); // And just to double check, we assert the new merged schedule we be cleaned up as expected. System::set_block_number(30); @@ -663,7 +666,7 @@ fn merging_shifts_other_schedules_index() { ); // Account 3 starts out with no schedules, - assert_eq!(Vesting::vesting(&3), None); + assert_eq!(vesting::::get(&3), None); // and some usable balance. let usable_balance = Balances::usable_balance(&3); assert_eq!(usable_balance, 30 * ED); @@ -677,7 +680,7 @@ fn merging_shifts_other_schedules_index() { assert_ok!(Vesting::vested_transfer(Some(4).into(), 3, sched2)); // With no schedules vested or merged they are in the order they are created - assert_eq!(Vesting::vesting(&3).unwrap(), vec![sched0, sched1, sched2]); + assert_eq!(vesting::::get(&3).unwrap(), vec![sched0, sched1, sched2]); // and the usable balance has not changed. assert_eq!(usable_balance, Balances::usable_balance(&3)); @@ -698,7 +701,7 @@ fn merging_shifts_other_schedules_index() { let sched3 = VestingInfo::new(sched3_locked, sched3_per_block, sched3_start); // The not touched schedule moves left and the new merged schedule is appended. - assert_eq!(Vesting::vesting(&3).unwrap(), vec![sched1, sched3]); + assert_eq!(vesting::::get(&3).unwrap(), vec![sched1, sched3]); // The usable balance hasn't changed since none of the schedules have started. assert_eq!(Balances::usable_balance(&3), usable_balance); }); @@ -716,7 +719,7 @@ fn merge_ongoing_and_yet_to_be_started_schedules() { ED, // Vesting over 20 blocks 10, ); - assert_eq!(Vesting::vesting(&2).unwrap(), vec![sched0]); + assert_eq!(vesting::::get(&2).unwrap(), vec![sched0]); // Fast forward to half way through the life of sched1. let mut cur_block = @@ -769,7 +772,7 @@ fn merge_ongoing_and_yet_to_be_started_schedules() { let sched2_per_block = sched2_locked / sched2_duration; let sched2 = VestingInfo::new(sched2_locked, sched2_per_block, sched2_start); - assert_eq!(Vesting::vesting(&2).unwrap(), vec![sched2]); + assert_eq!(vesting::::get(&2).unwrap(), vec![sched2]); }); } @@ -785,7 +788,7 @@ fn merge_finished_and_ongoing_schedules() { ED, // Vesting over 20 blocks. 10, ); - assert_eq!(Vesting::vesting(&2).unwrap(), vec![sched0]); + assert_eq!(vesting::::get(&2).unwrap(), vec![sched0]); let sched1 = VestingInfo::new( ED * 40, @@ -804,7 +807,7 @@ fn merge_finished_and_ongoing_schedules() { assert_ok!(Vesting::vested_transfer(Some(3).into(), 2, sched2)); // The schedules are in expected order prior to merging. - assert_eq!(Vesting::vesting(&2).unwrap(), vec![sched0, sched1, sched2]); + assert_eq!(vesting::::get(&2).unwrap(), vec![sched0, sched1, sched2]); // Fast forward to sched0's end block. let cur_block = sched0.ending_block_as_balance::(); @@ -819,7 +822,7 @@ fn merge_finished_and_ongoing_schedules() { // sched2 is now the first, since sched0 & sched1 get filtered out while "merging". // sched1 gets treated like the new merged schedule by getting pushed onto back // of the vesting schedules vec. Note: sched0 finished at the current block. - assert_eq!(Vesting::vesting(&2).unwrap(), vec![sched2, sched1]); + assert_eq!(vesting::::get(&2).unwrap(), vec![sched2, sched1]); // sched0 has finished, so its funds are fully unlocked. let sched0_unlocked_now = sched0.locked(); @@ -850,7 +853,7 @@ fn merge_finishing_schedules_does_not_create_a_new_one() { ED, // 20 block duration. 10, ); - assert_eq!(Vesting::vesting(&2).unwrap(), vec![sched0]); + assert_eq!(vesting::::get(&2).unwrap(), vec![sched0]); // Create sched1 and transfer it to account 2. let sched1 = VestingInfo::new( @@ -859,7 +862,7 @@ fn merge_finishing_schedules_does_not_create_a_new_one() { 10, ); assert_ok!(Vesting::vested_transfer(Some(3).into(), 2, sched1)); - assert_eq!(Vesting::vesting(&2).unwrap(), vec![sched0, sched1]); + assert_eq!(vesting::::get(&2).unwrap(), vec![sched0, sched1]); let all_scheds_end = sched0 .ending_block_as_balance::() @@ -893,7 +896,7 @@ fn merge_finished_and_yet_to_be_started_schedules() { ED, // 20 block duration. 10, // Ends at block 30 ); - assert_eq!(Vesting::vesting(&2).unwrap(), vec![sched0]); + assert_eq!(vesting::::get(&2).unwrap(), vec![sched0]); let sched1 = VestingInfo::new( ED * 30, @@ -901,7 +904,7 @@ fn merge_finished_and_yet_to_be_started_schedules() { 35, ); assert_ok!(Vesting::vested_transfer(Some(13).into(), 2, sched1)); - assert_eq!(Vesting::vesting(&2).unwrap(), vec![sched0, sched1]); + assert_eq!(vesting::::get(&2).unwrap(), vec![sched0, sched1]); let sched2 = VestingInfo::new( ED * 40, @@ -910,7 +913,7 @@ fn merge_finished_and_yet_to_be_started_schedules() { ); // Add a 3rd schedule to demonstrate how sched1 shifts. assert_ok!(Vesting::vested_transfer(Some(13).into(), 2, sched2)); - assert_eq!(Vesting::vesting(&2).unwrap(), vec![sched0, sched1, sched2]); + assert_eq!(vesting::::get(&2).unwrap(), vec![sched0, sched1, sched2]); System::set_block_number(30); @@ -925,7 +928,7 @@ fn merge_finished_and_yet_to_be_started_schedules() { // sched0 is removed since it finished, and sched1 is removed and then pushed on the back // because it is treated as the merged schedule - assert_eq!(Vesting::vesting(&2).unwrap(), vec![sched2, sched1]); + assert_eq!(vesting::::get(&2).unwrap(), vec![sched2, sched1]); // The usable balance is updated because merging fully unlocked sched0. assert_eq!(Balances::usable_balance(&2), sched0.locked()); @@ -941,7 +944,7 @@ fn merge_schedules_throws_proper_errors() { ED, // 20 block duration. 10, ); - assert_eq!(Vesting::vesting(&2).unwrap(), vec![sched0]); + assert_eq!(vesting::::get(&2).unwrap(), vec![sched0]); // Account 2 only has 1 vesting schedule. assert_noop!( @@ -950,12 +953,12 @@ fn merge_schedules_throws_proper_errors() { ); // Account 4 has 0 vesting schedules. - assert_eq!(Vesting::vesting(&4), None); + assert_eq!(vesting::::get(&4), None); assert_noop!(Vesting::merge_schedules(Some(4).into(), 0, 1), Error::::NotVesting); // There are enough schedules to merge but an index is non-existent. Vesting::vested_transfer(Some(3).into(), 2, sched0).unwrap(); - assert_eq!(Vesting::vesting(&2).unwrap(), vec![sched0, sched0]); + assert_eq!(vesting::::get(&2).unwrap(), vec![sched0, sched0]); assert_noop!( Vesting::merge_schedules(Some(2).into(), 0, 2), Error::::ScheduleIndexOutOfBounds From c97cdc22e58ee201948bd11929d0fba638aeef5d Mon Sep 17 00:00:00 2001 From: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Date: Mon, 30 Sep 2024 15:20:17 +0800 Subject: [PATCH 13/30] Feat/vtoken voting vbnc (#1442) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Bifrost v0.12.0 * remove old migrations * Fix vtokenVoting.removeDelegatorVote (#1288) * add PollClass type * add the calss parameter to the remove_delegator_vote method * Add metadata hash (#1299) * feat: 🎸 add buy-back * Bifrost v0.10.001 * feat: 🎸 benchmark * SLPx mint support commission id (#1261) * Add vtoken exchange rate rpc (#1260) * fix: 🐛 add event (#1263) * add update_currency_metadata function (#1259) * add update_currency_metadata function * fix: 🐛 correct update_currency_metadata weight * add the use of Vec (#1264) * Add vtoken exchange rate rpc * add the use of Vec * Upgrade to Polkadot-SDK v1.7.0 (#1262) * Bifrost v0.10.0 * fix: 🐛 clippy * Fix chain spec (#1243) * Upgrade to polkadot-v1.7.0 --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: Edwin Wang * Fix compile * feat: 🎸 add metadata-hash-extension (#1265) * feat: 🎸 add metadata-hash-extension * Fix compile (#1266) * Fix/fix vtoken voting unlock (#1267) * update the exchange rate of vtokenminting of vtokenvoting test * Resolve the frozen anomaly when unlocking * Revert "feat: 🎸 add metadata-hash-extension (#1265)" (#1268) This reverts commit 489fc9c6adeae44d23edf449e74fde3d6aa40bc3. * rename the version number to 0.11.0 * Slp supports XCMv4 and reconstruct integration tests (#1272) * Fix compile * Reconstruct integration tests and slp supports XCMv4 * Fix slp construct_xcm_message * Feat/slpx mint add commission (#1273) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * Feat/add vtoken exchange rate rpc (#1274) * Add vtoken exchange rate rpc * add the use of Vec * supplement the RPC logic && fix bugs * adjust the RPC exchange rate precision to three decimal places * fix clippy * fix bug: storage migration anomaly (#1276) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * fix bug: storage migration anomaly * Slp removes refund (#1275) * Slp removes refund * Fix clippy * Feat/add vtoken exchange rate rpc (#1277) * Add vtoken exchange rate rpc * add the use of Vec * supplement the RPC logic && fix bugs * adjust the RPC exchange rate precision to three decimal places * fix clippy * supplement omissions: adjust the RPC exchange rate precision to three decimal places * Remove dmp queue (#1279) * fix: 🐛 CheckMetadataHash to false * fix: 🐛 update sp-api * refactor: 💡 fmt * fix: 🐛 add metadata-hash * fix: 🐛 add feature metadata-hash * fix: 🐛 rm metadata-hash feature --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Co-authored-by: NingBo Wang <2536935847@qq.com> Co-authored-by: Edwin Wang * refactor: 💡 update MaxTurnout and whitelisted_caller track (#1304) * Allow to receive and send Ethereum assets (#1305) * feat: 🎸 add buy-back * Bifrost v0.10.001 * feat: 🎸 benchmark * SLPx mint support commission id (#1261) * Add vtoken exchange rate rpc (#1260) * fix: 🐛 add event (#1263) * add update_currency_metadata function (#1259) * add update_currency_metadata function * fix: 🐛 correct update_currency_metadata weight * add the use of Vec (#1264) * Add vtoken exchange rate rpc * add the use of Vec * Upgrade to Polkadot-SDK v1.7.0 (#1262) * Bifrost v0.10.0 * fix: 🐛 clippy * Fix chain spec (#1243) * Upgrade to polkadot-v1.7.0 --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: Edwin Wang * feat: 🎸 add metadata-hash-extension (#1265) * Fix compile (#1266) * Fix/fix vtoken voting unlock (#1267) * update the exchange rate of vtokenminting of vtokenvoting test * Resolve the frozen anomaly when unlocking * Revert "feat: 🎸 add metadata-hash-extension (#1265)" (#1268) This reverts commit 489fc9c6adeae44d23edf449e74fde3d6aa40bc3. * rename the version number to 0.11.0 * Slp supports XCMv4 and reconstruct integration tests (#1272) * Fix compile * Reconstruct integration tests and slp supports XCMv4 * Fix slp construct_xcm_message * Feat/slpx mint add commission (#1273) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * Feat/add vtoken exchange rate rpc (#1274) * Add vtoken exchange rate rpc * add the use of Vec * supplement the RPC logic && fix bugs * adjust the RPC exchange rate precision to three decimal places * fix clippy * fix bug: storage migration anomaly (#1276) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * fix bug: storage migration anomaly * Slp removes refund (#1275) * Slp removes refund * Fix clippy * Allow to receive and send Ethereum assets * Add constants --------- Co-authored-by: yooml Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Co-authored-by: Edwin Wang * Disable supplement_fee_reserve (#1306) * Remove call_switchgear and add tx_pause (#1308) * Remove call_switchgear and add tx_pause * Fix clippy * Optimize flexible fee (#1307) * Optimize flexible fee * Fix bug * Fix bug * Add PalletId * Add error handle * feat: 🎸 add market-bond * fix: 🐛 test-all * fix: 🐛 try-runtime * Add the channel_id field to the Minted event * Upgrade to polkadot-v1.13.0 (#1312) * Upgrade to polkadot-v1.13.0 * remove the warning * Fix dep issues * Upgrade to polkadot-v1.13.0 * supplement and upgrade the code * Upgrade the new parts from v0.12.0 * Fix dep issues * format Cargo.toml * Modify the AddOrigin type of the fellowship in bifrost-polkadot * Cancel the cross-in-out migration. * fix clippy --------- Co-authored-by: hqwangningbo <2536935847@qq.com> * Use github dependencies (#1314) * Fix flexible_fee TransferTo (#1315) * Refactor code structure: extract the vote operation from the relaychain. * Refactor code structure: extract the remove_vote operation from the relaychain. * Move the XCM-related methods into the relaychain_agent. * Move the call.rs into the relaychain_agent. * vtokenvoting functionality supports vBNC * Bifrost v0.13.0 * Remove getter in buy-back. (#1354) * Bifrost v0.12.0 * remove old migrations * Fix vtokenVoting.removeDelegatorVote (#1288) * add PollClass type * add the calss parameter to the remove_delegator_vote method * Add metadata hash (#1299) * feat: 🎸 add buy-back * Bifrost v0.10.001 * feat: 🎸 benchmark * SLPx mint support commission id (#1261) * Add vtoken exchange rate rpc (#1260) * fix: 🐛 add event (#1263) * add update_currency_metadata function (#1259) * add update_currency_metadata function * fix: 🐛 correct update_currency_metadata weight * add the use of Vec (#1264) * Add vtoken exchange rate rpc * add the use of Vec * Upgrade to Polkadot-SDK v1.7.0 (#1262) * Bifrost v0.10.0 * fix: 🐛 clippy * Fix chain spec (#1243) * Upgrade to polkadot-v1.7.0 --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: Edwin Wang * Fix compile * feat: 🎸 add metadata-hash-extension (#1265) * feat: 🎸 add metadata-hash-extension * Fix compile (#1266) * Fix/fix vtoken voting unlock (#1267) * update the exchange rate of vtokenminting of vtokenvoting test * Resolve the frozen anomaly when unlocking * Revert "feat: 🎸 add metadata-hash-extension (#1265)" (#1268) This reverts commit 489fc9c6adeae44d23edf449e74fde3d6aa40bc3. * rename the version number to 0.11.0 * Slp supports XCMv4 and reconstruct integration tests (#1272) * Fix compile * Reconstruct integration tests and slp supports XCMv4 * Fix slp construct_xcm_message * Feat/slpx mint add commission (#1273) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * Feat/add vtoken exchange rate rpc (#1274) * Add vtoken exchange rate rpc * add the use of Vec * supplement the RPC logic && fix bugs * adjust the RPC exchange rate precision to three decimal places * fix clippy * fix bug: storage migration anomaly (#1276) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * fix bug: storage migration anomaly * Slp removes refund (#1275) * Slp removes refund * Fix clippy * Feat/add vtoken exchange rate rpc (#1277) * Add vtoken exchange rate rpc * add the use of Vec * supplement the RPC logic && fix bugs * adjust the RPC exchange rate precision to three decimal places * fix clippy * supplement omissions: adjust the RPC exchange rate precision to three decimal places * Remove dmp queue (#1279) * fix: 🐛 CheckMetadataHash to false * fix: 🐛 update sp-api * refactor: 💡 fmt * fix: 🐛 add metadata-hash * fix: 🐛 add feature metadata-hash * fix: 🐛 rm metadata-hash feature --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Co-authored-by: NingBo Wang <2536935847@qq.com> Co-authored-by: Edwin Wang * refactor: 💡 update MaxTurnout and whitelisted_caller track (#1304) * Allow to receive and send Ethereum assets (#1305) * feat: 🎸 add buy-back * Bifrost v0.10.001 * feat: 🎸 benchmark * SLPx mint support commission id (#1261) * Add vtoken exchange rate rpc (#1260) * fix: 🐛 add event (#1263) * add update_currency_metadata function (#1259) * add update_currency_metadata function * fix: 🐛 correct update_currency_metadata weight * add the use of Vec (#1264) * Add vtoken exchange rate rpc * add the use of Vec * Upgrade to Polkadot-SDK v1.7.0 (#1262) * Bifrost v0.10.0 * fix: 🐛 clippy * Fix chain spec (#1243) * Upgrade to polkadot-v1.7.0 --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: Edwin Wang * feat: 🎸 add metadata-hash-extension (#1265) * Fix compile (#1266) * Fix/fix vtoken voting unlock (#1267) * update the exchange rate of vtokenminting of vtokenvoting test * Resolve the frozen anomaly when unlocking * Revert "feat: 🎸 add metadata-hash-extension (#1265)" (#1268) This reverts commit 489fc9c6adeae44d23edf449e74fde3d6aa40bc3. * rename the version number to 0.11.0 * Slp supports XCMv4 and reconstruct integration tests (#1272) * Fix compile * Reconstruct integration tests and slp supports XCMv4 * Fix slp construct_xcm_message * Feat/slpx mint add commission (#1273) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * Feat/add vtoken exchange rate rpc (#1274) * Add vtoken exchange rate rpc * add the use of Vec * supplement the RPC logic && fix bugs * adjust the RPC exchange rate precision to three decimal places * fix clippy * fix bug: storage migration anomaly (#1276) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * fix bug: storage migration anomaly * Slp removes refund (#1275) * Slp removes refund * Fix clippy * Allow to receive and send Ethereum assets * Add constants --------- Co-authored-by: yooml Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Co-authored-by: Edwin Wang * Disable supplement_fee_reserve (#1306) * Remove call_switchgear and add tx_pause (#1308) * Remove call_switchgear and add tx_pause * Fix clippy * Optimize flexible fee (#1307) * Optimize flexible fee * Fix bug * Fix bug * Add PalletId * Add error handle * feat: 🎸 add market-bond * fix: 🐛 test-all * fix: 🐛 try-runtime * Add the channel_id field to the Minted event * Upgrade to polkadot-v1.13.0 (#1312) * Upgrade to polkadot-v1.13.0 * remove the warning * Fix dep issues * Upgrade to polkadot-v1.13.0 * supplement and upgrade the code * Upgrade the new parts from v0.12.0 * Fix dep issues * format Cargo.toml * Modify the AddOrigin type of the fellowship in bifrost-polkadot * Cancel the cross-in-out migration. * fix clippy --------- Co-authored-by: hqwangningbo <2536935847@qq.com> * Use github dependencies (#1314) * Fix flexible_fee TransferTo (#1315) * Fix generate_genesis_state (#1317) * Optimize oracle (#1318) * refactor: 💡 optimize orml-oracle * fix: 🐛 MinimumTimestampInterval * style: 💄 rename to MaximumValueInterval * Add some tests for ve-minting * Add some tests for ve-minting * Integrate evm (#1319) * Update dep * Ingrate EVM * Fix deps * Add precompiles.rs * Remove pallet-hotfix-sufficients * Add pallet-evm-accounts * Evm precompiles * EVM integration * Fix compile * Fix rpc * Fix `encode_evm_address` and `decode_evm_address` * Fix evm precompile multicurrency * Implementing Erc20Mapping using xc-20 standard * Compatible with BNC Decimal * Increase min_gas_price * feat: enable dev mode with manual seal & fix pending block problem * Add copyright and fix some bugs * Change native token to WETH * Support evm flexible fee * Add inner_swap_exact_assets_for_assets to evm withdraw fee * Remove swap * EVM migration from bifrost kusama to bifrost polkadot * Fix erc20 precompile * Use OraclePrice * Fix some errors * feat: add prices genesis config & optimize dev mode code * Fix conflicts * Fix some errors * Fix clippy * Format Cargo.toml * Remove unused code * Fix clippy * Fix some errors * Fix erc20 precompile --------- Co-authored-by: Edwin Wang Co-authored-by: Damian.lu * Fix try-runtime (#1323) * Fix manual seal * Fix manual seal (#1324) * fix: 🐛 fellowship collective data (#1325) * fix: add parachain mock inherent data provider * Fix ethereum transfer fee (#1328) * Add evm genesis migration (#1338) * Bifrost v0.12.0 (#1286) * Bifrost v0.12.0 * remove old migrations * Fix vtokenVoting.removeDelegatorVote (#1288) * add PollClass type * add the calss parameter to the remove_delegator_vote method * Add metadata hash (#1299) * feat: 🎸 add buy-back * Bifrost v0.10.001 * feat: 🎸 benchmark * SLPx mint support commission id (#1261) * Add vtoken exchange rate rpc (#1260) * fix: 🐛 add event (#1263) * add update_currency_metadata function (#1259) * add update_currency_metadata function * fix: 🐛 correct update_currency_metadata weight * add the use of Vec (#1264) * Add vtoken exchange rate rpc * add the use of Vec * Upgrade to Polkadot-SDK v1.7.0 (#1262) * Bifrost v0.10.0 * fix: 🐛 clippy * Fix chain spec (#1243) * Upgrade to polkadot-v1.7.0 --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: Edwin Wang * Fix compile * feat: 🎸 add metadata-hash-extension (#1265) * feat: 🎸 add metadata-hash-extension * Fix compile (#1266) * Fix/fix vtoken voting unlock (#1267) * update the exchange rate of vtokenminting of vtokenvoting test * Resolve the frozen anomaly when unlocking * Revert "feat: 🎸 add metadata-hash-extension (#1265)" (#1268) This reverts commit 489fc9c6adeae44d23edf449e74fde3d6aa40bc3. * rename the version number to 0.11.0 * Slp supports XCMv4 and reconstruct integration tests (#1272) * Fix compile * Reconstruct integration tests and slp supports XCMv4 * Fix slp construct_xcm_message * Feat/slpx mint add commission (#1273) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * Feat/add vtoken exchange rate rpc (#1274) * Add vtoken exchange rate rpc * add the use of Vec * supplement the RPC logic && fix bugs * adjust the RPC exchange rate precision to three decimal places * fix clippy * fix bug: storage migration anomaly (#1276) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * fix bug: storage migration anomaly * Slp removes refund (#1275) * Slp removes refund * Fix clippy * Feat/add vtoken exchange rate rpc (#1277) * Add vtoken exchange rate rpc * add the use of Vec * supplement the RPC logic && fix bugs * adjust the RPC exchange rate precision to three decimal places * fix clippy * supplement omissions: adjust the RPC exchange rate precision to three decimal places * Remove dmp queue (#1279) * fix: 🐛 CheckMetadataHash to false * fix: 🐛 update sp-api * refactor: 💡 fmt * fix: 🐛 add metadata-hash * fix: 🐛 add feature metadata-hash * fix: 🐛 rm metadata-hash feature --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Co-authored-by: NingBo Wang <2536935847@qq.com> Co-authored-by: Edwin Wang * refactor: 💡 update MaxTurnout and whitelisted_caller track (#1304) * Allow to receive and send Ethereum assets (#1305) * feat: 🎸 add buy-back * Bifrost v0.10.001 * feat: 🎸 benchmark * SLPx mint support commission id (#1261) * Add vtoken exchange rate rpc (#1260) * fix: 🐛 add event (#1263) * add update_currency_metadata function (#1259) * add update_currency_metadata function * fix: 🐛 correct update_currency_metadata weight * add the use of Vec (#1264) * Add vtoken exchange rate rpc * add the use of Vec * Upgrade to Polkadot-SDK v1.7.0 (#1262) * Bifrost v0.10.0 * fix: 🐛 clippy * Fix chain spec (#1243) * Upgrade to polkadot-v1.7.0 --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: Edwin Wang * feat: 🎸 add metadata-hash-extension (#1265) * Fix compile (#1266) * Fix/fix vtoken voting unlock (#1267) * update the exchange rate of vtokenminting of vtokenvoting test * Resolve the frozen anomaly when unlocking * Revert "feat: 🎸 add metadata-hash-extension (#1265)" (#1268) This reverts commit 489fc9c6adeae44d23edf449e74fde3d6aa40bc3. * rename the version number to 0.11.0 * Slp supports XCMv4 and reconstruct integration tests (#1272) * Fix compile * Reconstruct integration tests and slp supports XCMv4 * Fix slp construct_xcm_message * Feat/slpx mint add commission (#1273) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * Feat/add vtoken exchange rate rpc (#1274) * Add vtoken exchange rate rpc * add the use of Vec * supplement the RPC logic && fix bugs * adjust the RPC exchange rate precision to three decimal places * fix clippy * fix bug: storage migration anomaly (#1276) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * fix bug: storage migration anomaly * Slp removes refund (#1275) * Slp removes refund * Fix clippy * Allow to receive and send Ethereum assets * Add constants --------- Co-authored-by: yooml Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Co-authored-by: Edwin Wang * Disable supplement_fee_reserve (#1306) * Remove call_switchgear and add tx_pause (#1308) * Remove call_switchgear and add tx_pause * Fix clippy * Optimize flexible fee (#1307) * Optimize flexible fee * Fix bug * Fix bug * Add PalletId * Add error handle * feat: 🎸 add market-bond * fix: 🐛 test-all * fix: 🐛 try-runtime * Add the channel_id field to the Minted event * Upgrade to polkadot-v1.13.0 (#1312) * Upgrade to polkadot-v1.13.0 * remove the warning * Fix dep issues * Upgrade to polkadot-v1.13.0 * supplement and upgrade the code * Upgrade the new parts from v0.12.0 * Fix dep issues * format Cargo.toml * Modify the AddOrigin type of the fellowship in bifrost-polkadot * Cancel the cross-in-out migration. * fix clippy --------- Co-authored-by: hqwangningbo <2536935847@qq.com> * Use github dependencies (#1314) * Fix flexible_fee TransferTo (#1315) * Fix generate_genesis_state (#1317) * Optimize oracle (#1318) * refactor: 💡 optimize orml-oracle * fix: 🐛 MinimumTimestampInterval * style: 💄 rename to MaximumValueInterval * Add some tests for ve-minting * Add some tests for ve-minting * Integrate evm (#1319) * Update dep * Ingrate EVM * Fix deps * Add precompiles.rs * Remove pallet-hotfix-sufficients * Add pallet-evm-accounts * Evm precompiles * EVM integration * Fix compile * Fix rpc * Fix `encode_evm_address` and `decode_evm_address` * Fix evm precompile multicurrency * Implementing Erc20Mapping using xc-20 standard * Compatible with BNC Decimal * Increase min_gas_price * feat: enable dev mode with manual seal & fix pending block problem * Add copyright and fix some bugs * Change native token to WETH * Support evm flexible fee * Add inner_swap_exact_assets_for_assets to evm withdraw fee * Remove swap * EVM migration from bifrost kusama to bifrost polkadot * Fix erc20 precompile * Use OraclePrice * Fix some errors * feat: add prices genesis config & optimize dev mode code * Fix conflicts * Fix some errors * Fix clippy * Format Cargo.toml * Remove unused code * Fix clippy * Fix some errors * Fix erc20 precompile --------- Co-authored-by: Edwin Wang Co-authored-by: Damian.lu * Fix try-runtime (#1323) * Fix manual seal * Fix manual seal (#1324) * fix: 🐛 fellowship collective data (#1325) * fix: add parachain mock inherent data provider * Fix ethereum transfer fee (#1328) --------- Co-authored-by: Edwin Wang Co-authored-by: yooml Co-authored-by: NingBo Wang <2536935847@qq.com> Co-authored-by: Gemma Co-authored-by: Damian.lu * Add evm genesis storage * [skip ci] Add evmSince --------- Co-authored-by: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Co-authored-by: Edwin Wang Co-authored-by: yooml Co-authored-by: Gemma Co-authored-by: Damian.lu * Bump version to 0.12.1 * Update Cargo.lock * Fix migration (#1341) * Bifrost v0.12.0 (#1286) * Bifrost v0.12.0 * remove old migrations * Fix vtokenVoting.removeDelegatorVote (#1288) * add PollClass type * add the calss parameter to the remove_delegator_vote method * Add metadata hash (#1299) * feat: 🎸 add buy-back * Bifrost v0.10.001 * feat: 🎸 benchmark * SLPx mint support commission id (#1261) * Add vtoken exchange rate rpc (#1260) * fix: 🐛 add event (#1263) * add update_currency_metadata function (#1259) * add update_currency_metadata function * fix: 🐛 correct update_currency_metadata weight * add the use of Vec (#1264) * Add vtoken exchange rate rpc * add the use of Vec * Upgrade to Polkadot-SDK v1.7.0 (#1262) * Bifrost v0.10.0 * fix: 🐛 clippy * Fix chain spec (#1243) * Upgrade to polkadot-v1.7.0 --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: Edwin Wang * Fix compile * feat: 🎸 add metadata-hash-extension (#1265) * feat: 🎸 add metadata-hash-extension * Fix compile (#1266) * Fix/fix vtoken voting unlock (#1267) * update the exchange rate of vtokenminting of vtokenvoting test * Resolve the frozen anomaly when unlocking * Revert "feat: 🎸 add metadata-hash-extension (#1265)" (#1268) This reverts commit 489fc9c6adeae44d23edf449e74fde3d6aa40bc3. * rename the version number to 0.11.0 * Slp supports XCMv4 and reconstruct integration tests (#1272) * Fix compile * Reconstruct integration tests and slp supports XCMv4 * Fix slp construct_xcm_message * Feat/slpx mint add commission (#1273) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * Feat/add vtoken exchange rate rpc (#1274) * Add vtoken exchange rate rpc * add the use of Vec * supplement the RPC logic && fix bugs * adjust the RPC exchange rate precision to three decimal places * fix clippy * fix bug: storage migration anomaly (#1276) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * fix bug: storage migration anomaly * Slp removes refund (#1275) * Slp removes refund * Fix clippy * Feat/add vtoken exchange rate rpc (#1277) * Add vtoken exchange rate rpc * add the use of Vec * supplement the RPC logic && fix bugs * adjust the RPC exchange rate precision to three decimal places * fix clippy * supplement omissions: adjust the RPC exchange rate precision to three decimal places * Remove dmp queue (#1279) * fix: 🐛 CheckMetadataHash to false * fix: 🐛 update sp-api * refactor: 💡 fmt * fix: 🐛 add metadata-hash * fix: 🐛 add feature metadata-hash * fix: 🐛 rm metadata-hash feature --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Co-authored-by: NingBo Wang <2536935847@qq.com> Co-authored-by: Edwin Wang * refactor: 💡 update MaxTurnout and whitelisted_caller track (#1304) * Allow to receive and send Ethereum assets (#1305) * feat: 🎸 add buy-back * Bifrost v0.10.001 * feat: 🎸 benchmark * SLPx mint support commission id (#1261) * Add vtoken exchange rate rpc (#1260) * fix: 🐛 add event (#1263) * add update_currency_metadata function (#1259) * add update_currency_metadata function * fix: 🐛 correct update_currency_metadata weight * add the use of Vec (#1264) * Add vtoken exchange rate rpc * add the use of Vec * Upgrade to Polkadot-SDK v1.7.0 (#1262) * Bifrost v0.10.0 * fix: 🐛 clippy * Fix chain spec (#1243) * Upgrade to polkadot-v1.7.0 --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: Edwin Wang * feat: 🎸 add metadata-hash-extension (#1265) * Fix compile (#1266) * Fix/fix vtoken voting unlock (#1267) * update the exchange rate of vtokenminting of vtokenvoting test * Resolve the frozen anomaly when unlocking * Revert "feat: 🎸 add metadata-hash-extension (#1265)" (#1268) This reverts commit 489fc9c6adeae44d23edf449e74fde3d6aa40bc3. * rename the version number to 0.11.0 * Slp supports XCMv4 and reconstruct integration tests (#1272) * Fix compile * Reconstruct integration tests and slp supports XCMv4 * Fix slp construct_xcm_message * Feat/slpx mint add commission (#1273) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * Feat/add vtoken exchange rate rpc (#1274) * Add vtoken exchange rate rpc * add the use of Vec * supplement the RPC logic && fix bugs * adjust the RPC exchange rate precision to three decimal places * fix clippy * fix bug: storage migration anomaly (#1276) * SLPx mint support commission id * remove the channel_id parameter from the mint method * add mint_with_channel_id method * perform data migration for OrderQueue storage * slpx: set the default value of channel_id to 0 * resolve conflicts * change the location of the old data structure during storage migration * fix bug: storage migration anomaly * Slp removes refund (#1275) * Slp removes refund * Fix clippy * Allow to receive and send Ethereum assets * Add constants --------- Co-authored-by: yooml Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Co-authored-by: Edwin Wang * Disable supplement_fee_reserve (#1306) * Remove call_switchgear and add tx_pause (#1308) * Remove call_switchgear and add tx_pause * Fix clippy * Optimize flexible fee (#1307) * Optimize flexible fee * Fix bug * Fix bug * Add PalletId * Add error handle * feat: 🎸 add market-bond * fix: 🐛 test-all * fix: 🐛 try-runtime * Add the channel_id field to the Minted event * Upgrade to polkadot-v1.13.0 (#1312) * Upgrade to polkadot-v1.13.0 * remove the warning * Fix dep issues * Upgrade to polkadot-v1.13.0 * supplement and upgrade the code * Upgrade the new parts from v0.12.0 * Fix dep issues * format Cargo.toml * Modify the AddOrigin type of the fellowship in bifrost-polkadot * Cancel the cross-in-out migration. * fix clippy --------- Co-authored-by: hqwangningbo <2536935847@qq.com> * Use github dependencies (#1314) * Fix flexible_fee TransferTo (#1315) * Fix generate_genesis_state (#1317) * Optimize oracle (#1318) * refactor: 💡 optimize orml-oracle * fix: 🐛 MinimumTimestampInterval * style: 💄 rename to MaximumValueInterval * Add some tests for ve-minting * Add some tests for ve-minting * Integrate evm (#1319) * Update dep * Ingrate EVM * Fix deps * Add precompiles.rs * Remove pallet-hotfix-sufficients * Add pallet-evm-accounts * Evm precompiles * EVM integration * Fix compile * Fix rpc * Fix `encode_evm_address` and `decode_evm_address` * Fix evm precompile multicurrency * Implementing Erc20Mapping using xc-20 standard * Compatible with BNC Decimal * Increase min_gas_price * feat: enable dev mode with manual seal & fix pending block problem * Add copyright and fix some bugs * Change native token to WETH * Support evm flexible fee * Add inner_swap_exact_assets_for_assets to evm withdraw fee * Remove swap * EVM migration from bifrost kusama to bifrost polkadot * Fix erc20 precompile * Use OraclePrice * Fix some errors * feat: add prices genesis config & optimize dev mode code * Fix conflicts * Fix some errors * Fix clippy * Format Cargo.toml * Remove unused code * Fix clippy * Fix some errors * Fix erc20 precompile --------- Co-authored-by: Edwin Wang Co-authored-by: Damian.lu * Fix try-runtime (#1323) * Fix manual seal * Fix manual seal (#1324) * fix: 🐛 fellowship collective data (#1325) * fix: add parachain mock inherent data provider * Fix ethereum transfer fee (#1328) --------- Co-authored-by: Edwin Wang Co-authored-by: yooml Co-authored-by: NingBo Wang <2536935847@qq.com> Co-authored-by: Gemma Co-authored-by: Damian.lu * Add evm genesis storage * [skip ci] Add evmSince * Fix migration * Fix migration * Remove unused code --------- Co-authored-by: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Co-authored-by: Edwin Wang Co-authored-by: yooml Co-authored-by: Gemma Co-authored-by: Damian.lu * Remove getter in buy-back --------- Co-authored-by: SunTiebing <1045060705@qq.com> Co-authored-by: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Co-authored-by: Edwin Wang Co-authored-by: yooml Co-authored-by: NingBo Wang <2536935847@qq.com> Co-authored-by: Damian.lu * Remove getters in xcm-interface (#1352) * Remove getters in salp. (#1351) * Remove getter in evm-accounts (#1350) * Remove getters in slp (#1353) * Remove getters in slpx (#1360) * Remove getters in vstoken-conversion. (#1362) * Remove getters in vtoken-minting. (#1363) * Remove getter in system-maker. (#1364) * Remove getter in fee-share (#1365) * Remove getters in prices (#1367) * Remove getters in lend-market (#1366) * Remove getters in ve-minting (#1368) * Optimize clippy (#1369) * Deprecated unused pallets (#1383) * Review format (#1386) * style: 💄 format * style: 💄 check-all * fix: 🐛 bench * Update buy back (#1387) * style: 💄 format * style: 💄 check-all * fix: 🐛 bench * feat: 🎸 add destruction_ratio * fix: 🐛 benchmark * EVM flexible fee logic optimization (#1370) * EVM flexible fee logic optimization * Add comments * Add support for handling different currency precisions & included error handling. * Adjust the gas_fee parameter in the get_balance_in_currency method to an exact value * fix clippy * add test code of flexiable-fee pallet * Update fee share (#1395) * feat: 🎸 add usd_cumulation * feat: 🎸 bench * fix: 🐛 fmt * docs: ✏️ add note * Feat/change evm address convert rule (#1396) * Change EVM Address convert rule * Change EVM Address convert rule * Remove the unused function:is_evm_account & rename truncated_account_id function to convert_account_id * fix clippy * refactor: 💡 move to TechAdmin (#1398) * refactor: 💡 transfer to BuyBackAccount (#1399) * Fix mint_with_channel_id weights (#1400) * Recoverd imgs of banner and logo (#1401) * feat: 🎸 add fn set_swap_out_min (#1389) * feat: 🎸 add fn set_swap_out_min * fix: 🐛 fmt * fix: 🐛 fmt * fix: 🐛 error * feat: 🎸 add bais * fix: 🐛 add test * fix: 🐛 rename field bias * Optimize the `channel-commission` code. (#1390) * Optimize the `channel-commission` code. * Replace the insert method with the mutate method * Added a result check for the clear_prefix method * Supplement the test code of `channel-commission`. * Handling Error cases in hooks. * Optimize the handling of the `check_removed_all` method. * Remove getters in cross-in-out (#1402) * Removed getters in channel-commission. (#1404) * Removed getters in flexible-fee. (#1405) * Removed getters in channel-commission. * Removed getters in flexible-fee. * Removed getters in parachain-staking. (#1406) * Removed getters in channel-commission. * Removed getters in flexible-fee. * Removed getterd in parachain-staking. * Update buy back (#1407) * fix: 🐛 add field last_buyback_cycle for accurate judgment * style: 💄 fmt * Update ve minting (#1408) * refactor: 💡 transfer to BuyBackAccount * feat: 🎸 add auto notify_reward * Optimize vtokenvoting pallet. * Use the call.dispatch method to support vBNC in vTokenVoting. * Use the call.dispatch method to support vBNC in vTokenVoting. * adjust mock file * Change the way the vtoken-voting pallet interacts with other runtime pallets to a decoding-based approach. * Plump vtokenvoting supports vbnc * optimize test * optimize reviewed code * Add vtoken-voting Kusama tests to the test-all command. --------- Co-authored-by: Edwin Wang Co-authored-by: yooml Co-authored-by: NingBo Wang <2536935847@qq.com> Co-authored-by: MJLNSN <96321798+MJLNSN@users.noreply.github.com> Co-authored-by: Damian.lu --- Makefile | 5 +- pallets/slp/src/lib.rs | 15 +- pallets/vtoken-minting/src/lib.rs | 2 +- .../src/agents/bifrost_agent/agent.rs | 150 ++ .../src/agents/bifrost_agent/call.rs | 73 + .../src/agents/bifrost_agent/mod.rs | 22 + pallets/vtoken-voting/src/agents/mod.rs | 23 + .../src/agents/relaychain_agent/agent.rs | 120 ++ .../src/{ => agents/relaychain_agent}/call.rs | 35 +- .../src/agents/relaychain_agent/mod.rs | 22 + pallets/vtoken-voting/src/lib.rs | 584 +++--- pallets/vtoken-voting/src/mock.rs | 149 +- pallets/vtoken-voting/src/tests.rs | 1379 --------------- .../vtoken-voting/src/tests/common_test.rs | 1564 +++++++++++++++++ pallets/vtoken-voting/src/tests/mod.rs | 23 + pallets/vtoken-voting/src/tests/vbnc_test.rs | 841 +++++++++ pallets/vtoken-voting/src/traits.rs | 142 ++ pallets/vtoken-voting/src/vote.rs | 4 +- primitives/src/traits.rs | 4 +- runtime/bifrost-kusama/src/lib.rs | 1 + runtime/bifrost-polkadot/src/lib.rs | 1 + 21 files changed, 3526 insertions(+), 1633 deletions(-) create mode 100644 pallets/vtoken-voting/src/agents/bifrost_agent/agent.rs create mode 100644 pallets/vtoken-voting/src/agents/bifrost_agent/call.rs create mode 100644 pallets/vtoken-voting/src/agents/bifrost_agent/mod.rs create mode 100644 pallets/vtoken-voting/src/agents/mod.rs create mode 100644 pallets/vtoken-voting/src/agents/relaychain_agent/agent.rs rename pallets/vtoken-voting/src/{ => agents/relaychain_agent}/call.rs (78%) create mode 100644 pallets/vtoken-voting/src/agents/relaychain_agent/mod.rs delete mode 100644 pallets/vtoken-voting/src/tests.rs create mode 100644 pallets/vtoken-voting/src/tests/common_test.rs create mode 100644 pallets/vtoken-voting/src/tests/mod.rs create mode 100644 pallets/vtoken-voting/src/tests/vbnc_test.rs create mode 100644 pallets/vtoken-voting/src/traits.rs diff --git a/Makefile b/Makefile index 121749f9c..e72e6af14 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ check-all: format SKIP_WASM_BUILD= cargo check -p bifrost-cli --locked --features "with-all-runtime,runtime-benchmarks,try-runtime" .PHONY: test-all # cargo test all -test-all: test-runtimes test-benchmarks +test-all: test-runtimes test-benchmarks test-vtoken-voting-kusama .PHONY: test-runtimes test-runtimes: @@ -40,6 +40,9 @@ test-runtimes: test-benchmarks: SKIP_WASM_BUILD= cargo test benchmarking --features="with-bifrost-runtime, runtime-benchmarks, polkadot" +test-vtoken-voting-kusama: + SKIP_WASM_BUILD= cargo test -p bifrost-vtoken-voting --features="kusama, runtime-benchmarks" + .PHONY: clean # cargo clean clean: cargo clean diff --git a/pallets/slp/src/lib.rs b/pallets/slp/src/lib.rs index d4a5fd67a..4ca0f422a 100644 --- a/pallets/slp/src/lib.rs +++ b/pallets/slp/src/lib.rs @@ -2254,7 +2254,8 @@ pub mod pallet { pub struct DerivativeAccountProvider(PhantomData<(T, F)>); impl>> - DerivativeAccountHandler, BalanceOf> for DerivativeAccountProvider + DerivativeAccountHandler, BalanceOf, AccountIdOf> + for DerivativeAccountProvider { fn check_derivative_index_exists( token: CurrencyIdOf, @@ -2270,6 +2271,18 @@ impl>> DelegatorsIndex2Multilocation::::get(token, derivative_index) } + fn get_account_id( + token: CurrencyIdOf, + derivative_index: DerivativeIndex, + ) -> Option> { + Self::get_multilocation(token, derivative_index).and_then(|location| { + location.interior.last().and_then(|interior| match interior { + AccountId32 { id, .. } => T::AccountId::decode(&mut &id[..]).ok(), + _ => None, + }) + }) + } + fn get_stake_info( token: CurrencyIdOf, derivative_index: DerivativeIndex, diff --git a/pallets/vtoken-minting/src/lib.rs b/pallets/vtoken-minting/src/lib.rs index 687ee5475..b145c2de7 100644 --- a/pallets/vtoken-minting/src/lib.rs +++ b/pallets/vtoken-minting/src/lib.rs @@ -2182,7 +2182,7 @@ impl VTokenSupplyProvider, BalanceOf> for Pallet) -> Option> { - if CurrencyId::is_token(&token) { + if CurrencyId::is_token(&token) | CurrencyId::is_native(&token) { Some(TokenPool::::get(token)) } else { None diff --git a/pallets/vtoken-voting/src/agents/bifrost_agent/agent.rs b/pallets/vtoken-voting/src/agents/bifrost_agent/agent.rs new file mode 100644 index 000000000..24c250a24 --- /dev/null +++ b/pallets/vtoken-voting/src/agents/bifrost_agent/agent.rs @@ -0,0 +1,150 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 crate::*; +use bifrost_primitives::{CurrencyId, DerivativeIndex}; +use frame_support::pallet_prelude::*; +use xcm::v4::Location; + +use crate::{agents::bifrost_agent::BifrostCall, pallet::Error, traits::*}; + +/// VotingAgent implementation for Bifrost +pub struct BifrostAgent { + vtoken: CurrencyIdOf, + location: Location, +} + +impl BifrostAgent { + // Only polkadot networks are supported. + pub fn new(vtoken: CurrencyId) -> Result> { + if cfg!(feature = "polkadot") { + let location = Pallet::::convert_vtoken_to_dest_location(vtoken)?; + Ok(Self { vtoken, location }) + } else { + Err(Error::::VTokenNotSupport) + } + } +} + +impl VotingAgent for BifrostAgent { + fn vtoken(&self) -> CurrencyIdOf { + self.vtoken + } + + fn location(&self) -> Location { + self.location.clone() + } + + fn delegate_vote( + &self, + who: AccountIdOf, + vtoken: CurrencyIdOf, + poll_index: PollIndex, + _submitted: bool, + new_delegator_votes: Vec<(DerivativeIndex, AccountVote>)>, + maybe_old_vote: Option<(AccountVote>, BalanceOf)>, + ) -> DispatchResult { + // Get the derivative index from the first delegator vote. + let derivative_index = new_delegator_votes[0].0; + let call_encode = + self.vote_call_encode(new_delegator_votes, poll_index, derivative_index)?; + let vote_call: ::RuntimeCall = + ::RuntimeCall::decode(&mut &*call_encode) + .map_err(|_| Error::::CallDecodeFailed)?; + + let token = CurrencyId::to_token(&vtoken).map_err(|_| Error::::NoData)?; + let delegator: AccountIdOf = + T::DerivativeAccount::get_account_id(token, derivative_index) + .ok_or(Error::::NoData)?; + let origin = RawOrigin::Signed(delegator).into(); + let success = vote_call.dispatch(origin).is_ok(); + Pallet::::handle_vote_result( + success, + who, + vtoken, + poll_index, + maybe_old_vote, + derivative_index, + )?; + + if success { + Ok(()) + } else { + Err(Error::::InvalidCallDispatch.into()) + } + } + + fn vote_call_encode( + &self, + new_delegator_votes: Vec<(DerivativeIndex, AccountVote>)>, + poll_index: PollIndex, + _derivative_index: DerivativeIndex, + ) -> Result, Error> { + let vote_calls = new_delegator_votes + .iter() + .map(|(_derivative_index, vote)| { + as ConvictionVotingCall>::vote(poll_index, *vote) + }) + .collect::>(); + let vote_call = if vote_calls.len() == 1 { + vote_calls.into_iter().nth(0).ok_or(Error::::NoData)? + } else { + ensure!(false, Error::::NoPermissionYet); + as UtilityCall>>::batch_all(vote_calls) + }; + + Ok(vote_call.encode()) + } + + fn delegate_remove_delegator_vote( + &self, + vtoken: CurrencyIdOf, + poll_index: PollIndex, + class: PollClass, + derivative_index: DerivativeIndex, + ) -> DispatchResult { + let call_encode = + self.remove_delegator_vote_call_encode(class, poll_index, derivative_index)?; + let call = ::RuntimeCall::decode(&mut &*call_encode) + .map_err(|_| Error::::CallDecodeFailed)?; + + let token = CurrencyId::to_token(&vtoken).map_err(|_| Error::::NoData)?; + let delegator: AccountIdOf = + T::DerivativeAccount::get_account_id(token, derivative_index) + .ok_or(Error::::NoData)?; + let origin = RawOrigin::Signed(delegator).into(); + let success = call.dispatch(origin).is_ok(); + + if success { + Pallet::::handle_remove_delegator_vote_success(vtoken, poll_index); + Ok(()) + } else { + Err(Error::::InvalidCallDispatch.into()) + } + } + + fn remove_delegator_vote_call_encode( + &self, + class: PollClass, + poll_index: PollIndex, + _derivative_index: DerivativeIndex, + ) -> Result, Error> { + Ok( as ConvictionVotingCall>::remove_vote(Some(class), poll_index) + .encode()) + } +} diff --git a/pallets/vtoken-voting/src/agents/bifrost_agent/call.rs b/pallets/vtoken-voting/src/agents/bifrost_agent/call.rs new file mode 100644 index 000000000..ee89348e3 --- /dev/null +++ b/pallets/vtoken-voting/src/agents/bifrost_agent/call.rs @@ -0,0 +1,73 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 crate::{traits::*, *}; +use parity_scale_codec::{Decode, Encode}; +use sp_runtime::{traits::StaticLookup, RuntimeDebug}; + +pub(in crate::agents::bifrost_agent) use bifrost::*; + +pub(in crate::agents::bifrost_agent) mod bifrost { + use crate::agents::bifrost_agent::call::*; + + #[derive(Encode, Decode, RuntimeDebug)] + pub(in crate::agents::bifrost_agent) enum BifrostCall { + #[codec(index = 36)] + ConvictionVoting(ConvictionVoting), + #[codec(index = 50)] + Utility(Utility), + } +} + +#[derive(Encode, Decode, RuntimeDebug, Clone)] +pub(in crate::agents::bifrost_agent) enum ConvictionVoting { + #[codec(index = 0)] + Vote(#[codec(compact)] PollIndex, AccountVote>), + #[codec(index = 3)] + Unlock(PollClass, ::Source), + #[codec(index = 4)] + RemoveVote(Option, PollIndex), +} + +impl ConvictionVotingCall for BifrostCall { + fn vote(poll_index: PollIndex, vote: AccountVote>) -> Self { + Self::ConvictionVoting(ConvictionVoting::Vote(poll_index, vote)) + } + + fn remove_vote(class: Option, poll_index: PollIndex) -> Self { + Self::ConvictionVoting(ConvictionVoting::RemoveVote(class, poll_index)) + } +} + +#[derive(Encode, Decode, RuntimeDebug, Clone)] +pub(in crate::agents::bifrost_agent) enum Utility { + #[codec(index = 1)] + AsDerivative(DerivativeIndex, Box), + #[codec(index = 2)] + BatchAll(Vec), +} + +impl UtilityCall> for BifrostCall { + fn as_derivative(derivative_index: DerivativeIndex, call: Self) -> Self { + Self::Utility(Utility::AsDerivative(derivative_index, Box::new(call))) + } + + fn batch_all(calls: Vec) -> Self { + Self::Utility(Utility::BatchAll(calls)) + } +} diff --git a/pallets/vtoken-voting/src/agents/bifrost_agent/mod.rs b/pallets/vtoken-voting/src/agents/bifrost_agent/mod.rs new file mode 100644 index 000000000..533ae6ef3 --- /dev/null +++ b/pallets/vtoken-voting/src/agents/bifrost_agent/mod.rs @@ -0,0 +1,22 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . +pub mod agent; +mod call; + +pub use agent::*; +pub(in crate::agents::bifrost_agent) use call::*; diff --git a/pallets/vtoken-voting/src/agents/mod.rs b/pallets/vtoken-voting/src/agents/mod.rs new file mode 100644 index 000000000..b89becf7d --- /dev/null +++ b/pallets/vtoken-voting/src/agents/mod.rs @@ -0,0 +1,23 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . + +mod bifrost_agent; +mod relaychain_agent; + +pub use bifrost_agent::*; +pub use relaychain_agent::*; diff --git a/pallets/vtoken-voting/src/agents/relaychain_agent/agent.rs b/pallets/vtoken-voting/src/agents/relaychain_agent/agent.rs new file mode 100644 index 000000000..73e2a9b2e --- /dev/null +++ b/pallets/vtoken-voting/src/agents/relaychain_agent/agent.rs @@ -0,0 +1,120 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 crate::*; +use bifrost_primitives::{CurrencyId, DerivativeIndex}; +use frame_support::{ensure, pallet_prelude::*}; +use xcm::v4::Location; + +use crate::{agents::relaychain_agent::call::*, pallet::Error, traits::*}; + +/// VotingAgent implementation for relay chain +pub struct RelaychainAgent { + vtoken: CurrencyIdOf, + location: Location, +} +impl RelaychainAgent { + pub fn new(vtoken: CurrencyId) -> Result> { + let location = Pallet::::convert_vtoken_to_dest_location(vtoken)?; + Ok(Self { vtoken, location }) + } +} + +impl VotingAgent for RelaychainAgent { + fn vtoken(&self) -> CurrencyIdOf { + self.vtoken + } + + fn location(&self) -> Location { + self.location.clone() + } + fn delegate_vote( + &self, + who: AccountIdOf, + vtoken: CurrencyIdOf, + poll_index: PollIndex, + submitted: bool, + new_delegator_votes: Vec<(DerivativeIndex, AccountVote>)>, + maybe_old_vote: Option<(AccountVote>, BalanceOf)>, + ) -> DispatchResult { + Pallet::::send_xcm_vote_message( + who, + vtoken, + poll_index, + submitted, + new_delegator_votes, + maybe_old_vote, + ) + } + + fn vote_call_encode( + &self, + new_delegator_votes: Vec<(DerivativeIndex, AccountVote>)>, + poll_index: PollIndex, + derivative_index: DerivativeIndex, + ) -> Result, Error> { + let vote_calls = new_delegator_votes + .iter() + .map(|(_derivative_index, vote)| { + as ConvictionVotingCall>::vote(poll_index, *vote) + }) + .collect::>(); + let vote_call = if vote_calls.len() == 1 { + vote_calls.into_iter().nth(0).ok_or(Error::::NoData)? + } else { + ensure!(false, Error::::NoPermissionYet); + as UtilityCall>>::batch_all(vote_calls) + }; + + let encode_call = + as UtilityCall>>::as_derivative(derivative_index, vote_call) + .encode(); + + Ok(encode_call) + } + + fn delegate_remove_delegator_vote( + &self, + vtoken: CurrencyIdOf, + poll_index: PollIndex, + class: PollClass, + derivative_index: DerivativeIndex, + ) -> DispatchResult { + Pallet::::send_xcm_remove_delegator_vote_message( + vtoken, + poll_index, + class, + derivative_index, + ) + } + + fn remove_delegator_vote_call_encode( + &self, + class: PollClass, + poll_index: PollIndex, + derivative_index: DerivativeIndex, + ) -> Result, Error> { + let remove_vote_call = + as ConvictionVotingCall>::remove_vote(Some(class), poll_index); + Ok( as UtilityCall>>::as_derivative( + derivative_index, + remove_vote_call, + ) + .encode()) + } +} diff --git a/pallets/vtoken-voting/src/call.rs b/pallets/vtoken-voting/src/agents/relaychain_agent/call.rs similarity index 78% rename from pallets/vtoken-voting/src/call.rs rename to pallets/vtoken-voting/src/agents/relaychain_agent/call.rs index 956d2a15a..8fb6ce1f1 100644 --- a/pallets/vtoken-voting/src/call.rs +++ b/pallets/vtoken-voting/src/agents/relaychain_agent/call.rs @@ -19,23 +19,22 @@ #![allow(ambiguous_glob_reexports)] #![allow(unused_imports)] -use crate::{AccountVote, BalanceOf, Config, DerivativeIndex, PollClass, PollIndex}; +use crate::{traits::*, *}; use parity_scale_codec::{Decode, Encode}; use sp_runtime::{traits::StaticLookup, RuntimeDebug}; -use sp_std::prelude::*; #[cfg(feature = "kusama")] -pub use kusama::*; +pub(in crate::agents::relaychain_agent) use kusama::*; #[cfg(feature = "polkadot")] -pub use polkadot::*; +pub(in crate::agents::relaychain_agent) use polkadot::*; #[cfg(feature = "kusama")] -mod kusama { - use crate::*; +pub(in crate::agents::relaychain_agent) mod kusama { + use crate::agents::relaychain_agent::call::*; #[derive(Encode, Decode, RuntimeDebug)] - pub enum RelayCall { + pub(in crate::agents::relaychain_agent) enum RelayCall { #[codec(index = 20)] ConvictionVoting(ConvictionVoting), #[codec(index = 24)] @@ -44,11 +43,11 @@ mod kusama { } #[cfg(feature = "polkadot")] -mod polkadot { - use crate::*; +pub(in crate::agents::relaychain_agent) mod polkadot { + use crate::agents::relaychain_agent::call::*; #[derive(Encode, Decode, RuntimeDebug)] - pub enum RelayCall { + pub(in crate::agents::relaychain_agent) enum RelayCall { #[codec(index = 20)] ConvictionVoting(ConvictionVoting), #[codec(index = 26)] @@ -57,7 +56,7 @@ mod polkadot { } #[derive(Encode, Decode, RuntimeDebug, Clone)] -pub enum ConvictionVoting { +pub(in crate::agents::relaychain_agent) enum ConvictionVoting { #[codec(index = 0)] Vote(#[codec(compact)] PollIndex, AccountVote>), #[codec(index = 3)] @@ -66,12 +65,6 @@ pub enum ConvictionVoting { RemoveVote(Option, PollIndex), } -pub trait ConvictionVotingCall { - fn vote(poll_index: PollIndex, vote: AccountVote>) -> Self; - - fn remove_vote(class: Option, poll_index: PollIndex) -> Self; -} - impl ConvictionVotingCall for RelayCall { fn vote(poll_index: PollIndex, vote: AccountVote>) -> Self { Self::ConvictionVoting(ConvictionVoting::Vote(poll_index, vote)) @@ -83,19 +76,13 @@ impl ConvictionVotingCall for RelayCall { } #[derive(Encode, Decode, RuntimeDebug, Clone)] -pub enum Utility { +pub(in crate::agents::relaychain_agent) enum Utility { #[codec(index = 1)] AsDerivative(DerivativeIndex, Box), #[codec(index = 2)] BatchAll(Vec), } -pub trait UtilityCall { - fn as_derivative(derivative_index: DerivativeIndex, call: Call) -> Call; - - fn batch_all(calls: Vec) -> Call; -} - impl UtilityCall> for RelayCall { fn as_derivative(derivative_index: DerivativeIndex, call: Self) -> Self { Self::Utility(Utility::AsDerivative(derivative_index, Box::new(call))) diff --git a/pallets/vtoken-voting/src/agents/relaychain_agent/mod.rs b/pallets/vtoken-voting/src/agents/relaychain_agent/mod.rs new file mode 100644 index 000000000..321c37045 --- /dev/null +++ b/pallets/vtoken-voting/src/agents/relaychain_agent/mod.rs @@ -0,0 +1,22 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . + +pub mod agent; +mod call; + +pub use agent::*; diff --git a/pallets/vtoken-voting/src/lib.rs b/pallets/vtoken-voting/src/lib.rs index 5d99397b8..95d4bd80b 100644 --- a/pallets/vtoken-voting/src/lib.rs +++ b/pallets/vtoken-voting/src/lib.rs @@ -27,41 +27,48 @@ mod mock; #[cfg(test)] mod tests; -mod call; +mod agents; mod vote; // pub mod migration; +pub mod traits; pub mod weights; -use crate::vote::{Casting, Tally, Voting}; -pub use crate::{ - call::*, - vote::{AccountVote, PollStatus, ReferendumInfo, ReferendumStatus, VoteRole}, +pub use crate::vote::{AccountVote, PollStatus, ReferendumInfo, ReferendumStatus, VoteRole}; +use crate::{ + agents::{BifrostAgent, RelaychainAgent}, + traits::VotingAgent, + vote::{Casting, Tally, Voting}, }; use bifrost_primitives::{ - currency::{VDOT, VKSM}, + currency::{BNC, DOT, KSM, VBNC, VDOT, VKSM}, traits::{DerivativeAccountHandler, VTokenSupplyProvider, XcmDestWeightAndFeeHandler}, CurrencyId, DerivativeIndex, XcmOperationType, }; use cumulus_primitives_core::{ParaId, QueryId, Response}; use frame_support::{ - dispatch::GetDispatchInfo, + dispatch::{GetDispatchInfo, PostDispatchInfo}, pallet_prelude::*, traits::{Get, LockIdentifier}, }; -use frame_system::pallet_prelude::{BlockNumberFor, *}; +use frame_system::{ + pallet_prelude::{BlockNumberFor, *}, + RawOrigin, +}; use orml_traits::{MultiCurrency, MultiLockableCurrency}; pub use pallet::*; +pub use pallet_conviction_voting::AccountVote as ConvictionVotingAccountVote; use pallet_conviction_voting::{Conviction, UnvoteScope, Vote}; use sp_runtime::{ traits::{ - BlockNumberProvider, Bounded, CheckedDiv, CheckedMul, Saturating, UniqueSaturatedInto, Zero, + BlockNumberProvider, Bounded, CheckedDiv, CheckedMul, Dispatchable, Saturating, + UniqueSaturatedInto, Zero, }, ArithmeticError, Perbill, }; -use sp_std::prelude::*; +use sp_std::{boxed::Box, vec::Vec}; pub use weights::WeightInfo; -use xcm::v4::{prelude::*, Weight as XcmWeight}; +use xcm::v4::{prelude::*, Location, Weight as XcmWeight}; const CONVICTION_VOTING_ID: LockIdentifier = *b"vtvoting"; @@ -82,9 +89,12 @@ type VotingOf = pub type ReferendumInfoOf = ReferendumInfo, TallyOf>; +type VotingAgentBoxType = Box>; + #[frame_support::pallet] pub mod pallet { use super::*; + use frame_support::traits::CallerTrait; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(3); @@ -102,7 +112,11 @@ pub mod pallet { type RuntimeCall: IsType<::RuntimeCall> + From> - + GetDispatchInfo; + + GetDispatchInfo + + Dispatchable< + RuntimeOrigin = ::RuntimeOrigin, + PostInfo = PostDispatchInfo, + > + Parameter; type MultiCurrency: MultiLockableCurrency, CurrencyId = CurrencyId>; @@ -110,12 +124,16 @@ pub mod pallet { type ResponseOrigin: EnsureOrigin< ::RuntimeOrigin, - Success = xcm::v4::Location, + Success = Location, >; type XcmDestWeightAndFee: XcmDestWeightAndFeeHandler, BalanceOf>; - type DerivativeAccount: DerivativeAccountHandler, BalanceOf>; + type DerivativeAccount: DerivativeAccountHandler< + CurrencyIdOf, + BalanceOf, + AccountIdOf, + >; type RelaychainBlockNumberProvider: BlockNumberProvider>; @@ -136,11 +154,20 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; + + type PalletsOrigin: CallerTrait; } #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { + /// A vote has been cast. + /// + /// - `who`: The account that cast the vote. + /// - `vtoken`: The token used for voting. + /// - `poll_index`: The index of the poll being voted on. + /// - `token_vote`: The vote cast using the token. + /// - `delegator_vote`: The vote cast by a delegator. Voted { who: AccountIdOf, vtoken: CurrencyIdOf, @@ -148,61 +175,101 @@ pub mod pallet { token_vote: AccountVote>, delegator_vote: AccountVote>, }, - Unlocked { - who: AccountIdOf, - vtoken: CurrencyIdOf, - poll_index: PollIndex, - }, + + /// A user's vote has been unlocked, allowing them to retrieve their tokens. + /// + /// - `who`: The account whose tokens are unlocked. + /// - `vtoken`: The token that was locked during voting. + /// - `poll_index`: The index of the poll associated with the unlocking. + Unlocked { who: AccountIdOf, vtoken: CurrencyIdOf, poll_index: PollIndex }, + + /// A delegator's vote has been removed. + /// + /// - `who`: The account that dispatched remove_delegator_vote. + /// - `vtoken`: The token associated with the delegator's vote. + /// - `derivative_index`: The index of the derivative. DelegatorVoteRemoved { who: AccountIdOf, vtoken: CurrencyIdOf, derivative_index: DerivativeIndex, }, - DelegatorAdded { - vtoken: CurrencyIdOf, - derivative_index: DerivativeIndex, - }, + + /// A delegator has been added. + /// + /// - `vtoken`: The token associated with the delegator. + /// - `derivative_index`: The index of the derivative being added for the delegator. + DelegatorAdded { vtoken: CurrencyIdOf, derivative_index: DerivativeIndex }, + + /// A new referendum information has been created. + /// + /// - `vtoken`: The token associated with the referendum. + /// - `poll_index`: The index of the poll. + /// - `info`: The referendum information (details about the poll). ReferendumInfoCreated { vtoken: CurrencyIdOf, poll_index: PollIndex, info: ReferendumInfoOf, }, + + /// Referendum information has been updated. + /// + /// - `vtoken`: The token associated with the referendum. + /// - `poll_index`: The index of the poll. + /// - `info`: The updated referendum information. ReferendumInfoSet { vtoken: CurrencyIdOf, poll_index: PollIndex, info: ReferendumInfoOf, }, - VoteLockingPeriodSet { - vtoken: CurrencyIdOf, - locking_period: BlockNumberFor, - }, - UndecidingTimeoutSet { - vtoken: CurrencyIdOf, - undeciding_timeout: BlockNumberFor, - }, - ReferendumKilled { - vtoken: CurrencyIdOf, - poll_index: PollIndex, - }, - VoteNotified { - vtoken: CurrencyIdOf, - poll_index: PollIndex, - success: bool, - }, + + /// The vote locking period has been set. + /// + /// - `vtoken`: The token for which the locking period is being set. + /// - `locking_period`: The period for which votes will be locked (in block numbers). + VoteLockingPeriodSet { vtoken: CurrencyIdOf, locking_period: BlockNumberFor }, + + /// The undeciding timeout period has been set. + /// + /// - `vtoken`: The token associated with the timeout. + /// - `undeciding_timeout`: The period of time before a poll is considered undecided. + UndecidingTimeoutSet { vtoken: CurrencyIdOf, undeciding_timeout: BlockNumberFor }, + + /// A referendum has been killed (cancelled or ended). + /// + /// - `vtoken`: The token associated with the referendum. + /// - `poll_index`: The index of the poll being killed. + ReferendumKilled { vtoken: CurrencyIdOf, poll_index: PollIndex }, + + /// A notification about the result of a vote has been sent. + /// + /// - `vtoken`: The token associated with the poll. + /// - `poll_index`: The index of the poll. + /// - `success`: Whether the notification was successful or not. + VoteNotified { vtoken: CurrencyIdOf, poll_index: PollIndex, success: bool }, + + /// A notification about the removal of a delegator's vote has been sent. + /// + /// - `vtoken`: The token associated with the poll. + /// - `poll_index`: The index of the poll. + /// - `success`: Whether the notification was successful or not. DelegatorVoteRemovedNotified { vtoken: CurrencyIdOf, poll_index: PollIndex, success: bool, }, - ResponseReceived { - responder: xcm::v4::Location, - query_id: QueryId, - response: Response, - }, - VoteCapRatioSet { - vtoken: CurrencyIdOf, - vote_cap_ratio: Perbill, - }, + + /// A response has been received from a specific location. + /// + /// - `responder`: The location that sent the response. + /// - `query_id`: The ID of the query that was responded to. + /// - `response`: The content of the response. + ResponseReceived { responder: Location, query_id: QueryId, response: Response }, + + /// The vote cap ratio has been set. + /// + /// - `vtoken`: The token associated with the cap. + /// - `vote_cap_ratio`: The maximum allowed ratio for the vote. + VoteCapRatioSet { vtoken: CurrencyIdOf, vote_cap_ratio: Perbill }, } #[pallet::error] @@ -247,6 +314,8 @@ pub mod pallet { InvalidConviction, /// The given value is out of range. OutOfRange, + InvalidCallDispatch, + CallDecodeFailed, } /// Information concerning any given referendum. @@ -366,20 +435,25 @@ pub mod pallet { #[pallet::genesis_config] #[derive(frame_support::DefaultNoBound)] pub struct GenesisConfig { - pub delegators: (CurrencyIdOf, Vec), + pub delegators: Vec<(CurrencyIdOf, Vec)>, pub undeciding_timeouts: Vec<(CurrencyIdOf, BlockNumberFor)>, - pub vote_cap_ratio: (CurrencyIdOf, Perbill), + pub vote_cap_ratio: Vec<(CurrencyIdOf, Perbill)>, } #[pallet::genesis_build] impl BuildGenesisConfig for GenesisConfig { fn build(&self) { - let (vtoken, delegators) = &self.delegators; - Delegators::::insert(vtoken, BoundedVec::truncate_from(delegators.clone())); + self.delegators.iter().for_each(|(vtoken, delegators)| { + Delegators::::insert(vtoken, BoundedVec::truncate_from(delegators.clone())); + }); + self.undeciding_timeouts.iter().for_each(|(vtoken, undeciding_timeout)| { UndecidingTimeout::::insert(vtoken, undeciding_timeout); }); - VoteCapRatio::::insert(self.vote_cap_ratio.0, self.vote_cap_ratio.1); + + self.vote_cap_ratio.iter().for_each(|(vtoken, cap_ratio)| { + VoteCapRatio::::insert(vtoken, cap_ratio); + }); } } @@ -435,7 +509,7 @@ pub mod pallet { pub fn vote( origin: OriginFor, vtoken: CurrencyIdOf, - #[pallet::compact] poll_index: PollIndex, + poll_index: PollIndex, vtoken_vote: AccountVote>, ) -> DispatchResult { let who = ensure_signed(origin)?; @@ -479,42 +553,14 @@ pub mod pallet { Ok(()) })?; - // send XCM message - let vote_calls = new_delegator_votes - .iter() - .map(|(_derivative_index, vote)| { - as ConvictionVotingCall>::vote(poll_index, *vote) - }) - .collect::>(); - let vote_call = if vote_calls.len() == 1 { - vote_calls.into_iter().nth(0).ok_or(Error::::NoData)? - } else { - ensure!(false, Error::::NoPermissionYet); - as UtilityCall>>::batch_all(vote_calls) - }; - let notify_call = Call::::notify_vote { query_id: 0, response: Default::default() }; - let (weight, extra_fee) = T::XcmDestWeightAndFee::get_operation_weight_and_fee( - CurrencyId::to_token(&vtoken).map_err(|_| Error::::NoData)?, - XcmOperationType::Vote, - ) - .ok_or(Error::::NoData)?; - - let derivative_index = new_delegator_votes[0].0; - Self::send_xcm_with_notify( - derivative_index, - vote_call, - notify_call, - weight, - extra_fee, - |query_id| { - if !submitted { - PendingReferendumInfo::::insert(query_id, (vtoken, poll_index)); - } - PendingVotingInfo::::insert( - query_id, - (vtoken, poll_index, derivative_index, who.clone(), maybe_old_vote), - ) - }, + let voting_agent = Self::get_voting_agent(&vtoken)?; + voting_agent.delegate_vote( + who.clone(), + vtoken, + poll_index, + submitted, + new_delegator_votes.clone(), + maybe_old_vote, )?; Self::deposit_event(Event::::Voted { @@ -567,29 +613,12 @@ pub mod pallet { ensure!(DelegatorVotes::::get(vtoken, poll_index).len() > 0, Error::::NoData); Self::ensure_referendum_expired(vtoken, poll_index)?; - let notify_call = Call::::notify_remove_delegator_vote { - query_id: 0, - response: Default::default(), - }; - let remove_vote_call = - as ConvictionVotingCall>::remove_vote(Some(class), poll_index); - let (weight, extra_fee) = T::XcmDestWeightAndFee::get_operation_weight_and_fee( - CurrencyId::to_token(&vtoken).map_err(|_| Error::::NoData)?, - XcmOperationType::RemoveVote, - ) - .ok_or(Error::::NoData)?; - Self::send_xcm_with_notify( + let voting_agent = Self::get_voting_agent(&vtoken)?; + voting_agent.delegate_remove_delegator_vote( + vtoken, + poll_index, + class, derivative_index, - remove_vote_call, - notify_call, - weight, - extra_fee, - |query_id| { - PendingRemoveDelegatorVote::::insert( - query_id, - (vtoken, poll_index, derivative_index), - ); - }, )?; Self::deposit_event(Event::::DelegatorVoteRemoved { who, vtoken, derivative_index }); @@ -710,33 +739,15 @@ pub mod pallet { if let Some((vtoken, poll_index, derivative_index, who, maybe_old_vote)) = PendingVotingInfo::::get(query_id) { - if !success { - // rollback vote - let _ = PendingDelegatorVotes::::clear(u32::MAX, None); - Self::try_remove_vote(&who, vtoken, poll_index, UnvoteScope::Any)?; - Self::update_lock(&who, vtoken)?; - if let Some((old_vote, vtoken_balance)) = maybe_old_vote { - Self::try_vote(&who, vtoken, poll_index, old_vote, vtoken_balance)?; - } - } else { - if !VoteDelegatorFor::::contains_key((&who, vtoken, poll_index)) { - VoteDelegatorFor::::insert((&who, vtoken, poll_index), derivative_index); - } - DelegatorVotes::::remove(vtoken, poll_index); - DelegatorVotes::::try_mutate( - vtoken, - poll_index, - |item| -> DispatchResult { - for (derivative_index, vote) in - PendingDelegatorVotes::::take(vtoken, poll_index).iter() - { - item.try_push((*derivative_index, *vote)) - .map_err(|_| Error::::TooMany)?; - } - Ok(()) - }, - )?; - } + Self::handle_vote_result( + success, + who, + vtoken, + poll_index, + maybe_old_vote, + derivative_index, + )?; + PendingVotingInfo::::remove(query_id); Self::deposit_event(Event::::VoteNotified { vtoken, poll_index, success }); } @@ -797,7 +808,7 @@ pub mod pallet { { let success = Response::DispatchResult(MaybeErrorCode::Success) == response; if success { - DelegatorVotes::::remove(vtoken, poll_index); + Self::handle_remove_delegator_vote_success(vtoken, poll_index); } PendingRemoveDelegatorVote::::remove(query_id); Self::deposit_event(Event::::DelegatorVoteRemovedNotified { @@ -828,6 +839,201 @@ pub mod pallet { } impl Pallet { + pub(crate) fn handle_remove_delegator_vote_success( + vtoken: CurrencyIdOf, + poll_index: PollIndex, + ) { + DelegatorVotes::::remove(vtoken, poll_index); + } + + pub(crate) fn handle_vote_result( + success: bool, + who: AccountIdOf, + vtoken: CurrencyIdOf, + poll_index: PollIndex, + maybe_old_vote: Option<(AccountVote>, BalanceOf)>, + derivative_index: DerivativeIndex, + ) -> DispatchResult { + if !success { + // rollback vote + let _ = PendingDelegatorVotes::::clear(u32::MAX, None); + Self::try_remove_vote(&who, vtoken, poll_index, UnvoteScope::Any)?; + Self::update_lock(&who, vtoken)?; + if let Some((old_vote, vtoken_balance)) = maybe_old_vote { + Self::try_vote(&who, vtoken, poll_index, old_vote, vtoken_balance)?; + } + } else { + if !VoteDelegatorFor::::contains_key((&who, vtoken, poll_index)) { + VoteDelegatorFor::::insert((&who, vtoken, poll_index), derivative_index); + } + DelegatorVotes::::remove(vtoken, poll_index); + DelegatorVotes::::try_mutate(vtoken, poll_index, |item| -> DispatchResult { + for (derivative_index, vote) in + PendingDelegatorVotes::::take(vtoken, poll_index).iter() + { + item.try_push((*derivative_index, *vote)) + .map_err(|_| Error::::TooMany)?; + } + Ok(()) + })?; + } + + Ok(()) + } + + pub(crate) fn send_xcm_vote_message( + who: AccountIdOf, + vtoken: CurrencyIdOf, + poll_index: PollIndex, + submitted: bool, + new_delegator_votes: Vec<(DerivativeIndex, AccountVote>)>, + maybe_old_vote: Option<(AccountVote>, BalanceOf)>, + ) -> DispatchResult { + let notify_call = Call::::notify_vote { query_id: 0, response: Default::default() }; + let (weight, extra_fee) = T::XcmDestWeightAndFee::get_operation_weight_and_fee( + CurrencyId::to_token(&vtoken).map_err(|_| Error::::NoData)?, + XcmOperationType::Vote, + ) + .ok_or(Error::::NoData)?; + + let derivative_index = new_delegator_votes[0].0; + + let voting_agent = Self::get_voting_agent(&vtoken)?; + let encode_call = voting_agent.vote_call_encode( + new_delegator_votes.clone(), + poll_index, + derivative_index, + )?; + + Self::send_xcm_with_notify( + voting_agent.location(), + encode_call, + notify_call, + weight, + extra_fee, + |query_id| { + if !submitted { + PendingReferendumInfo::::insert(query_id, (vtoken, poll_index)); + } + PendingVotingInfo::::insert( + query_id, + (vtoken, poll_index, derivative_index, who.clone(), maybe_old_vote), + ) + }, + )?; + + Ok(()) + } + + pub(crate) fn send_xcm_remove_delegator_vote_message( + vtoken: CurrencyIdOf, + poll_index: PollIndex, + class: PollClass, + derivative_index: DerivativeIndex, + ) -> DispatchResult { + let voting_agent = Self::get_voting_agent(&vtoken)?; + let encode_call = voting_agent.remove_delegator_vote_call_encode( + class, + poll_index, + derivative_index, + )?; + let notify_call = Call::::notify_remove_delegator_vote { + query_id: 0, + response: Default::default(), + }; + + let (weight, extra_fee) = T::XcmDestWeightAndFee::get_operation_weight_and_fee( + CurrencyId::to_token(&vtoken).map_err(|_| Error::::NoData)?, + XcmOperationType::RemoveVote, + ) + .ok_or(Error::::NoData)?; + + Self::send_xcm_with_notify( + voting_agent.location(), + encode_call, + notify_call, + weight, + extra_fee, + |query_id| { + PendingRemoveDelegatorVote::::insert( + query_id, + (vtoken, poll_index, derivative_index), + ); + }, + )?; + + Ok(()) + } + + pub(crate) fn send_xcm_with_notify( + responder_location: Location, + encode_call: Vec, + notify_call: Call, + transact_weight: XcmWeight, + extra_fee: BalanceOf, + f: impl FnOnce(QueryId) -> (), + ) -> DispatchResult { + let now = frame_system::Pallet::::block_number(); + let timeout = now.saturating_add(T::QueryTimeout::get()); + let notify_runtime_call = ::RuntimeCall::from(notify_call); + let notify_call_weight = notify_runtime_call.get_dispatch_info().weight; + let query_id = pallet_xcm::Pallet::::new_notify_query( + responder_location.clone(), + notify_runtime_call, + timeout, + xcm::v4::Junctions::Here, + ); + f(query_id); + + let xcm_message = Self::construct_xcm_message( + encode_call, + extra_fee, + transact_weight, + notify_call_weight, + query_id, + )?; + + xcm::v4::send_xcm::(responder_location, xcm_message) + .map_err(|_| Error::::XcmFailure)?; + + Ok(()) + } + + pub(crate) fn construct_xcm_message( + call: Vec, + extra_fee: BalanceOf, + transact_weight: XcmWeight, + notify_call_weight: XcmWeight, + query_id: QueryId, + ) -> Result, Error> { + let para_id = T::ParachainId::get().into(); + let asset = Asset { + id: AssetId(Location::here()), + fun: Fungible(UniqueSaturatedInto::::unique_saturated_into(extra_fee)), + }; + let xcm_message = sp_std::vec![ + WithdrawAsset(asset.clone().into()), + BuyExecution { fees: asset, weight_limit: Unlimited }, + Transact { + origin_kind: OriginKind::SovereignAccount, + require_weight_at_most: transact_weight, + call: call.into(), + }, + ReportTransactStatus(QueryResponseInfo { + destination: Location::from(Parachain(para_id)), + query_id, + max_weight: notify_call_weight, + }), + RefundSurplus, + DepositAsset { + assets: All.into(), + beneficiary: Location::new(0, [Parachain(para_id)]), + }, + ]; + + Ok(Xcm(xcm_message)) + } + fn try_vote( who: &AccountIdOf, vtoken: CurrencyIdOf, @@ -1004,79 +1210,8 @@ pub mod pallet { } } - fn send_xcm_with_notify( - derivative_index: DerivativeIndex, - call: RelayCall, - notify_call: Call, - transact_weight: XcmWeight, - extra_fee: BalanceOf, - f: impl FnOnce(QueryId) -> (), - ) -> DispatchResult { - let responder = xcm::v4::Location::parent(); - let now = frame_system::Pallet::::block_number(); - let timeout = now.saturating_add(T::QueryTimeout::get()); - let notify_runtime_call = ::RuntimeCall::from(notify_call); - let notify_call_weight = notify_runtime_call.get_dispatch_info().weight; - let query_id = pallet_xcm::Pallet::::new_notify_query( - responder, - notify_runtime_call, - timeout, - xcm::v4::Junctions::Here, - ); - f(query_id); - - let xcm_message = Self::construct_xcm_message( - as UtilityCall>>::as_derivative(derivative_index, call) - .encode(), - extra_fee, - transact_weight, - notify_call_weight, - query_id, - )?; - - xcm::v4::send_xcm::(Parent.into(), xcm_message) - .map_err(|_e| Error::::XcmFailure)?; - - Ok(()) - } - - fn construct_xcm_message( - call: Vec, - extra_fee: BalanceOf, - transact_weight: XcmWeight, - notify_call_weight: XcmWeight, - query_id: QueryId, - ) -> Result, Error> { - let para_id = T::ParachainId::get().into(); - let asset = Asset { - id: AssetId(Location::here()), - fun: Fungible(UniqueSaturatedInto::::unique_saturated_into(extra_fee)), - }; - let xcm_message = sp_std::vec![ - WithdrawAsset(asset.clone().into()), - BuyExecution { fees: asset, weight_limit: Unlimited }, - Transact { - origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: transact_weight, - call: call.into(), - }, - ReportTransactStatus(QueryResponseInfo { - destination: Location::from(Parachain(para_id)), - query_id, - max_weight: notify_call_weight, - }), - RefundSurplus, - DepositAsset { - assets: All.into(), - beneficiary: Location::new(0, [Parachain(para_id)]), - }, - ]; - - Ok(Xcm(xcm_message)) - } - fn ensure_vtoken(vtoken: &CurrencyIdOf) -> Result<(), DispatchError> { - ensure!([VKSM, VDOT].contains(vtoken), Error::::VTokenNotSupport); + ensure!([VKSM, VDOT, VBNC].contains(vtoken), Error::::VTokenNotSupport); Ok(()) } @@ -1156,7 +1291,7 @@ pub mod pallet { fn ensure_xcm_response_or_governance( origin: OriginFor, - ) -> Result { + ) -> Result { let responder = T::ResponseOrigin::ensure_origin(origin.clone()).or_else(|_| { T::ControlOrigin::ensure_origin(origin).map(|_| xcm::v4::Junctions::Here.into()) })?; @@ -1293,5 +1428,26 @@ pub mod pallet { Ok(delegator_votes) } + + pub(crate) fn get_voting_agent( + currency_id: &CurrencyIdOf, + ) -> Result, Error> { + match *currency_id { + VKSM | VDOT => Ok(Box::new(RelaychainAgent::::new(*currency_id)?)), + VBNC => Ok(Box::new(BifrostAgent::::new(*currency_id)?)), + _ => Err(Error::::VTokenNotSupport), + } + } + + pub(crate) fn convert_vtoken_to_dest_location( + vtoken: CurrencyId, + ) -> Result> { + let token = CurrencyId::to_token(&vtoken).map_err(|_| Error::::NoData)?; + match token { + KSM | DOT => Ok(Location::parent()), + BNC => Ok(Location::new(1, [Parachain(T::ParachainId::get().into())])), + _ => Err(Error::::VTokenNotSupport), + } + } } } diff --git a/pallets/vtoken-voting/src/mock.rs b/pallets/vtoken-voting/src/mock.rs index 16a6adfc6..397c7f9a9 100644 --- a/pallets/vtoken-voting/src/mock.rs +++ b/pallets/vtoken-voting/src/mock.rs @@ -21,24 +21,26 @@ use crate as vtoken_voting; use crate::{BalanceOf, DerivativeAccountHandler, DerivativeIndex, DispatchResult}; use bifrost_primitives::{ - currency::{KSM, VBNC, VKSM}, + currency::{DOT, KSM, VBNC, VDOT, VKSM}, traits::XcmDestWeightAndFeeHandler, CurrencyId, MockXcmRouter, VTokenSupplyProvider, XcmOperationType, BNC, }; use cumulus_primitives_core::ParaId; use frame_support::{ derive_impl, ord_parameter_types, - pallet_prelude::Weight, + pallet_prelude::{DispatchError, Weight}, parameter_types, - traits::{Everything, Get, Nothing}, + traits::{ConstU64, Everything, Get, Nothing, PollStatus, Polling, VoteTally}, weights::RuntimeDbWeight, }; use frame_system::EnsureRoot; +use pallet_conviction_voting::{Tally, TallyOf}; use pallet_xcm::EnsureResponse; use sp_runtime::{ traits::{BlockNumberProvider, ConstU32, IdentityLookup}, BuildStorage, Perbill, }; +use std::collections::BTreeMap; use xcm::{prelude::*, v3::MultiLocation}; use xcm_builder::{FixedWeightBounds, FrameTransactionalProcessor}; use xcm_executor::XcmExecutor; @@ -63,6 +65,7 @@ frame_support::construct_runtime!( Currencies: bifrost_currencies, PolkadotXcm: pallet_xcm, VtokenVoting: vtoken_voting, + ConvictionVoting: pallet_conviction_voting = 36, } ); @@ -103,7 +106,7 @@ impl pallet_balances::Config for Runtime { type DustRemoval = (); type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ExistentialDeposit; - type MaxLocks = (); + type MaxLocks = ConstU32<100>; type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type WeightInfo = (); @@ -113,10 +116,107 @@ impl pallet_balances::Config for Runtime { type MaxFreezes = ConstU32<0>; } +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum TestPollState { + Ongoing(TallyOf, u8), + Completed(u64, bool), +} +use TestPollState::*; + +parameter_types! { + pub static Polls: BTreeMap = (0u8..=255) + .map(|i| (i, Ongoing(Tally::from_parts(0, 0, 0), 0))) + .collect(); +} + +pub struct TestPolls; +impl Polling> for TestPolls { + type Index = u8; + type Votes = u128; + type Moment = u64; + type Class = u8; + fn classes() -> Vec { + vec![0, 1, 2] + } + fn as_ongoing(index: u8) -> Option<(TallyOf, Self::Class)> { + Polls::get().remove(&index).and_then(|x| { + if let TestPollState::Ongoing(t, c) = x { + Some((t, c)) + } else { + None + } + }) + } + fn access_poll( + index: Self::Index, + f: impl FnOnce(PollStatus<&mut TallyOf, u64, u8>) -> R, + ) -> R { + let mut polls = Polls::get(); + let entry = polls.get_mut(&index); + let r = match entry { + Some(Ongoing(ref mut tally_mut_ref, class)) => + f(PollStatus::Ongoing(tally_mut_ref, *class)), + Some(Completed(when, succeeded)) => f(PollStatus::Completed(*when, *succeeded)), + None => f(PollStatus::None), + }; + Polls::set(polls); + r + } + fn try_access_poll( + index: Self::Index, + f: impl FnOnce(PollStatus<&mut TallyOf, u64, u8>) -> Result, + ) -> Result { + let mut polls = Polls::get(); + let entry = polls.get_mut(&index); + let r = match entry { + Some(Ongoing(ref mut tally_mut_ref, class)) => + f(PollStatus::Ongoing(tally_mut_ref, *class)), + Some(Completed(when, succeeded)) => f(PollStatus::Completed(*when, *succeeded)), + None => f(PollStatus::None), + }?; + Polls::set(polls); + Ok(r) + } + + #[cfg(feature = "runtime-benchmarks")] + fn create_ongoing(class: Self::Class) -> Result { + let mut polls = Polls::get(); + let i = polls.keys().rev().next().map_or(0, |x| x + 1); + polls.insert(i, Ongoing(Tally::new(0), class)); + Polls::set(polls); + Ok(i) + } + + #[cfg(feature = "runtime-benchmarks")] + fn end_ongoing(index: Self::Index, approved: bool) -> Result<(), ()> { + let mut polls = Polls::get(); + match polls.get(&index) { + Some(Ongoing(..)) => {}, + _ => return Err(()), + } + let now = frame_system::Pallet::::block_number(); + polls.insert(index, Completed(now, approved)); + Polls::set(polls); + Ok(()) + } +} + +impl pallet_conviction_voting::Config for Runtime { + type WeightInfo = (); + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type VoteLockingPeriod = ConstU64<3>; + type MaxVotes = ConstU32<512>; + type MaxTurnout = frame_support::traits::TotalIssuanceOf; + type Polls = TestPolls; +} + orml_traits::parameter_type_with_key! { pub ExistentialDeposits: |currency_id: CurrencyId| -> Balance { match currency_id { + &DOT => 0, &KSM => 0, + &VDOT => 0, &VBNC => 0, &VKSM => 0, _ => 0, @@ -239,7 +339,7 @@ impl XcmDestWeightAndFeeHandler> for XcmDestWeigh } pub struct DerivativeAccount; -impl DerivativeAccountHandler for DerivativeAccount { +impl DerivativeAccountHandler for DerivativeAccount { fn check_derivative_index_exists( _token: CurrencyId, _derivative_index: DerivativeIndex, @@ -254,6 +354,10 @@ impl DerivativeAccountHandler for DerivativeAccount { Some(xcm::v3::Parent.into()) } + fn get_account_id(_token: CurrencyId, _derivative_index: DerivativeIndex) -> Option { + Some(CHARLIE) + } + fn get_stake_info( token: CurrencyId, derivative_index: DerivativeIndex, @@ -337,26 +441,51 @@ impl vtoken_voting::Config for Runtime { type QueryTimeout = QueryTimeout; type ReferendumCheckInterval = ReferendumCheckInterval; type WeightInfo = (); + type PalletsOrigin = OriginCaller; } pub fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); pallet_balances::GenesisConfig:: { - balances: vec![(ALICE, 10), (BOB, 20), (CHARLIE, 30)], + balances: vec![(ALICE, 10), (BOB, 20), (CHARLIE, 3000)], } .assimilate_storage(&mut t) .unwrap(); orml_tokens::GenesisConfig:: { - balances: vec![(1, VKSM, 10), (2, VKSM, 20), (3, VKSM, 30), (4, VKSM, 40), (5, VKSM, 50)], + balances: vec![ + (1, VKSM, 10), + (2, VKSM, 20), + (3, VKSM, 30), + (4, VKSM, 40), + (5, VKSM, 50), + (1, VDOT, 10), + (2, VDOT, 20), + (3, VDOT, 30), + (4, VDOT, 40), + (5, VDOT, 50), + (1, VBNC, 10), + (2, VBNC, 20), + (3, VBNC, 30), + (4, VBNC, 40), + (5, VBNC, 50), + ], } .assimilate_storage(&mut t) .unwrap(); vtoken_voting::GenesisConfig:: { - delegators: (VKSM, vec![0, 1, 2, 3, 4, 5, 10, 11, 15, 20, 21]), - undeciding_timeouts: vec![(VKSM, 100)], - vote_cap_ratio: (VKSM, Perbill::from_percent(10)), + delegators: vec![ + (VKSM, vec![0, 1, 2, 3, 4, 5, 10, 11, 15, 20, 21]), + (VDOT, vec![0, 1, 2, 3, 4, 5, 10, 11, 15, 20, 21]), + (VBNC, vec![0, 1, 2, 3, 4, 5, 10, 11, 15, 20, 21]), + ], + undeciding_timeouts: vec![(VDOT, 100), (VKSM, 100), (VBNC, 100)], + vote_cap_ratio: vec![ + (VDOT, Perbill::from_percent(10)), + (VKSM, Perbill::from_percent(10)), + (VBNC, Perbill::from_percent(10)), + ], } .assimilate_storage(&mut t) .unwrap(); diff --git a/pallets/vtoken-voting/src/tests.rs b/pallets/vtoken-voting/src/tests.rs deleted file mode 100644 index de56e74e0..000000000 --- a/pallets/vtoken-voting/src/tests.rs +++ /dev/null @@ -1,1379 +0,0 @@ -// This file is part of Bifrost. - -// Copyright (C) Liebi Technologies PTE. 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 . - -// Ensure we're `no_std` when compiling for Wasm. - -use super::*; -use crate::mock::*; -use bifrost_primitives::currency::{VBNC, VKSM}; -use frame_support::{ - assert_noop, assert_ok, - traits::{ - fungibles::Inspect, - tokens::{Fortitude::Polite, Preservation::Expendable}, - }, - weights::RuntimeDbWeight, -}; -use pallet_conviction_voting::Vote; -use pallet_xcm::Origin as XcmOrigin; - -fn aye(amount: Balance, conviction: u8) -> AccountVote { - let vote = Vote { aye: true, conviction: conviction.try_into().unwrap() }; - AccountVote::Standard { vote, balance: amount } -} - -fn nay(amount: Balance, conviction: u8) -> AccountVote { - let vote = Vote { aye: false, conviction: conviction.try_into().unwrap() }; - AccountVote::Standard { vote, balance: amount } -} - -fn tally(vtoken: CurrencyId, poll_index: u32) -> TallyOf { - VtokenVoting::ensure_referendum_ongoing(vtoken, poll_index) - .expect("No poll") - .tally -} - -fn usable_balance(vtoken: CurrencyId, who: &AccountId) -> Balance { - Tokens::reducible_balance(vtoken, who, Expendable, Polite) -} - -fn origin_response() -> RuntimeOrigin { - XcmOrigin::Response(Parent.into()).into() -} - -fn response_success() -> Response { - Response::DispatchResult(MaybeErrorCode::Success) -} - -fn response_fail() -> Response { - Response::DispatchResult(MaybeErrorCode::Error(BoundedVec::try_from(vec![0u8, 1u8]).unwrap())) -} - -#[test] -fn basic_voting_works() { - new_test_ext().execute_with(|| { - let poll_index = 3; - let vtoken = VKSM; - - assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, poll_index, aye(2, 5))); - assert_eq!(tally(vtoken, poll_index), Tally::from_parts(20, 0, 4)); - System::assert_last_event(RuntimeEvent::VtokenVoting(Event::Voted { - who: ALICE, - vtoken, - poll_index, - token_vote: aye(4, 5), - delegator_vote: aye(200, 0), - })); - assert_ok!(VtokenVoting::notify_vote(origin_response(), 0, response_success())); - - assert_ok!(VtokenVoting::try_remove_vote(&ALICE, vtoken, poll_index, UnvoteScope::Any)); - assert_eq!(tally(vtoken, poll_index), Tally::from_parts(0, 0, 0)); - - assert_ok!(VtokenVoting::update_lock(&ALICE, vtoken)); - assert_eq!(usable_balance(vtoken, &ALICE), 10); - }); -} - -#[test] -fn voting_balance_gets_locked() { - new_test_ext().execute_with(|| { - let poll_index = 3; - let vtoken = VKSM; - - assert_ok!(VtokenVoting::vote( - RuntimeOrigin::signed(ALICE), - vtoken, - poll_index, - nay(10, 0) - )); - assert_eq!(tally(vtoken, poll_index), Tally::from_parts(0, 2, 0)); - assert_ok!(VtokenVoting::notify_vote(origin_response(), 0, response_success())); - assert_eq!(usable_balance(vtoken, &ALICE), 0); - - assert_ok!(VtokenVoting::try_remove_vote(&ALICE, vtoken, poll_index, UnvoteScope::Any)); - assert_eq!(tally(vtoken, poll_index), Tally::from_parts(0, 0, 0)); - - assert_ok!(VtokenVoting::update_lock(&ALICE, vtoken)); - assert_eq!(usable_balance(vtoken, &ALICE), 10); - }); -} - -#[test] -fn successful_but_zero_conviction_vote_balance_can_be_unlocked() { - new_test_ext().execute_with(|| { - let poll_index = 3; - let vtoken = VKSM; - - assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, poll_index, aye(1, 1))); - assert_eq!(usable_balance(vtoken, &ALICE), 9); - assert_ok!(VtokenVoting::notify_vote(origin_response(), 0, response_success())); - assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, poll_index, aye(3, 1))); - assert_eq!(usable_balance(vtoken, &ALICE), 7); - assert_ok!(VtokenVoting::notify_vote(origin_response(), 1, response_success())); - - assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(BOB), vtoken, poll_index, nay(20, 0))); - assert_eq!(usable_balance(vtoken, &BOB), 0); - assert_ok!(VtokenVoting::notify_vote(origin_response(), 2, response_success())); - - assert_ok!(VtokenVoting::set_vote_locking_period(RuntimeOrigin::root(), vtoken, 10)); - assert_ok!(VtokenVoting::set_referendum_status( - RuntimeOrigin::root(), - vtoken, - poll_index, - ReferendumInfoOf::::Completed(3), - )); - - assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(BOB), vtoken, poll_index)); - assert_eq!(usable_balance(vtoken, &BOB), 20); - - RelaychainDataProvider::set_block_number(13); - assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, poll_index)); - assert_eq!(usable_balance(vtoken, &ALICE), 10); - }); -} - -#[test] -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())); - assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(BOB), vtoken, poll_index, nay(20, 0))); - assert_ok!(VtokenVoting::notify_vote(origin_response(), 1, response_success())); - - assert_ok!(VtokenVoting::set_referendum_status( - RuntimeOrigin::root(), - vtoken, - 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)); - assert_eq!(usable_balance(vtoken, &ALICE), 10); - }); -} - -#[test] -fn ensure_balance_after_unlock() { - new_test_ext().execute_with(|| { - let poll_index = 3; - let poll_index_2 = 4; - 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(10, 1) - )); - assert_ok!(VtokenVoting::notify_vote(origin_response(), 0, response_success())); - assert_ok!(VtokenVoting::vote( - RuntimeOrigin::signed(ALICE), - vtoken, - poll_index_2, - aye(10, 5) - )); - assert_ok!(VtokenVoting::notify_vote(origin_response(), 1, response_success())); - - assert_ok!(VtokenVoting::set_referendum_status( - RuntimeOrigin::root(), - vtoken, - poll_index, - ReferendumInfoOf::::Completed(3), - )); - RelaychainDataProvider::set_block_number(13); - assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, poll_index)); - assert_eq!(usable_balance(vtoken, &ALICE), 0); - assert_eq!(Tokens::accounts(&ALICE, vtoken).frozen, 10); - assert_eq!(VotingFor::::get(&ALICE).locked_balance(), 10); - }); -} - -#[test] -fn ensure_comprehensive_balance_after_unlock() { - new_test_ext().execute_with(|| { - let poll_index = 3; - let poll_index_2 = 4; - let poll_index_3 = 5; - 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(2, 1))); - assert_ok!(VtokenVoting::notify_vote(origin_response(), 0, response_success())); - assert_ok!(VtokenVoting::vote( - RuntimeOrigin::signed(ALICE), - vtoken, - poll_index_2, - aye(1, 5) - )); - assert_ok!(VtokenVoting::notify_vote(origin_response(), 1, response_success())); - assert_ok!(VtokenVoting::vote( - RuntimeOrigin::signed(ALICE), - vtoken, - poll_index_3, - aye(2, 5) - )); - assert_ok!(VtokenVoting::notify_vote(origin_response(), 2, response_success())); - - assert_ok!(VtokenVoting::set_referendum_status( - RuntimeOrigin::root(), - vtoken, - poll_index, - ReferendumInfoOf::::Completed(3), - )); - RelaychainDataProvider::set_block_number(13); - assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, poll_index)); - assert_eq!(usable_balance(vtoken, &ALICE), 8); - assert_eq!(Tokens::accounts(&ALICE, vtoken).frozen, 2); - assert_eq!(VotingFor::::get(&ALICE).locked_balance(), 2); - - assert_ok!(VtokenVoting::vote( - RuntimeOrigin::signed(ALICE), - vtoken, - poll_index_2, - aye(10, 5) - )); - assert_ok!(VtokenVoting::notify_vote(origin_response(), 3, response_success())); - - assert_eq!(usable_balance(vtoken, &ALICE), 0); - assert_eq!(Tokens::accounts(&ALICE, vtoken).frozen, 10); - assert_eq!(VotingFor::::get(&ALICE).locked_balance(), 10); - }); -} - -#[test] -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), - vtoken, - poll_index, - aye(10, i as u8) - )); - assert_ok!(VtokenVoting::notify_vote(origin_response(), i - 1, response_success())); - } - assert_ok!(VtokenVoting::set_referendum_status( - RuntimeOrigin::root(), - vtoken, - 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)); - } - for i in 1..=5 { - assert_ok!(VtokenVoting::update_lock(&i, vtoken)); - assert_eq!(usable_balance(vtoken, &i), 10 * i as u128); - } - }); -} - -#[test] -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::notify_vote(origin_response(), 0, response.clone())); - assert_eq!( - ClassLocksFor::::get(&ALICE), - BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 5),]).unwrap() - ); - - assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, 1, aye(10, 1))); - assert_ok!(VtokenVoting::notify_vote(origin_response(), 1, response.clone())); - assert_eq!( - ClassLocksFor::::get(&ALICE), - BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 10),]).unwrap() - ); - - assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, 1, aye(5, 1))); - assert_ok!(VtokenVoting::notify_vote(origin_response(), 2, response.clone())); - assert_eq!( - ClassLocksFor::::get(&ALICE), - BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 5),]).unwrap() - ); - assert_eq!(usable_balance(vtoken, &ALICE), 5); - - assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, 2, aye(10, 2))); - assert_ok!(VtokenVoting::notify_vote(origin_response(), 3, response.clone())); - assert_eq!( - ClassLocksFor::::get(&ALICE), - BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 10),]).unwrap() - ); - - 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), - )); - - let locking_period = 10; - assert_ok!(VtokenVoting::set_vote_locking_period( - RuntimeOrigin::root(), - vtoken, - locking_period, - )); - assert_eq!(VoteLockingPeriod::::get(vtoken), Some(10)); - - assert_eq!( - ClassLocksFor::::get(&ALICE), - BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 10),]).unwrap() - ); - - RelaychainDataProvider::set_block_number(10); - assert_noop!( - VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 0), - Error::::NoPermissionYet - ); - assert_eq!(VotingFor::::get(&ALICE).locked_balance(), 10); - assert_eq!(usable_balance(vtoken, &ALICE), 0); - - RelaychainDataProvider::set_block_number(11); - assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 0)); - assert_eq!(VotingFor::::get(&ALICE).locked_balance(), 10); - assert_eq!(usable_balance(vtoken, &ALICE), 0); - assert_eq!( - ClassLocksFor::::get(&ALICE), - BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 10),]).unwrap() - ); - - RelaychainDataProvider::set_block_number(11); - assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 1)); - assert_eq!(usable_balance(vtoken, &ALICE), 0); - assert_eq!( - ClassLocksFor::::get(&ALICE), - BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 10)]).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::<(CurrencyId, 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); - - 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, - 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), - )); - - 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::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 10),]).unwrap() - ); - - assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 0)); - assert_eq!(usable_balance(vtoken, &ALICE), 0); - assert_eq!( - ClassLocksFor::::get(&ALICE), - BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 10),]).unwrap() - ); - - assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 1)); - assert_eq!(usable_balance(vtoken, &ALICE), 5); - assert_eq!( - ClassLocksFor::::get(&ALICE), - BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 5)]).unwrap() - ); - - assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 2)); - assert_eq!(usable_balance(vtoken, &ALICE), 10); - assert_eq!( - ClassLocksFor::::get(&ALICE), - BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![]).unwrap() - ); - }); -} - -#[test] -fn errors_with_vote_works() { - new_test_ext().execute_with(|| { - let vtoken = VKSM; - - assert_noop!( - VtokenVoting::vote(RuntimeOrigin::signed(1), VBNC, 0, aye(10, 0)), - Error::::VTokenNotSupport - ); - assert_noop!( - VtokenVoting::vote(RuntimeOrigin::signed(1), vtoken, 3, aye(11, 0)), - Error::::InsufficientFunds - ); - - for poll_index in 0..256 { - assert_ok!(VtokenVoting::vote( - RuntimeOrigin::signed(1), - vtoken, - poll_index, - aye(10, 0) - )); - } - assert_noop!( - VtokenVoting::vote(RuntimeOrigin::signed(1), vtoken, 256, aye(10, 0)), - Error::::MaxVotesReached - ); - }); -} - -#[test] -fn kill_referendum_works() { - new_test_ext().execute_with(|| { - let vtoken = VKSM; - let poll_index = 3; - - assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, poll_index, aye(5, 1))); - assert_ok!(VtokenVoting::set_referendum_status( - RuntimeOrigin::root(), - vtoken, - poll_index, - ReferendumInfoOf::::Completed(1), - )); - assert_ok!(VtokenVoting::kill_referendum(RuntimeOrigin::root(), vtoken, poll_index)); - System::assert_last_event(RuntimeEvent::VtokenVoting(Event::ReferendumKilled { - vtoken, - poll_index, - })); - }); -} - -#[test] -fn kill_referendum_with_origin_signed_fails() { - new_test_ext().execute_with(|| { - let vtoken = VKSM; - let poll_index = 3; - - assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, poll_index, aye(5, 1))); - assert_ok!(VtokenVoting::set_referendum_status( - RuntimeOrigin::root(), - vtoken, - poll_index, - ReferendumInfoOf::::Completed(1), - )); - assert_noop!( - VtokenVoting::kill_referendum(RuntimeOrigin::signed(ALICE), vtoken, poll_index), - DispatchError::BadOrigin - ); - }); -} - -#[test] -fn add_delegator_works() { - new_test_ext().execute_with(|| { - let vtoken = VKSM; - let derivative_index: DerivativeIndex = 100; - - assert_ok!(VtokenVoting::add_delegator(RuntimeOrigin::root(), vtoken, derivative_index,)); - - System::assert_last_event(RuntimeEvent::VtokenVoting(Event::DelegatorAdded { - vtoken, - derivative_index, - })); - }); -} - -#[test] -fn set_referendum_status_works() { - new_test_ext().execute_with(|| { - let poll_index = 3; - let vtoken = VKSM; - let info = ReferendumInfo::Completed(3); - - assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, poll_index, aye(2, 5))); - assert_ok!(VtokenVoting::set_referendum_status( - RuntimeOrigin::root(), - vtoken, - poll_index, - info.clone(), - )); - - System::assert_last_event(RuntimeEvent::VtokenVoting(Event::ReferendumInfoSet { - vtoken, - poll_index, - info, - })); - }); -} - -#[test] -fn set_referendum_status_without_vote_should_fail() { - new_test_ext().execute_with(|| { - let poll_index = 3; - let vtoken = VKSM; - let info = ReferendumInfo::Completed(3); - - assert_noop!( - VtokenVoting::set_referendum_status( - RuntimeOrigin::root(), - vtoken, - poll_index, - info.clone(), - ), - Error::::NoData - ); - }); -} - -#[test] -fn set_referendum_status_with_origin_signed_should_fail() { - new_test_ext().execute_with(|| { - let poll_index = 3; - let vtoken = VKSM; - let info = ReferendumInfo::Completed(3); - - assert_noop!( - VtokenVoting::set_referendum_status( - RuntimeOrigin::signed(ALICE), - vtoken, - poll_index, - info.clone(), - ), - DispatchError::BadOrigin - ); - }); -} - -#[test] -fn set_vote_locking_period_works() { - new_test_ext().execute_with(|| { - let vtoken = VKSM; - let locking_period = 100; - - assert_ok!(VtokenVoting::set_vote_locking_period( - RuntimeOrigin::root(), - vtoken, - locking_period, - )); - - System::assert_last_event(RuntimeEvent::VtokenVoting(Event::VoteLockingPeriodSet { - vtoken, - locking_period, - })); - }); -} - -#[test] -fn set_vote_locking_period_with_origin_signed_should_fail() { - new_test_ext().execute_with(|| { - let vtoken = VKSM; - let locking_period = 100; - - assert_noop!( - VtokenVoting::set_vote_locking_period( - RuntimeOrigin::signed(ALICE), - vtoken, - locking_period, - ), - DispatchError::BadOrigin - ); - }); -} - -#[test] -fn set_undeciding_timeout_works() { - new_test_ext().execute_with(|| { - let vtoken = VKSM; - let undeciding_timeout = 100; - - assert_ok!(VtokenVoting::set_undeciding_timeout( - RuntimeOrigin::root(), - vtoken, - undeciding_timeout, - )); - - System::assert_last_event(RuntimeEvent::VtokenVoting(Event::UndecidingTimeoutSet { - vtoken, - undeciding_timeout, - })); - }); -} - -#[test] -fn set_undeciding_timeout_with_origin_signed_should_fail() { - new_test_ext().execute_with(|| { - let vtoken = VKSM; - let undeciding_timeout = 100; - - assert_noop!( - VtokenVoting::set_undeciding_timeout( - RuntimeOrigin::signed(ALICE), - vtoken, - undeciding_timeout, - ), - DispatchError::BadOrigin - ); - }); -} - -#[test] -fn notify_vote_success_works() { - new_test_ext().execute_with(|| { - let poll_index = 3; - let vtoken = VKSM; - let query_id = 0; - let response = response_success(); - let derivative_index = 0; - - assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, poll_index, aye(2, 5))); - assert_eq!( - ReferendumInfoFor::::get(vtoken, poll_index), - Some(ReferendumInfo::Ongoing(ReferendumStatus { - submitted: None, - tally: TallyOf::::from_parts(20, 0, 4), - })) - ); - assert_eq!( - PendingDelegatorVotes::::get(vtoken, poll_index), - BoundedVec::<(DerivativeIndex, AccountVote), ConstU32<100>>::try_from(vec![( - derivative_index, - aye(200, 0) - )]) - .unwrap() - ); - assert_eq!(DelegatorVotes::::get(vtoken, poll_index).len(), 0); - assert_eq!(tally(vtoken, poll_index), Tally::from_parts(20, 0, 4)); - System::assert_last_event(RuntimeEvent::VtokenVoting(Event::Voted { - who: ALICE, - vtoken, - poll_index, - token_vote: aye(4, 5), - delegator_vote: aye(200, 0), - })); - - assert_ok!(VtokenVoting::notify_vote(origin_response(), query_id, response.clone())); - assert_eq!( - ReferendumInfoFor::::get(vtoken, poll_index), - Some(ReferendumInfo::Ongoing(ReferendumStatus { - submitted: Some(1), - tally: TallyOf::::from_parts(20, 0, 4), - })) - ); - assert_eq!(PendingDelegatorVotes::::get(vtoken, poll_index).len(), 0); - assert_eq!( - DelegatorVotes::::get(vtoken, poll_index), - BoundedVec::<(DerivativeIndex, AccountVote), ConstU32<100>>::try_from(vec![( - derivative_index, - aye(200, 0) - )]) - .unwrap() - ); - System::assert_has_event(RuntimeEvent::VtokenVoting(Event::VoteNotified { - vtoken, - poll_index, - success: true, - })); - System::assert_has_event(RuntimeEvent::VtokenVoting(Event::ReferendumInfoCreated { - vtoken, - poll_index, - info: ReferendumInfo::Ongoing(ReferendumStatus { - submitted: Some(1), - tally: TallyOf::::from_parts(20, 0, 4), - }), - })); - System::assert_last_event(RuntimeEvent::VtokenVoting(Event::ResponseReceived { - responder: Parent.into(), - query_id, - response, - })); - }); -} - -#[test] -fn notify_vote_success_max_works() { - new_test_ext().execute_with(|| { - let vtoken = VKSM; - - for poll_index in 0..256 { - RelaychainDataProvider::set_block_number(1); - - assert_ok!(VtokenVoting::vote( - RuntimeOrigin::signed(ALICE), - vtoken, - poll_index, - aye(2, 5) - )); - assert_ok!(VtokenVoting::notify_vote( - origin_response(), - poll_index as QueryId, - response_success() - )); - - RelaychainDataProvider::set_block_number( - 1 + UndecidingTimeout::::get(vtoken).unwrap(), - ); - VtokenVoting::on_idle(Zero::zero(), Weight::MAX); - } - }); -} - -#[test] -fn notify_vote_success_exceed_max_fail() { - new_test_ext().execute_with(|| { - let vtoken = VKSM; - - for poll_index in 0..50 { - assert_ok!(VtokenVoting::vote( - RuntimeOrigin::signed(ALICE), - vtoken, - poll_index, - aye(2, 5) - )); - assert_ok!(VtokenVoting::notify_vote( - origin_response(), - poll_index as QueryId, - response_success() - )); - } - let poll_index = 50; - assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, poll_index, aye(2, 5))); - assert_noop!( - VtokenVoting::notify_vote(origin_response(), poll_index as QueryId, response_success()), - Error::::TooMany - ); - }); -} - -#[test] -fn notify_vote_fail_works() { - new_test_ext().execute_with(|| { - let poll_index = 3; - let vtoken = VKSM; - let query_id = 0; - let response = response_fail(); - let derivative_index = 0; - - assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, poll_index, aye(2, 5))); - assert_eq!( - ReferendumInfoFor::::get(vtoken, poll_index), - Some(ReferendumInfo::Ongoing(ReferendumStatus { - submitted: None, - tally: TallyOf::::from_parts(20, 0, 4), - })) - ); - assert_eq!(DelegatorVotes::::get(vtoken, poll_index).len(), 0); - assert_eq!( - PendingDelegatorVotes::::get(vtoken, poll_index), - BoundedVec::<(DerivativeIndex, AccountVote), ConstU32<100>>::try_from(vec![( - derivative_index, - aye(200, 0) - )]) - .unwrap() - ); - assert_eq!(tally(vtoken, poll_index), Tally::from_parts(20, 0, 4)); - System::assert_last_event(RuntimeEvent::VtokenVoting(Event::Voted { - who: ALICE, - vtoken, - poll_index, - token_vote: aye(4, 5), - delegator_vote: aye(200, 0), - })); - - assert_ok!(VtokenVoting::notify_vote(origin_response(), query_id, response.clone())); - assert_eq!(ReferendumInfoFor::::get(vtoken, poll_index), None); - assert_eq!(DelegatorVotes::::get(vtoken, poll_index).len(), 0); - assert_eq!(PendingDelegatorVotes::::get(vtoken, poll_index).len(), 0); - System::assert_last_event(RuntimeEvent::VtokenVoting(Event::ResponseReceived { - responder: Parent.into(), - query_id, - response, - })); - }); -} - -#[test] -fn notify_vote_with_no_data_works() { - new_test_ext().execute_with(|| { - let query_id = 0; - let response = response_success(); - - assert_ok!(VtokenVoting::notify_vote(origin_response(), query_id, response.clone())); - System::assert_last_event(RuntimeEvent::VtokenVoting(Event::ResponseReceived { - responder: Parent.into(), - query_id, - response, - })); - }); -} - -#[test] -fn notify_remove_delegator_vote_success_works() { - new_test_ext().execute_with(|| { - let class = 0; - let poll_index = 3; - let vtoken = VKSM; - let mut query_id = 0; - let derivative_index = 0; - let response = response_success(); - - assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, poll_index, aye(2, 5))); - assert_eq!(DelegatorVotes::::get(vtoken, poll_index).len(), 0); - assert_eq!( - PendingDelegatorVotes::::get(vtoken, poll_index), - BoundedVec::<(DerivativeIndex, AccountVote), ConstU32<100>>::try_from(vec![( - derivative_index, - aye(200, 0) - )]) - .unwrap() - ); - assert_eq!(tally(vtoken, poll_index), Tally::from_parts(20, 0, 4)); - System::assert_last_event(RuntimeEvent::VtokenVoting(Event::Voted { - who: ALICE, - vtoken, - poll_index, - token_vote: aye(4, 5), - delegator_vote: aye(200, 0), - })); - assert_ok!(VtokenVoting::notify_vote(origin_response(), query_id, response.clone())); - assert_eq!( - DelegatorVotes::::get(vtoken, poll_index), - BoundedVec::<(DerivativeIndex, AccountVote), ConstU32<100>>::try_from(vec![( - derivative_index, - aye(200, 0) - )]) - .unwrap() - ); - assert_eq!(PendingDelegatorVotes::::get(vtoken, poll_index).len(), 0); - - assert_ok!(VtokenVoting::set_referendum_status( - RuntimeOrigin::root(), - vtoken, - poll_index, - ReferendumInfoOf::::Completed(3), - )); - assert_ok!(VtokenVoting::set_vote_locking_period(RuntimeOrigin::root(), vtoken, 10)); - - RelaychainDataProvider::set_block_number(3); - assert_ok!(VtokenVoting::remove_delegator_vote( - RuntimeOrigin::signed(ALICE), - vtoken, - class, - poll_index, - derivative_index, - )); - assert_eq!(DelegatorVotes::::get(vtoken, poll_index).len(), 1); - - query_id = 1; - assert_ok!(VtokenVoting::notify_remove_delegator_vote( - origin_response(), - query_id, - response.clone() - )); - assert_eq!(DelegatorVotes::::get(vtoken, poll_index).len(), 0); - System::assert_has_event(RuntimeEvent::VtokenVoting(Event::DelegatorVoteRemovedNotified { - vtoken, - poll_index, - success: true, - })); - System::assert_last_event(RuntimeEvent::VtokenVoting(Event::ResponseReceived { - responder: Parent.into(), - query_id, - response, - })); - }); -} - -#[test] -fn notify_remove_delegator_vote_fail_works() { - new_test_ext().execute_with(|| { - let class = 0; - let poll_index = 3; - let vtoken = VKSM; - let mut query_id = 0; - let derivative_index = 0; - let response = response_fail(); - - assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, poll_index, aye(2, 5))); - assert_eq!(DelegatorVotes::::get(vtoken, poll_index).len(), 0); - assert_eq!( - PendingDelegatorVotes::::get(vtoken, poll_index), - BoundedVec::<(DerivativeIndex, AccountVote), ConstU32<100>>::try_from(vec![( - derivative_index, - aye(200, 0) - )]) - .unwrap() - ); - assert_eq!(tally(vtoken, poll_index), Tally::from_parts(20, 0, 4)); - System::assert_last_event(RuntimeEvent::VtokenVoting(Event::Voted { - who: ALICE, - vtoken, - poll_index, - token_vote: aye(4, 5), - delegator_vote: aye(200, 0), - })); - assert_ok!(VtokenVoting::notify_vote(origin_response(), query_id, response_success())); - assert_eq!( - DelegatorVotes::::get(vtoken, poll_index), - BoundedVec::<(DerivativeIndex, AccountVote), ConstU32<100>>::try_from(vec![( - derivative_index, - aye(200, 0) - )]) - .unwrap() - ); - assert_eq!(PendingDelegatorVotes::::get(vtoken, poll_index).len(), 0); - - assert_ok!(VtokenVoting::set_referendum_status( - RuntimeOrigin::root(), - vtoken, - poll_index, - ReferendumInfoOf::::Completed(3), - )); - assert_ok!(VtokenVoting::set_vote_locking_period(RuntimeOrigin::root(), vtoken, 10)); - - RelaychainDataProvider::set_block_number(3); - assert_ok!(VtokenVoting::remove_delegator_vote( - RuntimeOrigin::signed(ALICE), - vtoken, - class, - poll_index, - derivative_index, - )); - assert_eq!(DelegatorVotes::::get(vtoken, poll_index).len(), 1); - - query_id = 1; - assert_ok!(VtokenVoting::notify_remove_delegator_vote( - origin_response(), - query_id, - response.clone() - )); - assert_eq!(DelegatorVotes::::get(vtoken, poll_index).len(), 1); - System::assert_last_event(RuntimeEvent::VtokenVoting(Event::ResponseReceived { - responder: Parent.into(), - query_id, - response, - })); - }); -} - -#[test] -fn notify_remove_delegator_vote_with_no_data_works() { - new_test_ext().execute_with(|| { - let query_id = 0; - let response = response_success(); - - assert_ok!(VtokenVoting::notify_remove_delegator_vote( - origin_response(), - query_id, - response.clone(), - )); - System::assert_last_event(RuntimeEvent::VtokenVoting(Event::ResponseReceived { - responder: Parent.into(), - query_id, - response, - })); - }); -} - -#[test] -fn on_idle_works() { - new_test_ext().execute_with(|| { - let vtoken = VKSM; - 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, - *poll_index, - aye(2, 5) - )); - assert_ok!(VtokenVoting::notify_vote( - origin_response(), - query_id as QueryId, - response_success() - )); - } - - let count = 30; - RelaychainDataProvider::set_block_number( - count + UndecidingTimeout::::get(vtoken).unwrap(), - ); - 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(0, 0)); - - let mut actual_count = 0; - for poll_index in 0..50 { - 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, 31); - }); -} - -#[test] -fn set_vote_cap_ratio_works() { - new_test_ext().execute_with(|| { - let vtoken = VKSM; - - assert_ok!(VtokenVoting::set_vote_cap_ratio( - RuntimeOrigin::root(), - vtoken, - Perbill::from_percent(0) - )); - assert_eq!(VoteCapRatio::::get(vtoken), Perbill::from_percent(0)); - - assert_ok!(VtokenVoting::set_vote_cap_ratio( - RuntimeOrigin::root(), - vtoken, - Perbill::from_percent(10) - )); - assert_eq!(VoteCapRatio::::get(vtoken), Perbill::from_percent(10)); - - assert_ok!(VtokenVoting::set_vote_cap_ratio( - RuntimeOrigin::root(), - vtoken, - Perbill::from_percent(100) - )); - assert_eq!(VoteCapRatio::::get(vtoken), Perbill::from_percent(100)); - }); -} - -#[test] -fn vote_cap_works() { - new_test_ext().execute_with(|| { - let vtoken = VKSM; - assert_eq!(VtokenVoting::vote_cap(vtoken), Ok((u64::MAX / 10) as Balance)); - }); -} - -#[test] -fn vote_to_capital_works() { - new_test_ext().execute_with(|| { - assert_eq!(VtokenVoting::vote_to_capital(Conviction::None, 300), 3000); - assert_eq!(VtokenVoting::vote_to_capital(Conviction::Locked1x, 300), 300); - assert_eq!(VtokenVoting::vote_to_capital(Conviction::Locked2x, 300), 150); - assert_eq!(VtokenVoting::vote_to_capital(Conviction::Locked3x, 300), 100); - assert_eq!(VtokenVoting::vote_to_capital(Conviction::Locked4x, 300), 75); - assert_eq!(VtokenVoting::vote_to_capital(Conviction::Locked5x, 300), 60); - assert_eq!(VtokenVoting::vote_to_capital(Conviction::Locked6x, 300), 50); - }); -} - -#[test] -fn compute_delegator_total_vote_works() { - new_test_ext().execute_with(|| { - let vtoken = VKSM; - assert_eq!(VtokenVoting::compute_delegator_total_vote(vtoken, aye(10, 0)), Ok(aye(10, 0))); - assert_eq!(VtokenVoting::compute_delegator_total_vote(vtoken, aye(2, 1)), Ok(aye(20, 0))); - assert_eq!(VtokenVoting::compute_delegator_total_vote(vtoken, aye(2, 2)), Ok(aye(40, 0))); - assert_eq!(VtokenVoting::compute_delegator_total_vote(vtoken, aye(2, 3)), Ok(aye(60, 0))); - assert_eq!(VtokenVoting::compute_delegator_total_vote(vtoken, aye(2, 4)), Ok(aye(80, 0))); - assert_eq!(VtokenVoting::compute_delegator_total_vote(vtoken, aye(2, 5)), Ok(aye(100, 0))); - assert_eq!(VtokenVoting::compute_delegator_total_vote(vtoken, aye(2, 6)), Ok(aye(120, 0))); - - assert_eq!(VtokenVoting::compute_delegator_total_vote(vtoken, nay(10, 0)), Ok(nay(10, 0))); - assert_eq!(VtokenVoting::compute_delegator_total_vote(vtoken, nay(2, 1)), Ok(nay(20, 0))); - assert_eq!(VtokenVoting::compute_delegator_total_vote(vtoken, nay(2, 2)), Ok(nay(40, 0))); - assert_eq!(VtokenVoting::compute_delegator_total_vote(vtoken, nay(2, 3)), Ok(nay(60, 0))); - assert_eq!(VtokenVoting::compute_delegator_total_vote(vtoken, nay(2, 4)), Ok(nay(80, 0))); - assert_eq!(VtokenVoting::compute_delegator_total_vote(vtoken, nay(2, 5)), Ok(nay(100, 0))); - assert_eq!(VtokenVoting::compute_delegator_total_vote(vtoken, nay(2, 6)), Ok(nay(120, 0))); - - SimpleVTokenSupplyProvider::set_token_supply(10_000_000); - assert_eq!(VtokenVoting::vote_cap(vtoken), Ok(1_000_000)); - assert_eq!( - VtokenVoting::compute_delegator_total_vote(vtoken, aye(1_000_000, 0)), - Ok(aye(1_000_000, 0)) - ); - for i in 1..=6_u8 { - assert_eq!( - VtokenVoting::compute_delegator_total_vote( - vtoken, - aye(10_000_000 * i as Balance, 0) - ), - Ok(aye(1_000_000, i)) - ); - } - - assert_eq!( - VtokenVoting::compute_delegator_total_vote(vtoken, aye(100_000, 1)), - Ok(aye(1_000_000, 0)) - ); - for i in 1..=6_u8 { - assert_eq!( - VtokenVoting::compute_delegator_total_vote( - vtoken, - aye(1_000_000 * i as Balance, 1) - ), - Ok(aye(1_000_000, i)) - ); - } - assert_noop!( - VtokenVoting::compute_delegator_total_vote(vtoken, aye(6_000_006, 1)), - Error::::InsufficientFunds - ); - - assert_eq!( - VtokenVoting::compute_delegator_total_vote(vtoken, aye(50_000, 2)), - Ok(aye(1_000_000, 0)) - ); - for i in 1..=6_u8 { - assert_eq!( - VtokenVoting::compute_delegator_total_vote(vtoken, aye(500_000 * i as Balance, 2)), - Ok(aye(1_000_000, i)) - ); - } - assert_noop!( - VtokenVoting::compute_delegator_total_vote(vtoken, aye(3_000_003, 2)), - Error::::InsufficientFunds - ); - - assert_eq!( - VtokenVoting::compute_delegator_total_vote(vtoken, aye(33_333, 3)), - Ok(aye(999_990, 0)) - ); - for i in 1..=6_u8 { - assert_eq!( - VtokenVoting::compute_delegator_total_vote(vtoken, aye(333_333 * i as Balance, 3)), - Ok(aye(999_999, i)) - ); - } - assert_noop!( - VtokenVoting::compute_delegator_total_vote(vtoken, aye(2_000_002, 3)), - Error::::InsufficientFunds - ); - - assert_eq!( - VtokenVoting::compute_delegator_total_vote(vtoken, aye(25_000, 4)), - Ok(aye(1_000_000, 0)) - ); - for i in 1..=6_u8 { - assert_eq!( - VtokenVoting::compute_delegator_total_vote(vtoken, aye(250_000 * i as Balance, 4)), - Ok(aye(1_000_000, i)) - ); - } - assert_noop!( - VtokenVoting::compute_delegator_total_vote(vtoken, aye(1_500_002, 4)), - Error::::InsufficientFunds - ); - - assert_eq!( - VtokenVoting::compute_delegator_total_vote(vtoken, aye(20_000, 5)), - Ok(aye(1_000_000, 0)) - ); - for i in 1..=6_u8 { - assert_eq!( - VtokenVoting::compute_delegator_total_vote(vtoken, aye(200_000 * i as Balance, 5)), - Ok(aye(1_000_000, i)) - ); - } - assert_noop!( - VtokenVoting::compute_delegator_total_vote(vtoken, aye(1_200_002, 5)), - Error::::InsufficientFunds - ); - - assert_eq!( - VtokenVoting::compute_delegator_total_vote(vtoken, aye(16_666, 6)), - Ok(aye(999_960, 0)) - ); - for i in 1..=6_u8 { - assert_eq!( - VtokenVoting::compute_delegator_total_vote(vtoken, aye(166_666 * i as Balance, 6)), - Ok(aye(999_996, i)) - ); - } - assert_noop!( - VtokenVoting::compute_delegator_total_vote(vtoken, aye(1_000_001, 6)), - Error::::InsufficientFunds - ); - }); -} - -#[test] -fn compute_delegator_total_vote_with_low_value_will_loss() { - new_test_ext().execute_with(|| { - let vtoken = VKSM; - assert_eq!(VtokenVoting::compute_delegator_total_vote(vtoken, aye(9, 0)), Ok(aye(0, 0))); - assert_eq!(VtokenVoting::compute_delegator_total_vote(vtoken, nay(9, 0)), Ok(nay(0, 0))); - }); -} - -#[test] -fn allocate_delegator_votes_works() { - new_test_ext().execute_with(|| { - let vtoken = VKSM; - let poll_index = 3; - - for conviction in 0..=6 { - let vote = aye(5e9 as Balance, conviction); - let delegator_votes = VtokenVoting::allocate_delegator_votes(vtoken, poll_index, vote); - assert_eq!( - delegator_votes, - Ok(vec![(0, aye(4294967295, conviction)), (1, aye(705032705, conviction))]) - ); - assert_eq!( - delegator_votes.unwrap().into_iter().map(|(_derivative_index, vote)| vote).fold( - aye(0, conviction), - |mut acc, vote| { - let _ = acc.checked_add(vote); - acc - }, - ), - vote - ); - } - - for conviction in 0..=6 { - let vote = aye(3e10 as Balance, conviction); - let delegator_votes = VtokenVoting::allocate_delegator_votes(vtoken, poll_index, vote); - assert_eq!( - delegator_votes, - Ok(vec![ - (0, aye(4294967295, conviction)), - (1, aye(4294967295, conviction)), - (2, aye(4294967295, conviction)), - (3, aye(4294967295, conviction)), - (4, aye(4294967295, conviction)), - (5, aye(4294967295, conviction)), - (10, aye(4230196230, conviction)) - ]) - ); - assert_eq!( - delegator_votes.unwrap().into_iter().map(|(_derivative_index, vote)| vote).fold( - aye(0, conviction), - |mut acc, vote| { - let _ = acc.checked_add(vote); - acc - }, - ), - vote - ); - } - }); -} - -#[test] -fn tally_convert_works() { - assert_eq!( - TallyOf::::from_parts(10, 9, 0).account_vote(Conviction::Locked1x), - aye(1, 1) - ); - assert_eq!( - TallyOf::::from_parts(10, 11, 0).account_vote(Conviction::Locked1x), - nay(1, 1) - ); - assert_eq!( - TallyOf::::from_parts(10, 10, 0).account_vote(Conviction::Locked1x), - aye(0, 1) - ); -} - -#[test] -fn set_lock_works() { - new_test_ext().execute_with(|| { - let vtoken = VKSM; - - assert_ok!(VtokenVoting::set_lock(&ALICE, vtoken, 10)); - assert_eq!(usable_balance(vtoken, &ALICE), 0); - - assert_ok!(VtokenVoting::set_lock(&ALICE, vtoken, 1)); - assert_eq!(usable_balance(vtoken, &ALICE), 9); - - assert_ok!(VtokenVoting::set_lock(&ALICE, vtoken, 0)); - assert_eq!(usable_balance(vtoken, &ALICE), 10); - }); -} diff --git a/pallets/vtoken-voting/src/tests/common_test.rs b/pallets/vtoken-voting/src/tests/common_test.rs new file mode 100644 index 000000000..721d4aebd --- /dev/null +++ b/pallets/vtoken-voting/src/tests/common_test.rs @@ -0,0 +1,1564 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . + +// Ensure we're `no_std` when compiling for Wasm. +use crate::{mock::*, *}; +use bifrost_primitives::currency::VPHA; +use frame_support::{ + assert_noop, assert_ok, + traits::{ + fungibles::Inspect, + tokens::{Fortitude::Polite, Preservation::Expendable}, + }, + weights::RuntimeDbWeight, +}; +use pallet_xcm::Origin as XcmOrigin; + +const TOKENS: &[CurrencyId] = if cfg!(feature = "polkadot") { + &[VDOT] +} else if cfg!(feature = "kusama") { + &[VKSM] +} else { + &[] +}; + +fn aye(amount: Balance, conviction: u8) -> AccountVote { + let vote = Vote { aye: true, conviction: conviction.try_into().unwrap() }; + AccountVote::Standard { vote, balance: amount } +} + +fn nay(amount: Balance, conviction: u8) -> AccountVote { + let vote = Vote { aye: false, conviction: conviction.try_into().unwrap() }; + AccountVote::Standard { vote, balance: amount } +} + +fn tally(vtoken: CurrencyId, poll_index: u32) -> TallyOf { + VtokenVoting::ensure_referendum_ongoing(vtoken, poll_index) + .expect("No poll") + .tally +} + +fn usable_balance(vtoken: CurrencyId, who: &AccountId) -> Balance { + Tokens::reducible_balance(vtoken, who, Expendable, Polite) +} + +fn origin_response() -> RuntimeOrigin { + XcmOrigin::Response(Parent.into()).into() +} + +fn response_success() -> Response { + Response::DispatchResult(MaybeErrorCode::Success) +} + +fn response_fail() -> Response { + Response::DispatchResult(MaybeErrorCode::Error(BoundedVec::try_from(vec![0u8, 1u8]).unwrap())) +} + +#[test] +fn basic_voting_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index, + aye(2, 5) + )); + assert_eq!(tally(vtoken, poll_index), Tally::from_parts(20, 0, 4)); + System::assert_last_event(RuntimeEvent::VtokenVoting(Event::Voted { + who: ALICE, + vtoken, + poll_index, + token_vote: aye(4, 5), + delegator_vote: aye(200, 0), + })); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 0, response_success())); + + assert_ok!(VtokenVoting::try_remove_vote(&ALICE, vtoken, poll_index, UnvoteScope::Any)); + assert_eq!(tally(vtoken, poll_index), Tally::from_parts(0, 0, 0)); + + assert_ok!(VtokenVoting::update_lock(&ALICE, vtoken)); + assert_eq!(usable_balance(vtoken, &ALICE), 10); + }); + } +} + +#[test] +fn voting_balance_gets_locked() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index, + nay(10, 0) + )); + assert_eq!(tally(vtoken, poll_index), Tally::from_parts(0, 2, 0)); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 0, response_success())); + assert_eq!(usable_balance(vtoken, &ALICE), 0); + + assert_ok!(VtokenVoting::try_remove_vote(&ALICE, vtoken, poll_index, UnvoteScope::Any)); + assert_eq!(tally(vtoken, poll_index), Tally::from_parts(0, 0, 0)); + + assert_ok!(VtokenVoting::update_lock(&ALICE, vtoken)); + assert_eq!(usable_balance(vtoken, &ALICE), 10); + }); + } +} + +#[test] +fn successful_but_zero_conviction_vote_balance_can_be_unlocked() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index, + aye(1, 1) + )); + assert_eq!(usable_balance(vtoken, &ALICE), 9); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 0, response_success())); + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index, + aye(3, 1) + )); + assert_eq!(usable_balance(vtoken, &ALICE), 7); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 1, response_success())); + + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(BOB), + vtoken, + poll_index, + nay(20, 0) + )); + assert_eq!(usable_balance(vtoken, &BOB), 0); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 2, response_success())); + + assert_ok!(VtokenVoting::set_vote_locking_period(RuntimeOrigin::root(), vtoken, 10)); + assert_ok!(VtokenVoting::set_referendum_status( + RuntimeOrigin::root(), + vtoken, + poll_index, + ReferendumInfoOf::::Completed(3), + )); + + assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(BOB), vtoken, poll_index)); + assert_eq!(usable_balance(vtoken, &BOB), 20); + + RelaychainDataProvider::set_block_number(13); + assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, poll_index)); + assert_eq!(usable_balance(vtoken, &ALICE), 10); + }); + } +} + +#[test] +fn unsuccessful_conviction_vote_balance_can_be_unlocked() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + 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())); + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(BOB), + vtoken, + poll_index, + nay(20, 0) + )); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 1, response_success())); + + assert_ok!(VtokenVoting::set_referendum_status( + RuntimeOrigin::root(), + vtoken, + 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)); + assert_eq!(usable_balance(vtoken, &ALICE), 10); + }); + } +} + +#[test] +fn ensure_balance_after_unlock() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + let poll_index_2 = 4; + 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(10, 1) + )); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 0, response_success())); + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index_2, + aye(10, 5) + )); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 1, response_success())); + + assert_ok!(VtokenVoting::set_referendum_status( + RuntimeOrigin::root(), + vtoken, + poll_index, + ReferendumInfoOf::::Completed(3), + )); + RelaychainDataProvider::set_block_number(13); + assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, poll_index)); + assert_eq!(usable_balance(vtoken, &ALICE), 0); + assert_eq!(Tokens::accounts(&ALICE, vtoken).frozen, 10); + assert_eq!(VotingFor::::get(&ALICE).locked_balance(), 10); + }); + } +} + +#[test] +fn ensure_comprehensive_balance_after_unlock() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + let poll_index_2 = 4; + let poll_index_3 = 5; + 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(2, 1) + )); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 0, response_success())); + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index_2, + aye(1, 5) + )); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 1, response_success())); + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index_3, + aye(2, 5) + )); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 2, response_success())); + + assert_ok!(VtokenVoting::set_referendum_status( + RuntimeOrigin::root(), + vtoken, + poll_index, + ReferendumInfoOf::::Completed(3), + )); + RelaychainDataProvider::set_block_number(13); + assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, poll_index)); + assert_eq!(usable_balance(vtoken, &ALICE), 8); + assert_eq!(Tokens::accounts(&ALICE, vtoken).frozen, 2); + assert_eq!(VotingFor::::get(&ALICE).locked_balance(), 2); + + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index_2, + aye(10, 5) + )); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 3, response_success())); + + assert_eq!(usable_balance(vtoken, &ALICE), 0); + assert_eq!(Tokens::accounts(&ALICE, vtoken).frozen, 10); + assert_eq!(VotingFor::::get(&ALICE).locked_balance(), 10); + }); + } +} + +#[test] +fn successful_conviction_vote_balance_stays_locked_for_correct_time() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + 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), + vtoken, + poll_index, + aye(10, i as u8) + )); + assert_ok!(VtokenVoting::notify_vote(origin_response(), i - 1, response_success())); + } + assert_ok!(VtokenVoting::set_referendum_status( + RuntimeOrigin::root(), + vtoken, + 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)); + } + for i in 1..=5 { + assert_ok!(VtokenVoting::update_lock(&i, vtoken)); + assert_eq!(usable_balance(vtoken, &i), 10 * i as u128); + } + }); + } +} + +#[test] +fn lock_amalgamation_valid_with_multiple_removed_votes() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let response = response_success(); + + assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, 0, aye(5, 1))); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 0, response.clone())); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 5),]) + .unwrap() + ); + + assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, 1, aye(10, 1))); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 1, response.clone())); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 10),]) + .unwrap() + ); + + assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, 1, aye(5, 1))); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 2, response.clone())); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 5),]) + .unwrap() + ); + assert_eq!(usable_balance(vtoken, &ALICE), 5); + + assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, 2, aye(10, 2))); + assert_ok!(VtokenVoting::notify_vote(origin_response(), 3, response.clone())); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 10),]) + .unwrap() + ); + + 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), + )); + + let locking_period = 10; + assert_ok!(VtokenVoting::set_vote_locking_period( + RuntimeOrigin::root(), + vtoken, + locking_period, + )); + assert_eq!(VoteLockingPeriod::::get(vtoken), Some(10)); + + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 10),]) + .unwrap() + ); + + RelaychainDataProvider::set_block_number(10); + assert_noop!( + VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 0), + Error::::NoPermissionYet + ); + assert_eq!(VotingFor::::get(&ALICE).locked_balance(), 10); + assert_eq!(usable_balance(vtoken, &ALICE), 0); + + RelaychainDataProvider::set_block_number(11); + assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 0)); + assert_eq!(VotingFor::::get(&ALICE).locked_balance(), 10); + assert_eq!(usable_balance(vtoken, &ALICE), 0); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 10),]) + .unwrap() + ); + + RelaychainDataProvider::set_block_number(11); + assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 1)); + assert_eq!(usable_balance(vtoken, &ALICE), 0); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 10)]) + .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::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![]).unwrap() + ); + }); + } +} + +#[test] +fn removed_votes_when_referendum_killed() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + 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, + 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), + )); + + 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::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 10),]) + .unwrap() + ); + + assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 0)); + assert_eq!(usable_balance(vtoken, &ALICE), 0); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 10),]) + .unwrap() + ); + + assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 1)); + assert_eq!(usable_balance(vtoken, &ALICE), 5); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 5)]) + .unwrap() + ); + + assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 2)); + assert_eq!(usable_balance(vtoken, &ALICE), 10); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![]).unwrap() + ); + }); + } +} + +#[test] +fn errors_with_vote_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + assert_noop!( + VtokenVoting::vote(RuntimeOrigin::signed(1), VPHA, 0, aye(10, 0)), + Error::::VTokenNotSupport + ); + assert_noop!( + VtokenVoting::vote(RuntimeOrigin::signed(1), vtoken, 3, aye(11, 0)), + Error::::InsufficientFunds + ); + + for poll_index in 0..256 { + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(1), + vtoken, + poll_index, + aye(10, 0) + )); + } + assert_noop!( + VtokenVoting::vote(RuntimeOrigin::signed(1), vtoken, 256, aye(10, 0)), + Error::::MaxVotesReached + ); + }); + } +} + +#[test] +fn kill_referendum_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index, + aye(5, 1) + )); + assert_ok!(VtokenVoting::set_referendum_status( + RuntimeOrigin::root(), + vtoken, + poll_index, + ReferendumInfoOf::::Completed(1), + )); + assert_ok!(VtokenVoting::kill_referendum(RuntimeOrigin::root(), vtoken, poll_index)); + System::assert_last_event(RuntimeEvent::VtokenVoting(Event::ReferendumKilled { + vtoken, + poll_index, + })); + }); + } +} + +#[test] +fn kill_referendum_with_origin_signed_fails() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index, + aye(5, 1) + )); + assert_ok!(VtokenVoting::set_referendum_status( + RuntimeOrigin::root(), + vtoken, + poll_index, + ReferendumInfoOf::::Completed(1), + )); + assert_noop!( + VtokenVoting::kill_referendum(RuntimeOrigin::signed(ALICE), vtoken, poll_index), + DispatchError::BadOrigin + ); + }); + } +} + +#[test] +fn add_delegator_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let derivative_index: DerivativeIndex = 100; + + assert_ok!(VtokenVoting::add_delegator( + RuntimeOrigin::root(), + vtoken, + derivative_index, + )); + + System::assert_last_event(RuntimeEvent::VtokenVoting(Event::DelegatorAdded { + vtoken, + derivative_index, + })); + }); + } +} + +#[test] +fn set_referendum_status_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + let info = ReferendumInfo::Completed(3); + + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index, + aye(2, 5) + )); + assert_ok!(VtokenVoting::set_referendum_status( + RuntimeOrigin::root(), + vtoken, + poll_index, + info.clone(), + )); + + System::assert_last_event(RuntimeEvent::VtokenVoting(Event::ReferendumInfoSet { + vtoken, + poll_index, + info, + })); + }); + } +} + +#[test] +fn set_referendum_status_without_vote_should_fail() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + let info = ReferendumInfo::Completed(3); + + assert_noop!( + VtokenVoting::set_referendum_status( + RuntimeOrigin::root(), + vtoken, + poll_index, + info.clone(), + ), + Error::::NoData + ); + }); + } +} + +#[test] +fn set_referendum_status_with_origin_signed_should_fail() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + let info = ReferendumInfo::Completed(3); + + assert_noop!( + VtokenVoting::set_referendum_status( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index, + info.clone(), + ), + DispatchError::BadOrigin + ); + }); + } +} + +#[test] +fn set_vote_locking_period_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let locking_period = 100; + + assert_ok!(VtokenVoting::set_vote_locking_period( + RuntimeOrigin::root(), + vtoken, + locking_period, + )); + + System::assert_last_event(RuntimeEvent::VtokenVoting(Event::VoteLockingPeriodSet { + vtoken, + locking_period, + })); + }); + } +} + +#[test] +fn set_vote_locking_period_with_origin_signed_should_fail() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let locking_period = 100; + + assert_noop!( + VtokenVoting::set_vote_locking_period( + RuntimeOrigin::signed(ALICE), + vtoken, + locking_period, + ), + DispatchError::BadOrigin + ); + }); + } +} + +#[test] +fn set_undeciding_timeout_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let undeciding_timeout = 100; + + assert_ok!(VtokenVoting::set_undeciding_timeout( + RuntimeOrigin::root(), + vtoken, + undeciding_timeout, + )); + + System::assert_last_event(RuntimeEvent::VtokenVoting(Event::UndecidingTimeoutSet { + vtoken, + undeciding_timeout, + })); + }); + } +} + +#[test] +fn set_undeciding_timeout_with_origin_signed_should_fail() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let undeciding_timeout = 100; + + assert_noop!( + VtokenVoting::set_undeciding_timeout( + RuntimeOrigin::signed(ALICE), + vtoken, + undeciding_timeout, + ), + DispatchError::BadOrigin + ); + }); + } +} + +#[test] +fn notify_vote_success_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + let query_id = 0; + let response = response_success(); + let derivative_index = 0; + + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index, + aye(2, 5) + )); + assert_eq!( + ReferendumInfoFor::::get(vtoken, poll_index), + Some(ReferendumInfo::Ongoing(ReferendumStatus { + submitted: None, + tally: TallyOf::::from_parts(20, 0, 4), + })) + ); + assert_eq!( + PendingDelegatorVotes::::get(vtoken, poll_index), + BoundedVec::<(DerivativeIndex, AccountVote), ConstU32<100>>::try_from( + vec![(derivative_index, aye(200, 0))] + ) + .unwrap() + ); + assert_eq!(DelegatorVotes::::get(vtoken, poll_index).len(), 0); + assert_eq!(tally(vtoken, poll_index), Tally::from_parts(20, 0, 4)); + System::assert_last_event(RuntimeEvent::VtokenVoting(Event::Voted { + who: ALICE, + vtoken, + poll_index, + token_vote: aye(4, 5), + delegator_vote: aye(200, 0), + })); + + assert_ok!(VtokenVoting::notify_vote(origin_response(), query_id, response.clone())); + assert_eq!( + ReferendumInfoFor::::get(vtoken, poll_index), + Some(ReferendumInfo::Ongoing(ReferendumStatus { + submitted: Some(1), + tally: TallyOf::::from_parts(20, 0, 4), + })) + ); + assert_eq!(PendingDelegatorVotes::::get(vtoken, poll_index).len(), 0); + assert_eq!( + DelegatorVotes::::get(vtoken, poll_index), + BoundedVec::<(DerivativeIndex, AccountVote), ConstU32<100>>::try_from( + vec![(derivative_index, aye(200, 0))] + ) + .unwrap() + ); + System::assert_has_event(RuntimeEvent::VtokenVoting(Event::VoteNotified { + vtoken, + poll_index, + success: true, + })); + System::assert_has_event(RuntimeEvent::VtokenVoting(Event::ReferendumInfoCreated { + vtoken, + poll_index, + info: ReferendumInfo::Ongoing(ReferendumStatus { + submitted: Some(1), + tally: TallyOf::::from_parts(20, 0, 4), + }), + })); + System::assert_last_event(RuntimeEvent::VtokenVoting(Event::ResponseReceived { + responder: Parent.into(), + query_id, + response, + })); + }); + } +} + +#[test] +fn notify_vote_success_max_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + for poll_index in 0..256 { + RelaychainDataProvider::set_block_number(1); + + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index, + aye(2, 5) + )); + assert_ok!(VtokenVoting::notify_vote( + origin_response(), + poll_index as QueryId, + response_success() + )); + + RelaychainDataProvider::set_block_number( + 1 + UndecidingTimeout::::get(vtoken).unwrap(), + ); + VtokenVoting::on_idle(Zero::zero(), Weight::MAX); + } + }); + } +} + +#[test] +fn notify_vote_success_exceed_max_fail() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + for poll_index in 0..50 { + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index, + aye(2, 5) + )); + assert_ok!(VtokenVoting::notify_vote( + origin_response(), + poll_index as QueryId, + response_success() + )); + } + let poll_index = 50; + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index, + aye(2, 5) + )); + assert_noop!( + VtokenVoting::notify_vote( + origin_response(), + poll_index as QueryId, + response_success() + ), + Error::::TooMany + ); + }); + } +} + +#[test] +fn notify_vote_fail_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + let query_id = 0; + let response = response_fail(); + let derivative_index = 0; + + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index, + aye(2, 5) + )); + assert_eq!( + ReferendumInfoFor::::get(vtoken, poll_index), + Some(ReferendumInfo::Ongoing(ReferendumStatus { + submitted: None, + tally: TallyOf::::from_parts(20, 0, 4), + })) + ); + assert_eq!(DelegatorVotes::::get(vtoken, poll_index).len(), 0); + assert_eq!( + PendingDelegatorVotes::::get(vtoken, poll_index), + BoundedVec::<(DerivativeIndex, AccountVote), ConstU32<100>>::try_from( + vec![(derivative_index, aye(200, 0))] + ) + .unwrap() + ); + assert_eq!(tally(vtoken, poll_index), Tally::from_parts(20, 0, 4)); + System::assert_last_event(RuntimeEvent::VtokenVoting(Event::Voted { + who: ALICE, + vtoken, + poll_index, + token_vote: aye(4, 5), + delegator_vote: aye(200, 0), + })); + + assert_ok!(VtokenVoting::notify_vote(origin_response(), query_id, response.clone())); + assert_eq!(ReferendumInfoFor::::get(vtoken, poll_index), None); + assert_eq!(DelegatorVotes::::get(vtoken, poll_index).len(), 0); + assert_eq!(PendingDelegatorVotes::::get(vtoken, poll_index).len(), 0); + System::assert_last_event(RuntimeEvent::VtokenVoting(Event::ResponseReceived { + responder: Parent.into(), + query_id, + response, + })); + }); + } +} + +#[test] +fn notify_vote_with_no_data_works() { + new_test_ext().execute_with(|| { + let query_id = 0; + let response = response_success(); + + assert_ok!(VtokenVoting::notify_vote(origin_response(), query_id, response.clone())); + System::assert_last_event(RuntimeEvent::VtokenVoting(Event::ResponseReceived { + responder: Parent.into(), + query_id, + response, + })); + }); +} + +#[test] +fn notify_remove_delegator_vote_success_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let class = 0; + let poll_index = 3; + let mut query_id = 0; + let derivative_index = 0; + let response = response_success(); + + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index, + aye(2, 5) + )); + assert_eq!(DelegatorVotes::::get(vtoken, poll_index).len(), 0); + assert_eq!( + PendingDelegatorVotes::::get(vtoken, poll_index), + BoundedVec::<(DerivativeIndex, AccountVote), ConstU32<100>>::try_from( + vec![(derivative_index, aye(200, 0))] + ) + .unwrap() + ); + assert_eq!(tally(vtoken, poll_index), Tally::from_parts(20, 0, 4)); + System::assert_last_event(RuntimeEvent::VtokenVoting(Event::Voted { + who: ALICE, + vtoken, + poll_index, + token_vote: aye(4, 5), + delegator_vote: aye(200, 0), + })); + assert_ok!(VtokenVoting::notify_vote(origin_response(), query_id, response.clone())); + assert_eq!( + DelegatorVotes::::get(vtoken, poll_index), + BoundedVec::<(DerivativeIndex, AccountVote), ConstU32<100>>::try_from( + vec![(derivative_index, aye(200, 0))] + ) + .unwrap() + ); + assert_eq!(PendingDelegatorVotes::::get(vtoken, poll_index).len(), 0); + + assert_ok!(VtokenVoting::set_referendum_status( + RuntimeOrigin::root(), + vtoken, + poll_index, + ReferendumInfoOf::::Completed(3), + )); + assert_ok!(VtokenVoting::set_vote_locking_period(RuntimeOrigin::root(), vtoken, 10)); + + RelaychainDataProvider::set_block_number(3); + assert_ok!(VtokenVoting::remove_delegator_vote( + RuntimeOrigin::signed(ALICE), + vtoken, + class, + poll_index, + derivative_index, + )); + assert_eq!(DelegatorVotes::::get(vtoken, poll_index).len(), 1); + + query_id = 1; + assert_ok!(VtokenVoting::notify_remove_delegator_vote( + origin_response(), + query_id, + response.clone() + )); + assert_eq!(DelegatorVotes::::get(vtoken, poll_index).len(), 0); + System::assert_has_event(RuntimeEvent::VtokenVoting( + Event::DelegatorVoteRemovedNotified { vtoken, poll_index, success: true }, + )); + System::assert_last_event(RuntimeEvent::VtokenVoting(Event::ResponseReceived { + responder: Parent.into(), + query_id, + response, + })); + }); + } +} + +#[test] +fn notify_remove_delegator_vote_fail_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let class = 0; + let poll_index = 3; + let mut query_id = 0; + let derivative_index = 0; + let response = response_fail(); + + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index, + aye(2, 5) + )); + assert_eq!(DelegatorVotes::::get(vtoken, poll_index).len(), 0); + assert_eq!( + PendingDelegatorVotes::::get(vtoken, poll_index), + BoundedVec::<(DerivativeIndex, AccountVote), ConstU32<100>>::try_from( + vec![(derivative_index, aye(200, 0))] + ) + .unwrap() + ); + assert_eq!(tally(vtoken, poll_index), Tally::from_parts(20, 0, 4)); + System::assert_last_event(RuntimeEvent::VtokenVoting(Event::Voted { + who: ALICE, + vtoken, + poll_index, + token_vote: aye(4, 5), + delegator_vote: aye(200, 0), + })); + assert_ok!(VtokenVoting::notify_vote(origin_response(), query_id, response_success())); + assert_eq!( + DelegatorVotes::::get(vtoken, poll_index), + BoundedVec::<(DerivativeIndex, AccountVote), ConstU32<100>>::try_from( + vec![(derivative_index, aye(200, 0))] + ) + .unwrap() + ); + assert_eq!(PendingDelegatorVotes::::get(vtoken, poll_index).len(), 0); + + assert_ok!(VtokenVoting::set_referendum_status( + RuntimeOrigin::root(), + vtoken, + poll_index, + ReferendumInfoOf::::Completed(3), + )); + assert_ok!(VtokenVoting::set_vote_locking_period(RuntimeOrigin::root(), vtoken, 10)); + + RelaychainDataProvider::set_block_number(3); + assert_ok!(VtokenVoting::remove_delegator_vote( + RuntimeOrigin::signed(ALICE), + vtoken, + class, + poll_index, + derivative_index, + )); + assert_eq!(DelegatorVotes::::get(vtoken, poll_index).len(), 1); + + query_id = 1; + assert_ok!(VtokenVoting::notify_remove_delegator_vote( + origin_response(), + query_id, + response.clone() + )); + assert_eq!(DelegatorVotes::::get(vtoken, poll_index).len(), 1); + System::assert_last_event(RuntimeEvent::VtokenVoting(Event::ResponseReceived { + responder: Parent.into(), + query_id, + response, + })); + }); + } +} + +#[test] +fn notify_remove_delegator_vote_with_no_data_works() { + new_test_ext().execute_with(|| { + let query_id = 0; + let response = response_success(); + + assert_ok!(VtokenVoting::notify_remove_delegator_vote( + origin_response(), + query_id, + response.clone(), + )); + System::assert_last_event(RuntimeEvent::VtokenVoting(Event::ResponseReceived { + responder: Parent.into(), + query_id, + response, + })); + }); +} + +#[test] +fn on_idle_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + 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, + *poll_index, + aye(2, 5) + )); + assert_ok!(VtokenVoting::notify_vote( + origin_response(), + query_id as QueryId, + response_success() + )); + } + + let count = 30; + RelaychainDataProvider::set_block_number( + count + UndecidingTimeout::::get(vtoken).unwrap(), + ); + 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(0, 0)); + + let mut actual_count = 0; + for poll_index in 0..50 { + 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, 31); + }); + } +} + +#[test] +fn set_vote_cap_ratio_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + assert_ok!(VtokenVoting::set_vote_cap_ratio( + RuntimeOrigin::root(), + vtoken, + Perbill::from_percent(0) + )); + assert_eq!(VoteCapRatio::::get(vtoken), Perbill::from_percent(0)); + + assert_ok!(VtokenVoting::set_vote_cap_ratio( + RuntimeOrigin::root(), + vtoken, + Perbill::from_percent(10) + )); + assert_eq!(VoteCapRatio::::get(vtoken), Perbill::from_percent(10)); + + assert_ok!(VtokenVoting::set_vote_cap_ratio( + RuntimeOrigin::root(), + vtoken, + Perbill::from_percent(100) + )); + assert_eq!(VoteCapRatio::::get(vtoken), Perbill::from_percent(100)); + }); + } +} + +#[test] +fn vote_cap_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + assert_eq!(VtokenVoting::vote_cap(vtoken), Ok((u64::MAX / 10) as Balance)); + }); + } +} + +#[test] +fn vote_to_capital_works() { + new_test_ext().execute_with(|| { + assert_eq!(VtokenVoting::vote_to_capital(Conviction::None, 300), 3000); + assert_eq!(VtokenVoting::vote_to_capital(Conviction::Locked1x, 300), 300); + assert_eq!(VtokenVoting::vote_to_capital(Conviction::Locked2x, 300), 150); + assert_eq!(VtokenVoting::vote_to_capital(Conviction::Locked3x, 300), 100); + assert_eq!(VtokenVoting::vote_to_capital(Conviction::Locked4x, 300), 75); + assert_eq!(VtokenVoting::vote_to_capital(Conviction::Locked5x, 300), 60); + assert_eq!(VtokenVoting::vote_to_capital(Conviction::Locked6x, 300), 50); + }); +} + +#[test] +fn compute_delegator_total_vote_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(10, 0)), + Ok(aye(10, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(2, 1)), + Ok(aye(20, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(2, 2)), + Ok(aye(40, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(2, 3)), + Ok(aye(60, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(2, 4)), + Ok(aye(80, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(2, 5)), + Ok(aye(100, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(2, 6)), + Ok(aye(120, 0)) + ); + + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, nay(10, 0)), + Ok(nay(10, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, nay(2, 1)), + Ok(nay(20, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, nay(2, 2)), + Ok(nay(40, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, nay(2, 3)), + Ok(nay(60, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, nay(2, 4)), + Ok(nay(80, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, nay(2, 5)), + Ok(nay(100, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, nay(2, 6)), + Ok(nay(120, 0)) + ); + + SimpleVTokenSupplyProvider::set_token_supply(10_000_000); + assert_eq!(VtokenVoting::vote_cap(vtoken), Ok(1_000_000)); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(1_000_000, 0)), + Ok(aye(1_000_000, 0)) + ); + for i in 1..=6_u8 { + assert_eq!( + VtokenVoting::compute_delegator_total_vote( + vtoken, + aye(10_000_000 * i as Balance, 0) + ), + Ok(aye(1_000_000, i)) + ); + } + + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(100_000, 1)), + Ok(aye(1_000_000, 0)) + ); + for i in 1..=6_u8 { + assert_eq!( + VtokenVoting::compute_delegator_total_vote( + vtoken, + aye(1_000_000 * i as Balance, 1) + ), + Ok(aye(1_000_000, i)) + ); + } + assert_noop!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(6_000_006, 1)), + Error::::InsufficientFunds + ); + + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(50_000, 2)), + Ok(aye(1_000_000, 0)) + ); + for i in 1..=6_u8 { + assert_eq!( + VtokenVoting::compute_delegator_total_vote( + vtoken, + aye(500_000 * i as Balance, 2) + ), + Ok(aye(1_000_000, i)) + ); + } + assert_noop!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(3_000_003, 2)), + Error::::InsufficientFunds + ); + + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(33_333, 3)), + Ok(aye(999_990, 0)) + ); + for i in 1..=6_u8 { + assert_eq!( + VtokenVoting::compute_delegator_total_vote( + vtoken, + aye(333_333 * i as Balance, 3) + ), + Ok(aye(999_999, i)) + ); + } + assert_noop!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(2_000_002, 3)), + Error::::InsufficientFunds + ); + + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(25_000, 4)), + Ok(aye(1_000_000, 0)) + ); + for i in 1..=6_u8 { + assert_eq!( + VtokenVoting::compute_delegator_total_vote( + vtoken, + aye(250_000 * i as Balance, 4) + ), + Ok(aye(1_000_000, i)) + ); + } + assert_noop!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(1_500_002, 4)), + Error::::InsufficientFunds + ); + + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(20_000, 5)), + Ok(aye(1_000_000, 0)) + ); + for i in 1..=6_u8 { + assert_eq!( + VtokenVoting::compute_delegator_total_vote( + vtoken, + aye(200_000 * i as Balance, 5) + ), + Ok(aye(1_000_000, i)) + ); + } + assert_noop!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(1_200_002, 5)), + Error::::InsufficientFunds + ); + + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(16_666, 6)), + Ok(aye(999_960, 0)) + ); + for i in 1..=6_u8 { + assert_eq!( + VtokenVoting::compute_delegator_total_vote( + vtoken, + aye(166_666 * i as Balance, 6) + ), + Ok(aye(999_996, i)) + ); + } + assert_noop!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(1_000_001, 6)), + Error::::InsufficientFunds + ); + }); + } +} + +#[test] +fn compute_delegator_total_vote_with_low_value_will_loss() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(9, 0)), + Ok(aye(0, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, nay(9, 0)), + Ok(nay(0, 0)) + ); + }); + } +} + +#[test] +fn allocate_delegator_votes_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + + for conviction in 0..=6 { + let vote = aye(5e9 as Balance, conviction); + let delegator_votes = + VtokenVoting::allocate_delegator_votes(vtoken, poll_index, vote); + assert_eq!( + delegator_votes, + Ok(vec![(0, aye(4294967295, conviction)), (1, aye(705032705, conviction))]) + ); + assert_eq!( + delegator_votes + .unwrap() + .into_iter() + .map(|(_derivative_index, vote)| vote) + .fold(aye(0, conviction), |mut acc, vote| { + let _ = acc.checked_add(vote); + acc + },), + vote + ); + } + + for conviction in 0..=6 { + let vote = aye(3e10 as Balance, conviction); + let delegator_votes = + VtokenVoting::allocate_delegator_votes(vtoken, poll_index, vote); + assert_eq!( + delegator_votes, + Ok(vec![ + (0, aye(4294967295, conviction)), + (1, aye(4294967295, conviction)), + (2, aye(4294967295, conviction)), + (3, aye(4294967295, conviction)), + (4, aye(4294967295, conviction)), + (5, aye(4294967295, conviction)), + (10, aye(4230196230, conviction)) + ]) + ); + assert_eq!( + delegator_votes + .unwrap() + .into_iter() + .map(|(_derivative_index, vote)| vote) + .fold(aye(0, conviction), |mut acc, vote| { + let _ = acc.checked_add(vote); + acc + },), + vote + ); + } + }); + } +} + +#[test] +fn tally_convert_works() { + assert_eq!( + TallyOf::::from_parts(10, 9, 0).account_vote(Conviction::Locked1x), + aye(1, 1) + ); + assert_eq!( + TallyOf::::from_parts(10, 11, 0).account_vote(Conviction::Locked1x), + nay(1, 1) + ); + assert_eq!( + TallyOf::::from_parts(10, 10, 0).account_vote(Conviction::Locked1x), + aye(0, 1) + ); +} + +#[test] +fn set_lock_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + assert_ok!(VtokenVoting::set_lock(&ALICE, vtoken, 10)); + assert_eq!(usable_balance(vtoken, &ALICE), 0); + + assert_ok!(VtokenVoting::set_lock(&ALICE, vtoken, 1)); + assert_eq!(usable_balance(vtoken, &ALICE), 9); + + assert_ok!(VtokenVoting::set_lock(&ALICE, vtoken, 0)); + assert_eq!(usable_balance(vtoken, &ALICE), 10); + }); + } +} diff --git a/pallets/vtoken-voting/src/tests/mod.rs b/pallets/vtoken-voting/src/tests/mod.rs new file mode 100644 index 000000000..955f282ad --- /dev/null +++ b/pallets/vtoken-voting/src/tests/mod.rs @@ -0,0 +1,23 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . + +#[cfg(test)] +mod common_test; + +#[cfg(test)] +mod vbnc_test; diff --git a/pallets/vtoken-voting/src/tests/vbnc_test.rs b/pallets/vtoken-voting/src/tests/vbnc_test.rs new file mode 100644 index 000000000..ebf45665e --- /dev/null +++ b/pallets/vtoken-voting/src/tests/vbnc_test.rs @@ -0,0 +1,841 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . + +// Ensure we're `no_std` when compiling for Wasm. +use crate::{mock::*, *}; +use bifrost_primitives::currency::VPHA; +use frame_support::{ + assert_noop, assert_ok, + traits::{ + fungibles::Inspect, + tokens::{Fortitude::Polite, Preservation::Expendable}, + }, +}; + +const TOKENS: &[CurrencyId] = if cfg!(feature = "polkadot") { &[VBNC] } else { &[] }; + +fn aye(amount: Balance, conviction: u8) -> AccountVote { + let vote = Vote { aye: true, conviction: conviction.try_into().unwrap() }; + AccountVote::Standard { vote, balance: amount } +} + +fn nay(amount: Balance, conviction: u8) -> AccountVote { + let vote = Vote { aye: false, conviction: conviction.try_into().unwrap() }; + AccountVote::Standard { vote, balance: amount } +} + +fn tally(vtoken: CurrencyId, poll_index: u32) -> TallyOf { + VtokenVoting::ensure_referendum_ongoing(vtoken, poll_index) + .expect("No poll") + .tally +} + +fn usable_balance(vtoken: CurrencyId, who: &AccountId) -> Balance { + Tokens::reducible_balance(vtoken, who, Expendable, Polite) +} + +#[test] +fn basic_voting_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index, + aye(2, 5) + )); + assert_eq!(tally(vtoken, poll_index), Tally::from_parts(20, 0, 4)); + System::assert_last_event(RuntimeEvent::VtokenVoting(Event::Voted { + who: ALICE, + vtoken, + poll_index, + token_vote: aye(4, 5), + delegator_vote: aye(200, 0), + })); + + assert_ok!(VtokenVoting::try_remove_vote(&ALICE, vtoken, poll_index, UnvoteScope::Any)); + assert_eq!(tally(vtoken, poll_index), Tally::from_parts(0, 0, 0)); + + assert_ok!(VtokenVoting::update_lock(&ALICE, vtoken)); + assert_eq!(usable_balance(vtoken, &ALICE), 10); + }); + } +} + +#[test] +fn voting_balance_gets_locked() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index, + nay(10, 0) + )); + assert_eq!(tally(vtoken, poll_index), Tally::from_parts(0, 2, 0)); + assert_eq!(usable_balance(vtoken, &ALICE), 0); + + assert_ok!(VtokenVoting::try_remove_vote(&ALICE, vtoken, poll_index, UnvoteScope::Any)); + assert_eq!(tally(vtoken, poll_index), Tally::from_parts(0, 0, 0)); + + assert_ok!(VtokenVoting::update_lock(&ALICE, vtoken)); + assert_eq!(usable_balance(vtoken, &ALICE), 10); + }); + } +} + +#[test] +fn successful_but_zero_conviction_vote_balance_can_be_unlocked() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index, + aye(1, 1) + )); + assert_eq!(usable_balance(vtoken, &ALICE), 9); + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index, + aye(3, 1) + )); + assert_eq!(usable_balance(vtoken, &ALICE), 7); + + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(BOB), + vtoken, + poll_index, + nay(20, 0) + )); + assert_eq!(usable_balance(vtoken, &BOB), 0); + + assert_ok!(VtokenVoting::set_vote_locking_period(RuntimeOrigin::root(), vtoken, 10)); + assert_ok!(VtokenVoting::set_referendum_status( + RuntimeOrigin::root(), + vtoken, + poll_index, + ReferendumInfoOf::::Completed(3), + )); + + assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(BOB), vtoken, poll_index)); + assert_eq!(usable_balance(vtoken, &BOB), 20); + + RelaychainDataProvider::set_block_number(13); + assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, poll_index)); + assert_eq!(usable_balance(vtoken, &ALICE), 10); + }); + } +} + +#[test] +fn unsuccessful_conviction_vote_balance_can_be_unlocked() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + 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::vote( + RuntimeOrigin::signed(BOB), + vtoken, + poll_index, + nay(20, 0) + )); + + assert_ok!(VtokenVoting::set_referendum_status( + RuntimeOrigin::root(), + vtoken, + 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)); + assert_eq!(usable_balance(vtoken, &ALICE), 10); + }); + } +} + +#[test] +fn ensure_balance_after_unlock() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + let poll_index_2 = 4; + 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(10, 1) + )); + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index_2, + aye(10, 5) + )); + + assert_ok!(VtokenVoting::set_referendum_status( + RuntimeOrigin::root(), + vtoken, + poll_index, + ReferendumInfoOf::::Completed(3), + )); + RelaychainDataProvider::set_block_number(13); + assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, poll_index)); + assert_eq!(usable_balance(vtoken, &ALICE), 0); + assert_eq!(Tokens::accounts(&ALICE, vtoken).frozen, 10); + assert_eq!(VotingFor::::get(&ALICE).locked_balance(), 10); + }); + } +} + +#[test] +fn ensure_comprehensive_balance_after_unlock() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + let poll_index_2 = 4; + let poll_index_3 = 5; + 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(2, 1) + )); + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index_2, + aye(1, 5) + )); + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index_3, + aye(2, 5) + )); + + assert_ok!(VtokenVoting::set_referendum_status( + RuntimeOrigin::root(), + vtoken, + poll_index, + ReferendumInfoOf::::Completed(3), + )); + RelaychainDataProvider::set_block_number(13); + assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, poll_index)); + assert_eq!(usable_balance(vtoken, &ALICE), 8); + assert_eq!(Tokens::accounts(&ALICE, vtoken).frozen, 2); + assert_eq!(VotingFor::::get(&ALICE).locked_balance(), 2); + + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index_2, + aye(10, 5) + )); + + assert_eq!(usable_balance(vtoken, &ALICE), 0); + assert_eq!(Tokens::accounts(&ALICE, vtoken).frozen, 10); + assert_eq!(VotingFor::::get(&ALICE).locked_balance(), 10); + }); + } +} + +#[test] +fn successful_conviction_vote_balance_stays_locked_for_correct_time() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + 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), + vtoken, + poll_index, + aye(10, i as u8) + )); + } + assert_ok!(VtokenVoting::set_referendum_status( + RuntimeOrigin::root(), + vtoken, + 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)); + } + for i in 1..=5 { + assert_ok!(VtokenVoting::update_lock(&i, vtoken)); + assert_eq!(usable_balance(vtoken, &i), 10 * i as u128); + } + }); + } +} + +#[test] +fn lock_amalgamation_valid_with_multiple_removed_votes() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, 0, aye(5, 1))); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 5),]) + .unwrap() + ); + + assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, 1, aye(10, 1))); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 10),]) + .unwrap() + ); + + assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, 1, aye(5, 1))); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 5),]) + .unwrap() + ); + assert_eq!(usable_balance(vtoken, &ALICE), 5); + + assert_ok!(VtokenVoting::vote(RuntimeOrigin::signed(ALICE), vtoken, 2, aye(10, 2))); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 10),]) + .unwrap() + ); + + 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), + )); + + let locking_period = 10; + assert_ok!(VtokenVoting::set_vote_locking_period( + RuntimeOrigin::root(), + vtoken, + locking_period, + )); + assert_eq!(VoteLockingPeriod::::get(vtoken), Some(10)); + + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 10),]) + .unwrap() + ); + + RelaychainDataProvider::set_block_number(10); + assert_noop!( + VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 0), + Error::::NoPermissionYet + ); + assert_eq!(VotingFor::::get(&ALICE).locked_balance(), 10); + assert_eq!(usable_balance(vtoken, &ALICE), 0); + + RelaychainDataProvider::set_block_number(11); + assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 0)); + assert_eq!(VotingFor::::get(&ALICE).locked_balance(), 10); + assert_eq!(usable_balance(vtoken, &ALICE), 0); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 10),]) + .unwrap() + ); + + RelaychainDataProvider::set_block_number(11); + assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 1)); + assert_eq!(usable_balance(vtoken, &ALICE), 0); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 10)]) + .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::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![]).unwrap() + ); + }); + } +} + +#[test] +fn removed_votes_when_referendum_killed() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + 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::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), + )); + + 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::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 10),]) + .unwrap() + ); + + assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 0)); + assert_eq!(usable_balance(vtoken, &ALICE), 0); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 10),]) + .unwrap() + ); + + assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 1)); + assert_eq!(usable_balance(vtoken, &ALICE), 5); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![(vtoken, 5)]) + .unwrap() + ); + + assert_ok!(VtokenVoting::unlock(RuntimeOrigin::signed(ALICE), vtoken, 2)); + assert_eq!(usable_balance(vtoken, &ALICE), 10); + assert_eq!( + ClassLocksFor::::get(&ALICE), + BoundedVec::<(CurrencyId, u128), ConstU32<256>>::try_from(vec![]).unwrap() + ); + }); + } +} + +#[test] +fn errors_with_vote_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + assert_noop!( + VtokenVoting::vote(RuntimeOrigin::signed(1), VPHA, 0, aye(10, 0)), + Error::::VTokenNotSupport + ); + assert_noop!( + VtokenVoting::vote(RuntimeOrigin::signed(1), vtoken, 3, aye(11, 0)), + Error::::InsufficientFunds + ); + + for poll_index in 0..256 { + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(1), + vtoken, + poll_index, + aye(10, 0) + )); + } + assert_noop!( + VtokenVoting::vote(RuntimeOrigin::signed(1), vtoken, 256, aye(10, 0)), + Error::::MaxVotesReached + ); + }); + } +} + +#[test] +fn kill_referendum_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index, + aye(5, 1) + )); + assert_ok!(VtokenVoting::set_referendum_status( + RuntimeOrigin::root(), + vtoken, + poll_index, + ReferendumInfoOf::::Completed(1), + )); + assert_ok!(VtokenVoting::kill_referendum(RuntimeOrigin::root(), vtoken, poll_index)); + System::assert_last_event(RuntimeEvent::VtokenVoting(Event::ReferendumKilled { + vtoken, + poll_index, + })); + }); + } +} + +#[test] +fn kill_referendum_with_origin_signed_fails() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + + assert_ok!(VtokenVoting::vote( + RuntimeOrigin::signed(ALICE), + vtoken, + poll_index, + aye(5, 1) + )); + assert_ok!(VtokenVoting::set_referendum_status( + RuntimeOrigin::root(), + vtoken, + poll_index, + ReferendumInfoOf::::Completed(1), + )); + assert_noop!( + VtokenVoting::kill_referendum(RuntimeOrigin::signed(ALICE), vtoken, poll_index), + DispatchError::BadOrigin + ); + }); + } +} + +#[test] +fn compute_delegator_total_vote_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(10, 0)), + Ok(aye(10, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(2, 1)), + Ok(aye(20, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(2, 2)), + Ok(aye(40, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(2, 3)), + Ok(aye(60, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(2, 4)), + Ok(aye(80, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(2, 5)), + Ok(aye(100, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(2, 6)), + Ok(aye(120, 0)) + ); + + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, nay(10, 0)), + Ok(nay(10, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, nay(2, 1)), + Ok(nay(20, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, nay(2, 2)), + Ok(nay(40, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, nay(2, 3)), + Ok(nay(60, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, nay(2, 4)), + Ok(nay(80, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, nay(2, 5)), + Ok(nay(100, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, nay(2, 6)), + Ok(nay(120, 0)) + ); + + SimpleVTokenSupplyProvider::set_token_supply(10_000_000); + assert_eq!(VtokenVoting::vote_cap(vtoken), Ok(1_000_000)); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(1_000_000, 0)), + Ok(aye(1_000_000, 0)) + ); + for i in 1..=6_u8 { + assert_eq!( + VtokenVoting::compute_delegator_total_vote( + vtoken, + aye(10_000_000 * i as Balance, 0) + ), + Ok(aye(1_000_000, i)) + ); + } + + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(100_000, 1)), + Ok(aye(1_000_000, 0)) + ); + for i in 1..=6_u8 { + assert_eq!( + VtokenVoting::compute_delegator_total_vote( + vtoken, + aye(1_000_000 * i as Balance, 1) + ), + Ok(aye(1_000_000, i)) + ); + } + assert_noop!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(6_000_006, 1)), + Error::::InsufficientFunds + ); + + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(50_000, 2)), + Ok(aye(1_000_000, 0)) + ); + for i in 1..=6_u8 { + assert_eq!( + VtokenVoting::compute_delegator_total_vote( + vtoken, + aye(500_000 * i as Balance, 2) + ), + Ok(aye(1_000_000, i)) + ); + } + assert_noop!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(3_000_003, 2)), + Error::::InsufficientFunds + ); + + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(33_333, 3)), + Ok(aye(999_990, 0)) + ); + for i in 1..=6_u8 { + assert_eq!( + VtokenVoting::compute_delegator_total_vote( + vtoken, + aye(333_333 * i as Balance, 3) + ), + Ok(aye(999_999, i)) + ); + } + assert_noop!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(2_000_002, 3)), + Error::::InsufficientFunds + ); + + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(25_000, 4)), + Ok(aye(1_000_000, 0)) + ); + for i in 1..=6_u8 { + assert_eq!( + VtokenVoting::compute_delegator_total_vote( + vtoken, + aye(250_000 * i as Balance, 4) + ), + Ok(aye(1_000_000, i)) + ); + } + assert_noop!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(1_500_002, 4)), + Error::::InsufficientFunds + ); + + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(20_000, 5)), + Ok(aye(1_000_000, 0)) + ); + for i in 1..=6_u8 { + assert_eq!( + VtokenVoting::compute_delegator_total_vote( + vtoken, + aye(200_000 * i as Balance, 5) + ), + Ok(aye(1_000_000, i)) + ); + } + assert_noop!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(1_200_002, 5)), + Error::::InsufficientFunds + ); + + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(16_666, 6)), + Ok(aye(999_960, 0)) + ); + for i in 1..=6_u8 { + assert_eq!( + VtokenVoting::compute_delegator_total_vote( + vtoken, + aye(166_666 * i as Balance, 6) + ), + Ok(aye(999_996, i)) + ); + } + assert_noop!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(1_000_001, 6)), + Error::::InsufficientFunds + ); + }); + } +} + +#[test] +fn compute_delegator_total_vote_with_low_value_will_loss() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, aye(9, 0)), + Ok(aye(0, 0)) + ); + assert_eq!( + VtokenVoting::compute_delegator_total_vote(vtoken, nay(9, 0)), + Ok(nay(0, 0)) + ); + }); + } +} + +#[test] +fn allocate_delegator_votes_works() { + for &vtoken in TOKENS { + new_test_ext().execute_with(|| { + let poll_index = 3; + + for conviction in 0..=6 { + let vote = aye(5e9 as Balance, conviction); + let delegator_votes = + VtokenVoting::allocate_delegator_votes(vtoken, poll_index, vote); + assert_eq!( + delegator_votes, + Ok(vec![(0, aye(4294967295, conviction)), (1, aye(705032705, conviction))]) + ); + assert_eq!( + delegator_votes + .unwrap() + .into_iter() + .map(|(_derivative_index, vote)| vote) + .fold(aye(0, conviction), |mut acc, vote| { + let _ = acc.checked_add(vote); + acc + },), + vote + ); + } + + for conviction in 0..=6 { + let vote = aye(3e10 as Balance, conviction); + let delegator_votes = + VtokenVoting::allocate_delegator_votes(vtoken, poll_index, vote); + assert_eq!( + delegator_votes, + Ok(vec![ + (0, aye(4294967295, conviction)), + (1, aye(4294967295, conviction)), + (2, aye(4294967295, conviction)), + (3, aye(4294967295, conviction)), + (4, aye(4294967295, conviction)), + (5, aye(4294967295, conviction)), + (10, aye(4230196230, conviction)) + ]) + ); + assert_eq!( + delegator_votes + .unwrap() + .into_iter() + .map(|(_derivative_index, vote)| vote) + .fold(aye(0, conviction), |mut acc, vote| { + let _ = acc.checked_add(vote); + acc + },), + vote + ); + } + }); + } +} diff --git a/pallets/vtoken-voting/src/traits.rs b/pallets/vtoken-voting/src/traits.rs new file mode 100644 index 000000000..30fe18202 --- /dev/null +++ b/pallets/vtoken-voting/src/traits.rs @@ -0,0 +1,142 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 crate::{AccountVote, PollClass, PollIndex, *}; +use bifrost_primitives::DerivativeIndex; +use sp_std::vec::Vec; + +/// Abstraction over a voting agent for a certain parachain. +/// +/// This trait defines the operations a voting agent should implement for handling votes and +/// delegator-related actions within a certain parachain's voting system. +pub trait VotingAgent { + /// Retrieves the voting token (`vtoken`) associated with the agent. + /// + /// This function should return the currency ID representing the token used for voting. + fn vtoken(&self) -> CurrencyIdOf; + + /// Retrieves the location of the agent. + /// + /// This function returns the location associated with the agent, which could be used to + /// identify the origin or context within the parachain system. + fn location(&self) -> Location; + + /// Delegate a vote on behalf of a user. + /// + /// - `who`: The account for which the vote is being delegated. + /// - `vtoken`: The token used for voting. + /// - `poll_index`: The index of the poll on which the vote is being cast. + /// - `submitted`: A flag indicating whether the vote was already submitted. + /// - `new_delegator_votes`: A vector of delegator votes, represented by the index of the + /// derivative and the account's vote. + /// - `maybe_old_vote`: An optional tuple representing the old vote and its associated balance, + /// in case an old vote exists. + /// + /// This function handles the delegation of votes for the specified account and updates the + /// voting state accordingly. It returns a `DispatchResult` to indicate success or failure. + fn delegate_vote( + &self, + who: AccountIdOf, + vtoken: CurrencyIdOf, + poll_index: PollIndex, + submitted: bool, + new_delegator_votes: Vec<(DerivativeIndex, AccountVote>)>, + maybe_old_vote: Option<(AccountVote>, BalanceOf)>, + ) -> DispatchResult; + + /// Encode the call data for voting. + /// + /// - `new_delegator_votes`: A vector of new delegator votes to be encoded. + /// - `poll_index`: The index of the poll. + /// - `derivative_index`: The index of the derivative (delegator) involved in the voting + /// process. + /// + /// This function encodes the call for a vote delegation action, returning the byte-encoded + /// representation of the call data. In case of errors during encoding, an `Error` is + /// returned. + fn vote_call_encode( + &self, + new_delegator_votes: Vec<(DerivativeIndex, AccountVote>)>, + poll_index: PollIndex, + derivative_index: DerivativeIndex, + ) -> Result, Error>; + + /// Remove a delegator's vote. + /// + /// - `vtoken`: The token associated with the vote. + /// - `poll_index`: The index of the poll from which the vote is being removed. + /// - `class`: The class/type of the poll. + /// - `derivative_index`: The index of the delegator's derivative whose vote is being removed. + /// + /// This function handles the removal of a delegator's vote for the specified poll and class, + /// returning a `DispatchResult` to indicate success or failure. + fn delegate_remove_delegator_vote( + &self, + vtoken: CurrencyIdOf, + poll_index: PollIndex, + class: PollClass, + derivative_index: DerivativeIndex, + ) -> DispatchResult; + + /// Encode the call data for removing a delegator's vote. + /// + /// - `class`: The class/type of the poll. + /// - `poll_index`: The index of the poll from which the vote is being removed. + /// - `derivative_index`: The index of the delegator's derivative involved in the vote removal. + /// + /// This function encodes the call for removing a delegator's vote, returning the byte-encoded + /// representation of the call data. In case of errors during encoding, an `Error` is + /// returned. + fn remove_delegator_vote_call_encode( + &self, + class: PollClass, + poll_index: PollIndex, + derivative_index: DerivativeIndex, + ) -> Result, Error>; +} + +/// Trait defining calls related to conviction voting mechanisms. +pub trait ConvictionVotingCall { + /// Casts a vote in a poll. + /// + /// - `poll_index`: The index of the poll where the vote is being cast. + /// - `vote`: The vote being cast, which includes the voter's balance and conviction. + fn vote(poll_index: PollIndex, vote: AccountVote>) -> Self; + + /// Removes a vote from a poll. + /// + /// - `class`: Optionally specify the class of the poll (if applicable). + /// - `poll_index`: The index of the poll from which the vote is being removed. + fn remove_vote(class: Option, poll_index: PollIndex) -> Self; +} + +/// Trait defining utility calls for handling batch or derivative actions. +pub trait UtilityCall { + /// Executes a call as a derivative of another account. + /// + /// - `derivative_index`: The index representing a specific derivative account (usually for + /// staking or delegation purposes). + /// - `call`: The call that will be executed by the derivative account. + fn as_derivative(derivative_index: DerivativeIndex, call: Call) -> Call; + + /// Executes a batch of calls where all must succeed or none will be executed. + /// + /// - `calls`: A vector of calls that will be executed in batch. If any call fails, none of the + /// calls will be applied. + fn batch_all(calls: Vec) -> Call; +} diff --git a/pallets/vtoken-voting/src/vote.rs b/pallets/vtoken-voting/src/vote.rs index a9a9b1b86..f34984d7c 100644 --- a/pallets/vtoken-voting/src/vote.rs +++ b/pallets/vtoken-voting/src/vote.rs @@ -357,8 +357,8 @@ where #[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[scale_info(skip_type_params(MaxVotes))] #[codec(mel_bound( -Balance: MaxEncodedLen, AccountId: MaxEncodedLen, BlockNumber: MaxEncodedLen, -PollIndex: MaxEncodedLen, + Balance: MaxEncodedLen, AccountId: MaxEncodedLen, BlockNumber: MaxEncodedLen, + PollIndex: MaxEncodedLen, ))] pub enum Voting where diff --git a/primitives/src/traits.rs b/primitives/src/traits.rs index c6cf28de0..1d9f630bc 100644 --- a/primitives/src/traits.rs +++ b/primitives/src/traits.rs @@ -387,7 +387,7 @@ where } } -pub trait DerivativeAccountHandler { +pub trait DerivativeAccountHandler { fn check_derivative_index_exists(token: CurrencyId, derivative_index: DerivativeIndex) -> bool; fn get_multilocation( @@ -395,6 +395,8 @@ pub trait DerivativeAccountHandler { derivative_index: DerivativeIndex, ) -> Option; + fn get_account_id(token: CurrencyId, derivative_index: DerivativeIndex) -> Option; + fn get_stake_info( token: CurrencyId, derivative_index: DerivativeIndex, diff --git a/runtime/bifrost-kusama/src/lib.rs b/runtime/bifrost-kusama/src/lib.rs index 2a71076ee..19d700739 100644 --- a/runtime/bifrost-kusama/src/lib.rs +++ b/runtime/bifrost-kusama/src/lib.rs @@ -1349,6 +1349,7 @@ impl bifrost_vtoken_voting::Config for Runtime { type QueryTimeout = QueryTimeout; type ReferendumCheckInterval = ReferendumCheckInterval; type WeightInfo = weights::bifrost_vtoken_voting::BifrostWeight; + type PalletsOrigin = OriginCaller; } // Bifrost modules end diff --git a/runtime/bifrost-polkadot/src/lib.rs b/runtime/bifrost-polkadot/src/lib.rs index f63de4618..ee97874bf 100644 --- a/runtime/bifrost-polkadot/src/lib.rs +++ b/runtime/bifrost-polkadot/src/lib.rs @@ -1261,6 +1261,7 @@ impl bifrost_vtoken_voting::Config for Runtime { type QueryTimeout = QueryTimeout; type ReferendumCheckInterval = ReferendumCheckInterval; type WeightInfo = weights::bifrost_vtoken_voting::BifrostWeight; + type PalletsOrigin = OriginCaller; } // Bifrost modules end From 8ba3c31882b77437dce2e3f1adec898ddbb23fec Mon Sep 17 00:00:00 2001 From: NingBo Wang <2536935847@qq.com> Date: Tue, 8 Oct 2024 13:42:32 +0800 Subject: [PATCH 14/30] Fix try-runtime (#1451) --- pallets/asset-registry/src/migrations/v1.rs | 17 ++++++++++++++--- pallets/flexible-fee/src/lib.rs | 4 ++++ runtime/bifrost-kusama/src/lib.rs | 1 + runtime/bifrost-polkadot/src/lib.rs | 1 + 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/pallets/asset-registry/src/migrations/v1.rs b/pallets/asset-registry/src/migrations/v1.rs index 99a7481a2..b74b62711 100644 --- a/pallets/asset-registry/src/migrations/v1.rs +++ b/pallets/asset-registry/src/migrations/v1.rs @@ -27,10 +27,11 @@ pub struct MigrateToV1(sp_std::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV1 { fn on_runtime_upgrade() -> frame_support::weights::Weight { // Check the storage version - let onchain_version = Pallet::::on_chain_storage_version(); + let in_code_version = Pallet::::in_code_storage_version(); + let on_chain_version = Pallet::::on_chain_storage_version(); // Transform storage values // We transform the storage values from the old into the new format. - if onchain_version < 1 { + if on_chain_version == 0 && in_code_version == 1 { let mut count = 0; log::info!(target: LOG_TARGET, "Start to migrate RegisterWhiteList storage..."); @@ -59,7 +60,7 @@ impl OnRuntimeUpgrade for MigrateToV1 { } // Update the storage version - StorageVersion::new(1).put::>(); + in_code_version.put::>(); // Return the consumed weight Weight::from(T::DbWeight::get().reads_writes(count as u64 + 1, count as u64 + 1)) @@ -71,6 +72,8 @@ impl OnRuntimeUpgrade for MigrateToV1 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, TryRuntimeError> { + ensure!(Pallet::::on_chain_storage_version() == 0, "must upgrade linearly"); + ensure!(Pallet::::in_code_storage_version() == 1, "must upgrade linearly"); let currency_id_to_locations_count = CurrencyIdToLocations::::iter().count(); log::info!(target: LOG_TARGET, "CurrencyIdToLocations pre-migrate storage count: {:?}", currency_id_to_locations_count); @@ -85,6 +88,14 @@ impl OnRuntimeUpgrade for MigrateToV1 { #[cfg(feature = "try-runtime")] fn post_upgrade(cnt: Vec) -> Result<(), TryRuntimeError> { + let in_code_version = Pallet::::in_code_storage_version(); + let on_chain_version = Pallet::::on_chain_storage_version(); + ensure!(in_code_version == 1, "must_upgrade"); + ensure!( + in_code_version == on_chain_version, + "after migration, the in_code_version and on_chain_version should be the same" + ); + let (old_currency_id_to_locations_count, old_location_to_currency_ids_count): (u64, u64) = Decode::decode(&mut cnt.as_slice()).expect( "the state parameter should be something that was generated by pre_upgrade", diff --git a/pallets/flexible-fee/src/lib.rs b/pallets/flexible-fee/src/lib.rs index 2b585be1f..48a065209 100644 --- a/pallets/flexible-fee/src/lib.rs +++ b/pallets/flexible-fee/src/lib.rs @@ -158,6 +158,9 @@ pub mod pallet { }, } + /// The current storage version, we set to 2 our new version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); + /// Universal fee currency order list for all users #[pallet::storage] pub type UniversalFeeCurrencyOrderList = @@ -180,6 +183,7 @@ pub mod pallet { >; #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); #[pallet::error] diff --git a/runtime/bifrost-kusama/src/lib.rs b/runtime/bifrost-kusama/src/lib.rs index 19d700739..47a399465 100644 --- a/runtime/bifrost-kusama/src/lib.rs +++ b/runtime/bifrost-kusama/src/lib.rs @@ -1918,6 +1918,7 @@ pub mod migrations { // permanent migration, do not remove pallet_xcm::migration::MigrateToLatestXcmVersion, bifrost_cross_in_out::migrations::v3::MigrateToV2, + bifrost_asset_registry::migrations::v1::MigrateToV1, SystemMakerClearPalletId, frame_support::migrations::RemovePallet, ); diff --git a/runtime/bifrost-polkadot/src/lib.rs b/runtime/bifrost-polkadot/src/lib.rs index ee97874bf..fcbc36dbc 100644 --- a/runtime/bifrost-polkadot/src/lib.rs +++ b/runtime/bifrost-polkadot/src/lib.rs @@ -1832,6 +1832,7 @@ pub mod migrations { // permanent migration, do not remove pallet_xcm::migration::MigrateToLatestXcmVersion, bifrost_cross_in_out::migrations::v3::MigrateToV2, + bifrost_asset_registry::migrations::v1::MigrateToV1, frame_support::migrations::RemovePallet, ); } From 81f5c6dc5200a34012b517220ea1eeaf4af9008f Mon Sep 17 00:00:00 2001 From: NingBo Wang <2536935847@qq.com> Date: Thu, 10 Oct 2024 23:09:42 +0800 Subject: [PATCH 15/30] Slpx add evm create (#1454) * Fix try-runtime * Slpx add evm create order --- pallets/slp/src/tests/phala_tests.rs | 37 +++++++++ pallets/slpx/src/lib.rs | 118 +++++++++++++++++++++++---- pallets/slpx/src/migration.rs | 95 ++++++++++++++++++++- pallets/slpx/src/tests.rs | 2 +- pallets/slpx/src/types.rs | 2 + primitives/src/xcm.rs | 7 ++ runtime/bifrost-kusama/src/lib.rs | 1 + runtime/bifrost-polkadot/src/lib.rs | 1 + 8 files changed, 246 insertions(+), 17 deletions(-) diff --git a/pallets/slp/src/tests/phala_tests.rs b/pallets/slp/src/tests/phala_tests.rs index f5a930017..1f8589918 100644 --- a/pallets/slp/src/tests/phala_tests.rs +++ b/pallets/slp/src/tests/phala_tests.rs @@ -28,6 +28,7 @@ use crate::{ use bifrost_primitives::currency::{PHA, VPHA}; use frame_support::{assert_noop, assert_ok, PalletId}; use polkadot_parachain_primitives::primitives::Sibling; +use sp_core::crypto::Ss58Codec; use sp_runtime::traits::AccountIdConversion; // parents 0 means vault, parents 1 means stake_pool @@ -1460,3 +1461,39 @@ fn phala_convert_asset_works() { ); }); } + +#[test] +fn generate_derivative_account() { + ExtBuilder::default().build().execute_with(|| { + // PublicKey: 0x70617261d1070000000000000000000000000000000000000000000000000000 + // AccountId(42): 5Ec4AhPV91i9yNuiWuNunPf6AQCYDhFTTA4G5QCbtqYApH9E + let sovereign_account = >::into_account_truncating( + &ParaId::from(2001), + ); + println!("sovereign_account: {:?}", sovereign_account); + // PublicKey: 0x5a53736d8e96f1c007cf0d630acf5209b20611617af23ce924c8e25328eb5d28 + // AccountId(42): 5E78xTBiaN3nAGYtcNnqTJQJqYAkSDGggKqaDfpNsKyPpbcb + let sovereign_account_derivative_0 = + Utility::derivative_account_id(sovereign_account.clone(), 0); + assert_eq!( + sovereign_account_derivative_0, + AccountId::from_ss58check("5E78xTBiaN3nAGYtcNnqTJQJqYAkSDGggKqaDfpNsKyPpbcb").unwrap() + ); + // PublicKey: 0xf1c5ca0368e7a567945a59aaea92b9be1e0794fe5e077d017462b7ce8fc1ed7c + // AccountId(42): 5HXi9pzWnTQzk7VKzY6VQn92KfWCcA5NbSm53uKHrYU1VsjP + let sovereign_account_derivative_1 = + Utility::derivative_account_id(sovereign_account.clone(), 1); + assert_eq!( + sovereign_account_derivative_1, + AccountId::from_ss58check("5HXi9pzWnTQzk7VKzY6VQn92KfWCcA5NbSm53uKHrYU1VsjP").unwrap() + ); + // PublicKey: 0x1e365411cfd0b0f78466be433a2ec5f7d545c5e28cb2e9a31ce97d4a28447dfc + // AccountId(42): 5CkKS3YMx64TguUYrMERc5Bn6Mn2aKMUkcozUFREQDgHS3Tv + let sovereign_account_derivative_2 = + Utility::derivative_account_id(sovereign_account.clone(), 2); + assert_eq!( + sovereign_account_derivative_2, + AccountId::from_ss58check("5CkKS3YMx64TguUYrMERc5Bn6Mn2aKMUkcozUFREQDgHS3Tv").unwrap() + ); + }) +} diff --git a/pallets/slpx/src/lib.rs b/pallets/slpx/src/lib.rs index a51e96c89..407832e2a 100644 --- a/pallets/slpx/src/lib.rs +++ b/pallets/slpx/src/lib.rs @@ -25,9 +25,9 @@ use crate::types::{ use bifrost_asset_registry::AssetMetadata; use bifrost_primitives::{ currency::{BNC, MOVR, VFIL}, - AstarChainId, Balance, BifrostKusamaChainId, CurrencyId, CurrencyIdMapping, HydrationChainId, - InterlayChainId, MantaChainId, RedeemType, SlpxOperator, TokenInfo, VtokenMintingInterface, - GLMR, + AstarChainId, AstarEvmChainId, Balance, BifrostKusamaChainId, CurrencyId, CurrencyIdMapping, + HydrationChainId, InterlayChainId, MantaChainId, MoonbeamEvmChainId, MoonriverEvmChainId, + RedeemType, SlpxOperator, TokenInfo, VtokenMintingInterface, GLMR, }; use cumulus_primitives_core::ParaId; use ethereum::TransactionAction; @@ -82,7 +82,7 @@ pub mod pallet { }; use frame_system::ensure_root; - const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -351,6 +351,8 @@ pub mod pallet { Self::do_create_order( source_chain_caller, + Default::default(), + None, bifrost_chain_caller, currency_id, Default::default(), @@ -390,6 +392,8 @@ pub mod pallet { Self::do_create_order( source_chain_caller, + Default::default(), + None, bifrost_chain_caller, vtoken_id, Default::default(), @@ -627,6 +631,8 @@ pub mod pallet { ensure_root(origin)?; Self::do_create_order( source_chain_caller, + Default::default(), + None, bifrost_chain_caller, currency_id, Default::default(), @@ -658,6 +664,8 @@ pub mod pallet { Self::do_create_order( source_chain_caller, + Default::default(), + None, bifrost_chain_caller, currency_id, Default::default(), @@ -667,6 +675,54 @@ pub mod pallet { ) } + /// EVM create order + /// Parameters: + /// - `source_chain_caller`: The caller of the source chain + /// - `source_chain_id`: The source chain id + /// - `source_chain_block_number`: The source chain block number + /// - `currency_id`: The currency id of the token + /// - `currency_amount`: The currency amount of the token + /// - `send_to`: The target chain to transfer the token to + /// - `remark`: The remark of the order + /// - `channel_id`: The channel id of the order + #[pallet::call_index(14)] + #[pallet::weight(::WeightInfo::mint())] + pub fn evm_create_order( + origin: OriginFor, + source_chain_caller: H160, + source_chain_id: u64, + source_chain_block_number: u128, + currency_id: CurrencyId, + currency_amount: BalanceOf, + send_to: TargetChain, + remark: BoundedVec>, + channel_id: u32, + ) -> DispatchResultWithPostInfo { + let bifrost_chain_caller = ensure_signed(origin)?; + + let support_chain = + Self::match_source_chain_id(source_chain_id).ok_or(Error::::Unsupported)?; + + ensure!( + WhitelistAccountId::::get(support_chain).contains(&bifrost_chain_caller), + Error::::AccountNotFound + ); + + let source_chain_caller = OrderCaller::Evm(source_chain_caller); + + Self::do_create_order( + source_chain_caller, + source_chain_id, + Some(source_chain_block_number), + bifrost_chain_caller, + currency_id, + currency_amount, + remark, + channel_id, + send_to, + ) + } + // TODO: Substrate user create order // #[pallet::call_index(14)] // #[pallet::weight(::WeightInfo::mint())] @@ -696,6 +752,18 @@ pub mod pallet { } impl Pallet { + fn match_source_chain_id(source_chain_id: u64) -> Option { + if source_chain_id == AstarEvmChainId::get() { + Some(SupportChain::Astar) + } else if source_chain_id == MoonriverEvmChainId::get() || + source_chain_id == MoonbeamEvmChainId::get() + { + Some(SupportChain::Moonbeam) + } else { + None + } + } + /// According to currency_id, return the order type fn order_type(currency_id: CurrencyId) -> Result> { match currency_id { @@ -753,6 +821,8 @@ impl Pallet { fn do_create_order( source_chain_caller: OrderCaller, + source_chain_id: u64, + source_chain_block_number: Option, bifrost_chain_caller: T::AccountId, currency_id: CurrencyId, currency_amount: BalanceOf, @@ -769,6 +839,8 @@ impl Pallet { currency_amount, remark, source_chain_caller, + source_chain_id, + source_chain_block_number, bifrost_chain_caller, derivative_account, target_chain, @@ -897,9 +969,9 @@ impl Pallet { /// Charge an execution fee fn charge_execution_fee( currency_id: CurrencyIdOf, + currency_amount: BalanceOf, evm_caller_account_id: &AccountIdOf, ) -> Result, DispatchError> { - let free_balance = T::MultiCurrency::free_balance(currency_id, evm_caller_account_id); let execution_fee = ExecutionFee::::get(currency_id) .unwrap_or_else(|| Self::get_default_fee(currency_id)); @@ -910,8 +982,9 @@ impl Pallet { execution_fee, )?; - let balance_exclude_fee = - free_balance.checked_sub(&execution_fee).ok_or(Error::::FreeBalanceTooLow)?; + let balance_exclude_fee = currency_amount + .checked_sub(&execution_fee) + .ok_or(Error::::FreeBalanceTooLow)?; Ok(balance_exclude_fee) } @@ -1016,11 +1089,24 @@ impl Pallet { pub fn handle_order( order: &Order, CurrencyIdOf, BalanceOf, BlockNumberFor>, ) -> DispatchResult { - let currency_amount = - Self::charge_execution_fee(order.currency_id, &order.derivative_account) - .map_err(|_| Error::::ErrorChargeFee)?; + let currency_amount = Self::charge_execution_fee( + order.currency_id, + order.currency_amount, + &order.derivative_account, + ) + .map_err(|_| Error::::ErrorChargeFee)?; match order.order_type { OrderType::Mint => { + let vtoken_id = + order.currency_id.to_vtoken().map_err(|_| Error::::ErrorConvertVtoken)?; + + let vtoken_amount = T::VtokenMintingInterface::token_to_vtoken( + order.currency_id, + vtoken_id, + currency_amount, + ) + .map_err(|_| Error::::ErrorVtokenMiting)?; + T::VtokenMintingInterface::mint( order.derivative_account.clone(), order.currency_id, @@ -1029,10 +1115,6 @@ impl Pallet { Some(order.channel_id), ) .map_err(|_| Error::::ErrorVtokenMiting)?; - let vtoken_id = - order.currency_id.to_vtoken().map_err(|_| Error::::ErrorConvertVtoken)?; - let vtoken_amount = - T::MultiCurrency::free_balance(vtoken_id, &order.derivative_account); Self::transfer_to( order.derivative_account.clone(), @@ -1079,11 +1161,19 @@ impl Pallet { if current_block_number - order_queue[0].create_block_number >= DelayBlock::::get() { let mut order = order_queue.remove(0); + // For compatibility with older versions if order.currency_amount == Default::default() { order.currency_amount = T::MultiCurrency::free_balance( order.currency_id, &order.derivative_account, ); + } else { + // Ensure that the currency amount is not greater than the free balance + let free_balance = T::MultiCurrency::free_balance( + order.currency_id, + &order.derivative_account, + ); + order.currency_amount = order.currency_amount.min(free_balance); } match Self::handle_order(&order) { Ok(_) => { diff --git a/pallets/slpx/src/migration.rs b/pallets/slpx/src/migration.rs index 3fabbbf81..e2c38cee2 100644 --- a/pallets/slpx/src/migration.rs +++ b/pallets/slpx/src/migration.rs @@ -106,10 +106,34 @@ mod v0 { } pub mod v1 { - use frame_support::pallet_prelude::StorageVersion; + use frame_support::pallet_prelude::{StorageVersion, ValueQuery}; use super::*; + #[derive(Encode, Decode, Clone)] + pub struct Order { + pub source_chain_caller: OrderCaller, + pub bifrost_chain_caller: AccountId, + pub derivative_account: AccountId, + pub create_block_number: BlockNumber, + pub currency_id: CurrencyId, + pub currency_amount: Balance, + pub order_type: OrderType, + pub remark: BoundedVec>, + pub target_chain: TargetChain, + pub channel_id: u32, + } + + #[storage_alias] + pub(super) type OrderQueue = StorageValue< + Pallet, + BoundedVec< + Order, CurrencyIdOf, BalanceOf, BlockNumberFor>, + ConstU32<1000>, + >, + ValueQuery, + >; + pub struct MigrateToV1(sp_std::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV1 { fn on_runtime_upgrade() -> Weight { @@ -142,12 +166,47 @@ pub mod v1 { } } +pub mod v2 { + use super::*; + use frame_support::traits::GetStorageVersion; + + pub struct MigrateToV2(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV2 { + fn on_runtime_upgrade() -> Weight { + let on_chain_storage_version = Pallet::::on_chain_storage_version(); + let in_code_storage_version = Pallet::::in_code_storage_version(); + if on_chain_storage_version == 1 && in_code_storage_version == 2 { + let weight_consumed = migrate_to_v2::(); + log::info!("Migrating slpx storage to v2"); + in_code_storage_version.put::>(); + weight_consumed.saturating_add(T::DbWeight::get().writes(1)) + } else { + log::warn!("slpx migration should be removed."); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_: Vec) -> Result<(), sp_runtime::DispatchError> { + ensure!( + Pallet::::on_chain_storage_version() == 2, + "on_chain_storage_version should be 2" + ); + ensure!( + Pallet::::in_code_storage_version() == 2, + "in_code_storage_version should be 2" + ); + Ok(()) + } + } +} + pub fn migrate_to_v1() -> Weight { let mut weight: Weight = Weight::zero(); let old_orders = v0::OrderQueue::::get(); for old_order in old_orders.into_iter() { - let order = Order { + let order = v1::Order { source_chain_caller: old_order.source_chain_caller, bifrost_chain_caller: old_order.bifrost_chain_caller, derivative_account: old_order.derivative_account, @@ -161,6 +220,38 @@ pub fn migrate_to_v1() -> Weight { channel_id: 0u32, }; + v1::OrderQueue::::mutate(|order_queue| -> DispatchResultWithPostInfo { + order_queue.try_push(order.clone()).map_err(|_| Error::::ErrorArguments)?; + Ok(().into()) + }) + .expect("BoundedVec should not overflow"); + + weight = weight.saturating_add(T::DbWeight::get().writes(1)); + } + + weight +} + +pub fn migrate_to_v2() -> Weight { + let mut weight: Weight = Weight::zero(); + + let old_order_queue = v1::OrderQueue::::take(); + for old_order in old_order_queue.into_iter() { + let order = Order { + source_chain_caller: old_order.source_chain_caller, + source_chain_id: 0, + source_chain_block_number: None, + bifrost_chain_caller: old_order.bifrost_chain_caller, + derivative_account: old_order.derivative_account, + create_block_number: old_order.create_block_number, + currency_id: old_order.currency_id, + currency_amount: old_order.currency_amount, + order_type: old_order.order_type, + remark: old_order.remark, + target_chain: old_order.target_chain, + channel_id: old_order.channel_id, + }; + OrderQueue::::mutate(|order_queue| -> DispatchResultWithPostInfo { order_queue.try_push(order.clone()).map_err(|_| Error::::ErrorArguments)?; Ok(().into()) diff --git a/pallets/slpx/src/tests.rs b/pallets/slpx/src/tests.rs index 0f4e8c824..762d56562 100644 --- a/pallets/slpx/src/tests.rs +++ b/pallets/slpx/src/tests.rs @@ -190,7 +190,7 @@ fn test_execution_fee_work() { assert_eq!(ExecutionFee::::get(CurrencyId::Token2(0)), Some(10 * 1_000_000_000)); let balance_exclude_fee = - Slpx::charge_execution_fee(CurrencyId::Token2(0), &ALICE).unwrap(); + Slpx::charge_execution_fee(CurrencyId::Token2(0), 50 * 1_000_000_000, &ALICE).unwrap(); assert_eq!(balance_exclude_fee, 40 * 1_000_000_000); assert_ok!(Slpx::set_transfer_to_fee( diff --git a/pallets/slpx/src/types.rs b/pallets/slpx/src/types.rs index e38e0568a..082ffa3b3 100644 --- a/pallets/slpx/src/types.rs +++ b/pallets/slpx/src/types.rs @@ -134,6 +134,8 @@ pub enum OrderType { #[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct Order { pub source_chain_caller: OrderCaller, + pub source_chain_id: u64, + pub source_chain_block_number: Option, pub bifrost_chain_caller: AccountId, pub derivative_account: AccountId, pub create_block_number: BlockNumber, diff --git a/primitives/src/xcm.rs b/primitives/src/xcm.rs index b6d59929c..efcb265a8 100644 --- a/primitives/src/xcm.rs +++ b/primitives/src/xcm.rs @@ -43,7 +43,14 @@ parameter_types! { pub const MoonriverChainId: u32 = 2023; pub const PhalaChainId: u32 = 2035; pub const KaruraChainId: u32 = 2000; +} + +// Evm chain id +parameter_types! { pub const EthereumChainId: u64 = 1; + pub const MoonriverEvmChainId: u64 = 1285; + pub const MoonbeamEvmChainId: u64 = 1284; + pub const AstarEvmChainId: u64 = 592; } // Location diff --git a/runtime/bifrost-kusama/src/lib.rs b/runtime/bifrost-kusama/src/lib.rs index 47a399465..01276e4dd 100644 --- a/runtime/bifrost-kusama/src/lib.rs +++ b/runtime/bifrost-kusama/src/lib.rs @@ -1919,6 +1919,7 @@ pub mod migrations { pallet_xcm::migration::MigrateToLatestXcmVersion, bifrost_cross_in_out::migrations::v3::MigrateToV2, bifrost_asset_registry::migrations::v1::MigrateToV1, + bifrost_slpx::migration::v2::MigrateToV2, SystemMakerClearPalletId, frame_support::migrations::RemovePallet, ); diff --git a/runtime/bifrost-polkadot/src/lib.rs b/runtime/bifrost-polkadot/src/lib.rs index fcbc36dbc..9bded4470 100644 --- a/runtime/bifrost-polkadot/src/lib.rs +++ b/runtime/bifrost-polkadot/src/lib.rs @@ -1833,6 +1833,7 @@ pub mod migrations { pallet_xcm::migration::MigrateToLatestXcmVersion, bifrost_cross_in_out::migrations::v3::MigrateToV2, bifrost_asset_registry::migrations::v1::MigrateToV1, + bifrost_slpx::migration::v2::MigrateToV2, frame_support::migrations::RemovePallet, ); } From b1542d22219896979b98a66716f61570f18ca78f Mon Sep 17 00:00:00 2001 From: yooml Date: Thu, 10 Oct 2024 23:13:08 +0800 Subject: [PATCH 16/30] Update farming (#1455) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 🐛 for review * fix: 🐛 for review --- pallets/farming/src/benchmarking.rs | 12 +-- pallets/farming/src/lib.rs | 133 ++++++++++++++++++++++++++-- pallets/farming/src/rewards.rs | 6 +- pallets/farming/src/tests.rs | 26 +++--- pallets/system-staking/src/tests.rs | 2 +- 5 files changed, 151 insertions(+), 28 deletions(-) diff --git a/pallets/farming/src/benchmarking.rs b/pallets/farming/src/benchmarking.rs index fe5e4504a..c743e1dd3 100644 --- a/pallets/farming/src/benchmarking.rs +++ b/pallets/farming/src/benchmarking.rs @@ -65,7 +65,7 @@ benchmarks! { )); let charge_rewards = vec![(default_currency_id,BalanceOf::::unique_saturated_from(300000u128))]; assert_ok!(Farming::::charge(RawOrigin::Signed(caller.clone()).into(), 0, charge_rewards, false)); - }: _(RawOrigin::Signed(caller.clone()), 0, token_amount, None) + }: _(RawOrigin::Signed(caller.clone()), 0, token_amount) withdraw { let caller: T::AccountId = whitelisted_caller(); @@ -87,7 +87,7 @@ benchmarks! { )); let charge_rewards = vec![(default_currency_id,BalanceOf::::unique_saturated_from(300000u128))]; assert_ok!(Farming::::charge(RawOrigin::Signed(caller.clone()).into(), 0, charge_rewards, false)); - assert_ok!(Farming::::deposit(RawOrigin::Signed(caller.clone()).into(), 0, token_amount, None)); + assert_ok!(Farming::::deposit(RawOrigin::Signed(caller.clone()).into(), 0, token_amount)); }: _(RawOrigin::Signed(caller.clone()), 0, None) claim { @@ -110,7 +110,7 @@ benchmarks! { )); let charge_rewards = vec![(default_currency_id,BalanceOf::::unique_saturated_from(300000u128))]; assert_ok!(Farming::::charge(RawOrigin::Signed(caller.clone()).into(), 0, charge_rewards, false)); - assert_ok!(Farming::::deposit(RawOrigin::Signed(caller.clone()).into(), 0, token_amount, None)); + assert_ok!(Farming::::deposit(RawOrigin::Signed(caller.clone()).into(), 0, token_amount)); System::::set_block_number(System::::block_number() + BlockNumberFor::::from(10u32)); Farming::::on_initialize(BlockNumberFor::::from(0u32)); }: _(RawOrigin::Signed(caller.clone()), 0) @@ -135,7 +135,7 @@ benchmarks! { )); let charge_rewards = vec![(default_currency_id,BalanceOf::::unique_saturated_from(300000u128))]; assert_ok!(Farming::::charge(RawOrigin::Signed(caller.clone()).into(), 0, charge_rewards, false)); - assert_ok!(Farming::::deposit(RawOrigin::Signed(caller.clone()).into(), 0, token_amount, Some((BalanceOf::::unique_saturated_from(100u128), BlockNumberFor::::from(100u32))))); + assert_ok!(Farming::::deposit(RawOrigin::Signed(caller.clone()).into(), 0, token_amount)); // System::::set_block_number(System::::block_number() + BlockNumberFor::::from(10u32)); }: _(RawOrigin::Signed(caller.clone()), 0) @@ -159,7 +159,7 @@ benchmarks! { )); let charge_rewards = vec![(default_currency_id,BalanceOf::::unique_saturated_from(300000u128))]; assert_ok!(Farming::::charge(RawOrigin::Signed(caller.clone()).into(), 0, charge_rewards, false)); - assert_ok!(Farming::::deposit(RawOrigin::Signed(caller.clone()).into(), 0, token_amount, None)); + assert_ok!(Farming::::deposit(RawOrigin::Signed(caller.clone()).into(), 0, token_amount)); }: _(RawOrigin::Signed(caller.clone()), 0) reset_pool { @@ -335,7 +335,7 @@ benchmarks! { )); let charge_rewards = vec![(default_currency_id,BalanceOf::::unique_saturated_from(300000u128))]; assert_ok!(Farming::::charge(RawOrigin::Signed(caller.clone()).into(), 0, charge_rewards, false)); - assert_ok!(Farming::::deposit(RawOrigin::Signed(caller.clone()).into(), 0, token_amount, Some((BalanceOf::::unique_saturated_from(100u128), BlockNumberFor::::from(100u32))))); + assert_ok!(Farming::::deposit(RawOrigin::Signed(caller.clone()).into(), 0, token_amount)); assert_ok!(Farming::::set_retire_limit(RawOrigin::Root.into(), 10)); }: _(RawOrigin::Root, 0) diff --git a/pallets/farming/src/lib.rs b/pallets/farming/src/lib.rs index 73d4badfd..b86a75ea7 100644 --- a/pallets/farming/src/lib.rs +++ b/pallets/farming/src/lib.rs @@ -153,7 +153,6 @@ pub mod pallet { who: AccountIdOf, pid: PoolId, add_value: BalanceOf, - gauge_info: Option<(BalanceOf, BlockNumberFor)>, }, Withdrawn { who: AccountIdOf, @@ -211,28 +210,46 @@ pub mod pallet { #[pallet::error] pub enum Error { + /// The field tokens_proportion cannot be empty. NotNullable, + /// The pool does not exist. PoolDoesNotExist, + /// The gauge pool does not exist. GaugePoolNotExist, + /// The gauge info does not exist. GaugeInfoNotExist, + /// The pool is not in the correct state. InvalidPoolState, - LastGaugeNotClaim, /// claim_limit_time exceeded CanNotClaim, /// gauge pool max_block exceeded GaugeMaxBlockOverflow, /// withdraw_limit_time exceeded WithdrawLimitCountExceeded, + /// User's personal share info does not exist ShareInfoNotExists, + /// The current block height needs to be greater than the field after_block_to_start in + /// order to execute deposit. CanNotDeposit, + /// Whitelist cannot be empty WhitelistEmpty, + /// When starting a round, the field end_round needs to be 0 to indicate that the previous + /// round has ended. RoundNotOver, + /// The round length needs to be set when starting a round RoundLengthNotSet, + /// Whitelist maximum limit exceeded WhitelistLimitExceeded, + /// No one voted for this pool. NobodyVoting, + /// The pool is not in the whitelist NotInWhitelist, + /// The total voting percentage of users cannot exceed 100%. PercentOverflow, + /// The pool cannot be cleaned completely PoolNotCleared, + /// Invalid remove amount + InvalidRemoveAmount, } #[pallet::storage] @@ -371,6 +388,20 @@ pub mod pallet { BlockNumberFor: AtLeast32BitUnsigned + Copy, BalanceOf: AtLeast32BitUnsigned + Copy, { + /// Create a farming pool. + /// + /// The state of the pool will be set to `Ongoing` if the current block number is greater + /// than or equal to the field `after_block_to_start` or the total shares of the pool is + /// greater than or equal to the field `min_deposit_to_start`. + /// + /// - `tokens_proportion`: The proportion of each token in the pool. + /// - `basic_rewards`: The basic reward of each token in the pool. + /// - `gauge_init`: The initial gauge pool info. + /// - `min_deposit_to_start`: The minimum deposit to start the pool. + /// - `after_block_to_start`: The block number to start the pool. + /// - `withdraw_limit_time`: The block number to limit the withdraw. + /// - `claim_limit_time`: The block number to limit the claim. + /// - `withdraw_limit_count`: The count to limit the withdraw. #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::create_farming_pool())] pub fn create_farming_pool( @@ -426,6 +457,15 @@ pub mod pallet { Ok(()) } + /// Charge the pool. + /// + /// Transfer the rewards from the exchanger to the pool. It will charge the rewards to the + /// gauge pool if the `if_gauge` is true, otherwise it will charge the rewards to the + /// farming pool. + /// + /// - `pid`: The pool id. + /// - `rewards`: The rewards to charge. + /// - `if_gauge`: If the rewards are for the gauge pool. #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::charge())] pub fn charge( @@ -476,13 +516,20 @@ pub mod pallet { Ok(()) } + /// Deposit the pool. + /// + /// Mint the share to the exchanger and transfer the tokens to the pool. The state of the + /// pool should be `Ongoing` or `Charged`. The current block number should be greater than + /// or equal to the field `after_block_to_start` if the state of the pool is `Charged`. + /// + /// - `pid`: The pool id. + /// - `add_value`: The value to deposit. #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::deposit())] pub fn deposit( origin: OriginFor, pid: PoolId, add_value: BalanceOf, - gauge_info: Option<(BalanceOf, BlockNumberFor)>, ) -> DispatchResult { // Check origin let exchanger = ensure_signed(origin)?; @@ -516,10 +563,19 @@ pub mod pallet { Self::add_share(&exchanger, pid, &mut pool_info, add_value); Self::update_reward(&exchanger, pid)?; - Self::deposit_event(Event::Deposited { who: exchanger, pid, add_value, gauge_info }); + Self::deposit_event(Event::Deposited { who: exchanger, pid, add_value }); Ok(()) } + /// Withdraw from the pool. + /// + /// The state of the pool should be `Ongoing`, `Charged` or `Dead`. + /// User's withdraw limit count should be less than the field `withdraw_limit_count`. + /// It will remove the share from the user, but not transfer the tokens to the user + /// immediately. + /// + /// - `pid`: The pool id. + /// - `remove_value`: The value to withdraw. #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::withdraw())] pub fn withdraw( @@ -551,6 +607,13 @@ pub mod pallet { Ok(()) } + /// Claim the rewards from the pool. + /// + /// The state of the pool should be `Ongoing` or `Dead`. + /// The user should not claim the rewards within the field `claim_limit_time`. + /// It will claim the rewards to the user, and transfer the tokens to the user immediately. + /// + /// - `pid`: The pool id. #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::claim())] pub fn claim(origin: OriginFor, pid: PoolId) -> DispatchResult { @@ -579,6 +642,11 @@ pub mod pallet { Ok(()) } + /// Withdraw the claim from the pool. + /// + /// It will immediately transfer the withdrawable tokens to the user. + /// + /// - `pid`: The pool id. #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::withdraw_claim())] pub fn withdraw_claim(origin: OriginFor, pid: PoolId) -> DispatchResult { @@ -592,6 +660,12 @@ pub mod pallet { Ok(()) } + /// Force retire the pool. + /// + /// The state of the pool should be `Dead`. + /// It will retire the pool and transfer the withdrawable tokens to the users. + /// + /// - `pid`: The pool id. #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::force_retire_pool())] pub fn force_retire_pool(origin: OriginFor, pid: PoolId) -> DispatchResult { @@ -630,6 +704,9 @@ pub mod pallet { Ok(()) } + /// Set the retire limit. + /// + /// - `limit`: The retire limit. #[pallet::call_index(7)] #[pallet::weight(T::WeightInfo::set_retire_limit())] pub fn set_retire_limit(origin: OriginFor, limit: u32) -> DispatchResult { @@ -643,6 +720,11 @@ pub mod pallet { Ok(()) } + /// Close the pool. + /// + /// Change the state of the pool to `Dead` before retiring the pool. + /// + /// - `pid`: The pool id. #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::close_pool())] pub fn close_pool(origin: OriginFor, pid: PoolId) -> DispatchResult { @@ -657,6 +739,16 @@ pub mod pallet { Ok(()) } + /// Reuse retired pools + /// + /// - `pid`: The pool id. + /// - `basic_rewards`: The basic reward of each token in the pool. + /// - `min_deposit_to_start`: The minimum deposit to start the pool. + /// - `after_block_to_start`: The block number to start the pool. + /// - `withdraw_limit_time`: The block number to limit the withdraw. + /// - `claim_limit_time`: The block number to limit the claim. + /// - `withdraw_limit_count`: The count to limit the withdraw. + /// - `gauge_init`: The initial gauge pool info. #[pallet::call_index(9)] #[pallet::weight(T::WeightInfo::reset_pool())] pub fn reset_pool( @@ -710,6 +802,9 @@ pub mod pallet { Ok(()) } + /// Kill the pool after retired. + /// + /// - `pid`: The pool id. #[pallet::call_index(10)] #[pallet::weight(T::WeightInfo::kill_pool())] pub fn kill_pool(origin: OriginFor, pid: PoolId) -> DispatchResult { @@ -728,6 +823,7 @@ pub mod pallet { Ok(()) } + /// Edit the pool at the state of `Retired`, `Ongoing`, `Charged` or `UnCharged`. #[pallet::call_index(11)] #[pallet::weight(T::WeightInfo::edit_pool())] pub fn edit_pool( @@ -782,6 +878,9 @@ pub mod pallet { Ok(()) } + /// Withdraw the rewards from the gauge pool. + /// + /// - `gid`: The gauge pool id. #[pallet::call_index(12)] #[pallet::weight(T::WeightInfo::gauge_withdraw())] pub fn gauge_withdraw(origin: OriginFor, gid: PoolId) -> DispatchResult { @@ -797,6 +896,11 @@ pub mod pallet { Ok(()) } + /// Force claim the rewards from the gauge pool. + /// + /// Control origin can force claim the rewards from the gauge pool to the users. + /// + /// - `gid`: The gauge pool id. #[pallet::call_index(13)] #[pallet::weight(T::WeightInfo::force_gauge_claim())] pub fn force_gauge_claim(origin: OriginFor, gid: PoolId) -> DispatchResult { @@ -829,7 +933,9 @@ pub mod pallet { Ok(()) } - // Add whitelist and take effect immediately + /// Add whitelist and take effect immediately + /// + /// - `whitelist`: The whitelist to add #[pallet::call_index(14)] #[pallet::weight(T::WeightInfo::add_boost_pool_whitelist())] pub fn add_boost_pool_whitelist( @@ -843,7 +949,9 @@ pub mod pallet { Ok(()) } - // Whitelist for next round in effect + /// Whitelist for next round in effect + /// + /// - `whitelist`: The whitelist for the next round #[pallet::call_index(15)] #[pallet::weight(T::WeightInfo::set_next_round_whitelist())] pub fn set_next_round_whitelist( @@ -851,13 +959,17 @@ pub mod pallet { whitelist: Vec, ) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; - let _ = BoostNextRoundWhitelist::::clear(u32::max_value(), None); + let res = BoostNextRoundWhitelist::::clear(u32::max_value(), None); + ensure!(res.maybe_cursor.is_none(), Error::::PoolNotCleared); whitelist.iter().for_each(|pid| { BoostNextRoundWhitelist::::insert(pid, ()); }); Ok(()) } + /// Vote for the pool + /// + /// - `vote_list`: The vote list for the pool #[pallet::call_index(16)] #[pallet::weight(T::WeightInfo::claim())] pub fn vote(origin: OriginFor, vote_list: Vec<(PoolId, Percent)>) -> DispatchResult { @@ -867,6 +979,9 @@ pub mod pallet { Ok(()) } + /// Start the boost round + /// + /// - `round_length`: The length of the round #[pallet::call_index(17)] #[pallet::weight(T::WeightInfo::claim())] pub fn start_boost_round( @@ -878,6 +993,7 @@ pub mod pallet { Ok(()) } + /// Force end of boost round #[pallet::call_index(18)] #[pallet::weight(T::WeightInfo::claim())] pub fn end_boost_round(origin: OriginFor) -> DispatchResult { @@ -886,6 +1002,9 @@ pub mod pallet { Ok(()) } + /// Charge the boost rewards to the FarmingBoost account + /// + /// - `rewards`: The rewards to charge #[pallet::call_index(19)] #[pallet::weight(T::WeightInfo::claim())] pub fn charge_boost( diff --git a/pallets/farming/src/rewards.rs b/pallets/farming/src/rewards.rs index a284fa85d..7fb23d95c 100644 --- a/pallets/farming/src/rewards.rs +++ b/pallets/farming/src/rewards.rs @@ -228,7 +228,11 @@ impl Pallet { if let Some(mut share_info) = share_info_old.take() { let remove_amount; if let Some(remove_amount_input) = remove_amount_input { - remove_amount = remove_amount_input.min(share_info.share); + ensure!( + remove_amount_input <= share_info.share, + Error::::InvalidRemoveAmount + ); + remove_amount = remove_amount_input; } else { remove_amount = share_info.share; } diff --git a/pallets/farming/src/tests.rs b/pallets/farming/src/tests.rs index 7c6a9e765..3afbc3987 100644 --- a/pallets/farming/src/tests.rs +++ b/pallets/farming/src/tests.rs @@ -60,9 +60,9 @@ fn deposit() { ExtBuilder::default().one_hundred_for_alice_n_bob().build().execute_with(|| { let (pid, tokens) = init_gauge(); System::set_block_number(System::block_number() + 1); - assert_ok!(Farming::deposit(RuntimeOrigin::signed(ALICE), pid, tokens, Some((100, 100)))); + assert_ok!(Farming::deposit(RuntimeOrigin::signed(ALICE), pid, tokens)); System::set_block_number(System::block_number() + 1); - assert_ok!(Farming::deposit(RuntimeOrigin::signed(ALICE), pid, 0, Some((100, 100)))); + assert_ok!(Farming::deposit(RuntimeOrigin::signed(ALICE), pid, 0)); assert_eq!(Tokens::free_balance(KSM, &ALICE), 1000); let keeper: AccountId = ::Keeper::get().into_sub_account_truncating(pid); let reward_issuer: AccountId = @@ -109,7 +109,7 @@ fn withdraw() { assert_ok!(Farming::claim(RuntimeOrigin::signed(ALICE), pid)); assert_eq!(Tokens::free_balance(KSM, &ALICE), 3000); System::set_block_number(System::block_number() + 100); - assert_ok!(Farming::deposit(RuntimeOrigin::signed(BOB), pid, tokens, None)); + assert_ok!(Farming::deposit(RuntimeOrigin::signed(BOB), pid, tokens)); Farming::on_initialize(0); assert_ok!(Farming::claim(RuntimeOrigin::signed(ALICE), pid)); assert_eq!(Tokens::free_balance(KSM, &ALICE), 3966); @@ -146,18 +146,18 @@ fn gauge() { assert_eq!(Tokens::free_balance(KSM, &ALICE), 3018); Farming::on_initialize(0); System::set_block_number(System::block_number() + 10); - assert_ok!(Farming::deposit(RuntimeOrigin::signed(ALICE), pid, tokens, Some((100, 100)))); + assert_ok!(Farming::deposit(RuntimeOrigin::signed(ALICE), pid, tokens)); assert_eq!(Tokens::free_balance(KSM, &ALICE), 2018); System::set_block_number(System::block_number() + 20); assert_ok!(Farming::claim(RuntimeOrigin::signed(ALICE), pid)); assert_eq!(Tokens::free_balance(KSM, &ALICE), 3586); - assert_ok!(Farming::deposit(RuntimeOrigin::signed(BOB), pid, 10, None)); + assert_ok!(Farming::deposit(RuntimeOrigin::signed(BOB), pid, 10)); assert_eq!(Tokens::free_balance(KSM, &BOB), 9699990); System::set_block_number(System::block_number() + 200); assert_ok!(Farming::claim(RuntimeOrigin::signed(ALICE), pid)); assert_eq!(Tokens::free_balance(KSM, &ALICE), 7366); assert_eq!(Tokens::free_balance(KSM, &BOB), 9699990); - assert_ok!(Farming::deposit(RuntimeOrigin::signed(BOB), pid, 0, Some((100, 100)))); + assert_ok!(Farming::deposit(RuntimeOrigin::signed(BOB), pid, 0)); System::set_block_number(System::block_number() + 200); assert_ok!(Farming::set_retire_limit(RuntimeOrigin::signed(ALICE), 10)); assert_ok!(Farming::force_gauge_claim(RuntimeOrigin::signed(ALICE), pid)); @@ -193,9 +193,9 @@ fn retire() { let (pid, tokens) = init_no_gauge(); Farming::on_initialize(0); System::set_block_number(System::block_number() + 1); - assert_ok!(Farming::deposit(RuntimeOrigin::signed(ALICE), pid, tokens, None)); + assert_ok!(Farming::deposit(RuntimeOrigin::signed(ALICE), pid, tokens)); System::set_block_number(System::block_number() + 1); - assert_ok!(Farming::deposit(RuntimeOrigin::signed(ALICE), pid, 0, None)); + assert_ok!(Farming::deposit(RuntimeOrigin::signed(ALICE), pid, 0)); assert_eq!(Tokens::free_balance(KSM, &ALICE), 1000); assert_ok!(Farming::close_pool(RuntimeOrigin::signed(ALICE), pid)); assert_ok!(Farming::set_retire_limit(RuntimeOrigin::signed(ALICE), 10)); @@ -260,7 +260,7 @@ fn reset() { assert_eq!(Tokens::free_balance(KSM, &ALICE), 4018); let charge_rewards = vec![(KSM, 300000)]; assert_ok!(Farming::charge(RuntimeOrigin::signed(BOB), pid, charge_rewards, false)); - assert_ok!(Farming::deposit(RuntimeOrigin::signed(ALICE), pid, 1, Some((100, 100)))); + assert_ok!(Farming::deposit(RuntimeOrigin::signed(ALICE), pid, 1)); assert_eq!(Tokens::free_balance(KSM, &ALICE), 4017); Farming::on_initialize(0); System::set_block_number(System::block_number() + 20); @@ -292,7 +292,7 @@ fn init_gauge() -> (PoolId, BalanceOf) { let pid = 0; let charge_rewards = vec![(KSM, 300000)]; assert_ok!(Farming::charge(RuntimeOrigin::signed(BOB), pid, charge_rewards, false)); - assert_ok!(Farming::deposit(RuntimeOrigin::signed(ALICE), pid, tokens, Some((100, 100)))); + assert_ok!(Farming::deposit(RuntimeOrigin::signed(ALICE), pid, tokens)); assert_ok!(BbBNC::set_config(RuntimeOrigin::signed(ALICE), Some(0), Some(7 * 86400 / 12))); assert_ok!(BbBNC::notify_reward_amount(pid, &Some(CHARLIE), gauge_basic_rewards.clone())); assert_ok!(BbBNC::create_lock_inner( @@ -325,7 +325,7 @@ fn init_no_gauge() -> (PoolId, BalanceOf) { let pid = 0; let charge_rewards = vec![(KSM, 100000)]; assert_ok!(Farming::charge(RuntimeOrigin::signed(BOB), pid, charge_rewards, false)); - assert_ok!(Farming::deposit(RuntimeOrigin::signed(ALICE), pid, tokens, None)); + assert_ok!(Farming::deposit(RuntimeOrigin::signed(ALICE), pid, tokens)); (pid, tokens) } @@ -391,11 +391,11 @@ fn create_farming_pool() { assert_eq!(pool_infos.state, PoolState::Charged) }; assert_err!( - Farming::deposit(RuntimeOrigin::signed(ALICE), pid, tokens, Some((100, 100))), + Farming::deposit(RuntimeOrigin::signed(ALICE), pid, tokens), Error::::CanNotDeposit ); System::set_block_number(System::block_number() + 3); - assert_ok!(Farming::deposit(RuntimeOrigin::signed(ALICE), pid, tokens, Some((100, 100)))); + assert_ok!(Farming::deposit(RuntimeOrigin::signed(ALICE), pid, tokens)); Farming::on_initialize(System::block_number() + 3); Farming::on_initialize(0); if let Some(pool_infos) = PoolInfos::::get(0) { diff --git a/pallets/system-staking/src/tests.rs b/pallets/system-staking/src/tests.rs index d97ec5aae..75544e3ba 100644 --- a/pallets/system-staking/src/tests.rs +++ b/pallets/system-staking/src/tests.rs @@ -246,7 +246,7 @@ fn init_farming_no_gauge() -> (PoolId, BalanceOf) { let pid = 0; let charge_rewards = vec![(KSM, 100000)]; assert_ok!(Farming::charge(RuntimeOrigin::signed(BOB), pid, charge_rewards, false)); - assert_ok!(Farming::deposit(RuntimeOrigin::signed(ALICE), pid, tokens, None)); + assert_ok!(Farming::deposit(RuntimeOrigin::signed(ALICE), pid, tokens)); (pid, tokens) } From 8d19729320d21d06804bf06e5ea733153ac9a99b Mon Sep 17 00:00:00 2001 From: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:08:08 +0800 Subject: [PATCH 17/30] Remove vsbond auction pallet (#1456) * Backup vsbond-auction pallet * remove unnecessary call method of vsbond-auction * remove vsbond-auction pallet * fix clippy * Optimize migration code --- Cargo.lock | 21 -- Cargo.toml | 2 - .../vsbond-auction/Cargo.toml | 0 .../vsbond-auction/src/benchmarking.rs | 0 .../vsbond-auction/src/lib.rs | 0 .../vsbond-auction/src/migration.rs | 0 .../vsbond-auction/src/mock.rs | 0 .../vsbond-auction/src/tests.rs | 0 .../vsbond-auction/src/weights.rs | 0 primitives/src/lib.rs | 1 + runtime/bifrost-kusama/Cargo.toml | 4 - runtime/bifrost-kusama/src/lib.rs | 23 +- runtime/bifrost-kusama/src/migration.rs | 325 +++++++++++++++++- .../src/weights/bifrost_vsbond_auction.rs | 150 -------- runtime/bifrost-kusama/src/weights/mod.rs | 1 - runtime/bifrost-kusama/src/xcm_config.rs | 7 - 16 files changed, 329 insertions(+), 205 deletions(-) rename pallets/{ => deprecated}/vsbond-auction/Cargo.toml (100%) rename pallets/{ => deprecated}/vsbond-auction/src/benchmarking.rs (100%) rename pallets/{ => deprecated}/vsbond-auction/src/lib.rs (100%) rename pallets/{ => deprecated}/vsbond-auction/src/migration.rs (100%) rename pallets/{ => deprecated}/vsbond-auction/src/mock.rs (100%) rename pallets/{ => deprecated}/vsbond-auction/src/tests.rs (100%) rename pallets/{ => deprecated}/vsbond-auction/src/weights.rs (100%) delete mode 100644 runtime/bifrost-kusama/src/weights/bifrost_vsbond_auction.rs diff --git a/Cargo.lock b/Cargo.lock index 0eecd8dd6..3af063867 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1333,7 +1333,6 @@ dependencies = [ "bifrost-token-issuer", "bifrost-vbnc-convert", "bifrost-vesting", - "bifrost-vsbond-auction", "bifrost-vstoken-conversion", "bifrost-vtoken-minting", "bifrost-vtoken-minting-rpc-runtime-api", @@ -2240,26 +2239,6 @@ dependencies = [ "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.13.0)", ] -[[package]] -name = "bifrost-vsbond-auction" -version = "0.8.0" -dependencies = [ - "bifrost-primitives", - "frame-benchmarking", - "frame-support", - "frame-system", - "log", - "orml-tokens", - "orml-traits", - "parity-scale-codec", - "scale-info", - "sp-arithmetic", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.13.0)", -] - [[package]] name = "bifrost-vstoken-conversion" version = "0.8.0" diff --git a/Cargo.toml b/Cargo.toml index 7a72f45b8..dbe0830a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,6 @@ members = [ "pallets/salp", "pallets/token-issuer", "pallets/vesting", - "pallets/vsbond-auction", "pallets/cross-in-out", "pallets/evm-accounts", "pallets/xcm-interface", @@ -92,7 +91,6 @@ bifrost-vbnc-convert = { path = "pallets/vbnc-convert", defaul bb-bnc = { path = "pallets/bb-bnc", default-features = false } bb-bnc-rpc-runtime-api = { path = "pallets/bb-bnc/rpc/runtime-api", default-features = false } bifrost-vesting = { path = "pallets/vesting", default-features = false } -bifrost-vsbond-auction = { path = "pallets/vsbond-auction", default-features = false } bifrost-vstoken-conversion = { path = "pallets/vstoken-conversion", default-features = false } bifrost-vtoken-minting = { path = "pallets/vtoken-minting", default-features = false } bifrost-vtoken-minting-rpc-runtime-api = { path = "pallets/vtoken-minting/rpc/runtime-api", default-features = false } diff --git a/pallets/vsbond-auction/Cargo.toml b/pallets/deprecated/vsbond-auction/Cargo.toml similarity index 100% rename from pallets/vsbond-auction/Cargo.toml rename to pallets/deprecated/vsbond-auction/Cargo.toml diff --git a/pallets/vsbond-auction/src/benchmarking.rs b/pallets/deprecated/vsbond-auction/src/benchmarking.rs similarity index 100% rename from pallets/vsbond-auction/src/benchmarking.rs rename to pallets/deprecated/vsbond-auction/src/benchmarking.rs diff --git a/pallets/vsbond-auction/src/lib.rs b/pallets/deprecated/vsbond-auction/src/lib.rs similarity index 100% rename from pallets/vsbond-auction/src/lib.rs rename to pallets/deprecated/vsbond-auction/src/lib.rs diff --git a/pallets/vsbond-auction/src/migration.rs b/pallets/deprecated/vsbond-auction/src/migration.rs similarity index 100% rename from pallets/vsbond-auction/src/migration.rs rename to pallets/deprecated/vsbond-auction/src/migration.rs diff --git a/pallets/vsbond-auction/src/mock.rs b/pallets/deprecated/vsbond-auction/src/mock.rs similarity index 100% rename from pallets/vsbond-auction/src/mock.rs rename to pallets/deprecated/vsbond-auction/src/mock.rs diff --git a/pallets/vsbond-auction/src/tests.rs b/pallets/deprecated/vsbond-auction/src/tests.rs similarity index 100% rename from pallets/vsbond-auction/src/tests.rs rename to pallets/deprecated/vsbond-auction/src/tests.rs diff --git a/pallets/vsbond-auction/src/weights.rs b/pallets/deprecated/vsbond-auction/src/weights.rs similarity index 100% rename from pallets/vsbond-auction/src/weights.rs rename to pallets/deprecated/vsbond-auction/src/weights.rs diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 6b58e7f04..b114b3912 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -193,6 +193,7 @@ parameter_types! { pub const TreasuryPalletId: PalletId = PalletId(*b"bf/trsry"); pub const VBNCConvertPalletId: PalletId = PalletId(*b"bf/vbncc"); pub const VeMintingPalletId: PalletId = PalletId(*b"bf/vemnt"); + // unused after vsbond_auction pallet removed pub const VsbondAuctionPalletId: PalletId = PalletId(*b"bf/vsbnd"); pub const ZenlinkPalletId: PalletId = PalletId(*b"/zenlink"); } diff --git a/runtime/bifrost-kusama/Cargo.toml b/runtime/bifrost-kusama/Cargo.toml index 2d123a6fa..20bca7d5d 100644 --- a/runtime/bifrost-kusama/Cargo.toml +++ b/runtime/bifrost-kusama/Cargo.toml @@ -134,7 +134,6 @@ bifrost-system-maker = { workspace = true } bifrost-system-staking = { workspace = true } bifrost-token-issuer = { workspace = true } bifrost-vesting = { workspace = true } -bifrost-vsbond-auction = { workspace = true } bifrost-vstoken-conversion = { workspace = true } bifrost-vtoken-minting = { workspace = true } bifrost-vtoken-voting = { workspace = true, features = [ "kusama" ] } @@ -260,7 +259,6 @@ std = [ "bifrost-system-staking/std", "bifrost-token-issuer/std", "bifrost-vesting/std", - "bifrost-vsbond-auction/std", "bifrost-vstoken-conversion/std", "bifrost-vtoken-minting/std", "bifrost-vtoken-voting/std", @@ -306,7 +304,6 @@ runtime-benchmarks = [ "xcm-builder/runtime-benchmarks", "bifrost-flexible-fee/runtime-benchmarks", "bifrost-salp/runtime-benchmarks", - "bifrost-vsbond-auction/runtime-benchmarks", "bifrost-token-issuer/runtime-benchmarks", "bifrost-vtoken-minting/runtime-benchmarks", "bifrost-farming/runtime-benchmarks", @@ -380,7 +377,6 @@ try-runtime = [ "bifrost-flexible-fee/try-runtime", "bifrost-salp/try-runtime", "bifrost-token-issuer/try-runtime", - "bifrost-vsbond-auction/try-runtime", "bifrost-asset-registry/try-runtime", "bifrost-vtoken-minting/try-runtime", "bifrost-slp/try-runtime", diff --git a/runtime/bifrost-kusama/src/lib.rs b/runtime/bifrost-kusama/src/lib.rs index 01276e4dd..b25e34213 100644 --- a/runtime/bifrost-kusama/src/lib.rs +++ b/runtime/bifrost-kusama/src/lib.rs @@ -36,7 +36,7 @@ use bifrost_primitives::{ FarmingRewardIssuerPalletId, FeeSharePalletId, FlexibleFeePalletId, IncentivePoolAccount, LendMarketPalletId, MerkleDirtributorPalletId, OraclePalletId, ParachainStakingPalletId, SlpEntrancePalletId, SlpExitPalletId, SystemMakerPalletId, SystemStakingPalletId, - TreasuryPalletId, VBNCConvertPalletId, VsbondAuctionPalletId, + TreasuryPalletId, VBNCConvertPalletId, }; pub use frame_support::{ construct_runtime, match_types, parameter_types, @@ -1159,18 +1159,6 @@ parameter_types! { pub const MinimumSupply: Balance = 0; } -impl bifrost_vsbond_auction::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type InvoicingCurrency = RelayCurrencyId; - type MaximumOrderInTrade = MaximumOrderInTrade; - type MinimumAmount = MinimumSupply; - type MultiCurrency = Currencies; - type WeightInfo = weights::bifrost_vsbond_auction::BifrostWeight; - type PalletId = VsbondAuctionPalletId; - type TreasuryAccount = BifrostTreasuryAccount; - type ControlOrigin = TechAdminOrCouncil; -} - impl bifrost_token_issuer::Config for Runtime { type RuntimeEvent = RuntimeEvent; type MultiCurrency = Currencies; @@ -1828,7 +1816,6 @@ construct_runtime! { FlexibleFee: bifrost_flexible_fee = 100, Salp: bifrost_salp = 105, TokenIssuer: bifrost_token_issuer = 109, - VSBondAuction: bifrost_vsbond_auction = 113, AssetRegistry: bifrost_asset_registry = 114, VtokenMinting: bifrost_vtoken_minting = 115, Slp: bifrost_slp = 116, @@ -1905,13 +1892,16 @@ pub type Migrations = migrations::Unreleased; parameter_types! { pub const SystemMakerName: &'static str = "SystemMaker"; + pub const VSBondAuctionName: &'static str = "VSBondAuction"; } /// The runtime migrations per release. pub mod migrations { #![allow(unused_imports)] use super::*; - use migration::system_maker::SystemMakerClearPalletId; + use migration::{ + system_maker::SystemMakerClearPalletId, vsbond_auction::VSBondAuctionClearPalletId, + }; /// Unreleased migrations. Add new ones here: pub type Unreleased = ( @@ -1921,7 +1911,9 @@ pub mod migrations { bifrost_asset_registry::migrations::v1::MigrateToV1, bifrost_slpx::migration::v2::MigrateToV2, SystemMakerClearPalletId, + VSBondAuctionClearPalletId, frame_support::migrations::RemovePallet, + frame_support::migrations::RemovePallet, ); } @@ -1952,7 +1944,6 @@ mod benches { [bifrost_stable_pool, StablePool] [bifrost_system_staking, SystemStaking] [bifrost_token_issuer, TokenIssuer] - [bifrost_vsbond_auction, VSBondAuction] [bifrost_vstoken_conversion, VstokenConversion] [bifrost_vtoken_minting, VtokenMinting] [bifrost_vtoken_voting, VtokenVoting] diff --git a/runtime/bifrost-kusama/src/migration.rs b/runtime/bifrost-kusama/src/migration.rs index c6209c79c..487a48617 100644 --- a/runtime/bifrost-kusama/src/migration.rs +++ b/runtime/bifrost-kusama/src/migration.rs @@ -382,13 +382,13 @@ pub mod system_maker { fn pre_upgrade() -> Result, sp_runtime::DispatchError> { #[allow(unused_imports)] use frame_support::PalletId; - log::info!("Bifrost `pre_upgrade`..."); + log::info!("Bifrost SystemMakerClearPalletId `pre_upgrade`..."); Ok(vec![]) } fn on_runtime_upgrade() -> Weight { - log::info!("Bifrost `on_runtime_upgrade`..."); + log::info!("Bifrost SystemMakerClearPalletId `on_runtime_upgrade`..."); let account_id = SystemMakerPalletId::get().into_account_truncating(); let ksm_balance = T::MultiCurrency::free_balance(KSM, &account_id); @@ -410,14 +410,14 @@ pub mod system_maker { log::info!("KSM balance: {:?}", ksm_balance); log::info!("VKSM balance: {:?}", vksm_balance); - log::info!("Bifrost `on_runtime_upgrade finished`"); + log::info!("Bifrost SystemMakerClearPalletId `on_runtime_upgrade finished`"); Weight::from(T::DbWeight::get().reads_writes(1, 1)) } #[cfg(feature = "try-runtime")] fn post_upgrade(_: sp_std::prelude::Vec) -> Result<(), sp_runtime::DispatchError> { - log::info!("Bifrost `post_upgrade`..."); + log::info!("Bifrost SystemMakerClearPalletId `post_upgrade`..."); let account_id = SystemMakerPalletId::get().into_account_truncating(); let ksm_balance = T::MultiCurrency::free_balance(KSM, &account_id); assert_eq!(ksm_balance, Zero::zero()); @@ -428,3 +428,320 @@ pub mod system_maker { } } } + +pub mod vsbond_auction { + use super::*; + pub use bifrost_primitives::currency::{BNC, KSM}; + use bifrost_primitives::VsbondAuctionPalletId; + use frame_support::{pallet_prelude::PhantomData, traits::OnRuntimeUpgrade}; + use sp_core::Get; + + pub struct VSBondAuctionClearPalletId(PhantomData); + impl OnRuntimeUpgrade for VSBondAuctionClearPalletId { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::DispatchError> { + log::info!("Bifrost VSBondAuctionClearPalletId `pre_upgrade`..."); + + Ok(vec![]) + } + + fn on_runtime_upgrade() -> Weight { + log::info!("Bifrost VSBondAuctionClearPalletId `on_runtime_upgrade`..."); + + let account_id = VsbondAuctionPalletId::get().into_account_truncating(); + let mut count: u64 = 0; + + let bnc_balance = T::MultiCurrency::free_balance(BNC, &account_id); + if !bnc_balance.is_zero() { + match T::MultiCurrency::transfer( + BNC, + &account_id, + &TreasuryPalletId::get().into_account_truncating(), + bnc_balance, + ) { + Ok(_) => { + count += 1; + log::info!("Transfer successful: {:?} of BNC transferred", bnc_balance); + }, + Err(e) => { + log::error!("Failed to transfer {:?} of BNC: {:?}", bnc_balance, e); + }, + } + } else { + log::info!("No transfer needed for BNC as the balance is 0"); + } + + let ksm_balance = T::MultiCurrency::free_balance(KSM, &account_id); + if !ksm_balance.is_zero() { + match T::MultiCurrency::transfer( + KSM, + &account_id, + &TreasuryPalletId::get().into_account_truncating(), + ksm_balance, + ) { + Ok(_) => { + count += 1; + log::info!("Transfer successful: {:?} of KSM transferred", ksm_balance); + }, + Err(e) => { + log::error!("Failed to transfer {:?} of KSM: {:?}", ksm_balance, e); + }, + } + } else { + log::info!("No transfer needed for KSM as the balance is 0"); + } + + let vs_bond_1 = CurrencyId::VSBond(TokenSymbol::KSM, 2092, 15, 22); + let vs_bond_1_balance = T::MultiCurrency::free_balance(vs_bond_1, &account_id); + if !vs_bond_1_balance.is_zero() { + match T::MultiCurrency::transfer( + vs_bond_1, + &account_id, + &TreasuryPalletId::get().into_account_truncating(), + vs_bond_1_balance, + ) { + Ok(_) => { + count += 1; + log::info!( + "Transfer successful: {:?} of VSBond(TokenSymbol::KSM, 2092, 15, 22); transferred", + vs_bond_1_balance + ); + }, + Err(e) => { + log::error!( + "Failed to transfer {:?} of VSBond(TokenSymbol::KSM, 2092, 15, 22);: {:?}", + vs_bond_1_balance, + e + ); + }, + } + } else { + log::info!("No transfer needed for VSBond(TokenSymbol::KSM, 2092, 15, 22) as the balance is 0"); + } + + let vs_bond_2 = CurrencyId::VSBond(TokenSymbol::KSM, 2096, 17, 24); + let vs_bond_2_balance = T::MultiCurrency::free_balance(vs_bond_2, &account_id); + if !vs_bond_2_balance.is_zero() { + match T::MultiCurrency::transfer( + vs_bond_2, + &account_id, + &TreasuryPalletId::get().into_account_truncating(), + vs_bond_2_balance, + ) { + Ok(_) => { + count += 1; + log::info!( + "Transfer successful: {:?} of VSBond(TokenSymbol::KSM, 2096, 17, 24) transferred", + vs_bond_2_balance + ); + }, + Err(e) => { + log::error!( + "Failed to transfer {:?} of VSBond(TokenSymbol::KSM, 2096, 17, 24): {:?}", + vs_bond_2_balance, + e + ); + }, + } + } else { + log::info!("No transfer needed for VSBond(TokenSymbol::KSM, 2096, 17, 24) as the balance is 0"); + } + + let vs_bond_3 = CurrencyId::VSBond(TokenSymbol::KSM, 2100, 18, 25); + let vs_bond_3_balance = T::MultiCurrency::free_balance(vs_bond_3, &account_id); + if !vs_bond_3_balance.is_zero() { + match T::MultiCurrency::transfer( + vs_bond_3, + &account_id, + &TreasuryPalletId::get().into_account_truncating(), + vs_bond_3_balance, + ) { + Ok(_) => { + count += 1; + log::info!( + "Transfer successful: {:?} of VSBond(TokenSymbol::KSM, 2100, 18, 25) transferred", + vs_bond_3_balance + ); + }, + Err(e) => { + log::error!( + "Failed to transfer {:?} of VSBond(TokenSymbol::KSM, 2100, 18, 25): {:?}", + vs_bond_3_balance, + e + ); + }, + } + } else { + log::info!("No transfer needed for VSBond(TokenSymbol::KSM, 2100, 18, 25) as the balance is 0"); + } + + let vs_bond_4 = CurrencyId::VSBond(TokenSymbol::KSM, 2125, 23, 30); + let vs_bond_4_balance = T::MultiCurrency::free_balance(vs_bond_4, &account_id); + if !vs_bond_4_balance.is_zero() { + match T::MultiCurrency::transfer( + vs_bond_4, + &account_id, + &TreasuryPalletId::get().into_account_truncating(), + vs_bond_4_balance, + ) { + Ok(_) => { + count += 1; + log::info!( + "Transfer successful: {:?} of VSBond(TokenSymbol::KSM, 2125, 23, 30) transferred", + vs_bond_4_balance + ); + }, + Err(e) => { + log::error!( + "Failed to transfer {:?} of VSBond(TokenSymbol::KSM, 2125, 23, 30): {:?}", + vs_bond_4_balance, + e + ); + }, + } + } else { + log::info!("No transfer needed for VSBond(TokenSymbol::KSM, 2125, 23, 30) as the balance is 0"); + } + + let vs_bond_5 = CurrencyId::VSBond(TokenSymbol::KSM, 2114, 20, 27); + let vs_bond_5_balance = T::MultiCurrency::free_balance(vs_bond_5, &account_id); + if !vs_bond_5_balance.is_zero() { + match T::MultiCurrency::transfer( + vs_bond_5, + &account_id, + &TreasuryPalletId::get().into_account_truncating(), + vs_bond_5_balance, + ) { + Ok(_) => { + count += 1; + log::info!( + "Transfer successful: {:?} of VSBond(TokenSymbol::KSM, 2114, 20, 27) transferred", + vs_bond_5_balance + ); + }, + Err(e) => { + log::error!( + "Failed to transfer {:?} of VSBond(TokenSymbol::KSM, 2114, 20, 27): {:?}", + vs_bond_5_balance, + e + ); + }, + } + } else { + log::info!("No transfer needed for VSBond(TokenSymbol::KSM, 2114, 20, 27) as the balance is 0"); + } + + let vs_bond_6 = CurrencyId::VSBond(TokenSymbol::KSM, 2118, 22, 29); + let vs_bond_6_balance = T::MultiCurrency::free_balance(vs_bond_6, &account_id); + if !vs_bond_6_balance.is_zero() { + match T::MultiCurrency::transfer( + vs_bond_6, + &account_id, + &TreasuryPalletId::get().into_account_truncating(), + vs_bond_6_balance, + ) { + Ok(_) => { + count += 1; + log::info!( + "Transfer successful: {:?} of VSBond(TokenSymbol::KSM, 2118, 22, 29) transferred", + vs_bond_6_balance + ); + }, + Err(e) => { + log::error!( + "Failed to transfer {:?} of VSBond(TokenSymbol::KSM, 2118, 22, 29): {:?}", + vs_bond_6_balance, + e + ); + }, + } + } else { + log::info!("No transfer needed for VSBond(TokenSymbol::KSM, 2118, 22, 29) as the balance is 0"); + } + + let vs_bond_7 = CurrencyId::VSBond(TokenSymbol::BNC, 2001, 13, 20); + let vs_bond_7_balance = T::MultiCurrency::free_balance(vs_bond_7, &account_id); + if !vs_bond_7_balance.is_zero() { + match T::MultiCurrency::transfer( + vs_bond_7, + &account_id, + &TreasuryPalletId::get().into_account_truncating(), + vs_bond_7_balance, + ) { + Ok(_) => { + count += 1; + log::info!( + "Transfer successful: {:?} of VSBond(TokenSymbol::BNC, 2001, 13, 20) transferred", + vs_bond_7_balance + ); + }, + Err(e) => { + log::error!( + "Failed to transfer {:?} of VSBond(TokenSymbol::BNC, 2001, 13, 20): {:?}", + vs_bond_7_balance, + e + ); + }, + } + } else { + log::info!("No transfer needed for VSBond(TokenSymbol::BNC, 2001, 13, 20) as the balance is 0"); + } + + log::info!("BNC balance: {:?}", bnc_balance); + log::info!("KSM balance: {:?}", ksm_balance); + log::info!("vs_bond_1_balance balance: {:?}", vs_bond_1_balance); + log::info!("vs_bond_2_balance balance: {:?}", vs_bond_2_balance); + log::info!("vs_bond_3_balance balance: {:?}", vs_bond_3_balance); + log::info!("vs_bond_4_balance balance: {:?}", vs_bond_4_balance); + log::info!("vs_bond_5_balance balance: {:?}", vs_bond_5_balance); + log::info!("vs_bond_6_balance balance: {:?}", vs_bond_6_balance); + log::info!("vs_bond_7_balance balance: {:?}", vs_bond_7_balance); + + log::info!("Bifrost VSBondAuctionClearPalletId `on_runtime_upgrade finished`"); + + Weight::from(T::DbWeight::get().reads_writes(count + 1, 10)) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_: sp_std::prelude::Vec) -> Result<(), sp_runtime::DispatchError> { + log::info!("Bifrost VSBondAuctionClearPalletId `post_upgrade`..."); + let account_id = VsbondAuctionPalletId::get().into_account_truncating(); + + let bnc_balance = T::MultiCurrency::free_balance(BNC, &account_id); + assert_eq!(bnc_balance, Zero::zero()); + + let ksm_balance = T::MultiCurrency::free_balance(KSM, &account_id); + assert_eq!(ksm_balance, Zero::zero()); + + let vs_bond_1 = CurrencyId::VSBond(TokenSymbol::KSM, 2092, 15, 22); + let vs_bond_1_balance = T::MultiCurrency::free_balance(vs_bond_1, &account_id); + assert_eq!(vs_bond_1_balance, Zero::zero()); + + let vs_bond_2 = CurrencyId::VSBond(TokenSymbol::KSM, 2096, 17, 24); + let vs_bond_2_balance = T::MultiCurrency::free_balance(vs_bond_2, &account_id); + assert_eq!(vs_bond_2_balance, Zero::zero()); + + let vs_bond_3 = CurrencyId::VSBond(TokenSymbol::KSM, 2100, 18, 25); + let vs_bond_3_balance = T::MultiCurrency::free_balance(vs_bond_3, &account_id); + assert_eq!(vs_bond_3_balance, Zero::zero()); + + let vs_bond_4 = CurrencyId::VSBond(TokenSymbol::KSM, 2125, 23, 30); + let vs_bond_4_balance = T::MultiCurrency::free_balance(vs_bond_4, &account_id); + assert_eq!(vs_bond_4_balance, Zero::zero()); + + let vs_bond_5 = CurrencyId::VSBond(TokenSymbol::KSM, 2114, 20, 27); + let vs_bond_5_balance = T::MultiCurrency::free_balance(vs_bond_5, &account_id); + assert_eq!(vs_bond_5_balance, Zero::zero()); + + let vs_bond_6 = CurrencyId::VSBond(TokenSymbol::KSM, 2118, 22, 29); + let vs_bond_6_balance = T::MultiCurrency::free_balance(vs_bond_6, &account_id); + assert_eq!(vs_bond_6_balance, Zero::zero()); + + let vs_bond_7 = CurrencyId::VSBond(TokenSymbol::BNC, 2001, 13, 20); + let vs_bond_7_balance = T::MultiCurrency::free_balance(vs_bond_7, &account_id); + assert_eq!(vs_bond_7_balance, Zero::zero()); + + Ok(()) + } + } +} diff --git a/runtime/bifrost-kusama/src/weights/bifrost_vsbond_auction.rs b/runtime/bifrost-kusama/src/weights/bifrost_vsbond_auction.rs deleted file mode 100644 index b74cd417a..000000000 --- a/runtime/bifrost-kusama/src/weights/bifrost_vsbond_auction.rs +++ /dev/null @@ -1,150 +0,0 @@ -// This file is part of Bifrost. - -// Copyright (C) Liebi Technologies PTE. 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 . -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Autogenerated weights for bifrost_vsbond_auction -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-14, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bifrost-jenkins`, CPU: `Intel(R) Xeon(R) CPU E5-26xx v4` -//! WASM-EXECUTION: Compiled, CHAIN: Some("bifrost-kusama-local"), DB CACHE: 1024 - -// Executed Command: -// target/release/bifrost -// benchmark -// pallet -// --chain=bifrost-kusama-local -// --steps=50 -// --repeat=20 -// --pallet=bifrost_vsbond_auction -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --heap-pages=4096 -// --output=./runtime/bifrost-kusama/src/weights/bifrost_vsbond_auction.rs -// --template=./weight-template/runtime-weight-template.hbs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] - -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use sp_std::marker::PhantomData; - -/// Weight functions for bifrost_vsbond_auction. -pub struct BifrostWeight(PhantomData); -impl bifrost_vsbond_auction::WeightInfo for BifrostWeight { - // Storage: VSBondAuction TransactionFee (r:1 w:0) - // Proof Skipped: VSBondAuction TransactionFee (max_values: Some(1), max_size: None, mode: Measured) - // Storage: Tokens Accounts (r:2 w:2) - // Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) - // Storage: VSBondAuction UserOrderIds (r:1 w:1) - // Proof Skipped: VSBondAuction UserOrderIds (max_values: None, max_size: None, mode: Measured) - // Storage: VSBondAuction NextOrderId (r:1 w:1) - // Proof Skipped: VSBondAuction NextOrderId (max_values: Some(1), max_size: None, mode: Measured) - // Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) - // Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - // Storage: System Account (r:1 w:1) - // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - // Storage: VSBondAuction TotalOrderInfos (r:0 w:1) - // Proof Skipped: VSBondAuction TotalOrderInfos (max_values: None, max_size: None, mode: Measured) - fn create_order() -> Weight { - // Proof Size summary in bytes: - // Measured: `1789` - // Estimated: `6176` - // Minimum execution time: 175_259 nanoseconds. - Weight::from_parts(177_403_000, 6176) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(6)) - } - // Storage: VSBondAuction TotalOrderInfos (r:1 w:1) - // Proof Skipped: VSBondAuction TotalOrderInfos (max_values: None, max_size: None, mode: Measured) - // Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) - // Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - // Storage: Tokens Accounts (r:2 w:2) - // Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) - // Storage: System Account (r:1 w:1) - // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - // Storage: VSBondAuction UserOrderIds (r:1 w:1) - // Proof Skipped: VSBondAuction UserOrderIds (max_values: None, max_size: None, mode: Measured) - fn revoke_order() -> Weight { - // Proof Size summary in bytes: - // Measured: `2023` - // Estimated: `6176` - // Minimum execution time: 161_381 nanoseconds. - Weight::from_parts(162_871_000, 6176) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(5)) - } - // Storage: VSBondAuction TotalOrderInfos (r:1 w:1) - // Proof Skipped: VSBondAuction TotalOrderInfos (max_values: None, max_size: None, mode: Measured) - // Storage: VSBondAuction TransactionFee (r:1 w:0) - // Proof Skipped: VSBondAuction TransactionFee (max_values: Some(1), max_size: None, mode: Measured) - // Storage: Tokens Accounts (r:4 w:4) - // Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) - // Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) - // Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - // Storage: System Account (r:1 w:1) - // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - // Storage: VSBondAuction UserOrderIds (r:1 w:1) - // Proof Skipped: VSBondAuction UserOrderIds (max_values: None, max_size: None, mode: Measured) - fn clinch_order() -> Weight { - // Proof Size summary in bytes: - // Measured: `2383` - // Estimated: `11362` - // Minimum execution time: 236_772 nanoseconds. - Weight::from_parts(238_487_000, 11362) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(7)) - } - // Storage: VSBondAuction TotalOrderInfos (r:1 w:1) - // Proof Skipped: VSBondAuction TotalOrderInfos (max_values: None, max_size: None, mode: Measured) - // Storage: VSBondAuction TransactionFee (r:1 w:0) - // Proof Skipped: VSBondAuction TransactionFee (max_values: Some(1), max_size: None, mode: Measured) - // Storage: Tokens Accounts (r:4 w:4) - // Proof: Tokens Accounts (max_values: None, max_size: Some(118), added: 2593, mode: MaxEncodedLen) - // Storage: AssetRegistry CurrencyMetadatas (r:1 w:0) - // Proof Skipped: AssetRegistry CurrencyMetadatas (max_values: None, max_size: None, mode: Measured) - // Storage: System Account (r:1 w:0) - // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn partial_clinch_order() -> Weight { - // Proof Size summary in bytes: - // Measured: `2291` - // Estimated: `11362` - // Minimum execution time: 206_572 nanoseconds. - Weight::from_parts(214_687_000, 11362) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(5)) - } - // Storage: VSBondAuction TransactionFee (r:1 w:1) - // Proof Skipped: VSBondAuction TransactionFee (max_values: Some(1), max_size: None, mode: Measured) - fn set_buy_and_sell_transaction_fee_rate() -> Weight { - // Proof Size summary in bytes: - // Measured: `4` - // Estimated: `1489` - // Minimum execution time: 26_870 nanoseconds. - Weight::from_parts(27_527_000, 1489) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/runtime/bifrost-kusama/src/weights/mod.rs b/runtime/bifrost-kusama/src/weights/mod.rs index 5de22ec76..c69a7e8be 100644 --- a/runtime/bifrost-kusama/src/weights/mod.rs +++ b/runtime/bifrost-kusama/src/weights/mod.rs @@ -36,7 +36,6 @@ pub mod bifrost_system_staking; pub mod bifrost_token_issuer; pub mod bifrost_vbnc_convert; pub mod bifrost_vesting; -pub mod bifrost_vsbond_auction; pub mod bifrost_vstoken_conversion; pub mod bifrost_vtoken_minting; pub mod bifrost_vtoken_voting; diff --git a/runtime/bifrost-kusama/src/xcm_config.rs b/runtime/bifrost-kusama/src/xcm_config.rs index 414600305..90b13211a 100644 --- a/runtime/bifrost-kusama/src/xcm_config.rs +++ b/runtime/bifrost-kusama/src/xcm_config.rs @@ -352,12 +352,6 @@ impl Contains for SafeCallFilter { RuntimeCall::Salp( bifrost_salp::Call::redeem { .. } ) | - RuntimeCall::VSBondAuction( - bifrost_vsbond_auction::Call::clinch_order { .. } | - bifrost_vsbond_auction::Call::create_order { .. } | - bifrost_vsbond_auction::Call::partial_clinch_order { .. } | - bifrost_vsbond_auction::Call::revoke_order { .. } - ) | RuntimeCall::VstokenConversion( bifrost_vstoken_conversion::Call::vsbond_convert_to_vstoken { .. } | bifrost_vstoken_conversion::Call::vstoken_convert_to_vsbond { .. } @@ -566,7 +560,6 @@ impl Contains for DustRemovalWhitelist { SystemMakerPalletId::get().into_account_truncating(), ZenklinkFeeAccount::get(), CommissionPalletId::get().into_account_truncating(), - VsbondAuctionPalletId::get().into_account_truncating(), ParachainStakingPalletId::get().into_account_truncating(), SystemStakingPalletId::get().into_account_truncating(), VBNCConvertPalletId::get().into_account_truncating(), From 9ac8443649519d3bc16db805bd4031221649cda1 Mon Sep 17 00:00:00 2001 From: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Date: Fri, 11 Oct 2024 17:40:47 +0800 Subject: [PATCH 18/30] This version of vtoken_voting does not support VBNC. (#1459) --- pallets/vtoken-voting/src/lib.rs | 2 +- pallets/vtoken-voting/src/tests/mod.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pallets/vtoken-voting/src/lib.rs b/pallets/vtoken-voting/src/lib.rs index 95d4bd80b..a8452f646 100644 --- a/pallets/vtoken-voting/src/lib.rs +++ b/pallets/vtoken-voting/src/lib.rs @@ -1211,7 +1211,7 @@ pub mod pallet { } fn ensure_vtoken(vtoken: &CurrencyIdOf) -> Result<(), DispatchError> { - ensure!([VKSM, VDOT, VBNC].contains(vtoken), Error::::VTokenNotSupport); + ensure!([VKSM, VDOT].contains(vtoken), Error::::VTokenNotSupport); Ok(()) } diff --git a/pallets/vtoken-voting/src/tests/mod.rs b/pallets/vtoken-voting/src/tests/mod.rs index 955f282ad..aa137efcd 100644 --- a/pallets/vtoken-voting/src/tests/mod.rs +++ b/pallets/vtoken-voting/src/tests/mod.rs @@ -19,5 +19,5 @@ #[cfg(test)] mod common_test; -#[cfg(test)] -mod vbnc_test; +// #[cfg(test)] +// mod vbnc_test; From c62e8169ab074b42afe48b4096bbc42e8df3bbc7 Mon Sep 17 00:00:00 2001 From: NingBo Wang <2536935847@qq.com> Date: Sun, 13 Oct 2024 00:06:23 +0800 Subject: [PATCH 19/30] Update parachain staking (#1460) * Fix staking collator snapshot to use total counted instead of total exposure(1719) * deprecate delegator leave in favor of batch schedule revoke(1760) * move Default config associated types to GenesisConfig(1798) * Fix overflow for large round numbers(1817) * Fix clippy --- node/service/src/chain_spec/bifrost_kusama.rs | 17 ++-- pallets/buy-back/src/lib.rs | 4 +- pallets/parachain-staking/Cargo.toml | 1 + pallets/parachain-staking/src/inflation.rs | 26 ++++-- pallets/parachain-staking/src/lib.rs | 83 ++++++++++++------- pallets/parachain-staking/src/migrations.rs | 12 ++- pallets/parachain-staking/src/mock.rs | 6 +- pallets/parachain-staking/src/tests.rs | 64 +++++++------- pallets/parachain-staking/src/types.rs | 5 ++ pallets/slp/src/mocks/mock.rs | 9 +- pallets/slp/src/mocks/mock_kusama.rs | 9 +- runtime/bifrost-kusama/src/lib.rs | 9 -- 12 files changed, 138 insertions(+), 107 deletions(-) diff --git a/node/service/src/chain_spec/bifrost_kusama.rs b/node/service/src/chain_spec/bifrost_kusama.rs index ba38b8ab7..4a307e7ea 100644 --- a/node/service/src/chain_spec/bifrost_kusama.rs +++ b/node/service/src/chain_spec/bifrost_kusama.rs @@ -18,13 +18,13 @@ use crate::chain_spec::{get_account_id_from_seed, get_from_seed, RelayExtensions}; use bifrost_kusama_runtime::{ - constants::currency::DOLLARS, AccountId, Balance, BalancesConfig, BlockNumber, - DefaultBlocksPerRound, InflationInfo, Range, SS58Prefix, VestingConfig, + constants::currency::DOLLARS, AccountId, Balance, BalancesConfig, BlockNumber, InflationInfo, + Range, SS58Prefix, VestingConfig, }; use bifrost_primitives::{ BifrostKusamaChainId, CurrencyId, CurrencyId::*, TokenInfo, TokenSymbol::*, }; -use bifrost_runtime_common::AuraId; +use bifrost_runtime_common::{constants::time::HOURS, AuraId}; use cumulus_primitives_core::ParaId; use frame_benchmarking::{account, whitelisted_caller}; use hex_literal::hex; @@ -33,7 +33,7 @@ use sc_service::ChainType; use serde::de::DeserializeOwned; use serde_json as json; use sp_core::{crypto::UncheckedInto, sr25519}; -use sp_runtime::{traits::Zero, Perbill}; +use sp_runtime::{traits::Zero, Perbill, Percent}; use std::{ collections::BTreeMap, fs::{read_dir, File}, @@ -50,6 +50,10 @@ pub fn ENDOWMENT() -> u128 { 1_000_000 * DOLLARS } +const COLLATOR_COMMISSION: Perbill = Perbill::from_percent(10); +const PARACHAIN_BOND_RESERVE_PERCENT: Percent = Percent::from_percent(0); +const BLOCKS_PER_ROUND: u32 = 2 * HOURS; + pub fn inflation_config() -> InflationInfo { fn to_round_inflation(annual: Range) -> Range { use bifrost_parachain_staking::inflation::{ @@ -58,7 +62,7 @@ pub fn inflation_config() -> InflationInfo { perbill_annual_to_perbill_round( annual, // rounds per year - BLOCKS_PER_YEAR / DefaultBlocksPerRound::get(), + BLOCKS_PER_YEAR / BLOCKS_PER_ROUND, ) } let annual = Range { @@ -171,6 +175,9 @@ pub fn bifrost_genesis( .collect::>(), "delegations": delegations, "inflationConfig": inflation_config(), + "collatorCommission": COLLATOR_COMMISSION, + "parachainBondReservePercent": PARACHAIN_BOND_RESERVE_PERCENT, + "blocksPerRound": BLOCKS_PER_ROUND, }, }) } diff --git a/pallets/buy-back/src/lib.rs b/pallets/buy-back/src/lib.rs index b3ea80623..f6668d663 100644 --- a/pallets/buy-back/src/lib.rs +++ b/pallets/buy-back/src/lib.rs @@ -270,6 +270,7 @@ pub mod pallet { n.saturating_sub(info.last_buyback_cycle) .saturated_into::() .saturating_sub(One::one()) => + { if let Some(swap_out_min) = SwapOutMin::::get(currency_id) { if let Some(e) = Self::buy_back(&buyback_address, currency_id, &info, swap_out_min) @@ -295,7 +296,8 @@ pub mod pallet { info.last_buyback = n; Infos::::insert(currency_id, info); SwapOutMin::::remove(currency_id); - }, + } + }, _ => (), } } diff --git a/pallets/parachain-staking/Cargo.toml b/pallets/parachain-staking/Cargo.toml index c9a7d34b9..04aa346cd 100644 --- a/pallets/parachain-staking/Cargo.toml +++ b/pallets/parachain-staking/Cargo.toml @@ -46,6 +46,7 @@ std = [ "pallet-authorship/std", "pallet-session/std", "log/std", + "bifrost-primitives/std", ] runtime-benchmarks = ["frame-benchmarking"] try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/parachain-staking/src/inflation.rs b/pallets/parachain-staking/src/inflation.rs index 53c2a465a..a01314375 100644 --- a/pallets/parachain-staking/src/inflation.rs +++ b/pallets/parachain-staking/src/inflation.rs @@ -20,10 +20,7 @@ use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; use sp_runtime::{PerThing, Perbill, RuntimeDebug}; -use substrate_fixed::{ - transcendental::pow as floatpow, - types::{I32F32, I64F64}, -}; +use substrate_fixed::{transcendental::pow as floatpow, types::I64F64}; use crate::{ pallet::{BalanceOf, Config}, @@ -76,10 +73,10 @@ pub fn perbill_annual_to_perbill_round( annual: Range, rounds_per_year: u32, ) -> Range { - let exponent = I32F32::from_num(1) / I32F32::from_num(rounds_per_year); + let exponent = I64F64::from_num(1) / I64F64::from_num(rounds_per_year); let annual_to_round = |annual: Perbill| -> Perbill { - let x = I32F32::from_num(annual.deconstruct()) / I32F32::from_num(Perbill::ACCURACY); - let y: I64F64 = floatpow(I32F32::from_num(1) + x, exponent) + let x = I64F64::from_num(annual.deconstruct()) / I64F64::from_num(Perbill::ACCURACY); + let y: I64F64 = floatpow(I64F64::from_num(1) + x, exponent) .expect("Cannot overflow since rounds_per_year is u32 so worst case 0; QED"); Perbill::from_parts( ((y - I64F64::from_num(1)) * I64F64::from_num(Perbill::ACCURACY)) @@ -208,4 +205,19 @@ mod tests { mock_round_issuance_range(10_000_000, mock_annual_to_round(schedule, 8766)) ); } + + #[test] + fn inflation_does_not_panic_at_round_number_limit() { + let schedule = Range { + min: Perbill::from_percent(100), + ideal: Perbill::from_percent(100), + max: Perbill::from_percent(100), + }; + mock_round_issuance_range(u32::MAX.into(), mock_annual_to_round(schedule, u32::MAX)); + mock_round_issuance_range(u64::MAX.into(), mock_annual_to_round(schedule, u32::MAX)); + mock_round_issuance_range(u128::MAX.into(), mock_annual_to_round(schedule, u32::MAX)); + mock_round_issuance_range(u32::MAX.into(), mock_annual_to_round(schedule, 1)); + mock_round_issuance_range(u64::MAX.into(), mock_annual_to_round(schedule, 1)); + mock_round_issuance_range(u128::MAX.into(), mock_annual_to_round(schedule, 1)); + } } diff --git a/pallets/parachain-staking/src/lib.rs b/pallets/parachain-staking/src/lib.rs index 3504f24f7..41a0e3cc0 100755 --- a/pallets/parachain-staking/src/lib.rs +++ b/pallets/parachain-staking/src/lib.rs @@ -131,9 +131,6 @@ pub mod pallet { /// Minimum number of blocks per round #[pallet::constant] type MinBlocksPerRound: Get; - /// Default number of blocks per round at genesis - #[pallet::constant] - type DefaultBlocksPerRound: Get; /// Number of rounds that candidates remain bonded before exit request is executable #[pallet::constant] type LeaveCandidatesDelay: Get; @@ -164,12 +161,6 @@ pub mod pallet { /// Maximum delegations per delegator #[pallet::constant] type MaxDelegationsPerDelegator: Get; - /// Default commission due to collators, is `CollatorCommission` storage value in genesis - #[pallet::constant] - type DefaultCollatorCommission: Get; - /// Default percent of inflation set aside for parachain bond account - #[pallet::constant] - type DefaultParachainBondReservePercent: Get; /// Minimum stake required for any candidate to be in `SelectedCandidates` for the round #[pallet::constant] type MinCollatorStk: Get>; @@ -591,18 +582,41 @@ pub mod pallet { >; #[pallet::genesis_config] - #[derive(frame_support::DefaultNoBound)] pub struct GenesisConfig { + /// Initialize balance and register all as collators: `(collator AccountId, balance + /// Amount)` pub candidates: Vec<(AccountIdOf, BalanceOf)>, - /// Vec of tuples of the format (delegator AccountId, collator AccountId, delegation - /// Amount) + /// Initialize balance and make delegations: + /// `(delegator AccountId, collator AccountId, delegation Amount, auto-compounding + /// Percent)` pub delegations: Vec<(AccountIdOf, AccountIdOf, BalanceOf)>, + /// Inflation configuration pub inflation_config: InflationInfo>, + /// Default fixed percent a collator takes off the top of due rewards + pub collator_commission: Perbill, + /// Default percent of inflation set aside for parachain bond every round + pub parachain_bond_reserve_percent: Percent, + /// Default number of blocks in a round + pub blocks_per_round: u32, + } + + impl Default for GenesisConfig { + fn default() -> Self { + Self { + candidates: vec![], + delegations: vec![], + inflation_config: Default::default(), + collator_commission: Default::default(), + parachain_bond_reserve_percent: Default::default(), + blocks_per_round: 1u32, + } + } } #[pallet::genesis_build] impl BuildGenesisConfig for GenesisConfig { fn build(&self) { + assert!(self.blocks_per_round > 0, "Blocks per round must be > 0"); >::put(self.inflation_config.clone()); let mut candidate_count = 0u32; // Initialize the candidates @@ -656,7 +670,7 @@ pub mod pallet { } } // Set collator commission to default config - >::put(T::DefaultCollatorCommission::get()); + >::put(self.collator_commission); // Set parachain bond config to default config >::put(ParachainBondConfig { // must be set soon; if not => due inflation will be sent to collators/delegators @@ -664,7 +678,7 @@ pub mod pallet { &mut sp_runtime::traits::TrailingZeroInput::zeroes(), ) .expect("infinite length input; no invalid inputs for type; qed"), - percent: T::DefaultParachainBondReservePercent::get(), + percent: self.parachain_bond_reserve_percent, payment_in_round: T::PaymentInRound::get(), }); // Set total selected candidates to minimum config @@ -673,7 +687,7 @@ pub mod pallet { let (v_count, _, total_staked) = >::select_top_candidates(1u32); // Start Round 1 at Block 0 let round: RoundInfo> = - RoundInfo::new(1u32, 0u32.into(), T::DefaultBlocksPerRound::get()); + RoundInfo::new(1u32, 0u32.into(), self.blocks_per_round); >::put(round); // Snapshot total stake >::insert(1u32, >::get()); @@ -1134,18 +1148,21 @@ pub mod pallet { ) } - #[pallet::call_index(18)] - #[pallet::weight(::WeightInfo::schedule_leave_delegators())] + /// DEPRECATED use batch util with schedule_revoke_delegation for all delegations /// Request to leave the set of delegators. If successful, the caller is scheduled to be /// allowed to exit via a [DelegationAction::Revoke] towards all existing delegations. /// Success forbids future delegation requests until the request is invoked or cancelled. + #[pallet::call_index(18)] + #[pallet::weight(::WeightInfo::schedule_leave_delegators())] pub fn schedule_leave_delegators(origin: OriginFor) -> DispatchResultWithPostInfo { let delegator = ensure_signed(origin)?; Self::delegator_schedule_revoke_all(delegator) } + + /// DEPRECATED use batch util with execute_delegation_request for all delegations + /// Execute the right to exit the set of delegators and revoke all ongoing delegations. #[pallet::call_index(19)] #[pallet::weight(::WeightInfo::execute_leave_delegators(*delegation_count))] - /// Execute the right to exit the set of delegators and revoke all ongoing delegations. pub fn execute_leave_delegators( origin: OriginFor, delegator: AccountIdOf, @@ -1154,10 +1171,12 @@ pub mod pallet { ensure_signed(origin)?; Self::delegator_execute_scheduled_revoke_all(delegator, delegation_count) } - #[pallet::call_index(20)] - #[pallet::weight(::WeightInfo::cancel_leave_delegators())] + + /// DEPRECATED use batch util with cancel_delegation_request for all delegations /// Cancel a pending request to exit the set of delegators. Success clears the pending exit /// request (thereby resetting the delay upon another `leave_delegators` call). + #[pallet::call_index(20)] + #[pallet::weight(::WeightInfo::cancel_leave_delegators())] pub fn cancel_leave_delegators(origin: OriginFor) -> DispatchResultWithPostInfo { let delegator = ensure_signed(origin)?; Self::delegator_cancel_scheduled_revoke_all(delegator) @@ -1710,19 +1729,21 @@ pub mod pallet { collator_count = collator_count.saturating_add(1u32); delegation_count = delegation_count.saturating_add(state.delegation_count); total = total.saturating_add(state.total_counted); - let snapshot_total = state.total_counted; - let top_rewardable_delegations = Self::get_rewardable_delegators(account); + + let CountedDelegations { uncounted_stake, rewardable_delegations } = + Self::get_rewardable_delegators(&account); + let total_counted = state.total_counted.saturating_sub(uncounted_stake); let snapshot = CollatorSnapshot { bond: state.bond, - delegations: top_rewardable_delegations, - total: state.total_counted, + delegations: rewardable_delegations, + total: total_counted, }; >::insert(now, account, snapshot); Self::deposit_event(Event::CollatorChosen { round: now, collator_account: account.clone(), - total_exposed_amount: snapshot_total, + total_exposed_amount: state.total_counted, }); } // insert canonical collator set @@ -1739,15 +1760,14 @@ pub mod pallet { /// - else, do nothing /// /// The intended bond amounts will be used while calculating rewards. - fn get_rewardable_delegators( - collator: &AccountIdOf, - ) -> Vec, BalanceOf>> { + fn get_rewardable_delegators(collator: &AccountIdOf) -> CountedDelegations { let requests = >::get(collator) .into_iter() .map(|x| (x.delegator, x.action)) .collect::>(); - >::get(collator) + let mut uncounted_stake = BalanceOf::::zero(); + let rewardable_delegations = >::get(collator) .expect("all members of CandidateQ must be candidates") .delegations .into_iter() @@ -1760,6 +1780,7 @@ pub mod pallet { revoke request", bond.owner ); + uncounted_stake = uncounted_stake.saturating_add(bond.amount); BalanceOf::::zero() }, Some(DelegationAction::Decrease(amount)) => { @@ -1768,13 +1789,15 @@ pub mod pallet { decrease request", bond.owner ); + uncounted_stake = uncounted_stake.saturating_add(*amount); bond.amount.saturating_sub(*amount) }, }; bond }) - .collect() + .collect(); + CountedDelegations { uncounted_stake, rewardable_delegations } } /// Temporary JIT migration of a single delegator's reserve -> lock. This will query diff --git a/pallets/parachain-staking/src/migrations.rs b/pallets/parachain-staking/src/migrations.rs index 21d43b070..4fbfb1bd9 100644 --- a/pallets/parachain-staking/src/migrations.rs +++ b/pallets/parachain-staking/src/migrations.rs @@ -36,7 +36,7 @@ use frame_system::pallet_prelude::BlockNumberFor; use scale_info::prelude::string::String; use sp_runtime::{ traits::{AccountIdConversion, Saturating, Zero}, - Perbill, TryRuntimeError, + Perbill, Percent, TryRuntimeError, }; use sp_std::{convert::TryInto, vec::Vec}; @@ -53,6 +53,10 @@ use crate::{ RoundInfo, Staked, TopDelegations, TotalSelected, }; +const COLLATOR_COMMISSION: Perbill = Perbill::from_percent(10); +const PARACHAIN_BOND_RESERVE_PERCENT: Percent = Percent::from_percent(0); +const BLOCKS_PER_ROUND: u32 = 2 * 300; + /// Migration to purge staking storage bloat for `Points` and `AtStake` storage items pub struct InitGenesisMigration(PhantomData); impl OnRuntimeUpgrade for InitGenesisMigration { @@ -97,12 +101,12 @@ impl OnRuntimeUpgrade for InitGenesisMigration { } } // Set collator commission to default config - >::put(T::DefaultCollatorCommission::get()); + >::put(COLLATOR_COMMISSION); // Set parachain bond config to default config >::put(ParachainBondConfig { // must be set soon; if not => due inflation will be sent to collators/delegators account: T::PalletId::get().into_account_truncating(), - percent: T::DefaultParachainBondReservePercent::get(), + percent: PARACHAIN_BOND_RESERVE_PERCENT, payment_in_round: T::PaymentInRound::get(), }); // Set total selected candidates to minimum config @@ -111,7 +115,7 @@ impl OnRuntimeUpgrade for InitGenesisMigration { >::select_top_candidates(1u32); // Start Round 1 at Block 0 let round: RoundInfo> = - RoundInfo::new(1u32, 0u32.into(), T::DefaultBlocksPerRound::get()); + RoundInfo::new(1u32, 0u32.into(), BLOCKS_PER_ROUND); >::put(round); // Snapshot total stake >::insert(1u32, >::get()); diff --git a/pallets/parachain-staking/src/mock.rs b/pallets/parachain-staking/src/mock.rs index 45acfb13b..72235e155 100644 --- a/pallets/parachain-staking/src/mock.rs +++ b/pallets/parachain-staking/src/mock.rs @@ -106,7 +106,6 @@ impl Config for Test { type Currency = Balances; type MonetaryGovernanceOrigin = frame_system::EnsureRoot; type MinBlocksPerRound = MinBlocksPerRound; - type DefaultBlocksPerRound = DefaultBlocksPerRound; type LeaveCandidatesDelay = LeaveCandidatesDelay; type CandidateBondLessDelay = CandidateBondLessDelay; type LeaveDelegatorsDelay = LeaveDelegatorsDelay; @@ -117,8 +116,6 @@ impl Config for Test { type MaxTopDelegationsPerCandidate = MaxTopDelegationsPerCandidate; type MaxBottomDelegationsPerCandidate = MaxBottomDelegationsPerCandidate; type MaxDelegationsPerDelegator = MaxDelegationsPerDelegator; - type DefaultCollatorCommission = DefaultCollatorCommission; - type DefaultParachainBondReservePercent = DefaultParachainBondReservePercent; type MinCollatorStk = MinCollatorStk; type MinCandidateStk = MinCollatorStk; type MinDelegatorStk = MinDelegatorStk; @@ -206,6 +203,9 @@ impl ExtBuilder { candidates: self.collators, delegations: self.delegations, inflation_config: self.inflation, + collator_commission: DefaultCollatorCommission::get(), + parachain_bond_reserve_percent: DefaultParachainBondReservePercent::get(), + blocks_per_round: DefaultBlocksPerRound::get(), } .assimilate_storage(&mut t) .expect("Parachain Staking's storage can be assimilated"); diff --git a/pallets/parachain-staking/src/tests.rs b/pallets/parachain-staking/src/tests.rs index 0ed9682ff..c7b5ff82f 100644 --- a/pallets/parachain-staking/src/tests.rs +++ b/pallets/parachain-staking/src/tests.rs @@ -3490,9 +3490,9 @@ fn parachain_bond_inflation_reserve_matches_config() { selected_collators_number: 5, total_balance: 130, }, - Event::Rewarded { account: 1, rewards: 24 }, - Event::Rewarded { account: 7, rewards: 6 }, - Event::Rewarded { account: 10, rewards: 6 }, + Event::Rewarded { account: 1, rewards: 26 }, + Event::Rewarded { account: 7, rewards: 7 }, + Event::Rewarded { account: 10, rewards: 7 }, ]; expected.append(&mut new2); assert_eq_events!(expected.clone()); @@ -3522,9 +3522,9 @@ fn parachain_bond_inflation_reserve_matches_config() { selected_collators_number: 5, total_balance: 130, }, - Event::Rewarded { account: 1, rewards: 20 }, - Event::Rewarded { account: 7, rewards: 4 }, - Event::Rewarded { account: 10, rewards: 4 }, + Event::Rewarded { account: 1, rewards: 21 }, + Event::Rewarded { account: 7, rewards: 5 }, + Event::Rewarded { account: 10, rewards: 5 }, ]; expected.append(&mut new3); assert_eq_events!(expected.clone()); @@ -3533,7 +3533,7 @@ fn parachain_bond_inflation_reserve_matches_config() { roll_to(40); // no more paying 6 let mut new4 = vec![ - Event::ReservedForParachainBond { account: 11, value: 31 }, + Event::ReservedForParachainBond { account: 11, value: 32 }, Event::CollatorChosen { round: 9, collator_account: 1, total_exposed_amount: 40 }, Event::CollatorChosen { round: 9, collator_account: 2, total_exposed_amount: 40 }, Event::CollatorChosen { round: 9, collator_account: 3, total_exposed_amount: 20 }, @@ -3551,7 +3551,7 @@ fn parachain_bond_inflation_reserve_matches_config() { ]; expected.append(&mut new4); assert_eq_events!(expected.clone()); - assert_eq!(Balances::free_balance(&11), 126); + assert_eq!(Balances::free_balance(&11), 127); set_author(8, 1, 100); assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(8), 1, 10, 10, 10)); roll_to(45); @@ -3581,7 +3581,7 @@ fn parachain_bond_inflation_reserve_matches_config() { ]; expected.append(&mut new5); assert_eq_events!(expected.clone()); - assert_eq!(Balances::free_balance(&11), 159); + assert_eq!(Balances::free_balance(&11), 160); set_author(9, 1, 100); set_author(10, 1, 100); roll_to(50); @@ -3605,11 +3605,11 @@ fn parachain_bond_inflation_reserve_matches_config() { ]; expected.append(&mut new6); assert_eq_events!(expected.clone()); - assert_eq!(Balances::free_balance(&11), 194); + assert_eq!(Balances::free_balance(&11), 195); roll_to(55); // new delegation is rewarded, 2 rounds after joining (`RewardPaymentDelay` is 2) let mut new7 = vec![ - Event::ReservedForParachainBond { account: 11, value: 36 }, + Event::ReservedForParachainBond { account: 11, value: 37 }, Event::CollatorChosen { round: 12, collator_account: 1, total_exposed_amount: 50 }, Event::CollatorChosen { round: 12, collator_account: 2, total_exposed_amount: 40 }, Event::CollatorChosen { round: 12, collator_account: 3, total_exposed_amount: 20 }, @@ -3628,7 +3628,7 @@ fn parachain_bond_inflation_reserve_matches_config() { ]; expected.append(&mut new7); assert_eq_events!(expected); - assert_eq!(Balances::free_balance(&11), 230); + assert_eq!(Balances::free_balance(&11), 232); }); } @@ -4407,9 +4407,9 @@ fn payouts_follow_delegation_changes() { selected_collators_number: 5, total_balance: 130, }, - Event::Rewarded { account: 1, rewards: 30 }, - Event::Rewarded { account: 7, rewards: 9 }, - Event::Rewarded { account: 10, rewards: 9 }, + Event::Rewarded { account: 1, rewards: 35 }, + Event::Rewarded { account: 7, rewards: 11 }, + Event::Rewarded { account: 10, rewards: 11 }, Event::CollatorChosen { round: 8, collator_account: 1, total_exposed_amount: 40 }, Event::CollatorChosen { round: 8, collator_account: 2, total_exposed_amount: 40 }, Event::CollatorChosen { round: 8, collator_account: 3, total_exposed_amount: 20 }, @@ -4421,9 +4421,9 @@ fn payouts_follow_delegation_changes() { selected_collators_number: 5, total_balance: 130, }, - Event::Rewarded { account: 1, rewards: 31 }, - Event::Rewarded { account: 7, rewards: 10 }, - Event::Rewarded { account: 10, rewards: 10 }, + Event::Rewarded { account: 1, rewards: 36 }, + Event::Rewarded { account: 7, rewards: 12 }, + Event::Rewarded { account: 10, rewards: 12 }, ]; expected.append(&mut new3); assert_eq_events!(expected.clone()); @@ -4443,8 +4443,8 @@ fn payouts_follow_delegation_changes() { total_balance: 130, }, Event::Rewarded { account: 1, rewards: 38 }, - Event::Rewarded { account: 7, rewards: 12 }, - Event::Rewarded { account: 10, rewards: 12 }, + Event::Rewarded { account: 7, rewards: 13 }, + Event::Rewarded { account: 10, rewards: 13 }, ]; expected.append(&mut new4); assert_eq_events!(expected.clone()); @@ -4470,7 +4470,7 @@ fn payouts_follow_delegation_changes() { selected_collators_number: 5, total_balance: 140, }, - Event::Rewarded { account: 1, rewards: 39 }, + Event::Rewarded { account: 1, rewards: 40 }, Event::Rewarded { account: 7, rewards: 13 }, Event::Rewarded { account: 10, rewards: 13 }, ]; @@ -4491,7 +4491,7 @@ fn payouts_follow_delegation_changes() { selected_collators_number: 5, total_balance: 140, }, - Event::Rewarded { account: 1, rewards: 41 }, + Event::Rewarded { account: 1, rewards: 42 }, Event::Rewarded { account: 7, rewards: 14 }, Event::Rewarded { account: 10, rewards: 14 }, ]; @@ -4512,7 +4512,7 @@ fn payouts_follow_delegation_changes() { selected_collators_number: 5, total_balance: 140, }, - Event::Rewarded { account: 1, rewards: 38 }, + Event::Rewarded { account: 1, rewards: 39 }, Event::Rewarded { account: 7, rewards: 12 }, Event::Rewarded { account: 10, rewards: 12 }, Event::Rewarded { account: 8, rewards: 12 }, @@ -5586,7 +5586,7 @@ fn test_delegator_scheduled_for_revoke_is_rewarded_for_previous_rounds_but_not_f roll_to_round_begin(4); assert_eq_last_events!( - vec![Event::::Rewarded { account: 1, rewards: 4 }], + vec![Event::::Rewarded { account: 1, rewards: 5 }], "delegator was rewarded unexpectedly" ); let collator_snapshot = AtStake::::get(Round::::get().current, 1); @@ -5596,7 +5596,7 @@ fn test_delegator_scheduled_for_revoke_is_rewarded_for_previous_rounds_but_not_f "collator snapshot's delegator count was reduced unexpectedly" ); assert_eq!( - 30, collator_snapshot.total, + 20, collator_snapshot.total, "collator snapshot's total was reduced unexpectedly", ); }); @@ -5632,7 +5632,7 @@ fn test_delegator_scheduled_for_revoke_is_rewarded_when_request_cancelled() { roll_to_round_begin(4); assert_eq_last_events!( - vec![Event::::Rewarded { account: 1, rewards: 4 }], + vec![Event::::Rewarded { account: 1, rewards: 5 }], "delegator was rewarded unexpectedly", ); let collator_snapshot = AtStake::::get(Round::::get().current, 1); @@ -5699,7 +5699,7 @@ fn test_delegator_scheduled_for_bond_decrease_is_rewarded_for_previous_rounds_bu roll_to_round_begin(4); assert_eq_last_events!( vec![ - Event::::Rewarded { account: 1, rewards: 3 }, + Event::::Rewarded { account: 1, rewards: 4 }, Event::::Rewarded { account: 2, rewards: 1 }, ], "delegator was rewarded unexpectedly" @@ -5711,7 +5711,7 @@ fn test_delegator_scheduled_for_bond_decrease_is_rewarded_for_previous_rounds_bu "collator snapshot's delegator count was reduced unexpectedly" ); assert_eq!( - 40, collator_snapshot.total, + 30, collator_snapshot.total, "collator snapshot's total was reduced unexpectedly", ); }); @@ -5752,7 +5752,7 @@ fn test_delegator_scheduled_for_bond_decrease_is_rewarded_when_request_cancelled roll_to_round_begin(4); assert_eq_last_events!( vec![ - Event::::Rewarded { account: 1, rewards: 3 }, + Event::::Rewarded { account: 1, rewards: 4 }, Event::::Rewarded { account: 2, rewards: 1 }, ], "delegator was rewarded unexpectedly", @@ -5814,7 +5814,7 @@ fn test_delegator_scheduled_for_leave_is_rewarded_for_previous_rounds_but_not_fo roll_to_round_begin(4); assert_eq_last_events!( - vec![Event::::Rewarded { account: 1, rewards: 4 },], + vec![Event::::Rewarded { account: 1, rewards: 5 },], "delegator was rewarded unexpectedly" ); let collator_snapshot = AtStake::::get(Round::::get().current, 1); @@ -5824,7 +5824,7 @@ fn test_delegator_scheduled_for_leave_is_rewarded_for_previous_rounds_but_not_fo "collator snapshot's delegator count was reduced unexpectedly" ); assert_eq!( - 30, collator_snapshot.total, + 20, collator_snapshot.total, "collator snapshot's total was reduced unexpectedly", ); }); @@ -5859,7 +5859,7 @@ fn test_delegator_scheduled_for_leave_is_rewarded_when_request_cancelled() { roll_to_round_begin(4); assert_eq_last_events!( - vec![Event::::Rewarded { account: 1, rewards: 4 },], + vec![Event::::Rewarded { account: 1, rewards: 5 },], "delegator was rewarded unexpectedly", ); let collator_snapshot = AtStake::::get(Round::::get().current, 1); diff --git a/pallets/parachain-staking/src/types.rs b/pallets/parachain-staking/src/types.rs index e7b933f57..c8c2b1802 100644 --- a/pallets/parachain-staking/src/types.rs +++ b/pallets/parachain-staking/src/types.rs @@ -34,6 +34,11 @@ use crate::{ COLLATOR_LOCK_ID, DELEGATOR_LOCK_ID, }; +pub struct CountedDelegations { + pub uncounted_stake: BalanceOf, + pub rewardable_delegations: Vec>>, +} + #[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct Bond { pub owner: AccountId, diff --git a/pallets/slp/src/mocks/mock.rs b/pallets/slp/src/mocks/mock.rs index 4495ad6be..47a728994 100644 --- a/pallets/slp/src/mocks/mock.rs +++ b/pallets/slp/src/mocks/mock.rs @@ -41,10 +41,9 @@ use frame_system::{EnsureRoot, EnsureSignedBy}; use orml_traits::{location::RelativeReserveProvider, parameter_type_with_key}; use parity_scale_codec::{Decode, Encode}; use sp_core::{bounded::BoundedVec, hashing::blake2_256, ConstU32}; -pub use sp_runtime::Perbill; use sp_runtime::{ traits::{AccountIdConversion, Convert, IdentityLookup, TrailingZeroInput}, - AccountId32, BuildStorage, Percent, + AccountId32, BuildStorage, }; use sp_std::{boxed::Box, vec::Vec}; use xcm::v3::{prelude::*, MultiLocation, Weight}; @@ -216,7 +215,6 @@ impl bifrost_vtoken_minting::Config for Runtime { parameter_types! { pub const MinBlocksPerRound: u32 = 3; - pub const DefaultBlocksPerRound: u32 = 5; pub const LeaveCandidatesDelay: u32 = 2; pub const CandidateBondLessDelay: u32 = 2; pub const LeaveDelegatorsDelay: u32 = 2; @@ -227,8 +225,6 @@ parameter_types! { pub const MaxTopDelegationsPerCandidate: u32 = 4; pub const MaxBottomDelegationsPerCandidate: u32 = 4; pub const MaxDelegationsPerDelegator: u32 = 4; - pub const DefaultCollatorCommission: Perbill = Perbill::from_percent(20); - pub const DefaultParachainBondReservePercent: Percent = Percent::from_percent(30); pub const MinCollatorStk: u128 = 10; pub const MinDelegatorStk: u128 = 5; pub const MinDelegation: u128 = 3; @@ -242,7 +238,6 @@ impl bifrost_parachain_staking::Config for Runtime { type Currency = Balances; type MonetaryGovernanceOrigin = frame_system::EnsureRoot; type MinBlocksPerRound = MinBlocksPerRound; - type DefaultBlocksPerRound = DefaultBlocksPerRound; type LeaveCandidatesDelay = LeaveCandidatesDelay; type CandidateBondLessDelay = CandidateBondLessDelay; type LeaveDelegatorsDelay = LeaveDelegatorsDelay; @@ -253,8 +248,6 @@ impl bifrost_parachain_staking::Config for Runtime { type MaxTopDelegationsPerCandidate = MaxTopDelegationsPerCandidate; type MaxBottomDelegationsPerCandidate = MaxBottomDelegationsPerCandidate; type MaxDelegationsPerDelegator = MaxDelegationsPerDelegator; - type DefaultCollatorCommission = DefaultCollatorCommission; - type DefaultParachainBondReservePercent = DefaultParachainBondReservePercent; type MinCollatorStk = MinCollatorStk; type MinCandidateStk = MinCollatorStk; type MinDelegatorStk = MinDelegatorStk; diff --git a/pallets/slp/src/mocks/mock_kusama.rs b/pallets/slp/src/mocks/mock_kusama.rs index adb01aa24..141e0c1b8 100644 --- a/pallets/slp/src/mocks/mock_kusama.rs +++ b/pallets/slp/src/mocks/mock_kusama.rs @@ -43,10 +43,9 @@ use hex_literal::hex; use orml_traits::{location::RelativeReserveProvider, parameter_type_with_key}; use parity_scale_codec::{Decode, Encode}; use sp_core::{bounded::BoundedVec, hashing::blake2_256}; -pub use sp_runtime::Perbill; use sp_runtime::{ traits::{AccountIdConversion, Convert, TrailingZeroInput}, - AccountId32, BuildStorage, Percent, + AccountId32, BuildStorage, }; use sp_std::{boxed::Box, vec::Vec}; use xcm::v3::{prelude::*, Weight}; @@ -272,7 +271,6 @@ impl bifrost_vtoken_minting::Config for Runtime { parameter_types! { pub const MinBlocksPerRound: u32 = 3; - pub const DefaultBlocksPerRound: u32 = 5; pub const LeaveCandidatesDelay: u32 = 2; pub const CandidateBondLessDelay: u32 = 2; pub const LeaveDelegatorsDelay: u32 = 2; @@ -283,8 +281,6 @@ parameter_types! { pub const MaxTopDelegationsPerCandidate: u32 = 4; pub const MaxBottomDelegationsPerCandidate: u32 = 4; pub const MaxDelegationsPerDelegator: u32 = 4; - pub const DefaultCollatorCommission: Perbill = Perbill::from_percent(20); - pub const DefaultParachainBondReservePercent: Percent = Percent::from_percent(30); pub const MinCollatorStk: u128 = 10; pub const MinDelegatorStk: u128 = 5; pub const MinDelegation: u128 = 3; @@ -298,7 +294,6 @@ impl bifrost_parachain_staking::Config for Runtime { type Currency = Balances; type MonetaryGovernanceOrigin = frame_system::EnsureRoot; type MinBlocksPerRound = MinBlocksPerRound; - type DefaultBlocksPerRound = DefaultBlocksPerRound; type LeaveCandidatesDelay = LeaveCandidatesDelay; type CandidateBondLessDelay = CandidateBondLessDelay; type LeaveDelegatorsDelay = LeaveDelegatorsDelay; @@ -309,8 +304,6 @@ impl bifrost_parachain_staking::Config for Runtime { type MaxTopDelegationsPerCandidate = MaxTopDelegationsPerCandidate; type MaxBottomDelegationsPerCandidate = MaxBottomDelegationsPerCandidate; type MaxDelegationsPerDelegator = MaxDelegationsPerDelegator; - type DefaultCollatorCommission = DefaultCollatorCommission; - type DefaultParachainBondReservePercent = DefaultParachainBondReservePercent; type MinCollatorStk = MinCollatorStk; type MinCandidateStk = MinCollatorStk; type MinDelegatorStk = MinDelegatorStk; diff --git a/runtime/bifrost-kusama/src/lib.rs b/runtime/bifrost-kusama/src/lib.rs index b25e34213..d697fe916 100644 --- a/runtime/bifrost-kusama/src/lib.rs +++ b/runtime/bifrost-kusama/src/lib.rs @@ -878,8 +878,6 @@ impl cumulus_pallet_aura_ext::Config for Runtime {} parameter_types! { /// Minimum round length is 2 minutes (10 * 12 second block times) pub const MinBlocksPerRound: u32 = 10; - /// Blocks per round - pub const DefaultBlocksPerRound: u32 = prod_or_fast!(2 * HOURS, 10); /// Rounds before the collator leaving the candidates request can be executed pub const LeaveCandidatesDelay: u32 = 84; /// Rounds before the candidate bond increase/decrease can be executed @@ -900,10 +898,6 @@ parameter_types! { pub const MaxBottomDelegationsPerCandidate: u32 = 50; /// Maximum delegations per delegator pub const MaxDelegationsPerDelegator: u32 = 100; - /// Default fixed percent a collator takes off the top of due rewards - pub const DefaultCollatorCommission: Perbill = Perbill::from_percent(10); - /// Default percent of inflation set aside for parachain bond every round - pub const DefaultParachainBondReservePercent: Percent = Percent::from_percent(0); /// Minimum stake required to become a collator pub MinCollatorStk: u128 = 5000 * BNCS; /// Minimum stake required to be reserved to be a candidate @@ -928,7 +922,6 @@ impl bifrost_parachain_staking::Config for Runtime { type Currency = Balances; type MonetaryGovernanceOrigin = TechAdminOrCouncil; type MinBlocksPerRound = MinBlocksPerRound; - type DefaultBlocksPerRound = DefaultBlocksPerRound; type LeaveCandidatesDelay = LeaveCandidatesDelay; type CandidateBondLessDelay = CandidateBondLessDelay; type LeaveDelegatorsDelay = LeaveDelegatorsDelay; @@ -939,8 +932,6 @@ impl bifrost_parachain_staking::Config for Runtime { type MaxTopDelegationsPerCandidate = MaxTopDelegationsPerCandidate; type MaxBottomDelegationsPerCandidate = MaxBottomDelegationsPerCandidate; type MaxDelegationsPerDelegator = MaxDelegationsPerDelegator; - type DefaultCollatorCommission = DefaultCollatorCommission; - type DefaultParachainBondReservePercent = DefaultParachainBondReservePercent; type MinCollatorStk = MinCollatorStk; type MinCandidateStk = MinCandidateStk; type MinDelegation = MinDelegatorStk; From c6f72d51ec793b7df98a1166ff3b554bf541d80c Mon Sep 17 00:00:00 2001 From: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Date: Tue, 15 Oct 2024 09:56:34 +0800 Subject: [PATCH 20/30] Optimize system-staking pallet. (#1461) * Optimize system-staking pallet. * change unwrap_or_default to unwrap --- pallets/system-staking/src/benchmarking.rs | 16 +- pallets/system-staking/src/lib.rs | 138 +++++++++++---- pallets/system-staking/src/migrations/mod.rs | 19 +++ pallets/system-staking/src/migrations/v1.rs | 130 ++++++++++++++ pallets/system-staking/src/mock.rs | 5 +- pallets/system-staking/src/tests.rs | 169 ++++++++++++++++++- pallets/system-staking/src/types.rs | 76 ++++++--- runtime/bifrost-kusama/src/lib.rs | 1 + runtime/bifrost-polkadot/src/lib.rs | 1 + 9 files changed, 492 insertions(+), 63 deletions(-) create mode 100644 pallets/system-staking/src/migrations/mod.rs create mode 100644 pallets/system-staking/src/migrations/v1.rs diff --git a/pallets/system-staking/src/benchmarking.rs b/pallets/system-staking/src/benchmarking.rs index ab8dc86c4..d40ef8b1a 100644 --- a/pallets/system-staking/src/benchmarking.rs +++ b/pallets/system-staking/src/benchmarking.rs @@ -35,7 +35,7 @@ benchmarks! { assert_ok!(SystemStaking::::token_config( RawOrigin::Root.into(), KSM, - Some(1), + Some(BlockNumberFor::::from(1u32)), Some(Permill::from_percent(80)), Some(false), Some(BalanceOf::::unique_saturated_from(1000u128)), @@ -45,7 +45,7 @@ benchmarks! { assert_ok!(SystemStaking::::token_config( RawOrigin::Root.into(), MOVR, - Some(2), + Some(BlockNumberFor::::from(2u32)), Some(Permill::from_percent(80)), Some(false), Some(BalanceOf::::unique_saturated_from(1000u128)), @@ -66,14 +66,14 @@ benchmarks! { const KSM: CurrencyId = CurrencyId::Token(TokenSymbol::KSM); let token_amount = BalanceOf::::unique_saturated_from(1000u128); let pool_id = PoolId::from(1u32); - }: _(RawOrigin::Root, KSM, Some(1), Some(Permill::from_percent(80)),Some(false),Some(token_amount),Some(vec![pool_id]),Some(vec![Perbill::from_percent(100)])) + }: _(RawOrigin::Root, KSM, Some(BlockNumberFor::::from(1u32)), Some(Permill::from_percent(80)),Some(false),Some(token_amount),Some(vec![pool_id]),Some(vec![Perbill::from_percent(100)])) refresh_token_info { const KSM: CurrencyId = CurrencyId::Token(TokenSymbol::KSM); assert_ok!(SystemStaking::::token_config( RawOrigin::Root.into(), KSM, - Some(1), + Some(BlockNumberFor::::from(1u32)), Some(Permill::from_percent(80)), Some(false), Some(BalanceOf::::unique_saturated_from(1000u128)), @@ -87,7 +87,7 @@ benchmarks! { assert_ok!(SystemStaking::::token_config( RawOrigin::Root.into(), KSM, - Some(1), + Some(BlockNumberFor::::from(1u32)), Some(Permill::from_percent(80)), Some(false), Some(BalanceOf::::unique_saturated_from(1000u128)), @@ -104,7 +104,7 @@ benchmarks! { assert_ok!(SystemStaking::::token_config( RawOrigin::Root.into(), KSM, - Some(1), + Some(BlockNumberFor::::from(1u32)), Some(Permill::from_percent(80)), Some(false), Some(BalanceOf::::unique_saturated_from(1000u128)), @@ -120,7 +120,7 @@ benchmarks! { assert_ok!(SystemStaking::::token_config( RawOrigin::Root.into(), KSM, - Some(1), + Some(BlockNumberFor::::from(1u32)), Some(Permill::from_percent(80)), Some(false), Some(BalanceOf::::unique_saturated_from(1000u128)), @@ -137,7 +137,7 @@ benchmarks! { assert_ok!(SystemStaking::::token_config( RawOrigin::Root.into(), KSM, - Some(1), + Some(BlockNumberFor::::from(1u32)), Some(Permill::from_percent(80)), Some(false), Some(BalanceOf::::unique_saturated_from(1000u128)), diff --git a/pallets/system-staking/src/lib.rs b/pallets/system-staking/src/lib.rs index a496f8e4e..5a7cbd392 100644 --- a/pallets/system-staking/src/lib.rs +++ b/pallets/system-staking/src/lib.rs @@ -23,6 +23,7 @@ pub use weights::WeightInfo; use bifrost_primitives::{CurrencyId, FarmingInfo, PoolId, VtokenMintingInterface}; pub use frame_support::weights::Weight; use frame_support::{dispatch::DispatchResultWithPostInfo, traits::Get, PalletId}; +use frame_system::pallet_prelude::BlockNumberFor; use orml_traits::MultiCurrency; pub use pallet::*; use sp_runtime::{ @@ -41,6 +42,8 @@ mod tests; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +pub mod migrations; + pub type AccountIdOf = ::AccountId; pub type CurrencyIdOf = <::MultiCurrency as MultiCurrency< @@ -98,13 +101,18 @@ pub mod pallet { #[pallet::constant] type PalletId: Get; - /// 1500 + /// The number of blocks per round, as defined in the runtime. + /// + /// This value is set to 1500 in the runtime configuration. #[pallet::constant] type BlocksPerRound: Get; } + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] #[pallet::without_storage_info] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(PhantomData); /// Current Round Information @@ -113,8 +121,13 @@ pub mod pallet { /// The tokenInfo for each currency #[pallet::storage] - pub(crate) type TokenStatus = - StorageMap<_, Twox64Concat, CurrencyIdOf, TokenInfo>, OptionQuery>; + pub(crate) type TokenStatus = StorageMap< + _, + Twox64Concat, + CurrencyIdOf, + TokenInfo, BlockNumberFor>, + OptionQuery, + >; /// All token sets #[pallet::storage] @@ -124,20 +137,38 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - NewRound { - current: RoundIndex, - first: BlockNumberFor, - length: u32, - }, + /// A new staking round has started. + /// + /// - `current`: The index of the current round. + /// - `first`: The block number at which this round started. + /// - `length`: The length of the round in blocks. + NewRound { current: RoundIndex, first: BlockNumberFor, length: u32 }, + /// Configuration of a token has been changed. + /// + /// - `token`: The identifier of the token whose configuration changed. + /// - `exec_delay`: The delay in blocks before the changes take effect. + /// - `system_stakable_farming_rate`: The farming rate applied to system-stakable tokens. + /// - `add_or_sub`: Whether to add or subtract from the stakable farming rate. + /// - `system_stakable_base`: The base value of system-stakable assets. + /// - `farming_poolids`: List of pool IDs related to the token. + /// - `lptoken_rates`: List of rates for liquidity provider (LP) tokens. TokenConfigChanged { token: CurrencyIdOf, - exec_delay: u32, + exec_delay: BlockNumberFor, system_stakable_farming_rate: Permill, add_or_sub: bool, system_stakable_base: BalanceOf, - farming_poolids: Vec, - lptoken_rates: Vec, + farming_poolids: BoundedVec>, + lptoken_rates: BoundedVec>, }, + /// A deposit operation has failed. + /// + /// - `token`: The identifier of the token being deposited. + /// - `amount`: The amount of the token to be deposited. + /// - `farming_staking_amount`: The amount staked in the farming pool. + /// - `system_stakable_amount`: The amount staked in the system-stakable pool. + /// - `system_shadow_amount`: The amount shadow-staked in the system. + /// - `pending_redeem_amount`: The amount pending redemption. DepositFailed { token: CurrencyIdOf, amount: BalanceOf, @@ -146,6 +177,15 @@ pub mod pallet { system_shadow_amount: BalanceOf, pending_redeem_amount: BalanceOf, }, + + /// Minting operation succeeded. + /// + /// - `token`: The identifier of the token being minted. + /// - `amount`: The amount of the token to be minted. + /// - `farming_staking_amount`: The amount staked in the farming pool. + /// - `system_stakable_amount`: The amount staked in the system-stakable pool. + /// - `system_shadow_amount`: The amount shadow-staked in the system. + /// - `pending_redeem_amount`: The amount pending redemption. MintSuccess { token: CurrencyIdOf, amount: BalanceOf, @@ -154,6 +194,10 @@ pub mod pallet { system_shadow_amount: BalanceOf, pending_redeem_amount: BalanceOf, }, + /// Minting operation failed. + /// + /// # Parameters + /// (Same as MintSuccess) MintFailed { token: CurrencyIdOf, amount: BalanceOf, @@ -162,6 +206,10 @@ pub mod pallet { system_shadow_amount: BalanceOf, pending_redeem_amount: BalanceOf, }, + /// Withdrawal operation succeeded. + /// + /// # Parameters + /// (Same as MintSuccess) WithdrawSuccess { token: CurrencyIdOf, amount: BalanceOf, @@ -170,6 +218,10 @@ pub mod pallet { system_shadow_amount: BalanceOf, pending_redeem_amount: BalanceOf, }, + /// Withdrawal operation failed. + /// + /// # Parameters + /// (Same as MintSuccess) WithdrawFailed { token: CurrencyIdOf, amount: BalanceOf, @@ -178,6 +230,11 @@ pub mod pallet { system_shadow_amount: BalanceOf, pending_redeem_amount: BalanceOf, }, + + /// A redemption operation has succeeded. + /// + /// # Parameters + /// (Same as MintSuccess) Redeemed { token: CurrencyIdOf, amount: BalanceOf, @@ -186,6 +243,10 @@ pub mod pallet { system_shadow_amount: BalanceOf, pending_redeem_amount: BalanceOf, }, + /// A redemption operation has failed. + /// + /// # Parameters + /// (Same as MintSuccess) RedeemFailed { token: CurrencyIdOf, amount: BalanceOf, @@ -194,12 +255,24 @@ pub mod pallet { system_shadow_amount: BalanceOf, pending_redeem_amount: BalanceOf, }, - VtokenNotFound { - token: CurrencyIdOf, - }, - TokenInfoRefreshed { - token: CurrencyIdOf, - }, + /// The specified token could not be found. + /// + /// - `token`: The identifier of the token that was not found. + VtokenNotFound { token: CurrencyIdOf }, + /// Token information has been refreshed. + /// + /// - `token`: The identifier of the token whose information was refreshed. + TokenInfoRefreshed { token: CurrencyIdOf }, + /// A payout has been made. + /// + /// - `token`: The identifier of the token involved in the payout. + /// - `vtoken`: The identifier of the vtoken involved. + /// - `from`: The account from which the payout originated. + /// - `to`: The account to which the payout was made. + /// - `amount`: The total amount of the payout. + /// - `free`: The amount of free balance after the payout. + /// - `vfree`: The amount of vtoken free balance after the payout. + /// - `shadow`: The shadow balance after the payout. Payout { token: CurrencyIdOf, vtoken: CurrencyIdOf, @@ -224,6 +297,8 @@ pub mod pallet { TokenInfoNotFound, /// payout error PayoutFailed, + /// Error converting Vec to BoundedVec. + ConversionError, } #[pallet::hooks] @@ -296,7 +371,7 @@ pub mod pallet { pub fn token_config( origin: OriginFor, token: CurrencyIdOf, - exec_delay: Option, // TODO: blocknum + exec_delay: Option>, system_stakable_farming_rate: Option, add_or_sub: Option, system_stakable_base: Option>, @@ -311,7 +386,7 @@ pub mod pallet { state } else { new_token = true; - >>::default() + , BlockNumberFor>>::default() }; // Set token_info.new_config @@ -319,16 +394,12 @@ pub mod pallet { // Set token_info.new_config.exec_delay = exec_delay if let Some(exec_delay) = exec_delay { - ensure!(exec_delay != 0, Error::::InvalidTokenConfig); + ensure!(!exec_delay.is_zero(), Error::::InvalidTokenConfig); token_info.new_config.exec_delay = exec_delay; } // Set token_info.new_config.system_stakable_farming_rate = system_stakable_farming_rate if let Some(system_stakable_farming_rate) = system_stakable_farming_rate { - ensure!( - system_stakable_farming_rate >= Permill::zero(), - Error::::InvalidTokenConfig - ); token_info.new_config.system_stakable_farming_rate = system_stakable_farming_rate; } @@ -349,7 +420,9 @@ pub mod pallet { farming_poolids.len() as u32 <= T::MaxFarmingPoolIdLen::get(), Error::::ExceedMaxFarmingPoolidLen ); - token_info.new_config.farming_poolids = farming_poolids.clone(); + token_info.new_config.farming_poolids = + BoundedVec::try_from(farming_poolids.clone()) + .map_err(|_| Error::::ConversionError)?; } // Set token_info.new_config.lptoken_rates = lptoken_rates @@ -359,7 +432,8 @@ pub mod pallet { lptoken_rates.len() as u32 <= T::MaxFarmingPoolIdLen::get(), Error::::ExceedMaxFarmingPoolidLen ); - token_info.new_config.lptoken_rates = lptoken_rates.clone(); + token_info.new_config.lptoken_rates = BoundedVec::try_from(lptoken_rates.clone()) + .map_err(|_| Error::::ConversionError)?; } // Update token info @@ -487,7 +561,7 @@ pub mod pallet { impl Pallet { fn process_token_info( account: AccountIdOf, - mut token_info: TokenInfo>, + mut token_info: TokenInfo, BlockNumberFor>, token_id: CurrencyIdOf, ) -> DispatchResultWithPostInfo { // Query farming info @@ -561,11 +635,9 @@ impl Pallet { system_shadow_amount: token_info.system_shadow_amount, pending_redeem_amount: token_info.pending_redeem_amount, }); - } - // Check stakable_amount < (system_shadow_amount - pending_redeem_amount) ===> redeem vksm , // update pending_redeem_amount += token_amount - if stakable_amount < + } else if stakable_amount < token_info.system_shadow_amount.saturating_sub(token_info.pending_redeem_amount) { // redeem_amount = system_shadow_amount - pending_redeem_amount - stakable_amount @@ -589,7 +661,7 @@ impl Pallet { let new_token_info = if let Some(state) = >::get(&token_id) { state } else { - >>::default() + , BlockNumberFor>>::default() }; token_info.pending_redeem_amount = new_token_info.pending_redeem_amount; } @@ -618,7 +690,7 @@ impl Pallet { let mut token_info = if let Some(state) = >::get(&token_id) { state } else { - >>::default() + , BlockNumberFor>>::default() }; // pending_redeem_amount -= token_amount @@ -682,7 +754,7 @@ impl Pallet { let mut token_info = if let Some(state) = >::get(&token_id) { state } else { - >>::default() + , BlockNumberFor>>::default() }; // pending_redeem_amount += token_amount diff --git a/pallets/system-staking/src/migrations/mod.rs b/pallets/system-staking/src/migrations/mod.rs new file mode 100644 index 000000000..379d174c5 --- /dev/null +++ b/pallets/system-staking/src/migrations/mod.rs @@ -0,0 +1,19 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . + +pub mod v1; diff --git a/pallets/system-staking/src/migrations/v1.rs b/pallets/system-staking/src/migrations/v1.rs new file mode 100644 index 000000000..4468a16ae --- /dev/null +++ b/pallets/system-staking/src/migrations/v1.rs @@ -0,0 +1,130 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 crate::*; +use frame_support::{ + ensure, + pallet_prelude::StorageVersion, + traits::{GetStorageVersion, OnRuntimeUpgrade}, +}; +use parity_scale_codec::{Decode, Encode}; +#[cfg(feature = "try-runtime")] +use sp_runtime::TryRuntimeError; + +const LOG_TARGET: &str = "system-staking::migration"; + +pub struct MigrateToV1(sp_std::marker::PhantomData); +impl OnRuntimeUpgrade for MigrateToV1 { + fn on_runtime_upgrade() -> frame_support::weights::Weight { + // Check the storage version + let onchain_version = Pallet::::on_chain_storage_version(); + if onchain_version < 1 { + // Transform storage values + // We transform the storage values from the old into the new format. + log::info!(target: LOG_TARGET, "Start to migrate TokenStatus storage..."); + TokenStatus::::translate::, BlockNumberFor>, _>( + |k: CurrencyId, old_token_info: TokenInfo, BlockNumberFor>| { + log::info!(target: LOG_TARGET, "Migrated to boundedvec for {:?}...", k); + + let mut new_token_info = + , BlockNumberFor>>::default(); + + new_token_info.farming_staking_amount = old_token_info.farming_staking_amount; + new_token_info.system_stakable_amount = old_token_info.system_stakable_amount; + new_token_info.system_shadow_amount = old_token_info.system_shadow_amount; + new_token_info.pending_redeem_amount = old_token_info.pending_redeem_amount; + + new_token_info.current_config.exec_delay = + BlockNumberFor::::from(old_token_info.current_config.exec_delay); + new_token_info.current_config.system_stakable_farming_rate = + old_token_info.current_config.system_stakable_farming_rate; + new_token_info.current_config.lptoken_rates = + BoundedVec::try_from(old_token_info.current_config.lptoken_rates) + .map_err(|e| { log::error!("Failed to convert old current_config.lptoken_rates into BoundedVec during migration for {:?}: {:?}", k, e) }) + .unwrap(); + new_token_info.current_config.add_or_sub = + old_token_info.current_config.add_or_sub; + new_token_info.current_config.system_stakable_base = + old_token_info.current_config.system_stakable_base; + new_token_info.current_config.farming_poolids = + BoundedVec::try_from(old_token_info.current_config.farming_poolids) + .map_err(|e| { log::error!("Failed to convert old current_config.farming_poolids into BoundedVec during migration for {:?}: {:?}", k, e) }) + .unwrap(); + + new_token_info.new_config.exec_delay = + BlockNumberFor::::from(old_token_info.new_config.exec_delay); + new_token_info.new_config.system_stakable_farming_rate = + old_token_info.new_config.system_stakable_farming_rate; + new_token_info.new_config.lptoken_rates = + BoundedVec::try_from(old_token_info.new_config.lptoken_rates) + .map_err(|e| { log::error!("Failed to convert old new_config.lptoken_rates into BoundedVec during migration for {:?}: {:?}", k, e) }) + .unwrap(); + new_token_info.new_config.add_or_sub = old_token_info.new_config.add_or_sub; + new_token_info.new_config.system_stakable_base = + old_token_info.new_config.system_stakable_base; + new_token_info.new_config.farming_poolids = + BoundedVec::try_from(old_token_info.new_config.farming_poolids) + .map_err(|e| { log::error!("Failed to convert old new_config.farming_poolids into BoundedVec during migration for {:?}: {:?}", k, e) }) + .unwrap(); + + Some(new_token_info) + }, + ); + + // Update the storage version + StorageVersion::new(1).put::>(); + + // Return the consumed weight + let count = TokenStatus::::iter().count(); + Weight::from(T::DbWeight::get().reads_writes(count as u64 + 1, count as u64 + 1)) + } else { + // We don't do anything here. + Weight::zero() + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + let cnt = TokenStatus::::iter().count(); + // print out the pre-migrate storage count + log::info!(target: LOG_TARGET, "TokenStatus pre-migrate storage count: {:?}", cnt); + Ok((cnt as u64).encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(cnt: Vec) -> Result<(), TryRuntimeError> { + let new_count = TokenStatus::::iter().count(); + + let old_count: u64 = Decode::decode(&mut cnt.as_slice()) + .expect("the state parameter should be something that was generated by pre_upgrade"); + + // print out the post-migrate storage count + log::info!( + target: LOG_TARGET, + "TokenStatus post-migrate storage count: {:?}", + new_count + ); + + ensure!( + new_count as u64 == old_count, + "Post-migration storage count does not match pre-migration count" + ); + + Ok(()) + } +} diff --git a/pallets/system-staking/src/mock.rs b/pallets/system-staking/src/mock.rs index a50e2f26a..dbb3fd60a 100644 --- a/pallets/system-staking/src/mock.rs +++ b/pallets/system-staking/src/mock.rs @@ -38,7 +38,7 @@ use frame_system::{EnsureRoot, EnsureSignedBy}; use orml_traits::{location::RelativeReserveProvider, parameter_type_with_key}; use sp_core::ConstU32; use sp_runtime::{ - traits::{ConvertInto, IdentityLookup}, + traits::{AccountIdConversion, ConvertInto, IdentityLookup}, AccountId32, BuildStorage, }; use sp_std::vec; @@ -47,6 +47,7 @@ use xcm_builder::{FixedWeightBounds, FrameTransactionalProcessor}; use xcm_executor::XcmExecutor; use crate as system_staking; +use crate::Config; pub type BlockNumber = u64; pub type Amount = i128; @@ -407,6 +408,7 @@ impl ExtBuilder { } pub fn one_hundred_for_alice_n_bob(self) -> Self { + let pallet_account = ::PalletId::get().into_account_truncating(); self.balances(vec![ (ALICE, BNC, 100), (BOB, BNC, 100), @@ -417,6 +419,7 @@ impl ExtBuilder { (BOB, VKSM, 1000), (BOB, KSM, 10000000000), (BOB, MOVR, 1000000000000000000000), + (pallet_account, VKSM, 100), ]) } diff --git a/pallets/system-staking/src/tests.rs b/pallets/system-staking/src/tests.rs index 75544e3ba..cabff83e5 100644 --- a/pallets/system-staking/src/tests.rs +++ b/pallets/system-staking/src/tests.rs @@ -21,7 +21,7 @@ use bifrost_asset_registry::AssetMetadata; use bifrost_primitives::{TimeUnit, TokenInfo, VtokenMintingOperator}; use bifrost_runtime_common::milli; use frame_support::{ - assert_ok, + assert_noop, assert_ok, sp_runtime::{Perbill, Permill}, }; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; @@ -32,7 +32,7 @@ fn token_config_should_work() { assert_ok!(SystemStaking::token_config( RuntimeOrigin::root(), KSM, - Some(1), + Some(BlockNumberFor::::from(1u32)), Some(Permill::from_percent(80)), Some(false), Some(100), @@ -151,6 +151,171 @@ fn refresh_token_info_should_work() { }); } +#[test] +fn payout_should_work() { + ExtBuilder::default().one_hundred_for_alice_n_bob().build().execute_with(|| { + let (pid, _tokens) = init_farming_no_gauge(); + asset_registry(); + + assert_ok!(VtokenMinting::set_minimum_mint(RuntimeOrigin::signed(ALICE), KSM, 0)); + pub const FEE: Permill = Permill::from_percent(5); + assert_ok!(VtokenMinting::set_fees(RuntimeOrigin::root(), FEE, FEE)); + + assert_ok!(SystemStaking::token_config( + RuntimeOrigin::root(), + KSM, + Some(1), + Some(Permill::from_percent(80)), + Some(false), + Some(100), + Some(vec![pid]), + Some(vec![Perbill::from_percent(100)]), + )); + + assert_ok!(VtokenMinting::mint( + RuntimeOrigin::signed(ALICE), + KSM, + 1000, + BoundedVec::default(), + Some(0u32), + )); + + let pallet_account = ::PalletId::get().into_account_truncating(); + + let pallet_vfree_balance = Currencies::free_balance(VKSM, &pallet_account); + assert_eq!(pallet_vfree_balance, 100); + + assert_ok!(SystemStaking::payout(RuntimeOrigin::root(), KSM)); + + let pallet_vfree_balance = Currencies::free_balance(VKSM, &pallet_account); + assert_eq!(pallet_vfree_balance, 1); + + let treasury_balance = Currencies::free_balance(VKSM, &TreasuryAccount::get()); + assert_eq!(treasury_balance, 99); + }); +} + +#[test] +fn payout_should_fail() { + ExtBuilder::default().one_hundred_for_alice_n_bob().build().execute_with(|| { + asset_registry(); + + assert_ok!(VtokenMinting::set_minimum_mint(RuntimeOrigin::signed(ALICE), KSM, 0)); + pub const FEE: Permill = Permill::from_percent(5); + assert_ok!(VtokenMinting::set_fees(RuntimeOrigin::root(), FEE, FEE)); + + assert_ok!(VtokenMinting::mint( + RuntimeOrigin::signed(ALICE), + KSM, + 1000, + BoundedVec::default(), + Some(0u32), + )); + + assert_noop!( + SystemStaking::payout(RuntimeOrigin::root(), KSM), + Error::::TokenInfoNotFound + ); + }); +} + +#[test] +fn on_redeem_success_should_work() { + ExtBuilder::default().one_hundred_for_alice_n_bob().build().execute_with(|| { + asset_registry(); + + let pallet_account = ::PalletId::get().into_account_truncating(); + + let pallet_vfree_balance = Currencies::free_balance(VKSM, &pallet_account); + assert_eq!(pallet_vfree_balance, 100); + + SystemStaking::on_redeem_success(VKSM, pallet_account.clone(), 10); + + let pallet_vfree_balance = Currencies::free_balance(VKSM, &pallet_account); + assert_eq!(pallet_vfree_balance, 90); + let mut token_info = >::get(VKSM).unwrap(); + assert_eq!(token_info.pending_redeem_amount, 0); + assert_eq!(token_info.system_shadow_amount, 0); + + token_info.pending_redeem_amount = 100; + token_info.system_shadow_amount = 100; + >::insert(&VKSM, token_info.clone()); + assert_eq!(token_info.pending_redeem_amount, 100); + assert_eq!(token_info.system_shadow_amount, 100); + + SystemStaking::on_redeem_success(VKSM, pallet_account.clone(), 90); + + let pallet_vfree_balance = Currencies::free_balance(VKSM, &pallet_account); + assert_eq!(pallet_vfree_balance, 0); + let token_info = >::get(VKSM).unwrap(); + assert_eq!(token_info.pending_redeem_amount, 10); + assert_eq!(token_info.system_shadow_amount, 10); + }); +} + +#[test] +fn on_refund_should_work() { + ExtBuilder::default().one_hundred_for_alice_n_bob().build().execute_with(|| { + asset_registry(); + + let pallet_account = ::PalletId::get().into_account_truncating(); + + let pallet_vfree_balance = Currencies::free_balance(VKSM, &pallet_account); + assert_eq!(pallet_vfree_balance, 100); + + SystemStaking::on_refund(VKSM, pallet_account.clone(), 10); + + let pallet_vfree_balance = Currencies::free_balance(VKSM, &pallet_account); + assert_eq!(pallet_vfree_balance, 90); + let mut token_info = >::get(VKSM).unwrap(); + assert_eq!(token_info.pending_redeem_amount, 0); + assert_eq!(token_info.system_shadow_amount, 0); + + token_info.pending_redeem_amount = 100; + token_info.system_shadow_amount = 100; + >::insert(&VKSM, token_info.clone()); + assert_eq!(token_info.pending_redeem_amount, 100); + assert_eq!(token_info.system_shadow_amount, 100); + + SystemStaking::on_refund(VKSM, pallet_account.clone(), 90); + + let pallet_vfree_balance = Currencies::free_balance(VKSM, &pallet_account); + assert_eq!(pallet_vfree_balance, 0); + let token_info = >::get(VKSM).unwrap(); + assert_eq!(token_info.pending_redeem_amount, 10); + assert_eq!(token_info.system_shadow_amount, 10); + }); +} + +#[test] +fn on_redeemed_should_work() { + ExtBuilder::default().one_hundred_for_alice_n_bob().build().execute_with(|| { + asset_registry(); + + let pallet_account = ::PalletId::get().into_account_truncating(); + let pallet_vfree_balance = Currencies::free_balance(VKSM, &pallet_account); + assert_eq!(pallet_vfree_balance, 100); + + SystemStaking::on_redeemed(pallet_account.clone(), VKSM, 10, 0, 0); + + let pallet_vfree_balance = Currencies::free_balance(VKSM, &pallet_account); + assert_eq!(pallet_vfree_balance, 100); + let mut token_info = >::get(VKSM).unwrap(); + assert_eq!(token_info.pending_redeem_amount, 10); + + token_info.pending_redeem_amount = 100; + >::insert(&VKSM, token_info.clone()); + assert_eq!(token_info.pending_redeem_amount, 100); + + SystemStaking::on_redeemed(pallet_account.clone(), VKSM, 10, 0, 0); + + let pallet_vfree_balance = Currencies::free_balance(VKSM, &pallet_account); + assert_eq!(pallet_vfree_balance, 100); + let token_info = >::get(VKSM).unwrap(); + assert_eq!(token_info.pending_redeem_amount, 110); + }); +} + #[test] fn round_process_token() { ExtBuilder::default().one_hundred_for_alice_n_bob().build().execute_with(|| { diff --git a/pallets/system-staking/src/types.rs b/pallets/system-staking/src/types.rs index 08b7a64c4..d0ce95821 100644 --- a/pallets/system-staking/src/types.rs +++ b/pallets/system-staking/src/types.rs @@ -54,9 +54,9 @@ impl< } /// Check exec_delay match - pub fn check_delay(&self, now: B, delay: u32) -> bool { + pub fn check_delay(&self, now: B, delay: B) -> bool { //Current blockNumber - BlockNumber of Round Start == delay blockNumber ===> true - now - self.first == delay.into() && delay != 0 + now - self.first == delay && delay != 0.into() } } impl< @@ -69,7 +69,14 @@ impl< } #[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct TokenInfo { +pub struct TokenInfo< + Balance: Copy, + BlockNumber: Copy + + sp_std::ops::Add + + sp_std::ops::Sub + + From + + PartialOrd, +> { /// The number of token staking in Farming pub farming_staking_amount: Balance, /// token_config.system_stakable_farming_rate(100%) * farming_staking_amount(0) +/- @@ -80,25 +87,41 @@ pub struct TokenInfo { /// Number of pending redemptions pub pending_redeem_amount: Balance, /// Current TokenConfig - pub current_config: TokenConfig, + pub current_config: TokenConfig, /// New TokenConfig - pub new_config: TokenConfig, + pub new_config: TokenConfig, } -impl Default for TokenInfo { - fn default() -> TokenInfo { +impl< + Balance: Zero + Copy, + BlockNumber: Copy + + sp_std::ops::Add + + sp_std::ops::Sub + + From + + PartialOrd, + > Default for TokenInfo +{ + fn default() -> TokenInfo { TokenInfo { farming_staking_amount: Balance::zero(), system_stakable_amount: Balance::zero(), system_shadow_amount: Balance::zero(), pending_redeem_amount: Balance::zero(), - current_config: TokenConfig::::default(), - new_config: TokenConfig::::default(), + current_config: TokenConfig::::default(), + new_config: TokenConfig::::default(), } } } -impl TokenInfo { +impl< + Balance: Copy + PartialEq, + BlockNumber: Copy + + sp_std::ops::Add + + sp_std::ops::Sub + + From + + PartialOrd, + > TokenInfo +{ pub fn check_config_change(&self) -> bool { self.current_config != self.new_config } @@ -109,30 +132,45 @@ impl TokenInfo { } #[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct TokenConfig { +pub struct TokenConfig +where + BlockNumber: Copy + + sp_std::ops::Add + + sp_std::ops::Sub + + From + + PartialOrd, +{ /// Number of blocks with delayed execution - pub exec_delay: u32, + pub exec_delay: BlockNumber, /// 100 % pub system_stakable_farming_rate: Permill, /// - pub lptoken_rates: Vec, + pub lptoken_rates: BoundedVec>, /// true: add, false: sub , +/- token_config.system_stakable_base pub add_or_sub: bool, /// pub system_stakable_base: Balance, /// Farming pool ids - pub farming_poolids: Vec, + pub farming_poolids: BoundedVec>, } -impl Default for TokenConfig { - fn default() -> TokenConfig { +impl< + Balance: Zero, + BlockNumber: Copy + + sp_std::ops::Add + + sp_std::ops::Sub + + From + + PartialOrd, + > Default for TokenConfig +{ + fn default() -> TokenConfig { TokenConfig { - exec_delay: 0u32, + exec_delay: 0u32.into(), system_stakable_farming_rate: Permill::from_percent(0), - lptoken_rates: Vec::new(), + lptoken_rates: BoundedVec::default(), system_stakable_base: Balance::zero(), add_or_sub: true, // default add - farming_poolids: Vec::new(), + farming_poolids: BoundedVec::default(), } } } diff --git a/runtime/bifrost-kusama/src/lib.rs b/runtime/bifrost-kusama/src/lib.rs index d697fe916..a7ef423db 100644 --- a/runtime/bifrost-kusama/src/lib.rs +++ b/runtime/bifrost-kusama/src/lib.rs @@ -1905,6 +1905,7 @@ pub mod migrations { VSBondAuctionClearPalletId, frame_support::migrations::RemovePallet, frame_support::migrations::RemovePallet, + bifrost_system_staking::migrations::v1::MigrateToV1, ); } diff --git a/runtime/bifrost-polkadot/src/lib.rs b/runtime/bifrost-polkadot/src/lib.rs index 9bded4470..4f2431d13 100644 --- a/runtime/bifrost-polkadot/src/lib.rs +++ b/runtime/bifrost-polkadot/src/lib.rs @@ -1835,6 +1835,7 @@ pub mod migrations { bifrost_asset_registry::migrations::v1::MigrateToV1, bifrost_slpx::migration::v2::MigrateToV2, frame_support::migrations::RemovePallet, + bifrost_system_staking::migrations::v1::MigrateToV1, ); } From 3f0cf674560e862bc0a747a8aa347229f939cc8f Mon Sep 17 00:00:00 2001 From: yooml Date: Tue, 15 Oct 2024 09:58:15 +0800 Subject: [PATCH 21/30] =?UTF-8?q?fix:=20=F0=9F=90=9B=20for=20review=20(#14?= =?UTF-8?q?62)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pallets/farming/src/gauge.rs | 9 +++++ pallets/farming/src/lib.rs | 65 ++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/pallets/farming/src/gauge.rs b/pallets/farming/src/gauge.rs index 4827eed16..7062935e8 100644 --- a/pallets/farming/src/gauge.rs +++ b/pallets/farming/src/gauge.rs @@ -30,14 +30,23 @@ use crate::*; #[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo)] pub struct GaugeInfo { + /// Gauge pool controller pub who: AccountIdOf, + /// The amount of the user deposited in the gauge pool. pub gauge_amount: BalanceOf, + /// Total time factor pub total_time_factor: u128, + /// The latest time factor when the user deposit/withdraw. pub latest_time_factor: u128, + /// The time factor when the user claimed the rewards last time. pub claimed_time_factor: u128, + /// The block number when the pool started to gauge. pub gauge_start_block: BlockNumberFor, + /// The block number when the pool stopped to gauge. pub gauge_stop_block: BlockNumberFor, + /// The block number when the user deposit/withdraw last time. pub gauge_last_block: BlockNumberFor, + /// The block number when the user claimed the rewards last time. pub last_claim_block: BlockNumberFor, } diff --git a/pallets/farming/src/lib.rs b/pallets/farming/src/lib.rs index b86a75ea7..84fbac7f3 100644 --- a/pallets/farming/src/lib.rs +++ b/pallets/farming/src/lib.rs @@ -128,82 +128,137 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { + /// A farming pool is created. FarmingPoolCreated { + /// The pool id of the new pool. pid: PoolId, }, + /// The farming pool is reset. FarmingPoolReset { + /// The pool id of the pool to reset. pid: PoolId, }, + /// The farming pool is closed. FarmingPoolClosed { + /// The pool id of the pool to close. pid: PoolId, }, + /// The farming pool is killed. FarmingPoolKilled { + /// The pool id of the pool to kill. pid: PoolId, }, + /// The farming pool is edited. FarmingPoolEdited { + /// The pool id of the pool to edit. pid: PoolId, }, + /// The pool is charged. Charged { + /// The exchanger who charged the pool. who: AccountIdOf, + /// Charged pool id. pid: PoolId, + /// Charged rewards. rewards: Vec<(CurrencyIdOf, BalanceOf)>, + /// Returns true if the reward is for gauge pool, false otherwise. if_gauge: bool, }, + /// The pool is deposited. Deposited { + /// The exchanger who deposited the pool. who: AccountIdOf, + /// Deposited pool id. pid: PoolId, + /// Deposited value. add_value: BalanceOf, }, + /// The pool is withdrawn. Withdrawn { + /// The exchanger who withdrew the pool. who: AccountIdOf, + /// Withdrawn pool id. pid: PoolId, + /// Withdrawn value. remove_value: Option>, }, + /// The pool is claimed. Claimed { + /// The exchanger who claimed the pool. who: AccountIdOf, + /// Claimed pool id. pid: PoolId, }, + /// The pool is withdrawn claimed. WithdrawClaimed { + /// The exchanger who withdrew claimed the pool. who: AccountIdOf, + /// Withdraw claimed pool id. pid: PoolId, }, + /// The gauge pool is withdrawn. GaugeWithdrawn { + /// The exchanger who withdrew the gauge pool. who: AccountIdOf, + /// Withdrawn gauge pool id. gid: PoolId, }, + /// All gauge pools have been claimed. AllForceGaugeClaimed { + /// Last claimed gauge pool id. gid: PoolId, }, + /// Partially gauge pools have been claimed. PartiallyForceGaugeClaimed { + /// Last claimed gauge pool id. gid: PoolId, }, + /// All pools is retired. AllRetired { + /// Last retired pool id. pid: PoolId, }, + /// Partially pools is retired. PartiallyRetired { + /// Last retired pool id. pid: PoolId, }, + /// The retire limit is set. RetireLimitSet { + /// The retire limit. limit: u32, }, + /// The round has ended. RoundEnd { // voting_pools: BTreeMap>, total_votes: BalanceOf, + /// The start block of the round. start_round: BlockNumberFor, + /// The end block of the round. end_round: BlockNumberFor, }, + /// The round has started to fail. RoundStartError { + /// The error info: DispatchError, }, + /// The round has started. RoundStart { + /// The length of the round. round_length: BlockNumberFor, }, + /// The exchanger is voted. Voted { + /// The exchanger who voted. who: AccountIdOf, + /// Voted pool id. vote_list: Vec<(PoolId, Percent)>, }, + /// The boost pool is charged. BoostCharged { + /// The exchanger who charged the boost pool. who: AccountIdOf, + /// Charged boost pool id. rewards: Vec<(CurrencyIdOf, BalanceOf)>, }, } @@ -252,12 +307,15 @@ pub mod pallet { InvalidRemoveAmount, } + /// Record the id of the new pool. #[pallet::storage] pub type PoolNextId = StorageValue<_, PoolId, ValueQuery>; + /// Record the id of the new gauge pool. #[pallet::storage] pub type GaugePoolNextId = StorageValue<_, PoolId, ValueQuery>; + /// The upper limit of a single retirement pool #[pallet::storage] pub type RetireLimit = StorageValue<_, u32, ValueQuery>; @@ -283,6 +341,7 @@ pub mod pallet { GaugePoolInfo, CurrencyIdOf, AccountIdOf, BlockNumberFor>, >; + /// Record gauge config #[pallet::storage] pub type GaugeInfos = StorageDoubleMap< _, @@ -307,23 +366,29 @@ pub mod pallet { ShareInfo, CurrencyIdOf, BlockNumberFor, AccountIdOf>, >; + /// Record all voting pool information. #[pallet::storage] pub type BoostPoolInfos = StorageValue<_, BoostPoolInfo, BlockNumberFor>, ValueQuery>; + /// Record the voting pool id and the voting percentage of the user. #[pallet::storage] pub type UserBoostInfos = StorageMap<_, Blake2_128Concat, T::AccountId, UserBoostInfo>; + /// Record the pools which the user can voted for. #[pallet::storage] pub type BoostWhitelist = StorageMap<_, Twox64Concat, PoolId, ()>; + /// Record the pools which the user can voted for in the next round. #[pallet::storage] pub type BoostNextRoundWhitelist = StorageMap<_, Twox64Concat, PoolId, ()>; + /// Record the voting amount for each pool. #[pallet::storage] pub type BoostVotingPools = StorageMap<_, Twox64Concat, PoolId, BalanceOf>; + /// Voting rewards for corresponding currency. #[pallet::storage] pub type BoostBasicRewards = StorageDoubleMap<_, Twox64Concat, PoolId, Twox64Concat, CurrencyIdOf, BalanceOf>; From f1bf1c41347e929bd8d93411a463ef50dffe8f18 Mon Sep 17 00:00:00 2001 From: yooml Date: Tue, 15 Oct 2024 09:59:09 +0800 Subject: [PATCH 22/30] =?UTF-8?q?fix:=20=F0=9F=90=9B=20for=20review=20(#14?= =?UTF-8?q?63)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pallets/stable-asset/src/lib.rs | 154 +++++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 2 deletions(-) diff --git a/pallets/stable-asset/src/lib.rs b/pallets/stable-asset/src/lib.rs index 77d6e473a..8477985fc 100644 --- a/pallets/stable-asset/src/lib.rs +++ b/pallets/stable-asset/src/lib.rs @@ -41,7 +41,7 @@ use scale_info::TypeInfo; use sp_core::{U256, U512}; use sp_runtime::{ traits::{AccountIdConversion, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, One, Zero}, - DispatchError, SaturatedConversion, + ArithmeticError, DispatchError, SaturatedConversion, }; use sp_std::prelude::*; @@ -400,9 +400,11 @@ pub mod pallet { #[pallet::without_storage_info] pub struct Pallet(_); + /// The last pool id. #[pallet::storage] pub type PoolCount = StorageValue<_, StableAssetPoolId, ValueQuery>; + /// The pool info. #[pallet::storage] pub type Pools = StorageMap< _, @@ -417,6 +419,7 @@ pub mod pallet { >, >; + /// Price anchor used to bind the corresponding pool and currency. #[pallet::storage] pub type TokenRateCaches = StorageDoubleMap< _, @@ -427,193 +430,340 @@ pub mod pallet { (T::AtLeast64BitUnsigned, T::AtLeast64BitUnsigned), >; + /// Record the maximum percentage that can exceed the token rate. #[pallet::storage] pub type TokenRateHardcap = StorageMap<_, Twox64Concat, T::AssetId, Permill>; #[pallet::event] #[pallet::generate_deposit(pub fn deposit_event)] pub enum Event { + /// A new pool is created. CreatePool { + /// The pool id. pool_id: StableAssetPoolId, + /// Amplification coefficient of the pool. a: T::AtLeast64BitUnsigned, + /// The system account of the pool. swap_id: T::AccountId, + /// Pallet id. pallet_id: T::AccountId, }, + /// Liquidity is added to the pool. LiquidityAdded { + /// The account who added the liquidity. minter: T::AccountId, + /// The pool id. pool_id: StableAssetPoolId, + /// Amplification coefficient of the pool. a: T::AtLeast64BitUnsigned, + /// The input amounts of the assets. input_amounts: Vec, + /// Expected minimum output amount. min_output_amount: T::Balance, + /// Balances data. balances: Vec, + /// The total supply of the pool asset. total_supply: T::Balance, + /// fee amount of the pool asset. fee_amount: T::Balance, + /// Actual minimum output amount. output_amount: T::Balance, }, + /// Token is swapped. TokenSwapped { + /// The account who swapped the token. swapper: T::AccountId, + /// The pool id. pool_id: StableAssetPoolId, + /// Amplification coefficient of the pool. a: T::AtLeast64BitUnsigned, + /// The input asset type. input_asset: T::AssetId, + /// The output asset type. output_asset: T::AssetId, + /// The input amount of the input asset. input_amount: T::Balance, + /// The expected minimum output amount of the output asset. min_output_amount: T::Balance, + /// Balances data. balances: Vec, + /// The total supply of the pool asset. total_supply: T::Balance, + /// Actual output amount of the output asset. output_amount: T::Balance, }, + /// Token is redeemed by proportion. RedeemedProportion { + /// The account who redeemed the token. redeemer: T::AccountId, + /// The pool id. pool_id: StableAssetPoolId, + /// Amplification coefficient of the pool. a: T::AtLeast64BitUnsigned, + /// The input amount of the pool asset. input_amount: T::Balance, + /// The expected minimum output amounts of the assets. min_output_amounts: Vec, + /// Balances data. balances: Vec, + /// The total supply of the pool asset. total_supply: T::Balance, + /// fee amount of the pool asset. fee_amount: T::Balance, + /// Actual output amounts of the assets. output_amounts: Vec, }, + /// Token is redeemed by single asset. RedeemedSingle { + /// The account who redeemed the token. redeemer: T::AccountId, + /// The pool id. pool_id: StableAssetPoolId, + /// Amplification coefficient of the pool. a: T::AtLeast64BitUnsigned, + /// The input asset type. input_amount: T::Balance, + /// The output asset type. output_asset: T::AssetId, + /// The expected minimum output amount of the output asset. min_output_amount: T::Balance, + /// Balances data. balances: Vec, + /// The total supply of the pool asset. total_supply: T::Balance, + /// fee amount of the pool asset. fee_amount: T::Balance, + /// Actual output amount of the output asset. output_amount: T::Balance, }, + /// Token is redeemed by multiple assets. RedeemedMulti { + /// The account who redeemed the token. redeemer: T::AccountId, + /// The pool id. pool_id: StableAssetPoolId, + /// Amplification coefficient of the pool. a: T::AtLeast64BitUnsigned, + /// The expected output amounts. output_amounts: Vec, + /// The maximum input amount of the pool asset to get the output amounts. max_input_amount: T::Balance, + /// Balances data. balances: Vec, + /// The total supply of the pool asset. total_supply: T::Balance, + /// fee amount of the pool asset. fee_amount: T::Balance, + /// Actual input amount of the pool asset. input_amount: T::Balance, }, + /// The pool field balances is updated. BalanceUpdated { + /// The pool id. pool_id: StableAssetPoolId, + /// The old balances. old_balances: Vec, + /// The new balances. new_balances: Vec, }, + /// Yield is collected. YieldCollected { + /// The pool id. pool_id: StableAssetPoolId, + /// Amplification coefficient of the pool. a: T::AtLeast64BitUnsigned, + /// The old total supply of the pool asset. old_total_supply: T::Balance, + /// The new total supply of the pool asset. new_total_supply: T::Balance, + /// The account who collected the yield. who: T::AccountId, + /// The amount of the pool asset collected. amount: T::Balance, }, + /// Fee is collected. FeeCollected { + /// The pool id. pool_id: StableAssetPoolId, + /// Amplification coefficient of the pool. a: T::AtLeast64BitUnsigned, + /// The old balances. old_balances: Vec, + /// The new balances. new_balances: Vec, + /// The old total supply of the pool asset. old_total_supply: T::Balance, + /// The new total supply of the pool asset. new_total_supply: T::Balance, + /// The account who has been collected the fee. who: T::AccountId, + /// The fee amount of the pool asset. amount: T::Balance, }, + /// The pool amplification coefficient is modified. AModified { + /// The pool id. pool_id: StableAssetPoolId, + /// The new amplification coefficient. value: T::AtLeast64BitUnsigned, + /// The block number when the new amplification coefficient will be effective. time: BlockNumberFor, }, + /// The pool fees are modified. FeeModified { + /// The pool id. pool_id: StableAssetPoolId, + /// The new mint fee. mint_fee: T::AtLeast64BitUnsigned, + /// The new swap fee. swap_fee: T::AtLeast64BitUnsigned, + /// The new redeem fee. redeem_fee: T::AtLeast64BitUnsigned, }, + /// The pool recipients are modified. RecipientModified { + /// The pool id. pool_id: StableAssetPoolId, + /// The new fee recipient. fee_recipient: T::AccountId, + /// The new yield recipient. yield_recipient: T::AccountId, }, + /// The token rate is set. TokenRateSet { + /// The pool id. pool_id: StableAssetPoolId, + /// The token rate info[(currency_id, (denominator, numerator))]. token_rate: Vec<(T::AssetId, (T::AtLeast64BitUnsigned, T::AtLeast64BitUnsigned))>, }, + /// The hardcap of the token rate is configured. TokenRateHardcapConfigured { + /// The token type. vtoken: T::AssetId, + /// The hardcap of the token rate. hardcap: Permill, }, + /// The hardcap of the token rate is removed. TokenRateHardcapRemoved { + /// The token type. vtoken: T::AssetId, }, + /// The token rate is refreshed. TokenRateRefreshFailed { + /// The pool id. pool_id: StableAssetPoolId, }, } #[pallet::error] pub enum Error { + /// The pool is existed, cannot create again. InconsistentStorage, + /// The pool asset is invalid. InvalidPoolAsset, + /// The arguments are mismatch, not match the expected length. ArgumentsMismatch, + /// The arguments are error. ArgumentsError, + /// The pool is not found, cannot modify. PoolNotFound, + /// make mistakes in calculation. Math, + /// The new invariant of the pool is invalid. InvalidPoolValue, + /// The actual output amount is less than the expected minimum output amount when add + /// liquidity. MintUnderMin, + /// The actual output amount is less than the expected minimum output amount when swap. SwapUnderMin, + /// The actual output amount is less than the expected minimum output amount when redeem. RedeemUnderMin, + /// The actual input amount is more than the expected maximum input amount when redeem + /// multi. RedeemOverMax, + /// The old token rate is not cleared. TokenRateNotCleared, } + /// The add liquidity result. #[derive(Encode, Decode, Clone, Default, PartialEq, Eq, Debug)] pub struct MintResult { + /// The amount of the pool asset that the user will get. pub mint_amount: T::Balance, + /// The fee amount of the pool asset that the user will pay. pub fee_amount: T::Balance, + /// The balances data. pub balances: Vec, + /// The total supply of the pool asset. pub total_supply: T::Balance, } + /// The swap result. #[derive(Encode, Decode, Clone, Default, PartialEq, Eq, Debug)] pub struct SwapResult { + /// the input amount. pub dx: Balance, + /// the output amount. pub dy: Balance, + /// the output amount in balances field. pub y: Balance, + /// the input amount in balances field. pub balance_i: Balance, } + /// The redeem proportion result. #[derive(Encode, Decode, Clone, Default, PartialEq, Eq, Debug)] pub struct RedeemProportionResult { + /// The amounts of the assets that the user will get. pub amounts: Vec, + /// Balances data. pub balances: Vec, + /// The fee amount of the pool asset that the user will pay. pub fee_amount: Balance, + /// The total supply of the pool asset. pub total_supply: Balance, + /// The amount of the pool asset that the user want to redeem. pub redeem_amount: Balance, } + /// The redeem single result. #[derive(Encode, Decode, Clone, Default, PartialEq, Eq, Debug)] pub struct RedeemSingleResult { + /// The amount of the token index i that the user will get. pub dy: T::Balance, + /// The fee amount of the pool asset that the user will pay. pub fee_amount: T::Balance, + /// The total supply of the pool asset. pub total_supply: T::Balance, + /// The balances data. pub balances: Vec, + /// The amount of the pool asset that the user want to redeem. pub redeem_amount: T::Balance, } + /// The redeem multi result. #[derive(Encode, Decode, Clone, Default, PartialEq, Eq, Debug)] pub struct RedeemMultiResult { + /// The amount of the pool asset that the user should redeemed. pub redeem_amount: T::Balance, + /// The fee amount of the pool asset that the user will pay. pub fee_amount: T::Balance, + /// The balances data. pub balances: Vec, + /// The total supply of the pool asset. pub total_supply: T::Balance, + /// The amount of the pool asset that the user should redeemed except fee amount. pub burn_amount: T::Balance, } + /// The pending fee result. #[derive(Encode, Decode, Clone, Default, PartialEq, Eq, Debug)] pub struct PendingFeeResult { + /// The fee amount of the pool asset that the user will pay. pub fee_amount: T::Balance, + /// The balances data. pub balances: Vec, + /// The total supply of the pool asset. pub total_supply: T::Balance, } @@ -1814,7 +1964,7 @@ impl StableAsset for Pallet { Ok(()) })?; - *pool_count = pool_id.checked_add(1).ok_or(Error::::InconsistentStorage)?; + *pool_count = pool_id.checked_add(1).ok_or(ArithmeticError::Overflow)?; Self::deposit_event(Event::CreatePool { pool_id, From d980c23272c7dba484f9b14eb114210335b570af Mon Sep 17 00:00:00 2001 From: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Date: Tue, 15 Oct 2024 09:59:37 +0800 Subject: [PATCH 23/30] Optimize stable pool (#1465) * change unwrap_or_default to unwrap * optimize stable-pool pallet --- pallets/stable-pool/src/lib.rs | 67 ++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 7 deletions(-) diff --git a/pallets/stable-pool/src/lib.rs b/pallets/stable-pool/src/lib.rs index 3499248e6..e324d65cd 100644 --- a/pallets/stable-pool/src/lib.rs +++ b/pallets/stable-pool/src/lib.rs @@ -66,23 +66,24 @@ pub mod pallet { pub trait Config: frame_system::Config + bifrost_stable_asset::Config> { + /// Weight information for the pallet's dispatchables. type WeightInfo: WeightInfo; - + /// Origin type that will be used to enforce permissions. type ControlOrigin: EnsureOrigin; - + /// MultiCurrency trait for handling various currencies associated with accounts. type MultiCurrency: MultiCurrency< AccountIdOf, CurrencyId = AssetIdOf, Balance = Self::Balance, >; - + /// Represents the currency identifier type, implementing necessary traits. type CurrencyId: Parameter + Ord + Copy + CurrencyIdExt + From + Into; - + /// The stable asset interface used for handling stable assets. type StableAsset: bifrost_stable_asset::StableAsset< AssetId = AssetIdOf, Balance = Self::Balance, @@ -91,30 +92,36 @@ pub mod pallet { Config = Self, BlockNumber = BlockNumberFor, >; - + /// Interface for minting tokens. type VtokenMinting: VtokenMintingOperator< AssetIdOf, Self::Balance, AccountIdOf, TimeUnit, >; - + /// Type for converting between different currency IDs. type CurrencyIdConversion: CurrencyIdConversion>; - + /// Type for registering currency IDs. type CurrencyIdRegister: CurrencyIdRegister>; } #[pallet::error] pub enum Error { + /// A swap occurred, but the result is below the minimum swap amount. SwapUnderMin, + /// A minting operation occurred, but the minted amount is below the minimum mint amount. MintUnderMin, + /// Cannot mint tokens, possibly due to invalid parameters or illegal state. CantMint, + /// The redeemed amount exceeds the allowed maximum. RedeemOverMax, + /// The token rate is not set, preventing related operations. TokenRateNotSet, } #[pallet::call] impl Pallet { + /// Creates a new liquidity pool with the specified parameters. #[pallet::call_index(0)] #[pallet::weight(::WeightInfo::create_pool())] pub fn create_pool( @@ -129,8 +136,10 @@ pub mod pallet { yield_recipient: AccountIdOf, precision: AtLeast64BitUnsignedOf, ) -> DispatchResult { + // Ensure the caller has the necessary control origin T::ControlOrigin::ensure_origin(origin)?; + // Register the metadata for the new pool let pool_id = PoolCount::::get(); T::CurrencyIdRegister::register_blp_metadata( pool_id, @@ -140,6 +149,8 @@ pub mod pallet { .ok_or(bifrost_stable_asset::Error::::ArgumentsMismatch)? .saturated_into::(), )?; + + // Create the liquidity pool in the StableAsset module T::StableAsset::create_pool( CurrencyId::BLP(pool_id).into(), assets, @@ -154,6 +165,7 @@ pub mod pallet { ) } + /// Adds liquidity to an existing pool. #[pallet::call_index(1)] #[pallet::weight(::WeightInfo::add_liquidity())] pub fn add_liquidity( @@ -163,9 +175,11 @@ pub mod pallet { min_mint_amount: T::Balance, ) -> DispatchResult { let who = ensure_signed(origin)?; + // Mint new liquidity tokens based on the provided amounts Self::mint_inner(&who, pool_id, amounts, min_mint_amount) } + /// Swaps one asset for another in a specified pool. #[pallet::call_index(2)] #[pallet::weight(::WeightInfo::swap())] pub fn swap( @@ -177,9 +191,11 @@ pub mod pallet { min_dy: T::Balance, ) -> DispatchResult { let who = ensure_signed(origin)?; + // Execute the swap operation Self::on_swap(&who, pool_id, i, j, dx, min_dy) } + /// Redeems a proportion of assets from a liquidity pool. #[pallet::call_index(3)] #[pallet::weight(::WeightInfo::redeem_proportion())] pub fn redeem_proportion( @@ -189,9 +205,11 @@ pub mod pallet { min_redeem_amounts: Vec, ) -> DispatchResult { let who = ensure_signed(origin)?; + // Redeem a specified proportion of tokens Self::redeem_proportion_inner(&who, pool_id, amount, min_redeem_amounts) } + /// Redeems a single asset from a liquidity pool. #[pallet::call_index(4)] #[pallet::weight(::WeightInfo::redeem_single())] pub fn redeem_single( @@ -203,10 +221,12 @@ pub mod pallet { asset_length: u32, ) -> DispatchResult { let who = ensure_signed(origin)?; + // Redeem a single asset from the pool Self::redeem_single_inner(&who, pool_id, amount, i, min_redeem_amount, asset_length)?; Ok(()) } + /// Redeems multiple assets from a liquidity pool. #[pallet::call_index(5)] #[pallet::weight(::WeightInfo::redeem_multi())] pub fn redeem_multi( @@ -216,9 +236,11 @@ pub mod pallet { max_redeem_amount: T::Balance, ) -> DispatchResult { let who = ensure_signed(origin)?; + // Redeem multiple assets based on provided amounts Self::redeem_multi_inner(&who, pool_id, amounts, max_redeem_amount) } + /// Modifies the parameter 'a' of a pool at a future block. #[pallet::call_index(6)] #[pallet::weight(::WeightInfo::modify_a())] pub fn modify_a( @@ -227,10 +249,13 @@ pub mod pallet { a: T::AtLeast64BitUnsigned, future_a_block: BlockNumberFor, ) -> DispatchResult { + // Ensure the caller has the necessary control origin T::ControlOrigin::ensure_origin(origin)?; + // Modify the parameter 'a' in the StableAsset module T::StableAsset::modify_a(pool_id, a, future_a_block) } + /// Modifies the fees of a specified liquidity pool. #[pallet::call_index(7)] #[pallet::weight(::WeightInfo::modify_fees())] pub fn modify_fees( @@ -240,14 +265,19 @@ pub mod pallet { swap_fee: Option, redeem_fee: Option, ) -> DispatchResult { + // Ensure the caller has the necessary control origin T::ControlOrigin::ensure_origin(origin)?; let fee_denominator: T::AtLeast64BitUnsigned = T::FeePrecision::get(); + + // Ensure that the provided fees are within valid limits 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), bifrost_stable_asset::Error::::ArgumentsError ); + + // Update the pool's fee information Pools::::try_mutate_exists(pool_id, |maybe_pool_info| -> DispatchResult { let pool_info = maybe_pool_info .as_mut() @@ -261,6 +291,7 @@ pub mod pallet { if let Some(fee) = redeem_fee { pool_info.redeem_fee = fee; } + // Emit an event indicating that the fees have been modified bifrost_stable_asset::Pallet::::deposit_event( bifrost_stable_asset::Event::::FeeModified { pool_id, @@ -273,6 +304,7 @@ pub mod pallet { }) } + /// Modifies the fee and yield recipients of a liquidity pool. #[pallet::call_index(8)] #[pallet::weight(::WeightInfo::modify_recipients())] pub fn modify_recipients( @@ -281,6 +313,7 @@ pub mod pallet { fee_recipient: Option, yield_recipient: Option, ) -> DispatchResult { + // Ensure the caller has the necessary control origin T::ControlOrigin::ensure_origin(origin)?; Pools::::try_mutate_exists(pool_id, |maybe_pool_info| -> DispatchResult { let pool_info = maybe_pool_info @@ -292,6 +325,7 @@ pub mod pallet { if let Some(recipient) = yield_recipient { pool_info.yield_recipient = recipient; } + // Emit an event indicating that the recipients have been modified bifrost_stable_asset::Pallet::::deposit_event( bifrost_stable_asset::Event::::RecipientModified { pool_id, @@ -303,6 +337,7 @@ pub mod pallet { }) } + /// Edits the token rates for the specified pool. #[pallet::call_index(9)] #[pallet::weight(::WeightInfo::edit_token_rate())] pub fn edit_token_rate( @@ -313,10 +348,16 @@ pub mod pallet { (AtLeast64BitUnsignedOf, AtLeast64BitUnsignedOf), )>, ) -> DispatchResult { + // Ensure the caller has the necessary control origin T::ControlOrigin::ensure_origin(origin)?; + // Update the token rates in the StableAsset module bifrost_stable_asset::Pallet::::set_token_rate(pool_id, token_rate_info) } + /// Configures the auto-refresh settings for a given vToken. + /// + /// This method sets the hard cap for the specified vToken's token rate. + /// Only an authorized origin can call this function. #[pallet::call_index(10)] #[pallet::weight(::WeightInfo::config_vtoken_auto_refresh())] pub fn config_vtoken_auto_refresh( @@ -324,30 +365,42 @@ pub mod pallet { vtoken: AssetIdOf, hardcap: Permill, ) -> DispatchResult { + // Ensure the caller has the necessary control origin T::ControlOrigin::ensure_origin(origin)?; + // Ensure that the provided vtoken is valid ensure!( CurrencyId::is_vtoken(&vtoken.into()), bifrost_stable_asset::Error::::ArgumentsError ); + // Insert the hardcap for the specified vToken into storage TokenRateHardcap::::insert(vtoken, hardcap); + // Emit an event indicating that the vToken's hardcap has been configured bifrost_stable_asset::Pallet::::deposit_event( bifrost_stable_asset::Event::::TokenRateHardcapConfigured { vtoken, hardcap }, ); + Ok(()) } + /// Removes the auto-refresh configuration for a given vToken. + /// + /// This method deletes the hard cap setting for the specified vToken. + /// Only an authorized origin can call this function. #[pallet::call_index(11)] #[pallet::weight(::WeightInfo::remove_vtoken_auto_refresh())] pub fn remove_vtoken_auto_refresh( origin: OriginFor, vtoken: AssetIdOf, ) -> DispatchResult { + // Ensure the caller has the necessary control origin T::ControlOrigin::ensure_origin(origin)?; + // Remove the hardcap setting for the specified vToken from storage TokenRateHardcap::::remove(vtoken); + // Emit an event indicating that the vToken's hardcap has been removed bifrost_stable_asset::Pallet::::deposit_event( bifrost_stable_asset::Event::::TokenRateHardcapRemoved { vtoken }, ); From 4196c42f9934b27e0d5ec305bce1f1f6ba6d99d1 Mon Sep 17 00:00:00 2001 From: yooml Date: Tue, 15 Oct 2024 22:26:50 +0800 Subject: [PATCH 24/30] =?UTF-8?q?fix:=20=F0=9F=90=9B=20for=20review=20(#14?= =?UTF-8?q?67)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pallets/leverage-staking/src/lib.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/pallets/leverage-staking/src/lib.rs b/pallets/leverage-staking/src/lib.rs index 6522cb1d9..50b50756f 100644 --- a/pallets/leverage-staking/src/lib.rs +++ b/pallets/leverage-staking/src/lib.rs @@ -87,23 +87,36 @@ pub mod pallet { #[pallet::error] pub enum Error { + /// Arguments error, old rate is equal to new rate ArgumentsError, + /// Not support token type NotSupportTokenType, } #[pallet::event] #[pallet::generate_deposit(pub (crate) fn deposit_event)] pub enum Event { + /// User's leverage rate has been changed. FlashLoanDeposited { + /// Account who change the leverage rate. who: AccountIdOf, + /// The asset id of the token. asset_id: AssetIdOf, + /// The old leverage rate. old_rate: Rate, + /// The new leverage rate. new_rate: Rate, }, } #[pallet::call] impl Pallet { + /// Deposit flash loan + /// + /// Using borrowed funds to increase the amount of liquid staking (yield-bearing) assets. + /// + /// - `asset_id`: The asset id of the token + /// - `rate`: Leverage rate #[pallet::call_index(0)] #[pallet::weight(::WeightInfo::flash_loan_deposit())] pub fn flash_loan_deposit( @@ -111,7 +124,9 @@ pub mod pallet { asset_id: AssetIdOf, rate: Rate, ) -> DispatchResult { - Pallet::::flash_loan_deposit_inner(origin, asset_id, rate) + let who = ensure_signed(origin)?; + + Pallet::::flash_loan_deposit_inner(who, asset_id, rate) } } } @@ -119,12 +134,10 @@ pub mod pallet { impl Pallet { #[transactional] pub fn flash_loan_deposit_inner( - origin: OriginFor, + who: AccountIdOf, asset_id: AssetIdOf, rate: Rate, ) -> DispatchResult { - let who = ensure_signed(origin)?; - let vtoken_id = T::CurrencyIdConversion::convert_to_vtoken(asset_id) .map_err(|_| Error::::NotSupportTokenType)?; @@ -182,7 +195,7 @@ impl Pallet { ) -> DispatchResult { let (pool_id, currency_id_in, currency_id_out) = T::StablePoolHandler::get_pool_id(&vtoken_id, &asset_id) - .ok_or(Error::::ArgumentsError)?; + .ok_or(Error::::NotSupportTokenType)?; ::Assets::mint_into(asset_id, &who, reduce_amount)?; From 87accfb37d3f9e5b17782823b31ed3c821584033 Mon Sep 17 00:00:00 2001 From: SunTiebing <87381708+SunTiebing@users.noreply.github.com> Date: Wed, 16 Oct 2024 09:36:38 +0800 Subject: [PATCH 25/30] optimize lend-market pallet (#1468) * optimize lend-market pallet * Correct the indentation format. --- pallets/lend-market/Cargo.toml | 2 + pallets/lend-market/src/lib.rs | 52 +++++---- pallets/lend-market/src/migrations/mod.rs | 19 +++ pallets/lend-market/src/migrations/v1.rs | 136 ++++++++++++++++++++++ pallets/lend-market/src/mock.rs | 2 + pallets/leverage-staking/src/mock.rs | 2 + runtime/bifrost-kusama/src/lib.rs | 2 + runtime/bifrost-polkadot/src/lib.rs | 2 + 8 files changed, 192 insertions(+), 25 deletions(-) create mode 100644 pallets/lend-market/src/migrations/mod.rs create mode 100644 pallets/lend-market/src/migrations/v1.rs diff --git a/pallets/lend-market/Cargo.toml b/pallets/lend-market/Cargo.toml index e530d0f87..fa38f07ba 100644 --- a/pallets/lend-market/Cargo.toml +++ b/pallets/lend-market/Cargo.toml @@ -23,6 +23,7 @@ pallet-traits = { workspace = true } parity-scale-codec = { workspace = true, features = ["derive"] } scale-info = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ['derive'], optional = true } +sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } @@ -49,6 +50,7 @@ std = [ 'frame-benchmarking/std', 'orml-traits/std', 'bifrost-primitives/std', + 'sp-core/std', 'sp-runtime/std', 'sp-std/std', 'sp-io/std', diff --git a/pallets/lend-market/src/lib.rs b/pallets/lend-market/src/lib.rs index 743701a0e..f5ad462b2 100644 --- a/pallets/lend-market/src/lib.rs +++ b/pallets/lend-market/src/lib.rs @@ -45,6 +45,7 @@ use pallet_traits::{ ConvertToBigUint, LendMarket as LendMarketTrait, LendMarketMarketDataProvider, LendMarketPositionDataProvider, MarketInfo, MarketStatus, }; +use sp_core::bounded::BoundedVec; use sp_runtime::{ traits::{ AccountIdConversion, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, One, @@ -62,6 +63,7 @@ pub use weights::WeightInfo; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +pub mod migrations; #[cfg(test)] pub mod mock; #[cfg(test)] @@ -75,9 +77,6 @@ mod types; pub mod weights; -pub const MAX_INTEREST_CALCULATING_INTERVAL: u64 = 5 * 24 * 3600; // 5 days -pub const MIN_INTEREST_CALCULATING_INTERVAL: u64 = 100; // 100 seconds - pub const MAX_EXCHANGE_RATE: u128 = 1_000_000_000_000_000_000; // 1 pub const MIN_EXCHANGE_RATE: u128 = 20_000_000_000_000_000; // 0.02 @@ -87,12 +86,6 @@ pub type AssetIdOf = pub type BalanceOf = <::Assets as Inspect<::AccountId>>::Balance; -/// Utility type for managing upgrades/migrations. -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)] -pub enum Versions { - V0, -} - #[frame_support::pallet] pub mod pallet { @@ -132,6 +125,9 @@ pub mod pallet { #[pallet::constant] type LiquidationFreeAssetId: Get>; + + #[pallet::constant] + type MaxLengthLimit: Get; } #[pallet::error] @@ -196,6 +192,8 @@ pub mod pallet { CollateralReserved, /// Market bond does not exist MarketBondDoesNotExist, + /// Error converting Vec to BoundedVec. + ConversionError, } #[pallet::event] @@ -275,7 +273,8 @@ pub mod pallet { /// Liquidation free collateral. #[pallet::storage] - pub type LiquidationFreeCollaterals = StorageValue<_, Vec>, ValueQuery>; + pub type LiquidationFreeCollaterals = + StorageValue<_, BoundedVec, T::MaxLengthLimit>, ValueQuery>; /// Total number of collateral tokens in circulation /// CollateralType -> Balance @@ -434,21 +433,13 @@ pub mod pallet { #[pallet::storage] pub type MarketBond = - StorageMap<_, Blake2_128Concat, AssetIdOf, Vec>>; - - /// DefaultVersion is using for initialize the StorageVersion - #[pallet::type_value] - pub(super) fn DefaultVersion() -> Versions { - Versions::V0 - } + StorageMap<_, Blake2_128Concat, AssetIdOf, BoundedVec, T::MaxLengthLimit>>; - /// Storage version of the pallet. - #[pallet::storage] - pub(crate) type StorageVersion = - StorageValue<_, Versions, ValueQuery, DefaultVersion>; + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::pallet] #[pallet::without_storage_info] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(PhantomData); #[pallet::call] @@ -1110,9 +1101,16 @@ pub mod pallet { collaterals: Vec>, ) -> DispatchResultWithPostInfo { T::UpdateOrigin::ensure_origin(origin)?; - LiquidationFreeCollaterals::::mutate(|liquidation_free_collaterals| { - *liquidation_free_collaterals = collaterals.clone() - }); + LiquidationFreeCollaterals::::try_mutate( + |liquidation_free_collaterals| -> DispatchResultWithPostInfo { + // Attempt to convert `collaterals` into a `BoundedVec` and handle potential + // conversion error + *liquidation_free_collaterals = BoundedVec::try_from(collaterals.clone()) + .map_err(|_| Error::::ConversionError)?; + Ok(().into()) + }, + )?; + Self::deposit_event(Event::::LiquidationFreeCollateralsUpdated(collaterals)); Ok(().into()) } @@ -1126,7 +1124,11 @@ pub mod pallet { market_bond: Vec>, ) -> DispatchResultWithPostInfo { T::UpdateOrigin::ensure_origin(origin)?; - MarketBond::::insert(asset_id, market_bond.clone()); + MarketBond::::insert( + asset_id, + BoundedVec::try_from(market_bond.clone()) + .map_err(|_| Error::::ConversionError)?, + ); Self::deposit_event(Event::::MarketBonded { asset_id, market_bond }); Ok(().into()) diff --git a/pallets/lend-market/src/migrations/mod.rs b/pallets/lend-market/src/migrations/mod.rs new file mode 100644 index 000000000..379d174c5 --- /dev/null +++ b/pallets/lend-market/src/migrations/mod.rs @@ -0,0 +1,19 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . + +pub mod v1; diff --git a/pallets/lend-market/src/migrations/v1.rs b/pallets/lend-market/src/migrations/v1.rs new file mode 100644 index 000000000..e79155a62 --- /dev/null +++ b/pallets/lend-market/src/migrations/v1.rs @@ -0,0 +1,136 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 crate::*; +use frame_support::{ + ensure, + pallet_prelude::StorageVersion, + traits::{GetStorageVersion, Len, OnRuntimeUpgrade}, +}; +use parity_scale_codec::{Decode, Encode}; +#[cfg(feature = "try-runtime")] +use sp_runtime::TryRuntimeError; + +const LOG_TARGET: &str = "lend-market::migration"; + +pub struct MigrateToV1(sp_std::marker::PhantomData); +impl OnRuntimeUpgrade for MigrateToV1 { + fn on_runtime_upgrade() -> frame_support::weights::Weight { + // Check the storage version + let onchain_version = Pallet::::on_chain_storage_version(); + if onchain_version < 1 { + // Transform storage values + // We transform the storage values from the old into the new format. + log::info!(target: LOG_TARGET, "Start to migrate LiquidationFreeCollateralsstorage..."); + LiquidationFreeCollaterals::::translate::>, _>( + |maybe_value: Option>>| { + let target_bounded_vec: BoundedVec, T::MaxLengthLimit>; + if let Some(value) = maybe_value { + // If there's a value, try to convert Vec to BoundedVec + target_bounded_vec = BoundedVec::try_from(value).unwrap(); + } else { + // If there's no value (None), set the BoundedVec to default (empty) + target_bounded_vec = + BoundedVec::, T::MaxLengthLimit>::default(); + } + // Return the new BoundedVec as the migrated value + Some(target_bounded_vec) + }, + ) + .unwrap(); + + log::info!(target: LOG_TARGET, "Start to migrate MarketBond storage..."); + MarketBond::::translate::>, _>( + |k: AssetIdOf, value: Vec>| { + log::info!(target: LOG_TARGET, "Migrated to boundedvec for {:?}...", k); + + let target_bounded_vec: BoundedVec, T::MaxLengthLimit>; + if value.len() != 0 { + target_bounded_vec = BoundedVec::try_from(value).unwrap(); + } else { + target_bounded_vec = + BoundedVec::, T::MaxLengthLimit>::default(); + } + + Some(target_bounded_vec) + }, + ); + + // Update the storage version + StorageVersion::new(1).put::>(); + + // Return the consumed weight + let liquidation_free_collaterals_count = 1u64; + let market_bond_count = MarketBond::::iter().count(); + Weight::from(T::DbWeight::get().reads_writes( + liquidation_free_collaterals_count + market_bond_count as u64 + 1, + liquidation_free_collaterals_count as u64 + market_bond_count as u64 + 1, + )) + } else { + // We don't do anything here. + Weight::zero() + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + let liquidation_free_collaterals_count = LiquidationFreeCollaterals::::get().len(); + let market_bond_count = MarketBond::::iter().count(); + + // print out the pre-migrate storage count + log::info!(target: LOG_TARGET, "LiquidationFreeCollaterals pre-migrate storage count: {:?}", liquidation_free_collaterals_count); + log::info!(target: LOG_TARGET, "MarketBond pre-migrate storage count: {:?}", market_bond_count); + Ok((liquidation_free_collaterals_count as u64, market_bond_count as u64).encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(cnt: Vec) -> Result<(), TryRuntimeError> { + let new_liquidation_free_collaterals_count = LiquidationFreeCollaterals::::get().len(); + let new_market_bond_count = MarketBond::::iter().count(); + + let (old_liquidation_free_collaterals_count, old_market_bond_count): (u64, u64) = + Decode::decode(&mut cnt.as_slice()).expect( + "the state parameter should be something that was generated by pre_upgrade", + ); + + // print out the post-migrate storage count + log::info!( + target: LOG_TARGET, + "LiquidationFreeCollaterals post-migrate storage count: {:?}", + new_liquidation_free_collaterals_count + ); + + log::info!( + target: LOG_TARGET, + "MarketBond post-migrate storage count: {:?}", + new_market_bond_count + ); + + ensure!( + new_liquidation_free_collaterals_count as u64 == old_liquidation_free_collaterals_count, + "LiquidationFreeCollaterals Post-migration storage count does not match pre-migration count" + ); + + ensure!( + new_market_bond_count as u64 == old_market_bond_count, + "MarketBond Post-migration storage count does not match pre-migration count" + ); + + Ok(()) + } +} diff --git a/pallets/lend-market/src/mock.rs b/pallets/lend-market/src/mock.rs index 9e2ba4bb1..332debd7d 100644 --- a/pallets/lend-market/src/mock.rs +++ b/pallets/lend-market/src/mock.rs @@ -308,6 +308,7 @@ impl pallet_prices::Config for Test { parameter_types! { pub const RewardAssetId: CurrencyId = BNC; pub const LiquidationFreeAssetId: CurrencyId = DOT; + pub const MaxLengthLimit: u32 = 500; } impl Config for Test { @@ -321,6 +322,7 @@ impl Config for Test { type Assets = Currencies; type RewardAssetId = RewardAssetId; type LiquidationFreeAssetId = LiquidationFreeAssetId; + type MaxLengthLimit = MaxLengthLimit; } pub(crate) fn new_test_ext() -> sp_io::TestExternalities { diff --git a/pallets/leverage-staking/src/mock.rs b/pallets/leverage-staking/src/mock.rs index dc76e26b3..0e4e7cf35 100644 --- a/pallets/leverage-staking/src/mock.rs +++ b/pallets/leverage-staking/src/mock.rs @@ -437,6 +437,7 @@ impl OraclePriceProvider for MockOraclePriceProvider { parameter_types! { pub const RewardAssetId: CurrencyId = BNC; pub const LiquidationFreeAssetId: CurrencyId = DOT; + pub const MaxLengthLimit: u32 = 500; } impl lend_market::Config for Test { @@ -450,6 +451,7 @@ impl lend_market::Config for Test { type Assets = Currencies; type RewardAssetId = RewardAssetId; type LiquidationFreeAssetId = LiquidationFreeAssetId; + type MaxLengthLimit = MaxLengthLimit; } impl pallet_prices::Config for Test { diff --git a/runtime/bifrost-kusama/src/lib.rs b/runtime/bifrost-kusama/src/lib.rs index a7ef423db..023e7fbc9 100644 --- a/runtime/bifrost-kusama/src/lib.rs +++ b/runtime/bifrost-kusama/src/lib.rs @@ -1592,6 +1592,7 @@ impl lend_market::Config for Runtime { type Assets = Currencies; type RewardAssetId = NativeCurrencyId; type LiquidationFreeAssetId = RelayCurrencyId; + type MaxLengthLimit = MaxLengthLimit; } parameter_types! { @@ -1906,6 +1907,7 @@ pub mod migrations { frame_support::migrations::RemovePallet, frame_support::migrations::RemovePallet, bifrost_system_staking::migrations::v1::MigrateToV1, + lend_market::migrations::v1::MigrateToV1, ); } diff --git a/runtime/bifrost-polkadot/src/lib.rs b/runtime/bifrost-polkadot/src/lib.rs index 4f2431d13..38f978abb 100644 --- a/runtime/bifrost-polkadot/src/lib.rs +++ b/runtime/bifrost-polkadot/src/lib.rs @@ -1455,6 +1455,7 @@ impl lend_market::Config for Runtime { type Assets = Currencies; type RewardAssetId = NativeCurrencyId; type LiquidationFreeAssetId = RelayCurrencyId; + type MaxLengthLimit = MaxLengthLimit; } parameter_types! { @@ -1836,6 +1837,7 @@ pub mod migrations { bifrost_slpx::migration::v2::MigrateToV2, frame_support::migrations::RemovePallet, bifrost_system_staking::migrations::v1::MigrateToV1, + lend_market::migrations::v1::MigrateToV1, ); } From a7b8eda9ff59bd010e2ad261e7a9f1d1ee0b4970 Mon Sep 17 00:00:00 2001 From: NingBo Wang <2536935847@qq.com> Date: Wed, 16 Oct 2024 12:04:15 +0800 Subject: [PATCH 26/30] Optimize vtoken minting (#1469) * Optimize vtoken minting * Fix clippy --- Cargo.lock | 1 - node/rpc/src/lib.rs | 4 +- pallets/bb-bnc/src/mock.rs | 4 - pallets/buy-back/src/mock.rs | 4 - pallets/deprecated/system-maker/src/mock.rs | 4 - pallets/fee-share/src/mock.rs | 4 - pallets/leverage-staking/src/lib.rs | 10 +- pallets/leverage-staking/src/mock.rs | 4 - pallets/salp/src/lib.rs | 2 +- pallets/salp/src/mock.rs | 4 - pallets/salp/src/tests.rs | 2 +- pallets/slp-v2/src/mock.rs | 4 - pallets/slp/src/mocks/mock.rs | 4 - pallets/slp/src/mocks/mock_kusama.rs | 4 - pallets/slpx/src/lib.rs | 16 +- pallets/slpx/src/mock.rs | 4 - pallets/stable-pool/src/mock.rs | 4 - pallets/system-staking/src/lib.rs | 24 +- pallets/system-staking/src/mock.rs | 4 - pallets/vtoken-minting/Cargo.toml | 2 - .../vtoken-minting/rpc/runtime-api/src/lib.rs | 7 +- pallets/vtoken-minting/rpc/src/lib.rs | 77 +- pallets/vtoken-minting/src/benchmarking.rs | 4 +- pallets/vtoken-minting/src/impls.rs | 1008 ++++++++ pallets/vtoken-minting/src/lib.rs | 2019 ++++------------- pallets/vtoken-minting/src/mock.rs | 181 +- pallets/vtoken-minting/src/tests.rs | 11 +- pallets/vtoken-minting/src/weights.rs | 4 +- primitives/src/time_unit.rs | 16 + primitives/src/traits.rs | 25 +- runtime/bifrost-kusama/src/lib.rs | 16 +- .../src/weights/bifrost_vtoken_minting.rs | 2 +- runtime/bifrost-polkadot/src/lib.rs | 14 +- .../src/weights/bifrost_vtoken_minting.rs | 2 +- 34 files changed, 1623 insertions(+), 1872 deletions(-) create mode 100644 pallets/vtoken-minting/src/impls.rs diff --git a/Cargo.lock b/Cargo.lock index 3af063867..8dac475d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2272,7 +2272,6 @@ dependencies = [ "bifrost-currencies", "bifrost-primitives", "bifrost-runtime-common", - "bifrost-slp", "cumulus-primitives-core", "env_logger", "frame-benchmarking", diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index 1bfb4d3cd..7f1b7d55e 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -110,7 +110,7 @@ where C::Api: SalpRuntimeApi, C::Api: StablePoolRuntimeApi, C::Api: LendMarketApi, - C::Api: VtokenMintingRuntimeApi, + C::Api: VtokenMintingRuntimeApi, C::Api: ZenlinkProtocolRuntimeApi, C::Api: zenlink_stable_amm_runtime_api::StableAmmApi, @@ -154,7 +154,7 @@ where C::Api: SalpRuntimeApi, C::Api: BbBNCRuntimeApi, C::Api: LendMarketApi, - C::Api: VtokenMintingRuntimeApi, + C::Api: VtokenMintingRuntimeApi, C::Api: ZenlinkProtocolRuntimeApi, C::Api: StablePoolRuntimeApi, C::Api: BlockBuilder, diff --git a/pallets/bb-bnc/src/mock.rs b/pallets/bb-bnc/src/mock.rs index 5bfd05d76..36d34a318 100644 --- a/pallets/bb-bnc/src/mock.rs +++ b/pallets/bb-bnc/src/mock.rs @@ -207,11 +207,8 @@ impl bifrost_vtoken_minting::Config for Runtime { type ExitAccount = BifrostExitAccount; type FeeAccount = BifrostFeeAccount; type RedeemFeeAccount = BifrostFeeAccount; - type BifrostSlp = Slp; type BifrostSlpx = SlpxInterface; type RelayChainToken = RelayCurrencyId; - type CurrencyIdConversion = AssetIdMaps; - type CurrencyIdRegister = AssetIdMaps; type WeightInfo = (); type OnRedeemSuccess = (); type XcmTransfer = XTokens; @@ -220,7 +217,6 @@ impl bifrost_vtoken_minting::Config for Runtime { type MaxLockRecords = ConstU32<100>; type IncentivePoolAccount = IncentivePoolAccount; type BbBNC = (); - type AssetIdMaps = AssetIdMaps; } ord_parameter_types! { diff --git a/pallets/buy-back/src/mock.rs b/pallets/buy-back/src/mock.rs index ce98941ad..c11aa3872 100644 --- a/pallets/buy-back/src/mock.rs +++ b/pallets/buy-back/src/mock.rs @@ -293,11 +293,8 @@ impl bifrost_vtoken_minting::Config for Runtime { type ExitAccount = BifrostExitAccount; type FeeAccount = BifrostFeeAccount; type RedeemFeeAccount = BifrostFeeAccount; - type BifrostSlp = Slp; type BifrostSlpx = SlpxInterface; type RelayChainToken = RelayCurrencyId; - type CurrencyIdConversion = AssetIdMaps; - type CurrencyIdRegister = AssetIdMaps; type WeightInfo = (); type OnRedeemSuccess = (); type XcmTransfer = XTokens; @@ -306,7 +303,6 @@ impl bifrost_vtoken_minting::Config for Runtime { type MaxLockRecords = ConstU32<100>; type IncentivePoolAccount = IncentivePoolAccount; type BbBNC = (); - type AssetIdMaps = AssetIdMaps; } parameter_types! { diff --git a/pallets/deprecated/system-maker/src/mock.rs b/pallets/deprecated/system-maker/src/mock.rs index 33f85fb4f..7a309d1ae 100644 --- a/pallets/deprecated/system-maker/src/mock.rs +++ b/pallets/deprecated/system-maker/src/mock.rs @@ -292,11 +292,8 @@ impl bifrost_vtoken_minting::Config for Runtime { type ExitAccount = BifrostExitAccount; type FeeAccount = BifrostFeeAccount; type RedeemFeeAccount = BifrostFeeAccount; - type BifrostSlp = Slp; type BifrostSlpx = SlpxInterface; type RelayChainToken = RelayCurrencyId; - type CurrencyIdConversion = AssetIdMaps; - type CurrencyIdRegister = AssetIdMaps; type WeightInfo = (); type OnRedeemSuccess = (); type XcmTransfer = XTokens; @@ -305,7 +302,6 @@ impl bifrost_vtoken_minting::Config for Runtime { type MaxLockRecords = ConstU32<100>; type IncentivePoolAccount = IncentivePoolAccount; type BbBNC = (); - type AssetIdMaps = AssetIdMaps; } parameter_types! { diff --git a/pallets/fee-share/src/mock.rs b/pallets/fee-share/src/mock.rs index 5b404135b..f138d448f 100644 --- a/pallets/fee-share/src/mock.rs +++ b/pallets/fee-share/src/mock.rs @@ -405,11 +405,8 @@ impl bifrost_vtoken_minting::Config for Runtime { type ExitAccount = BifrostExitAccount; type FeeAccount = BifrostFeeAccount; type RedeemFeeAccount = BifrostFeeAccount; - type BifrostSlp = Slp; type BifrostSlpx = SlpxInterface; type RelayChainToken = RelayCurrencyId; - type CurrencyIdConversion = AssetIdMaps; - type CurrencyIdRegister = AssetIdMaps; type WeightInfo = (); type OnRedeemSuccess = (); type XcmTransfer = XTokens; @@ -418,7 +415,6 @@ impl bifrost_vtoken_minting::Config for Runtime { type MaxLockRecords = ConstU32<100>; type IncentivePoolAccount = IncentivePoolAccount; type BbBNC = (); - type AssetIdMaps = AssetIdMaps; } parameter_types! { diff --git a/pallets/leverage-staking/src/lib.rs b/pallets/leverage-staking/src/lib.rs index 50b50756f..4ddf4b32d 100644 --- a/pallets/leverage-staking/src/lib.rs +++ b/pallets/leverage-staking/src/lib.rs @@ -149,9 +149,13 @@ impl Pallet { let account_borrows = lend_market::Pallet::::get_current_borrow_balance(&who, asset_id)?; // Formula - // current_rate = account_borrows / ( vtoken_to_token(account_deposits) - account_borrows ) - let deposits_token_value = - T::VtokenMinting::vtoken_to_token(asset_id, vtoken_id, account_deposits)?; + // current_rate = account_borrows / ( + // get_currency_amount_by_v_currency_amount(account_deposits) - account_borrows ) + let deposits_token_value = T::VtokenMinting::get_currency_amount_by_v_currency_amount( + asset_id, + vtoken_id, + account_deposits, + )?; let base_token_value = deposits_token_value .checked_sub(account_borrows) .ok_or(ArithmeticError::Overflow)?; diff --git a/pallets/leverage-staking/src/mock.rs b/pallets/leverage-staking/src/mock.rs index 0e4e7cf35..e984ffb6b 100644 --- a/pallets/leverage-staking/src/mock.rs +++ b/pallets/leverage-staking/src/mock.rs @@ -301,10 +301,7 @@ impl bifrost_vtoken_minting::Config for Test { type ExitAccount = BifrostExitAccount; type FeeAccount = One; type RedeemFeeAccount = One; - type BifrostSlp = Slp; type RelayChainToken = RelayCurrencyId; - type CurrencyIdConversion = AssetIdMaps; - type CurrencyIdRegister = AssetIdMaps; type WeightInfo = (); type OnRedeemSuccess = (); type XcmTransfer = XTokens; @@ -314,7 +311,6 @@ impl bifrost_vtoken_minting::Config for Test { type MaxLockRecords = ConstU32<100>; type IncentivePoolAccount = IncentivePoolAccount; type BbBNC = (); - type AssetIdMaps = AssetIdMaps; } pub struct Slp; diff --git a/pallets/salp/src/lib.rs b/pallets/salp/src/lib.rs index d4943958e..ae042ac7a 100644 --- a/pallets/salp/src/lib.rs +++ b/pallets/salp/src/lib.rs @@ -690,7 +690,7 @@ pub mod pallet { )?; }, cid if cid == relay_vtoken_id => { - let token_value = T::VtokenMinting::vtoken_to_token( + let token_value = T::VtokenMinting::get_currency_amount_by_v_currency_amount( relay_currency_id, relay_vtoken_id, value, diff --git a/pallets/salp/src/mock.rs b/pallets/salp/src/mock.rs index f377cbab3..4d3970623 100644 --- a/pallets/salp/src/mock.rs +++ b/pallets/salp/src/mock.rs @@ -419,10 +419,7 @@ impl bifrost_vtoken_minting::Config for Test { type ExitAccount = BifrostExitAccount; type FeeAccount = CouncilAccount; type RedeemFeeAccount = CouncilAccount; - type BifrostSlp = Slp; type RelayChainToken = RelayCurrencyId; - type CurrencyIdConversion = AssetIdMaps; - type CurrencyIdRegister = AssetIdMaps; type WeightInfo = (); type OnRedeemSuccess = (); type XcmTransfer = XTokens; @@ -432,7 +429,6 @@ impl bifrost_vtoken_minting::Config for Test { type MaxLockRecords = ConstU32<100>; type IncentivePoolAccount = IncentivePoolAccount; type BbBNC = (); - type AssetIdMaps = AssetIdMaps; } parameter_types! { diff --git a/pallets/salp/src/tests.rs b/pallets/salp/src/tests.rs index b30fb0d16..6c80cbeef 100644 --- a/pallets/salp/src/tests.rs +++ b/pallets/salp/src/tests.rs @@ -981,7 +981,7 @@ fn refund_meanwhile_issue_should_work() { Salp::buyback_vstoken_by_stable_pool(Some(ALICE).into(), 1, KSM, 100), orml_tokens::Error::::BalanceTooLow ); - let token_value = VtokenMinting::token_to_vtoken(KSM, VKSM, 100); + let token_value = VtokenMinting::get_v_currency_amount_by_currency_amount(KSM, VKSM, 100); assert_eq!(token_value, Ok(100)); assert_eq!(Tokens::free_balance(KSM, &ALICE), 95000); assert_ok!(Tokens::set_balance(RuntimeOrigin::root(), buyback_account, KSM, 100, 0)); diff --git a/pallets/slp-v2/src/mock.rs b/pallets/slp-v2/src/mock.rs index c4f8990eb..afa120a69 100644 --- a/pallets/slp-v2/src/mock.rs +++ b/pallets/slp-v2/src/mock.rs @@ -241,9 +241,6 @@ impl bifrost_vtoken_minting::Config for Test { type FeeAccount = BifrostFeeAccount; type RedeemFeeAccount = BifrostFeeAccount; type RelayChainToken = RelayCurrencyId; - type CurrencyIdConversion = AssetIdMaps; - type CurrencyIdRegister = AssetIdMaps; - type BifrostSlp = MockSlp; type BifrostSlpx = SlpxInterface; type WeightInfo = (); type OnRedeemSuccess = (); @@ -253,7 +250,6 @@ impl bifrost_vtoken_minting::Config for Test { type MaxLockRecords = ConstU32<100>; type IncentivePoolAccount = IncentivePoolAccount; type BbBNC = (); - type AssetIdMaps = AssetIdMaps; } parameter_types! { diff --git a/pallets/slp/src/mocks/mock.rs b/pallets/slp/src/mocks/mock.rs index 47a728994..a8328f5b3 100644 --- a/pallets/slp/src/mocks/mock.rs +++ b/pallets/slp/src/mocks/mock.rs @@ -198,9 +198,6 @@ impl bifrost_vtoken_minting::Config for Runtime { type FeeAccount = BifrostFeeAccount; type RedeemFeeAccount = BifrostFeeAccount; type RelayChainToken = RelayCurrencyId; - type CurrencyIdConversion = AssetIdMaps; - type CurrencyIdRegister = AssetIdMaps; - type BifrostSlp = Slp; type BifrostSlpx = SlpxInterface; type WeightInfo = (); type OnRedeemSuccess = (); @@ -210,7 +207,6 @@ impl bifrost_vtoken_minting::Config for Runtime { type MaxLockRecords = ConstU32<100>; type IncentivePoolAccount = IncentivePoolAccount; type BbBNC = (); - type AssetIdMaps = AssetIdMaps; } parameter_types! { diff --git a/pallets/slp/src/mocks/mock_kusama.rs b/pallets/slp/src/mocks/mock_kusama.rs index 141e0c1b8..6c7c53986 100644 --- a/pallets/slp/src/mocks/mock_kusama.rs +++ b/pallets/slp/src/mocks/mock_kusama.rs @@ -254,9 +254,6 @@ impl bifrost_vtoken_minting::Config for Runtime { type FeeAccount = BifrostFeeAccount; type RedeemFeeAccount = BifrostFeeAccount; type RelayChainToken = RelayCurrencyId; - type CurrencyIdConversion = AssetIdMaps; - type CurrencyIdRegister = AssetIdMaps; - type BifrostSlp = Slp; type BifrostSlpx = SlpxInterface; type WeightInfo = (); type OnRedeemSuccess = (); @@ -266,7 +263,6 @@ impl bifrost_vtoken_minting::Config for Runtime { type MaxLockRecords = ConstU32<100>; type IncentivePoolAccount = IncentivePoolAccount; type BbBNC = (); - type AssetIdMaps = AssetIdMaps; } parameter_types! { diff --git a/pallets/slpx/src/lib.rs b/pallets/slpx/src/lib.rs index 407832e2a..1e3fdb129 100644 --- a/pallets/slpx/src/lib.rs +++ b/pallets/slpx/src/lib.rs @@ -515,8 +515,7 @@ pub mod pallet { // Check the validity of origin T::ControlOrigin::ensure_origin(origin)?; // Check in advance to avoid hook errors - T::VtokenMintingInterface::vtoken_id(currency_id) - .ok_or(Error::::ErrorConvertVtoken)?; + currency_id.to_vtoken().map_err(|_| Error::::ErrorConvertVtoken)?; let mut currency_list = CurrencyIdList::::get(); if is_support { ensure!(!currency_list.contains(¤cy_id), Error::::CurrencyAlreadyExists); @@ -1100,12 +1099,13 @@ impl Pallet { let vtoken_id = order.currency_id.to_vtoken().map_err(|_| Error::::ErrorConvertVtoken)?; - let vtoken_amount = T::VtokenMintingInterface::token_to_vtoken( - order.currency_id, - vtoken_id, - currency_amount, - ) - .map_err(|_| Error::::ErrorVtokenMiting)?; + let vtoken_amount = + T::VtokenMintingInterface::get_v_currency_amount_by_currency_amount( + order.currency_id, + vtoken_id, + currency_amount, + ) + .map_err(|_| Error::::ErrorVtokenMiting)?; T::VtokenMintingInterface::mint( order.derivative_account.clone(), diff --git a/pallets/slpx/src/mock.rs b/pallets/slpx/src/mock.rs index 0abbbe43d..12c3aa264 100644 --- a/pallets/slpx/src/mock.rs +++ b/pallets/slpx/src/mock.rs @@ -182,9 +182,6 @@ impl bifrost_vtoken_minting::Config for Test { type FeeAccount = BifrostFeeAccount; type RedeemFeeAccount = BifrostFeeAccount; type RelayChainToken = RelayCurrencyId; - type CurrencyIdConversion = AssetIdMaps; - type CurrencyIdRegister = AssetIdMaps; - type BifrostSlp = MockSlp; type BifrostSlpx = SlpxInterface; type WeightInfo = (); type OnRedeemSuccess = (); @@ -194,7 +191,6 @@ impl bifrost_vtoken_minting::Config for Test { type MaxLockRecords = ConstU32<100>; type IncentivePoolAccount = IncentivePoolAccount; type BbBNC = (); - type AssetIdMaps = AssetIdMaps; } parameter_types! { diff --git a/pallets/stable-pool/src/mock.rs b/pallets/stable-pool/src/mock.rs index 5dd4d6798..20dcfac75 100644 --- a/pallets/stable-pool/src/mock.rs +++ b/pallets/stable-pool/src/mock.rs @@ -279,10 +279,7 @@ impl bifrost_vtoken_minting::Config for Test { type ExitAccount = BifrostExitAccount; type FeeAccount = One; type RedeemFeeAccount = One; - type BifrostSlp = Slp; type RelayChainToken = RelayCurrencyId; - type CurrencyIdConversion = AssetIdMaps; - type CurrencyIdRegister = AssetIdMaps; type WeightInfo = (); type OnRedeemSuccess = (); type XcmTransfer = XTokens; @@ -292,7 +289,6 @@ impl bifrost_vtoken_minting::Config for Test { type MaxLockRecords = ConstU32<100>; type IncentivePoolAccount = IncentivePoolAccount; type BbBNC = (); - type AssetIdMaps = AssetIdMaps; } pub struct Slp; diff --git a/pallets/system-staking/src/lib.rs b/pallets/system-staking/src/lib.rs index 5a7cbd392..9f6f8daee 100644 --- a/pallets/system-staking/src/lib.rs +++ b/pallets/system-staking/src/lib.rs @@ -518,20 +518,26 @@ pub mod pallet { let token_info = >::get(&token).ok_or(Error::::TokenInfoNotFound)?; // token_id convert to vtoken_id - let vtoken_id = - T::VtokenMintingInterface::vtoken_id(token).ok_or(Error::::TokenInfoNotFound)?; + let vtoken_id = token.to_vtoken().map_err(|_| Error::::TokenInfoNotFound)?; let pallet_account: AccountIdOf = T::PalletId::get().into_account_truncating(); // Calculate the revenue generated by vtoken let vfree_amount = T::MultiCurrency::free_balance(vtoken_id, &pallet_account); - let free_amount = - T::VtokenMintingInterface::vtoken_to_token(token, vtoken_id, vfree_amount)?; + let free_amount = T::VtokenMintingInterface::get_currency_amount_by_v_currency_amount( + token, + vtoken_id, + vfree_amount, + )?; let token_amount = free_amount.saturating_sub(token_info.system_shadow_amount); // Calculate the number of benefits converted to vtoken let vtoken_amount = - T::VtokenMintingInterface::token_to_vtoken(token, vtoken_id, token_amount)?; + T::VtokenMintingInterface::get_v_currency_amount_by_currency_amount( + token, + vtoken_id, + token_amount, + )?; // Transfer vtoken(benefits) to TreasuryAccount T::MultiCurrency::transfer( @@ -647,11 +653,15 @@ impl Pallet { .saturating_sub(stakable_amount); // token_id convert to vtoken_id - if let Some(vtoken_id) = T::VtokenMintingInterface::vtoken_id(token_id) { + if let Ok(vtoken_id) = token_id.to_vtoken() { // Calculate how many ksm can be received by vksm through VtokenMintingInterface // ===> vredeem_amount(vksm amount) let vredeem_amount = - T::VtokenMintingInterface::token_to_vtoken(token_id, vtoken_id, redeem_amount)?; + T::VtokenMintingInterface::get_v_currency_amount_by_currency_amount( + token_id, + vtoken_id, + redeem_amount, + )?; if vredeem_amount != BalanceOf::::zero() { // redeem vksm ===> vTokenMinting redeem_inner on_redeemed , update // pending_redeem_amount += token_amount diff --git a/pallets/system-staking/src/mock.rs b/pallets/system-staking/src/mock.rs index dbb3fd60a..4bd238afb 100644 --- a/pallets/system-staking/src/mock.rs +++ b/pallets/system-staking/src/mock.rs @@ -189,11 +189,8 @@ impl bifrost_vtoken_minting::Config for Runtime { type ExitAccount = BifrostExitAccount; type FeeAccount = BifrostFeeAccount; type RedeemFeeAccount = BifrostFeeAccount; - type BifrostSlp = Slp; type BifrostSlpx = SlpxInterface; type RelayChainToken = RelayCurrencyId; - type CurrencyIdConversion = AssetIdMaps; - type CurrencyIdRegister = AssetIdMaps; type WeightInfo = (); type OnRedeemSuccess = (); type XcmTransfer = XTokens; @@ -202,7 +199,6 @@ impl bifrost_vtoken_minting::Config for Runtime { type MaxLockRecords = ConstU32<100>; type IncentivePoolAccount = IncentivePoolAccount; type BbBNC = (); - type AssetIdMaps = AssetIdMaps; } ord_parameter_types! { diff --git a/pallets/vtoken-minting/Cargo.toml b/pallets/vtoken-minting/Cargo.toml index 248ac8e8d..4226b370e 100644 --- a/pallets/vtoken-minting/Cargo.toml +++ b/pallets/vtoken-minting/Cargo.toml @@ -38,7 +38,6 @@ xcm-executor = { workspace = true } xcm-builder = { workspace = true } pallet-xcm = { workspace = true } xcm = { workspace = true } -bifrost-slp = { workspace = true } bifrost-asset-registry = { workspace = true } bifrost-runtime-common = { workspace = true } env_logger = { workspace = true } @@ -54,7 +53,6 @@ std = [ "bifrost-primitives/std", "orml-traits/std", "orml-xtokens/std", - "bifrost-slp/std", "bifrost-asset-registry/std", "bifrost-runtime-common/std", ] diff --git a/pallets/vtoken-minting/rpc/runtime-api/src/lib.rs b/pallets/vtoken-minting/rpc/runtime-api/src/lib.rs index 6af2840b8..9f086e44a 100644 --- a/pallets/vtoken-minting/rpc/runtime-api/src/lib.rs +++ b/pallets/vtoken-minting/rpc/runtime-api/src/lib.rs @@ -20,12 +20,11 @@ use parity_scale_codec::Codec; use sp_api::decl_runtime_apis; -use sp_core::U256; -use sp_std::vec::Vec; decl_runtime_apis! { - pub trait VtokenMintingRuntimeApi where CurrencyId: Codec + pub trait VtokenMintingRuntimeApi where CurrencyId: Codec, Balance: Codec { - fn get_exchange_rate(token_id: Option) -> Vec<(CurrencyId, U256)>; + fn get_v_currency_amount_by_currency_amount(currency_id: CurrencyId, v_currency_id: CurrencyId, currency_amount: Balance) -> Balance; + fn get_currency_amount_by_v_currency_amount(currency_id: CurrencyId, v_currency_id: CurrencyId, v_currency_amount: Balance) -> Balance; } } diff --git a/pallets/vtoken-minting/rpc/src/lib.rs b/pallets/vtoken-minting/rpc/src/lib.rs index 301d82f26..7c412626f 100644 --- a/pallets/vtoken-minting/rpc/src/lib.rs +++ b/pallets/vtoken-minting/rpc/src/lib.rs @@ -27,19 +27,29 @@ use jsonrpsee::{ use parity_scale_codec::Codec; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; -use sp_core::U256; -use sp_rpc::number::NumberOrHex; use sp_runtime::traits::Block as BlockT; #[rpc(client, server)] -pub trait VtokenMintingRpcApi { +pub trait VtokenMintingRpcApi { /// rpc method for getting vtoken exchange rate - #[method(name = "vtoken_minting_getExchangeRate")] - fn get_exchange_rate( + #[method(name = "vtoken_minting_get_v_currency_amount_by_currency_amount")] + fn get_v_currency_amount_by_currency_amount( &self, - asset_id: Option, + currency_id: CurrencyId, + v_currency_id: CurrencyId, + currency_amount: Balance, at: Option, - ) -> RpcResult>; + ) -> RpcResult; + + /// rpc method for getting vtoken exchange rate + #[method(name = "vtoken_minting_get_currency_amount_by_v_currency_amount")] + fn get_currency_amount_by_v_currency_amount( + &self, + currency_id: CurrencyId, + v_currency_id: CurrencyId, + v_currency_amount: Balance, + at: Option, + ) -> RpcResult; } #[derive(Clone, Debug)] @@ -55,29 +65,62 @@ impl VtokenMintingRpc { } #[async_trait] -impl VtokenMintingRpcApiServer::Hash> +impl + VtokenMintingRpcApiServer::Hash> for VtokenMintingRpc where Block: BlockT, C: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, - C::Api: VtokenMintingRuntimeApi, + C::Api: VtokenMintingRuntimeApi, CurrencyId: Codec, + Balance: Codec, { - fn get_exchange_rate( + fn get_v_currency_amount_by_currency_amount( + &self, + currency_id: CurrencyId, + v_currency_id: CurrencyId, + currency_amount: Balance, + at: Option<::Hash>, + ) -> RpcResult { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + let rs: Result = api.get_v_currency_amount_by_currency_amount( + at, + currency_id, + v_currency_id, + currency_amount, + ); + + match rs { + Ok(data) => Ok(data), + Err(e) => Err(ErrorObject::owned( + ErrorCode::InternalError.code(), + "Failed to get find_block_epoch.", + Some(format!("{:?}", e)), + )), + } + } + + fn get_currency_amount_by_v_currency_amount( &self, - token_id: Option, + currency_id: CurrencyId, + v_currency_id: CurrencyId, + v_currency_amount: Balance, at: Option<::Hash>, - ) -> RpcResult> { + ) -> RpcResult { let api = self.client.runtime_api(); let at = at.unwrap_or_else(|| self.client.info().best_hash); - let rs: Result, _> = api.get_exchange_rate(at, token_id); + let rs: Result = api.get_currency_amount_by_v_currency_amount( + at, + currency_id, + v_currency_id, + v_currency_amount, + ); match rs { - Ok(data) => Ok(data - .into_iter() - .map(|(token, rate)| (token, NumberOrHex::Hex(rate.into()))) - .collect()), + Ok(data) => Ok(data), Err(e) => Err(ErrorObject::owned( ErrorCode::InternalError.code(), "Failed to get find_block_epoch.", diff --git a/pallets/vtoken-minting/src/benchmarking.rs b/pallets/vtoken-minting/src/benchmarking.rs index 56691957e..181296889 100644 --- a/pallets/vtoken-minting/src/benchmarking.rs +++ b/pallets/vtoken-minting/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use crate::{Pallet as VtokenMinting, *}; -use bifrost_primitives::{CurrencyId, TokenSymbol, VKSM}; +use bifrost_primitives::{CurrencyId, TokenSymbol, VtokenMintingOperator, VKSM}; use frame_benchmarking::v1::{benchmarks, whitelisted_caller, BenchmarkError}; use frame_support::{assert_ok, sp_runtime::traits::UniqueSaturatedFrom}; use frame_system::RawOrigin; @@ -73,7 +73,7 @@ benchmarks! { let token = CurrencyId::Token(TokenSymbol::KSM); }: _(origin, token, TimeUnit::Era(1)) - recreate_currency_ongoing_time_unit { + set_ongoing_time_unit { let origin = T::ControlOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let token = CurrencyId::Token(TokenSymbol::KSM); }: _(origin, token, TimeUnit::Era(1)) diff --git a/pallets/vtoken-minting/src/impls.rs b/pallets/vtoken-minting/src/impls.rs new file mode 100644 index 000000000..d0315f99b --- /dev/null +++ b/pallets/vtoken-minting/src/impls.rs @@ -0,0 +1,1008 @@ +// This file is part of Bifrost. + +// Copyright (C) Liebi Technologies PTE. 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 . + +// Ensure we're `no_std` when compiling for Wasm. +#![cfg_attr(not(feature = "std"), no_std)] + +use crate::{ + AccountIdOf, BalanceOf, Config, CurrencyIdOf, Error, Event, Fees, HookIterationLimit, + MinTimeUnit, MinimumMint, MinimumRedeem, MintWithLockBlocks, OnRedeemSuccess, OngoingTimeUnit, + Pallet, RedeemTo, TimeUnitUnlockLedger, TokenPool, TokenUnlockLedger, TokenUnlockNextId, + UnlockDuration, UnlockId, UnlockingTotal, UserUnlockLedger, VtokenIncentiveCoef, + VtokenLockLedger, WeightInfo, +}; +use bb_bnc::traits::BbBNCInterface; +use bifrost_primitives::{ + currency::BNC, AstarChainId, CurrencyId, CurrencyIdExt, HydrationChainId, InterlayChainId, + MantaChainId, RedeemType, SlpxOperator, TimeUnit, VTokenMintRedeemProvider, + VTokenSupplyProvider, VtokenMintingInterface, VtokenMintingOperator, FIL, +}; +use frame_support::{ + pallet_prelude::{DispatchResultWithPostInfo, *}, + sp_runtime::{ + traits::{AccountIdConversion, CheckedAdd, CheckedSub, UniqueSaturatedInto, Zero}, + DispatchError, FixedU128, Permill, SaturatedConversion, + }, + traits::LockIdentifier, + transactional, BoundedVec, +}; +use frame_system::pallet_prelude::*; +use orml_traits::{MultiCurrency, MultiLockableCurrency, XcmTransfer}; +use sp_core::U256; +use sp_runtime::{helpers_128bit::multiply_by_rational_with_rounding, Rounding}; +use sp_std::{vec, vec::Vec}; +use xcm::{prelude::*, v4::Location}; + +// incentive lock id for vtoken minted by user +const INCENTIVE_LOCK_ID: LockIdentifier = *b"vmincntv"; + +#[derive(Encode, Decode, Clone, Copy, Debug, PartialEq, Eq)] +pub enum Operation { + Set, + Add, + Sub, +} + +impl Pallet { + /// Update the token pool amount. + /// Parameters: + /// - `currency_id`: The currency id. + /// - `currency_amount`: The currency amount. + /// - `operation`: The operation type. Set, Add, Sub. + pub fn update_token_pool( + currency_id: &CurrencyId, + currency_amount: &BalanceOf, + operation: Operation, + ) -> DispatchResult { + TokenPool::::mutate(currency_id, |token_pool_amount| -> DispatchResult { + match operation { + Operation::Set => *token_pool_amount = *currency_amount, + Operation::Add => + *token_pool_amount = token_pool_amount + .checked_add(currency_amount) + .ok_or(Error::::CalculationOverflow)?, + Operation::Sub => + *token_pool_amount = token_pool_amount + .checked_sub(currency_amount) + .ok_or(Error::::CalculationOverflow)?, + } + Ok(()) + }) + } + + /// Update the unlocking total amount. + /// Parameters: + /// - `currency_id`: The currency id. + /// - `currency_amount`: The currency amount. + /// - `operation`: The operation type. Set, Add, Sub. + pub fn update_unlocking_total( + currency_id: &CurrencyId, + currency_amount: &BalanceOf, + operation: Operation, + ) -> DispatchResult { + UnlockingTotal::::mutate(currency_id, |unlocking_total_amount| -> DispatchResult { + match operation { + Operation::Set => *unlocking_total_amount = *currency_amount, + Operation::Add => + *unlocking_total_amount = unlocking_total_amount + .checked_add(currency_amount) + .ok_or(Error::::CalculationOverflow)?, + Operation::Sub => + *unlocking_total_amount = unlocking_total_amount + .checked_sub(currency_amount) + .ok_or(Error::::CalculationOverflow)?, + } + Ok(()) + }) + } + + /// Update the token unlock ledger. + /// Parameters: + /// - `currency_id`: The currency id. + /// - `currency_amount`: The redeem currency amount. + /// - `unlock_id`: The unlock id. + /// - `lock_to_time_unit`: The lock to time unit. + /// - `redeem_type`: The redeem type. + /// Returns: + /// - `bool`: Whether the record is removed. + pub fn update_token_unlock_ledger( + redeemer: &AccountIdOf, + currency_id: &CurrencyId, + currency_amount: &BalanceOf, + unlock_id: &UnlockId, + lock_to_time_unit: &TimeUnit, + redeem_type: Option>>, + operation: Operation, + ) -> Result> { + TokenUnlockLedger::::mutate_exists(currency_id, unlock_id, |value| match operation { + Operation::Set | Operation::Add => { + let redeem_type = redeem_type.ok_or(Error::::TimeUnitUnlockLedgerNotFound)?; + *value = Some(( + redeemer.clone(), + *currency_amount, + lock_to_time_unit.clone(), + redeem_type, + )); + Ok(false) + }, + Operation::Sub => { + let (_, total_locked_amount, _, _) = + value.as_mut().ok_or(Error::::TimeUnitUnlockLedgerNotFound)?; + + if currency_amount >= total_locked_amount { + *value = None; + Ok(true) + } else { + *total_locked_amount = total_locked_amount + .checked_sub(currency_amount) + .ok_or(Error::::CalculationOverflow)?; + Ok(false) + } + }, + }) + } + + /// Update the time unit unlock ledger. + /// Parameters: + /// - `time_unit`: The time unit. + /// - `currency_id`: The currency id. + /// - `currency_amount`: The redeem currency amount. + /// - `unlock_id`: The unlock id. + /// - `operation`: The operation type. Set, Add, Sub. + /// - `is_remove_record`: Whether to remove the record. + pub fn update_time_unit_unlock_ledger( + time_unit: &TimeUnit, + currency_id: &CurrencyId, + currency_amount: &BalanceOf, + unlock_id: &UnlockId, + operation: Operation, + is_remove_record: bool, + ) -> DispatchResult { + TimeUnitUnlockLedger::::mutate_exists(time_unit, currency_id, |unlocking_ledger| { + match operation { + Operation::Set | Operation::Add => match unlocking_ledger { + Some((total_locked, ledger_list, _token_id)) => { + ledger_list.try_push(*unlock_id).map_err(|_| Error::::TooManyRedeems)?; + + *total_locked = total_locked + .checked_add(¤cy_amount) + .ok_or(Error::::CalculationOverflow)?; + }, + None => + *unlocking_ledger = Some(( + *currency_amount, + BoundedVec::try_from(vec![*unlock_id]) + .map_err(|_| Error::::TooManyRedeems)?, + *currency_id, + )), + }, + Operation::Sub => { + let (total_locked_amount, ledger_list, _) = unlocking_ledger + .as_mut() + .ok_or(Error::::TimeUnitUnlockLedgerNotFound)?; + + if currency_amount >= total_locked_amount { + *unlocking_ledger = None; + } else { + *total_locked_amount = total_locked_amount + .checked_sub(currency_amount) + .ok_or(Error::::CalculationOverflow)?; + if is_remove_record { + ledger_list.retain(|x| x != unlock_id); + } + } + }, + } + Ok(()) + }) + } + + /// Update the user unlock ledger. + /// Parameters: + /// - `account`: The account id. + /// - `currency_id`: The currency id. + /// - `currency_amount`: The redeem currency amount. + /// - `unlock_id`: The unlock id. + /// - `operation`: The operation type. Set, Add, Sub. + /// - `is_remove_record`: Whether to remove the record. + pub fn update_user_unlock_ledger( + account: &AccountIdOf, + currency_id: &CurrencyId, + currency_amount: &BalanceOf, + unlock_id: &UnlockId, + operation: Operation, + is_remove_record: bool, + ) -> Result<(), Error> { + UserUnlockLedger::::mutate_exists(account, currency_id, |user_unlock_ledger| { + match operation { + Operation::Set | Operation::Add => match user_unlock_ledger { + Some((total_locked, ledger_list)) => { + ledger_list.try_push(*unlock_id).map_err(|_| Error::::TooManyRedeems)?; + + *total_locked = total_locked + .checked_add(¤cy_amount) + .ok_or(Error::::CalculationOverflow)?; + }, + None => { + *user_unlock_ledger = Some(( + *currency_amount, + BoundedVec::try_from(vec![*unlock_id]) + .map_err(|_| Error::::TooManyRedeems)?, + )); + }, + }, + Operation::Sub => { + let (total_locked_amount, ledger_list) = user_unlock_ledger + .as_mut() + .ok_or(Error::::TimeUnitUnlockLedgerNotFound)?; + + if currency_amount >= total_locked_amount { + *user_unlock_ledger = None; + } else { + *total_locked_amount = total_locked_amount + .checked_sub(currency_amount) + .ok_or(Error::::CalculationOverflow)?; + if is_remove_record { + ledger_list.retain(|x| x != unlock_id); + } + } + }, + } + Ok(()) + }) + } + + /// Update the token lock ledger. + /// Parameters: + /// - `account`: The account id. + /// - `currency_id`: The currency id. + /// - `currency_amount`: The redeem currency amount. + /// - `unlock_id`: The unlock id. + /// - `lock_to_time_unit`: The lock to time unit. + /// - `redeem_type`: The redeem type. + /// - `operation`: The operation type. Set, Add, Sub. + pub fn update_unlock_ledger( + account: &AccountIdOf, + currency_id: &CurrencyId, + currency_amount: &BalanceOf, + unlock_id: &UnlockId, + lock_to_time_unit: &TimeUnit, + redeem_type: Option>>, + operation: Operation, + ) -> Result { + let is_remove_record = Self::update_token_unlock_ledger( + account, + currency_id, + currency_amount, + unlock_id, + lock_to_time_unit, + redeem_type, + operation, + )?; + Self::update_user_unlock_ledger( + account, + currency_id, + currency_amount, + unlock_id, + operation, + is_remove_record, + )?; + Self::update_time_unit_unlock_ledger( + lock_to_time_unit, + currency_id, + currency_amount, + unlock_id, + operation, + is_remove_record, + )?; + Self::update_unlocking_total(¤cy_id, ¤cy_amount, operation)?; + Ok(is_remove_record) + } + + /// Mint without transfer. + /// Parameters: + /// - `minter`: The minter account id. + /// - `v_currency_id`: The v_currency id. + /// - `currency_id`: The currency id. + /// - `currency_amount`: The currency amount. + /// Returns: + /// - `(BalanceOf, BalanceOf, BalanceOf)`: The currency amount, v_currency amount, mint + /// fee. + pub fn mint_without_transfer( + minter: &AccountIdOf, + v_currency_id: CurrencyId, + currency_id: CurrencyId, + currency_amount: BalanceOf, + ) -> Result<(BalanceOf, BalanceOf, BalanceOf), DispatchError> { + let (mint_rate, _) = Fees::::get(); + let mint_fee = mint_rate.mul_floor(currency_amount); + // Charging fees + T::MultiCurrency::transfer(currency_id, minter, &T::FeeAccount::get(), mint_fee)?; + + let currency_amount = + currency_amount.checked_sub(&mint_fee).ok_or(Error::::CalculationOverflow)?; + let v_currency_amount = Self::get_v_currency_amount_by_currency_amount( + currency_id, + v_currency_id, + currency_amount, + )?; + + // Issue the corresponding v_currency to the user's account. + T::MultiCurrency::deposit(v_currency_id, minter, v_currency_amount)?; + // Increase the token pool amount. + Self::update_token_pool(¤cy_id, ¤cy_amount, Operation::Add)?; + + Ok((currency_amount, v_currency_amount, mint_fee)) + } + + /// Process redeem. + /// Parameters: + /// - `redeem_currency_id`: The redeem currency id. + /// - `redeemer`: The redeemer account id. + /// - `unlock_id`: The unlock id. + /// - `redeem_currency_amount`: The redeem currency amount. + /// - `entrance_account_balance`: The entrance account balance. + /// - `time_unit`: The time unit. + /// - `redeem_type`: The redeem type. + fn process_redeem( + redeem_currency_id: CurrencyId, + redeemer: AccountIdOf, + unlock_id: &UnlockId, + redeem_currency_amount: BalanceOf, + entrance_account_balance: BalanceOf, + time_unit: TimeUnit, + redeem_type: RedeemType>, + ) -> DispatchResult { + let (redeem_currency_amount, redeem_to) = Self::transfer_to_by_redeem_type( + redeemer.clone(), + redeem_currency_id, + redeem_currency_amount, + entrance_account_balance, + redeem_type, + )?; + + Self::update_unlock_ledger( + &redeemer, + &redeem_currency_id, + &redeem_currency_amount, + unlock_id, + &time_unit, + None, + Operation::Sub, + )?; + + T::OnRedeemSuccess::on_redeem_success( + redeem_currency_id, + redeemer.clone(), + redeem_currency_amount, + ); + + Self::deposit_event(Event::RedeemSuccess { + redeemer, + unlock_id: *unlock_id, + currency_id: redeem_currency_id, + to: redeem_to, + currency_amount: redeem_currency_amount, + }); + Ok(()) + } + + /// Transfer to by redeem type. + /// Parameters: + /// - `redeemer`: The redeemer account id. + /// - `redeem_currency_id`: The redeem currency id. + /// - `redeem_currency_amount`: The redeem currency amount. + /// - `entrance_account_balance`: The entrance account balance. + /// - `redeem_type`: The redeem type. + /// Returns: + /// - `(BalanceOf, RedeemTo)`: The redeem currency amount, redeem to. + pub fn transfer_to_by_redeem_type( + redeemer: T::AccountId, + redeem_currency_id: CurrencyId, + mut redeem_currency_amount: BalanceOf, + entrance_account_balance: BalanceOf, + redeem_type: RedeemType, + ) -> Result<(BalanceOf, RedeemTo), DispatchError> { + let entrance_account = T::EntranceAccount::get().into_account_truncating(); + if entrance_account_balance >= redeem_currency_amount { + if let RedeemType::Native = redeem_type { + let ed = T::MultiCurrency::minimum_balance(redeem_currency_id); + if redeem_currency_amount >= ed { + T::MultiCurrency::transfer( + redeem_currency_id, + &entrance_account, + &redeemer, + redeem_currency_amount, + )?; + } + return Ok((redeem_currency_amount, RedeemTo::Native(redeemer))); + } + let (dest, redeem_to) = match redeem_type { + RedeemType::Astar(receiver) => ( + Location::new( + 1, + [ + Parachain(AstarChainId::get()), + AccountId32 { + network: None, + id: receiver.encode().try_into().unwrap(), + }, + ], + ), + RedeemTo::Astar(receiver), + ), + RedeemType::Hydradx(receiver) => ( + Location::new( + 1, + [ + Parachain(HydrationChainId::get()), + AccountId32 { + network: None, + id: receiver.encode().try_into().unwrap(), + }, + ], + ), + RedeemTo::Hydradx(receiver), + ), + RedeemType::Interlay(receiver) => ( + Location::new( + 1, + [ + Parachain(InterlayChainId::get()), + AccountId32 { + network: None, + id: receiver.encode().try_into().unwrap(), + }, + ], + ), + RedeemTo::Interlay(receiver), + ), + RedeemType::Manta(receiver) => ( + Location::new( + 1, + [ + Parachain(MantaChainId::get()), + AccountId32 { + network: None, + id: receiver.encode().try_into().unwrap(), + }, + ], + ), + RedeemTo::Manta(receiver), + ), + RedeemType::Moonbeam(receiver) => ( + Location::new( + 1, + [ + Parachain(T::MoonbeamChainId::get()), + AccountKey20 { network: None, key: receiver.to_fixed_bytes() }, + ], + ), + RedeemTo::Moonbeam(receiver), + ), + RedeemType::Native => { + unreachable!() + }, + }; + if redeem_currency_id == FIL { + let assets = vec![ + (redeem_currency_id, redeem_currency_amount), + (BNC, T::BifrostSlpx::get_moonbeam_transfer_to_fee()), + ]; + + T::XcmTransfer::transfer_multicurrencies( + entrance_account.clone(), + assets, + 1, + dest, + Unlimited, + )?; + } else { + T::XcmTransfer::transfer( + entrance_account.clone(), + redeem_currency_id, + redeem_currency_amount, + dest, + Unlimited, + )?; + }; + Ok((redeem_currency_amount, redeem_to)) + } else { + redeem_currency_amount = entrance_account_balance; + let ed = T::MultiCurrency::minimum_balance(redeem_currency_id); + if redeem_currency_amount >= ed { + T::MultiCurrency::transfer( + redeem_currency_id, + &entrance_account, + &redeemer, + redeem_currency_amount, + )?; + } + Ok((redeem_currency_amount, RedeemTo::Native(redeemer))) + } + } + + #[transactional] + pub fn handle_ledger_by_currency(currency: CurrencyId) -> DispatchResult { + let time_unit = MinTimeUnit::::get(currency); + if let Some((_total_locked, ledger_list, currency_id)) = + TimeUnitUnlockLedger::::get(&time_unit, currency) + { + for unlock_id in ledger_list.iter().take(HookIterationLimit::::get() as usize) { + if let Some((account, unlock_amount, time_unit, redeem_type)) = + TokenUnlockLedger::::get(currency_id, unlock_id) + { + let entrance_account_balance = T::MultiCurrency::free_balance( + currency_id, + &T::EntranceAccount::get().into_account_truncating(), + ); + if entrance_account_balance == BalanceOf::::zero() { + break; + } + + Self::process_redeem( + currency_id, + account, + unlock_id, + unlock_amount, + entrance_account_balance, + time_unit, + redeem_type, + )?; + } + } + } else { + MinTimeUnit::::mutate(currency, |time_unit| -> Result<(), Error> { + let unlock_duration = + UnlockDuration::::get(currency).ok_or(Error::::UnlockDurationNotFound)?; + let ongoing_time = + OngoingTimeUnit::::get(currency).ok_or(Error::::OngoingTimeUnitNotSet)?; + let result_time_unit = + ongoing_time.add(unlock_duration).ok_or(Error::::CalculationOverflow)?; + if result_time_unit.gt(time_unit) { + *time_unit = time_unit.clone().add_one(); + } + Ok(()) + })?; + }; + + Ok(()) + } + + pub fn do_mint( + minter: AccountIdOf, + currency_id: CurrencyIdOf, + currency_amount: BalanceOf, + remark: BoundedVec>, + channel_id: Option, + ) -> Result, DispatchError> { + ensure!( + currency_amount >= MinimumMint::::get(currency_id), + Error::::BelowMinimumMint + ); + let v_currency_id = currency_id.to_vtoken().map_err(|_| Error::::NotSupportTokenType)?; + + let (currency_amount_excluding_fee, v_currency_amount, mint_fee) = + Self::mint_without_transfer(&minter, v_currency_id, currency_id, currency_amount)?; + + // Transfer the user's token to EntranceAccount. + T::MultiCurrency::transfer( + currency_id, + &minter, + &T::EntranceAccount::get().into_account_truncating(), + currency_amount_excluding_fee, + )?; + + // record the minting information for ChannelCommission module + T::ChannelCommission::record_mint_amount(channel_id, v_currency_id, v_currency_amount)?; + + Self::deposit_event(Event::Minted { + minter, + currency_id, + currency_amount, + v_currency_amount, + mint_fee, + remark, + channel_id, + }); + Ok(v_currency_amount.into()) + } + + pub fn do_redeem( + redeemer: AccountIdOf, + v_currency_id: CurrencyIdOf, + v_currency_amount: BalanceOf, + redeem_type: RedeemType>, + ) -> DispatchResultWithPostInfo { + let currency_id = v_currency_id.to_token().map_err(|_| Error::::NotSupportTokenType)?; + ensure!( + v_currency_amount >= MinimumRedeem::::get(v_currency_id), + Error::::BelowMinimumRedeem + ); + + // Charging fees + let (_, redeem_rate) = Fees::::get(); + let redeem_fee = redeem_rate.mul_floor(v_currency_amount); + T::MultiCurrency::transfer( + v_currency_id, + &redeemer, + &T::RedeemFeeAccount::get(), + redeem_fee, + )?; + + // Calculate the currency amount by v_currency_amount + let v_currency_amount = v_currency_amount + .checked_sub(&redeem_fee) + .ok_or(Error::::CalculationOverflow)?; + let currency_amount = Self::get_currency_amount_by_v_currency_amount( + currency_id, + v_currency_id, + v_currency_amount, + )?; + + // Withdraw the token from redeemer + T::MultiCurrency::withdraw(v_currency_id, &redeemer, v_currency_amount)?; + + // Calculate the time to be locked + let ongoing_time_unit = + OngoingTimeUnit::::get(currency_id).ok_or(Error::::OngoingTimeUnitNotSet)?; + let unlock_duration = + UnlockDuration::::get(currency_id).ok_or(Error::::UnlockDurationNotFound)?; + let lock_to_time_unit = ongoing_time_unit + .add(unlock_duration) + .ok_or(Error::::UnlockDurationNotFound)?; + + // Decrease the token pool amount + Self::update_token_pool(¤cy_id, ¤cy_amount, Operation::Sub)?; + + TokenUnlockNextId::::mutate(¤cy_id, |next_id| -> DispatchResultWithPostInfo { + Self::update_unlock_ledger( + &redeemer, + ¤cy_id, + ¤cy_amount, + &next_id, + &lock_to_time_unit, + Some(redeem_type), + Operation::Add, + )?; + + Self::deposit_event(Event::Redeemed { + redeemer: redeemer.clone(), + currency_id, + v_currency_amount, + currency_amount, + redeem_fee, + unlock_id: *next_id, + }); + + // Increase the next unlock id + *next_id = next_id.checked_add(1).ok_or(Error::::CalculationOverflow)?; + + T::ChannelCommission::record_redeem_amount(v_currency_id, v_currency_amount)?; + let extra_weight = T::OnRedeemSuccess::on_redeemed( + redeemer, + currency_id, + currency_amount, + v_currency_amount, + redeem_fee, + ); + Ok(Some(T::WeightInfo::redeem() + extra_weight).into()) + }) + } + + pub fn incentive_pool_account() -> AccountIdOf { + T::IncentivePoolAccount::get().into_account_truncating() + } + + // to lock user vtoken for incentive minting + pub fn lock_vtoken_for_incentive_minting( + minter: AccountIdOf, + v_currency_id: CurrencyIdOf, + v_currency_amount: BalanceOf, + ) -> Result<(), Error> { + // first, lock the vtoken + // second, record the lock in ledger + + // check whether the minter has enough vtoken + T::MultiCurrency::ensure_can_withdraw(v_currency_id, &minter, v_currency_amount) + .map_err(|_| Error::::NotEnoughBalance)?; + + // new amount that should be locked + let mut new_lock_total = v_currency_amount; + + // check the previous locked amount under the same v_currency_id from ledger + // and revise ledger to set the new_amount to be previous_amount + v_currency_amount + VtokenLockLedger::::mutate_exists( + &minter, + &v_currency_id, + |v_token_lock_ledger| -> Result<(), Error> { + // get the vtoken lock duration from VtokenIncentiveCoef + let lock_duration = MintWithLockBlocks::::get(v_currency_id) + .ok_or(Error::::IncentiveLockBlocksNotSet)?; + let current_block = frame_system::Pallet::::block_number(); + let due_block = current_block + .checked_add(&lock_duration) + .ok_or(Error::::CalculationOverflow)?; + + match v_token_lock_ledger { + Some((total_locked, lock_records)) => { + // check the total locked amount + new_lock_total = total_locked + .checked_add(&v_currency_amount) + .ok_or(Error::::CalculationOverflow)?; + + *total_locked = new_lock_total; + + // push new item to the boundedvec of the ledger + lock_records + .try_push((v_currency_amount, due_block)) + .map_err(|_| Error::::TooManyLocks)?; + }, + None => + *v_token_lock_ledger = Some(( + v_currency_amount, + BoundedVec::try_from(vec![(v_currency_amount, due_block)]) + .map_err(|_| Error::::TooManyLocks)?, + )), + } + + // extend the locked amount to be new_lock_total + T::MultiCurrency::set_lock( + INCENTIVE_LOCK_ID, + v_currency_id, + &minter, + new_lock_total, + ) + .map_err(|_| Error::::NotEnoughBalance) + }, + ) + } + + pub fn calculate_incentive_vtoken_amount( + minter: &AccountIdOf, + v_currency_id: CurrencyIdOf, + v_currency_amount: BalanceOf, + ) -> Result, Error> { + // get the vtoken pool balance + let vtoken_pool_balance = + T::MultiCurrency::free_balance(v_currency_id, &Self::incentive_pool_account()); + ensure!(vtoken_pool_balance > BalanceOf::::zero(), Error::::NotEnoughBalance); + + // get current block number + let current_block_number: BlockNumberFor = frame_system::Pallet::::block_number(); + // get the veBNC total amount + let vebnc_total_issuance = T::BbBNC::total_supply(current_block_number) + .map_err(|_| Error::::VeBNCCheckingError)?; + ensure!(vebnc_total_issuance > BalanceOf::::zero(), Error::::BalanceZero); + + // get the veBNC balance of the minter + let minter_vebnc_balance = + T::BbBNC::balance_of(minter, None).map_err(|_| Error::::VeBNCCheckingError)?; + ensure!(minter_vebnc_balance > BalanceOf::::zero(), Error::::NotEnoughBalance); + + // get the percentage of the veBNC balance of the minter to the total veBNC amount and + // get the square root of the percentage + let percentage = Permill::from_rational(minter_vebnc_balance, vebnc_total_issuance); + let sqrt_percentage = + FixedU128::from_inner(percentage * 1_000_000_000_000_000_000u128).sqrt(); + let percentage = Permill::from_rational( + sqrt_percentage.into_inner(), + 1_000_000_000_000_000_000u128.into(), + ); + // get the total issuance of the vtoken + let v_currency_total_issuance = T::MultiCurrency::total_issuance(v_currency_id); + + // get the incentive coef for the vtoken + let incentive_coef = VtokenIncentiveCoef::::get(v_currency_id) + .ok_or(Error::::IncentiveCoefNotFound)?; + + // calculate the incentive amount, but mind the overflow + // incentive_amount = vtoken_pool_balance * incentive_coef * v_currency_amount * + // sqrt_percentage / v_currency_total_issuance + let incentive_amount = + U256::from(percentage.mul_ceil(vtoken_pool_balance).saturated_into::()) + .checked_mul(U256::from(incentive_coef)) + .and_then(|x| x.checked_mul(U256::from(v_currency_amount.saturated_into::()))) + // .and_then(|x| x.checked_mul(percentage)) + .and_then(|x| { + x.checked_div(U256::from(v_currency_total_issuance.saturated_into::())) + }) + // first turn into u128,then use unique_saturated_into BalanceOf + .map(|x| x.saturated_into::()) + .map(|x| x.unique_saturated_into()) + .ok_or(Error::::CalculationOverflow)?; + + Ok(incentive_amount) + } +} + +impl VtokenMintingOperator, AccountIdOf, TimeUnit> + for Pallet +{ + fn get_token_pool(currency_id: CurrencyId) -> BalanceOf { + TokenPool::::get(currency_id) + } + + fn increase_token_pool( + currency_id: CurrencyId, + currency_amount: BalanceOf, + ) -> DispatchResult { + Self::update_token_pool(¤cy_id, ¤cy_amount, Operation::Add) + } + + fn decrease_token_pool( + currency_id: CurrencyId, + currency_amount: BalanceOf, + ) -> DispatchResult { + Self::update_token_pool(¤cy_id, ¤cy_amount, Operation::Sub) + } + + fn update_ongoing_time_unit(currency_id: CurrencyId, time_unit: TimeUnit) -> DispatchResult { + OngoingTimeUnit::::mutate(currency_id, |time_unit_old| -> Result<(), Error> { + *time_unit_old = Some(time_unit); + Ok(()) + })?; + + Ok(()) + } + + fn get_ongoing_time_unit(currency_id: CurrencyId) -> Option { + OngoingTimeUnit::::get(currency_id) + } + + fn get_unlock_records( + currency_id: CurrencyId, + time_unit: TimeUnit, + ) -> Option<(BalanceOf, Vec)> { + if let Some((balance, list, _)) = TimeUnitUnlockLedger::::get(&time_unit, currency_id) { + Some((balance, list.into_inner())) + } else { + None + } + } + + fn get_entrance_and_exit_accounts() -> (AccountIdOf, AccountIdOf) { + ( + T::EntranceAccount::get().into_account_truncating(), + T::ExitAccount::get().into_account_truncating(), + ) + } + + fn get_token_unlock_ledger( + currency_id: CurrencyId, + index: u32, + ) -> Option<(AccountIdOf, BalanceOf, TimeUnit, RedeemType>)> { + TokenUnlockLedger::::get(currency_id, index) + } + + fn get_moonbeam_parachain_id() -> u32 { + T::MoonbeamChainId::get() + } +} + +impl VtokenMintingInterface, CurrencyIdOf, BalanceOf> + for Pallet +{ + fn mint( + exchanger: AccountIdOf, + currency_id: CurrencyIdOf, + currency_amount: BalanceOf, + remark: BoundedVec>, + channel_id: Option, + ) -> Result, DispatchError> { + Self::do_mint(exchanger, currency_id, currency_amount, remark, channel_id) + } + + fn redeem( + exchanger: AccountIdOf, + v_currency_id: CurrencyIdOf, + v_currency_amount: BalanceOf, + ) -> DispatchResultWithPostInfo { + Self::do_redeem(exchanger, v_currency_id, v_currency_amount, RedeemType::Native) + } + + fn slpx_redeem( + exchanger: AccountIdOf, + v_currency_id: CurrencyIdOf, + v_currency_amount: BalanceOf, + redeem_type: RedeemType>, + ) -> DispatchResultWithPostInfo { + Self::do_redeem(exchanger, v_currency_id, v_currency_amount, redeem_type) + } + + fn get_v_currency_amount_by_currency_amount( + currency_id: CurrencyIdOf, + v_currency_id: CurrencyIdOf, + currency_amount: BalanceOf, + ) -> Result, DispatchError> { + let token_pool_amount = TokenPool::::get(currency_id); + let v_currency_total_issuance = T::MultiCurrency::total_issuance(v_currency_id); + + if BalanceOf::::zero().eq(&token_pool_amount) { + Ok(currency_amount) + } else { + Ok(multiply_by_rational_with_rounding( + currency_amount.saturated_into::(), + v_currency_total_issuance.saturated_into::(), + token_pool_amount.saturated_into::(), + Rounding::Down, + ) + .ok_or(Error::::CalculationOverflow)? + .unique_saturated_into()) + } + } + + /// Get the v_currency amount by currency amount. + /// Parameters: + /// - `currency_id`: The currency id. + /// - `v_currency_id`: The v_currency id. + /// - `currency_amount`: The currency amount. + /// Returns: + /// - `Result`: The v_currency amount. + fn get_currency_amount_by_v_currency_amount( + currency_id: CurrencyIdOf, + v_currency_id: CurrencyIdOf, + v_currency_amount: BalanceOf, + ) -> Result, DispatchError> { + let token_pool_amount = TokenPool::::get(currency_id); + let v_currency_total_issuance = T::MultiCurrency::total_issuance(v_currency_id); + + if BalanceOf::::zero().eq(&v_currency_total_issuance) { + Ok(v_currency_amount) + } else { + Ok(multiply_by_rational_with_rounding( + v_currency_amount.saturated_into::(), + token_pool_amount.saturated_into::(), + v_currency_total_issuance.saturated_into::(), + Rounding::Down, + ) + .ok_or(Error::::CalculationOverflow)? + .unique_saturated_into()) + } + } + + fn get_minimums_redeem(v_currency_id: CurrencyIdOf) -> BalanceOf { + MinimumRedeem::::get(v_currency_id) + } + + fn get_token_pool(currency_id: CurrencyId) -> BalanceOf { + TokenPool::::get(currency_id) + } + + fn get_moonbeam_parachain_id() -> u32 { + T::MoonbeamChainId::get() + } +} + +impl VTokenSupplyProvider, BalanceOf> for Pallet { + fn get_vtoken_supply(vtoken: CurrencyIdOf) -> Option> { + if CurrencyId::is_vtoken(&vtoken) { + Some(T::MultiCurrency::total_issuance(vtoken)) + } else { + None + } + } + + fn get_token_supply(token: CurrencyIdOf) -> Option> { + if CurrencyId::is_token(&token) | CurrencyId::is_native(&token) { + Some(TokenPool::::get(token)) + } else { + None + } + } +} diff --git a/pallets/vtoken-minting/src/lib.rs b/pallets/vtoken-minting/src/lib.rs index b145c2de7..849633dab 100644 --- a/pallets/vtoken-minting/src/lib.rs +++ b/pallets/vtoken-minting/src/lib.rs @@ -28,44 +28,37 @@ mod tests; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +pub mod impls; pub mod migration; pub mod traits; pub mod weights; pub use weights::WeightInfo; +use crate::impls::Operation; use bb_bnc::traits::BbBNCInterface; -use bifrost_asset_registry::AssetMetadata; use bifrost_primitives::{ - CurrencyId, CurrencyIdConversion, CurrencyIdExt, CurrencyIdMapping, CurrencyIdRegister, - RedeemType, SlpOperator, SlpxOperator, TimeUnit, VTokenMintRedeemProvider, - VTokenSupplyProvider, VtokenMintingInterface, VtokenMintingOperator, + CurrencyId, RedeemType, SlpxOperator, TimeUnit, VTokenMintRedeemProvider, }; use frame_support::{ - pallet_prelude::*, + pallet_prelude::{DispatchResultWithPostInfo, *}, sp_runtime::{ - traits::{ - AccountIdConversion, CheckedAdd, CheckedSub, Saturating, UniqueSaturatedInto, Zero, - }, - ArithmeticError, DispatchError, FixedU128, Permill, SaturatedConversion, + traits::{CheckedAdd, CheckedSub, Saturating, Zero}, + DispatchError, Permill, }, traits::LockIdentifier, - transactional, BoundedVec, PalletId, + BoundedVec, PalletId, }; use frame_system::pallet_prelude::*; use log; -use orml_traits::{MultiCurrency, MultiLockableCurrency}; +use orml_traits::{MultiCurrency, MultiLockableCurrency, XcmTransfer}; pub use pallet::*; -use sp_core::U256; -use sp_std::{vec, vec::Vec}; +use sp_std::vec; pub use traits::*; -use xcm::v3::MultiLocation; pub type AccountIdOf = ::AccountId; - pub type CurrencyIdOf = <::MultiCurrency as MultiCurrency< ::AccountId, >>::CurrencyId; - pub type BalanceOf = <::MultiCurrency as MultiCurrency>>::Balance; pub type UnlockId = u32; @@ -76,12 +69,6 @@ const INCENTIVE_LOCK_ID: LockIdentifier = *b"vmincntv"; #[frame_support::pallet] pub mod pallet { use super::*; - use bifrost_primitives::{ - currency::BNC, AstarChainId, HydrationChainId, InterlayChainId, MantaChainId, FIL, - }; - use frame_support::pallet_prelude::DispatchResultWithPostInfo; - use orml_traits::XcmTransfer; - use xcm::{prelude::*, v4::Location}; #[pallet::pallet] pub struct Pallet(_); @@ -89,13 +76,13 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; - - type MultiCurrency: MultiCurrency, CurrencyId = CurrencyId> - + MultiLockableCurrency>; - + /// Set default weight. + type WeightInfo: WeightInfo; /// The only origin that can edit token issuer list type ControlOrigin: EnsureOrigin; - + /// The multi currency trait. + type MultiCurrency: MultiCurrency, CurrencyId = CurrencyId> + + MultiLockableCurrency>; /// Handler to notify the runtime when redeem success /// If you don't need it, you can specify the type `()`. type OnRedeemSuccess: OnRedeemSuccess< @@ -103,30 +90,39 @@ pub mod pallet { CurrencyIdOf, BalanceOf, >; - - /// xtokens xcm transfer interface + /// Xtokens xcm transfer interface type XcmTransfer: XcmTransfer, BalanceOf, CurrencyIdOf>; + /// Slpx operator + type BifrostSlpx: SlpxOperator>; + /// bbBNC interface + type BbBNC: BbBNCInterface< + AccountIdOf, + CurrencyIdOf, + BalanceOf, + BlockNumberFor, + >; + /// Channel commission provider + type ChannelCommission: VTokenMintRedeemProvider>; - /// The amount of mint + /// Maximum unlock id of user #[pallet::constant] type MaximumUnlockIdOfUser: Get; - + /// Maximum unlock id of time unit #[pallet::constant] type MaximumUnlockIdOfTimeUnit: Get; - - // maximum unlocked vtoken records minted in an incentive mode + /// Maximum unlocked vtoken records minted in an incentive mode #[pallet::constant] type MaxLockRecords: Get; - + /// Currency receive account #[pallet::constant] type EntranceAccount: Get; - + /// Currency exit account #[pallet::constant] type ExitAccount: Get; - + /// Fee account #[pallet::constant] type FeeAccount: Get; - + /// Redeem fee account #[pallet::constant] type RedeemFeeAccount: Get; @@ -138,192 +134,249 @@ pub mod pallet { #[pallet::constant] type MoonbeamChainId: Get; - - type BifrostSlp: SlpOperator; - - type BifrostSlpx: SlpxOperator>; - - // bbBNC interface - type BbBNC: BbBNCInterface< - AccountIdOf, - CurrencyIdOf, - BalanceOf, - BlockNumberFor, - >; - - type CurrencyIdConversion: CurrencyIdConversion; - - type CurrencyIdRegister: CurrencyIdRegister; - - type ChannelCommission: VTokenMintRedeemProvider>; - - type AssetIdMaps: CurrencyIdMapping< - CurrencyId, - MultiLocation, - AssetMetadata>, - >; - - /// Set default weight. - type WeightInfo: WeightInfo; } #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { + /// Vtoken minted successfully. Minted { - address: AccountIdOf, - token_id: CurrencyIdOf, - token_amount: BalanceOf, - vtoken_amount: BalanceOf, - fee: BalanceOf, + /// The minter account. + minter: AccountIdOf, + /// The currency id minted. + currency_id: CurrencyIdOf, + /// The currency amount minted. + currency_amount: BalanceOf, + /// The v_currency amount minted. + v_currency_amount: BalanceOf, + /// The mint fee. + mint_fee: BalanceOf, + /// The remark of minting. remark: BoundedVec>, + /// The channel id of minting. channel_id: Option, }, + /// Vtoken redeemed successfully. Redeemed { - address: AccountIdOf, - token_id: CurrencyIdOf, - token_amount: BalanceOf, - vtoken_amount: BalanceOf, - fee: BalanceOf, + /// The redeemer account. + redeemer: AccountIdOf, + /// The currency id redeemed. + currency_id: CurrencyIdOf, + /// Will be received currency amount. + currency_amount: BalanceOf, + /// The v_currency amount redeemed. + v_currency_amount: BalanceOf, + /// The redeem fee. + redeem_fee: BalanceOf, + /// The unlock_id of redeeming. unlock_id: UnlockId, }, + /// Process redeem successfully. RedeemSuccess { + /// The redeemer account. + redeemer: AccountIdOf, + /// The unlock_id redeemed. unlock_id: UnlockId, - token_id: CurrencyIdOf, + /// The currency id redeemed. + currency_id: CurrencyIdOf, + /// Will transfer to this account. to: RedeemTo>, - token_amount: BalanceOf, + /// The redeem amount. + currency_amount: BalanceOf, }, + /// Vtoken rebonded successfully. Rebonded { - address: AccountIdOf, - token_id: CurrencyIdOf, - token_amount: BalanceOf, - vtoken_amount: BalanceOf, + /// The rebonder account. + rebonder: AccountIdOf, + /// The currency id rebonded. + currency_id: CurrencyIdOf, + /// The currency amount rebonded. + currency_amount: BalanceOf, + /// The v_currency amount rebonded. + v_currency_amount: BalanceOf, + /// Mint fee fee: BalanceOf, }, + /// Vtoken rebonded by unlock_id successfully. RebondedByUnlockId { - address: AccountIdOf, - token_id: CurrencyIdOf, - token_amount: BalanceOf, - vtoken_amount: BalanceOf, + /// The rebonder account. + rebonder: AccountIdOf, + /// The currency id rebonded. + currency_id: CurrencyIdOf, + /// The currency amount rebonded. + currency_amount: BalanceOf, + /// The v_currency amount rebonded. + v_currency_amount: BalanceOf, + /// Mint fee fee: BalanceOf, + /// The unlock_id rebonded. unlock_id: UnlockId, }, + /// Set unlock duration. UnlockDurationSet { - token_id: CurrencyIdOf, + /// The currency id set unlock duration. + currency_id: CurrencyIdOf, + /// The unlock duration set. unlock_duration: TimeUnit, }, + /// Set minimum mint amount. MinimumMintSet { - token_id: CurrencyIdOf, - amount: BalanceOf, + /// The currency id set minimum mint amount. + currency_id: CurrencyIdOf, + /// The minimum mint amount set. + minimum_amount: BalanceOf, }, + /// Set minimum redeem amount. MinimumRedeemSet { - token_id: CurrencyIdOf, - amount: BalanceOf, + /// The currency id set minimum redeem amount. + currency_id: CurrencyIdOf, + /// The minimum redeem amount set. + minimum_amount: BalanceOf, }, + /// Support rebond token added. SupportRebondTokenAdded { - token_id: CurrencyIdOf, + /// The currency id support rebond. + currency_id: CurrencyIdOf, }, + /// Support rebond token removed. SupportRebondTokenRemoved { - token_id: CurrencyIdOf, + /// The currency id remove support rebond. + currency_id: CurrencyIdOf, }, - /// Several fees has been set. + /// Set mint fee and redeem fee. FeeSet { + /// The mint fee rate set. mint_fee: Permill, + /// The redeem fee rate set. redeem_fee: Permill, - // hosting_fee: BalanceOf, - }, - HookIterationLimitSet { - limit: u32, }, + /// Set hook iteration limit. + HookIterationLimitSet { limit: u32 }, + /// Set unlock total amount. UnlockingTotalSet { - token_id: CurrencyIdOf, - amount: BalanceOf, + /// The currency id set unlock total amount. + currency_id: CurrencyIdOf, + /// The unlock total amount set. + currency_amount: BalanceOf, }, + /// Set minimum time unit. MinTimeUnitSet { - token_id: CurrencyIdOf, + /// The currency id set minimum time unit. + currency_id: CurrencyIdOf, + /// The minimum time unit set. time_unit: TimeUnit, }, - FastRedeemFailed { - err: DispatchError, - }, - CurrencyTimeUnitRecreated { - token_id: CurrencyIdOf, + /// Fast redeem failed. + FastRedeemFailed { err: DispatchError }, + /// Set ongoing time unit. + SetOngoingTimeUnit { + /// The currency id set ongoing time unit. + currency_id: CurrencyIdOf, + /// The ongoing time unit set. time_unit: TimeUnit, }, + /// Incentivized minting. IncentivizedMinting { address: AccountIdOf, - token_id: CurrencyIdOf, - token_amount: BalanceOf, + currency_id: CurrencyIdOf, + currency_amount: BalanceOf, locked_vtoken_amount: BalanceOf, incentive_vtoken_amount: BalanceOf, }, - VtokenIncentiveCoefSet { - vtoken_id: CurrencyIdOf, - coefficient: Option, - }, + /// Incentive coefficient set. + VtokenIncentiveCoefSet { v_currency_id: CurrencyIdOf, coefficient: Option }, + /// Incentive lock blocks set. VtokenIncentiveLockBlocksSet { - vtoken_id: CurrencyIdOf, + v_currency_id: CurrencyIdOf, blocks: Option>, }, } #[pallet::error] pub enum Error { + /// Below minimum mint amount. BelowMinimumMint, + /// Below minimum redeem amount. BelowMinimumRedeem, /// Invalid token to rebond. InvalidRebondToken, /// Token type not support. NotSupportTokenType, + /// Not enough balance to unlock. NotEnoughBalanceToUnlock, + /// Token unlock ledger not found. TokenToRebondNotZero, + /// Ongoing time unit not set. OngoingTimeUnitNotSet, + /// Token unlock ledger not found. TokenUnlockLedgerNotFound, + /// User unlock ledger not found. UserUnlockLedgerNotFound, + /// Time unit unlock ledger not found. TimeUnitUnlockLedgerNotFound, + /// Unlock duration not found. UnlockDurationNotFound, + /// Unexpected error. Unexpected, + /// Calculation overflow. CalculationOverflow, + /// Exceed maximum unlock id. ExceedMaximumUnlockId, + /// Too many redeems. TooManyRedeems, - CanNotRedeem, + /// Can not rebond. CanNotRebond, + /// Not enough balance. NotEnoughBalance, + /// veBNC checking error. VeBNCCheckingError, + /// IncentiveCoef not found. IncentiveCoefNotFound, + /// Too many locks. TooManyLocks, - ConvertError, + /// No unlock record. NoUnlockRecord, + /// Fail to remove lock. FailToRemoveLock, + /// Balance not zero. BalanceZero, + /// IncentiveLockBlocksNotSet IncentiveLockBlocksNotSet, } + /// The mint fee and redeem fee. #[pallet::storage] pub type Fees = StorageValue<_, (Permill, Permill), ValueQuery>; + /// Token pool amount #[pallet::storage] pub type TokenPool = StorageMap<_, Twox64Concat, CurrencyIdOf, BalanceOf, ValueQuery>; + /// Unlock duration for each currency #[pallet::storage] pub type UnlockDuration = StorageMap<_, Twox64Concat, CurrencyIdOf, TimeUnit>; + /// Ongoing time unit for each currency #[pallet::storage] pub type OngoingTimeUnit = StorageMap<_, Twox64Concat, CurrencyIdOf, TimeUnit>; + /// Minimum mint amount for each currency #[pallet::storage] pub type MinimumMint = StorageMap<_, Twox64Concat, CurrencyIdOf, BalanceOf, ValueQuery>; + /// Minimum redeem amount for each currency #[pallet::storage] pub type MinimumRedeem = StorageMap<_, Twox64Concat, CurrencyIdOf, BalanceOf, ValueQuery>; + /// Next unlock id for each currency #[pallet::storage] pub type TokenUnlockNextId = StorageMap<_, Twox64Concat, CurrencyIdOf, u32, ValueQuery>; + /// According to currency_id and unlock_id, unlock information are stored. #[pallet::storage] pub type TokenUnlockLedger = StorageDoubleMap< _, @@ -331,10 +384,20 @@ pub mod pallet { CurrencyIdOf, Blake2_128Concat, UnlockId, - (T::AccountId, BalanceOf, TimeUnit, RedeemType>), + ( + // redeemer account + T::AccountId, + // redeem amount + BalanceOf, + // lock to time unit + TimeUnit, + // redeem type + RedeemType>, + ), OptionQuery, >; + /// According to the user's account, the locked amount and unlock id list are stored. #[pallet::storage] pub type UserUnlockLedger = StorageDoubleMap< _, @@ -342,10 +405,16 @@ pub mod pallet { AccountIdOf, Blake2_128Concat, CurrencyIdOf, - (BalanceOf, BoundedVec), + ( + // Total locked amount + BalanceOf, + // UnlockId list + BoundedVec, + ), OptionQuery, >; + /// The total amount of tokens that are currently locked for unlocking. #[pallet::storage] pub type TimeUnitUnlockLedger = StorageDoubleMap< _, @@ -353,21 +422,32 @@ pub mod pallet { TimeUnit, Blake2_128Concat, CurrencyIdOf, - (BalanceOf, BoundedVec, CurrencyIdOf), + ( + // Total locked amount + BalanceOf, + // UnlockId list + BoundedVec, + // CurrencyId + CurrencyIdOf, + ), OptionQuery, >; + /// The total amount of tokens that are currently locked for rebonding. #[pallet::storage] pub type TokenToRebond = StorageMap<_, Twox64Concat, CurrencyIdOf, BalanceOf>; + /// The min time unit for each currency #[pallet::storage] pub type MinTimeUnit = StorageMap<_, Twox64Concat, CurrencyIdOf, TimeUnit, ValueQuery>; + /// The total amount of tokens that are currently unlocking. #[pallet::storage] pub type UnlockingTotal = StorageMap<_, Twox64Concat, CurrencyIdOf, BalanceOf, ValueQuery>; + /// The hook iteration limit #[pallet::storage] pub type HookIterationLimit = StorageValue<_, u32, ValueQuery>; @@ -397,17 +477,20 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { fn on_initialize(_n: BlockNumberFor) -> Weight { - Self::handle_on_initialize() - .map_err(|err| { - Self::deposit_event(Event::FastRedeemFailed { err }); - log::error!( - target: "runtime::vtoken-minting", - "Received invalid justification for {:?}", - err, - ); - err - }) - .ok(); + for currency in OngoingTimeUnit::::iter_keys() { + let result = Self::handle_ledger_by_currency(currency); + match result { + Ok(_) => (), + Err(err) => { + Self::deposit_event(Event::FastRedeemFailed { err }); + log::error!( + target: "runtime::vtoken-minting", + "Received invalid justification for {:?}", + err, + ); + }, + } + } T::WeightInfo::on_initialize() } @@ -415,401 +498,293 @@ pub mod pallet { #[pallet::call] impl Pallet { + /// Mint v_currency by transferring currency to entrance_account. + /// The minted v_currency will be deposited to the minter's account. + /// Parameters: + /// - `currency_id`: The currency to mint. + /// - `currency_amount`: The amount of currency to mint. + /// - `remark`: The remark of minting. + /// - `channel_id`: The channel id of minting. #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::mint())] pub fn mint( origin: OriginFor, - token_id: CurrencyIdOf, - token_amount: BalanceOf, + currency_id: CurrencyIdOf, + currency_amount: BalanceOf, remark: BoundedVec>, channel_id: Option, ) -> DispatchResult { // Check origin - let exchanger = ensure_signed(origin)?; - Self::mint_inner(exchanger, token_id, token_amount, remark, channel_id).map(|_| ()) + let minter = ensure_signed(origin)?; + Self::do_mint(minter, currency_id, currency_amount, remark, channel_id)?; + Ok(()) } + /// Redeem currency by burning v_currency. But need to wait for the unlock period. + /// The redeemed currency will be transferred to the redeemer's account. + /// Parameters: + /// - `v_currency_id`: The v_currency to redeem. + /// - `v_currency_amount`: The amount of v_currency to redeem. #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::redeem())] pub fn redeem( origin: OriginFor, - vtoken_id: CurrencyIdOf, - vtoken_amount: BalanceOf, + v_currency_id: CurrencyIdOf, + v_currency_amount: BalanceOf, ) -> DispatchResultWithPostInfo { - let exchanger = ensure_signed(origin)?; - Self::redeem_inner(exchanger, vtoken_id, vtoken_amount, RedeemType::Native) + let redeemer = ensure_signed(origin)?; + Self::do_redeem(redeemer, v_currency_id, v_currency_amount, RedeemType::Native) } + /// Already redeemed currency by burning v_currency. But need to wait for the unlock period. + /// In unlock period, you call rebond to cancel the redeem. + /// Parameters: + /// - `currency_id`: The currency to rebond. + /// - `currency_amount`: The amount of currency to rebond. The amount should be less than or + /// equal to the redeem amount. #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::rebond())] pub fn rebond( origin: OriginFor, - token_id: CurrencyIdOf, - token_amount: BalanceOf, + currency_id: CurrencyIdOf, + currency_amount: BalanceOf, ) -> DispatchResult { - let exchanger = ensure_signed(origin)?; - let vtoken_id = T::CurrencyIdConversion::convert_to_vtoken(token_id) - .map_err(|_| Error::::NotSupportTokenType)?; - let _token_amount_to_rebond = - TokenToRebond::::get(token_id).ok_or(Error::::InvalidRebondToken)?; - if let Some((user_unlock_amount, mut ledger_list)) = - UserUnlockLedger::::get(&exchanger, token_id) - { - ensure!(user_unlock_amount >= token_amount, Error::::NotEnoughBalanceToUnlock); - let mut tmp_amount = token_amount; - let ledger_list_rev: Vec = ledger_list.into_iter().rev().collect(); - ledger_list = - BoundedVec::::try_from(ledger_list_rev) - .map_err(|_| Error::::ExceedMaximumUnlockId)?; - let mut tmp = ledger_list - .iter() - .map(|&index| -> Result<(UnlockId, bool), Error> { - if let Some((_, unlock_amount, time_unit, _)) = - TokenUnlockLedger::::get(token_id, index) - { - if tmp_amount >= unlock_amount { - if let Some((_, _, time_unit, _)) = - TokenUnlockLedger::::take(&token_id, &index) - { - TimeUnitUnlockLedger::::mutate_exists( - &time_unit, - &token_id, - |value| -> Result<(), Error> { - if let Some(( - total_locked_origin, - ledger_list_origin, - _, - )) = value - { - if total_locked_origin == &unlock_amount { - *value = None; - return Ok(()); - } - *total_locked_origin = total_locked_origin - .checked_sub(&unlock_amount) - .ok_or(Error::::CalculationOverflow)?; - ledger_list_origin.retain(|&x| x != index); - } else { - return Err( - Error::::TimeUnitUnlockLedgerNotFound, - ); - } - Ok(()) - }, - )?; - tmp_amount = tmp_amount.saturating_sub(unlock_amount); - } else { - return Err(Error::::TokenUnlockLedgerNotFound.into()); - } - Ok((index, false)) - } else { - TokenUnlockLedger::::mutate_exists( - &token_id, - &index, - |value| -> Result<(), Error> { - if let Some((_, total_locked_origin, _, _)) = value { - if total_locked_origin == &tmp_amount { - *value = None; - return Ok(()); - } - *total_locked_origin = total_locked_origin - .checked_sub(&tmp_amount) - .ok_or(Error::::CalculationOverflow)?; - } else { - return Err(Error::::TokenUnlockLedgerNotFound); - } - Ok(()) - }, - )?; - TimeUnitUnlockLedger::::mutate_exists( - &time_unit, - &token_id, - |value| -> Result<(), Error> { - if let Some((total_locked_origin, _, _)) = value { - if total_locked_origin == &tmp_amount { - *value = None; - return Ok(()); - } - *total_locked_origin = total_locked_origin - .checked_sub(&tmp_amount) - .ok_or(Error::::CalculationOverflow)?; - } else { - return Err(Error::::TimeUnitUnlockLedgerNotFound); - } - Ok(()) - }, - )?; - Ok((index, true)) - } - } else { - Ok((index, true)) - } - }) - .collect::, Error>>()?; - tmp.retain(|(_index, result)| *result); - - let ledger_list_tmp: Vec = - tmp.into_iter().map(|(index, _)| index).rev().collect(); - - ledger_list = - BoundedVec::::try_from(ledger_list_tmp) - .map_err(|_| Error::::ExceedMaximumUnlockId)?; - - UnlockingTotal::::mutate(&token_id, |pool| -> Result<(), Error> { - *pool = - pool.checked_sub(&token_amount).ok_or(Error::::CalculationOverflow)?; - Ok(()) - })?; - UserUnlockLedger::::mutate_exists( - &exchanger, - &token_id, - |value| -> Result<(), Error> { - if let Some((total_locked_origin, ledger_list_origin)) = value { - if total_locked_origin == &token_amount { - *value = None; - return Ok(()); - } - *ledger_list_origin = ledger_list; - *total_locked_origin = total_locked_origin - .checked_sub(&token_amount) - .ok_or(Error::::CalculationOverflow)?; - } else { - return Err(Error::::UserUnlockLedgerNotFound); - } - Ok(()) - }, + let rebonder = ensure_signed(origin)?; + let v_currency_id = + currency_id.to_vtoken().map_err(|_| Error::::NotSupportTokenType)?; + + let (user_unlock_amount, unlock_id_list) = + UserUnlockLedger::::get(&rebonder, currency_id) + .ok_or(Error::::UserUnlockLedgerNotFound)?; + ensure!(user_unlock_amount >= currency_amount, Error::::NotEnoughBalanceToUnlock); + + let mut temp_currency_amount = currency_amount; + for unlock_id in unlock_id_list.into_iter().rev() { + let (_, mut unlock_amount, time_unit, _) = + TokenUnlockLedger::::get(currency_id, unlock_id) + .ok_or(Error::::TokenUnlockLedgerNotFound)?; + + if temp_currency_amount <= unlock_amount { + unlock_amount = temp_currency_amount; + } else { + temp_currency_amount = temp_currency_amount.saturating_sub(unlock_amount); + } + + let is_remove_record = Self::update_unlock_ledger( + &rebonder, + ¤cy_id, + &unlock_amount, + &unlock_id, + &time_unit, + None, + Operation::Sub, )?; - } else { - return Err(Error::::UserUnlockLedgerNotFound.into()); + + if !is_remove_record { + break; + } } - let (_, vtoken_amount, fee) = - Self::mint_without_tranfer(&exchanger, vtoken_id, token_id, token_amount)?; + let (_, v_currency_amount, fee) = Self::mint_without_transfer( + &rebonder, + v_currency_id, + currency_id, + currency_amount, + )?; - TokenToRebond::::mutate(&token_id, |value| -> Result<(), Error> { - if let Some(value_info) = value { - *value_info = value_info - .checked_add(&token_amount) - .ok_or(Error::::CalculationOverflow)?; - } else { - return Err(Error::::InvalidRebondToken); + TokenToRebond::::mutate(¤cy_id, |maybe_value| -> Result<(), Error> { + match maybe_value { + Some(rebonded_amount) => { + *rebonded_amount = rebonded_amount + .checked_add(¤cy_amount) + .ok_or(Error::::CalculationOverflow)?; + Ok(()) + }, + None => Err(Error::::InvalidRebondToken), } - Ok(()) })?; Self::deposit_event(Event::Rebonded { - address: exchanger, - token_id, - token_amount, - vtoken_amount, + rebonder, + currency_id, + currency_amount, + v_currency_amount, fee, }); Ok(()) } + /// Same function as Rebond. But need to provide unlock_id. + /// Parameters: + /// - `currency_id`: The currency to rebond. + /// - `unlock_id`: The unlock_id to rebond. #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::rebond_by_unlock_id())] pub fn rebond_by_unlock_id( origin: OriginFor, - token_id: CurrencyIdOf, + currency_id: CurrencyIdOf, unlock_id: UnlockId, ) -> DispatchResult { - let exchanger = ensure_signed(origin)?; - - let vtoken_id = T::CurrencyIdConversion::convert_to_vtoken(token_id) - .map_err(|_| Error::::NotSupportTokenType)?; - let _token_amount_to_rebond = - TokenToRebond::::get(token_id).ok_or(Error::::InvalidRebondToken)?; - - let unlock_amount = match TokenUnlockLedger::::get(token_id, unlock_id) { - Some((who, unlock_amount, time_unit, _)) => { - ensure!(who == exchanger, Error::::CanNotRebond); - TimeUnitUnlockLedger::::mutate_exists( - &time_unit, - &token_id, - |value| -> Result<(), Error> { - if let Some((total_locked_origin, ledger_list_origin, _)) = value { - if total_locked_origin == &unlock_amount { - *value = None; - return Ok(()); - } - *total_locked_origin = total_locked_origin - .checked_sub(&unlock_amount) - .ok_or(Error::::CalculationOverflow)?; - ledger_list_origin.retain(|&x| x != unlock_id); - } else { - return Err(Error::::TimeUnitUnlockLedgerNotFound); - } - Ok(()) - }, - )?; - - UserUnlockLedger::::mutate_exists( - &who, - &token_id, - |value| -> Result<(), Error> { - if let Some((total_locked_origin, ledger_list_origin)) = value { - if total_locked_origin == &unlock_amount { - *value = None; - return Ok(()); - } - *total_locked_origin = total_locked_origin - .checked_sub(&unlock_amount) - .ok_or(Error::::CalculationOverflow)?; - ledger_list_origin.retain(|&x| x != unlock_id); - } else { - return Err(Error::::UserUnlockLedgerNotFound); - } - Ok(()) - }, - )?; - UnlockingTotal::::mutate(&token_id, |pool| -> Result<(), Error> { - *pool = pool - .checked_sub(&unlock_amount) - .ok_or(Error::::CalculationOverflow)?; - Ok(()) - })?; + let rebonder = ensure_signed(origin)?; - TokenUnlockLedger::::remove(&token_id, &unlock_id); - unlock_amount - }, - _ => return Err(Error::::TokenUnlockLedgerNotFound.into()), - }; + let v_currency_id = + currency_id.to_vtoken().map_err(|_| Error::::NotSupportTokenType)?; - let (token_amount, vtoken_amount, fee) = - Self::mint_without_tranfer(&exchanger, vtoken_id, token_id, unlock_amount)?; + let (who, unlock_amount, time_unit, _) = + TokenUnlockLedger::::get(currency_id, unlock_id) + .ok_or(Error::::TokenUnlockLedgerNotFound)?; + ensure!(who == rebonder, Error::::CanNotRebond); - TokenToRebond::::mutate(&token_id, |value| -> Result<(), Error> { - if let Some(value_info) = value { - *value_info = value_info - .checked_add(&token_amount) - .ok_or(Error::::CalculationOverflow)?; - } else { - return Err(Error::::InvalidRebondToken); + Self::update_unlock_ledger( + &rebonder, + ¤cy_id, + &unlock_amount, + &unlock_id, + &time_unit, + None, + Operation::Sub, + )?; + + let (currency_amount, v_currency_amount, fee) = + Self::mint_without_transfer(&rebonder, v_currency_id, currency_id, unlock_amount)?; + + TokenToRebond::::mutate(¤cy_id, |maybe_value| -> Result<(), Error> { + match maybe_value { + Some(rebonded_amount) => { + *rebonded_amount = rebonded_amount + .checked_add(¤cy_amount) + .ok_or(Error::::CalculationOverflow)?; + Ok(()) + }, + None => Err(Error::::InvalidRebondToken), } - Ok(()) })?; Self::deposit_event(Event::RebondedByUnlockId { - address: exchanger, - token_id, - token_amount: unlock_amount, - vtoken_amount, + rebonder, + currency_id, + currency_amount: unlock_amount, + v_currency_amount, fee, unlock_id, }); Ok(()) } + /// Set the unlock duration for a currency. + /// Parameters: + /// - `currency_id`: The currency to set unlock duration. + /// - `unlock_duration`: The unlock duration to set. #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::set_unlock_duration())] pub fn set_unlock_duration( origin: OriginFor, - token_id: CurrencyIdOf, + currency_id: CurrencyIdOf, unlock_duration: TimeUnit, ) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; - UnlockDuration::::mutate(token_id, |old_unlock_duration| { + UnlockDuration::::mutate(currency_id, |old_unlock_duration| { *old_unlock_duration = Some(unlock_duration.clone()); }); - Self::deposit_event(Event::UnlockDurationSet { token_id, unlock_duration }); - + Self::deposit_event(Event::UnlockDurationSet { currency_id, unlock_duration }); Ok(()) } + /// Set the minimum mint amount for a currency. + /// Parameters: + /// - `currency_id`: The currency to set minimum mint amount. + /// - `minimum_amount`: The minimum mint amount to set. #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::set_minimum_mint())] pub fn set_minimum_mint( origin: OriginFor, - token_id: CurrencyIdOf, - amount: BalanceOf, + currency_id: CurrencyIdOf, + minimum_amount: BalanceOf, ) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; - if !MinimumMint::::contains_key(token_id) { - // mutate_exists - MinimumMint::::insert(token_id, amount); - } else { - MinimumMint::::mutate(token_id, |old_amount| { - *old_amount = amount; - }); - } - - match token_id { - CurrencyId::Token(token_symbol) => - if !T::CurrencyIdRegister::check_vtoken_registered(token_symbol) { - T::CurrencyIdRegister::register_vtoken_metadata(token_symbol)?; - }, - CurrencyId::Token2(token_id) => { - if !T::CurrencyIdRegister::check_vtoken2_registered(token_id) { - T::CurrencyIdRegister::register_vtoken2_metadata(token_id)?; - } - }, - _ => (), - } + MinimumMint::::mutate(currency_id, |old_amount| { + *old_amount = minimum_amount; + }); - Self::deposit_event(Event::MinimumMintSet { token_id, amount }); + Self::deposit_event(Event::MinimumMintSet { currency_id, minimum_amount }); Ok(()) } + /// Set the minimum redeem amount for a currency. + /// Parameters: + /// - `currency_id`: The currency to set minimum redeem amount. + /// - `minimum_amount`: The minimum redeem amount to set. #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::set_minimum_redeem())] pub fn set_minimum_redeem( origin: OriginFor, - token_id: CurrencyIdOf, - amount: BalanceOf, + currency_id: CurrencyIdOf, + minimum_amount: BalanceOf, ) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; - MinimumRedeem::::mutate(token_id, |old_amount| { - *old_amount = amount; + MinimumRedeem::::mutate(currency_id, |old_amount| { + *old_amount = minimum_amount; }); - Self::deposit_event(Event::MinimumRedeemSet { token_id, amount }); + Self::deposit_event(Event::MinimumRedeemSet { currency_id, minimum_amount }); Ok(()) } + /// Support a token to rebond. + /// Parameters: + /// - `currency_id`: The currency to support rebond. #[pallet::call_index(7)] #[pallet::weight(T::WeightInfo::add_support_rebond_token())] pub fn add_support_rebond_token( origin: OriginFor, - token_id: CurrencyIdOf, + currency_id: CurrencyIdOf, ) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; - if !TokenToRebond::::contains_key(token_id) { - TokenToRebond::::insert(token_id, BalanceOf::::zero()); - Self::deposit_event(Event::SupportRebondTokenAdded { token_id }); - } - - Ok(()) + TokenToRebond::::mutate(currency_id, |maybe_value| -> DispatchResult { + match maybe_value { + Some(_) => Err(Error::::InvalidRebondToken.into()), + None => { + *maybe_value = Some(BalanceOf::::zero()); + Self::deposit_event(Event::SupportRebondTokenAdded { currency_id }); + Ok(()) + }, + } + }) } + /// Remove the support of a token to rebond. + /// Parameters: + /// - `currency_id`: The currency to remove support rebond. #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::remove_support_rebond_token())] pub fn remove_support_rebond_token( origin: OriginFor, - token_id: CurrencyIdOf, + currency_id: CurrencyIdOf, ) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; - if TokenToRebond::::contains_key(token_id) { - let token_amount_to_rebond = - TokenToRebond::::get(token_id).ok_or(Error::::InvalidRebondToken)?; - ensure!( - token_amount_to_rebond == BalanceOf::::zero(), - Error::::TokenToRebondNotZero - ); - - TokenToRebond::::remove(token_id); - Self::deposit_event(Event::SupportRebondTokenRemoved { token_id }); - } - Ok(()) + TokenToRebond::::mutate(currency_id, |maybe_value| -> DispatchResult { + match maybe_value { + Some(_) => { + *maybe_value = None; + Self::deposit_event(Event::SupportRebondTokenRemoved { currency_id }); + Ok(()) + }, + None => Err(Error::::InvalidRebondToken.into()), + } + }) } + /// Set the fees for mint and redeem. + /// Parameters: + /// - `mint_fee`: The fee for mint. + /// - `redeem_fee`: The fee for redeem. #[pallet::call_index(9)] #[pallet::weight(T::WeightInfo::set_fees())] pub fn set_fees( @@ -825,6 +800,9 @@ pub mod pallet { Ok(()) } + /// Set the hook iteration limit. + /// Parameters: + /// - `limit`: The hook iteration limit. #[pallet::call_index(10)] #[pallet::weight(T::WeightInfo::set_hook_iteration_limit())] pub fn set_hook_iteration_limit(origin: OriginFor, limit: u32) -> DispatchResult { @@ -838,50 +816,63 @@ pub mod pallet { Ok(()) } + /// Set the total amount of tokens that are currently locked for unlocking. + /// Parameters: + /// - `currency_id`: The currency to set unlocking total. + /// - `currency_amount`: The total amount of tokens that are currently locked for unlocking. #[pallet::call_index(11)] #[pallet::weight(T::WeightInfo::set_unlocking_total())] pub fn set_unlocking_total( origin: OriginFor, - token_id: CurrencyIdOf, - amount: BalanceOf, + currency_id: CurrencyIdOf, + currency_amount: BalanceOf, ) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; - UnlockingTotal::::mutate(&token_id, |unlocking_total| *unlocking_total = amount); - - Self::deposit_event(Event::UnlockingTotalSet { token_id, amount }); + Self::update_unlocking_total(¤cy_id, ¤cy_amount, Operation::Set)?; + Self::deposit_event(Event::UnlockingTotalSet { currency_id, currency_amount }); Ok(()) } + /// Set the minimum time unit for a currency. + /// Parameters: + /// - `currency_id`: The currency to set minimum time unit. + /// - `time_unit`: The minimum time unit to set. #[pallet::call_index(12)] #[pallet::weight(T::WeightInfo::set_min_time_unit())] pub fn set_min_time_unit( origin: OriginFor, - token_id: CurrencyIdOf, + currency_id: CurrencyIdOf, time_unit: TimeUnit, ) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; - MinTimeUnit::::mutate(&token_id, |old_time_unit| *old_time_unit = time_unit.clone()); + MinTimeUnit::::mutate(¤cy_id, |old_time_unit| { + *old_time_unit = time_unit.clone() + }); - Self::deposit_event(Event::MinTimeUnitSet { token_id, time_unit }); + Self::deposit_event(Event::MinTimeUnitSet { currency_id, time_unit }); Ok(()) } + /// Set the ongoing time unit for a currency. + /// Parameters: + /// - `currency_id`: The currency to set ongoing time unit. + /// - `time_unit`: The ongoing time unit to set. #[pallet::call_index(13)] - #[pallet::weight(T::WeightInfo::recreate_currency_ongoing_time_unit())] - pub fn recreate_currency_ongoing_time_unit( + #[pallet::weight(T::WeightInfo::set_ongoing_time_unit())] + pub fn set_ongoing_time_unit( origin: OriginFor, - token_id: CurrencyIdOf, + currency_id: CurrencyIdOf, time_unit: TimeUnit, ) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; - OngoingTimeUnit::::mutate(&token_id, |old_time_unit| { + OngoingTimeUnit::::mutate(¤cy_id, |old_time_unit| { *old_time_unit = Some(time_unit.clone()) }); - Self::deposit_event(Event::CurrencyTimeUnitRecreated { token_id, time_unit }); + Self::deposit_event(Event::SetOngoingTimeUnit { currency_id, time_unit }); Ok(()) } @@ -890,20 +881,20 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::mint_with_lock())] pub fn mint_with_lock( origin: OriginFor, - token_id: CurrencyIdOf, - token_amount: BalanceOf, + currency_id: CurrencyIdOf, + currency_amount: BalanceOf, remark: BoundedVec>, channel_id: Option, ) -> DispatchResult { // Check origin let minter = ensure_signed(origin)?; - // check if the minter has at least token_amount of token_id which is transferable - T::MultiCurrency::ensure_can_withdraw(token_id, &minter, token_amount) + // check if the minter has at least currency_amount of currency_id which is transferable + T::MultiCurrency::ensure_can_withdraw(currency_id, &minter, currency_amount) .map_err(|_| Error::::NotEnoughBalance)?; - // check whether the token_id is supported - ensure!(MinimumMint::::contains_key(token_id), Error::::NotSupportTokenType); + // check whether the currency_id is supported + ensure!(MinimumMint::::contains_key(currency_id), Error::::NotSupportTokenType); // check whether the user has veBNC let vebnc_balance = @@ -911,36 +902,36 @@ pub mod pallet { ensure!(vebnc_balance > BalanceOf::::zero(), Error::::NotEnoughBalance); // check whether the vtoken coefficient is set - let vtoken_id = T::CurrencyIdConversion::convert_to_vtoken(token_id) - .map_err(|_| Error::::NotSupportTokenType)?; + let v_currency_id = + currency_id.to_vtoken().map_err(|_| Error::::NotSupportTokenType)?; ensure!( - VtokenIncentiveCoef::::contains_key(vtoken_id), + VtokenIncentiveCoef::::contains_key(v_currency_id), Error::::IncentiveCoefNotFound ); - // check whether the pool has balance of vtoken_id + // check whether the pool has balance of v_currency_id let incentive_pool_account = &Self::incentive_pool_account(); let vtoken_pool_balance = - T::MultiCurrency::free_balance(vtoken_id, &incentive_pool_account); + T::MultiCurrency::free_balance(v_currency_id, &incentive_pool_account); ensure!(vtoken_pool_balance > BalanceOf::::zero(), Error::::NotEnoughBalance); // mint vtoken let vtoken_minted = - Self::mint_inner(minter.clone(), token_id, token_amount, remark, channel_id)?; + Self::do_mint(minter.clone(), currency_id, currency_amount, remark, channel_id)?; // lock vtoken and record the lock - Self::lock_vtoken_for_incentive_minting(minter.clone(), vtoken_id, vtoken_minted)?; + Self::lock_vtoken_for_incentive_minting(minter.clone(), v_currency_id, vtoken_minted)?; // calculate the incentive amount let incentive_amount = - Self::calculate_incentive_vtoken_amount(&minter, vtoken_id, vtoken_minted)?; + Self::calculate_incentive_vtoken_amount(&minter, v_currency_id, vtoken_minted)?; // Since the user has already locked the vtoken, we can directly transfer the incentive // vtoken. It won't fail. transfer the incentive amount to the minter T::MultiCurrency::transfer( - vtoken_id, + v_currency_id, incentive_pool_account, &minter, incentive_amount, @@ -950,8 +941,8 @@ pub mod pallet { // deposit event Self::deposit_event(Event::IncentivizedMinting { address: minter, - token_id, - token_amount, + currency_id, + currency_amount, locked_vtoken_amount: vtoken_minted, incentive_vtoken_amount: incentive_amount, }); @@ -959,23 +950,26 @@ pub mod pallet { Ok(()) } + /// Unlock the vtoken minted in an incentive mode + /// Parameters: + /// - `v_currency_id`: The v_currency to unlock. #[pallet::call_index(15)] #[pallet::weight(T::WeightInfo::unlock_incentive_minted_vtoken())] pub fn unlock_incentive_minted_vtoken( origin: OriginFor, - vtoken_id: CurrencyIdOf, + v_currency_id: CurrencyIdOf, ) -> DispatchResult { let unlocker = ensure_signed(origin)?; // get the user's VtokenLockLedger ensure!( - VtokenLockLedger::::contains_key(&unlocker, vtoken_id), + VtokenLockLedger::::contains_key(&unlocker, v_currency_id), Error::::UserUnlockLedgerNotFound ); VtokenLockLedger::::mutate_exists( &unlocker, - vtoken_id, + v_currency_id, |maybe_ledger| -> Result<(), Error> { let current_block = frame_system::Pallet::::block_number(); @@ -1012,8 +1006,12 @@ pub mod pallet { .ok_or(Error::::CalculationOverflow)?; if remaining_locked_amount == BalanceOf::::zero() { - T::MultiCurrency::remove_lock(INCENTIVE_LOCK_ID, vtoken_id, &unlocker) - .map_err(|_| Error::::FailToRemoveLock)?; + T::MultiCurrency::remove_lock( + INCENTIVE_LOCK_ID, + v_currency_id, + &unlocker, + ) + .map_err(|_| Error::::FailToRemoveLock)?; // remove the ledger *maybe_ledger = None; @@ -1024,7 +1022,7 @@ pub mod pallet { // reset the locked amount to be remaining_locked_amount T::MultiCurrency::set_lock( INCENTIVE_LOCK_ID, - vtoken_id, + v_currency_id, &unlocker, remaining_locked_amount, ) @@ -1041,1151 +1039,58 @@ pub mod pallet { Ok(()) } + /// Set the incentive coefficient for a vtoken when minted in an incentive mode + /// Parameters: + /// - `v_currency_id`: The v_currency to set incentive coefficient. + /// - `new_coef_op`: The new incentive coefficient to set. #[pallet::call_index(16)] #[pallet::weight(T::WeightInfo::set_incentive_coef())] pub fn set_incentive_coef( origin: OriginFor, - vtoken_id: CurrencyIdOf, + v_currency_id: CurrencyIdOf, new_coef_op: Option, ) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; if let Some(new_coef) = new_coef_op { - VtokenIncentiveCoef::::insert(vtoken_id, new_coef); + VtokenIncentiveCoef::::insert(v_currency_id, new_coef); } else { - VtokenIncentiveCoef::::remove(vtoken_id); + VtokenIncentiveCoef::::remove(v_currency_id); } Self::deposit_event(Event::VtokenIncentiveCoefSet { - vtoken_id, + v_currency_id, coefficient: new_coef_op, }); Ok(()) } + /// Set the locked blocks for a vtoken when minted in an incentive mode + /// Parameters: + /// - `v_currency_id`: The v_currency to set locked blocks. + /// - `new_blockes_op`: The new locked blocks to set. #[pallet::call_index(17)] #[pallet::weight(T::WeightInfo::set_vtoken_incentive_lock_blocks())] pub fn set_vtoken_incentive_lock_blocks( origin: OriginFor, - vtoken_id: CurrencyIdOf, + v_currency_id: CurrencyIdOf, new_blockes_op: Option>, ) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; if let Some(new_blocks) = new_blockes_op { - MintWithLockBlocks::::insert(vtoken_id, new_blocks); + MintWithLockBlocks::::insert(v_currency_id, new_blocks); } else { - MintWithLockBlocks::::remove(vtoken_id); + MintWithLockBlocks::::remove(v_currency_id); } Self::deposit_event(Event::VtokenIncentiveLockBlocksSet { - vtoken_id, + v_currency_id, blocks: new_blockes_op, }); Ok(()) } } - - impl Pallet { - #[transactional] - pub fn add_time_unit(a: TimeUnit, b: TimeUnit) -> Result { - let result = match a { - TimeUnit::Era(era_a) => match b { - TimeUnit::Era(era_b) => TimeUnit::Era( - era_a.checked_add(era_b).ok_or(Error::::CalculationOverflow)?, - ), - _ => return Err(Error::::Unexpected.into()), - }, - TimeUnit::Round(round_a) => match b { - TimeUnit::Round(round_b) => TimeUnit::Round( - round_a.checked_add(round_b).ok_or(Error::::CalculationOverflow)?, - ), - _ => return Err(Error::::Unexpected.into()), - }, - TimeUnit::SlashingSpan(slashing_span_a) => match b { - TimeUnit::SlashingSpan(slashing_span_b) => TimeUnit::SlashingSpan( - slashing_span_a - .checked_add(slashing_span_b) - .ok_or(Error::::CalculationOverflow)?, - ), - _ => return Err(Error::::Unexpected.into()), - }, - TimeUnit::Kblock(kblock_a) => match b { - TimeUnit::Kblock(kblock_b) => TimeUnit::Kblock( - kblock_a.checked_add(kblock_b).ok_or(Error::::CalculationOverflow)?, - ), - _ => return Err(Error::::Unexpected.into()), - }, - TimeUnit::Hour(hour_a) => match b { - TimeUnit::Hour(hour_b) => TimeUnit::Hour( - hour_a.checked_add(hour_b).ok_or(Error::::CalculationOverflow)?, - ), - _ => return Err(Error::::Unexpected.into()), - }, - // _ => return Err(Error::::Unexpected.into()), - }; - - Ok(result) - } - - #[transactional] - pub fn mint_without_tranfer( - exchanger: &AccountIdOf, - vtoken_id: CurrencyId, - token_id: CurrencyId, - token_amount: BalanceOf, - ) -> Result<(BalanceOf, BalanceOf, BalanceOf), DispatchError> { - let token_pool_amount = TokenPool::::get(token_id); - let vtoken_total_issuance = T::MultiCurrency::total_issuance(vtoken_id); - let (mint_rate, _redeem_rate) = Fees::::get(); - let mint_fee = mint_rate * token_amount; - let token_amount_excluding_fee = - token_amount.checked_sub(&mint_fee).ok_or(Error::::CalculationOverflow)?; - let mut vtoken_amount = token_amount_excluding_fee; - if token_pool_amount != BalanceOf::::zero() { - vtoken_amount = U256::from(token_amount_excluding_fee.saturated_into::()) - .saturating_mul(vtoken_total_issuance.saturated_into::().into()) - .checked_div(token_pool_amount.saturated_into::().into()) - .map(|x| u128::try_from(x)) - .ok_or(Error::::CalculationOverflow)? - .map_err(|_| Error::::CalculationOverflow)? - .unique_saturated_into(); - } - - // Charging fees - T::MultiCurrency::transfer(token_id, exchanger, &T::FeeAccount::get(), mint_fee)?; - // Issue the corresponding vtoken to the user's account. - T::MultiCurrency::deposit(vtoken_id, exchanger, vtoken_amount)?; - TokenPool::::mutate(&token_id, |pool| -> Result<(), Error> { - *pool = pool - .checked_add(&token_amount_excluding_fee) - .ok_or(Error::::CalculationOverflow)?; - Ok(()) - })?; - Ok((token_amount_excluding_fee, vtoken_amount, mint_fee)) - } - - #[transactional] - fn on_initialize_update_ledger( - token_id: CurrencyId, - account: AccountIdOf, - index: &UnlockId, - mut unlock_amount: BalanceOf, - entrance_account_balance: BalanceOf, - time_unit: TimeUnit, - redeem_type: RedeemType>, - ) -> DispatchResult { - let ed = T::MultiCurrency::minimum_balance(token_id); - let mut account_to_send = account.clone(); - let mut redeem_to = RedeemTo::Native(account_to_send.clone()); - - if unlock_amount < ed { - let receiver_balance = T::MultiCurrency::total_balance(token_id, &account); - - let receiver_balance_after = receiver_balance - .checked_add(&unlock_amount) - .ok_or(ArithmeticError::Overflow)?; - if receiver_balance_after < ed { - account_to_send = T::FeeAccount::get(); - redeem_to = RedeemTo::Native(T::FeeAccount::get()); - } - } - if entrance_account_balance >= unlock_amount { - T::MultiCurrency::transfer( - token_id, - &T::EntranceAccount::get().into_account_truncating(), - &account_to_send, - unlock_amount, - )?; - TokenUnlockLedger::::remove(&token_id, &index); - - TimeUnitUnlockLedger::::mutate_exists( - &time_unit, - &token_id, - |value| -> Result<(), Error> { - if let Some((total_locked_origin, ledger_list_origin, _)) = value { - if total_locked_origin == &unlock_amount { - *value = None; - return Ok(()); - } - *total_locked_origin = total_locked_origin - .checked_sub(&unlock_amount) - .ok_or(Error::::CalculationOverflow)?; - ledger_list_origin.retain(|x| x != index); - } else { - return Err(Error::::TimeUnitUnlockLedgerNotFound); - } - Ok(()) - }, - )?; - - UserUnlockLedger::::mutate_exists( - &account, - &token_id, - |value| -> Result<(), Error> { - if let Some((total_locked_origin, ledger_list_origin)) = value { - if total_locked_origin == &unlock_amount { - *value = None; - return Ok(()); - } - ledger_list_origin.retain(|x| x != index); - *total_locked_origin = total_locked_origin - .checked_sub(&unlock_amount) - .ok_or(Error::::CalculationOverflow)?; - } else { - return Err(Error::::UserUnlockLedgerNotFound); - } - Ok(()) - }, - )?; - match redeem_type { - RedeemType::Native => {}, - RedeemType::Astar(receiver) => { - let dest = Location::new( - 1, - [ - Parachain(AstarChainId::get()), - AccountId32 { - network: None, - id: receiver.encode().try_into().unwrap(), - }, - ], - ); - T::XcmTransfer::transfer( - account.clone(), - token_id, - unlock_amount, - dest, - Unlimited, - )?; - redeem_to = RedeemTo::Astar(receiver); - }, - RedeemType::Hydradx(receiver) => { - let dest = Location::new( - 1, - [ - Parachain(HydrationChainId::get()), - AccountId32 { - network: None, - id: receiver.encode().try_into().unwrap(), - }, - ], - ); - T::XcmTransfer::transfer( - account.clone(), - token_id, - unlock_amount, - dest, - Unlimited, - )?; - redeem_to = RedeemTo::Hydradx(receiver); - }, - RedeemType::Interlay(receiver) => { - let dest = Location::new( - 1, - [ - Parachain(InterlayChainId::get()), - AccountId32 { - network: None, - id: receiver.encode().try_into().unwrap(), - }, - ], - ); - T::XcmTransfer::transfer( - account.clone(), - token_id, - unlock_amount, - dest, - Unlimited, - )?; - redeem_to = RedeemTo::Interlay(receiver); - }, - RedeemType::Manta(receiver) => { - let dest = Location::new( - 1, - [ - Parachain(MantaChainId::get()), - AccountId32 { - network: None, - id: receiver.encode().try_into().unwrap(), - }, - ], - ); - T::XcmTransfer::transfer( - account.clone(), - token_id, - unlock_amount, - dest, - Unlimited, - )?; - redeem_to = RedeemTo::Manta(receiver); - }, - RedeemType::Moonbeam(receiver) => { - let dest = Location::new( - 1, - [ - Parachain(T::MoonbeamChainId::get()), - AccountKey20 { network: None, key: receiver.to_fixed_bytes() }, - ], - ); - if token_id == FIL { - let assets = vec![ - (token_id, unlock_amount), - (BNC, T::BifrostSlpx::get_moonbeam_transfer_to_fee()), - ]; - - T::XcmTransfer::transfer_multicurrencies( - account.clone(), - assets, - 1, - dest, - Unlimited, - )?; - } else { - T::XcmTransfer::transfer( - account.clone(), - token_id, - unlock_amount, - dest, - Unlimited, - )?; - } - redeem_to = RedeemTo::Moonbeam(receiver); - }, - }; - } else { - match redeem_type { - RedeemType::Astar(_) | - RedeemType::Moonbeam(_) | - RedeemType::Hydradx(_) | - RedeemType::Manta(_) | - RedeemType::Interlay(_) => { - return Ok(()); - }, - RedeemType::Native => {}, - }; - unlock_amount = entrance_account_balance; - T::MultiCurrency::transfer( - token_id, - &T::EntranceAccount::get().into_account_truncating(), - &account_to_send, - unlock_amount, - )?; - TokenUnlockLedger::::mutate_exists( - &token_id, - &index, - |value| -> Result<(), Error> { - if let Some((_, total_locked_origin, _, _)) = value { - if total_locked_origin == &unlock_amount { - *value = None; - return Ok(()); - } - *total_locked_origin = total_locked_origin - .checked_sub(&unlock_amount) - .ok_or(Error::::CalculationOverflow)?; - } else { - return Err(Error::::TokenUnlockLedgerNotFound); - } - Ok(()) - }, - )?; - - TimeUnitUnlockLedger::::mutate_exists( - &time_unit, - &token_id, - |value| -> Result<(), Error> { - if let Some((total_locked_origin, _ledger_list_origin, _)) = value { - if total_locked_origin == &unlock_amount { - *value = None; - return Ok(()); - } - *total_locked_origin = total_locked_origin - .checked_sub(&unlock_amount) - .ok_or(Error::::CalculationOverflow)?; - } else { - return Err(Error::::TimeUnitUnlockLedgerNotFound); - } - Ok(()) - }, - )?; - - UserUnlockLedger::::mutate_exists( - &account, - &token_id, - |value| -> Result<(), Error> { - if let Some((total_locked_origin, _ledger_list_origin)) = value { - if total_locked_origin == &unlock_amount { - *value = None; - return Ok(()); - } - - *total_locked_origin = total_locked_origin - .checked_sub(&unlock_amount) - .ok_or(Error::::CalculationOverflow)?; - } else { - return Err(Error::::UserUnlockLedgerNotFound); - } - Ok(()) - }, - )?; - } - - entrance_account_balance - .checked_sub(&unlock_amount) - .ok_or(Error::::CalculationOverflow)?; - - UnlockingTotal::::mutate(&token_id, |pool| -> Result<(), Error> { - *pool = pool.checked_sub(&unlock_amount).ok_or(Error::::CalculationOverflow)?; - Ok(()) - })?; - - T::OnRedeemSuccess::on_redeem_success(token_id, account.clone(), unlock_amount); - - Self::deposit_event(Event::RedeemSuccess { - unlock_id: *index, - token_id, - to: redeem_to, - token_amount: unlock_amount, - }); - Ok(()) - } - - #[transactional] - fn handle_on_initialize() -> DispatchResult { - for currency in OngoingTimeUnit::::iter_keys() { - Self::handle_ledger_by_currency(currency)?; - } - Ok(()) - } - - fn handle_ledger_by_currency(currency: CurrencyId) -> DispatchResult { - let time_unit = MinTimeUnit::::get(currency); - let unlock_duration_elem = match UnlockDuration::::get(currency) { - Some(TimeUnit::Era(unlock_duration_era)) => unlock_duration_era, - Some(TimeUnit::Round(unlock_duration_round)) => unlock_duration_round, - Some(TimeUnit::Kblock(unlock_duration_kblock)) => unlock_duration_kblock, - Some(TimeUnit::Hour(unlock_duration_hour)) => unlock_duration_hour, - _ => 0, - }; - let ongoing_elem = match OngoingTimeUnit::::get(currency) { - Some(TimeUnit::Era(ongoing_era)) => ongoing_era, - Some(TimeUnit::Round(ongoing_round)) => ongoing_round, - Some(TimeUnit::Kblock(ongoing_kblock)) => ongoing_kblock, - Some(TimeUnit::Hour(ongoing_hour)) => ongoing_hour, - _ => 0, - }; - if let Some((_total_locked, ledger_list, token_id)) = - TimeUnitUnlockLedger::::get(time_unit.clone(), currency) - { - for index in ledger_list.iter().take(HookIterationLimit::::get() as usize) { - if let Some((account, unlock_amount, time_unit, redeem_type)) = - TokenUnlockLedger::::get(token_id, index) - { - let entrance_account_balance = T::MultiCurrency::free_balance( - token_id, - &T::EntranceAccount::get().into_account_truncating(), - ); - if entrance_account_balance != BalanceOf::::zero() { - Self::on_initialize_update_ledger( - token_id, - account, - index, - unlock_amount, - entrance_account_balance, - time_unit, - redeem_type, - ) - .ok(); - } - } - } - } else { - MinTimeUnit::::mutate(currency, |time_unit| -> Result<(), Error> { - match time_unit { - TimeUnit::Era(era) => { - if ongoing_elem + unlock_duration_elem > *era { - *era = era.checked_add(1).ok_or(Error::::CalculationOverflow)?; - } - Ok(()) - }, - TimeUnit::Round(round) => { - if ongoing_elem + unlock_duration_elem > *round { - *round = - round.checked_add(1).ok_or(Error::::CalculationOverflow)?; - } - Ok(()) - }, - TimeUnit::Kblock(kblock) => { - if ongoing_elem + unlock_duration_elem > *kblock { - *kblock = - kblock.checked_add(1).ok_or(Error::::CalculationOverflow)?; - } - Ok(()) - }, - TimeUnit::Hour(hour) => { - if ongoing_elem + unlock_duration_elem > *hour { - *hour = - hour.checked_add(1).ok_or(Error::::CalculationOverflow)?; - } - Ok(()) - }, - _ => Ok(()), - } - })?; - }; - - Ok(()) - } - - #[transactional] - pub fn mint_inner( - exchanger: AccountIdOf, - token_id: CurrencyIdOf, - token_amount: BalanceOf, - remark: BoundedVec>, - channel_id: Option, - ) -> Result, DispatchError> { - ensure!(token_amount >= MinimumMint::::get(token_id), Error::::BelowMinimumMint); - - let vtoken_id = T::CurrencyIdConversion::convert_to_vtoken(token_id) - .map_err(|_| Error::::NotSupportTokenType)?; - let (token_amount_excluding_fee, vtoken_amount, fee) = - Self::mint_without_tranfer(&exchanger, vtoken_id, token_id, token_amount)?; - // Transfer the user's token to EntranceAccount. - T::MultiCurrency::transfer( - token_id, - &exchanger, - &T::EntranceAccount::get().into_account_truncating(), - token_amount_excluding_fee, - )?; - - // record the minting information for ChannelCommission module - T::ChannelCommission::record_mint_amount(channel_id, vtoken_id, vtoken_amount)?; - - Self::deposit_event(Event::Minted { - address: exchanger, - token_id, - token_amount, - vtoken_amount, - fee, - remark, - channel_id, - }); - Ok(vtoken_amount.into()) - } - - #[transactional] - pub fn redeem_inner( - exchanger: AccountIdOf, - vtoken_id: CurrencyIdOf, - vtoken_amount: BalanceOf, - redeem_type: RedeemType>, - ) -> DispatchResultWithPostInfo { - let token_id = T::CurrencyIdConversion::convert_to_token(vtoken_id) - .map_err(|_| Error::::NotSupportTokenType)?; - ensure!( - vtoken_amount >= MinimumRedeem::::get(vtoken_id), - Error::::BelowMinimumRedeem - ); - - ensure!( - !T::BifrostSlp::all_delegation_requests_occupied(token_id), - Error::::CanNotRedeem, - ); - - let (_mint_rate, redeem_rate) = Fees::::get(); - let redeem_fee = redeem_rate * vtoken_amount; - let vtoken_amount = - vtoken_amount.checked_sub(&redeem_fee).ok_or(Error::::CalculationOverflow)?; - // Charging fees - T::MultiCurrency::transfer( - vtoken_id, - &exchanger, - &T::RedeemFeeAccount::get(), - redeem_fee, - )?; - - let token_pool_amount = TokenPool::::get(token_id); - let vtoken_total_issuance = T::MultiCurrency::total_issuance(vtoken_id); - let token_amount: BalanceOf = U256::from(vtoken_amount.saturated_into::()) - .saturating_mul(token_pool_amount.saturated_into::().into()) - .checked_div(vtoken_total_issuance.saturated_into::().into()) - .map(|x| u128::try_from(x)) - .ok_or(Error::::CalculationOverflow)? - .map_err(|_| Error::::CalculationOverflow)? - .unique_saturated_into(); - - let next_id = TokenUnlockNextId::::get(token_id); - match OngoingTimeUnit::::get(token_id) { - Some(time_unit) => { - // Calculate the time to be locked - let result_time_unit = Self::add_time_unit( - UnlockDuration::::get(token_id) - .ok_or(Error::::UnlockDurationNotFound)?, - time_unit, - )?; - - T::MultiCurrency::withdraw(vtoken_id, &exchanger, vtoken_amount)?; - TokenPool::::mutate(&token_id, |pool| -> Result<(), Error> { - *pool = pool - .checked_sub(&token_amount) - .ok_or(Error::::CalculationOverflow)?; - Ok(()) - })?; - UnlockingTotal::::mutate(&token_id, |pool| -> Result<(), Error> { - *pool = pool - .checked_add(&token_amount) - .ok_or(Error::::CalculationOverflow)?; - Ok(()) - })?; - TokenUnlockLedger::::insert( - &token_id, - &next_id, - (&exchanger, token_amount, &result_time_unit, redeem_type), - ); - - if UserUnlockLedger::::get(&exchanger, &token_id).is_some() { - UserUnlockLedger::::mutate( - &exchanger, - &token_id, - |value| -> Result<(), Error> { - if let Some((total_locked, ledger_list)) = value { - ledger_list - .try_push(next_id) - .map_err(|_| Error::::TooManyRedeems)?; - - *total_locked = total_locked - .checked_add(&token_amount) - .ok_or(Error::::CalculationOverflow)?; - }; - Ok(()) - }, - )?; - } else { - let mut ledger_list_origin = - BoundedVec::::default(); - ledger_list_origin - .try_push(next_id) - .map_err(|_| Error::::TooManyRedeems)?; - UserUnlockLedger::::insert( - &exchanger, - &token_id, - (token_amount, ledger_list_origin), - ); - } - - if let Some((_, _, _token_id)) = - TimeUnitUnlockLedger::::get(&result_time_unit, &token_id) - { - TimeUnitUnlockLedger::::mutate( - &result_time_unit, - &token_id, - |value| -> Result<(), Error> { - if let Some((total_locked, ledger_list, _token_id)) = value { - ledger_list - .try_push(next_id) - .map_err(|_| Error::::TooManyRedeems)?; - *total_locked = total_locked - .checked_add(&token_amount) - .ok_or(Error::::CalculationOverflow)?; - }; - Ok(()) - }, - )?; - } else { - let mut ledger_list_origin = - BoundedVec::::default(); - ledger_list_origin - .try_push(next_id) - .map_err(|_| Error::::TooManyRedeems)?; - - TimeUnitUnlockLedger::::insert( - &result_time_unit, - &token_id, - (token_amount, ledger_list_origin, token_id), - ); - } - }, - None => return Err(Error::::OngoingTimeUnitNotSet.into()), - } - - TokenUnlockNextId::::mutate(&token_id, |unlock_id| -> Result<(), Error> { - *unlock_id = unlock_id.checked_add(1).ok_or(Error::::CalculationOverflow)?; - Ok(()) - })?; - - let extra_weight = T::OnRedeemSuccess::on_redeemed( - exchanger.clone(), - token_id, - token_amount, - vtoken_amount, - redeem_fee, - ); - - T::ChannelCommission::record_redeem_amount(vtoken_id, vtoken_amount)?; - - Self::deposit_event(Event::Redeemed { - address: exchanger, - token_id, - vtoken_amount, - token_amount, - fee: redeem_fee, - unlock_id: next_id, - }); - Ok(Some(T::WeightInfo::redeem() + extra_weight).into()) - } - - pub fn token_to_vtoken_inner( - token_id: CurrencyIdOf, - vtoken_id: CurrencyIdOf, - token_amount: BalanceOf, - ) -> Result, DispatchError> { - let token_pool_amount = TokenPool::::get(token_id); - let vtoken_total_issuance = T::MultiCurrency::total_issuance(vtoken_id); - - let value = U256::from(token_amount.saturated_into::()) - .saturating_mul(vtoken_total_issuance.saturated_into::().into()) - .checked_div(token_pool_amount.saturated_into::().into()) - .ok_or(Error::::CalculationOverflow)?; - - Ok(u128::try_from(value) - .map(|x| x.unique_saturated_into()) - .map_err(|_| Error::::CalculationOverflow)?) - } - - pub fn vtoken_to_token_inner( - token_id: CurrencyIdOf, - vtoken_id: CurrencyIdOf, - vtoken_amount: BalanceOf, - ) -> Result, DispatchError> { - let token_pool_amount = TokenPool::::get(token_id); - let vtoken_total_issuance = T::MultiCurrency::total_issuance(vtoken_id); - - let value = U256::from(vtoken_amount.saturated_into::()) - .saturating_mul(token_pool_amount.saturated_into::().into()) - .checked_div(vtoken_total_issuance.saturated_into::().into()) - .ok_or(Error::::CalculationOverflow)?; - - Ok(u128::try_from(value) - .map(|x| x.unique_saturated_into()) - .map_err(|_| Error::::CalculationOverflow)?) - } - - pub fn vtoken_id_inner(token_id: CurrencyIdOf) -> Option> { - T::CurrencyIdConversion::convert_to_vtoken(token_id).ok() - } - - pub fn token_id_inner(vtoken_id: CurrencyIdOf) -> Option> { - T::CurrencyIdConversion::convert_to_token(vtoken_id).ok() - } - - pub fn incentive_pool_account() -> AccountIdOf { - T::IncentivePoolAccount::get().into_account_truncating() - } - - // to lock user vtoken for incentive minting - fn lock_vtoken_for_incentive_minting( - minter: AccountIdOf, - vtoken_id: CurrencyIdOf, - vtoken_amount: BalanceOf, - ) -> Result<(), Error> { - // first, lock the vtoken - // second, record the lock in ledger - - // check whether the minter has enough vtoken - T::MultiCurrency::ensure_can_withdraw(vtoken_id, &minter, vtoken_amount) - .map_err(|_| Error::::NotEnoughBalance)?; - - // new amount that should be locked - let mut new_lock_total = vtoken_amount; - - // check the previous locked amount under the same vtoken_id from ledger - // and revise ledger to set the new_amount to be previous_amount + vtoken_amount - VtokenLockLedger::::mutate_exists( - &minter, - &vtoken_id, - |value| -> Result<(), Error> { - // get the vtoken lock duration from VtokenIncentiveCoef - let lock_duration = MintWithLockBlocks::::get(vtoken_id) - .ok_or(Error::::IncentiveLockBlocksNotSet)?; - let current_block = frame_system::Pallet::::block_number(); - let due_block = current_block - .checked_add(&lock_duration) - .ok_or(Error::::CalculationOverflow)?; - - if let Some(ref mut ledger) = value { - new_lock_total = ledger - .0 - .checked_add(&vtoken_amount) - .ok_or(Error::::CalculationOverflow)?; - - ledger.0 = new_lock_total; - - // push new item to the boundedvec of the ledger - ledger - .1 - .try_push((vtoken_amount, due_block)) - .map_err(|_| Error::::TooManyLocks)?; - } else { - let item = BoundedVec::try_from(vec![(vtoken_amount, due_block)]) - .map_err(|_| Error::::ConvertError)?; - - *value = Some((vtoken_amount, item)); - } - Ok(()) - }, - )?; - - // extend the locked amount to be new_lock_total - T::MultiCurrency::set_lock(INCENTIVE_LOCK_ID, vtoken_id, &minter, new_lock_total) - .map_err(|_| Error::::NotEnoughBalance)?; - - Ok(()) - } - - fn calculate_incentive_vtoken_amount( - minter: &AccountIdOf, - vtoken_id: CurrencyIdOf, - vtoken_amount: BalanceOf, - ) -> Result, Error> { - // get the vtoken pool balance - let vtoken_pool_balance = - T::MultiCurrency::free_balance(vtoken_id, &Self::incentive_pool_account()); - ensure!(vtoken_pool_balance > BalanceOf::::zero(), Error::::NotEnoughBalance); - - // get current block number - let current_block_number: BlockNumberFor = frame_system::Pallet::::block_number(); - // get the veBNC total amount - let vebnc_total_issuance = T::BbBNC::total_supply(current_block_number) - .map_err(|_| Error::::VeBNCCheckingError)?; - ensure!(vebnc_total_issuance > BalanceOf::::zero(), Error::::BalanceZero); - - // get the veBNC balance of the minter - let minter_vebnc_balance = - T::BbBNC::balance_of(minter, None).map_err(|_| Error::::VeBNCCheckingError)?; - ensure!(minter_vebnc_balance > BalanceOf::::zero(), Error::::NotEnoughBalance); - - // get the percentage of the veBNC balance of the minter to the total veBNC amount and - // get the square root of the percentage - let percentage = Permill::from_rational(minter_vebnc_balance, vebnc_total_issuance); - let sqrt_percentage = - FixedU128::from_inner(percentage * 1_000_000_000_000_000_000u128).sqrt(); - let percentage = Permill::from_rational( - sqrt_percentage.into_inner(), - 1_000_000_000_000_000_000u128.into(), - ); - // get the total issuance of the vtoken - let vtoken_total_issuance = T::MultiCurrency::total_issuance(vtoken_id); - - // get the incentive coef for the vtoken - let incentive_coef = VtokenIncentiveCoef::::get(vtoken_id) - .ok_or(Error::::IncentiveCoefNotFound)?; - - // calculate the incentive amount, but mind the overflow - // incentive_amount = vtoken_pool_balance * incentive_coef * vtoken_amount * - // sqrt_percentage / vtoken_total_issuance - let incentive_amount = - U256::from(percentage.mul_ceil(vtoken_pool_balance).saturated_into::()) - .checked_mul(U256::from(incentive_coef)) - .and_then(|x| x.checked_mul(U256::from(vtoken_amount.saturated_into::()))) - // .and_then(|x| x.checked_mul(percentage)) - .and_then(|x| { - x.checked_div(U256::from(vtoken_total_issuance.saturated_into::())) - }) - // first turn into u128,then use unique_saturated_into BalanceOf - .map(|x| x.saturated_into::()) - .map(|x| x.unique_saturated_into()) - .ok_or(Error::::CalculationOverflow)?; - - Ok(incentive_amount) - } - - pub fn get_exchange_rate( - token_id: Option, - ) -> Result, U256)>, DispatchError> { - let mut result: Vec<(CurrencyIdOf, U256)> = Vec::new(); - - match token_id { - Some(token_id) => { - let vtoken_amount = Self::get_vtoken_amount(token_id, 1000u128)?; - result.push((token_id, vtoken_amount)); - }, - None => - for token_id in T::AssetIdMaps::get_all_currency() { - if token_id.is_vtoken() { - let vtoken_id = token_id; - let token_id = T::CurrencyIdConversion::convert_to_token(vtoken_id) - .map_err(|_| Error::::NotSupportTokenType)?; - - let vtoken_amount = Self::get_vtoken_amount(token_id, 1000u128)?; - result.push((token_id, vtoken_amount)); - } - }, - } - Ok(result) - } - - fn get_vtoken_amount(token: CurrencyIdOf, amount: u128) -> Result { - let vtoken_id = T::CurrencyIdConversion::convert_to_vtoken(token) - .map_err(|_| Error::::NotSupportTokenType)?; - - let token_pool_amount = TokenPool::::get(token); - let vtoken_total_issuance = T::MultiCurrency::total_issuance(vtoken_id); - - let mut vtoken_amount = U256::from(amount); - if token_pool_amount != BalanceOf::::zero() { - let vtoken_total_issuance_u256 = - U256::from(vtoken_total_issuance.saturated_into::()); - let token_pool_amount_u256 = U256::from(token_pool_amount.saturated_into::()); - - vtoken_amount = vtoken_amount - .saturating_mul(vtoken_total_issuance_u256) - .checked_div(token_pool_amount_u256) - .ok_or(Error::::CalculationOverflow)?; - } - Ok(vtoken_amount) - } - } -} - -impl VtokenMintingOperator, AccountIdOf, TimeUnit> - for Pallet -{ - fn get_token_pool(currency_id: CurrencyId) -> BalanceOf { - TokenPool::::get(currency_id) - } - - fn increase_token_pool(currency_id: CurrencyId, token_amount: BalanceOf) -> DispatchResult { - TokenPool::::mutate(currency_id, |pool| -> Result<(), Error> { - *pool = pool.checked_add(&token_amount).ok_or(Error::::CalculationOverflow)?; - - Ok(()) - })?; - - Ok(()) - } - - fn decrease_token_pool(currency_id: CurrencyId, token_amount: BalanceOf) -> DispatchResult { - TokenPool::::mutate(currency_id, |pool| -> Result<(), Error> { - *pool = pool.checked_sub(&token_amount).ok_or(Error::::CalculationOverflow)?; - Ok(()) - })?; - - Ok(()) - } - - fn update_ongoing_time_unit(currency_id: CurrencyId, time_unit: TimeUnit) -> DispatchResult { - OngoingTimeUnit::::mutate(currency_id, |time_unit_old| -> Result<(), Error> { - *time_unit_old = Some(time_unit); - Ok(()) - })?; - - Ok(()) - } - - fn get_ongoing_time_unit(currency_id: CurrencyId) -> Option { - OngoingTimeUnit::::get(currency_id) - } - - fn get_unlock_records( - currency_id: CurrencyId, - time_unit: TimeUnit, - ) -> Option<(BalanceOf, Vec)> { - if let Some((balance, list, _)) = TimeUnitUnlockLedger::::get(&time_unit, currency_id) { - Some((balance, list.into_inner())) - } else { - None - } - } - - #[transactional] - fn deduct_unlock_amount( - currency_id: CurrencyId, - index: u32, - deduct_amount: BalanceOf, - ) -> DispatchResult { - if let Some((who, unlock_amount, time_unit, _)) = - TokenUnlockLedger::::get(currency_id, index) - { - ensure!(unlock_amount >= deduct_amount, Error::::NotEnoughBalanceToUnlock); - - UnlockingTotal::::mutate(¤cy_id, |pool| -> Result<(), Error> { - *pool = pool.checked_sub(&deduct_amount).ok_or(Error::::CalculationOverflow)?; - Ok(()) - })?; - - TimeUnitUnlockLedger::::mutate_exists( - &time_unit, - ¤cy_id, - |value| -> Result<(), Error> { - if let Some((total_locked_origin, ledger_list_origin, _)) = value { - if total_locked_origin == &deduct_amount { - *value = None; - return Ok(()); - } - *total_locked_origin = total_locked_origin - .checked_sub(&deduct_amount) - .ok_or(Error::::CalculationOverflow)?; - if unlock_amount == deduct_amount { - ledger_list_origin.retain(|&x| x != index); - } - } else { - return Err(Error::::TimeUnitUnlockLedgerNotFound); - } - Ok(()) - }, - )?; - - UserUnlockLedger::::mutate_exists( - &who, - ¤cy_id, - |value| -> Result<(), Error> { - if let Some((total_locked_origin, ledger_list_origin)) = value { - if total_locked_origin == &deduct_amount { - *value = None; - return Ok(()); - } - *total_locked_origin = total_locked_origin - .checked_sub(&deduct_amount) - .ok_or(Error::::CalculationOverflow)?; - if unlock_amount == deduct_amount { - ledger_list_origin.retain(|&x| x != index); - } - } else { - return Err(Error::::UserUnlockLedgerNotFound); - } - Ok(()) - }, - )?; - - if unlock_amount == deduct_amount { - TokenUnlockLedger::::remove(¤cy_id, &index); - } else { - TokenUnlockLedger::::mutate_exists( - ¤cy_id, - &index, - |value| -> Result<(), Error> { - if let Some((_, total_locked_origin, _, _)) = value { - if total_locked_origin == &deduct_amount { - *value = None; - return Ok(()); - } - *total_locked_origin = total_locked_origin - .checked_sub(&deduct_amount) - .ok_or(Error::::CalculationOverflow)?; - } else { - return Err(Error::::TokenUnlockLedgerNotFound); - } - Ok(()) - }, - )?; - } - } - Ok(()) - } - - fn get_entrance_and_exit_accounts() -> (AccountIdOf, AccountIdOf) { - ( - T::EntranceAccount::get().into_account_truncating(), - T::ExitAccount::get().into_account_truncating(), - ) - } - - fn get_token_unlock_ledger( - currency_id: CurrencyId, - index: u32, - ) -> Option<(AccountIdOf, BalanceOf, TimeUnit, RedeemType>)> { - TokenUnlockLedger::::get(currency_id, index) - } - - fn get_moonbeam_parachain_id() -> u32 { - T::MoonbeamChainId::get() - } -} - -impl VtokenMintingInterface, CurrencyIdOf, BalanceOf> - for Pallet -{ - fn mint( - exchanger: AccountIdOf, - token_id: CurrencyIdOf, - token_amount: BalanceOf, - remark: BoundedVec>, - channel_id: Option, - ) -> Result, DispatchError> { - Self::mint_inner(exchanger, token_id, token_amount, remark, channel_id) - } - - fn redeem( - exchanger: AccountIdOf, - vtoken_id: CurrencyIdOf, - vtoken_amount: BalanceOf, - ) -> DispatchResultWithPostInfo { - Self::redeem_inner(exchanger, vtoken_id, vtoken_amount, RedeemType::Native) - } - - fn slpx_redeem( - exchanger: AccountIdOf, - vtoken_id: CurrencyIdOf, - vtoken_amount: BalanceOf, - redeem_type: RedeemType>, - ) -> DispatchResultWithPostInfo { - Self::redeem_inner(exchanger, vtoken_id, vtoken_amount, redeem_type) - } - - fn token_to_vtoken( - token_id: CurrencyIdOf, - vtoken_id: CurrencyIdOf, - token_amount: BalanceOf, - ) -> Result, DispatchError> { - Self::token_to_vtoken_inner(token_id, vtoken_id, token_amount) - } - - fn vtoken_to_token( - token_id: CurrencyIdOf, - vtoken_id: CurrencyIdOf, - vtoken_amount: BalanceOf, - ) -> Result, DispatchError> { - Self::vtoken_to_token_inner(token_id, vtoken_id, vtoken_amount) - } - - fn vtoken_id(token_id: CurrencyIdOf) -> Option> { - Self::vtoken_id_inner(token_id) - } - - fn token_id(vtoken_id: CurrencyIdOf) -> Option> { - Self::token_id_inner(vtoken_id) - } - - fn get_minimums_redeem(vtoken_id: CurrencyIdOf) -> BalanceOf { - MinimumRedeem::::get(vtoken_id) - } - - fn get_token_pool(currency_id: CurrencyId) -> BalanceOf { - TokenPool::::get(currency_id) - } - - fn get_moonbeam_parachain_id() -> u32 { - T::MoonbeamChainId::get() - } -} - -impl VTokenSupplyProvider, BalanceOf> for Pallet { - fn get_vtoken_supply(vtoken: CurrencyIdOf) -> Option> { - if CurrencyId::is_vtoken(&vtoken) { - Some(T::MultiCurrency::total_issuance(vtoken)) - } else { - None - } - } - - fn get_token_supply(token: CurrencyIdOf) -> Option> { - if CurrencyId::is_token(&token) | CurrencyId::is_native(&token) { - Some(TokenPool::::get(token)) - } else { - None - } - } } diff --git a/pallets/vtoken-minting/src/mock.rs b/pallets/vtoken-minting/src/mock.rs index 3a7bb38ad..46bffd730 100644 --- a/pallets/vtoken-minting/src/mock.rs +++ b/pallets/vtoken-minting/src/mock.rs @@ -26,26 +26,17 @@ use bifrost_asset_registry::AssetIdMaps; use bifrost_primitives::{ currency::{BNC, DOT, FIL, KSM, MOVR, VBNC, VFIL, VKSM, VMOVR}, BifrostEntranceAccount, BifrostExitAccount, BifrostFeeAccount, CurrencyId, CurrencyIdMapping, - IncentivePoolAccount, MoonbeamChainId, SlpxOperator, KUSD, + IncentivePoolAccount, MockXcmTransfer, MoonbeamChainId, SlpxOperator, KUSD, }; use bifrost_runtime_common::{micro, milli}; -use bifrost_slp::{QueryId, QueryResponseManager}; -pub use cumulus_primitives_core::ParaId; -use frame_support::{ - derive_impl, ord_parameter_types, - pallet_prelude::Get, - parameter_types, - traits::{Everything, Nothing}, -}; -use frame_system::{EnsureRoot, EnsureSignedBy}; -use orml_traits::{location::RelativeReserveProvider, parameter_type_with_key}; +use frame_support::{derive_impl, ord_parameter_types, parameter_types, traits::Nothing}; +use frame_system::EnsureSignedBy; +use orml_traits::parameter_type_with_key; use sp_runtime::{ traits::{ConstU32, IdentityLookup}, AccountId32, BuildStorage, DispatchError, DispatchResult, }; -use xcm::{prelude::*, v3::Weight}; -use xcm_builder::{FixedWeightBounds, FrameTransactionalProcessor}; -use xcm_executor::XcmExecutor; +use xcm::prelude::*; use crate as vtoken_minting; @@ -63,13 +54,10 @@ frame_support::construct_runtime!( pub enum Runtime { System: frame_system, Tokens: orml_tokens, - XTokens: orml_xtokens, Balances: pallet_balances, Currencies: bifrost_currencies, VtokenMinting: vtoken_minting, - Slp: bifrost_slp, AssetRegistry: bifrost_asset_registry, - PolkadotXcm: pallet_xcm, } ); @@ -164,31 +152,6 @@ parameter_type_with_key! { }; } -parameter_types! { - pub SelfRelativeLocation: Location = Location::here(); - pub const BaseXcmWeight: Weight = Weight::from_parts(1000_000_000u64, 0); - pub const MaxAssetsForTransfer: usize = 2; -} - -impl orml_xtokens::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Balance = Balance; - type CurrencyId = CurrencyId; - type CurrencyIdConvert = (); - type AccountIdToLocation = (); - type UniversalLocation = UniversalLocation; - type SelfLocation = SelfRelativeLocation; - type XcmExecutor = XcmExecutor; - type Weigher = FixedWeightBounds; - type BaseXcmWeight = BaseXcmWeight; - type MaxAssetsForTransfer = MaxAssetsForTransfer; - type MinXcmFee = ParachainMinFee; - type LocationsFilter = Everything; - type ReserveProvider = RelativeReserveProvider; - type RateLimiter = (); - type RateLimiterId = (); -} - parameter_types! { pub const MaximumUnlockIdOfUser: u32 = 1_000; pub const MaximumUnlockIdOfTimeUnit: u32 = 1_000; @@ -212,18 +175,14 @@ impl vtoken_minting::Config for Runtime { type FeeAccount = BifrostFeeAccount; type RedeemFeeAccount = BifrostFeeAccount; type IncentivePoolAccount = IncentivePoolAccount; - type BifrostSlp = Slp; type BifrostSlpx = SlpxInterface; type BbBNC = BbBNC; type RelayChainToken = RelayCurrencyId; - type CurrencyIdConversion = AssetIdMaps; - type CurrencyIdRegister = AssetIdMaps; type WeightInfo = (); type OnRedeemSuccess = (); - type XcmTransfer = XTokens; + type XcmTransfer = MockXcmTransfer; type MoonbeamChainId = MoonbeamChainId; type ChannelCommission = (); - type AssetIdMaps = AssetIdMaps; } ord_parameter_types! { @@ -235,35 +194,6 @@ impl bifrost_asset_registry::Config for Runtime { type RegisterOrigin = EnsureSignedBy; type WeightInfo = (); } -pub struct ParachainId; -impl Get for ParachainId { - fn get() -> ParaId { - 2001.into() - } -} - -parameter_types! { - pub const MaxTypeEntryPerBlock: u32 = 10; - pub const MaxRefundPerBlock: u32 = 10; - pub const MaxLengthLimit: u32 = 100; -} - -pub struct SubstrateResponseManager; -impl QueryResponseManager for SubstrateResponseManager { - fn get_query_response_record(_query_id: QueryId) -> bool { - Default::default() - } - fn create_query_record( - _responder: Location, - _call_back: Option, - _timeout: u64, - ) -> u64 { - Default::default() - } - fn remove_query_record(_query_id: QueryId) -> bool { - Default::default() - } -} pub struct SlpxInterface; impl SlpxOperator for SlpxInterface { @@ -272,105 +202,6 @@ impl SlpxOperator for SlpxInterface { } } -pub const TREASURY_ACCOUNT: AccountId = AccountId32::new([9u8; 32]); -parameter_types! { - pub const TreasuryAccount: AccountId32 = TREASURY_ACCOUNT; -} - -impl bifrost_slp::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type MultiCurrency = Currencies; - type ControlOrigin = EnsureSignedBy; - type WeightInfo = (); - type VtokenMinting = VtokenMinting; - type AccountConverter = (); - type ParachainId = ParachainId; - type SubstrateResponseManager = SubstrateResponseManager; - type MaxTypeEntryPerBlock = MaxTypeEntryPerBlock; - type MaxRefundPerBlock = MaxRefundPerBlock; - type ParachainStaking = (); - type XcmTransfer = XTokens; - type MaxLengthLimit = MaxLengthLimit; - type XcmWeightAndFeeHandler = (); - type ChannelCommission = (); - type StablePoolHandler = (); - type AssetIdMaps = AssetIdMaps; - type TreasuryAccount = TreasuryAccount; -} - -parameter_types! { - // One XCM operation is 200_000_000 XcmWeight, cross-chain transfer ~= 2x of transfer = 3_000_000_000 - pub UnitWeightCost: Weight = Weight::from_parts(200_000_000, 0); - pub const MaxInstructions: u32 = 100; - pub UniversalLocation: InteriorLocation = Parachain(2001).into(); -} - -pub struct XcmConfig; -impl xcm_executor::Config for XcmConfig { - type AssetClaims = PolkadotXcm; - type AssetTransactor = (); - type AssetTrap = PolkadotXcm; - type Barrier = (); - type RuntimeCall = RuntimeCall; - type IsReserve = (); - type IsTeleporter = (); - type UniversalLocation = UniversalLocation; - type OriginConverter = (); - type ResponseHandler = PolkadotXcm; - type SubscriptionService = PolkadotXcm; - type Trader = (); - type Weigher = FixedWeightBounds; - type XcmSender = (); - type PalletInstancesInfo = AllPalletsWithSystem; - type MaxAssetsIntoHolding = ConstU32<64>; - type FeeManager = (); - type MessageExporter = (); - type UniversalAliases = Nothing; - type CallDispatcher = RuntimeCall; - type SafeCallFilter = Everything; - type AssetLocker = (); - type AssetExchanger = (); - type Aliasers = Nothing; - type TransactionalProcessor = FrameTransactionalProcessor; - type HrmpNewChannelOpenRequestHandler = (); - type HrmpChannelAcceptedHandler = (); - type HrmpChannelClosingHandler = (); - type XcmRecorder = (); -} - -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); -} - -impl pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; - type UniversalLocation = UniversalLocation; - type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; - type Weigher = FixedWeightBounds; - type XcmExecuteFilter = Nothing; - type XcmExecutor = XcmExecutor; - type XcmReserveTransferFilter = Everything; - type XcmRouter = (); - type XcmTeleportFilter = Nothing; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; - type AdvertisedXcmVersion = ConstU32<2>; - type Currency = Balances; - type CurrencyMatcher = (); - type TrustedLockers = (); - type SovereignAccountOf = (); - type MaxLockers = ConstU32<8>; - type WeightInfo = pallet_xcm::TestWeightInfo; - type AdminOrigin = EnsureRoot; - type MaxRemoteLockConsumers = ConstU32<0>; - type RemoteLockConsumerIdentifier = (); -} - pub struct ExtBuilder { endowed_accounts: Vec<(AccountId, CurrencyId, Balance)>, } diff --git a/pallets/vtoken-minting/src/tests.rs b/pallets/vtoken-minting/src/tests.rs index 20e47dac7..791eddc4f 100644 --- a/pallets/vtoken-minting/src/tests.rs +++ b/pallets/vtoken-minting/src/tests.rs @@ -21,7 +21,10 @@ #![cfg(test)] use crate::{mock::*, DispatchError::Module, *}; -use bifrost_primitives::currency::{BNC, FIL, KSM, MOVR, VBNC, VFIL, VKSM, VMOVR}; +use bifrost_primitives::{ + currency::{BNC, FIL, KSM, MOVR, VBNC, VFIL, VKSM, VMOVR}, + VtokenMintingOperator, +}; use frame_support::{assert_noop, assert_ok, sp_runtime::Permill, BoundedVec}; use sp_runtime::ModuleError; @@ -492,7 +495,7 @@ fn fast_redeem_for_fil() { } #[test] -fn recreate_currency_ongoing_time_unit_should_work() { +fn set_ongoing_time_unit_should_work() { ExtBuilder::default().one_hundred_for_alice_n_bob().build().execute_with(|| { env_logger::try_init().unwrap_or(()); @@ -500,8 +503,8 @@ fn recreate_currency_ongoing_time_unit_should_work() { OngoingTimeUnit::::insert(KSM, TimeUnit::Era(1)); assert_eq!(OngoingTimeUnit::::get(KSM), Some(TimeUnit::Era(1))); - // recreate_currency_ongoing_time_unit the ongoing time unit of KSM to be Round(2) - assert_ok!(VtokenMinting::recreate_currency_ongoing_time_unit( + // set_ongoing_time_unit the ongoing time unit of KSM to be Round(2) + assert_ok!(VtokenMinting::set_ongoing_time_unit( RuntimeOrigin::signed(ALICE), KSM, TimeUnit::Round(2) diff --git a/pallets/vtoken-minting/src/weights.rs b/pallets/vtoken-minting/src/weights.rs index 68f316aaf..708be1483 100644 --- a/pallets/vtoken-minting/src/weights.rs +++ b/pallets/vtoken-minting/src/weights.rs @@ -58,7 +58,7 @@ pub trait WeightInfo { fn set_unlock_duration() -> Weight; fn set_unlocking_total() -> Weight; fn set_min_time_unit() -> Weight; - fn recreate_currency_ongoing_time_unit() -> Weight; + fn set_ongoing_time_unit() -> Weight; fn add_support_rebond_token() -> Weight; fn remove_support_rebond_token() -> Weight; fn set_fees() -> Weight; @@ -137,7 +137,7 @@ impl WeightInfo for () { } /// Storage: `VtokenMinting::OngoingTimeUnit` (r:1 w:1) /// Proof: `VtokenMinting::OngoingTimeUnit` (`max_values`: None, `max_size`: Some(27), added: 2502, mode: `MaxEncodedLen`) - fn recreate_currency_ongoing_time_unit() -> Weight { + fn set_ongoing_time_unit() -> Weight { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3492` diff --git a/primitives/src/time_unit.rs b/primitives/src/time_unit.rs index 8d6a5cafb..bf2242bc1 100644 --- a/primitives/src/time_unit.rs +++ b/primitives/src/time_unit.rs @@ -51,9 +51,25 @@ impl TimeUnit { pub fn add(self, other_time: Self) -> Option { match (self, other_time) { (TimeUnit::Era(a), TimeUnit::Era(b)) => Some(TimeUnit::Era(a.saturating_add(b))), + (TimeUnit::SlashingSpan(a), TimeUnit::SlashingSpan(b)) => + Some(TimeUnit::SlashingSpan(a.saturating_add(b))), + (TimeUnit::Round(a), TimeUnit::Round(b)) => Some(TimeUnit::Round(a.saturating_add(b))), + (TimeUnit::Kblock(a), TimeUnit::Kblock(b)) => + Some(TimeUnit::Kblock(a.saturating_add(b))), + (TimeUnit::Hour(a), TimeUnit::Hour(b)) => Some(TimeUnit::Hour(a.saturating_add(b))), _ => None, } } + + pub fn into_value(self) -> u32 { + match self { + TimeUnit::Era(a) => a, + TimeUnit::SlashingSpan(a) => a, + TimeUnit::Round(a) => a, + TimeUnit::Kblock(a) => a, + TimeUnit::Hour(a) => a, + } + } } impl Default for TimeUnit { diff --git a/primitives/src/traits.rs b/primitives/src/traits.rs index 1d9f630bc..e7d7e5d69 100644 --- a/primitives/src/traits.rs +++ b/primitives/src/traits.rs @@ -121,13 +121,6 @@ pub trait VtokenMintingOperator { time_unit: TimeUnit, ) -> Option<(Balance, Vec)>; - /// Revise the currency indexed unlocking record by some amount. - fn deduct_unlock_amount( - currency_id: CurrencyId, - index: u32, - deduct_amount: Balance, - ) -> DispatchResult; - /// Get currency Entrance and Exit accounts.【entrance_account, exit_account】 fn get_entrance_and_exit_accounts() -> (AccountId, AccountId); @@ -260,18 +253,16 @@ pub trait VtokenMintingInterface { vtoken_amount: Balance, redeem: RedeemType, ) -> DispatchResultWithPostInfo; - fn token_to_vtoken( + fn get_v_currency_amount_by_currency_amount( token_id: CurrencyId, vtoken_id: CurrencyId, token_amount: Balance, ) -> Result; - fn vtoken_to_token( + fn get_currency_amount_by_v_currency_amount( token_id: CurrencyId, vtoken_id: CurrencyId, vtoken_amount: Balance, ) -> Result; - fn vtoken_id(token_id: CurrencyId) -> Option; - fn token_id(vtoken_id: CurrencyId) -> Option; fn get_token_pool(currency_id: CurrencyId) -> Balance; fn get_minimums_redeem(vtoken_id: CurrencyId) -> Balance; fn get_moonbeam_parachain_id() -> u32; @@ -307,7 +298,7 @@ impl VtokenMintingInterface VtokenMintingInterface VtokenMintingInterface Option { - None - } - - fn token_id(_vtoken_id: CurrencyId) -> Option { - None - } - fn get_token_pool(_currency_id: CurrencyId) -> Balance { Zero::zero() } diff --git a/runtime/bifrost-kusama/src/lib.rs b/runtime/bifrost-kusama/src/lib.rs index 023e7fbc9..69f7802df 100644 --- a/runtime/bifrost-kusama/src/lib.rs +++ b/runtime/bifrost-kusama/src/lib.rs @@ -57,7 +57,7 @@ pub use pallet_balances::Call as BalancesCall; pub use pallet_timestamp::Call as TimestampCall; use sp_api::impl_runtime_apis; use sp_arithmetic::Percent; -use sp_core::{ConstBool, OpaqueMetadata, U256}; +use sp_core::{ConstBool, OpaqueMetadata}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{ @@ -1448,20 +1448,16 @@ impl bifrost_vtoken_minting::Config for Runtime { type ExitAccount = SlpExitPalletId; type FeeAccount = BifrostFeeAccount; type RedeemFeeAccount = BifrostFeeAccount; - type BifrostSlp = Slp; type BifrostSlpx = Slpx; type WeightInfo = weights::bifrost_vtoken_minting::BifrostWeight; type OnRedeemSuccess = OnRedeemSuccess; type RelayChainToken = RelayCurrencyId; - type CurrencyIdConversion = AssetIdMaps; - type CurrencyIdRegister = AssetIdMaps; type XcmTransfer = XTokens; type MoonbeamChainId = MoonriverChainId; type ChannelCommission = ChannelCommission; type MaxLockRecords = ConstU32<100>; type IncentivePoolAccount = IncentivePoolAccount; type BbBNC = (); - type AssetIdMaps = AssetIdMaps; } impl bifrost_slpx::Config for Runtime { @@ -2254,9 +2250,13 @@ impl_runtime_apis! { } } - impl bifrost_vtoken_minting_rpc_runtime_api::VtokenMintingRuntimeApi for Runtime { - fn get_exchange_rate(token_id: Option) -> Vec<(CurrencyId, U256)> { - VtokenMinting::get_exchange_rate(token_id).unwrap_or(Vec::new()) + impl bifrost_vtoken_minting_rpc_runtime_api::VtokenMintingRuntimeApi for Runtime { + fn get_currency_amount_by_v_currency_amount(currnecy_id: CurrencyId, v_currency_id: CurrencyId, v_currency_amount: Balance) -> Balance { + VtokenMinting::get_currency_amount_by_v_currency_amount(currnecy_id, v_currency_id, v_currency_amount).unwrap_or(0) + } + + fn get_v_currency_amount_by_currency_amount(currnecy_id: CurrencyId, v_currency_id: CurrencyId, currency_amount: Balance) -> Balance { + VtokenMinting::get_v_currency_amount_by_currency_amount(currnecy_id, v_currency_id, currency_amount).unwrap_or(0) } } diff --git a/runtime/bifrost-kusama/src/weights/bifrost_vtoken_minting.rs b/runtime/bifrost-kusama/src/weights/bifrost_vtoken_minting.rs index c53ec8bb6..b8430618a 100644 --- a/runtime/bifrost-kusama/src/weights/bifrost_vtoken_minting.rs +++ b/runtime/bifrost-kusama/src/weights/bifrost_vtoken_minting.rs @@ -115,7 +115,7 @@ impl bifrost_vtoken_minting::WeightInfo for BifrostWeig } /// Storage: `VtokenMinting::OngoingTimeUnit` (r:1 w:1) /// Proof: `VtokenMinting::OngoingTimeUnit` (`max_values`: None, `max_size`: Some(27), added: 2502, mode: `MaxEncodedLen`) - fn recreate_currency_ongoing_time_unit() -> Weight { + fn set_ongoing_time_unit() -> Weight { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3492` diff --git a/runtime/bifrost-polkadot/src/lib.rs b/runtime/bifrost-polkadot/src/lib.rs index 38f978abb..17f9270b1 100644 --- a/runtime/bifrost-polkadot/src/lib.rs +++ b/runtime/bifrost-polkadot/src/lib.rs @@ -1334,20 +1334,16 @@ impl bifrost_vtoken_minting::Config for Runtime { type ExitAccount = SlpExitPalletId; type FeeAccount = BifrostFeeAccount; type RedeemFeeAccount = BifrostFeeAccount; - type BifrostSlp = Slp; type BifrostSlpx = Slpx; type WeightInfo = weights::bifrost_vtoken_minting::BifrostWeight; type OnRedeemSuccess = OnRedeemSuccess; type RelayChainToken = RelayCurrencyId; - type CurrencyIdConversion = AssetIdMaps; - type CurrencyIdRegister = AssetIdMaps; type XcmTransfer = XTokens; type MoonbeamChainId = MoonbeamChainId; type ChannelCommission = ChannelCommission; type MaxLockRecords = ConstU32<100>; type IncentivePoolAccount = IncentivePoolAccount; type BbBNC = BbBNC; - type AssetIdMaps = AssetIdMaps; } parameter_types! { @@ -2459,9 +2455,13 @@ impl fp_rpc::EthereumRuntimeRPCApi for Runtime { } } - impl bifrost_vtoken_minting_rpc_runtime_api::VtokenMintingRuntimeApi for Runtime { - fn get_exchange_rate(token_id: Option) -> Vec<(CurrencyId, U256)> { - VtokenMinting::get_exchange_rate(token_id).unwrap_or(Vec::new()) + impl bifrost_vtoken_minting_rpc_runtime_api::VtokenMintingRuntimeApi for Runtime { + fn get_currency_amount_by_v_currency_amount(currnecy_id: CurrencyId, v_currency_id: CurrencyId, v_currency_amount: Balance) -> Balance { + VtokenMinting::get_currency_amount_by_v_currency_amount(currnecy_id, v_currency_id, v_currency_amount).unwrap_or(0) + } + + fn get_v_currency_amount_by_currency_amount(currnecy_id: CurrencyId, v_currency_id: CurrencyId, currency_amount: Balance) -> Balance { + VtokenMinting::get_v_currency_amount_by_currency_amount(currnecy_id, v_currency_id, currency_amount).unwrap_or(0) } } diff --git a/runtime/bifrost-polkadot/src/weights/bifrost_vtoken_minting.rs b/runtime/bifrost-polkadot/src/weights/bifrost_vtoken_minting.rs index c53ec8bb6..b8430618a 100644 --- a/runtime/bifrost-polkadot/src/weights/bifrost_vtoken_minting.rs +++ b/runtime/bifrost-polkadot/src/weights/bifrost_vtoken_minting.rs @@ -115,7 +115,7 @@ impl bifrost_vtoken_minting::WeightInfo for BifrostWeig } /// Storage: `VtokenMinting::OngoingTimeUnit` (r:1 w:1) /// Proof: `VtokenMinting::OngoingTimeUnit` (`max_values`: None, `max_size`: Some(27), added: 2502, mode: `MaxEncodedLen`) - fn recreate_currency_ongoing_time_unit() -> Weight { + fn set_ongoing_time_unit() -> Weight { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3492` From bcd1527121649ddfa71e5aeb0e08842c6eb1fbb7 Mon Sep 17 00:00:00 2001 From: MJLNSN <96321798+MJLNSN@users.noreply.github.com> Date: Wed, 16 Oct 2024 23:14:11 +0800 Subject: [PATCH 27/30] Replaced bifrost-finance with bifrost-io. (#1466) * updated * unsolved * unsolved * Fix compile --------- Co-authored-by: hqwangningbo <2536935847@qq.com> --- Cargo.lock | 84 ++++++++++++++--------------- Cargo.toml | 82 ++++++++++++++-------------- README.md | 8 +-- node/cli/src/command.rs | 4 +- pallets/parachain-staking/README.md | 6 +-- pallets/system-staking/Cargo.toml | 4 +- scripts/bifrost-ecosystem.config.js | 2 +- 7 files changed, 95 insertions(+), 95 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8dac475d6..c201192fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4736,7 +4736,7 @@ dependencies = [ [[package]] name = "fc-api" version = "1.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "async-trait", "fp-storage", @@ -4748,7 +4748,7 @@ dependencies = [ [[package]] name = "fc-consensus" version = "2.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "async-trait", "fp-consensus", @@ -4764,7 +4764,7 @@ dependencies = [ [[package]] name = "fc-db" version = "2.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "async-trait", "ethereum 0.15.0", @@ -4794,7 +4794,7 @@ dependencies = [ [[package]] name = "fc-mapping-sync" version = "2.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "fc-db", "fc-storage", @@ -4817,7 +4817,7 @@ dependencies = [ [[package]] name = "fc-rpc" version = "2.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "ethereum 0.15.0", "ethereum-types", @@ -4871,7 +4871,7 @@ dependencies = [ [[package]] name = "fc-rpc-core" version = "1.1.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "ethereum 0.15.0", "ethereum-types", @@ -4886,7 +4886,7 @@ dependencies = [ [[package]] name = "fc-storage" version = "1.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "ethereum 0.15.0", "ethereum-types", @@ -5088,7 +5088,7 @@ dependencies = [ [[package]] name = "fp-account" version = "1.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "hex", "impl-serde", @@ -5106,7 +5106,7 @@ dependencies = [ [[package]] name = "fp-consensus" version = "2.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "ethereum 0.15.0", "parity-scale-codec", @@ -5117,7 +5117,7 @@ dependencies = [ [[package]] name = "fp-dynamic-fee" version = "1.0.0" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "async-trait", "sp-core", @@ -5127,7 +5127,7 @@ dependencies = [ [[package]] name = "fp-ethereum" version = "1.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "ethereum 0.15.0", "ethereum-types", @@ -5139,7 +5139,7 @@ dependencies = [ [[package]] name = "fp-evm" version = "3.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "evm", "frame-support", @@ -5154,7 +5154,7 @@ dependencies = [ [[package]] name = "fp-rpc" version = "3.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "ethereum 0.15.0", "ethereum-types", @@ -5170,7 +5170,7 @@ dependencies = [ [[package]] name = "fp-self-contained" version = "1.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "frame-support", "parity-scale-codec", @@ -5182,7 +5182,7 @@ dependencies = [ [[package]] name = "fp-storage" version = "2.0.0" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "parity-scale-codec", "serde", @@ -7549,7 +7549,7 @@ dependencies = [ [[package]] name = "merkle-distributor" version = "0.1.0" -source = "git+https://github.com/bifrost-finance/Zenlink-DEX-Module?branch=release-polkadot-v1.13.0#64e75422be893afe8b5029ce831b7318748a99c6" +source = "git+https://github.com/bifrost-io/Zenlink-DEX-Module?branch=release-polkadot-v1.13.0#870ec20d64a994f6ab1ae87c6b819f07d3311319" dependencies = [ "frame-support", "frame-system", @@ -8427,7 +8427,7 @@ dependencies = [ [[package]] name = "orml-oracle" version = "0.13.0" -source = "git+https://github.com/bifrost-finance/open-runtime-module-library?branch=release-polkadot-v1.13.0#a7ea052e958275502022b25f1fc1e5b0e146fe51" +source = "git+https://github.com/bifrost-io/open-runtime-module-library?branch=release-polkadot-v1.13.0#a7ea052e958275502022b25f1fc1e5b0e146fe51" dependencies = [ "frame-benchmarking", "frame-support", @@ -8446,7 +8446,7 @@ dependencies = [ [[package]] name = "orml-tokens" version = "0.13.0" -source = "git+https://github.com/bifrost-finance/open-runtime-module-library?branch=release-polkadot-v1.13.0#a7ea052e958275502022b25f1fc1e5b0e146fe51" +source = "git+https://github.com/bifrost-io/open-runtime-module-library?branch=release-polkadot-v1.13.0#a7ea052e958275502022b25f1fc1e5b0e146fe51" dependencies = [ "frame-support", "frame-system", @@ -8463,7 +8463,7 @@ dependencies = [ [[package]] name = "orml-traits" version = "0.13.0" -source = "git+https://github.com/bifrost-finance/open-runtime-module-library?branch=release-polkadot-v1.13.0#a7ea052e958275502022b25f1fc1e5b0e146fe51" +source = "git+https://github.com/bifrost-io/open-runtime-module-library?branch=release-polkadot-v1.13.0#a7ea052e958275502022b25f1fc1e5b0e146fe51" dependencies = [ "frame-support", "impl-trait-for-tuples", @@ -8483,7 +8483,7 @@ dependencies = [ [[package]] name = "orml-unknown-tokens" version = "0.13.0" -source = "git+https://github.com/bifrost-finance/open-runtime-module-library?branch=release-polkadot-v1.13.0#a7ea052e958275502022b25f1fc1e5b0e146fe51" +source = "git+https://github.com/bifrost-io/open-runtime-module-library?branch=release-polkadot-v1.13.0#a7ea052e958275502022b25f1fc1e5b0e146fe51" dependencies = [ "frame-support", "frame-system", @@ -8498,7 +8498,7 @@ dependencies = [ [[package]] name = "orml-utilities" version = "0.13.0" -source = "git+https://github.com/bifrost-finance/open-runtime-module-library?branch=release-polkadot-v1.13.0#a7ea052e958275502022b25f1fc1e5b0e146fe51" +source = "git+https://github.com/bifrost-io/open-runtime-module-library?branch=release-polkadot-v1.13.0#a7ea052e958275502022b25f1fc1e5b0e146fe51" dependencies = [ "frame-support", "parity-scale-codec", @@ -8513,7 +8513,7 @@ dependencies = [ [[package]] name = "orml-xcm" version = "0.13.0" -source = "git+https://github.com/bifrost-finance/open-runtime-module-library?branch=release-polkadot-v1.13.0#a7ea052e958275502022b25f1fc1e5b0e146fe51" +source = "git+https://github.com/bifrost-io/open-runtime-module-library?branch=release-polkadot-v1.13.0#a7ea052e958275502022b25f1fc1e5b0e146fe51" dependencies = [ "frame-support", "frame-system", @@ -8527,7 +8527,7 @@ dependencies = [ [[package]] name = "orml-xcm-support" version = "0.13.0" -source = "git+https://github.com/bifrost-finance/open-runtime-module-library?branch=release-polkadot-v1.13.0#a7ea052e958275502022b25f1fc1e5b0e146fe51" +source = "git+https://github.com/bifrost-io/open-runtime-module-library?branch=release-polkadot-v1.13.0#a7ea052e958275502022b25f1fc1e5b0e146fe51" dependencies = [ "frame-support", "orml-traits", @@ -8541,7 +8541,7 @@ dependencies = [ [[package]] name = "orml-xtokens" version = "0.13.0" -source = "git+https://github.com/bifrost-finance/open-runtime-module-library?branch=release-polkadot-v1.13.0#a7ea052e958275502022b25f1fc1e5b0e146fe51" +source = "git+https://github.com/bifrost-io/open-runtime-module-library?branch=release-polkadot-v1.13.0#a7ea052e958275502022b25f1fc1e5b0e146fe51" dependencies = [ "frame-support", "frame-system", @@ -8745,7 +8745,7 @@ dependencies = [ [[package]] name = "pallet-base-fee" version = "1.0.0" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "fp-evm", "frame-support", @@ -8946,7 +8946,7 @@ dependencies = [ [[package]] name = "pallet-dynamic-fee" version = "4.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "fp-dynamic-fee", "fp-evm", @@ -9017,7 +9017,7 @@ dependencies = [ [[package]] name = "pallet-ethereum" version = "4.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "ethereum 0.15.0", "ethereum-types", @@ -9039,7 +9039,7 @@ dependencies = [ [[package]] name = "pallet-evm" version = "6.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "environmental", "evm", @@ -9089,7 +9089,7 @@ dependencies = [ [[package]] name = "pallet-evm-chain-id" version = "1.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "frame-support", "frame-system", @@ -9100,7 +9100,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-blake2" version = "2.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "fp-evm", ] @@ -9108,7 +9108,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-bn128" version = "2.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "fp-evm", "sp-core", @@ -9118,7 +9118,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-dispatch" version = "2.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "fp-evm", "frame-support", @@ -9130,7 +9130,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-modexp" version = "2.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "fp-evm", "num", @@ -9139,7 +9139,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-sha3fips" version = "2.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "fp-evm", "tiny-keccak", @@ -9148,7 +9148,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-simple" version = "2.0.0-dev" -source = "git+https://github.com/bifrost-finance/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" +source = "git+https://github.com/bifrost-io/frontier?branch=release-polkadot-v1.13.0#24a48ebc221399d129712eff41787ad800dc8a26" dependencies = [ "fp-evm", "ripemd", @@ -18034,7 +18034,7 @@ dependencies = [ [[package]] name = "zenlink-protocol" version = "0.4.4" -source = "git+https://github.com/bifrost-finance/Zenlink-DEX-Module?branch=release-polkadot-v1.13.0#64e75422be893afe8b5029ce831b7318748a99c6" +source = "git+https://github.com/bifrost-io/Zenlink-DEX-Module?branch=release-polkadot-v1.13.0#870ec20d64a994f6ab1ae87c6b819f07d3311319" dependencies = [ "cumulus-primitives-core", "frame-benchmarking", @@ -18056,7 +18056,7 @@ dependencies = [ [[package]] name = "zenlink-protocol-rpc" version = "0.4.4" -source = "git+https://github.com/bifrost-finance/Zenlink-DEX-Module?branch=release-polkadot-v1.13.0#64e75422be893afe8b5029ce831b7318748a99c6" +source = "git+https://github.com/bifrost-io/Zenlink-DEX-Module?branch=release-polkadot-v1.13.0#870ec20d64a994f6ab1ae87c6b819f07d3311319" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -18072,7 +18072,7 @@ dependencies = [ [[package]] name = "zenlink-protocol-runtime-api" version = "0.4.4" -source = "git+https://github.com/bifrost-finance/Zenlink-DEX-Module?branch=release-polkadot-v1.13.0#64e75422be893afe8b5029ce831b7318748a99c6" +source = "git+https://github.com/bifrost-io/Zenlink-DEX-Module?branch=release-polkadot-v1.13.0#870ec20d64a994f6ab1ae87c6b819f07d3311319" dependencies = [ "parity-scale-codec", "sp-api", @@ -18083,7 +18083,7 @@ dependencies = [ [[package]] name = "zenlink-stable-amm" version = "0.1.0" -source = "git+https://github.com/bifrost-finance/Zenlink-DEX-Module?branch=release-polkadot-v1.13.0#64e75422be893afe8b5029ce831b7318748a99c6" +source = "git+https://github.com/bifrost-io/Zenlink-DEX-Module?branch=release-polkadot-v1.13.0#870ec20d64a994f6ab1ae87c6b819f07d3311319" dependencies = [ "frame-support", "frame-system", @@ -18100,7 +18100,7 @@ dependencies = [ [[package]] name = "zenlink-stable-amm-rpc" version = "0.1.0" -source = "git+https://github.com/bifrost-finance/Zenlink-DEX-Module?branch=release-polkadot-v1.13.0#64e75422be893afe8b5029ce831b7318748a99c6" +source = "git+https://github.com/bifrost-io/Zenlink-DEX-Module?branch=release-polkadot-v1.13.0#870ec20d64a994f6ab1ae87c6b819f07d3311319" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -18114,7 +18114,7 @@ dependencies = [ [[package]] name = "zenlink-stable-amm-runtime-api" version = "0.1.0" -source = "git+https://github.com/bifrost-finance/Zenlink-DEX-Module?branch=release-polkadot-v1.13.0#64e75422be893afe8b5029ce831b7318748a99c6" +source = "git+https://github.com/bifrost-io/Zenlink-DEX-Module?branch=release-polkadot-v1.13.0#870ec20d64a994f6ab1ae87c6b819f07d3311319" dependencies = [ "parity-scale-codec", "sp-api", @@ -18125,7 +18125,7 @@ dependencies = [ [[package]] name = "zenlink-swap-router" version = "0.1.0" -source = "git+https://github.com/bifrost-finance/Zenlink-DEX-Module?branch=release-polkadot-v1.13.0#64e75422be893afe8b5029ce831b7318748a99c6" +source = "git+https://github.com/bifrost-io/Zenlink-DEX-Module?branch=release-polkadot-v1.13.0#870ec20d64a994f6ab1ae87c6b819f07d3311319" dependencies = [ "frame-support", "frame-system", diff --git a/Cargo.toml b/Cargo.toml index dbe0830a0..f3b79a2b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -106,51 +106,51 @@ pallet-prices = { path = "pallets/prices", default-feat pallet-traits = { path = "pallets/traits", default-features = false } # Zenlink -merkle-distributor = { git = "https://github.com/bifrost-finance/Zenlink-DEX-Module", branch = "release-polkadot-v1.13.0", default-features = false } -zenlink-protocol = { git = "https://github.com/bifrost-finance/Zenlink-DEX-Module", branch = "release-polkadot-v1.13.0", default-features = false } -zenlink-protocol-rpc = { git = "https://github.com/bifrost-finance/Zenlink-DEX-Module", branch = "release-polkadot-v1.13.0" } -zenlink-protocol-runtime-api = { git = "https://github.com/bifrost-finance/Zenlink-DEX-Module", branch = "release-polkadot-v1.13.0", default-features = false } -zenlink-stable-amm = { git = "https://github.com/bifrost-finance/Zenlink-DEX-Module", branch = "release-polkadot-v1.13.0", default-features = false } -zenlink-stable-amm-rpc = { git = "https://github.com/bifrost-finance/Zenlink-DEX-Module", branch = "release-polkadot-v1.13.0" } -zenlink-stable-amm-runtime-api = { git = "https://github.com/bifrost-finance/Zenlink-DEX-Module", branch = "release-polkadot-v1.13.0", default-features = false } -zenlink-swap-router = { git = "https://github.com/bifrost-finance/Zenlink-DEX-Module", branch = "release-polkadot-v1.13.0", default-features = false } +merkle-distributor = { git = "https://github.com/bifrost-io/Zenlink-DEX-Module", branch = "release-polkadot-v1.13.0", default-features = false } +zenlink-protocol = { git = "https://github.com/bifrost-io/Zenlink-DEX-Module", branch = "release-polkadot-v1.13.0", default-features = false } +zenlink-protocol-rpc = { git = "https://github.com/bifrost-io/Zenlink-DEX-Module", branch = "release-polkadot-v1.13.0" } +zenlink-protocol-runtime-api = { git = "https://github.com/bifrost-io/Zenlink-DEX-Module", branch = "release-polkadot-v1.13.0", default-features = false } +zenlink-stable-amm = { git = "https://github.com/bifrost-io/Zenlink-DEX-Module", branch = "release-polkadot-v1.13.0", default-features = false } +zenlink-stable-amm-rpc = { git = "https://github.com/bifrost-io/Zenlink-DEX-Module", branch = "release-polkadot-v1.13.0" } +zenlink-stable-amm-runtime-api = { git = "https://github.com/bifrost-io/Zenlink-DEX-Module", branch = "release-polkadot-v1.13.0", default-features = false } +zenlink-swap-router = { git = "https://github.com/bifrost-io/Zenlink-DEX-Module", branch = "release-polkadot-v1.13.0", default-features = false } # Orml -orml-tokens = { git = "https://github.com/bifrost-finance/open-runtime-module-library", branch = "release-polkadot-v1.13.0", default-features = false } -orml-traits = { git = "https://github.com/bifrost-finance/open-runtime-module-library", branch = "release-polkadot-v1.13.0", default-features = false } -orml-unknown-tokens = { git = "https://github.com/bifrost-finance/open-runtime-module-library", branch = "release-polkadot-v1.13.0", default-features = false } -orml-utilities = { git = "https://github.com/bifrost-finance/open-runtime-module-library", branch = "release-polkadot-v1.13.0", default-features = false } -orml-xcm = { git = "https://github.com/bifrost-finance/open-runtime-module-library", branch = "release-polkadot-v1.13.0", default-features = false } -orml-xcm-support = { git = "https://github.com/bifrost-finance/open-runtime-module-library", branch = "release-polkadot-v1.13.0", default-features = false } -orml-xtokens = { git = "https://github.com/bifrost-finance/open-runtime-module-library", branch = "release-polkadot-v1.13.0", default-features = false } -orml-oracle = { git = "https://github.com/bifrost-finance/open-runtime-module-library", branch = "release-polkadot-v1.13.0", default-features = false } +orml-tokens = { git = "https://github.com/bifrost-io/open-runtime-module-library", branch = "release-polkadot-v1.13.0", default-features = false } +orml-traits = { git = "https://github.com/bifrost-io/open-runtime-module-library", branch = "release-polkadot-v1.13.0", default-features = false } +orml-unknown-tokens = { git = "https://github.com/bifrost-io/open-runtime-module-library", branch = "release-polkadot-v1.13.0", default-features = false } +orml-utilities = { git = "https://github.com/bifrost-io/open-runtime-module-library", branch = "release-polkadot-v1.13.0", default-features = false } +orml-xcm = { git = "https://github.com/bifrost-io/open-runtime-module-library", branch = "release-polkadot-v1.13.0", default-features = false } +orml-xcm-support = { git = "https://github.com/bifrost-io/open-runtime-module-library", branch = "release-polkadot-v1.13.0", default-features = false } +orml-xtokens = { git = "https://github.com/bifrost-io/open-runtime-module-library", branch = "release-polkadot-v1.13.0", default-features = false } +orml-oracle = { git = "https://github.com/bifrost-io/open-runtime-module-library", branch = "release-polkadot-v1.13.0", default-features = false } # Frontier -fc-api = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -fc-consensus = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -fc-db = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -fc-mapping-sync = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -fc-rpc = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -fc-rpc-core = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -fc-storage = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -fp-account = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -fp-consensus = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -fp-dynamic-fee = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -fp-evm = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -fp-rpc = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -fp-self-contained = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -fp-storage = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -pallet-base-fee = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -pallet-dynamic-fee = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -pallet-ethereum = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -pallet-evm = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -pallet-evm-chain-id = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -pallet-evm-precompile-blake2 = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -pallet-evm-precompile-bn128 = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -pallet-evm-precompile-dispatch = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -pallet-evm-precompile-modexp = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -pallet-evm-precompile-sha3fips = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } -pallet-evm-precompile-simple = { git = "https://github.com/bifrost-finance/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +fc-api = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +fc-consensus = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +fc-db = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +fc-mapping-sync = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +fc-rpc = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +fc-rpc-core = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +fc-storage = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +fp-account = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +fp-consensus = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +fp-dynamic-fee = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +fp-evm = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +fp-rpc = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +fp-self-contained = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +fp-storage = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +pallet-base-fee = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +pallet-dynamic-fee = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +pallet-ethereum = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +pallet-evm = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +pallet-evm-chain-id = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +pallet-evm-precompile-blake2 = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +pallet-evm-precompile-bn128 = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +pallet-evm-precompile-dispatch = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +pallet-evm-precompile-modexp = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +pallet-evm-precompile-sha3fips = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } +pallet-evm-precompile-simple = { git = "https://github.com/bifrost-io/frontier", branch = "release-polkadot-v1.13.0", default-features = false } # polkadot-sdk (wasm) cumulus-client-collator = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.13.0", default-features = false } diff --git a/README.md b/README.md index c2d31c536..60bcfa523 100644 --- a/README.md +++ b/README.md @@ -21,13 +21,13 @@ Bifrost is a Web3 derivatives protocol that provides decentralized cross-chain l Web3 Bootcamp

-[![master-build](https://img.shields.io/github/actions/workflow/status/bifrost-finance/bifrost/ci-build.yml?logo=Buddy)](https://github.com/bifrost-finance/bifrost/actions/workflows/ci-build.yml) -[![Codacy Badge](https://app.codacy.com/project/badge/Grade/acec53276777415593c2b02b2200f62e)](https://www.codacy.com/gh/bifrost-finance/bifrost?utm_source=github.com&utm_medium=referral&utm_content=bifrost-finance/bifrost&utm_campaign=Badge_Grade) +[![master-build](https://img.shields.io/github/actions/workflow/status/bifrost-io/bifrost/ci-build.yml?logo=Buddy)](https://github.com/bifrost-io/bifrost/actions/workflows/ci-build.yml) +[![Codacy Badge](https://app.codacy.com/project/badge/Grade/acec53276777415593c2b02b2200f62e)](https://www.codacy.com/gh/bifrost-io/bifrost?utm_source=github.com&utm_medium=referral&utm_content=bifrost-io/bifrost&utm_campaign=Badge_Grade) [![Substrate Version](https://img.shields.io/badge/Substrate-latest-brightgreen?logo=Parity%20Substrate)](https://github.com/paritytech/substrate) -[![License](https://img.shields.io/github/license/bifrost-finance/bifrost?color=blue)](https://github.com/bifrost-finance/bifrost/blob/master/LICENSE) +[![License](https://img.shields.io/github/license/bifrost-io/bifrost?color=blue)](https://github.com/bifrost-io/bifrost/blob/master/LICENSE) [![Dapp](https://img.shields.io/badge/Dapp-5c5c5c?logo=Icinga)](https://app.bifrost.io) [![Analytics](https://img.shields.io/badge/-Analytics-5c5c5c?logo=Google%20Analytics)](https://stats.bifrost.io) -[![Discord](https://img.shields.io/badge/-Discord-5c5c5c?logo=Discord)](https://discord.gg/bifrost-finance) +[![Discord](https://img.shields.io/badge/-Discord-5c5c5c?logo=Discord)](https://discord.gg/bifrost-io) [![Twitter](https://img.shields.io/badge/-X-5c5c5c?logo=X&logoColor=white)](https://x.com/Bifrost) ## Get Build Help diff --git a/node/cli/src/command.rs b/node/cli/src/command.rs index ec2445401..f415a92b1 100644 --- a/node/cli/src/command.rs +++ b/node/cli/src/command.rs @@ -137,7 +137,7 @@ impl SubstrateCli for Cli { } fn support_url() -> String { - "https://github.com/bifrost-finance/bifrost/issues/new".into() + "https://github.com/bifrost-io/bifrost/issues/new".into() } fn copyright_start_year() -> i32 { @@ -171,7 +171,7 @@ impl SubstrateCli for RelayChainCli { } fn support_url() -> String { - "https://github.com/bifrost-finance/bifrost/issues/new".into() + "https://github.com/bifrost-io/bifrost/issues/new".into() } fn copyright_start_year() -> i32 { diff --git a/pallets/parachain-staking/README.md b/pallets/parachain-staking/README.md index f995f3161..9a8e2f58a 100644 --- a/pallets/parachain-staking/README.md +++ b/pallets/parachain-staking/README.md @@ -1,6 +1,6 @@ # Collator Staking -[![Rust Check & Build](https://github.com/bifrost-finance/parachain-staking/actions/workflows/ci.yml/badge.svg)](https://github.com/bifrost-finance/parachain-staking/actions/workflows/ci.yml) +[![Rust Check & Build](https://github.com/bifrost-io/parachain-staking/actions/workflows/ci.yml/badge.svg)](https://github.com/bifrost-io/parachain-staking/actions/workflows/ci.yml) ## check && build @@ -114,7 +114,7 @@ mainly reference moonbeam implementation while decouple `nimbus` from staking, i ### Decomple with Nimbus - + ## Benifit of Nimbus @@ -122,7 +122,7 @@ mainly reference moonbeam implementation while decouple `nimbus` from staking, i actually we've prepared another branch with nimbus integration and we may try it later if required - + ## api docs diff --git a/pallets/system-staking/Cargo.toml b/pallets/system-staking/Cargo.toml index f89f6a445..d6ed5d30a 100644 --- a/pallets/system-staking/Cargo.toml +++ b/pallets/system-staking/Cargo.toml @@ -3,10 +3,10 @@ name = "bifrost-system-staking" version = "4.0.0-dev" description = "System staking pallet" authors = ["Akagi201 "] -homepage = "https://github.com/bifrost-finance/bifrost" +homepage = "https://github.com/bifrost-io/bifrost" edition = "2021" publish = false -repository = "https://github.com/bifrost-finance/bifrost" +repository = "https://github.com/bifrost-io/bifrost" readme = 'README.md' [package.metadata.docs.rs] diff --git a/scripts/bifrost-ecosystem.config.js b/scripts/bifrost-ecosystem.config.js index 61d39cb87..da9bfd2fd 100644 --- a/scripts/bifrost-ecosystem.config.js +++ b/scripts/bifrost-ecosystem.config.js @@ -13,7 +13,7 @@ module.exports = { "host" : ["192.168.0.13", "192.168.0.14", "192.168.0.15"], "key": "~/.ssh/deploy_rsa.pub", "ref" : "origin/develop", - "repo" : "git@github.com/bifrost-finance/bifrost.git", + "repo" : "git@github.com/bifrost-io/bifrost.git", "path" : "/home/bifrost/app", "post-setup": "make build-bifrost-release", 'post-deploy' : 'pm2 reload scripts/bifost-ecosystem.config.js --env production' From 8fe2c9c38c76ddbed2c6492eee7ee5699112fa7f Mon Sep 17 00:00:00 2001 From: yooml Date: Wed, 16 Oct 2024 23:16:10 +0800 Subject: [PATCH 28/30] =?UTF-8?q?fix:=20=F0=9F=90=9B=20pool=20ID=20for=20b?= =?UTF-8?q?bBNC=20(#1471)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pallets/bb-bnc/src/lib.rs | 2 +- pallets/buy-back/src/lib.rs | 5 ++--- pallets/buy-back/src/tests.rs | 36 +++++++++++++++++++++++++++++------ 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/pallets/bb-bnc/src/lib.rs b/pallets/bb-bnc/src/lib.rs index e88290f02..a027655d5 100644 --- a/pallets/bb-bnc/src/lib.rs +++ b/pallets/bb-bnc/src/lib.rs @@ -62,7 +62,7 @@ pub type CurrencyIdOf = <::MultiCurrency as MultiCurrency< const BB_LOCK_ID: LockIdentifier = *b"bbbnclck"; const MARKUP_LOCK_ID: LockIdentifier = *b"bbbncmkp"; -const BB_BNC_SYSTEM_POOL_ID: PoolId = u32::MAX; +pub const BB_BNC_SYSTEM_POOL_ID: PoolId = u32::MAX; #[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Default)] pub struct BbConfig { /// Minimum number of TokenType that users can lock diff --git a/pallets/buy-back/src/lib.rs b/pallets/buy-back/src/lib.rs index f6668d663..3c8445906 100644 --- a/pallets/buy-back/src/lib.rs +++ b/pallets/buy-back/src/lib.rs @@ -30,7 +30,7 @@ mod benchmarking; pub mod weights; -use bb_bnc::BbBNCInterface; +use bb_bnc::{BbBNCInterface, BB_BNC_SYSTEM_POOL_ID}; use bifrost_primitives::{currency::BNC, CurrencyId, CurrencyIdRegister, TryConvertFrom}; use cumulus_primitives_core::ParaId; use frame_support::{ @@ -414,9 +414,8 @@ pub mod pallet { T::MultiCurrency::withdraw(BNC, &buyback_address, destruction_amount)?; } let bnc_balance = T::MultiCurrency::free_balance(BNC, &buyback_address); - let pool_id = 0; T::BbBNC::notify_reward( - pool_id, + BB_BNC_SYSTEM_POOL_ID, &Some(buyback_address.clone()), vec![(BNC, bnc_balance)], ) diff --git a/pallets/buy-back/src/tests.rs b/pallets/buy-back/src/tests.rs index 864c9dfd9..462542f05 100644 --- a/pallets/buy-back/src/tests.rs +++ b/pallets/buy-back/src/tests.rs @@ -108,7 +108,11 @@ fn buy_back_with_burn_should_work() { assert_eq!(Currencies::free_balance(BNC, &zenlink_pair_account_id), 2000); assert_eq!(Currencies::free_balance(BNC, &buyback_account), 0); assert_eq!(Currencies::free_balance(BNC, &incentive_account), 0); - BbBNC::set_incentive(0, Some(7 * 86400 / 12), Some(buyback_account.clone())); + BbBNC::set_incentive( + BB_BNC_SYSTEM_POOL_ID, + Some(7 * 86400 / 12), + Some(buyback_account.clone()), + ); assert_ok!(BuyBack::charge(RuntimeOrigin::signed(ALICE), VKSM, 1000)); let infos = Infos::::get(VKSM).unwrap(); assert_ok!(BuyBack::buy_back(&buyback_account, VKSM, &infos, 0)); @@ -146,7 +150,11 @@ fn buy_back_no_burn_should_work() { assert_eq!(Currencies::free_balance(BNC, &zenlink_pair_account_id), 2000); assert_eq!(Currencies::free_balance(BNC, &buyback_account), 0); assert_eq!(Currencies::free_balance(BNC, &incentive_account), 0); - BbBNC::set_incentive(0, Some(7 * 86400 / 12), Some(buyback_account.clone())); + BbBNC::set_incentive( + BB_BNC_SYSTEM_POOL_ID, + Some(7 * 86400 / 12), + Some(buyback_account.clone()), + ); assert_ok!(BuyBack::charge(RuntimeOrigin::signed(ALICE), VKSM, 1000)); let infos = Infos::::get(VKSM).unwrap(); assert_ok!(BuyBack::buy_back(&buyback_account, VKSM, &infos, 0)); @@ -184,7 +192,11 @@ fn on_initialize_no_burn_should_work() { assert_eq!(Currencies::free_balance(BNC, &zenlink_pair_account_id), 2000); assert_eq!(Currencies::free_balance(BNC, &buyback_account), 0); assert_eq!(Currencies::free_balance(BNC, &incentive_account), 0); - BbBNC::set_incentive(0, Some(7 * 86400 / 12), Some(buyback_account.clone())); + BbBNC::set_incentive( + BB_BNC_SYSTEM_POOL_ID, + Some(7 * 86400 / 12), + Some(buyback_account.clone()), + ); assert_ok!(BuyBack::charge(RuntimeOrigin::signed(ALICE), VKSM, 1000)); BuyBack::on_initialize(1); BuyBack::on_initialize(2); @@ -222,7 +234,11 @@ fn on_initialize_with_burn_should_work() { assert_eq!(Currencies::free_balance(BNC, &zenlink_pair_account_id), 2000); assert_eq!(Currencies::free_balance(BNC, &buyback_account), 0); assert_eq!(Currencies::free_balance(BNC, &incentive_account), 0); - BbBNC::set_incentive(0, Some(7 * 86400 / 12), Some(buyback_account.clone())); + BbBNC::set_incentive( + BB_BNC_SYSTEM_POOL_ID, + Some(7 * 86400 / 12), + Some(buyback_account.clone()), + ); assert_ok!(BuyBack::charge(RuntimeOrigin::signed(ALICE), VKSM, 1000)); BuyBack::on_initialize(>::block_number() + 1); System::set_block_number(System::block_number() + 1); @@ -261,7 +277,11 @@ fn on_initialize_with_bias_should_work() { assert_eq!(Currencies::free_balance(BNC, &zenlink_pair_account_id), 2000); assert_eq!(Currencies::free_balance(BNC, &buyback_account), 0); assert_eq!(Currencies::free_balance(BNC, &incentive_account), 0); - BbBNC::set_incentive(0, Some(7 * 86400 / 12), Some(buyback_account.clone())); + BbBNC::set_incentive( + BB_BNC_SYSTEM_POOL_ID, + Some(7 * 86400 / 12), + Some(buyback_account.clone()), + ); assert_ok!(BuyBack::charge(RuntimeOrigin::signed(ALICE), VKSM, 1000)); BuyBack::on_initialize(1); let path = vec![ @@ -311,7 +331,11 @@ fn on_initialize_with_bias_should_not_work() { assert_eq!(Currencies::free_balance(BNC, &zenlink_pair_account_id), 2000); assert_eq!(Currencies::free_balance(BNC, &buyback_account), 0); assert_eq!(Currencies::free_balance(BNC, &incentive_account), 0); - BbBNC::set_incentive(0, Some(7 * 86400 / 12), Some(buyback_account.clone())); + BbBNC::set_incentive( + BB_BNC_SYSTEM_POOL_ID, + Some(7 * 86400 / 12), + Some(buyback_account.clone()), + ); assert_ok!(BuyBack::charge(RuntimeOrigin::signed(ALICE), VKSM, 1000)); BuyBack::on_initialize(1); let path = vec![ From dbe5db5e43e3d27b923519e8ce9588c8eb3c41a5 Mon Sep 17 00:00:00 2001 From: Gemma Date: Thu, 17 Oct 2024 10:04:39 +0800 Subject: [PATCH 29/30] removed allow in channel commission --- pallets/channel-commission/src/benchmarking.rs | 1 - pallets/farming/rpc/src/lib.rs | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pallets/channel-commission/src/benchmarking.rs b/pallets/channel-commission/src/benchmarking.rs index 64fa5a4ef..3eed35248 100644 --- a/pallets/channel-commission/src/benchmarking.rs +++ b/pallets/channel-commission/src/benchmarking.rs @@ -27,7 +27,6 @@ use frame_system::RawOrigin; use sp_runtime::traits::UniqueSaturatedFrom; use super::*; -#[allow(unused_imports)] use crate::Pallet as ChannelCommission; benchmarks! { diff --git a/pallets/farming/rpc/src/lib.rs b/pallets/farming/rpc/src/lib.rs index 9a926babd..7bd515478 100644 --- a/pallets/farming/rpc/src/lib.rs +++ b/pallets/farming/rpc/src/lib.rs @@ -66,7 +66,8 @@ impl FarmingRpc { #[async_trait] impl - FarmingRpcApiServer<::Hash, AccountId, PoolId, CurrencyId> for FarmingRpc + FarmingRpcApiServer<::Hash, AccountId, PoolId, CurrencyId> + for FarmingRpc where Block: BlockT, C: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, From 06489f4a058ad54a7cc7b31d49a77de28dbe584c Mon Sep 17 00:00:00 2001 From: Gemma Date: Thu, 17 Oct 2024 10:06:41 +0800 Subject: [PATCH 30/30] removed allow in channel commission --- pallets/farming/rpc/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pallets/farming/rpc/src/lib.rs b/pallets/farming/rpc/src/lib.rs index 7bd515478..9a926babd 100644 --- a/pallets/farming/rpc/src/lib.rs +++ b/pallets/farming/rpc/src/lib.rs @@ -66,8 +66,7 @@ impl FarmingRpc { #[async_trait] impl - FarmingRpcApiServer<::Hash, AccountId, PoolId, CurrencyId> - for FarmingRpc + FarmingRpcApiServer<::Hash, AccountId, PoolId, CurrencyId> for FarmingRpc where Block: BlockT, C: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend,