diff --git a/Cargo.lock b/Cargo.lock index b92147d24..6476ca98b 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", @@ -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/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/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/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/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/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..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 { @@ -182,7 +181,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 +223,7 @@ impl DataFeeder for MockDataProvider { Ok(()) } } -pub struct MockPriceFeeder; +pub struct MockOraclePriceProvider; #[derive(Encode, Decode, Clone, Copy, RuntimeDebug)] pub struct CurrencyIdWrap(CurrencyId); @@ -242,7 +241,7 @@ impl PartialEq for CurrencyIdWrap { impl Eq for CurrencyIdWrap {} -impl MockPriceFeeder { +impl MockOraclePriceProvider { thread_local! { pub static PRICES: RefCell>> = { RefCell::new( @@ -269,15 +268,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, @@ -398,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 { @@ -431,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/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..7e061dcb0 100644 --- a/pallets/flexible-fee/src/mock.rs +++ b/pallets/flexible-fee/src/mock.rs @@ -19,9 +19,9 @@ #![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 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 { @@ -167,7 +166,7 @@ impl crate::Config for Test { type RelaychainCurrencyId = RelayCurrencyId; type XcmRouter = (); type PalletId = FlexibleFeePalletId; - type PriceFeeder = MockPriceFeeder; + type OraclePriceProvider = MockOraclePriceProvider; } pub struct XcmDestWeightAndFee; @@ -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/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/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/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..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 { @@ -205,7 +195,7 @@ impl SortedMembers for AliceCreatePoolOrigin { } } -pub struct MockPriceFeeder; +pub struct MockOraclePriceProvider; #[derive(Encode, Decode, Clone, Copy, RuntimeDebug)] pub struct CurrencyIdWrap(CurrencyId); @@ -223,7 +213,7 @@ impl PartialEq for CurrencyIdWrap { impl Eq for CurrencyIdWrap {} -impl MockPriceFeeder { +impl MockOraclePriceProvider { thread_local! { pub static PRICES: RefCell>> = { RefCell::new( @@ -250,15 +240,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, @@ -320,14 +306,13 @@ 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; } 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..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, Price, PriceDetail, PriceFeeder, 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 { @@ -340,7 +336,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 +383,7 @@ impl DataFeeder for MockDataProvider { } } -impl MockPriceFeeder { +impl MockOraclePriceProvider { thread_local! { pub static PRICES: RefCell>> = { RefCell::new( @@ -414,15 +410,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, @@ -443,14 +435,13 @@ impl PriceFeeder for MockPriceFeeder { } parameter_types! { - pub const LendMarketPalletId: PalletId = PalletId(*b"bf/ldmkt"); pub const RewardAssetId: CurrencyId = BNC; pub const LiquidationFreeAssetId: CurrencyId = DOT; } 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/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/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/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..f377cbab3 100644 --- a/pallets/salp/src/mock.rs +++ b/pallets/salp/src/mock.rs @@ -20,20 +20,23 @@ #![cfg(test)] -use crate::*; 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; 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, }; use frame_system::{EnsureRoot, EnsureSignedBy, RawOrigin}; use orml_traits::{location::RelativeReserveProvider, parameter_type_with_key, MultiCurrency}; @@ -81,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! { @@ -178,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; } @@ -269,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; @@ -282,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; } @@ -331,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; @@ -365,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; @@ -446,7 +440,6 @@ parameter_types! { } impl salp::Config for Test { - type BancorPool = (); type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type RuntimeOrigin = RuntimeOrigin; @@ -465,14 +458,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! { @@ -582,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), @@ -591,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 31d5870cf..b30fb0d16 100644 --- a/pallets/salp/src/tests.rs +++ b/pallets/salp/src/tests.rs @@ -19,142 +19,16 @@ // 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::{ + 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; -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 +120,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 +747,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 +776,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 +897,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 +1016,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/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/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/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, 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/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 084150837..0e5bf5da9 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, @@ -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! { @@ -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! { @@ -1331,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 { @@ -1626,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-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/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 3943c075f..6560618d8 100644 --- a/runtime/bifrost-polkadot/src/lib.rs +++ b/runtime/bifrost-polkadot/src/lib.rs @@ -168,7 +168,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, @@ -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! { @@ -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 { @@ -1192,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 { @@ -1467,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/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 { .. } | 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) - } -}