From 161fa279c40501bee53b7d8292fa7bcd32b92f87 Mon Sep 17 00:00:00 2001 From: Cheng JIANG Date: Tue, 12 Oct 2021 12:36:59 +0800 Subject: [PATCH] finalize liquid staking (#659) * remove pallet-liquid-staking-v2 * fix feature gate * remove stake-client * fix CI * add xcm pallet call * cleanup * cleanup * rename RelayAgent to ParachainAccount * add RelayOrigin * increase baseXcmWeight * cleanup * add ump_transfer * cleanup * fix ci * add relayChainBlockNumber provider * switch to use para id * add xcm reserve transfer call * fix u128 <-> BalanceOf * fix * implement MaxRewardsPerEra, MaxSlashesPerEra * add transact call in settlement * add withdraw_unbonded_internal so that we can call it in onfinalize * withdraw in on_finalize hook * update unbonding storage * use macro instead of feature to fix conflict * fix lint & tests * rename current_block_number to relaychain_block_number --- .githooks/pre-commit | 2 +- .github/workflows/ci.yml | 2 +- .github/workflows/coverage.yml | 4 +- .github/workflows/rustdoc.yml | 2 +- Cargo.lock | 24 +- Makefile | 3 +- docker-compose.override.yml | 13 - node/parallel/src/chain_spec/heiko.rs | 3 + pallets/liquid-staking-v2/Cargo.toml | 41 -- pallets/liquid-staking-v2/src/lib.rs | 558 ------------------ pallets/liquid-staking-v2/src/mock.rs | 204 ------- pallets/liquid-staking-v2/src/tests.rs | 139 ----- pallets/liquid-staking-v2/src/types.rs | 58 -- pallets/liquid-staking-v2/src/weights.rs | 39 -- pallets/liquid-staking/Cargo.toml | 8 +- pallets/liquid-staking/src/lib.rs | 720 +++++++++++++++++++---- pallets/liquid-staking/src/mock.rs | 44 +- pallets/liquid-staking/src/relaychain.rs | 252 -------- pallets/liquid-staking/src/tests.rs | 93 ++- pallets/liquid-staking/src/types.rs | 155 ++--- pallets/liquid-staking/src/weights.rs | 36 +- pallets/loans/src/lib.rs | 2 +- runtime/heiko/Cargo.toml | 2 +- runtime/heiko/src/lib.rs | 62 +- runtime/parallel/Cargo.toml | 2 +- runtime/parallel/src/lib.rs | 57 +- runtime/vanilla/Cargo.toml | 2 +- runtime/vanilla/src/lib.rs | 60 +- rust-toolchain | 2 +- 29 files changed, 943 insertions(+), 1646 deletions(-) delete mode 100644 pallets/liquid-staking-v2/Cargo.toml delete mode 100644 pallets/liquid-staking-v2/src/lib.rs delete mode 100644 pallets/liquid-staking-v2/src/mock.rs delete mode 100644 pallets/liquid-staking-v2/src/tests.rs delete mode 100644 pallets/liquid-staking-v2/src/types.rs delete mode 100644 pallets/liquid-staking-v2/src/weights.rs delete mode 100644 pallets/liquid-staking/src/relaychain.rs diff --git a/.githooks/pre-commit b/.githooks/pre-commit index 8b146ca06..acb16ba72 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -4,7 +4,7 @@ set -e -files=$((git diff --cached --name-only | grep -Ei "\.rs$") || true) +files=$((git diff --cached --name-only --diff-filter=ACMR | grep -Ei "\.rs$") || true) if [ ! -z "${files}" ]; then make fmt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a36da4a83..dd39c002b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - rust: [nightly-2021-09-06] + rust: [nightly-2021-09-29] # Steps represent a sequence of tasks that will be executed as part of the job steps: diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index b94ad4898..704decf3b 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - rust: [nightly-2021-09-06] + rust: [nightly-2021-09-29] steps: - name: Checkout Repository @@ -68,7 +68,7 @@ jobs: - name: Generate code coverage run: | - cargo +nightly-2021-09-06 tarpaulin --verbose --no-fail-fast -p pallet-loans -p pallet-liquid-staking -p pallet-liquid-staking-v2 -p pallet-nominee-election -p pallet-prices -p pallet-liquidation --timeout 300 --out Xml + cargo +nightly-2021-09-29 tarpaulin --verbose --no-fail-fast -p pallet-loans -p pallet-liquid-staking -p pallet-nominee-election -p pallet-prices -p pallet-liquidation --timeout 300 --out Xml - name: Upload To Codecov.io uses: codecov/codecov-action@v1 diff --git a/.github/workflows/rustdoc.yml b/.github/workflows/rustdoc.yml index 46da6f72e..e440e86d2 100644 --- a/.github/workflows/rustdoc.yml +++ b/.github/workflows/rustdoc.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - rust: [nightly-2021-09-06] + rust: [nightly-2021-09-29] steps: - name: Checkout Repository diff --git a/Cargo.lock b/Cargo.lock index 4a8677b06..575af6ed8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2939,7 +2939,7 @@ dependencies = [ "pallet-collective", "pallet-currency-adapter", "pallet-democracy", - "pallet-liquid-staking-v2", + "pallet-liquid-staking", "pallet-liquidation", "pallet-loans", "pallet-loans-rpc-runtime-api", @@ -5550,24 +5550,6 @@ dependencies = [ "xcm-simulator", ] -[[package]] -name = "pallet-liquid-staking-v2" -version = "3.0.0" -dependencies = [ - "frame-support", - "frame-system", - "orml-traits", - "pallet-assets", - "pallet-balances", - "parallel-primitives", - "parity-scale-codec", - "serde", - "sp-core", - "sp-runtime", - "sp-std", - "xcm", -] - [[package]] name = "pallet-liquidation" version = "3.0.0" @@ -6242,7 +6224,7 @@ dependencies = [ "pallet-collective", "pallet-currency-adapter", "pallet-democracy", - "pallet-liquid-staking-v2", + "pallet-liquid-staking", "pallet-liquidation", "pallet-loans", "pallet-loans-rpc-runtime-api", @@ -11839,7 +11821,7 @@ dependencies = [ "pallet-collective", "pallet-currency-adapter", "pallet-democracy", - "pallet-liquid-staking-v2", + "pallet-liquid-staking", "pallet-liquidation", "pallet-loans", "pallet-loans-rpc-runtime-api", diff --git a/Makefile b/Makefile index d3d03bbbe..e43732c0a 100644 --- a/Makefile +++ b/Makefile @@ -56,7 +56,7 @@ bench-amm-router: .PHONY: lint lint: SKIP_WASM_BUILD= cargo fmt --all -- --check - SKIP_WASM_BUILD= cargo clippy --workspace --features runtime-benchmarks --exclude parallel -- -A clippy::unnecessary_cast -A clippy::unnecessary_mut_passed -A clippy::too_many_arguments -A clippy::type_complexity -A clippy::identity_op -D warnings + SKIP_WASM_BUILD= cargo clippy --workspace --features runtime-benchmarks --exclude parallel -- -A dead_code -A clippy::derivable_impls -A clippy::unnecessary_cast -A clippy::unnecessary_mut_passed -A clippy::too_many_arguments -A clippy::type_complexity -A clippy::identity_op -D warnings .PHONY: fix fix: @@ -81,7 +81,6 @@ shutdown: launch: shutdown docker image pull parallelfinance/polkadot:v0.9.10 docker image pull parallelfinance/parallel-dapp:latest - docker image pull parallelfinance/stake-client:latest parachain-launch generate $(LAUNCH_CONFIG) && (cp -r keystore* output || true) && cp docker-compose.override.yml output && docker-compose -f output/docker-compose.yml -f output/docker-compose.override.yml up -d --build cd launch && yarn start diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 4de805be3..413876e98 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -16,18 +16,5 @@ services: command: --relay-ws ws://relaychain-alice:9944 --para-ws ws://parachain-2085-0:9944 --tick 120000 restart: always - redis: - image: redis - volumes: - - redis:/data - restart: always - - stake-client: - image: parallelfinance/stake-client:latest - command: --relay-ws=ws://relaychain-alice:9944 --para-ws=ws://parachain-2085-0:9944 --redis-host redis --redis-port 6379 - depends_on: - - "redis" - restart: always - volumes: redis: diff --git a/node/parallel/src/chain_spec/heiko.rs b/node/parallel/src/chain_spec/heiko.rs index bd4d6fa1b..ffb13f5af 100644 --- a/node/parallel/src/chain_spec/heiko.rs +++ b/node/parallel/src/chain_spec/heiko.rs @@ -136,18 +136,21 @@ pub fn heiko_config(_id: ParaId) -> Result { // let invulnerables: Vec<(AccountId, AuraId)> = vec![ // ( // // 5DfKxDtYyHkWnXkoc8Ek9KaPZE3FBD5kDByDziiRtHsd8D1x + // // hJGnmqMhfJ5fGh2wXQur7KhxFGjgiURsvmyKDNNCSBm8wavLW // hex!["46a4161c87a0c6d58dec1e01b8c360123e1373ffafcf100efd1a9999fbacf161"].into(), // hex!["46a4161c87a0c6d58dec1e01b8c360123e1373ffafcf100efd1a9999fbacf161"] // .unchecked_into(), // ), // ( // // 5EUmwapW8qScFGh4KGug1xb5Dnm4FYQtzrjTcvjynyRAMRR3 + // // hJHcDpidcTdMN9msn84X3CLxvwJQXYmD5Ze5SzaDz6SgUozT3 // hex!["6ad41b69e5ff9ec7fa541b9e61f56bc9dd5761e8ab69cf82a3c0722ba227dc5e"].into(), // hex!["6ad41b69e5ff9ec7fa541b9e61f56bc9dd5761e8ab69cf82a3c0722ba227dc5e"] // .unchecked_into(), // ), // ( // // 5DJd3duMMEeEo9Gi5az1esvuNRB31V8Fds91VkBMrZUCFyUn + // // hJGS4vmiTg2YzheTRtNbNqGJm5vpWJhvSCeUzsPfNA2jWiUQM // hex!["36d97965e462e9ca63079c1102db04f4293e59bca83713703a9a772d0017894d"].into(), // hex!["36d97965e462e9ca63079c1102db04f4293e59bca83713703a9a772d0017894d"] // .unchecked_into(), diff --git a/pallets/liquid-staking-v2/Cargo.toml b/pallets/liquid-staking-v2/Cargo.toml deleted file mode 100644 index f55714db5..000000000 --- a/pallets/liquid-staking-v2/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -[package] -authors = ['Parallel Team'] -edition = '2018' -name = 'pallet-liquid-staking-v2' -version = '3.0.0' - -[package.metadata.docs.rs] -targets = ['x86_64-unknown-linux-gnu'] - -[dependencies] -codec = { package = 'parity-scale-codec', version = '2.0.0', features = ['max-encoded-len'], default-features = false } -frame-support = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.10', default-features = false } -frame-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.10', default-features = false } -orml-traits = { git = 'https://github.com/open-web3-stack/open-runtime-module-library.git', default-features = false } -pallet-assets = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.10', default-features = false } -sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.10', default-features = false } -sp-std = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.10', default-features = false } -xcm = { git = 'https://github.com/paritytech/polkadot.git', branch = 'release-v0.9.10', default-features = false } - -# parallel pallets -primitives = { package = 'parallel-primitives', path = '../../primitives', default-features = false } - -[dev-dependencies] -pallet-balances = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.10', default-features = false } -serde = { version = '1' } -sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.10', default-features = false } - -[features] -default = ['std'] -std = [ - 'codec/std', - 'frame-support/std', - 'frame-system/std', - 'sp-runtime/std', - 'sp-std/std', - 'orml-traits/std', - 'primitives/std', - 'xcm/std', - 'pallet-assets/std', -] -try-runtime = ['frame-support/try-runtime'] diff --git a/pallets/liquid-staking-v2/src/lib.rs b/pallets/liquid-staking-v2/src/lib.rs deleted file mode 100644 index 11e9ebd51..000000000 --- a/pallets/liquid-staking-v2/src/lib.rs +++ /dev/null @@ -1,558 +0,0 @@ -// Copyright 2021 Parallel Finance Developer. -// This file is part of Parallel Finance. - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! # Liquid staking pallet v2 -//! -//! ## Overview -//! -//! This pallet manages the NPoS operations for relay chain asset. - -#![cfg_attr(not(feature = "std"), no_std)] - -#[cfg(test)] -mod mock; -#[cfg(test)] -mod tests; - -pub mod types; -pub mod weights; - -use primitives::{ExchangeRateProvider, LiquidStakingCurrenciesProvider}; - -pub use self::pallet::*; - -#[frame_support::pallet] -mod pallet { - use frame_support::{ - dispatch::{DispatchResult, DispatchResultWithPostInfo}, - ensure, - pallet_prelude::*, - traits::{ - fungibles::{Inspect, Mutate, Transfer}, - Get, IsType, - }, - transactional, - weights::Weight, - PalletId, Twox64Concat, - }; - use frame_system::{ - ensure_signed, - pallet_prelude::{BlockNumberFor, OriginFor}, - }; - use orml_traits::XcmTransfer; - use sp_runtime::{ - traits::{AccountIdConversion, AtLeast32BitUnsigned, CheckedAdd, CheckedSub, Zero}, - ArithmeticError, FixedPointNumber, FixedPointOperand, - }; - use sp_std::vec::Vec; - use xcm::latest::prelude::*; - - use primitives::{EraIndex, Rate, Ratio}; - - use crate::{ - types::{MatchingLedger, StakingSettlementKind}, - weights::WeightInfo, - }; - - pub type AssetIdOf = - <::Assets as Inspect<::AccountId>>::AssetId; - pub type BalanceOf = - <::Assets as Inspect<::AccountId>>::Balance; - - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - pub struct Pallet(_); - - #[pallet::config] - pub trait Config: frame_system::Config { - type Event: From> + IsType<::Event>; - - /// Assets for deposit/withdraw assets to/from pallet account - type Assets: Transfer + Inspect + Mutate; - - /// Offchain bridge accout who manages staking currency in relaychain. - type BridgeOrigin: EnsureOrigin; - - /// The origin which can update liquid currency, staking currency - type UpdateOrigin: EnsureOrigin; - - /// The pallet id of liquid staking, keeps all the staking assets. - #[pallet::constant] - type PalletId: Get; - - /// XCM transfer - type XcmTransfer: XcmTransfer, AssetIdOf>; - - /// Base xcm transaction weight - #[pallet::constant] - type BaseXcmWeight: Get; - - /// Account manages the staking assets. - #[pallet::constant] - type RelayAgent: Get; - - /// Basis of period. - #[pallet::constant] - type PeriodBasis: Get>; - - type WeightInfo: WeightInfo; - } - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - #[pallet::metadata(T::AccountId = "AccountId", BalanceOf = "Balance")] - pub enum Event { - /// The assets get staked successfully - Staked(T::AccountId, BalanceOf), - /// The derivative get unstaked successfully - Unstaked(T::AccountId, BalanceOf, BalanceOf), - /// Reward/Slash has been recorded. - StakingSettlementRecorded(StakingSettlementKind, BalanceOf), - /// Request to perform bond/rebond/unbond in relay chain - /// - /// Send `(bond_amount, rebond_amount, unbond_amount)` as args. - StakingOpRequest(BalanceOf, BalanceOf, BalanceOf), - /// Period terminated. - /// - /// Emit when a period is finished which is defined by `PeriodBasis`. While current block - /// height is accurately multiple of the basis, the event would be deposited during finalization of - /// the block. - PeriodTerminated, - } - - #[pallet::error] - pub enum Error { - /// Reward/Slash has been recorded. - StakingSettlementAlreadyRecorded, - /// Exchange rate is invalid. - InvalidExchangeRate, - /// Era has been pushed before. - EraAlreadyPushed, - /// Operation wasn't submitted to relaychain or has been processed. - OperationNotReady, - LiquidCurrencyNotSet, - StakingCurrencyNotSet, - } - - /// The exchange rate between relaychain native asset and the voucher. - #[pallet::storage] - #[pallet::getter(fn exchange_rate)] - pub type ExchangeRate = StorageValue<_, Rate, ValueQuery>; - - /// Total amount of staked assets in relaycahin. - #[pallet::storage] - #[pallet::getter(fn staking_pool)] - pub type StakingPool = StorageValue<_, BalanceOf, ValueQuery>; - - /// Fraction of reward currently set aside for reserves - #[pallet::storage] - #[pallet::getter(fn reserve_factor)] - pub type ReserveFactor = StorageValue<_, Ratio, ValueQuery>; - - /// Records reward or slash of era. - #[pallet::storage] - #[pallet::getter(fn staking_settlement_records)] - pub type StakingSettlementRecords = StorageDoubleMap< - _, - Blake2_128Concat, - EraIndex, - Twox64Concat, - StakingSettlementKind, - BalanceOf, - >; - - /// Store total stake amount and unstake amount in each era, - /// And will update when stake/unstake occurred. - #[pallet::storage] - #[pallet::getter(fn matching_pool)] - pub type MatchingPool = StorageValue<_, MatchingLedger>, ValueQuery>; - - /// Manage which we should pay off to. - /// - /// Insert a new record while user can't be paid instantly in unstaking operation. - #[pallet::storage] - #[pallet::getter(fn unstake_queue)] - pub type UnstakeQueue = - StorageValue<_, Vec<(T::AccountId, BalanceOf)>, ValueQuery>; - - /// Liquid currency asset id - #[pallet::storage] - #[pallet::getter(fn liquid_currency)] - pub type LiquidCurrency = StorageValue<_, AssetIdOf, OptionQuery>; - - /// Staking currency asset id - #[pallet::storage] - #[pallet::getter(fn staking_currency)] - pub type StakingCurrency = StorageValue<_, AssetIdOf, OptionQuery>; - - #[pallet::genesis_config] - pub struct GenesisConfig { - pub exchange_rate: Rate, - pub reserve_factor: Ratio, - } - - #[cfg(feature = "std")] - impl Default for GenesisConfig { - fn default() -> Self { - Self { - exchange_rate: Rate::default(), - reserve_factor: Ratio::default(), - } - } - } - - #[pallet::genesis_build] - impl GenesisBuild for GenesisConfig { - fn build(&self) { - ExchangeRate::::put(self.exchange_rate); - ReserveFactor::::put(self.reserve_factor); - } - } - - #[pallet::hooks] - impl Hooks> for Pallet - where - BalanceOf: FixedPointOperand, - AssetIdOf: AtLeast32BitUnsigned, - { - /// Try to pay off over the `UnstakeQueue` while blockchain is on idle. - /// - /// It breaks when: - /// - Pallet's balance is insufficiant. - /// - Queue is empty. - /// - `remaining_weight` is less than one pop_queue needed. - fn on_idle(_n: BlockNumberFor, mut remaining_weight: Weight) -> Weight { - // TODO should use T::WeightInfo::on_idle instead - // on_idle shouldn't run out of all remaining_weight normally - let base_weight = T::WeightInfo::pop_queue(); - if Self::staking_currency().is_none() { - return remaining_weight; - } - loop { - // Check weight is enough - if remaining_weight < base_weight { - break; - } - - if Self::unstake_queue().is_empty() { - break; - } - - // Get the front of the queue. - let (who, amount) = &Self::unstake_queue()[0]; - - if T::Assets::transfer( - Self::staking_currency().unwrap(), - &Self::account_id(), - who, - *amount, - true, - ) - .is_err() - { - // break if we cannot afford this - break; - } - - // substract weight of this action if succeed. - remaining_weight -= base_weight; - - // remove unstake request from queue - Self::pop_unstake_task(); - } - remaining_weight - } - - fn on_finalize(n: BlockNumberFor) { - let basis = T::PeriodBasis::get(); - - // Check if current period end. - if !(n % basis).is_zero() { - return; - } - - // Check if there are staking to be settled. - if Self::matching_pool().is_empty() { - return; - } - - Self::deposit_event(Event::::PeriodTerminated); - } - } - - #[pallet::call] - impl Pallet - where - BalanceOf: FixedPointOperand, - AssetIdOf: AtLeast32BitUnsigned, - { - /// Put assets under staking, the native assets will be transferred to the account - /// owned by the pallet, user receive derivative in return, such derivative can be - /// further used as collateral for lending. - /// - /// - `amount`: the amount of staking assets - #[pallet::weight(T::WeightInfo::stake())] - #[transactional] - pub fn stake( - origin: OriginFor, - #[pallet::compact] amount: BalanceOf, - ) -> DispatchResultWithPostInfo { - let who = ensure_signed(origin)?; - - let exchange_rate = ExchangeRate::::get(); - let liquid_amount = exchange_rate - .reciprocal() - .and_then(|r| r.checked_mul_int(amount)) - .ok_or(Error::::InvalidExchangeRate)?; - - T::Assets::transfer( - Self::staking_currency().ok_or(Error::::StakingCurrencyNotSet)?, - &who, - &Self::account_id(), - amount, - true, - )?; - T::Assets::mint_into( - Self::liquid_currency().ok_or(Error::::LiquidCurrencyNotSet)?, - &who, - liquid_amount, - )?; - - StakingPool::::try_mutate(|b| -> DispatchResult { - *b = b.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; - Ok(()) - })?; - - MatchingPool::::try_mutate(|p| -> DispatchResult { - p.total_stake_amount = p - .total_stake_amount - .checked_add(&amount) - .ok_or(ArithmeticError::Overflow)?; - Ok(()) - })?; - - Self::deposit_event(Event::::Staked(who, amount)); - Ok(().into()) - } - - /// Unstake by exchange derivative for assets, the assets will not be avaliable immediately. - /// Instead, the request is recorded and pending for the nomination accounts in relay - /// chain to do the `unbond` operation. - /// - /// - `amount`: the amount of derivative - #[pallet::weight(T::WeightInfo::unstake())] - #[transactional] - pub fn unstake( - origin: OriginFor, - #[pallet::compact] liquid_amount: BalanceOf, - ) -> DispatchResultWithPostInfo { - let who = ensure_signed(origin)?; - - let exchange_rate = ExchangeRate::::get(); - let asset_amount = exchange_rate - .checked_mul_int(liquid_amount) - .ok_or(Error::::InvalidExchangeRate)?; - - if T::Assets::transfer( - Self::staking_currency().ok_or(Error::::StakingCurrencyNotSet)?, - &Self::account_id(), - &who, - asset_amount, - true, - ) - .is_err() - { - Self::push_unstake_task(&who, asset_amount); - } - - T::Assets::burn_from( - Self::liquid_currency().ok_or(Error::::LiquidCurrencyNotSet)?, - &who, - liquid_amount, - )?; - StakingPool::::try_mutate(|b| -> DispatchResult { - *b = b - .checked_sub(&asset_amount) - .ok_or(ArithmeticError::Underflow)?; - Ok(()) - })?; - - MatchingPool::::try_mutate(|p| -> DispatchResult { - p.total_unstake_amount = p - .total_unstake_amount - .checked_add(&asset_amount) - .ok_or(ArithmeticError::Overflow)?; - Ok(()) - })?; - - Self::deposit_event(Event::::Unstaked(who, liquid_amount, asset_amount)); - Ok(().into()) - } - - /// Handle staking settlement at the end of an era, such as getting reward or been slashed in relaychain. - #[pallet::weight(::WeightInfo::record_staking_settlement())] - #[transactional] - pub fn record_staking_settlement( - origin: OriginFor, - era_index: EraIndex, - #[pallet::compact] amount: BalanceOf, - kind: StakingSettlementKind, - ) -> DispatchResultWithPostInfo { - T::BridgeOrigin::ensure_origin(origin)?; - Self::ensure_settlement_not_recorded(era_index, kind)?; - Self::update_staking_pool(kind, amount)?; - - StakingSettlementRecords::::insert(era_index, kind, amount); - Self::deposit_event(Event::::StakingSettlementRecorded(kind, amount)); - Ok(().into()) - } - - /// Do settlement for matching pool. - /// - /// Calculate the imbalance of current state and send corresponding operations to - /// relay-chain. - /// - /// NOTE: currently it finished by stake-client. - #[pallet::weight(::WeightInfo::settlement())] - #[transactional] - pub fn settlement( - origin: OriginFor, - #[pallet::compact] unbonding_amount: BalanceOf, - ) -> DispatchResultWithPostInfo { - T::BridgeOrigin::ensure_origin(origin)?; - let (bond_amount, rebond_amount, unbond_amount) = - MatchingPool::::take().matching(unbonding_amount); - - if !bond_amount.is_zero() { - T::XcmTransfer::transfer( - Self::account_id(), - Self::staking_currency().ok_or(Error::::StakingCurrencyNotSet)?, - bond_amount, - T::RelayAgent::get(), - T::BaseXcmWeight::get(), - )?; - } - - Self::deposit_event(Event::::StakingOpRequest( - bond_amount, - rebond_amount, - unbond_amount, - )); - Ok(().into()) - } - - /// set liquid currency via governance - #[pallet::weight(::WeightInfo::set_liquid_currency())] - #[transactional] - pub fn set_liquid_currency(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResult { - T::UpdateOrigin::ensure_origin(origin)?; - LiquidCurrency::::put(asset_id); - Ok(()) - } - - /// set staking currency via governance - #[pallet::weight(::WeightInfo::set_staking_currency())] - #[transactional] - pub fn set_staking_currency( - origin: OriginFor, - asset_id: AssetIdOf, - ) -> DispatchResult { - T::UpdateOrigin::ensure_origin(origin)?; - StakingCurrency::::put(asset_id); - Ok(()) - } - } - - impl Pallet { - /// Ensure settlement not recorded for this `era_index`. - #[inline] - fn ensure_settlement_not_recorded( - era_index: EraIndex, - kind: StakingSettlementKind, - ) -> DispatchResult { - ensure!( - !StakingSettlementRecords::::contains_key(era_index, kind), - Error::::StakingSettlementAlreadyRecorded - ); - Ok(()) - } - } - - impl Pallet - where - BalanceOf: FixedPointOperand, - AssetIdOf: AtLeast32BitUnsigned, - { - /// Increase/Decrease staked asset in staking pool, and synchronized the exchange rate. - fn update_staking_pool( - kind: StakingSettlementKind, - amount: BalanceOf, - ) -> DispatchResult { - use StakingSettlementKind::*; - match kind { - Reward => StakingPool::::try_mutate(|p| -> DispatchResult { - *p = p.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; - Ok(()) - }), - Slash => StakingPool::::try_mutate(|p| -> DispatchResult { - *p = p.checked_sub(&amount).ok_or(ArithmeticError::Underflow)?; - Ok(()) - }), - }?; - - // Update exchange rate. - let exchange_rate = Rate::checked_from_rational( - StakingPool::::get(), - T::Assets::total_issuance( - Self::liquid_currency().ok_or(Error::::LiquidCurrencyNotSet)?, - ), - ) - .ok_or(Error::::InvalidExchangeRate)?; - ExchangeRate::::put(exchange_rate); - Ok(()) - } - - pub fn account_id() -> T::AccountId { - T::PalletId::get().into_account() - } - - /// Push an unstake task into queue. - #[inline] - fn push_unstake_task(who: &T::AccountId, amount: BalanceOf) { - UnstakeQueue::::mutate(|q| q.push((who.clone(), amount))) - } - - /// Pop an unstake task from queue. - #[inline] - fn pop_unstake_task() { - UnstakeQueue::::mutate(|v| v.remove(0)); - } - } -} - -impl ExchangeRateProvider for Pallet { - fn get_exchange_rate() -> primitives::Rate { - ExchangeRate::::get() - } -} - -impl LiquidStakingCurrenciesProvider> for Pallet { - fn get_staking_currency() -> Option> { - Self::staking_currency() - } - - fn get_liquid_currency() -> Option> { - Self::liquid_currency() - } -} diff --git a/pallets/liquid-staking-v2/src/mock.rs b/pallets/liquid-staking-v2/src/mock.rs deleted file mode 100644 index 7d5b04b7c..000000000 --- a/pallets/liquid-staking-v2/src/mock.rs +++ /dev/null @@ -1,204 +0,0 @@ -use frame_support::{ - construct_runtime, - dispatch::DispatchResult, - dispatch::Weight, - parameter_types, sp_io, - traits::{GenesisBuild, SortedMembers}, - PalletId, -}; -use frame_system::{EnsureRoot, EnsureSignedBy}; -use orml_traits::XcmTransfer; - -use sp_core::H256; -use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup, One}, -}; - -use xcm::latest::prelude::*; - -use primitives::{tokens::*, Balance, Rate, Ratio}; - -type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; -type Block = frame_system::mocking::MockBlock; -type BlockNumber = u64; -type AccountId = u64; -type CurrencyId = u32; - -parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const SS58Prefix: u8 = 42; -} - -impl frame_system::Config for Test { - type BaseCallFilter = (); - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type Origin = Origin; - type Call = Call; - type Index = u64; - type BlockNumber = BlockNumber; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Header = Header; - type Event = Event; - type BlockHashCount = BlockHashCount; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = SS58Prefix; - type OnSetCode = (); -} - -parameter_types! { - pub const ExistentialDeposit: Balance = 1; - pub const MaxLocks: u32 = 50; -} - -impl pallet_balances::Config for Test { - type MaxLocks = MaxLocks; - type Balance = Balance; - type Event = Event; - type DustRemoval = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = (); -} - -parameter_types! { - pub const AssetDeposit: Balance = 0; - pub const ApprovalDeposit: Balance = 0; - pub const AssetsStringLimit: u32 = 50; - pub const MetadataDepositBase: Balance = 0; - pub const MetadataDepositPerByte: Balance = 0; -} - -impl pallet_assets::Config for Test { - type Event = Event; - type Balance = Balance; - type AssetId = CurrencyId; - type Currency = Balances; - type ForceOrigin = EnsureRoot; - type AssetDeposit = AssetDeposit; - type MetadataDepositBase = MetadataDepositBase; - type MetadataDepositPerByte = MetadataDepositPerByte; - type ApprovalDeposit = ApprovalDeposit; - type StringLimit = AssetsStringLimit; - type Freezer = (); - type WeightInfo = (); - type Extra = (); -} - -pub struct AliceOrigin; -impl SortedMembers for AliceOrigin { - fn sorted_members() -> Vec { - vec![ALICE.into()] - } -} - -pub struct BobOrigin; -impl SortedMembers for BobOrigin { - fn sorted_members() -> Vec { - vec![BOB.into()] - } -} - -pub type BridgeOrigin = EnsureSignedBy; -pub type UpdateOrigin = EnsureSignedBy; - -parameter_types! { - pub const StakingPalletId: PalletId = PalletId(*b"par/lqsk"); - pub const BaseXcmWeight: Weight = 0; - pub Agent: MultiLocation = MultiLocation::new(1, Junctions::X1(Junction::AccountId32 { - network: xcm::v0::NetworkId::Any, - id: [0; 32] - })); - pub const PeriodBasis: BlockNumber = 5u64; -} - -impl crate::Config for Test { - type Event = Event; - type PalletId = StakingPalletId; - type BridgeOrigin = BridgeOrigin; - type BaseXcmWeight = BaseXcmWeight; - type XcmTransfer = MockXcmTransfer; - type RelayAgent = Agent; - type PeriodBasis = PeriodBasis; - type WeightInfo = (); - type Assets = Assets; - type UpdateOrigin = UpdateOrigin; -} - -construct_runtime!( - pub enum Test where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Assets: pallet_assets::{Pallet, Call, Storage, Event}, - Balances: pallet_balances::{Pallet, Call, Storage, Event}, - LiquidStaking: crate::{Pallet, Storage, Call, Event}, - } -); - -pub const ALICE: AccountId = 1u64; -pub const BOB: AccountId = 2u64; - -pub struct MockXcmTransfer; -impl XcmTransfer for MockXcmTransfer { - fn transfer( - _who: AccountId, - _currency_id: CurrencyId, - _amount: Balance, - _to: MultiLocation, - _dest_weight: Weight, - ) -> DispatchResult { - Ok(().into()) - } - - fn transfer_multi_asset( - _who: AccountId, - _asset: MultiAsset, - _dest: MultiLocation, - _dest_weight: Weight, - ) -> DispatchResult { - Ok(().into()) - } -} - -pub(crate) fn new_test_ext() -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap(); - - GenesisBuild::::assimilate_storage( - &crate::GenesisConfig { - exchange_rate: Rate::one(), - reserve_factor: Ratio::from_perthousand(5), - }, - &mut t, - ) - .unwrap(); - - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| { - Assets::force_create(Origin::root(), DOT, ALICE, true, 1).unwrap(); - Assets::force_create(Origin::root(), XDOT, ALICE, true, 1).unwrap(); - Assets::mint(Origin::signed(ALICE), DOT, ALICE, 100).unwrap(); - Assets::mint(Origin::signed(ALICE), XDOT, ALICE, 100).unwrap(); - - LiquidStaking::set_liquid_currency(Origin::signed(BOB), XDOT).unwrap(); - LiquidStaking::set_staking_currency(Origin::signed(BOB), DOT).unwrap(); - }); - - ext -} diff --git a/pallets/liquid-staking-v2/src/tests.rs b/pallets/liquid-staking-v2/src/tests.rs deleted file mode 100644 index 3ed1fbd8d..000000000 --- a/pallets/liquid-staking-v2/src/tests.rs +++ /dev/null @@ -1,139 +0,0 @@ -use crate::{ - mock::*, - types::{MatchingLedger, StakingSettlementKind}, - *, -}; -use frame_support::{assert_err, assert_ok, traits::Hooks}; - -use primitives::{tokens::*, Balance, Rate}; -use sp_runtime::traits::One; - -#[test] -fn stake_should_work() { - new_test_ext().execute_with(|| { - assert_ok!(LiquidStaking::stake(Origin::signed(ALICE), 10)); - // Check storage is correct - assert_eq!(ExchangeRate::::get(), Rate::one()); - assert_eq!(StakingPool::::get(), 10); - assert_eq!( - MatchingPool::::get(), - MatchingLedger { - total_stake_amount: 10, - total_unstake_amount: 0, - } - ); - - // Check balance is correct - assert_eq!(::Assets::balance(DOT, &ALICE), 90); - assert_eq!(::Assets::balance(XDOT, &ALICE), 110); - assert_eq!( - ::Assets::balance(DOT, &LiquidStaking::account_id()), - 10 - ); - }) -} - -#[test] -fn unstake_should_work() { - new_test_ext().execute_with(|| { - assert_ok!(LiquidStaking::stake(Origin::signed(ALICE), 10)); - assert_ok!(LiquidStaking::unstake(Origin::signed(ALICE), 6)); - - // Check storage is correct - assert_eq!(ExchangeRate::::get(), Rate::one()); - assert_eq!(StakingPool::::get(), 4); - assert_eq!( - MatchingPool::::get(), - MatchingLedger { - total_stake_amount: 10, - total_unstake_amount: 6, - } - ); - - // Check balance is correct - assert_eq!(::Assets::balance(DOT, &ALICE), 96); - assert_eq!(::Assets::balance(XDOT, &ALICE), 104); - assert_eq!( - ::Assets::balance(DOT, &LiquidStaking::account_id()), - 4 - ); - }) -} - -#[test] -fn test_record_staking_settlement_ok() { - new_test_ext().execute_with(|| { - assert_ok!(LiquidStaking::record_staking_settlement( - Origin::signed(ALICE), - 1, - 100, - StakingSettlementKind::Reward - )); - - assert_eq!(LiquidStaking::exchange_rate(), Rate::from(1)); - }) -} - -#[test] -fn test_duplicated_record_staking_settlement() { - new_test_ext().execute_with(|| { - LiquidStaking::record_staking_settlement( - Origin::signed(ALICE), - 1, - 100, - StakingSettlementKind::Reward, - ) - .unwrap(); - - assert_err!( - LiquidStaking::record_staking_settlement( - Origin::signed(ALICE), - 1, - 100, - StakingSettlementKind::Reward - ), - Error::::StakingSettlementAlreadyRecorded - ) - }) -} - -enum StakeOp { - Stake(Balance), - Unstake(Balance), -} - -impl StakeOp { - fn execute(self) { - match self { - Self::Stake(amount) => LiquidStaking::stake(Origin::signed(ALICE), amount).unwrap(), - Self::Unstake(amount) => LiquidStaking::unstake(Origin::signed(ALICE), amount).unwrap(), - }; - } -} - -#[test] -fn test_settlement_should_work() { - use StakeOp::*; - new_test_ext().execute_with(|| { - let test_case: Vec<(Vec, Balance, (Balance, Balance, Balance), Balance)> = vec![ - (vec![Stake(30), Unstake(5)], 0, (25, 0, 0), 0), - // Calculate right here. - (vec![Unstake(10), Unstake(5), Stake(10)], 0, (0, 0, 5), 10), - (vec![], 0, (0, 0, 0), 0), - ]; - - for (stake_ops, unbonding_amount, matching_result, _pallet_balance) in test_case.into_iter() - { - stake_ops.into_iter().for_each(StakeOp::execute); - assert_eq!( - LiquidStaking::matching_pool().matching(unbonding_amount), - matching_result - ); - assert_ok!(LiquidStaking::settlement( - Origin::signed(ALICE), - unbonding_amount - )); - Pallet::::on_idle(0, 10000); - } - }) -} diff --git a/pallets/liquid-staking-v2/src/types.rs b/pallets/liquid-staking-v2/src/types.rs deleted file mode 100644 index 415740b0b..000000000 --- a/pallets/liquid-staking-v2/src/types.rs +++ /dev/null @@ -1,58 +0,0 @@ -use codec::{Decode, Encode}; -use sp_runtime::{ - traits::{AtLeast32BitUnsigned, Zero}, - RuntimeDebug, -}; -use sp_std::cmp::Ordering; - -/// Category of staking settlement at the end of era. -#[derive(Encode, Decode, Eq, PartialEq, Copy, Clone, RuntimeDebug)] -pub enum StakingSettlementKind { - Reward, - Slash, -} - -/// The matching pool's total stake & unstake amount in one era -#[derive(Copy, Clone, Eq, PartialEq, Default, Encode, Decode, RuntimeDebug)] -pub struct MatchingLedger { - /// The total stake amount in one era - pub total_stake_amount: Balance, - /// The total unstake amount in one era - /// **NOTE** will be calculated by: exchangeRate * xToken amount - pub total_unstake_amount: Balance, -} - -impl MatchingLedger -where - Balance: AtLeast32BitUnsigned + Copy + Clone, -{ - /// Matching requests in current period. - /// - /// `unbonding_amount` is the total amount of the unbonding asset in relaychain. - /// - /// the returned tri-tuple is formed as `(bond_amount, rebond_amount, unbond_amount)`. - pub fn matching(&self, unbonding_amount: Balance) -> (Balance, Balance, Balance) { - use Ordering::*; - - match self.total_stake_amount.cmp(&self.total_unstake_amount) { - Greater => { - let amount = self.total_stake_amount - self.total_unstake_amount; - if amount < unbonding_amount { - (Zero::zero(), amount, Zero::zero()) - } else { - (amount - unbonding_amount, unbonding_amount, Zero::zero()) - } - } - Less | Equal => ( - Zero::zero(), - Zero::zero(), - self.total_unstake_amount - self.total_stake_amount, - ), - } - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.total_stake_amount.is_zero() && self.total_unstake_amount.is_zero() - } -} diff --git a/pallets/liquid-staking-v2/src/weights.rs b/pallets/liquid-staking-v2/src/weights.rs deleted file mode 100644 index b9d5f6a6e..000000000 --- a/pallets/liquid-staking-v2/src/weights.rs +++ /dev/null @@ -1,39 +0,0 @@ -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(clippy::all)] - -use frame_support::dispatch::Weight; - -pub trait WeightInfo { - fn stake() -> Weight; - fn unstake() -> Weight; - fn record_staking_settlement() -> Weight; - fn settlement() -> Weight; - fn pop_queue() -> Weight; - fn set_liquid_currency() -> Weight; - fn set_staking_currency() -> Weight; -} - -impl WeightInfo for () { - fn stake() -> Weight { - 10000u64.into() - } - fn unstake() -> Weight { - 10000u64.into() - } - fn record_staking_settlement() -> Weight { - 10000u64.into() - } - fn settlement() -> Weight { - 10000u64.into() - } - fn pop_queue() -> Weight { - 10000u64.into() - } - fn set_liquid_currency() -> Weight { - 10000u64.into() - } - fn set_staking_currency() -> Weight { - 10000u64.into() - } -} diff --git a/pallets/liquid-staking/Cargo.toml b/pallets/liquid-staking/Cargo.toml index 1cf489e49..7ca7afa0a 100644 --- a/pallets/liquid-staking/Cargo.toml +++ b/pallets/liquid-staking/Cargo.toml @@ -17,6 +17,8 @@ sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = sp-std = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.10', default-features = false } xcm = { git = 'https://github.com/paritytech/polkadot.git', branch = 'release-v0.9.10', default-features = false } +cumulus-primitives-core = { git = 'https://github.com/paritytech/cumulus.git', branch = 'polkadot-v0.9.10', default-features = false } + # parallel pallets primitives = { package = 'parallel-primitives', path = '../../primitives', default-features = false } @@ -51,9 +53,7 @@ orml-xcm-support = { git = 'https://github.com/open-web3-stack/open-runtime-modu orml-xtokens = { git = 'https://github.com/open-web3-stack/open-runtime-module-library.git' } [features] -default = ['std', 'westend'] -kusama = [] -polkadot = [] +default = ['std'] std = [ 'codec/std', 'frame-support/std', @@ -64,6 +64,6 @@ std = [ 'primitives/std', 'xcm/std', 'pallet-assets/std', + 'cumulus-primitives-core/std', ] try-runtime = ['frame-support/try-runtime'] -westend = [] diff --git a/pallets/liquid-staking/src/lib.rs b/pallets/liquid-staking/src/lib.rs index 4056be986..191cba164 100644 --- a/pallets/liquid-staking/src/lib.rs +++ b/pallets/liquid-staking/src/lib.rs @@ -22,18 +22,39 @@ #[cfg(test)] mod mock; -pub mod relaychain; #[cfg(test)] mod tests; + pub mod types; pub mod weights; -use primitives::{ExchangeRateProvider, LiquidStakingCurrenciesProvider}; +use primitives::{ExchangeRateProvider, LiquidStakingCurrenciesProvider, Rate}; + +pub use pallet::*; + +macro_rules! switch_relay { + ({ $( $code:tt )* }) => { + if T::RelayNetwork::get() == NetworkId::Polkadot { + use crate::types::PolkadotCall as RelaychainCall; + + $( $code )* + } else if T::RelayNetwork::get() == NetworkId::Kusama { + use crate::types::KusamaCall as RelaychainCall; + + $( $code )* + } else if T::RelayNetwork::get() == NetworkId::Named("westend".into()) { + use crate::types::WestendCall as RelaychainCall; -pub use self::pallet::*; + $( $code )* + } else { + unreachable!() + } + } +} #[frame_support::pallet] -mod pallet { +pub mod pallet { + use cumulus_primitives_core::ParaId; use frame_support::{ dispatch::{DispatchResult, DispatchResultWithPostInfo}, ensure, @@ -52,23 +73,26 @@ mod pallet { }; use orml_traits::XcmTransfer; use sp_runtime::{ - traits::{AccountIdConversion, AtLeast32BitUnsigned, CheckedAdd, CheckedSub, Zero}, + traits::{ + AccountIdConversion, AtLeast32BitUnsigned, BlockNumberProvider, CheckedAdd, CheckedSub, + StaticLookup, Zero, + }, ArithmeticError, FixedPointNumber, FixedPointOperand, }; - use sp_std::vec::Vec; - use xcm::latest::prelude::*; + use sp_std::vec; + use sp_std::{boxed::Box, vec::Vec}; + use xcm::{latest::prelude::*, DoubleEncoded}; use primitives::{DerivativeProvider, EraIndex, Rate, Ratio}; - use crate::{ - types::{MatchingLedger, RewardDestination, StakingSettlementKind}, - weights::WeightInfo, - }; + use crate::{types::*, weights::WeightInfo}; pub type AssetIdOf = <::Assets as Inspect<::AccountId>>::AssetId; pub type BalanceOf = <::Assets as Inspect<::AccountId>>::Balance; + pub type RelaychainBlockNumberOf = + <::RelaychainBlockNumberProvider as BlockNumberProvider>::BlockNumber; #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] @@ -81,29 +105,32 @@ mod pallet { /// Assets for deposit/withdraw assets to/from pallet account type Assets: Transfer + Inspect + Mutate; - /// Offchain bridge accout who manages staking currency in relaychain. - type BridgeOrigin: EnsureOrigin; + /// The origin which can do operation on relaychain using parachain's sovereign account + type RelayOrigin: EnsureOrigin; /// The origin which can update liquid currency, staking currency type UpdateOrigin: EnsureOrigin; - /// The pallet id of liquid staking, keeps all the staking assets. + /// The pallet id of liquid staking, keeps all the staking assets #[pallet::constant] type PalletId: Get; /// XCM transfer type XcmTransfer: XcmTransfer, AssetIdOf>; - /// XCM transact + /// XCM message sender type XcmSender: SendXcm; - /// Base xcm transaction weight + /// Basic xcm transaction weight per message #[pallet::constant] type BaseXcmWeight: Get; - /// Parachain account on relaychain + /// Relaychain block number provider + type RelaychainBlockNumberProvider: BlockNumberProvider; + + /// Returns the parachain ID we are running with. #[pallet::constant] - type RelayAgent: Get; + type SelfParaId: Get; /// Account derivative index #[pallet::constant] @@ -116,10 +143,23 @@ mod pallet { #[pallet::constant] type UnstakeQueueCapacity: Get; - /// Basis of period. + /// Basis of period #[pallet::constant] type PeriodBasis: Get>; + /// Max rewards per era + #[pallet::constant] + type MaxRewardsPerEra: Get>; + + /// Max slashes per era + #[pallet::constant] + type MaxSlashesPerEra: Get>; + + /// Relay network + #[pallet::constant] + type RelayNetwork: Get; + + /// Weight information type WeightInfo: WeightInfo; } @@ -187,8 +227,12 @@ mod pallet { LiquidCurrencyNotSet, /// Staking currency hasn't been set StakingCurrencyNotSet, - /// UnstakeQueue is already full + /// Exceeded unstake queue's capacity ExceededUnstakeQueueCapacity, + /// Exceeded max rewards per era + ExceededMaxRewardsPerEra, + /// Exceeded max slashes per era + ExceededMaxSlashesPerEra, } /// The exchange rate between relaychain native asset and the voucher. @@ -196,12 +240,20 @@ mod pallet { #[pallet::getter(fn exchange_rate)] pub type ExchangeRate = StorageValue<_, Rate, ValueQuery>; - /// Total amount of staked assets in relaycahin. + /// Total amount of staked assets on relaycahin. #[pallet::storage] #[pallet::getter(fn staking_pool)] pub type StakingPool = StorageValue<_, BalanceOf, ValueQuery>; - /// Fraction of reward currently set aside for reserves + /// Unbonding amount and withdrawable block number on relaychain + /// + /// [amount, withdrawable_block_number] + #[pallet::storage] + #[pallet::getter(fn unbonding)] + pub type Unbonding = + StorageValue<_, (BalanceOf, RelaychainBlockNumberOf), ValueQuery>; + + /// Fraction of reward currently set aside for reserves. #[pallet::storage] #[pallet::getter(fn reserve_factor)] pub type ReserveFactor = StorageValue<_, Ratio, ValueQuery>; @@ -272,6 +324,10 @@ mod pallet { #[pallet::hooks] impl Hooks> for Pallet where + [u8; 32]: From<::AccountId>, + u128: From< + <::Assets as Inspect<::AccountId>>::Balance, + >, BalanceOf: FixedPointOperand, AssetIdOf: AtLeast32BitUnsigned, { @@ -301,15 +357,14 @@ mod pallet { // Get the front of the queue. let (who, amount) = &Self::unstake_queue()[0]; - if T::Assets::transfer( + let res = T::Assets::transfer( Self::staking_currency().unwrap(), &Self::account_id(), who, *amount, - true, - ) - .is_err() - { + false, + ); + if res.is_err() { // break if we cannot afford this break; } @@ -326,12 +381,22 @@ mod pallet { fn on_finalize(n: BlockNumberFor) { let basis = T::PeriodBasis::get(); - // Check if current period end. + let (unbonding_amount, withdrawable_block_number) = Self::unbonding(); + let relaychain_block_number = T::RelaychainBlockNumberProvider::current_block_number(); + + if !unbonding_amount.is_zero() + && relaychain_block_number >= withdrawable_block_number + && Self::withdraw_unbonded_internal(0, unbonding_amount.into()).is_ok() + { + Unbonding::::kill(); + } + + // check if current period end. if !(n % basis).is_zero() { return; } - // Check if there are staking to be settled. + // check if there are staking to be settled. if Self::matching_pool().is_empty() { return; } @@ -344,6 +409,9 @@ mod pallet { impl Pallet where [u8; 32]: From<::AccountId>, + u128: From< + <::Assets as Inspect<::AccountId>>::Balance, + >, BalanceOf: FixedPointOperand, AssetIdOf: AtLeast32BitUnsigned, { @@ -352,7 +420,7 @@ mod pallet { /// further used as collateral for lending. /// /// - `amount`: the amount of staking assets - #[pallet::weight(T::WeightInfo::stake())] + #[pallet::weight(::WeightInfo::stake())] #[transactional] pub fn stake( origin: OriginFor, @@ -366,18 +434,13 @@ mod pallet { .and_then(|r| r.checked_mul_int(amount)) .ok_or(Error::::InvalidExchangeRate)?; - T::Assets::transfer( - Self::staking_currency().ok_or(Error::::StakingCurrencyNotSet)?, - &who, - &Self::account_id(), - amount, - true, - )?; - T::Assets::mint_into( - Self::liquid_currency().ok_or(Error::::LiquidCurrencyNotSet)?, - &who, - liquid_amount, - )?; + let staking_currency = + Self::staking_currency().ok_or(Error::::StakingCurrencyNotSet)?; + let liquid_currency = + Self::liquid_currency().ok_or(Error::::LiquidCurrencyNotSet)?; + + T::Assets::transfer(staking_currency, &who, &Self::account_id(), amount, false)?; + T::Assets::mint_into(liquid_currency, &who, liquid_amount)?; StakingPool::::try_mutate(|b| -> DispatchResult { *b = b.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; @@ -401,7 +464,7 @@ mod pallet { /// chain to do the `unbond` operation. /// /// - `amount`: the amount of derivative - #[pallet::weight(T::WeightInfo::unstake())] + #[pallet::weight(::WeightInfo::unstake())] #[transactional] pub fn unstake( origin: OriginFor, @@ -414,23 +477,23 @@ mod pallet { .checked_mul_int(liquid_amount) .ok_or(Error::::InvalidExchangeRate)?; - if T::Assets::transfer( - Self::staking_currency().unwrap(), + let staking_currency = + Self::staking_currency().ok_or(Error::::StakingCurrencyNotSet)?; + let liquid_currency = + Self::liquid_currency().ok_or(Error::::LiquidCurrencyNotSet)?; + + let res = T::Assets::transfer( + staking_currency, &Self::account_id(), &who, asset_amount, - true, - ) - .is_err() - { + false, + ); + if res.is_err() { Self::push_unstake_task(&who, asset_amount)?; } - T::Assets::burn_from( - Self::liquid_currency().ok_or(Error::::LiquidCurrencyNotSet)?, - &who, - liquid_amount, - )?; + T::Assets::burn_from(liquid_currency, &who, liquid_amount)?; StakingPool::::try_mutate(|b| -> DispatchResult { *b = b .checked_sub(&asset_amount) @@ -450,7 +513,8 @@ mod pallet { Ok(().into()) } - /// Handle staking settlement at the end of an era, such as getting reward or been slashed in relaychain. + /// Handle staking settlement at the end of an era + /// such as getting reward or been slashed in relaychain. #[pallet::weight(::WeightInfo::record_staking_settlement())] #[transactional] pub fn record_staking_settlement( @@ -459,8 +523,12 @@ mod pallet { #[pallet::compact] amount: BalanceOf, kind: StakingSettlementKind, ) -> DispatchResultWithPostInfo { - T::BridgeOrigin::ensure_origin(origin)?; - Self::ensure_settlement_not_recorded(era_index, kind)?; + T::RelayOrigin::ensure_origin(origin)?; + ensure!( + !StakingSettlementRecords::::contains_key(era_index, kind), + Error::::StakingSettlementAlreadyRecorded + ); + Self::update_staking_pool(kind, amount)?; StakingSettlementRecords::::insert(era_index, kind, amount); @@ -472,32 +540,64 @@ mod pallet { /// /// Calculate the imbalance of current state and send corresponding operations to /// relay-chain. - /// - /// NOTE: currently it finished by stake-client. #[pallet::weight(::WeightInfo::settlement())] #[transactional] pub fn settlement( origin: OriginFor, + #[pallet::compact] bonding_amount: BalanceOf, #[pallet::compact] unbonding_amount: BalanceOf, + withdrawable_block_number: RelaychainBlockNumberOf, ) -> DispatchResultWithPostInfo { - T::BridgeOrigin::ensure_origin(origin)?; + T::RelayOrigin::ensure_origin(origin)?; + let (bond_amount, rebond_amount, unbond_amount) = MatchingPool::::take().matching(unbonding_amount); if !bond_amount.is_zero() { + let beneficiary = MultiLocation::new( + 1, + X1(AccountId32 { + network: NetworkId::Any, + id: Self::para_account_id().into(), + }), + ); + let staking_currency = + Self::staking_currency().ok_or(Error::::StakingCurrencyNotSet)?; + let base_weight = T::BaseXcmWeight::get(); + T::XcmTransfer::transfer( Self::account_id(), - Self::staking_currency().ok_or(Error::::StakingCurrencyNotSet)?, + staking_currency, bond_amount, - MultiLocation::new( - 1, - Junctions::X1(Junction::AccountId32 { - network: NetworkId::Any, - id: T::RelayAgent::get().into(), - }), - ), - T::BaseXcmWeight::get(), + beneficiary, + base_weight, )?; + + if !bonding_amount.is_zero() { + Self::bond_internal(bond_amount, RewardDestination::Staked)?; + } else { + Self::bond_extra_internal(bond_amount)?; + } + } + + let (unbonding_amount, old_withdrawable_block_number) = Self::unbonding(); + if !unbond_amount.is_zero() { + let new_unbonding_amount: BalanceOf = unbonding_amount + .checked_add(&unbond_amount) + .ok_or(ArithmeticError::Overflow)?; + Self::unbond_internal(unbond_amount)?; + Unbonding::::put(( + new_unbonding_amount, + withdrawable_block_number.max(old_withdrawable_block_number), + )); + } + + if !rebond_amount.is_zero() { + let new_unbonding_amount: BalanceOf = unbonding_amount + .checked_sub(&rebond_amount) + .ok_or(ArithmeticError::Underflow)?; + Self::rebond_internal(rebond_amount)?; + Unbonding::::put((new_unbonding_amount, old_withdrawable_block_number)); } Self::deposit_event(Event::::StakingOpRequest( @@ -505,9 +605,138 @@ mod pallet { rebond_amount, unbond_amount, )); + Ok(().into()) } + /// Bond on relaychain via xcm.transact + #[pallet::weight(::WeightInfo::bond())] + #[transactional] + pub fn bond( + origin: OriginFor, + value: BalanceOf, + payee: RewardDestination, + ) -> DispatchResult { + T::RelayOrigin::ensure_origin(origin)?; + Self::bond_internal(value, payee)?; + Ok(()) + } + + /// Bond_extra on relaychain via xcm.transact + #[pallet::weight(::WeightInfo::bond_extra())] + #[transactional] + pub fn bond_extra(origin: OriginFor, value: BalanceOf) -> DispatchResult { + T::RelayOrigin::ensure_origin(origin)?; + Self::bond_extra_internal(value)?; + Ok(()) + } + + /// unbond on relaychain via xcm.transact + #[pallet::weight(::WeightInfo::unbond())] + #[transactional] + pub fn unbond(origin: OriginFor, value: BalanceOf) -> DispatchResult { + T::RelayOrigin::ensure_origin(origin)?; + Self::unbond_internal(value)?; + Ok(()) + } + + /// rebond on relaychain via xcm.transact + #[pallet::weight(::WeightInfo::rebond())] + #[transactional] + pub fn rebond(origin: OriginFor, value: BalanceOf) -> DispatchResult { + T::RelayOrigin::ensure_origin(origin)?; + Self::rebond_internal(value)?; + Ok(()) + } + + /// withdraw unbonded on relaychain via xcm.transact + #[pallet::weight(::WeightInfo::withdraw_unbonded())] + #[transactional] + pub fn withdraw_unbonded( + origin: OriginFor, + num_slashing_spans: u32, + amount: BalanceOf, + ) -> DispatchResult { + T::RelayOrigin::ensure_origin(origin)?; + Self::withdraw_unbonded_internal(num_slashing_spans, amount.into())?; + Ok(()) + } + + /// Nominate on relaychain via xcm.transact + #[pallet::weight(::WeightInfo::nominate())] + #[transactional] + pub fn nominate(origin: OriginFor, targets: Vec) -> DispatchResult { + T::RelayOrigin::ensure_origin(origin)?; + + let targets_source = targets + .clone() + .into_iter() + .map(T::Lookup::unlookup) + .collect(); + + switch_relay!({ + let call = RelaychainCall::Utility(Box::new(UtilityCall::AsDerivative( + UtilityAsDerivativeCall { + index: T::DerivativeIndex::get(), + call: RelaychainCall::Staking::(StakingCall::Nominate( + StakingNominateCall { + targets: targets_source, + }, + )), + }, + ))); + + let msg = Self::ump_transact(call.encode().into()); + + match T::XcmSender::send_xcm(MultiLocation::parent(), msg) { + Ok(()) => { + Self::deposit_event(Event::::NominateCallSent(targets)); + } + Err(_e) => { + return Err(Error::::NominateCallFailed.into()); + } + } + }); + + Ok(()) + } + + /// Payout_stakers on relaychain via xcm.transact + #[pallet::weight(::WeightInfo::payout_stakers())] + #[transactional] + pub fn payout_stakers( + origin: OriginFor, + validator_stash: T::AccountId, + era: u32, + ) -> DispatchResult { + T::RelayOrigin::ensure_origin(origin)?; + + switch_relay!({ + let call = RelaychainCall::Staking::(StakingCall::PayoutStakers( + StakingPayoutStakersCall { + validator_stash: validator_stash.clone(), + era, + }, + )); + + let msg = Self::ump_transact(call.encode().into()); + + match T::XcmSender::send_xcm(MultiLocation::parent(), msg) { + Ok(()) => { + Self::deposit_event(Event::::PayoutStakersCallSent( + validator_stash, + era, + )); + } + Err(_e) => { + return Err(Error::::PayoutStakersCallFailed.into()); + } + } + }); + + Ok(()) + } + /// set liquid currency via governance #[pallet::weight(::WeightInfo::set_liquid_currency())] #[transactional] @@ -532,55 +761,290 @@ mod pallet { impl Pallet where + [u8; 32]: From<::AccountId>, + u128: From< + <::Assets as Inspect<::AccountId>>::Balance, + >, BalanceOf: FixedPointOperand, AssetIdOf: AtLeast32BitUnsigned, { - /// Ensure settlement not recorded for this `era_index`. - #[inline] - fn ensure_settlement_not_recorded( - era_index: EraIndex, - kind: StakingSettlementKind, - ) -> DispatchResult { - ensure!( - !StakingSettlementRecords::::contains_key(era_index, kind), - Error::::StakingSettlementAlreadyRecorded - ); - Ok(()) + /// Staking pool account + pub fn account_id() -> T::AccountId { + T::PalletId::get().into_account() } - /// Increase/Decrease staked asset in staking pool, and synchronized the exchange rate. + /// Parachain sovereign account + pub fn para_account_id() -> T::AccountId { + T::SelfParaId::get().into_account() + } + + /// Derivative parachain account + pub fn derivative_para_account_id() -> T::AccountId { + T::DerivativeProvider::derivative_account_id( + Self::para_account_id(), + T::DerivativeIndex::get(), + ) + } + + /// Increase / decrease staked asset in staking pool, and synchronized the exchange rate. fn update_staking_pool( kind: StakingSettlementKind, amount: BalanceOf, ) -> DispatchResult { use StakingSettlementKind::*; match kind { - Reward => StakingPool::::try_mutate(|p| -> DispatchResult { - *p = p.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; - Ok(()) - }), - Slash => StakingPool::::try_mutate(|p| -> DispatchResult { - *p = p.checked_sub(&amount).ok_or(ArithmeticError::Underflow)?; - Ok(()) - }), + Reward => { + ensure!( + amount <= T::MaxRewardsPerEra::get(), + Error::::ExceededMaxRewardsPerEra + ); + StakingPool::::try_mutate(|p| -> DispatchResult { + *p = p.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; + Ok(()) + }) + } + Slash => { + ensure!( + amount <= T::MaxSlashesPerEra::get(), + Error::::ExceededMaxSlashesPerEra + ); + StakingPool::::try_mutate(|p| -> DispatchResult { + *p = p.checked_sub(&amount).ok_or(ArithmeticError::Underflow)?; + Ok(()) + }) + } }?; + let liquid_currency = + Self::liquid_currency().ok_or(Error::::LiquidCurrencyNotSet)?; + // Update exchange rate. let exchange_rate = Rate::checked_from_rational( StakingPool::::get(), - T::Assets::total_issuance( - Self::liquid_currency().ok_or(Error::::LiquidCurrencyNotSet)?, - ), + T::Assets::total_issuance(liquid_currency), ) .ok_or(Error::::InvalidExchangeRate)?; ExchangeRate::::put(exchange_rate); + + Ok(()) + } + + fn bond_internal( + value: BalanceOf, + payee: RewardDestination, + ) -> DispatchResult { + let stash = Self::derivative_para_account_id(); + let controller = stash.clone(); + + switch_relay!({ + let call = + RelaychainCall::Utility(Box::new(UtilityCall::BatchAll(UtilityBatchAllCall { + calls: vec![ + RelaychainCall::Balances(BalancesCall::TransferKeepAlive( + BalancesTransferKeepAliveCall { + dest: T::Lookup::unlookup(stash), + value, + }, + )), + RelaychainCall::Utility(Box::new(UtilityCall::AsDerivative( + UtilityAsDerivativeCall { + index: T::DerivativeIndex::get(), + call: RelaychainCall::Staking::(StakingCall::Bond( + StakingBondCall { + controller: T::Lookup::unlookup(controller.clone()), + value, + payee: payee.clone(), + }, + )), + }, + ))), + ], + }))); + + let msg = Self::ump_transact(call.encode().into()); + + match T::XcmSender::send_xcm(MultiLocation::parent(), msg) { + Ok(()) => { + Self::deposit_event(Event::::BondCallSent(controller, value, payee)); + } + Err(_e) => { + return Err(Error::::BondCallFailed.into()); + } + } + }); + Ok(()) } - /// Push an unstake task into queue. + fn bond_extra_internal(value: BalanceOf) -> DispatchResult { + let stash = T::Lookup::unlookup(Self::derivative_para_account_id()); + + switch_relay!({ + let call = + RelaychainCall::Utility(Box::new(UtilityCall::BatchAll(UtilityBatchAllCall { + calls: vec![ + RelaychainCall::Balances(BalancesCall::TransferKeepAlive( + BalancesTransferKeepAliveCall { dest: stash, value }, + )), + RelaychainCall::Utility(Box::new(UtilityCall::AsDerivative( + UtilityAsDerivativeCall { + index: T::DerivativeIndex::get(), + call: RelaychainCall::Staking::(StakingCall::BondExtra( + StakingBondExtraCall { value }, + )), + }, + ))), + ], + }))); + + let msg = Self::ump_transact(call.encode().into()); + + match T::XcmSender::send_xcm(MultiLocation::parent(), msg) { + Ok(()) => { + Self::deposit_event(Event::::BondExtraCallSent(value)); + } + Err(_e) => { + return Err(Error::::BondExtraCallFailed.into()); + } + } + }); + + Ok(()) + } + + fn unbond_internal(value: BalanceOf) -> DispatchResult { + switch_relay!({ + let call = RelaychainCall::Utility(Box::new(UtilityCall::AsDerivative( + UtilityAsDerivativeCall { + index: T::DerivativeIndex::get(), + call: RelaychainCall::Staking::(StakingCall::Unbond( + StakingUnbondCall { value }, + )), + }, + ))); + + let msg = Self::ump_transact(call.encode().into()); + + match T::XcmSender::send_xcm(MultiLocation::parent(), msg) { + Ok(()) => { + Self::deposit_event(Event::::UnbondCallSent(value)); + } + Err(_e) => { + return Err(Error::::UnbondCallFailed.into()); + } + } + }); + + Ok(()) + } + + fn rebond_internal(value: BalanceOf) -> DispatchResult { + switch_relay!({ + let call = RelaychainCall::Utility(Box::new(UtilityCall::AsDerivative( + UtilityAsDerivativeCall { + index: T::DerivativeIndex::get(), + call: RelaychainCall::Staking::(StakingCall::Rebond( + StakingRebondCall { value }, + )), + }, + ))); + + let msg = Self::ump_transact(call.encode().into()); + + match T::XcmSender::send_xcm(MultiLocation::parent(), msg) { + Ok(()) => { + Self::deposit_event(Event::::RebondCallSent(value)); + } + Err(_e) => { + return Err(Error::::RebondCallFailed.into()); + } + } + }); + + Ok(()) + } + + fn withdraw_unbonded_internal(num_slashing_spans: u32, amount: u128) -> DispatchResult { + switch_relay!({ + let call = + RelaychainCall::Utility(Box::new(UtilityCall::BatchAll(UtilityBatchAllCall { + calls: vec![ + RelaychainCall::Utility(Box::new(UtilityCall::AsDerivative( + UtilityAsDerivativeCall { + index: T::DerivativeIndex::get(), + call: RelaychainCall::Staking::( + StakingCall::WithdrawUnbonded( + StakingWithdrawUnbondedCall { num_slashing_spans }, + ), + ), + }, + ))), + RelaychainCall::Utility(Box::new(UtilityCall::AsDerivative( + UtilityAsDerivativeCall { + index: T::DerivativeIndex::get(), + call: RelaychainCall::Balances::(BalancesCall::TransferAll( + BalancesTransferAllCall { + dest: T::Lookup::unlookup(Self::para_account_id()), + keep_alive: true, + }, + )), + }, + ))), + RelaychainCall::XcmPallet( + XcmPalletCall::XcmPalletReserveTransferAssetsCall( + XcmPalletReserveTransferAssetsCall { + dest: Box::new( + MultiLocation::new( + 0, + X1(Parachain(T::SelfParaId::get().into())), + ) + .into(), + ), + beneficiary: Box::new( + MultiLocation::new( + 0, + X1(AccountId32 { + network: NetworkId::Any, + id: Self::account_id().into(), + }), + ) + .into(), + ), + assets: Box::new( + MultiAssets::from(vec![MultiAsset { + id: AssetId::Concrete(MultiLocation::new(0, Here)), + fun: Fungibility::Fungible(amount), + }]) + .into(), + ), + fee_asset_item: 0, + dest_weight: 1_000_000_000, + }, + ), + ), + ], + }))); + + let msg = Self::ump_transact(call.encode().into()); + + match T::XcmSender::send_xcm(MultiLocation::parent(), msg) { + Ok(()) => { + Self::deposit_event(Event::::WithdrawUnbondedCallSent( + num_slashing_spans, + )); + } + Err(_e) => { + return Err(Error::::WithdrawUnbondedCallFailed.into()); + } + } + }); + + Ok(()) + } + + /// push an unstake task into queue. #[inline] fn push_unstake_task(who: &T::AccountId, amount: BalanceOf) -> DispatchResult { - // UnstakeQueue::::mutate(|q| q.push((who.clone(), amount))) UnstakeQueue::::try_mutate(|q| -> DispatchResult { q.try_push((who.clone(), amount)) .map_err(|_| Error::::ExceededUnstakeQueueCapacity)?; @@ -593,25 +1057,71 @@ mod pallet { fn pop_unstake_task() { UnstakeQueue::::mutate(|v| v.remove(0)); } - } - impl Pallet { - pub fn account_id() -> T::AccountId { - T::PalletId::get().into_account() + fn ump_transact(call: DoubleEncoded<()>) -> Xcm<()> { + let asset: MultiAsset = (MultiLocation::here(), 1_000_000_000_000).into(); + + WithdrawAsset { + assets: MultiAssets::from(asset.clone()), + effects: vec![ + BuyExecution { + fees: asset, + weight: 800_000_000, + debt: 600_000_000, + halt_on_error: false, + instructions: vec![Transact { + origin_type: OriginKind::SovereignAccount, + require_weight_at_most: u64::MAX, + call, + }], + }, + DepositAsset { + assets: All.into(), + max_assets: u32::max_value(), + beneficiary: X1(AccountId32 { + network: NetworkId::Any, + id: Self::para_account_id().into(), + }) + .into(), + }, + ], + } } - /// account derived from parachain account - pub fn derivative_account_id() -> T::AccountId { - T::DerivativeProvider::derivative_account_id( - T::RelayAgent::get(), - T::DerivativeIndex::get(), - ) + fn ump_transfer(amount: BalanceOf) -> Xcm<()> { + let asset: MultiAsset = (MultiLocation::here(), u128::from(amount)).into(); + + WithdrawAsset { + assets: MultiAssets::from(asset.clone()), + effects: vec![InitiateReserveWithdraw { + assets: All.into(), + reserve: MultiLocation::parent(), + effects: vec![ + BuyExecution { + fees: asset, + weight: 0, + debt: T::BaseXcmWeight::get(), + halt_on_error: false, + instructions: vec![], + }, + DepositAsset { + assets: All.into(), + max_assets: u32::max_value(), + beneficiary: X1(AccountId32 { + network: NetworkId::Any, + id: Self::para_account_id().into(), + }) + .into(), + }, + ], + }], + } } } } impl ExchangeRateProvider for Pallet { - fn get_exchange_rate() -> primitives::Rate { + fn get_exchange_rate() -> Rate { ExchangeRate::::get() } } diff --git a/pallets/liquid-staking/src/mock.rs b/pallets/liquid-staking/src/mock.rs index 811dfc947..1e6f1bf31 100644 --- a/pallets/liquid-staking/src/mock.rs +++ b/pallets/liquid-staking/src/mock.rs @@ -17,7 +17,9 @@ use primitives::{ use sp_core::H256; use sp_runtime::{ testing::Header, - traits::{AccountIdConversion, AccountIdLookup, BlakeTwo256, Convert, One}, + traits::{ + AccountIdConversion, AccountIdLookup, BlakeTwo256, BlockNumberProvider, Convert, One, + }, AccountId32, MultiAddress::Id, }; @@ -57,7 +59,7 @@ impl parachain_info::Config for Test {} parameter_types! { pub DotLocation: MultiLocation = MultiLocation::parent(); - pub const RelayNetwork: NetworkId = NetworkId::Kusama; + pub RelayNetwork: NetworkId = NetworkId::Named("westend".into()); pub RelayChainOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into(); pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); } @@ -285,15 +287,15 @@ impl SortedMembers for BobOrigin { } } -pub type BridgeOrigin = EnsureSignedBy; +pub type RelayOrigin = EnsureSignedBy; pub type UpdateOrigin = EnsureSignedBy; parameter_types! { pub const StakingPalletId: PalletId = PalletId(*b"par/lqsk"); - pub RelayAgent: AccountId = para_a_account(); pub const DerivativeIndex: u16 = 0; pub const PeriodBasis: BlockNumber = 5u64; pub const UnstakeQueueCapacity: u32 = 1000; + pub SelfParaId: ParaId = para_a_id(); } impl pallet_utility::Config for Test { @@ -310,21 +312,45 @@ impl DerivativeProvider for DerivativeProviderT { } } +pub struct RelaychainBlockNumberProvider(sp_std::marker::PhantomData); + +impl BlockNumberProvider + for RelaychainBlockNumberProvider +{ + type BlockNumber = BlockNumber; + + fn current_block_number() -> Self::BlockNumber { + cumulus_pallet_parachain_system::Pallet::::validation_data() + .map(|d| d.relay_parent_number) + .unwrap_or_default() + .into() + } +} + +parameter_types! { + pub const MaxRewardsPerEra: Balance = 100; + pub const MaxSlashesPerEra: Balance = 1; +} + impl crate::Config for Test { type Event = Event; type PalletId = StakingPalletId; - type BridgeOrigin = BridgeOrigin; type BaseXcmWeight = BaseXcmWeight; type XcmTransfer = XTokens; - type RelayAgent = RelayAgent; + type SelfParaId = SelfParaId; type PeriodBasis = PeriodBasis; type WeightInfo = (); type XcmSender = XcmRouter; type DerivativeIndex = DerivativeIndex; type DerivativeProvider = DerivativeProviderT; type Assets = Assets; + type RelayOrigin = RelayOrigin; type UpdateOrigin = UpdateOrigin; type UnstakeQueueCapacity = UnstakeQueueCapacity; + type RelaychainBlockNumberProvider = RelaychainBlockNumberProvider; + type MaxRewardsPerEra = MaxRewardsPerEra; + type MaxSlashesPerEra = MaxSlashesPerEra; + type RelayNetwork = RelayNetwork; } parameter_types! { @@ -440,8 +466,8 @@ pub type RelaySystem = frame_system::Pallet; pub type RelayEvent = westend_runtime::Event; pub type ParaSystem = frame_system::Pallet; -pub fn para_a_account() -> AccountId { - ParaId::from(1).into_account() +pub fn para_a_id() -> ParaId { + ParaId::from(1) } pub fn para_ext(para_id: u32) -> sp_io::TestExternalities { @@ -490,7 +516,7 @@ pub fn relay_ext() -> sp_io::TestExternalities { pallet_balances::GenesisConfig:: { balances: vec![ (ALICE, 100 * DOT_DECIMAL), - (para_a_account(), 1_000_000 * DOT_DECIMAL), + (para_a_id().into_account(), 1_000_000 * DOT_DECIMAL), ], } .assimilate_storage(&mut t) diff --git a/pallets/liquid-staking/src/relaychain.rs b/pallets/liquid-staking/src/relaychain.rs deleted file mode 100644 index 63570f1f4..000000000 --- a/pallets/liquid-staking/src/relaychain.rs +++ /dev/null @@ -1,252 +0,0 @@ -#![allow(dead_code)] -use super::{pallet::*, types::*, BalanceOf, Config, Pallet}; - -use frame_support::pallet_prelude::*; -use sp_runtime::{traits::StaticLookup, DispatchResult}; -use sp_std::prelude::*; -use xcm::{latest::prelude::*, DoubleEncoded}; - -impl Pallet -where - [u8; 32]: From<::AccountId>, -{ - /// Bond on relaychain via xcm.transact - pub(crate) fn bond( - value: BalanceOf, - payee: RewardDestination, - ) -> DispatchResult { - let stash = Self::derivative_account_id(); - let controller = stash.clone(); - let call = RelaychainCall::Utility(Box::new(UtilityCall::BatchAll(UtilityBatchAllCall { - calls: vec![ - RelaychainCall::Balances(BalancesCall::TransferKeepAlive( - BalancesTransferKeepAliveCall { - dest: T::Lookup::unlookup(stash), - value, - }, - )), - RelaychainCall::Utility(Box::new(UtilityCall::AsDerivative( - UtilityAsDerivativeCall { - index: T::DerivativeIndex::get(), - call: RelaychainCall::Staking::(StakingCall::Bond(StakingBondCall { - controller: T::Lookup::unlookup(controller.clone()), - value, - payee: payee.clone(), - })), - }, - ))), - ], - }))); - - let msg = Self::xcm_message(call.encode().into()); - - match T::XcmSender::send_xcm(MultiLocation::parent(), msg) { - Ok(()) => { - Self::deposit_event(Event::::BondCallSent(controller, value, payee)); - } - Err(_e) => { - return Err(Error::::BondCallFailed.into()); - } - } - Ok(()) - } - - /// Bond_extra on relaychain via xcm.transact - pub(crate) fn bond_extra(value: BalanceOf) -> DispatchResult { - let stash = T::Lookup::unlookup(Self::derivative_account_id()); - let call = RelaychainCall::Utility(Box::new(UtilityCall::BatchAll(UtilityBatchAllCall { - calls: vec![ - RelaychainCall::Balances(BalancesCall::TransferKeepAlive( - BalancesTransferKeepAliveCall { dest: stash, value }, - )), - RelaychainCall::Utility(Box::new(UtilityCall::AsDerivative( - UtilityAsDerivativeCall { - index: T::DerivativeIndex::get(), - call: RelaychainCall::Staking::(StakingCall::BondExtra( - StakingBondExtraCall { value }, - )), - }, - ))), - ], - }))); - - let msg = Self::xcm_message(call.encode().into()); - - match T::XcmSender::send_xcm(MultiLocation::parent(), msg) { - Ok(()) => { - Self::deposit_event(Event::::BondExtraCallSent(value)); - } - Err(_e) => { - return Err(Error::::BondExtraCallFailed.into()); - } - } - Ok(()) - } - - /// unbond on relaychain via xcm.transact - pub(crate) fn unbond(value: BalanceOf) -> DispatchResult { - let call = RelaychainCall::Utility(Box::new(UtilityCall::AsDerivative( - UtilityAsDerivativeCall { - index: T::DerivativeIndex::get(), - call: RelaychainCall::Staking::(StakingCall::Unbond(StakingUnbondCall { - value, - })), - }, - ))); - - let msg = Self::xcm_message(call.encode().into()); - - match T::XcmSender::send_xcm(MultiLocation::parent(), msg) { - Ok(()) => { - Self::deposit_event(Event::::UnbondCallSent(value)); - } - Err(_e) => { - return Err(Error::::UnbondCallFailed.into()); - } - } - Ok(()) - } - - /// rebond on relaychain via xcm.transact - pub(crate) fn rebond(value: BalanceOf) -> DispatchResult { - let call = RelaychainCall::Utility(Box::new(UtilityCall::AsDerivative( - UtilityAsDerivativeCall { - index: T::DerivativeIndex::get(), - call: RelaychainCall::Staking::(StakingCall::Rebond(StakingRebondCall { - value, - })), - }, - ))); - - let msg = Self::xcm_message(call.encode().into()); - - match T::XcmSender::send_xcm(MultiLocation::parent(), msg) { - Ok(()) => { - Self::deposit_event(Event::::RebondCallSent(value)); - } - Err(_e) => { - return Err(Error::::RebondCallFailed.into()); - } - } - Ok(()) - } - - /// withdraw unbonded on relaychain via xcm.transact - pub(crate) fn withdraw_unbonded(num_slashing_spans: u32) -> DispatchResult { - let call = RelaychainCall::Utility(Box::new(UtilityCall::BatchAll(UtilityBatchAllCall { - calls: vec![ - RelaychainCall::Utility(Box::new(UtilityCall::AsDerivative( - UtilityAsDerivativeCall { - index: T::DerivativeIndex::get(), - call: RelaychainCall::Staking::(StakingCall::WithdrawUnbonded( - StakingWithdrawUnbondedCall { num_slashing_spans }, - )), - }, - ))), - RelaychainCall::Utility(Box::new(UtilityCall::AsDerivative( - UtilityAsDerivativeCall { - index: T::DerivativeIndex::get(), - call: RelaychainCall::Balances::(BalancesCall::TransferAll( - BalancesTransferAllCall { - dest: T::Lookup::unlookup(T::RelayAgent::get()), - keep_alive: true, - }, - )), - }, - ))), - ], - }))); - - let msg = Self::xcm_message(call.encode().into()); - - match T::XcmSender::send_xcm(MultiLocation::parent(), msg) { - Ok(()) => { - Self::deposit_event(Event::::WithdrawUnbondedCallSent(num_slashing_spans)); - } - Err(_e) => { - return Err(Error::::WithdrawUnbondedCallFailed.into()); - } - } - Ok(()) - } - - /// Nominate on relaychain via xcm.transact - pub(crate) fn nominate(targets: Vec) -> DispatchResult { - let targets_source = targets - .clone() - .into_iter() - .map(T::Lookup::unlookup) - .collect(); - - let call = RelaychainCall::Utility(Box::new(UtilityCall::AsDerivative( - UtilityAsDerivativeCall { - index: T::DerivativeIndex::get(), - call: RelaychainCall::Staking::(StakingCall::Nominate(StakingNominateCall { - targets: targets_source, - })), - }, - ))); - let msg = Self::xcm_message(call.encode().into()); - - match T::XcmSender::send_xcm(MultiLocation::parent(), msg) { - Ok(()) => { - Self::deposit_event(Event::::NominateCallSent(targets)); - } - Err(_e) => { - return Err(Error::::NominateCallFailed.into()); - } - } - Ok(()) - } - - /// Payout_stakers on relaychain via xcm.transact - pub(crate) fn payout_stakers(validator_stash: T::AccountId, era: u32) -> DispatchResult { - let call = - RelaychainCall::Staking::(StakingCall::PayoutStakers(StakingPayoutStakersCall { - validator_stash: validator_stash.clone(), - era, - })); - - let msg = Self::xcm_message(call.encode().into()); - - match T::XcmSender::send_xcm(MultiLocation::parent(), msg) { - Ok(()) => { - Self::deposit_event(Event::::PayoutStakersCallSent(validator_stash, era)); - } - Err(_e) => { - return Err(Error::::PayoutStakersCallFailed.into()); - } - } - Ok(()) - } - - fn xcm_message(call: DoubleEncoded<()>) -> Xcm<()> { - let asset: MultiAsset = (MultiLocation::here(), 1_000_000_000_000).into(); - - WithdrawAsset { - assets: MultiAssets::from(asset.clone()), - effects: vec![ - BuyExecution { - fees: asset, - weight: 800_000_000, - debt: 600_000_000, - halt_on_error: false, - instructions: vec![Transact { - origin_type: OriginKind::SovereignAccount, - require_weight_at_most: 100_000_000_000, - call, - }], - }, - DepositAsset { - assets: All.into(), - max_assets: u32::max_value(), - beneficiary: X1(Junction::AccountId32 { - network: NetworkId::Any, - id: T::RelayAgent::get().into(), - }) - .into(), - }, - ], - } - } -} diff --git a/pallets/liquid-staking/src/tests.rs b/pallets/liquid-staking/src/tests.rs index ad095b1c6..c660382ac 100644 --- a/pallets/liquid-staking/src/tests.rs +++ b/pallets/liquid-staking/src/tests.rs @@ -141,16 +141,18 @@ fn test_settlement_should_work() { ); assert_ok!(LiquidStaking::settlement( Origin::signed(ALICE), - unbonding_amount + 0, + unbonding_amount, + 0 )); Pallet::::on_idle(0, 10000); } }); Relay::execute_with(|| { assert_eq!( - RelayBalances::free_balance(&RelayAgent::get()), + RelayBalances::free_balance(&LiquidStaking::para_account_id()), // FIXME: weight should be take into account - 9999999200000000 + 9999978717112000 ); }); } @@ -161,12 +163,13 @@ fn test_transact_bond_work() { ParaA::execute_with(|| { assert_ok!(LiquidStaking::bond( + Origin::signed(ALICE), 3 * DOT_DECIMAL, RewardDestination::Staked )); ParaSystem::assert_has_event(mock::Event::LiquidStaking(crate::Event::BondCallSent( - LiquidStaking::derivative_account_id(), + LiquidStaking::derivative_para_account_id(), 3 * DOT_DECIMAL, RewardDestination::Staked, ))); @@ -174,10 +177,10 @@ fn test_transact_bond_work() { Relay::execute_with(|| { RelaySystem::assert_has_event(RelayEvent::Staking(RelayStakingEvent::Bonded( - LiquidStaking::derivative_account_id(), + LiquidStaking::derivative_para_account_id(), 3 * DOT_DECIMAL, ))); - let ledger = RelayStaking::ledger(LiquidStaking::derivative_account_id()).unwrap(); + let ledger = RelayStaking::ledger(LiquidStaking::derivative_para_account_id()).unwrap(); assert_eq!(ledger.total, 3 * DOT_DECIMAL); }); } @@ -188,15 +191,19 @@ fn test_transact_bond_extra_work() { ParaA::execute_with(|| { assert_ok!(LiquidStaking::bond( + Origin::signed(ALICE), 2 * DOT_DECIMAL, RewardDestination::Staked )); - assert_ok!(LiquidStaking::bond_extra(3 * DOT_DECIMAL)); + assert_ok!(LiquidStaking::bond_extra( + Origin::signed(ALICE), + 3 * DOT_DECIMAL + )); }); Relay::execute_with(|| { - let ledger = RelayStaking::ledger(LiquidStaking::derivative_account_id()).unwrap(); + let ledger = RelayStaking::ledger(LiquidStaking::derivative_para_account_id()).unwrap(); assert_eq!(ledger.total, 5 * DOT_DECIMAL); }); } @@ -207,22 +214,26 @@ fn test_transact_unbond_work() { ParaA::execute_with(|| { assert_ok!(LiquidStaking::bond( + Origin::signed(ALICE), 5 * DOT_DECIMAL, RewardDestination::Staked )); - assert_ok!(LiquidStaking::unbond(2 * DOT_DECIMAL)); + assert_ok!(LiquidStaking::unbond( + Origin::signed(ALICE), + 2 * DOT_DECIMAL + )); }); Relay::execute_with(|| { RelaySystem::assert_has_event(RelayEvent::Staking(RelayStakingEvent::Bonded( - LiquidStaking::derivative_account_id(), + LiquidStaking::derivative_para_account_id(), 5 * DOT_DECIMAL, ))); RelaySystem::assert_has_event(RelayEvent::Staking(RelayStakingEvent::Unbonded( - LiquidStaking::derivative_account_id(), + LiquidStaking::derivative_para_account_id(), 2 * DOT_DECIMAL, ))); - let ledger = RelayStaking::ledger(LiquidStaking::derivative_account_id()).unwrap(); + let ledger = RelayStaking::ledger(LiquidStaking::derivative_para_account_id()).unwrap(); assert_eq!(ledger.total, 5 * DOT_DECIMAL); assert_eq!(ledger.active, 3 * DOT_DECIMAL); }); @@ -234,24 +245,28 @@ fn test_transact_withdraw_unbonded_work() { ParaA::execute_with(|| { assert_ok!(LiquidStaking::bond( + Origin::signed(ALICE), 5 * DOT_DECIMAL, RewardDestination::Staked )); - assert_ok!(LiquidStaking::unbond(2 * DOT_DECIMAL)); + assert_ok!(LiquidStaking::unbond( + Origin::signed(ALICE), + 2 * DOT_DECIMAL + )); }); Relay::execute_with(|| { - let ledger = RelayStaking::ledger(LiquidStaking::derivative_account_id()).unwrap(); + let ledger = RelayStaking::ledger(LiquidStaking::derivative_para_account_id()).unwrap(); assert_eq!(ledger.total, 5 * DOT_DECIMAL); assert_eq!(ledger.active, 3 * DOT_DECIMAL); assert_eq!(ledger.unlocking.len(), 1); RelaySystem::assert_has_event(RelayEvent::Staking(RelayStakingEvent::Bonded( - LiquidStaking::derivative_account_id(), + LiquidStaking::derivative_para_account_id(), 5 * DOT_DECIMAL, ))); RelaySystem::assert_has_event(RelayEvent::Staking(RelayStakingEvent::Unbonded( - LiquidStaking::derivative_account_id(), + LiquidStaking::derivative_para_account_id(), 2 * DOT_DECIMAL, ))); @@ -261,11 +276,15 @@ fn test_transact_withdraw_unbonded_work() { }); ParaA::execute_with(|| { - assert_ok!(LiquidStaking::withdraw_unbonded(0)); + assert_ok!(LiquidStaking::withdraw_unbonded( + Origin::signed(ALICE), + 0, + 0 + )); }); Relay::execute_with(|| { - let ledger = RelayStaking::ledger(LiquidStaking::derivative_account_id()).unwrap(); + let ledger = RelayStaking::ledger(LiquidStaking::derivative_para_account_id()).unwrap(); assert_eq!(ledger.total, 3 * DOT_DECIMAL); assert_eq!(ledger.active, 3 * DOT_DECIMAL); assert_eq!(ledger.unlocking.len(), 0); @@ -278,27 +297,34 @@ fn test_transact_rebond_work() { ParaA::execute_with(|| { assert_ok!(LiquidStaking::bond( + Origin::signed(ALICE), 10 * DOT_DECIMAL, RewardDestination::Staked )); - assert_ok!(LiquidStaking::unbond(5 * DOT_DECIMAL)); - assert_ok!(LiquidStaking::rebond(3 * DOT_DECIMAL)); + assert_ok!(LiquidStaking::unbond( + Origin::signed(ALICE), + 5 * DOT_DECIMAL + )); + assert_ok!(LiquidStaking::rebond( + Origin::signed(ALICE), + 3 * DOT_DECIMAL + )); }); Relay::execute_with(|| { RelaySystem::assert_has_event(RelayEvent::Staking(RelayStakingEvent::Bonded( - LiquidStaking::derivative_account_id(), + LiquidStaking::derivative_para_account_id(), 10 * DOT_DECIMAL, ))); RelaySystem::assert_has_event(RelayEvent::Staking(RelayStakingEvent::Unbonded( - LiquidStaking::derivative_account_id(), + LiquidStaking::derivative_para_account_id(), 5 * DOT_DECIMAL, ))); RelaySystem::assert_has_event(RelayEvent::Staking(RelayStakingEvent::Bonded( - LiquidStaking::derivative_account_id(), + LiquidStaking::derivative_para_account_id(), 3 * DOT_DECIMAL, ))); - let ledger = RelayStaking::ledger(LiquidStaking::derivative_account_id()).unwrap(); + let ledger = RelayStaking::ledger(LiquidStaking::derivative_para_account_id()).unwrap(); assert_eq!(ledger.total, 10 * DOT_DECIMAL); assert_eq!(ledger.active, 8 * DOT_DECIMAL); }); @@ -310,17 +336,22 @@ fn test_transact_nominate_work() { ParaA::execute_with(|| { assert_ok!(LiquidStaking::bond( + Origin::signed(ALICE), 10 * DOT_DECIMAL, RewardDestination::Staked )); - assert_ok!(LiquidStaking::nominate(vec![ALICE, BOB],)); + assert_ok!(LiquidStaking::nominate( + Origin::signed(ALICE), + vec![ALICE, BOB], + )); }); Relay::execute_with(|| { - let ledger = RelayStaking::ledger(LiquidStaking::derivative_account_id()).unwrap(); + let ledger = RelayStaking::ledger(LiquidStaking::derivative_para_account_id()).unwrap(); assert_eq!(ledger.total, 10 * DOT_DECIMAL); - let nominators = RelayStaking::nominators(LiquidStaking::derivative_account_id()).unwrap(); + let nominators = + RelayStaking::nominators(LiquidStaking::derivative_para_account_id()).unwrap(); assert_eq!(nominators.targets, vec![ALICE, BOB]); }); } @@ -345,21 +376,23 @@ fn test_transact_payout_stakers_work() { pallet_staking::ErasValidatorReward::::insert(0, 500 * DOT_DECIMAL); pallet_staking::ErasStakersClipped::::insert( 0, - LiquidStaking::derivative_account_id(), + LiquidStaking::derivative_para_account_id(), exposure, ); - RelayStaking::reward_by_ids(vec![(LiquidStaking::derivative_account_id(), 100)]); + RelayStaking::reward_by_ids(vec![(LiquidStaking::derivative_para_account_id(), 100)]); }); ParaA::execute_with(|| { assert_ok!(LiquidStaking::bond( + Origin::signed(ALICE), 1 * DOT_DECIMAL, RewardDestination::Account(BOB), )); // weight is 31701208000 assert_ok!(LiquidStaking::payout_stakers( - LiquidStaking::derivative_account_id(), + Origin::signed(ALICE), + LiquidStaking::derivative_para_account_id(), 0 )); }); diff --git a/pallets/liquid-staking/src/types.rs b/pallets/liquid-staking/src/types.rs index 9899588ee..faa4d6ad9 100644 --- a/pallets/liquid-staking/src/types.rs +++ b/pallets/liquid-staking/src/types.rs @@ -1,10 +1,12 @@ use super::{BalanceOf, Config}; use codec::{Decode, Encode}; +use frame_support::weights::Weight; use sp_runtime::{ traits::{AtLeast32BitUnsigned, StaticLookup, Zero}, RuntimeDebug, }; -use sp_std::{cmp::Ordering, vec::Vec}; +use sp_std::{boxed::Box, cmp::Ordering, vec::Vec}; +use xcm::{VersionedMultiAssets, VersionedMultiLocation}; /// Category of staking settlement at the end of era. #[derive(Encode, Decode, Eq, PartialEq, Copy, Clone, RuntimeDebug)] @@ -23,41 +25,6 @@ pub struct MatchingLedger { pub total_unstake_amount: Balance, } -impl MatchingLedger -where - Balance: AtLeast32BitUnsigned + Copy + Clone, -{ - /// Matching requests in current period. - /// - /// `unbonding_amount` is the total amount of the unbonding asset in relaychain. - /// - /// the returned tri-tuple is formed as `(bond_amount, rebond_amount, unbond_amount)`. - pub fn matching(&self, unbonding_amount: Balance) -> (Balance, Balance, Balance) { - use Ordering::*; - - match self.total_stake_amount.cmp(&self.total_unstake_amount) { - Greater => { - let amount = self.total_stake_amount - self.total_unstake_amount; - if amount < unbonding_amount { - (Zero::zero(), amount, Zero::zero()) - } else { - (amount - unbonding_amount, unbonding_amount, Zero::zero()) - } - } - Less | Equal => ( - Zero::zero(), - Zero::zero(), - self.total_unstake_amount - self.total_stake_amount, - ), - } - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.total_stake_amount.is_zero() && self.total_unstake_amount.is_zero() - } -} - /// A destination account for payment. #[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug)] pub enum RewardDestination { @@ -200,53 +167,89 @@ pub enum UtilityCall { BatchAll(UtilityBatchAllCall), } -pub mod westend { - use super::*; - - #[derive(Encode, Decode, RuntimeDebug)] - pub enum RelaychainCall { - #[codec(index = 4)] - Balances(BalancesCall), - #[codec(index = 6)] - Staking(StakingCall), - #[codec(index = 16)] - Utility(Box>), - } +/// Relaychain xcmPallet.reserve_transfer_assets call arguments +#[derive(Encode, Decode, RuntimeDebug)] +pub struct XcmPalletReserveTransferAssetsCall { + pub dest: Box, + pub beneficiary: Box, + pub assets: Box, + pub fee_asset_item: u32, + pub dest_weight: Weight, } -pub mod kusama { - use super::*; +#[derive(Encode, Decode, RuntimeDebug)] +pub enum XcmPalletCall { + #[codec(index = 2)] + XcmPalletReserveTransferAssetsCall(XcmPalletReserveTransferAssetsCall), +} - #[derive(Encode, Decode, RuntimeDebug)] - pub enum RelaychainCall { - #[codec(index = 4)] - Balances(BalancesCall), - #[codec(index = 6)] - Staking(StakingCall), - #[codec(index = 24)] - Utility(Box>), - } +#[derive(Encode, Decode, RuntimeDebug)] +pub enum WestendCall { + #[codec(index = 4)] + Balances(BalancesCall), + #[codec(index = 6)] + Staking(StakingCall), + #[codec(index = 16)] + Utility(Box>), + #[codec(index = 99)] + XcmPallet(XcmPalletCall), } -pub mod polkadot { - use super::*; +#[derive(Encode, Decode, RuntimeDebug)] +pub enum KusamaCall { + #[codec(index = 4)] + Balances(BalancesCall), + #[codec(index = 6)] + Staking(StakingCall), + #[codec(index = 24)] + Utility(Box>), + #[codec(index = 99)] + XcmPallet(XcmPalletCall), +} - #[derive(Encode, Decode, RuntimeDebug)] - pub enum RelaychainCall { - #[codec(index = 5)] - Balances(BalancesCall), - #[codec(index = 7)] - Staking(StakingCall), - #[codec(index = 26)] - Utility(Box>), - } +#[derive(Encode, Decode, RuntimeDebug)] +pub enum PolkadotCall { + #[codec(index = 5)] + Balances(BalancesCall), + #[codec(index = 7)] + Staking(StakingCall), + #[codec(index = 26)] + Utility(Box>), + // FIXME: polkadot runtime doesn't have xcm pallet yet + #[codec(index = 99)] + XcmPallet(XcmPalletCall), } -#[cfg(feature = "westend")] -pub use westend::RelaychainCall; +impl MatchingLedger { + /// Matching requests in current period. + /// + /// `unbonding_amount` is the total amount of the unbonding asset in relaychain. + /// + /// the returned tri-tuple is formed as `(bond_amount, rebond_amount, unbond_amount)`. + pub fn matching(&self, unbonding_amount: Balance) -> (Balance, Balance, Balance) { + use Ordering::*; -#[cfg(feature = "kusama")] -pub use kusama::RelaychainCall; + if matches!( + self.total_stake_amount.cmp(&self.total_unstake_amount), + Less | Equal + ) { + return ( + Zero::zero(), + Zero::zero(), + self.total_unstake_amount - self.total_stake_amount, + ); + } -#[cfg(feature = "polkadot")] -pub use polkadot::RelaychainCall; + let amount = self.total_stake_amount - self.total_unstake_amount; + if amount < unbonding_amount { + (Zero::zero(), amount, Zero::zero()) + } else { + (amount - unbonding_amount, unbonding_amount, Zero::zero()) + } + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.total_stake_amount.is_zero() && self.total_unstake_amount.is_zero() + } +} diff --git a/pallets/liquid-staking/src/weights.rs b/pallets/liquid-staking/src/weights.rs index b9d5f6a6e..a50d995e5 100644 --- a/pallets/liquid-staking/src/weights.rs +++ b/pallets/liquid-staking/src/weights.rs @@ -9,9 +9,16 @@ pub trait WeightInfo { fn unstake() -> Weight; fn record_staking_settlement() -> Weight; fn settlement() -> Weight; - fn pop_queue() -> Weight; fn set_liquid_currency() -> Weight; fn set_staking_currency() -> Weight; + fn withdraw_unbonded() -> Weight; + fn payout_stakers() -> Weight; + fn nominate() -> Weight; + fn rebond() -> Weight; + fn unbond() -> Weight; + fn bond_extra() -> Weight; + fn bond() -> Weight; + fn pop_queue() -> Weight; } impl WeightInfo for () { @@ -27,13 +34,34 @@ impl WeightInfo for () { fn settlement() -> Weight { 10000u64.into() } - fn pop_queue() -> Weight { - 10000u64.into() - } fn set_liquid_currency() -> Weight { 10000u64.into() } fn set_staking_currency() -> Weight { 10000u64.into() } + fn withdraw_unbonded() -> Weight { + 10000u64.into() + } + fn payout_stakers() -> Weight { + 10000u64.into() + } + fn nominate() -> Weight { + 10000u64.into() + } + fn rebond() -> Weight { + 10000u64.into() + } + fn unbond() -> Weight { + 10000u64.into() + } + fn bond_extra() -> Weight { + 10000u64.into() + } + fn bond() -> Weight { + 10000u64.into() + } + fn pop_queue() -> Weight { + 10000u64.into() + } } diff --git a/pallets/loans/src/lib.rs b/pallets/loans/src/lib.rs index ef55daf78..641a94fa7 100644 --- a/pallets/loans/src/lib.rs +++ b/pallets/loans/src/lib.rs @@ -23,6 +23,7 @@ #![cfg_attr(not(feature = "std"), no_std)] pub use crate::rate_model::*; +pub use pallet::*; use frame_support::{ log, @@ -35,7 +36,6 @@ use frame_support::{ transactional, PalletId, }; use frame_system::pallet_prelude::*; -pub use pallet::*; use primitives::{CurrencyId, Liquidity, Price, PriceFeeder, Rate, Ratio, Shortfall, Timestamp}; use sp_runtime::{ traits::{ diff --git a/runtime/heiko/Cargo.toml b/runtime/heiko/Cargo.toml index 975b18e9b..868ccaaeb 100644 --- a/runtime/heiko/Cargo.toml +++ b/runtime/heiko/Cargo.toml @@ -88,7 +88,7 @@ orml-xtokens = { git = 'https://github.com/open-web3-stack/open-r # Parallel dependencies pallet-amm = { path = '../../pallets/amm', default-features = false } pallet-currency-adapter = { path = '../../pallets/currency-adapter', default-features = false } -pallet-liquid-staking = { path = '../../pallets/liquid-staking-v2', package = 'pallet-liquid-staking-v2', default-features = false } +pallet-liquid-staking = { path = '../../pallets/liquid-staking', default-features = false } pallet-liquidation = { path = '../../pallets/liquidation', default-features = false } pallet-loans = { path = '../../pallets/loans', default-features = false } pallet-loans-rpc-runtime-api = { path = '../../pallets/loans/rpc/runtime-api', default-features = false } diff --git a/runtime/heiko/src/lib.rs b/runtime/heiko/src/lib.rs index 7d6f1799a..41bf74f18 100644 --- a/runtime/heiko/src/lib.rs +++ b/runtime/heiko/src/lib.rs @@ -53,9 +53,9 @@ use cumulus_primitives_core::ParaId; use frame_support::log; use frame_system::{ limits::{BlockLength, BlockWeights}, - EnsureOneOf, EnsureRoot, EnsureSigned, + EnsureOneOf, EnsureRoot, }; -use hex_literal::hex; + use orml_xcm_support::{IsNativeConcrete, MultiNativeAsset}; use polkadot_parachain::primitives::Sibling; use primitives::{ @@ -379,7 +379,10 @@ impl Convert for AccountIdToMultiLocation { parameter_types! { pub SelfLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(ParachainInfo::parachain_id().into()))); - pub const BaseXcmWeight: Weight = 100_000_000; + pub BaseXcmWeight: Weight = 150_000_000; +} +parameter_types! { + pub KsmPerSecond: (AssetId, u128) = (AssetId::Concrete(MultiLocation::parent()), ksm_per_second()); } impl orml_xtokens::Config for Runtime { @@ -390,7 +393,7 @@ impl orml_xtokens::Config for Runtime { type AccountIdToMultiLocation = AccountIdToMultiLocation; type SelfLocation = SelfLocation; type XcmExecutor = XcmExecutor; - type Weigher = FixedWeightBounds; + type Weigher = FixedWeightBounds; type BaseXcmWeight = BaseXcmWeight; type LocationInverter = LocationInverter; } @@ -452,28 +455,43 @@ impl pallet_membership::Config for Runtime parameter_types! { pub const StakingPalletId: PalletId = PalletId(*b"par/lqsk"); - pub RelayAgent: MultiLocation = MultiLocation::new( - 1, - X1(AccountId32{ - network: NetworkId::Any, - // Dave - id: hex!["306721211d5404bd9da88e0204360a1a9ab8b87c66c1bc2fcdd37f3c2222cc20"] - }) - ); pub const PeriodBasis: BlockNumber = 1000u32; + pub const DerivativeIndex: u16 = 0; + pub const UnstakeQueueCapacity: u32 = 1000; +} + +pub struct DerivativeProviderT; + +impl DerivativeProvider for DerivativeProviderT { + fn derivative_account_id(who: AccountId, index: u16) -> AccountId { + Utility::derivative_account_id(who, index) + } +} + +parameter_types! { + pub const MaxRewardsPerEra: Balance = 100; + pub const MaxSlashesPerEra: Balance = 1; } impl pallet_liquid_staking::Config for Runtime { type Event = Event; type PalletId = StakingPalletId; - type BridgeOrigin = EnsureSigned; type WeightInfo = (); type XcmTransfer = XTokens; - type RelayAgent = RelayAgent; + type SelfParaId = ParachainInfo; type PeriodBasis = PeriodBasis; type BaseXcmWeight = BaseXcmWeight; type Assets = Assets; + type RelayOrigin = EnsureRootOrMoreThanHalfGeneralCouncil; type UpdateOrigin = EnsureRootOrMoreThanHalfGeneralCouncil; + type XcmSender = XcmRouter; + type DerivativeIndex = DerivativeIndex; + type DerivativeProvider = DerivativeProviderT; + type UnstakeQueueCapacity = UnstakeQueueCapacity; + type RelaychainBlockNumberProvider = RelaychainBlockNumberProvider; + type MaxRewardsPerEra = MaxRewardsPerEra; + type MaxSlashesPerEra = MaxSlashesPerEra; + type RelayNetwork = RelayNetwork; } parameter_types! { @@ -708,7 +726,7 @@ impl pallet_xcm::Config for Runtime { type XcmExecutor = XcmExecutor; // Teleporting is disabled. type XcmTeleportFilter = (); - type Weigher = FixedWeightBounds; + type Weigher = FixedWeightBounds; type LocationInverter = LocationInverter; } @@ -805,18 +823,6 @@ pub type XcmOriginToTransactDispatchOrigin = ( XcmPassthrough, ); -parameter_types! { - pub UnitWeightCost: Weight = 20_000_000; - pub KsmPerSecond: (AssetId, u128) = (AssetId::Concrete(MultiLocation::parent()), ksm_per_second()); -} - -parameter_types! { - // 1_000_000_000_000 => 1 unit of asset for 1 unit of Weight. - // TODO Should take the actual weight price. This is just 1_000 KSM per second of weight. - pub WeightPrice: (MultiLocation, u128) = (MultiLocation::parent(), 1_000); - // pub AllowUnpaidFrom: Vec = vec![ Junction::Parent) ]; -} - pub type Barrier = (TakeWeightCredit, AllowTopLevelPaidExecutionFrom); pub struct ToTreasury; @@ -846,7 +852,7 @@ impl Config for XcmConfig { type IsTeleporter = (); type LocationInverter = LocationInverter; type Barrier = Barrier; - type Weigher = FixedWeightBounds; + type Weigher = FixedWeightBounds; type Trader = FixedRateOfFungible; type ResponseHandler = (); type SubscriptionService = PolkadotXcm; diff --git a/runtime/parallel/Cargo.toml b/runtime/parallel/Cargo.toml index acf7cf1c7..732aa5c88 100644 --- a/runtime/parallel/Cargo.toml +++ b/runtime/parallel/Cargo.toml @@ -88,7 +88,7 @@ orml-xtokens = { git = 'https://github.com/open-web3-stack/open-r # Parallel dependencies pallet-amm = { path = '../../pallets/amm', default-features = false } pallet-currency-adapter = { path = '../../pallets/currency-adapter', default-features = false } -pallet-liquid-staking = { path = '../../pallets/liquid-staking-v2', package = 'pallet-liquid-staking-v2', default-features = false } +pallet-liquid-staking = { path = '../../pallets/liquid-staking', default-features = false } pallet-liquidation = { path = '../../pallets/liquidation', default-features = false } pallet-loans = { path = '../../pallets/loans', default-features = false } pallet-loans-rpc-runtime-api = { path = '../../pallets/loans/rpc/runtime-api', default-features = false } diff --git a/runtime/parallel/src/lib.rs b/runtime/parallel/src/lib.rs index b7cd05cff..b88359bd4 100644 --- a/runtime/parallel/src/lib.rs +++ b/runtime/parallel/src/lib.rs @@ -25,7 +25,7 @@ mod weights; use codec::Encode; use frame_support::{ dispatch::Weight, - traits::{fungibles::Mutate, Contains, Everything, IsInVec}, + traits::{fungibles::Mutate, Contains, Everything}, PalletId, }; @@ -54,7 +54,7 @@ use cumulus_primitives_core::ParaId; use frame_support::log; use frame_system::{ limits::{BlockLength, BlockWeights}, - EnsureOneOf, EnsureRoot, EnsureSigned, EnsureSignedBy, + EnsureOneOf, EnsureRoot, EnsureSigned, }; use orml_xcm_support::{IsNativeConcrete, MultiNativeAsset}; use polkadot_parachain::primitives::Sibling; @@ -65,7 +65,6 @@ use primitives::{ Index, *, }; -use hex_literal::hex; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowTopLevelPaidExecutionFrom, EnsureXcmOrigin, FixedRateOfFungible, @@ -367,7 +366,7 @@ impl Convert for AccountIdToMultiLocation { parameter_types! { pub SelfLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(ParachainInfo::parachain_id().into()))); - pub const BaseXcmWeight: Weight = 100_000_000; + pub const BaseXcmWeight: Weight = 150_000_000; } impl orml_xtokens::Config for Runtime { @@ -378,7 +377,7 @@ impl orml_xtokens::Config for Runtime { type AccountIdToMultiLocation = AccountIdToMultiLocation; type SelfLocation = SelfLocation; type XcmExecutor = XcmExecutor; - type Weigher = FixedWeightBounds; + type Weigher = FixedWeightBounds; type BaseXcmWeight = BaseXcmWeight; type LocationInverter = LocationInverter; } @@ -440,29 +439,43 @@ impl pallet_membership::Config for Runtime parameter_types! { pub const StakingPalletId: PalletId = PalletId(*b"par/lqsk"); - pub RelayAgent: MultiLocation = MultiLocation::new( - 1, - X1(AccountId32{ - network: NetworkId::Any, - // Dave - id: hex!["306721211d5404bd9da88e0204360a1a9ab8b87c66c1bc2fcdd37f3c2222cc20"] - }) - ); pub const PeriodBasis: BlockNumber = 1000u32; - pub BridgeOrigin: Vec = vec![hex!["306721211d5404bd9da88e0204360a1a9ab8b87c66c1bc2fcdd37f3c2222cc20"].into()]; + pub const DerivativeIndex: u16 = 0; + pub const UnstakeQueueCapacity: u32 = 1000; +} + +pub struct DerivativeProviderT; + +impl DerivativeProvider for DerivativeProviderT { + fn derivative_account_id(who: AccountId, index: u16) -> AccountId { + Utility::derivative_account_id(who, index) + } +} + +parameter_types! { + pub const MaxRewardsPerEra: Balance = 100; + pub const MaxSlashesPerEra: Balance = 1; } impl pallet_liquid_staking::Config for Runtime { type Event = Event; type PalletId = StakingPalletId; - type BridgeOrigin = EnsureSignedBy, AccountId>; type WeightInfo = (); type XcmTransfer = XTokens; - type RelayAgent = RelayAgent; + type SelfParaId = ParachainInfo; type PeriodBasis = PeriodBasis; type BaseXcmWeight = BaseXcmWeight; type Assets = Assets; + type RelayOrigin = EnsureRootOrMoreThanHalfGeneralCouncil; type UpdateOrigin = EnsureRootOrMoreThanHalfGeneralCouncil; + type XcmSender = XcmRouter; + type DerivativeIndex = DerivativeIndex; + type DerivativeProvider = DerivativeProviderT; + type UnstakeQueueCapacity = UnstakeQueueCapacity; + type RelaychainBlockNumberProvider = RelaychainBlockNumberProvider; + type MaxRewardsPerEra = MaxRewardsPerEra; + type MaxSlashesPerEra = MaxSlashesPerEra; + type RelayNetwork = RelayNetwork; } parameter_types! { @@ -697,7 +710,7 @@ impl pallet_xcm::Config for Runtime { type XcmExecutor = XcmExecutor; // Teleporting is disabled. type XcmTeleportFilter = (); - type Weigher = FixedWeightBounds; + type Weigher = FixedWeightBounds; type LocationInverter = LocationInverter; } @@ -795,17 +808,9 @@ pub type XcmOriginToTransactDispatchOrigin = ( ); parameter_types! { - pub UnitWeightCost: Weight = 20_000_000; pub DotPerSecond: (AssetId, u128) = (AssetId::Concrete(MultiLocation::parent()), dot_per_second()); } -parameter_types! { - // 1_000_000_000_000 => 1 unit of asset for 1 unit of Weight. - // TODO Should take the actual weight price. This is just 1_000 DOT per second of weight. - pub WeightPrice: (MultiLocation, u128) = (MultiLocation::parent(), 1_000); - // pub AllowUnpaidFrom: Vec = vec![ X1(Junction::Parent) ]; -} - pub type Barrier = (TakeWeightCredit, AllowTopLevelPaidExecutionFrom); pub struct ToTreasury; @@ -835,7 +840,7 @@ impl Config for XcmConfig { type IsTeleporter = (); type LocationInverter = LocationInverter; type Barrier = Barrier; - type Weigher = FixedWeightBounds; + type Weigher = FixedWeightBounds; type Trader = FixedRateOfFungible; type ResponseHandler = (); // Don't handle responses for now. type SubscriptionService = PolkadotXcm; diff --git a/runtime/vanilla/Cargo.toml b/runtime/vanilla/Cargo.toml index 68c07ec94..cb4f56df5 100644 --- a/runtime/vanilla/Cargo.toml +++ b/runtime/vanilla/Cargo.toml @@ -88,7 +88,7 @@ orml-xtokens = { git = 'https://github.com/open-web3-stack/open-r # Parallel dependencies pallet-amm = { path = '../../pallets/amm', default-features = false } pallet-currency-adapter = { path = '../../pallets/currency-adapter', default-features = false } -pallet-liquid-staking = { path = '../../pallets/liquid-staking-v2', package = 'pallet-liquid-staking-v2', default-features = false } +pallet-liquid-staking = { path = '../../pallets/liquid-staking', default-features = false } pallet-liquidation = { path = '../../pallets/liquidation', default-features = false } pallet-loans = { path = '../../pallets/loans', default-features = false } pallet-loans-rpc-runtime-api = { path = '../../pallets/loans/rpc/runtime-api', default-features = false } diff --git a/runtime/vanilla/src/lib.rs b/runtime/vanilla/src/lib.rs index c046f0fa0..ff0fd58d9 100644 --- a/runtime/vanilla/src/lib.rs +++ b/runtime/vanilla/src/lib.rs @@ -28,14 +28,14 @@ use cumulus_primitives_core::ParaId; use frame_support::{ dispatch::Weight, log, - traits::{fungibles::Mutate, Contains, Everything, IsInVec}, + traits::{fungibles::Mutate, Contains, Everything}, PalletId, }; use frame_system::{ limits::{BlockLength, BlockWeights}, - EnsureOneOf, EnsureRoot, EnsureSignedBy, + EnsureOneOf, EnsureRoot, }; -use hex_literal::hex; + use orml_traits::{DataProvider, DataProviderExtended}; use orml_xcm_support::{IsNativeConcrete, MultiNativeAsset}; use polkadot_parachain::primitives::Sibling; @@ -364,7 +364,7 @@ impl Convert for AccountIdToMultiLocation { parameter_types! { pub SelfLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(ParachainInfo::parachain_id().into()))); - pub const BaseXcmWeight: Weight = 100_000_000; + pub const BaseXcmWeight: Weight = 150_000_000; } impl orml_xtokens::Config for Runtime { @@ -375,7 +375,7 @@ impl orml_xtokens::Config for Runtime { type AccountIdToMultiLocation = AccountIdToMultiLocation; type SelfLocation = SelfLocation; type XcmExecutor = XcmExecutor; - type Weigher = FixedWeightBounds; + type Weigher = FixedWeightBounds; type BaseXcmWeight = BaseXcmWeight; type LocationInverter = LocationInverter; } @@ -419,29 +419,43 @@ impl pallet_loans::Config for Runtime { parameter_types! { pub const StakingPalletId: PalletId = PalletId(*b"par/lqsk"); - pub RelayAgent: MultiLocation = MultiLocation::new( - 1, - X1(AccountId32{ - network: NetworkId::Any, - // Dave - id: hex!["306721211d5404bd9da88e0204360a1a9ab8b87c66c1bc2fcdd37f3c2222cc20"] - }) - ); pub const PeriodBasis: BlockNumber = 1000u32; - pub BridgeAccount: Vec = vec![hex!["306721211d5404bd9da88e0204360a1a9ab8b87c66c1bc2fcdd37f3c2222cc20"].into()]; + pub const DerivativeIndex: u16 = 0; + pub const UnstakeQueueCapacity: u32 = 1000; +} + +pub struct DerivativeProviderT; + +impl DerivativeProvider for DerivativeProviderT { + fn derivative_account_id(who: AccountId, index: u16) -> AccountId { + Utility::derivative_account_id(who, index) + } +} + +parameter_types! { + pub const MaxRewardsPerEra: Balance = 100; + pub const MaxSlashesPerEra: Balance = 1; } impl pallet_liquid_staking::Config for Runtime { type Event = Event; type PalletId = StakingPalletId; - type BridgeOrigin = EnsureSignedBy, AccountId>; + type RelayOrigin = EnsureRootOrMoreThanHalfGeneralCouncil; type UpdateOrigin = EnsureRootOrMoreThanHalfGeneralCouncil; type WeightInfo = (); type XcmTransfer = XTokens; - type RelayAgent = RelayAgent; + type SelfParaId = ParachainInfo; type PeriodBasis = PeriodBasis; type BaseXcmWeight = BaseXcmWeight; type Assets = Assets; + type XcmSender = XcmRouter; + type DerivativeIndex = DerivativeIndex; + type DerivativeProvider = DerivativeProviderT; + type UnstakeQueueCapacity = UnstakeQueueCapacity; + type RelaychainBlockNumberProvider = RelaychainBlockNumberProvider; + type MaxRewardsPerEra = MaxRewardsPerEra; + type MaxSlashesPerEra = MaxSlashesPerEra; + type RelayNetwork = RelayNetwork; } parameter_types! { @@ -676,7 +690,7 @@ impl pallet_xcm::Config for Runtime { type XcmExecutor = XcmExecutor; // Teleporting is disabled. type XcmTeleportFilter = (); - type Weigher = FixedWeightBounds; + type Weigher = FixedWeightBounds; type LocationInverter = LocationInverter; } @@ -718,7 +732,7 @@ impl parachain_info::Config for Runtime {} parameter_types! { pub const RelayLocation: MultiLocation = MultiLocation::parent(); - pub const RelayNetwork: NetworkId = NetworkId::Kusama; + pub RelayNetwork: NetworkId = NetworkId::Named("westend".into()); pub VanillaNetwork: NetworkId = NetworkId::Named("vanilla".into()); pub RelayChainOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into(); pub Ancestry: MultiLocation = MultiLocation::new(0, X1(Parachain(ParachainInfo::parachain_id().into()))); @@ -774,17 +788,9 @@ pub type XcmOriginToTransactDispatchOrigin = ( ); parameter_types! { - pub UnitWeightCost: Weight = 20_000_000; pub KsmPerSecond: (AssetId, u128) = (AssetId::Concrete(MultiLocation::parent()), ksm_per_second()); } -parameter_types! { - // 1_000_000_000_000 => 1 unit of asset for 1 unit of Weight. - // TODO Should take the actual weight price. This is just 1_000 KSM per second of weight. - pub const WeightPrice: (MultiLocation, u128) = (MultiLocation::parent(), 1_000); - // pub AllowUnpaidFrom: Vec = vec![ MultiLocation::parent() ]; -} - pub type Barrier = (TakeWeightCredit, AllowTopLevelPaidExecutionFrom); pub struct ToTreasury; @@ -814,7 +820,7 @@ impl Config for XcmConfig { type IsTeleporter = (); type LocationInverter = LocationInverter; type Barrier = Barrier; - type Weigher = FixedWeightBounds; + type Weigher = FixedWeightBounds; type Trader = FixedRateOfFungible; type ResponseHandler = (); // Don't handle responses for now. type SubscriptionService = PolkadotXcm; diff --git a/rust-toolchain b/rust-toolchain index 86993b8ba..916f7a706 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2021-09-06 +nightly-2021-09-29