From 0224470547050db78d94778e90e90dab35a7e3e5 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Mon, 19 Sep 2022 18:02:52 +0200 Subject: [PATCH 01/58] feat(lend): add lending protocol crates --- crates/currency-adapter/Cargo.toml | 31 + crates/currency-adapter/src/lib.rs | 221 ++ crates/loans/Cargo.toml | 60 + crates/loans/rpc/Cargo.toml | 21 + crates/loans/rpc/runtime-api/Cargo.toml | 18 + crates/loans/rpc/runtime-api/src/lib.rs | 29 + crates/loans/rpc/src/lib.rs | 201 ++ crates/loans/src/benchmarking.rs | 452 ++++ crates/loans/src/farming.rs | 216 ++ crates/loans/src/interest.rs | 214 ++ crates/loans/src/lib.rs | 2219 ++++++++++++++++++++ crates/loans/src/migrations.rs | 190 ++ crates/loans/src/mock.rs | 478 +++++ crates/loans/src/ptoken.rs | 232 ++ crates/loans/src/rate_model.rs | 273 +++ crates/loans/src/tests.rs | 1382 ++++++++++++ crates/loans/src/tests/edge_cases.rs | 135 ++ crates/loans/src/tests/interest_rate.rs | 344 +++ crates/loans/src/tests/liquidate_borrow.rs | 279 +++ crates/loans/src/tests/market.rs | 422 ++++ crates/loans/src/tests/ptokens.rs | 185 ++ crates/loans/src/types.rs | 78 + crates/loans/src/weights.rs | 654 ++++++ crates/traits/Cargo.toml | 53 + crates/traits/src/lib.rs | 252 +++ crates/traits/src/loans.rs | 89 + crates/traits/src/ump.rs | 340 +++ crates/traits/src/xcm.rs | 504 +++++ primitives/src/tokens.rs | 204 ++ 29 files changed, 9776 insertions(+) create mode 100644 crates/currency-adapter/Cargo.toml create mode 100644 crates/currency-adapter/src/lib.rs create mode 100644 crates/loans/Cargo.toml create mode 100644 crates/loans/rpc/Cargo.toml create mode 100644 crates/loans/rpc/runtime-api/Cargo.toml create mode 100644 crates/loans/rpc/runtime-api/src/lib.rs create mode 100644 crates/loans/rpc/src/lib.rs create mode 100644 crates/loans/src/benchmarking.rs create mode 100644 crates/loans/src/farming.rs create mode 100644 crates/loans/src/interest.rs create mode 100644 crates/loans/src/lib.rs create mode 100644 crates/loans/src/migrations.rs create mode 100644 crates/loans/src/mock.rs create mode 100644 crates/loans/src/ptoken.rs create mode 100644 crates/loans/src/rate_model.rs create mode 100644 crates/loans/src/tests.rs create mode 100644 crates/loans/src/tests/edge_cases.rs create mode 100644 crates/loans/src/tests/interest_rate.rs create mode 100644 crates/loans/src/tests/liquidate_borrow.rs create mode 100644 crates/loans/src/tests/market.rs create mode 100644 crates/loans/src/tests/ptokens.rs create mode 100644 crates/loans/src/types.rs create mode 100644 crates/loans/src/weights.rs create mode 100644 crates/traits/Cargo.toml create mode 100644 crates/traits/src/lib.rs create mode 100644 crates/traits/src/loans.rs create mode 100644 crates/traits/src/ump.rs create mode 100644 crates/traits/src/xcm.rs create mode 100644 primitives/src/tokens.rs diff --git a/crates/currency-adapter/Cargo.toml b/crates/currency-adapter/Cargo.toml new file mode 100644 index 0000000000..d741f8f768 --- /dev/null +++ b/crates/currency-adapter/Cargo.toml @@ -0,0 +1,31 @@ +[package] +authors = ['Parallel Team'] +edition = '2021' +name = 'pallet-currency-adapter' +version = '1.9.3' + +[package.metadata.docs.rs] +targets = ['x86_64-unknown-linux-gnu'] + +[dependencies] +codec = { package = 'parity-scale-codec', version = '3.1.5', features = ['max-encoded-len'], default-features = false } +frame-support = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +frame-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +primitives = { package = 'parallel-primitives', path = '../../primitives', default-features = false } +scale-info = { version = '2.1', default-features = false, features = ['derive'] } +sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } + +[features] +default = ['std'] +std = [ + 'codec/std', + 'frame-support/std', + 'frame-system/std', + 'sp-runtime/std', + 'scale-info/std', + 'primitives/std', +] +try-runtime = ['frame-support/try-runtime'] + +[lib] +doctest = false diff --git a/crates/currency-adapter/src/lib.rs b/crates/currency-adapter/src/lib.rs new file mode 100644 index 0000000000..43f87e5ee2 --- /dev/null +++ b/crates/currency-adapter/src/lib.rs @@ -0,0 +1,221 @@ +// 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. + +//! # Currency adapter pallet +//! +//! ## Overview +//! +//! This pallet works like a bridge between pallet-balances & pallet-assets + +#![cfg_attr(not(feature = "std"), no_std)] + +pub use pallet::*; + +use frame_support::{ + dispatch::DispatchResult, + pallet_prelude::*, + traits::{ + tokens::{ + fungible::{Inspect, Mutate, Transfer}, + fungibles::{Inspect as Inspects, Mutate as Mutates, Transfer as Transfers}, + DepositConsequence, WithdrawConsequence, + }, + Get, LockIdentifier, WithdrawReasons, + }, +}; +use primitives::{Balance, CurrencyId}; +use sp_runtime::DispatchError; + +type AssetIdOf = + <::Assets as Inspects<::AccountId>>::AssetId; +type BalanceOf = + <::Assets as Inspects<::AccountId>>::Balance; + +const CURRENCY_ADAPTER_ID: LockIdentifier = *b"cadapter"; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::traits::LockableCurrency; + use frame_system::pallet_prelude::OriginFor; + + #[pallet::config] + pub trait Config: frame_system::Config { + type Assets: Transfers + + Inspects + + Mutates; + + type Balances: Inspect + + Mutate + + Transfer + + LockableCurrency; + + #[pallet::constant] + type GetNativeCurrencyId: Get>; + + // Origin which can lock asset balance + type LockOrigin: EnsureOrigin<::Origin>; + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::error] + pub enum Error { + /// Not a native token + NotANativeToken, + } + + #[pallet::call] + impl Pallet { + #[pallet::weight(10_000)] + pub fn force_set_lock( + origin: OriginFor, + asset: AssetIdOf, + who: T::AccountId, + #[pallet::compact] amount: BalanceOf, + ) -> DispatchResult { + T::LockOrigin::ensure_origin(origin)?; + ensure!( + asset == T::GetNativeCurrencyId::get(), + Error::::NotANativeToken + ); + T::Balances::set_lock(CURRENCY_ADAPTER_ID, &who, amount, WithdrawReasons::all()); + Ok(()) + } + + #[pallet::weight(10_000)] + pub fn force_remove_lock( + origin: OriginFor, + asset: AssetIdOf, + who: T::AccountId, + ) -> DispatchResult { + T::LockOrigin::ensure_origin(origin)?; + ensure!( + asset == T::GetNativeCurrencyId::get(), + Error::::NotANativeToken + ); + T::Balances::remove_lock(CURRENCY_ADAPTER_ID, &who); + Ok(()) + } + } +} + +impl Inspects for Pallet { + type AssetId = AssetIdOf; + type Balance = BalanceOf; + + fn total_issuance(asset: Self::AssetId) -> Self::Balance { + if asset == T::GetNativeCurrencyId::get() { + T::Balances::total_issuance() + } else { + T::Assets::total_issuance(asset) + } + } + + fn minimum_balance(asset: Self::AssetId) -> Self::Balance { + if asset == T::GetNativeCurrencyId::get() { + T::Balances::minimum_balance() + } else { + T::Assets::minimum_balance(asset) + } + } + + fn balance(asset: Self::AssetId, who: &T::AccountId) -> Self::Balance { + if asset == T::GetNativeCurrencyId::get() { + T::Balances::balance(who) + } else { + T::Assets::balance(asset, who) + } + } + + fn reducible_balance( + asset: Self::AssetId, + who: &T::AccountId, + keep_alive: bool, + ) -> Self::Balance { + if asset == T::GetNativeCurrencyId::get() { + T::Balances::reducible_balance(who, keep_alive) + } else { + T::Assets::reducible_balance(asset, who, keep_alive) + } + } + + fn can_deposit( + asset: Self::AssetId, + who: &T::AccountId, + amount: Self::Balance, + mint: bool, + ) -> DepositConsequence { + if asset == T::GetNativeCurrencyId::get() { + T::Balances::can_deposit(who, amount, mint) + } else { + T::Assets::can_deposit(asset, who, amount, mint) + } + } + + fn can_withdraw( + asset: Self::AssetId, + who: &T::AccountId, + amount: Self::Balance, + ) -> WithdrawConsequence { + if asset == T::GetNativeCurrencyId::get() { + T::Balances::can_withdraw(who, amount) + } else { + T::Assets::can_withdraw(asset, who, amount) + } + } +} + +impl Mutates for Pallet { + fn mint_into( + asset: Self::AssetId, + who: &T::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + if asset == T::GetNativeCurrencyId::get() { + T::Balances::mint_into(who, amount) + } else { + T::Assets::mint_into(asset, who, amount) + } + } + + fn burn_from( + asset: Self::AssetId, + who: &T::AccountId, + amount: Self::Balance, + ) -> Result { + if asset == T::GetNativeCurrencyId::get() { + T::Balances::burn_from(who, amount) + } else { + T::Assets::burn_from(asset, who, amount) + } + } +} + +impl Transfers for Pallet { + fn transfer( + asset: Self::AssetId, + source: &T::AccountId, + dest: &T::AccountId, + amount: Self::Balance, + keep_alive: bool, + ) -> Result { + if asset == T::GetNativeCurrencyId::get() { + T::Balances::transfer(source, dest, amount, keep_alive) + } else { + T::Assets::transfer(asset, source, dest, amount, keep_alive) + } + } +} diff --git a/crates/loans/Cargo.toml b/crates/loans/Cargo.toml new file mode 100644 index 0000000000..3d17f85cff --- /dev/null +++ b/crates/loans/Cargo.toml @@ -0,0 +1,60 @@ +[package] +authors = ['Parallel Team'] +edition = '2021' +name = 'pallet-loans' +version = '1.9.3' + +[package.metadata.docs.rs] +targets = ['x86_64-unknown-linux-gnu'] + +[dependencies] +codec = { package = 'parity-scale-codec', version = '3.1.5', default-features = false } +frame-benchmarking = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false, optional = true } +frame-support = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +frame-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +num-traits = { default-features = false, version = '0.2' } +orml-traits = { version = '0.4.1-dev', default-features = false } +pallet-assets = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +pallet-balances = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +pallet-prices = { path = '../prices', default-features = false } +pallet-timestamp = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +pallet-traits = { path = '../traits', default-features = false } +primitives = { package = 'parallel-primitives', path = '../../primitives', default-features = false } +scale-info = { version = '2.1', default-features = false, features = ['derive'] } +serde = { version = '1.0.136', features = ['derive'], optional = true } +sp-io = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +sp-std = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } + +[dev-dependencies] +orml-oracle = { version = '0.4.1-dev' } +pallet-amm = { path = '../amm' } +pallet-currency-adapter = { path = '../currency-adapter' } +sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28' } + +[features] +default = ['std'] +runtime-benchmarks = ['frame-benchmarking'] +std = [ + 'codec/std', + 'frame-support/std', + 'frame-system/std', + 'frame-benchmarking/std', + 'orml-traits/std', + 'primitives/std', + 'sp-runtime/std', + 'sp-std/std', + 'sp-io/std', + 'pallet-assets/std', + 'pallet-prices/std', + 'pallet-balances/std', + 'pallet-timestamp/std', + 'serde', + 'scale-info/std', + 'num-traits/std', + 'pallet-traits/std', +] +try-runtime = ['frame-support/try-runtime'] + +[lib] +doctest = false diff --git a/crates/loans/rpc/Cargo.toml b/crates/loans/rpc/Cargo.toml new file mode 100644 index 0000000000..d56b6b036c --- /dev/null +++ b/crates/loans/rpc/Cargo.toml @@ -0,0 +1,21 @@ +[package] +authors = ['Parallel Team'] +edition = '2021' +name = 'pallet-loans-rpc' +version = '1.9.3' + +[dependencies] +codec = { package = 'parity-scale-codec', version = '3.1.5' } +jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } +primitives = { package = 'parallel-primitives', path = '../../../primitives', default-features = false } +serde = { version = '1.0.136', features = ['derive'] } +sp-api = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28' } +sp-blockchain = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28' } +sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28' } +sp-rpc = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28' } + +pallet-loans-rpc-runtime-api = { path = 'runtime-api', default-features = false } + +[lib] +doctest = false diff --git a/crates/loans/rpc/runtime-api/Cargo.toml b/crates/loans/rpc/runtime-api/Cargo.toml new file mode 100644 index 0000000000..55ddee224e --- /dev/null +++ b/crates/loans/rpc/runtime-api/Cargo.toml @@ -0,0 +1,18 @@ +[package] +authors = ['Parallel Team'] +edition = '2021' +name = 'pallet-loans-rpc-runtime-api' +version = '1.9.3' + +[dependencies] +codec = { package = 'parity-scale-codec', version = '3.1.5', default-features = false, features = ['derive'] } +primitives = { package = 'parallel-primitives', path = '../../../../primitives', default-features = false } +sp-api = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } + +[features] +default = ['std'] +std = ['codec/std', 'sp-api/std', 'sp-runtime/std'] + +[lib] +doctest = false diff --git a/crates/loans/rpc/runtime-api/src/lib.rs b/crates/loans/rpc/runtime-api/src/lib.rs new file mode 100644 index 0000000000..4530b907e3 --- /dev/null +++ b/crates/loans/rpc/runtime-api/src/lib.rs @@ -0,0 +1,29 @@ +// 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. + +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::Codec; +use primitives::{CurrencyId, Liquidity, Rate, Ratio, Shortfall}; +use sp_runtime::{DispatchError, FixedU128}; + +sp_api::decl_runtime_apis! { + pub trait LoansApi where + AccountId: Codec, + Balance: Codec { + fn get_account_liquidity(account: AccountId) -> Result<(Liquidity, Shortfall, Liquidity, Shortfall), DispatchError>; + fn get_market_status(asset_id: CurrencyId) -> Result<(Rate, Rate, Rate, Ratio, Balance, Balance, FixedU128), DispatchError>; + fn get_liquidation_threshold_liquidity(account: AccountId) -> Result<(Liquidity, Shortfall, Liquidity, Shortfall), DispatchError>; + } +} diff --git a/crates/loans/rpc/src/lib.rs b/crates/loans/rpc/src/lib.rs new file mode 100644 index 0000000000..fc7fa1bfc7 --- /dev/null +++ b/crates/loans/rpc/src/lib.rs @@ -0,0 +1,201 @@ +// 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. + +use std::sync::Arc; + +pub use pallet_loans_rpc_runtime_api::LoansApi as LoansRuntimeApi; + +use codec::Codec; +use jsonrpsee::{ + core::{async_trait, Error as JsonRpseeError, RpcResult}, + proc_macros::rpc, + types::error::{CallError, ErrorCode, ErrorObject}, +}; +use primitives::{CurrencyId, Liquidity, Rate, Ratio, Shortfall}; +use sp_api::ProvideRuntimeApi; +use sp_blockchain::HeaderBackend; +use sp_rpc::number::NumberOrHex; +use sp_runtime::{generic::BlockId, traits::Block as BlockT, FixedU128}; + +#[rpc(client, server)] +pub trait LoansApi +where + Balance: Codec + Copy + TryFrom, +{ + #[method(name = "loans_getCollateralLiquidity")] + fn get_account_liquidity( + &self, + account: AccountId, + at: Option, + ) -> RpcResult<(Liquidity, Shortfall, Liquidity, Shortfall)>; + #[method(name = "loans_getMarketStatus")] + fn get_market_status( + &self, + asset_id: CurrencyId, + at: Option, + ) -> RpcResult<(Rate, Rate, Rate, Ratio, NumberOrHex, NumberOrHex, FixedU128)>; + #[method(name = "loans_getLiquidationThresholdLiquidity")] + fn get_liquidation_threshold_liquidity( + &self, + account: AccountId, + at: Option, + ) -> RpcResult<(Liquidity, Shortfall, Liquidity, Shortfall)>; +} + +/// A struct that implements the [`LoansApi`]. +pub struct Loans { + client: Arc, + _marker: std::marker::PhantomData, +} + +impl Loans { + /// Create new `Loans` with the given reference to the client. + pub fn new(client: Arc) -> Self { + Self { + client, + _marker: Default::default(), + } + } +} + +pub enum Error { + RuntimeError, + AccountLiquidityError, + MarketStatusError, +} + +impl From for i32 { + fn from(e: Error) -> i32 { + match e { + Error::RuntimeError => 1, + Error::AccountLiquidityError => 2, + Error::MarketStatusError => 3, + } + } +} + +#[async_trait] +impl LoansApiServer<::Hash, AccountId, Balance> + for Loans +where + Block: BlockT, + C: Send + Sync + 'static, + C: ProvideRuntimeApi, + C: HeaderBackend, + C::Api: LoansRuntimeApi, + AccountId: Codec, + Balance: Codec + Copy + TryFrom + Into + std::fmt::Display, +{ + fn get_account_liquidity( + &self, + account: AccountId, + at: Option<::Hash>, + ) -> RpcResult<(Liquidity, Shortfall, Liquidity, Shortfall)> { + let api = self.client.runtime_api(); + let at = BlockId::hash(at.unwrap_or( + // If the block hash is not supplied assume the best block. + self.client.info().best_hash, + )); + api.get_account_liquidity(&at, account) + .map_err(runtime_error_into_rpc_error)? + .map_err(account_liquidity_error_into_rpc_error) + } + + fn get_market_status( + &self, + asset_id: CurrencyId, + at: Option<::Hash>, + ) -> RpcResult<(Rate, Rate, Rate, Ratio, NumberOrHex, NumberOrHex, FixedU128)> { + let api = self.client.runtime_api(); + let at = BlockId::hash(at.unwrap_or( + // If the block hash is not supplied assume the best block. + self.client.info().best_hash, + )); + let ( + borrow_rate, + supply_rate, + exchange_rate, + util, + total_borrows, + total_reserves, + borrow_index, + ) = api + .get_market_status(&at, asset_id) + .map_err(runtime_error_into_rpc_error)? + .map_err(market_status_error_into_rpc_error)?; + Ok(( + borrow_rate, + supply_rate, + exchange_rate, + util, + try_into_rpc_balance(total_borrows)?, + try_into_rpc_balance(total_reserves)?, + borrow_index, + )) + } + + fn get_liquidation_threshold_liquidity( + &self, + account: AccountId, + at: Option<::Hash>, + ) -> RpcResult<(Liquidity, Shortfall, Liquidity, Shortfall)> { + let api = self.client.runtime_api(); + let at = BlockId::hash(at.unwrap_or( + // If the block hash is not supplied assume the best block. + self.client.info().best_hash, + )); + api.get_liquidation_threshold_liquidity(&at, account) + .map_err(runtime_error_into_rpc_error)? + .map_err(account_liquidity_error_into_rpc_error) + } +} + +/// Converts a runtime trap into an RPC error. +fn runtime_error_into_rpc_error(err: impl std::fmt::Debug) -> JsonRpseeError { + JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( + Error::RuntimeError.into(), + "Runtime trapped", + Some(format!("{:?}", err)), + ))) +} + +/// Converts an account liquidity error into an RPC error. +fn account_liquidity_error_into_rpc_error(err: impl std::fmt::Debug) -> JsonRpseeError { + JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( + Error::AccountLiquidityError.into(), + "Not able to get account liquidity", + Some(format!("{:?}", err)), + ))) +} + +/// Converts an market status error into an RPC error. +fn market_status_error_into_rpc_error(err: impl std::fmt::Debug) -> JsonRpseeError { + JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( + Error::MarketStatusError.into(), + "Not able to get market status", + Some(format!("{:?}", err)), + ))) +} + +fn try_into_rpc_balance>( + value: T, +) -> RpcResult { + value.try_into().map_err(|_| { + JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( + ErrorCode::InvalidParams.code(), + format!("{} doesn't fit in NumberOrHex representation", value), + None::<()>, + ))) + }) +} diff --git a/crates/loans/src/benchmarking.rs b/crates/loans/src/benchmarking.rs new file mode 100644 index 0000000000..7e9ea937c7 --- /dev/null +++ b/crates/loans/src/benchmarking.rs @@ -0,0 +1,452 @@ +//! Loans pallet benchmarking. + +#![cfg(feature = "runtime-benchmarks")] +use super::*; +use crate::{AccountBorrows, Pallet as Loans}; + +use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller}; +use frame_support::assert_ok; +use frame_system::{self, RawOrigin as SystemOrigin}; +use primitives::{ + tokens::{CDOT_6_13, DOT, KSM, PKSM, PSKSM, PUSDT, SKSM, USDT}, + Balance, CurrencyId, +}; +use rate_model::{InterestRateModel, JumpModel}; +use sp_std::prelude::*; + +const SEED: u32 = 0; + +const RATE_MODEL_MOCK: InterestRateModel = InterestRateModel::Jump(JumpModel { + base_rate: Rate::from_inner(Rate::DIV / 100 * 2), + jump_rate: Rate::from_inner(Rate::DIV / 100 * 10), + full_rate: Rate::from_inner(Rate::DIV / 100 * 32), + jump_utilization: Ratio::from_percent(80), +}); + +fn market_mock() -> Market> { + Market { + close_factor: Ratio::from_percent(50), + collateral_factor: Ratio::from_percent(50), + liquidation_threshold: Ratio::from_percent(55), + liquidate_incentive: Rate::from_inner(Rate::DIV / 100 * 110), + state: MarketState::Active, + rate_model: InterestRateModel::Jump(JumpModel { + base_rate: Rate::from_inner(Rate::DIV / 100 * 2), + jump_rate: Rate::from_inner(Rate::DIV / 100 * 10), + full_rate: Rate::from_inner(Rate::DIV / 100 * 32), + jump_utilization: Ratio::from_percent(80), + }), + reserve_factor: Ratio::from_percent(15), + liquidate_incentive_reserved_factor: Ratio::from_percent(3), + supply_cap: 1_000_000_000_000_000_000_000u128, // set to 1B + borrow_cap: 1_000_000_000_000_000_000_000u128, // set to 1B + ptoken_id: 1200, + } +} + +fn pending_market_mock(ptoken_id: CurrencyId) -> Market> { + let mut market = market_mock::(); + market.state = MarketState::Pending; + market.ptoken_id = ptoken_id; + market +} + +const INITIAL_AMOUNT: u32 = 500_000_000; + +fn transfer_initial_balance< + T: Config + + pallet_assets::Config + + pallet_prices::Config + + pallet_balances::Config, +>( + caller: T::AccountId, +) { + let account_id = T::Lookup::unlookup(caller.clone()); + pallet_assets::Pallet::::force_create( + SystemOrigin::Root.into(), + KSM, + account_id.clone(), + true, + 1, + ) + .ok(); + pallet_assets::Pallet::::force_create( + SystemOrigin::Root.into(), + SKSM, + account_id.clone(), + true, + 1, + ) + .ok(); + pallet_assets::Pallet::::force_create( + SystemOrigin::Root.into(), + DOT, + account_id.clone(), + true, + 1, + ) + .ok(); + pallet_assets::Pallet::::force_create( + SystemOrigin::Root.into(), + CDOT_6_13, + account_id.clone(), + true, + 1, + ) + .ok(); + pallet_assets::Pallet::::force_create( + SystemOrigin::Root.into(), + USDT, + account_id.clone(), + true, + 1, + ) + .ok(); + pallet_assets::Pallet::::force_set_metadata( + SystemOrigin::Root.into(), + KSM, + b"kusama".to_vec(), + b"KSM".to_vec(), + 12, + true, + ) + .ok(); + pallet_assets::Pallet::::force_set_metadata( + SystemOrigin::Root.into(), + SKSM, + b"xkusama".to_vec(), + b"sKSM".to_vec(), + 12, + true, + ) + .ok(); + pallet_assets::Pallet::::force_set_metadata( + SystemOrigin::Root.into(), + DOT, + b"polkadot".to_vec(), + b"DOT".to_vec(), + 12, + true, + ) + .ok(); + pallet_assets::Pallet::::force_set_metadata( + SystemOrigin::Root.into(), + CDOT_6_13, + b"cDot_6_13".to_vec(), + b"cDot_6_13".to_vec(), + 12, + true, + ) + .ok(); + pallet_assets::Pallet::::force_set_metadata( + SystemOrigin::Root.into(), + USDT, + b"tether".to_vec(), + b"USDT".to_vec(), + 6, + true, + ) + .ok(); + pallet_balances::Pallet::::set_balance( + SystemOrigin::Root.into(), + account_id, + 10_000_000_000_000_u128, + 0_u128, + ) + .unwrap(); + ::Assets::mint_into(USDT, &caller, INITIAL_AMOUNT.into()).unwrap(); + ::Assets::mint_into(KSM, &caller, INITIAL_AMOUNT.into()).unwrap(); + ::Assets::mint_into(SKSM, &caller, INITIAL_AMOUNT.into()).unwrap(); + ::Assets::mint_into(DOT, &caller, INITIAL_AMOUNT.into()).unwrap(); + ::Assets::mint_into(CDOT_6_13, &caller, INITIAL_AMOUNT.into()).unwrap(); + pallet_prices::Pallet::::set_price(SystemOrigin::Root.into(), USDT, 1.into()).unwrap(); + pallet_prices::Pallet::::set_price(SystemOrigin::Root.into(), KSM, 1.into()).unwrap(); + pallet_prices::Pallet::::set_price(SystemOrigin::Root.into(), SKSM, 1.into()).unwrap(); + pallet_prices::Pallet::::set_price(SystemOrigin::Root.into(), DOT, 1.into()).unwrap(); + pallet_prices::Pallet::::set_price(SystemOrigin::Root.into(), CDOT_6_13, 1.into()).unwrap(); +} + +fn set_account_borrows( + who: T::AccountId, + asset_id: AssetIdOf, + borrow_balance: BalanceOf, +) { + AccountBorrows::::insert( + asset_id, + &who, + BorrowSnapshot { + principal: borrow_balance, + borrow_index: Rate::one(), + }, + ); + TotalBorrows::::insert(asset_id, borrow_balance); + T::Assets::burn_from(asset_id, &who, borrow_balance).unwrap(); +} + +fn assert_last_event(generic_event: ::Event) { + frame_system::Pallet::::assert_last_event(generic_event.into()); +} + +benchmarks! { + where_clause { + where + T: pallet_assets::Config + pallet_prices::Config + pallet_balances::Config + } + + add_market { + }: _(SystemOrigin::Root, SKSM, pending_market_mock::(PSKSM)) + verify { + assert_last_event::(Event::::NewMarket(SKSM, pending_market_mock::(PSKSM)).into()); + } + + activate_market { + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), SKSM, pending_market_mock::(PSKSM))); + }: _(SystemOrigin::Root, SKSM) + verify { + assert_last_event::(Event::::ActivatedMarket(SKSM).into()); + } + + update_rate_model { + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(PUSDT))); + }: _(SystemOrigin::Root, USDT, RATE_MODEL_MOCK) + verify { + let mut market = pending_market_mock::(PUSDT); + market.rate_model = RATE_MODEL_MOCK; + assert_last_event::(Event::::UpdatedMarket(USDT, market).into()); + } + + update_market { + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KSM, pending_market_mock::(PKSM))); + }: _( + SystemOrigin::Root, + KSM, + Some(Ratio::from_percent(50)), + Some(Ratio::from_percent(55)), + Some(Ratio::from_percent(50)), + Some(Ratio::from_percent(15)), + Some(Ratio::from_percent(3)), + Some(Rate::from_inner(Rate::DIV / 100 * 110)), + Some(1_000_000_000_000_000_000_000u128), + Some(1_000_000_000_000_000_000_000u128) + ) + verify { + let mut market = pending_market_mock::(PKSM); + market.reserve_factor = Ratio::from_percent(50); + market.close_factor = Ratio::from_percent(15); + assert_last_event::(Event::::UpdatedMarket(KSM, market).into()); + } + + force_update_market { + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(PUSDT))); + }: _(SystemOrigin::Root,USDT, pending_market_mock::(PUSDT)) + verify { + assert_last_event::(Event::::UpdatedMarket(USDT, pending_market_mock::(PUSDT)).into()); + } + + add_reward { + let caller: T::AccountId = whitelisted_caller(); + transfer_initial_balance::(caller.clone()); + }: _(SystemOrigin::Signed(caller.clone()), 1_000_000_000_000_u128) + verify { + assert_last_event::(Event::::RewardAdded(caller, 1_000_000_000_000_u128).into()); + } + + withdraw_missing_reward { + let caller: T::AccountId = whitelisted_caller(); + transfer_initial_balance::(caller.clone()); + assert_ok!(Loans::::add_reward(SystemOrigin::Signed(caller.clone()).into(), 1_000_000_000_000_u128)); + let receiver = T::Lookup::unlookup(caller.clone()); + }: _(SystemOrigin::Root, receiver, 500_000_000_000_u128) + verify { + assert_last_event::(Event::::RewardWithdrawn(caller, 500_000_000_000_u128).into()); + } + + update_market_reward_speed { + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(USDT))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); + }: _(SystemOrigin::Root, USDT, Some(1_000_000), Some(1_000_000)) + verify { + assert_last_event::(Event::::MarketRewardSpeedUpdated(USDT, 1_000_000, 1_000_000).into()); + } + + claim_reward { + let caller: T::AccountId = whitelisted_caller(); + transfer_initial_balance::(caller.clone()); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(USDT))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); + assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), USDT, 100_000_000)); + assert_ok!(Loans::::add_reward(SystemOrigin::Signed(caller.clone()).into(), 1_000_000_000_000_u128)); + assert_ok!(Loans::::update_market_reward_speed(SystemOrigin::Root.into(), USDT, Some(1_000_000), Some(1_000_000))); + let target_height = frame_system::Pallet::::block_number().saturating_add(One::one()); + frame_system::Pallet::::set_block_number(target_height); + }: _(SystemOrigin::Signed(caller.clone())) + verify { + assert_last_event::(Event::::RewardPaid(caller, 1_000_000).into()); + } + + claim_reward_for_market { + let caller: T::AccountId = whitelisted_caller(); + transfer_initial_balance::(caller.clone()); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(USDT))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); + assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), USDT, 100_000_000)); + assert_ok!(Loans::::add_reward(SystemOrigin::Signed(caller.clone()).into(), 1_000_000_000_000_u128)); + assert_ok!(Loans::::update_market_reward_speed(SystemOrigin::Root.into(), USDT, Some(1_000_000), Some(1_000_000))); + let target_height = frame_system::Pallet::::block_number().saturating_add(One::one()); + frame_system::Pallet::::set_block_number(target_height); + }: _(SystemOrigin::Signed(caller.clone()), USDT) + verify { + assert_last_event::(Event::::RewardPaid(caller, 1_000_000).into()); + } + + + mint { + let caller: T::AccountId = whitelisted_caller(); + transfer_initial_balance::(caller.clone()); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(USDT))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); + let amount: u32 = 100_000; + }: _(SystemOrigin::Signed(caller.clone()), USDT, amount.into()) + verify { + assert_last_event::(Event::::Deposited(caller, USDT, amount.into()).into()); + } + + borrow { + let caller: T::AccountId = whitelisted_caller(); + transfer_initial_balance::(caller.clone()); + let deposit_amount: u32 = 200_000_000; + let borrowed_amount: u32 = 100_000_000; + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(PUSDT))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); + assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), USDT, deposit_amount.into())); + assert_ok!(Loans::::collateral_asset(SystemOrigin::Signed(caller.clone()).into(), USDT, true)); + }: _(SystemOrigin::Signed(caller.clone()), USDT, borrowed_amount.into()) + verify { + assert_last_event::(Event::::Borrowed(caller, USDT, borrowed_amount.into()).into()); + } + + redeem { + let caller: T::AccountId = whitelisted_caller(); + transfer_initial_balance::(caller.clone()); + let deposit_amount: u32 = 100_000_000; + let redeem_amount: u32 = 100_000; + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(PUSDT))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); + assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), USDT, deposit_amount.into())); + }: _(SystemOrigin::Signed(caller.clone()), USDT, redeem_amount.into()) + verify { + assert_last_event::(Event::::Redeemed(caller, USDT, redeem_amount.into()).into()); + } + + redeem_all { + let caller: T::AccountId = whitelisted_caller(); + transfer_initial_balance::(caller.clone()); + let deposit_amount: u32 = 100_000_000; + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(PUSDT))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); + assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), USDT, deposit_amount.into())); + }: _(SystemOrigin::Signed(caller.clone()), USDT) + verify { + assert_last_event::(Event::::Redeemed(caller, USDT, deposit_amount.into()).into()); + } + + repay_borrow { + let caller: T::AccountId = whitelisted_caller(); + transfer_initial_balance::(caller.clone()); + let deposit_amount: u32 = 200_000_000; + let borrowed_amount: u32 = 100_000_000; + let repay_amount: u32 = 100; + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(PUSDT))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); + assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), USDT, deposit_amount.into())); + assert_ok!(Loans::::collateral_asset(SystemOrigin::Signed(caller.clone()).into(), USDT, true)); + assert_ok!(Loans::::borrow(SystemOrigin::Signed(caller.clone()).into(), USDT, borrowed_amount.into())); + }: _(SystemOrigin::Signed(caller.clone()), USDT, repay_amount.into()) + verify { + assert_last_event::(Event::::RepaidBorrow(caller, USDT, repay_amount.into()).into()); + } + + repay_borrow_all { + let caller: T::AccountId = whitelisted_caller(); + transfer_initial_balance::(caller.clone()); + let deposit_amount: u32 = 200_000_000; + let borrowed_amount: u32 = 100_000_000; + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(PUSDT))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); + assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), USDT, deposit_amount.into())); + assert_ok!(Loans::::collateral_asset(SystemOrigin::Signed(caller.clone()).into(), USDT, true)); + assert_ok!(Loans::::borrow(SystemOrigin::Signed(caller.clone()).into(), USDT, borrowed_amount.into())); + }: _(SystemOrigin::Signed(caller.clone()), USDT) + verify { + assert_last_event::(Event::::RepaidBorrow(caller, USDT, borrowed_amount.into()).into()); + } + + collateral_asset { + let caller: T::AccountId = whitelisted_caller(); + transfer_initial_balance::(caller.clone()); + let deposit_amount: u32 = 200_000_000; + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(PUSDT))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); + assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), USDT, deposit_amount.into())); + }: _(SystemOrigin::Signed(caller.clone()), USDT, true) + verify { + assert_last_event::(Event::::CollateralAssetAdded(caller, USDT).into()); + } + + liquidate_borrow { + let alice: T::AccountId = account("Sample", 100, SEED); + let bob: T::AccountId = account("Sample", 101, SEED); + transfer_initial_balance::(alice.clone()); + transfer_initial_balance::(bob.clone()); + let deposit_amount: u32 = 200_000_000; + let borrowed_amount: u32 = 200_000_000; + let liquidate_amount: u32 = 100_000_000; + let incentive_amount: u32 = 110_000_000; + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), SKSM, pending_market_mock::(PSKSM))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), SKSM)); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KSM, pending_market_mock::(PKSM))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KSM)); + assert_ok!(Loans::::mint(SystemOrigin::Signed(bob.clone()).into(), KSM, deposit_amount.into())); + assert_ok!(Loans::::mint(SystemOrigin::Signed(alice.clone()).into(), SKSM, deposit_amount.into())); + assert_ok!(Loans::::collateral_asset(SystemOrigin::Signed(alice.clone()).into(), SKSM, true)); + set_account_borrows::(alice.clone(), KSM, borrowed_amount.into()); + }: _(SystemOrigin::Signed(bob.clone()), alice.clone(), KSM, liquidate_amount.into(), SKSM) + verify { + assert_last_event::(Event::::LiquidatedBorrow(bob.clone(), alice.clone(), KSM, SKSM, liquidate_amount.into(), incentive_amount.into()).into()); + } + + add_reserves { + let caller: T::AccountId = whitelisted_caller(); + let payer = T::Lookup::unlookup(caller.clone()); + transfer_initial_balance::(caller.clone()); + let amount: u32 = 2000; + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(PUSDT))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); + }: _(SystemOrigin::Root, payer, USDT, amount.into()) + verify { + assert_last_event::(Event::::ReservesAdded(caller, USDT, amount.into(), amount.into()).into()); + } + + reduce_reserves { + let caller: T::AccountId = whitelisted_caller(); + let payer = T::Lookup::unlookup(caller.clone()); + transfer_initial_balance::(caller.clone()); + let add_amount: u32 = 2000; + let reduce_amount: u32 = 1000; + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(PUSDT))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); + assert_ok!(Loans::::add_reserves(SystemOrigin::Root.into(), payer.clone(), USDT, add_amount.into())); + }: _(SystemOrigin::Root, payer, USDT, reduce_amount.into()) + verify { + assert_last_event::(Event::::ReservesReduced(caller, USDT, reduce_amount.into(), (add_amount-reduce_amount).into()).into()); + } + + update_liquidation_free_collateral { + + }: _(SystemOrigin::Root, vec![CDOT_6_13]) + verify { + assert_last_event::(Event::::LiquidationFreeCollateralsUpdated(vec![CDOT_6_13]).into()); + } +} + +impl_benchmark_test_suite!(Loans, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/crates/loans/src/farming.rs b/crates/loans/src/farming.rs new file mode 100644 index 0000000000..b63af86725 --- /dev/null +++ b/crates/loans/src/farming.rs @@ -0,0 +1,216 @@ +// 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. + +use sp_io::hashing::blake2_256; +use sp_runtime::{traits::Zero, DispatchResult}; + +use crate::*; + +impl Pallet { + pub(crate) fn reward_account_id() -> Result { + let account_id: T::AccountId = T::PalletId::get().into_account_truncating(); + let entropy = (b"loans/farming", &[account_id]).using_encoded(blake2_256); + Ok(T::AccountId::decode(&mut &entropy[..]).map_err(|_| Error::::CodecError)?) + } + + fn reward_scale() -> u128 { + 10_u128.pow(12) + } + + fn calculate_reward_delta_index( + delta_block: T::BlockNumber, + reward_speed: BalanceOf, + total_share: BalanceOf, + ) -> Result { + if total_share.is_zero() { + return Ok(0); + } + let delta_block: BalanceOf = delta_block.saturated_into(); + let delta_index = delta_block + .get_big_uint() + .checked_mul(&reward_speed.get_big_uint()) + .and_then(|r| r.checked_mul(&Self::reward_scale().get_big_uint())) + .and_then(|r| r.checked_div(&total_share.get_big_uint())) + .and_then(|r| r.to_u128()) + .ok_or(ArithmeticError::Overflow)?; + Ok(delta_index) + } + + fn calculate_reward_delta( + share: BalanceOf, + reward_delta_index: u128, + ) -> Result { + let reward_delta = share + .get_big_uint() + .checked_mul(&reward_delta_index.get_big_uint()) + .and_then(|r| r.checked_div(&Self::reward_scale().get_big_uint())) + .and_then(|r| r.to_u128()) + .ok_or(ArithmeticError::Overflow)?; + Ok(reward_delta) + } + + pub(crate) fn update_reward_supply_index(asset_id: AssetIdOf) -> DispatchResult { + let current_block_number = >::block_number(); + RewardSupplyState::::try_mutate(asset_id, |supply_state| -> DispatchResult { + let delta_block = current_block_number.saturating_sub(supply_state.block); + if delta_block.is_zero() { + return Ok(()); + } + let supply_speed = RewardSupplySpeed::::get(asset_id); + if !supply_speed.is_zero() { + let total_supply = TotalSupply::::get(asset_id); + let delta_index = + Self::calculate_reward_delta_index(delta_block, supply_speed, total_supply)?; + supply_state.index = supply_state + .index + .checked_add(delta_index) + .ok_or(ArithmeticError::Overflow)?; + } + supply_state.block = current_block_number; + + Ok(()) + }) + } + + pub(crate) fn update_reward_borrow_index(asset_id: AssetIdOf) -> DispatchResult { + let current_block_number = >::block_number(); + RewardBorrowState::::try_mutate(asset_id, |borrow_state| -> DispatchResult { + let delta_block = current_block_number.saturating_sub(borrow_state.block); + if delta_block.is_zero() { + return Ok(()); + } + let borrow_speed = RewardBorrowSpeed::::get(asset_id); + if !borrow_speed.is_zero() { + let current_borrow_amount = TotalBorrows::::get(asset_id); + let current_borrow_index = BorrowIndex::::get(asset_id); + let base_borrow_amount = current_borrow_index + .reciprocal() + .and_then(|r| r.checked_mul_int(current_borrow_amount)) + .ok_or(ArithmeticError::Overflow)?; + let delta_index = Self::calculate_reward_delta_index( + delta_block, + borrow_speed, + base_borrow_amount, + )?; + borrow_state.index = borrow_state + .index + .checked_add(delta_index) + .ok_or(ArithmeticError::Overflow)?; + } + borrow_state.block = current_block_number; + + Ok(()) + }) + } + + pub(crate) fn distribute_supplier_reward( + asset_id: AssetIdOf, + supplier: &T::AccountId, + ) -> DispatchResult { + RewardSupplierIndex::::try_mutate( + asset_id, + supplier, + |supplier_index| -> DispatchResult { + let supply_state = RewardSupplyState::::get(asset_id); + let delta_index = supply_state + .index + .checked_sub(*supplier_index) + .ok_or(ArithmeticError::Underflow)?; + *supplier_index = supply_state.index; + + RewardAccrued::::try_mutate(supplier, |total_reward| -> DispatchResult { + let supplier_account = AccountDeposits::::get(asset_id, supplier); + let supplier_amount = supplier_account.voucher_balance; + let reward_delta = Self::calculate_reward_delta(supplier_amount, delta_index)?; + *total_reward = total_reward + .checked_add(reward_delta) + .ok_or(ArithmeticError::Overflow)?; + Self::deposit_event(Event::::DistributedSupplierReward( + asset_id, + supplier.clone(), + reward_delta, + supply_state.index, + )); + + Ok(()) + }) + }, + ) + } + + pub(crate) fn distribute_borrower_reward( + asset_id: AssetIdOf, + borrower: &T::AccountId, + ) -> DispatchResult { + RewardBorrowerIndex::::try_mutate( + asset_id, + borrower, + |borrower_index| -> DispatchResult { + let borrow_state = RewardBorrowState::::get(asset_id); + let delta_index = borrow_state + .index + .checked_sub(*borrower_index) + .ok_or(ArithmeticError::Underflow)?; + *borrower_index = borrow_state.index; + + RewardAccrued::::try_mutate(borrower, |total_reward| -> DispatchResult { + let current_borrow_amount = Self::current_borrow_balance(borrower, asset_id)?; + let current_borrow_index = BorrowIndex::::get(asset_id); + let base_borrow_amount = current_borrow_index + .reciprocal() + .and_then(|r| r.checked_mul_int(current_borrow_amount)) + .ok_or(ArithmeticError::Overflow)?; + let reward_delta = + Self::calculate_reward_delta(base_borrow_amount, delta_index)?; + *total_reward = total_reward + .checked_add(reward_delta) + .ok_or(ArithmeticError::Overflow)?; + Self::deposit_event(Event::::DistributedBorrowerReward( + asset_id, + borrower.clone(), + reward_delta, + borrow_state.index, + )); + + Ok(()) + }) + }, + ) + } + + pub(crate) fn collect_market_reward( + asset_id: AssetIdOf, + user: &T::AccountId, + ) -> DispatchResult { + Self::update_reward_supply_index(asset_id)?; + Self::distribute_supplier_reward(asset_id, user)?; + + Self::update_reward_borrow_index(asset_id)?; + Self::distribute_borrower_reward(asset_id, user)?; + + Ok(()) + } + + pub(crate) fn pay_reward(user: &T::AccountId) -> DispatchResult { + let pool_account = Self::reward_account_id()?; + let reward_asset = T::RewardAssetId::get(); + let total_reward = RewardAccrued::::get(user); + if total_reward > 0 { + T::Assets::transfer(reward_asset, &pool_account, user, total_reward, true)?; + RewardAccrued::::remove(user); + } + Self::deposit_event(Event::::RewardPaid(user.clone(), total_reward)); + Ok(()) + } +} diff --git a/crates/loans/src/interest.rs b/crates/loans/src/interest.rs new file mode 100644 index 0000000000..7176c2033c --- /dev/null +++ b/crates/loans/src/interest.rs @@ -0,0 +1,214 @@ +// 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. + +use primitives::{Timestamp, SECONDS_PER_YEAR}; +use sp_runtime::{traits::Zero, DispatchResult}; + +use crate::*; + +impl Pallet { + /// Accrue interest and update corresponding storage + pub(crate) fn accrue_interest(asset_id: AssetIdOf) -> DispatchResult { + let now = T::UnixTime::now().as_secs(); + let last_accrued_interest_time = Self::last_accrued_interest_time(asset_id); + if last_accrued_interest_time.is_zero() { + // For the initialization + Self::update_last_accrued_interest_time(asset_id, now)?; + return Ok(()); + } + if now <= last_accrued_interest_time { + return Ok(()); + } + + let ( + borrow_rate, + supply_rate, + exchange_rate, + util, + total_borrows_new, + total_reserves_new, + borrow_index_new, + ) = Self::get_market_status(asset_id)?; + + Self::update_last_accrued_interest_time(asset_id, now)?; + TotalBorrows::::insert(asset_id, total_borrows_new); + TotalReserves::::insert(asset_id, total_reserves_new); + BorrowIndex::::insert(asset_id, borrow_index_new); + + //save redundant storage right now. + UtilizationRatio::::insert(asset_id, util); + BorrowRate::::insert(asset_id, borrow_rate); + SupplyRate::::insert(asset_id, supply_rate); + ExchangeRate::::insert(asset_id, exchange_rate); + + Ok(()) + } + + pub fn get_market_status( + asset_id: AssetIdOf, + ) -> Result< + ( + Rate, + Rate, + Rate, + Ratio, + BalanceOf, + BalanceOf, + FixedU128, + ), + DispatchError, + > { + let market = Self::market(asset_id)?; + let total_supply = Self::total_supply(asset_id); + let total_cash = Self::get_total_cash(asset_id); + let mut total_borrows = Self::total_borrows(asset_id); + let mut total_reserves = Self::total_reserves(asset_id); + let mut borrow_index = Self::borrow_index(asset_id); + + let util = Self::calc_utilization_ratio(total_cash, total_borrows, total_reserves)?; + let borrow_rate = market + .rate_model + .get_borrow_rate(util) + .ok_or(ArithmeticError::Overflow)?; + let supply_rate = + InterestRateModel::get_supply_rate(borrow_rate, util, market.reserve_factor); + + let now = T::UnixTime::now().as_secs(); + let last_accrued_interest_time = Self::last_accrued_interest_time(asset_id); + if now > last_accrued_interest_time { + let delta_time = now - last_accrued_interest_time; + let interest_accumulated = + Self::accrued_interest(borrow_rate, total_borrows, delta_time) + .ok_or(ArithmeticError::Overflow)?; + total_borrows = interest_accumulated + .checked_add(total_borrows) + .ok_or(ArithmeticError::Overflow)?; + total_reserves = market + .reserve_factor + .mul_floor(interest_accumulated) + .checked_add(total_reserves) + .ok_or(ArithmeticError::Overflow)?; + + borrow_index = Self::increment_index(borrow_rate, borrow_index, delta_time) + .and_then(|r| r.checked_add(&borrow_index)) + .ok_or(ArithmeticError::Overflow)?; + } + + let exchange_rate = + Self::calculate_exchange_rate(total_supply, total_cash, total_borrows, total_reserves)?; + + Ok(( + borrow_rate, + supply_rate, + exchange_rate, + util, + total_borrows, + total_reserves, + borrow_index, + )) + } + + /// Update the exchange rate according to the totalCash, totalBorrows and totalSupply. + /// This function does not accrue interest before calculating the exchange rate. + /// exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply + pub fn exchange_rate_stored(asset_id: AssetIdOf) -> Result { + let total_supply = Self::total_supply(asset_id); + let total_cash = Self::get_total_cash(asset_id); + let total_borrows = Self::total_borrows(asset_id); + let total_reserves = Self::total_reserves(asset_id); + + Self::calculate_exchange_rate(total_supply, total_cash, total_borrows, total_reserves) + } + + /// Calculate the borrowing utilization ratio of the specified market + /// + /// utilizationRatio = totalBorrows / (totalCash + totalBorrows − totalReserves) + pub(crate) fn calc_utilization_ratio( + cash: BalanceOf, + borrows: BalanceOf, + reserves: BalanceOf, + ) -> Result { + // utilization ratio is 0 when there are no borrows + if borrows.is_zero() { + return Ok(Ratio::zero()); + } + let total = cash + .checked_add(borrows) + .and_then(|r| r.checked_sub(reserves)) + .ok_or(ArithmeticError::Overflow)?; + + Ok(Ratio::from_rational(borrows, total)) + } + + /// The exchange rate should be greater than 0.02 and less than 1 + pub(crate) fn ensure_valid_exchange_rate(exchange_rate: Rate) -> DispatchResult { + ensure!( + exchange_rate >= Rate::from_inner(MIN_EXCHANGE_RATE) + && exchange_rate < Rate::from_inner(MAX_EXCHANGE_RATE), + Error::::InvalidExchangeRate + ); + + Ok(()) + } + + pub(crate) fn update_last_accrued_interest_time( + asset_id: AssetIdOf, + time: Timestamp, + ) -> DispatchResult { + LastAccruedInterestTime::::try_mutate(asset_id, |last_time| -> DispatchResult { + *last_time = time; + Ok(()) + }) + } + + fn accrued_interest( + borrow_rate: Rate, + amount: BalanceOf, + delta_time: Timestamp, + ) -> Option> { + borrow_rate + .checked_mul_int(amount)? + .checked_mul(delta_time.into())? + .checked_div(SECONDS_PER_YEAR.into()) + } + + fn increment_index(borrow_rate: Rate, index: Rate, delta_time: Timestamp) -> Option { + borrow_rate + .checked_mul(&index)? + .checked_mul(&FixedU128::saturating_from_integer(delta_time))? + .checked_div(&FixedU128::saturating_from_integer(SECONDS_PER_YEAR)) + } + + fn calculate_exchange_rate( + total_supply: BalanceOf, + total_cash: BalanceOf, + total_borrows: BalanceOf, + total_reserves: BalanceOf, + ) -> Result { + if total_supply.is_zero() { + return Ok(Rate::from_inner(MIN_EXCHANGE_RATE)); + } + + let cash_plus_borrows_minus_reserves = total_cash + .checked_add(total_borrows) + .and_then(|r| r.checked_sub(total_reserves)) + .ok_or(ArithmeticError::Overflow)?; + let exchange_rate = + Rate::checked_from_rational(cash_plus_borrows_minus_reserves, total_supply) + .ok_or(ArithmeticError::Underflow)?; + Self::ensure_valid_exchange_rate(exchange_rate)?; + + Ok(exchange_rate) + } +} diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs new file mode 100644 index 0000000000..5b16d73b36 --- /dev/null +++ b/crates/loans/src/lib.rs @@ -0,0 +1,2219 @@ +// 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. + +//! # Loans pallet +//! +//! ## Overview +//! +//! Loans pallet implement the lending protocol by using a pool-based strategy +//! that aggregates each user's supplied assets. The interest rate is dynamically +//! determined by the supply and demand. + +#![cfg_attr(not(feature = "std"), no_std)] + +use core::cmp::max; + +pub use crate::rate_model::*; + +use frame_support::{ + log, + pallet_prelude::*, + require_transactional, + traits::{ + tokens::fungibles::{Inspect, Mutate, Transfer}, + UnixTime, + }, + transactional, PalletId, +}; +use frame_system::pallet_prelude::*; +use num_traits::cast::ToPrimitive; +pub use pallet::*; +use pallet_traits::{ + ConvertToBigUint, Loans as LoansTrait, LoansMarketDataProvider, LoansPositionDataProvider, + MarketInfo, MarketStatus, PriceFeeder, +}; +use primitives::{ + is_auxiliary_token, Balance, CurrencyId, Liquidity, Price, Rate, Ratio, Shortfall, Timestamp, +}; +use sp_runtime::{ + traits::{ + AccountIdConversion, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, One, + SaturatedConversion, Saturating, StaticLookup, Zero, + }, + ArithmeticError, FixedPointNumber, FixedU128, +}; +use sp_std::{result::Result, vec::Vec}; + +use sp_io::hashing::blake2_256; +pub use types::{BorrowSnapshot, Deposits, EarnedSnapshot, Market, MarketState, RewardMarketState}; +pub use weights::WeightInfo; + +mod benchmarking; + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + +mod farming; +mod interest; +mod ptoken; +mod rate_model; +mod types; + +pub mod migrations; +pub mod weights; + +pub const MAX_INTEREST_CALCULATING_INTERVAL: u64 = 5 * 24 * 3600; // 5 days +pub const MIN_INTEREST_CALCULATING_INTERVAL: u64 = 100; // 100 seconds + +pub const MAX_EXCHANGE_RATE: u128 = 1_000_000_000_000_000_000; // 1 +pub const MIN_EXCHANGE_RATE: u128 = 20_000_000_000_000_000; // 0.02 + +type AccountIdOf = ::AccountId; +type AssetIdOf = + <::Assets as Inspect<::AccountId>>::AssetId; +type BalanceOf = + <::Assets as Inspect<::AccountId>>::Balance; + +/// Utility type for managing upgrades/migrations. +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)] +pub enum Versions { + V1, + V2, + V3, + V4, + V5, + V6, +} + +#[frame_support::pallet] +pub mod pallet { + + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type Event: From> + IsType<::Event>; + + /// The oracle price feeder + type PriceFeeder: PriceFeeder; + + /// The loan's module id, keep all collaterals of CDPs. + #[pallet::constant] + type PalletId: Get; + + /// The origin which can add/reduce reserves. + type ReserveOrigin: EnsureOrigin; + + /// The origin which can update rate model, liquidate incentive and + /// add/reduce reserves. Root can always do this. + type UpdateOrigin: EnsureOrigin; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + + /// Unix time + type UnixTime: UnixTime; + + /// Assets for deposit/withdraw collateral assets to/from loans module + type Assets: Transfer + + Inspect + + Mutate; + + /// Reward asset id. + #[pallet::constant] + type RewardAssetId: Get>; + + #[pallet::constant] + type LiquidationFreeAssetId: Get>; + } + + #[pallet::error] + pub enum Error { + /// Insufficient liquidity to borrow more or disable collateral + InsufficientLiquidity, + /// Insufficient deposit to redeem + InsufficientDeposit, + /// Repay amount greater than allowed + TooMuchRepay, + /// Asset already enabled/disabled collateral + DuplicateOperation, + /// No deposit asset + NoDeposit, + /// Repay amount more than collateral amount + InsufficientCollateral, + /// Liquidator is same as borrower + LiquidatorIsBorrower, + /// Deposits are not used as a collateral + DepositsAreNotCollateral, + /// Insufficient shortfall to repay + InsufficientShortfall, + /// Insufficient reserves + InsufficientReserves, + /// Invalid rate model params + InvalidRateModelParam, + /// Market not activated + MarketNotActivated, + /// Oracle price not ready + PriceOracleNotReady, + /// Oracle price is zero + PriceIsZero, + /// Invalid asset id + InvalidCurrencyId, + /// Invalid ptoken id + InvalidPtokenId, + /// Market does not exist + MarketDoesNotExist, + /// Market already exists + MarketAlreadyExists, + /// New markets must have a pending state + NewMarketMustHavePendingState, + /// Upper bound of supplying is exceeded + SupplyCapacityExceeded, + /// Upper bound of borrowing is exceeded + BorrowCapacityExceeded, + /// Insufficient cash in the pool + InsufficientCash, + /// The factor should be greater than 0% and less than 100% + InvalidFactor, + /// The supply cap cannot be zero + InvalidSupplyCap, + /// The exchange rate should be greater than 0.02 and less than 1 + InvalidExchangeRate, + /// Amount cannot be zero + InvalidAmount, + /// Payer cannot be signer + PayerIsSigner, + /// Codec error + CodecError, + /// Collateral is reserved and cannot be liquidated + CollateralReserved, + } + + #[pallet::event] + #[pallet::generate_deposit(pub (crate) fn deposit_event)] + pub enum Event { + /// Enable collateral for certain asset + /// [sender, asset_id] + CollateralAssetAdded(T::AccountId, AssetIdOf), + /// Disable collateral for certain asset + /// [sender, asset_id] + CollateralAssetRemoved(T::AccountId, AssetIdOf), + /// Event emitted when assets are deposited + /// [sender, asset_id, amount] + Deposited(T::AccountId, AssetIdOf, BalanceOf), + /// Event emitted when assets are redeemed + /// [sender, asset_id, amount] + Redeemed(T::AccountId, AssetIdOf, BalanceOf), + /// Event emitted when cash is borrowed + /// [sender, asset_id, amount] + Borrowed(T::AccountId, AssetIdOf, BalanceOf), + /// Event emitted when a borrow is repaid + /// [sender, asset_id, amount] + RepaidBorrow(T::AccountId, AssetIdOf, BalanceOf), + /// Event emitted when a borrow is liquidated + /// [liquidator, borrower, liquidation_asset_id, collateral_asset_id, repay_amount, collateral_amount] + LiquidatedBorrow( + T::AccountId, + T::AccountId, + AssetIdOf, + AssetIdOf, + BalanceOf, + BalanceOf, + ), + /// Event emitted when the reserves are reduced + /// [admin, asset_id, reduced_amount, total_reserves] + ReservesReduced(T::AccountId, AssetIdOf, BalanceOf, BalanceOf), + /// Event emitted when the reserves are added + /// [admin, asset_id, added_amount, total_reserves] + ReservesAdded(T::AccountId, AssetIdOf, BalanceOf, BalanceOf), + /// New market is set + /// [new_interest_rate_model] + NewMarket(AssetIdOf, Market>), + /// Event emitted when a market is activated + /// [admin, asset_id] + ActivatedMarket(AssetIdOf), + /// New market parameters is updated + /// [admin, asset_id] + UpdatedMarket(AssetIdOf, Market>), + /// Reward added + RewardAdded(T::AccountId, BalanceOf), + /// Reward withdrawed + RewardWithdrawn(T::AccountId, BalanceOf), + /// Event emitted when market reward speed updated. + MarketRewardSpeedUpdated(AssetIdOf, BalanceOf, BalanceOf), + /// Deposited when Reward is distributed to a supplier + DistributedSupplierReward(AssetIdOf, T::AccountId, BalanceOf, BalanceOf), + /// Deposited when Reward is distributed to a borrower + DistributedBorrowerReward(AssetIdOf, T::AccountId, BalanceOf, BalanceOf), + /// Reward Paid for user + RewardPaid(T::AccountId, BalanceOf), + /// Event emitted when the incentive reserves are redeemed and transfer to receiver's account + /// [receive_account_id, asset_id, reduced_amount] + IncentiveReservesReduced(T::AccountId, AssetIdOf, BalanceOf), + /// Liquidation free collaterals has been updated + LiquidationFreeCollateralsUpdated(Vec>), + } + + /// The timestamp of the last calculation of accrued interest + #[pallet::storage] + #[pallet::getter(fn last_accrued_interest_time)] + pub type LastAccruedInterestTime = + StorageMap<_, Blake2_128Concat, AssetIdOf, Timestamp, ValueQuery>; + + /// Liquidation free collateral. + #[pallet::storage] + #[pallet::getter(fn liquidation_free_collaterals)] + pub type LiquidationFreeCollaterals = StorageValue<_, Vec>, ValueQuery>; + + /// Total number of collateral tokens in circulation + /// CollateralType -> Balance + #[pallet::storage] + #[pallet::getter(fn total_supply)] + pub type TotalSupply = + StorageMap<_, Blake2_128Concat, AssetIdOf, BalanceOf, ValueQuery>; + + /// Total amount of outstanding borrows of the underlying in this market + /// CurrencyId -> Balance + #[pallet::storage] + #[pallet::getter(fn total_borrows)] + pub type TotalBorrows = + StorageMap<_, Blake2_128Concat, AssetIdOf, BalanceOf, ValueQuery>; + + /// Total amount of reserves of the underlying held in this market + /// CurrencyId -> Balance + #[pallet::storage] + #[pallet::getter(fn total_reserves)] + pub type TotalReserves = + StorageMap<_, Blake2_128Concat, AssetIdOf, BalanceOf, ValueQuery>; + + /// Mapping of account addresses to outstanding borrow balances + /// CurrencyId -> Owner -> BorrowSnapshot + #[pallet::storage] + #[pallet::getter(fn account_borrows)] + pub type AccountBorrows = StorageDoubleMap< + _, + Blake2_128Concat, + AssetIdOf, + Blake2_128Concat, + T::AccountId, + BorrowSnapshot>, + ValueQuery, + >; + + /// Mapping of account addresses to deposit details + /// CollateralType -> Owner -> Deposits + #[pallet::storage] + #[pallet::getter(fn account_deposits)] + pub type AccountDeposits = StorageDoubleMap< + _, + Blake2_128Concat, + AssetIdOf, + Blake2_128Concat, + T::AccountId, + Deposits>, + ValueQuery, + >; + + /// Mapping of account addresses to total deposit interest accrual + /// CurrencyId -> Owner -> EarnedSnapshot + #[pallet::storage] + #[pallet::getter(fn account_earned)] + pub type AccountEarned = StorageDoubleMap< + _, + Blake2_128Concat, + AssetIdOf, + Blake2_128Concat, + T::AccountId, + EarnedSnapshot>, + ValueQuery, + >; + + /// Accumulator of the total earned interest rate since the opening of the market + /// CurrencyId -> u128 + #[pallet::storage] + #[pallet::getter(fn borrow_index)] + pub type BorrowIndex = + StorageMap<_, Blake2_128Concat, AssetIdOf, Rate, ValueQuery>; + + /// The exchange rate from the underlying to the internal collateral + #[pallet::storage] + #[pallet::getter(fn exchange_rate)] + pub type ExchangeRate = + StorageMap<_, Blake2_128Concat, AssetIdOf, Rate, ValueQuery>; + + /// Mapping of borrow rate to currency type + #[pallet::storage] + #[pallet::getter(fn borrow_rate)] + pub type BorrowRate = + StorageMap<_, Blake2_128Concat, AssetIdOf, Rate, ValueQuery>; + + /// Mapping of supply rate to currency type + #[pallet::storage] + #[pallet::getter(fn supply_rate)] + pub type SupplyRate = + StorageMap<_, Blake2_128Concat, AssetIdOf, Rate, ValueQuery>; + + /// Borrow utilization ratio + #[pallet::storage] + #[pallet::getter(fn utilization_ratio)] + pub type UtilizationRatio = + StorageMap<_, Blake2_128Concat, AssetIdOf, Ratio, ValueQuery>; + + /// Mapping of asset id to its market + #[pallet::storage] + pub type Markets = + StorageMap<_, Blake2_128Concat, AssetIdOf, Market>>; + + /// Mapping of ptoken id to asset id + /// `ptoken id`: voucher token id + /// `asset id`: underlying token id + #[pallet::storage] + pub type UnderlyingAssetId = + StorageMap<_, Blake2_128Concat, AssetIdOf, AssetIdOf>; + + /// Mapping of token id to supply reward speed + #[pallet::storage] + #[pallet::getter(fn reward_supply_speed)] + pub type RewardSupplySpeed = + StorageMap<_, Blake2_128Concat, AssetIdOf, BalanceOf, ValueQuery>; + + /// Mapping of token id to borrow reward speed + #[pallet::storage] + #[pallet::getter(fn reward_borrow_speed)] + pub type RewardBorrowSpeed = + StorageMap<_, Blake2_128Concat, AssetIdOf, BalanceOf, ValueQuery>; + + /// The Reward market supply state for each market + #[pallet::storage] + #[pallet::getter(fn reward_supply_state)] + pub type RewardSupplyState = StorageMap< + _, + Blake2_128Concat, + AssetIdOf, + RewardMarketState>, + ValueQuery, + >; + + /// The Reward market borrow state for each market + #[pallet::storage] + #[pallet::getter(fn reward_borrow_state)] + pub type RewardBorrowState = StorageMap< + _, + Blake2_128Concat, + AssetIdOf, + RewardMarketState>, + ValueQuery, + >; + + /// The Reward index for each market for each supplier as of the last time they accrued Reward + #[pallet::storage] + #[pallet::getter(fn reward_supplier_index)] + pub type RewardSupplierIndex = StorageDoubleMap< + _, + Blake2_128Concat, + AssetIdOf, + Blake2_128Concat, + T::AccountId, + BalanceOf, + ValueQuery, + >; + + /// The Reward index for each market for each borrower as of the last time they accrued Reward + #[pallet::storage] + #[pallet::getter(fn reward_borrower_index)] + pub type RewardBorrowerIndex = StorageDoubleMap< + _, + Blake2_128Concat, + AssetIdOf, + Blake2_128Concat, + T::AccountId, + BalanceOf, + ValueQuery, + >; + + /// The reward accrued but not yet transferred to each user. + #[pallet::storage] + #[pallet::storage_prefix = "RewardAccured"] + #[pallet::getter(fn reward_accrued)] + pub type RewardAccrued = + StorageMap<_, Blake2_128Concat, T::AccountId, BalanceOf, ValueQuery>; + + /// DefaultVersion is using for initialize the StorageVersion + #[pallet::type_value] + pub(super) fn DefaultVersion() -> Versions { + Versions::V2 + } + + /// Storage version of the pallet. + #[pallet::storage] + pub(crate) type StorageVersion = + StorageValue<_, Versions, ValueQuery, DefaultVersion>; + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(PhantomData); + + #[pallet::call] + impl Pallet { + /// Stores a new market and its related currency. Returns `Err` if a currency + /// is not attached to an existent market. + /// + /// All provided market states must be `Pending`, otherwise an error will be returned. + /// + /// If a currency is already attached to a market, then the market will be replaced + /// by the new provided value. + /// + /// The ptoken id and asset id are bound, the ptoken id of new provided market cannot + /// be duplicated with the existing one, otherwise it will return `InvalidPtokenId`. + /// + /// - `asset_id`: Market related currency + /// - `market`: The market that is going to be stored + #[pallet::weight(T::WeightInfo::add_market())] + #[transactional] + pub fn add_market( + origin: OriginFor, + asset_id: AssetIdOf, + market: Market>, + ) -> DispatchResultWithPostInfo { + T::UpdateOrigin::ensure_origin(origin)?; + ensure!( + !Markets::::contains_key(asset_id), + Error::::MarketAlreadyExists + ); + ensure!( + market.state == MarketState::Pending, + Error::::NewMarketMustHavePendingState + ); + ensure!( + market.rate_model.check_model(), + Error::::InvalidRateModelParam + ); + ensure!( + market.collateral_factor >= Ratio::zero() + && market.collateral_factor < Ratio::one(), + Error::::InvalidFactor, + ); + ensure!( + market.liquidation_threshold < Ratio::one() + && market.liquidation_threshold >= market.collateral_factor, + Error::::InvalidFactor + ); + ensure!( + market.reserve_factor > Ratio::zero() && market.reserve_factor < Ratio::one(), + Error::::InvalidFactor, + ); + ensure!( + market.liquidate_incentive_reserved_factor > Ratio::zero() + && market.liquidate_incentive_reserved_factor < Ratio::one(), + Error::::InvalidFactor, + ); + ensure!( + market.supply_cap > Zero::zero(), + Error::::InvalidSupplyCap, + ); + + // Ensures a given `ptoken_id` not exists on the `Market` and `UnderlyingAssetId`. + Self::ensure_ptoken(market.ptoken_id)?; + // Update storage of `Market` and `UnderlyingAssetId` + Markets::::insert(asset_id, market.clone()); + UnderlyingAssetId::::insert(market.ptoken_id, asset_id); + + // Init the ExchangeRate and BorrowIndex for asset + ExchangeRate::::insert(asset_id, Rate::from_inner(MIN_EXCHANGE_RATE)); + BorrowIndex::::insert(asset_id, Rate::one()); + + Self::deposit_event(Event::::NewMarket(asset_id, market)); + Ok(().into()) + } + + /// Activates a market. Returns `Err` if the market currency does not exist. + /// + /// If the market is already activated, does nothing. + /// + /// - `asset_id`: Market related currency + #[pallet::weight(T::WeightInfo::activate_market())] + #[transactional] + pub fn activate_market( + origin: OriginFor, + asset_id: AssetIdOf, + ) -> DispatchResultWithPostInfo { + T::UpdateOrigin::ensure_origin(origin)?; + Self::mutate_market(asset_id, |stored_market| { + if let MarketState::Active = stored_market.state { + return stored_market.clone(); + } + stored_market.state = MarketState::Active; + stored_market.clone() + })?; + Self::deposit_event(Event::::ActivatedMarket(asset_id)); + Ok(().into()) + } + + /// Updates the rate model of a stored market. Returns `Err` if the market + /// currency does not exist or the rate model is invalid. + /// + /// - `asset_id`: Market related currency + /// - `rate_model`: The new rate model to be updated + #[pallet::weight(T::WeightInfo::update_rate_model())] + #[transactional] + pub fn update_rate_model( + origin: OriginFor, + asset_id: AssetIdOf, + rate_model: InterestRateModel, + ) -> DispatchResultWithPostInfo { + T::UpdateOrigin::ensure_origin(origin)?; + ensure!(rate_model.check_model(), Error::::InvalidRateModelParam); + let market = Self::mutate_market(asset_id, |stored_market| { + stored_market.rate_model = rate_model; + stored_market.clone() + })?; + Self::deposit_event(Event::::UpdatedMarket(asset_id, market)); + + Ok(().into()) + } + + /// Updates a stored market. Returns `Err` if the market currency does not exist. + /// + /// - `asset_id`: market related currency + /// - `collateral_factor`: the collateral utilization ratio + /// - `reserve_factor`: fraction of interest currently set aside for reserves + /// - `close_factor`: maximum liquidation ratio at one time + /// - `liquidate_incentive`: liquidation incentive ratio + /// - `cap`: market capacity + #[pallet::weight(T::WeightInfo::update_market())] + #[transactional] + pub fn update_market( + origin: OriginFor, + asset_id: AssetIdOf, + collateral_factor: Option, + liquidation_threshold: Option, + reserve_factor: Option, + close_factor: Option, + liquidate_incentive_reserved_factor: Option, + liquidate_incentive: Option, + supply_cap: Option>, + borrow_cap: Option>, + ) -> DispatchResultWithPostInfo { + T::UpdateOrigin::ensure_origin(origin)?; + + let market = Self::market(asset_id)?; + + let collateral_factor = collateral_factor.unwrap_or(market.collateral_factor); + let liquidation_threshold = + liquidation_threshold.unwrap_or(market.liquidation_threshold); + let reserve_factor = reserve_factor.unwrap_or(market.reserve_factor); + let close_factor = close_factor.unwrap_or(market.close_factor); + let liquidate_incentive_reserved_factor = liquidate_incentive_reserved_factor + .unwrap_or(market.liquidate_incentive_reserved_factor); + let liquidate_incentive = liquidate_incentive.unwrap_or(market.liquidate_incentive); + let supply_cap = supply_cap.unwrap_or(market.supply_cap); + let borrow_cap = borrow_cap.unwrap_or(market.borrow_cap); + + ensure!( + collateral_factor >= Ratio::zero() && collateral_factor < Ratio::one(), + Error::::InvalidFactor + ); + ensure!( + liquidation_threshold >= collateral_factor && liquidation_threshold < Ratio::one(), + Error::::InvalidFactor + ); + ensure!( + reserve_factor > Ratio::zero() && reserve_factor < Ratio::one(), + Error::::InvalidFactor + ); + ensure!(supply_cap > Zero::zero(), Error::::InvalidSupplyCap); + + let market = Self::mutate_market(asset_id, |stored_market| { + *stored_market = Market { + state: stored_market.state, + ptoken_id: stored_market.ptoken_id, + rate_model: stored_market.rate_model, + collateral_factor, + liquidation_threshold, + reserve_factor, + close_factor, + liquidate_incentive, + liquidate_incentive_reserved_factor, + supply_cap, + borrow_cap, + }; + stored_market.clone() + })?; + Self::deposit_event(Event::::UpdatedMarket(asset_id, market)); + + Ok(().into()) + } + + /// Force updates a stored market. Returns `Err` if the market currency + /// does not exist. + /// + /// - `asset_id`: market related currency + /// - `market`: the new market parameters + #[pallet::weight(T::WeightInfo::force_update_market())] + #[transactional] + pub fn force_update_market( + origin: OriginFor, + asset_id: AssetIdOf, + market: Market>, + ) -> DispatchResultWithPostInfo { + T::UpdateOrigin::ensure_origin(origin)?; + ensure!( + market.rate_model.check_model(), + Error::::InvalidRateModelParam + ); + if UnderlyingAssetId::::contains_key(market.ptoken_id) { + ensure!( + Self::underlying_id(market.ptoken_id)? == asset_id, + Error::::InvalidPtokenId + ); + } + UnderlyingAssetId::::insert(market.ptoken_id, asset_id); + let updated_market = Self::mutate_market(asset_id, |stored_market| { + *stored_market = market; + stored_market.clone() + })?; + + Self::deposit_event(Event::::UpdatedMarket(asset_id, updated_market)); + Ok(().into()) + } + + /// Add reward for the pallet account. + /// + /// - `amount`: Reward amount added + #[pallet::weight(T::WeightInfo::add_reward())] + #[transactional] + pub fn add_reward( + origin: OriginFor, + amount: BalanceOf, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + ensure!(!amount.is_zero(), Error::::InvalidAmount); + + let reward_asset = T::RewardAssetId::get(); + let pool_account = Self::reward_account_id()?; + + T::Assets::transfer(reward_asset, &who, &pool_account, amount, true)?; + + Self::deposit_event(Event::::RewardAdded(who, amount)); + + Ok(().into()) + } + + /// Withdraw reward token from pallet account. + /// + /// The origin must conform to `UpdateOrigin`. + /// + /// - `target_account`: account receive reward token. + /// - `amount`: Withdraw amount + #[pallet::weight(T::WeightInfo::withdraw_missing_reward())] + #[transactional] + pub fn withdraw_missing_reward( + origin: OriginFor, + target_account: ::Source, + amount: BalanceOf, + ) -> DispatchResultWithPostInfo { + T::UpdateOrigin::ensure_origin(origin)?; + ensure!(!amount.is_zero(), Error::::InvalidAmount); + + let reward_asset = T::RewardAssetId::get(); + let pool_account = Self::reward_account_id()?; + let target_account = T::Lookup::lookup(target_account)?; + + T::Assets::transfer(reward_asset, &pool_account, &target_account, amount, true)?; + Self::deposit_event(Event::::RewardWithdrawn(target_account, amount)); + + Ok(().into()) + } + + /// Updates reward speed for the specified market + /// + /// The origin must conform to `UpdateOrigin`. + /// + /// - `asset_id`: Market related currency + /// - `reward_per_block`: reward amount per block. + #[pallet::weight(T::WeightInfo::update_market_reward_speed())] + #[transactional] + pub fn update_market_reward_speed( + origin: OriginFor, + asset_id: AssetIdOf, + supply_reward_per_block: Option>, + borrow_reward_per_block: Option>, + ) -> DispatchResultWithPostInfo { + T::UpdateOrigin::ensure_origin(origin)?; + Self::ensure_active_market(asset_id)?; + + let current_supply_speed = RewardSupplySpeed::::get(asset_id); + let current_borrow_speed = RewardBorrowSpeed::::get(asset_id); + + let supply_reward_per_block = supply_reward_per_block.unwrap_or(current_supply_speed); + let borrow_reward_per_block = borrow_reward_per_block.unwrap_or(current_borrow_speed); + + if supply_reward_per_block != current_supply_speed { + Self::update_reward_supply_index(asset_id)?; + RewardSupplySpeed::::try_mutate(asset_id, |current_speed| -> DispatchResult { + *current_speed = supply_reward_per_block; + Ok(()) + })?; + } + + if borrow_reward_per_block != current_borrow_speed { + Self::update_reward_borrow_index(asset_id)?; + RewardBorrowSpeed::::try_mutate(asset_id, |current_speed| -> DispatchResult { + *current_speed = borrow_reward_per_block; + Ok(()) + })?; + } + + Self::deposit_event(Event::::MarketRewardSpeedUpdated( + asset_id, + supply_reward_per_block, + borrow_reward_per_block, + )); + Ok(().into()) + } + + /// Claim reward from all market. + #[pallet::weight(T::WeightInfo::claim_reward())] + #[transactional] + pub fn claim_reward(origin: OriginFor) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + + for asset_id in Markets::::iter_keys() { + Self::collect_market_reward(asset_id, &who)?; + } + + Self::pay_reward(&who)?; + + Ok(().into()) + } + + /// Claim reward from the specified market. + /// + /// - `asset_id`: Market related currency + #[pallet::weight(T::WeightInfo::claim_reward_for_market())] + #[transactional] + pub fn claim_reward_for_market( + origin: OriginFor, + asset_id: AssetIdOf, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + + Self::collect_market_reward(asset_id, &who)?; + + Self::pay_reward(&who)?; + + Ok(().into()) + } + + /// Sender supplies assets into the market and receives internal supplies in exchange. + /// + /// - `asset_id`: the asset to be deposited. + /// - `mint_amount`: the amount to be deposited. + #[pallet::weight(T::WeightInfo::mint())] + #[transactional] + pub fn mint( + origin: OriginFor, + asset_id: AssetIdOf, + #[pallet::compact] mint_amount: BalanceOf, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + Self::do_mint(&who, asset_id, mint_amount)?; + + Ok(().into()) + } + + /// Sender redeems some of internal supplies in exchange for the underlying asset. + /// + /// - `asset_id`: the asset to be redeemed. + /// - `redeem_amount`: the amount to be redeemed. + #[pallet::weight(T::WeightInfo::redeem())] + #[transactional] + pub fn redeem( + origin: OriginFor, + asset_id: AssetIdOf, + #[pallet::compact] redeem_amount: BalanceOf, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + ensure!(!redeem_amount.is_zero(), Error::::InvalidAmount); + Self::do_redeem(&who, asset_id, redeem_amount)?; + + Ok(().into()) + } + + /// Sender redeems all of internal supplies in exchange for the underlying asset. + /// + /// - `asset_id`: the asset to be redeemed. + #[pallet::weight(T::WeightInfo::redeem_all())] + #[transactional] + pub fn redeem_all( + origin: OriginFor, + asset_id: AssetIdOf, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + Self::ensure_active_market(asset_id)?; + Self::accrue_interest(asset_id)?; + let exchange_rate = Self::exchange_rate_stored(asset_id)?; + Self::update_earned_stored(&who, asset_id, exchange_rate)?; + let deposits = AccountDeposits::::get(asset_id, &who); + let redeem_amount = Self::do_redeem_voucher(&who, asset_id, deposits.voucher_balance)?; + Self::deposit_event(Event::::Redeemed(who, asset_id, redeem_amount)); + + Ok(().into()) + } + + /// Sender borrows assets from the protocol to their own address. + /// + /// - `asset_id`: the asset to be borrowed. + /// - `borrow_amount`: the amount to be borrowed. + #[pallet::weight(T::WeightInfo::borrow())] + #[transactional] + pub fn borrow( + origin: OriginFor, + asset_id: AssetIdOf, + #[pallet::compact] borrow_amount: BalanceOf, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + + Self::do_borrow(&who, asset_id, borrow_amount)?; + + Ok(().into()) + } + + /// Sender repays some of their debts. + /// + /// - `asset_id`: the asset to be repaid. + /// - `repay_amount`: the amount to be repaid. + #[pallet::weight(T::WeightInfo::repay_borrow())] + #[transactional] + pub fn repay_borrow( + origin: OriginFor, + asset_id: AssetIdOf, + #[pallet::compact] repay_amount: BalanceOf, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + + Self::do_repay_borrow(&who, asset_id, repay_amount)?; + + Ok(().into()) + } + + /// Sender repays all of their debts. + /// + /// - `asset_id`: the asset to be repaid. + #[pallet::weight(T::WeightInfo::repay_borrow_all())] + #[transactional] + pub fn repay_borrow_all( + origin: OriginFor, + asset_id: AssetIdOf, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + Self::ensure_active_market(asset_id)?; + Self::accrue_interest(asset_id)?; + let account_borrows = Self::current_borrow_balance(&who, asset_id)?; + Self::do_repay_borrow(&who, asset_id, account_borrows)?; + + Ok(().into()) + } + + /// Set the collateral asset. + /// + /// - `asset_id`: the asset to be set. + /// - `enable`: turn on/off the collateral option. + #[pallet::weight(T::WeightInfo::collateral_asset())] + #[transactional] + pub fn collateral_asset( + origin: OriginFor, + asset_id: AssetIdOf, + enable: bool, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + Self::ensure_active_market(asset_id)?; + ensure!( + AccountDeposits::::contains_key(asset_id, &who), + Error::::NoDeposit + ); + let deposits = Self::account_deposits(asset_id, &who); + if deposits.is_collateral == enable { + return Err(Error::::DuplicateOperation.into()); + } + + Self::do_collateral_asset(&who, asset_id, enable)?; + + Ok(().into()) + } + + /// The sender liquidates the borrower's collateral. + /// + /// - `borrower`: the borrower to be liquidated. + /// - `liquidation_asset_id`: the assert to be liquidated. + /// - `repay_amount`: the amount to be repaid borrow. + /// - `collateral_asset_id`: The collateral to seize from the borrower. + #[pallet::weight(T::WeightInfo::liquidate_borrow())] + #[transactional] + pub fn liquidate_borrow( + origin: OriginFor, + borrower: T::AccountId, + liquidation_asset_id: AssetIdOf, + #[pallet::compact] repay_amount: BalanceOf, + collateral_asset_id: AssetIdOf, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + ensure!( + !Self::liquidation_free_collaterals().contains(&collateral_asset_id) + && !is_auxiliary_token(collateral_asset_id), + Error::::CollateralReserved + ); + Self::accrue_interest(liquidation_asset_id)?; + Self::accrue_interest(collateral_asset_id)?; + Self::do_liquidate_borrow( + who, + borrower, + liquidation_asset_id, + repay_amount, + collateral_asset_id, + )?; + Ok(().into()) + } + + /// Add reserves by transferring from payer. + /// + /// May only be called from `T::ReserveOrigin`. + /// + /// - `payer`: the payer account. + /// - `asset_id`: the assets to be added. + /// - `add_amount`: the amount to be added. + #[pallet::weight(T::WeightInfo::add_reserves())] + #[transactional] + pub fn add_reserves( + origin: OriginFor, + payer: ::Source, + asset_id: AssetIdOf, + #[pallet::compact] add_amount: BalanceOf, + ) -> DispatchResultWithPostInfo { + T::ReserveOrigin::ensure_origin(origin)?; + let payer = T::Lookup::lookup(payer)?; + Self::ensure_active_market(asset_id)?; + + T::Assets::transfer(asset_id, &payer, &Self::account_id(), add_amount, false)?; + let total_reserves = Self::total_reserves(asset_id); + let total_reserves_new = total_reserves + .checked_add(add_amount) + .ok_or(ArithmeticError::Overflow)?; + TotalReserves::::insert(asset_id, total_reserves_new); + + Self::deposit_event(Event::::ReservesAdded( + payer, + asset_id, + add_amount, + total_reserves_new, + )); + + Ok(().into()) + } + + /// Reduces reserves by transferring to receiver. + /// + /// May only be called from `T::ReserveOrigin`. + /// + /// - `receiver`: the receiver account. + /// - `asset_id`: the assets to be reduced. + /// - `reduce_amount`: the amount to be reduced. + #[pallet::weight(T::WeightInfo::reduce_reserves())] + #[transactional] + pub fn reduce_reserves( + origin: OriginFor, + receiver: ::Source, + asset_id: AssetIdOf, + #[pallet::compact] reduce_amount: BalanceOf, + ) -> DispatchResultWithPostInfo { + T::ReserveOrigin::ensure_origin(origin)?; + let receiver = T::Lookup::lookup(receiver)?; + Self::ensure_active_market(asset_id)?; + + let total_reserves = Self::total_reserves(asset_id); + if reduce_amount > total_reserves { + return Err(Error::::InsufficientReserves.into()); + } + let total_reserves_new = total_reserves + .checked_sub(reduce_amount) + .ok_or(ArithmeticError::Underflow)?; + TotalReserves::::insert(asset_id, total_reserves_new); + T::Assets::transfer( + asset_id, + &Self::account_id(), + &receiver, + reduce_amount, + false, + )?; + + Self::deposit_event(Event::::ReservesReduced( + receiver, + asset_id, + reduce_amount, + total_reserves_new, + )); + + Ok(().into()) + } + + /// Sender redeems some of internal supplies in exchange for the underlying asset. + /// + /// - `asset_id`: the asset to be redeemed. + /// - `redeem_amount`: the amount to be redeemed. + #[pallet::weight(T::WeightInfo::redeem()+T::WeightInfo::reduce_reserves())] + #[transactional] + pub fn reduce_incentive_reserves( + origin: OriginFor, + receiver: ::Source, + asset_id: AssetIdOf, + #[pallet::compact] redeem_amount: BalanceOf, + ) -> DispatchResultWithPostInfo { + T::ReserveOrigin::ensure_origin(origin)?; + ensure!(!redeem_amount.is_zero(), Error::::InvalidAmount); + let receiver = T::Lookup::lookup(receiver)?; + let from = Self::incentive_reward_account_id()?; + Self::ensure_active_market(asset_id)?; + let exchange_rate = Self::exchange_rate_stored(asset_id)?; + let voucher_amount = Self::calc_collateral_amount(redeem_amount, exchange_rate)?; + let redeem_amount = Self::do_redeem_voucher(&from, asset_id, voucher_amount)?; + T::Assets::transfer(asset_id, &from, &receiver, redeem_amount, false)?; + Self::deposit_event(Event::::IncentiveReservesReduced( + receiver, + asset_id, + redeem_amount, + )); + Ok(().into()) + } + + /// Update liquidation free collateral. + /// + /// The `assets` won't be counted when do general + #[pallet::weight(T::WeightInfo::update_liquidation_free_collateral())] + #[transactional] + pub fn update_liquidation_free_collateral( + origin: OriginFor, + collaterals: Vec>, + ) -> DispatchResultWithPostInfo { + T::UpdateOrigin::ensure_origin(origin)?; + LiquidationFreeCollaterals::::mutate(|liquidation_free_collaterals| { + *liquidation_free_collaterals = collaterals.clone() + }); + Self::deposit_event(Event::::LiquidationFreeCollateralsUpdated(collaterals)); + Ok(().into()) + } + } +} + +impl Pallet { + pub fn account_id() -> T::AccountId { + T::PalletId::get().into_account_truncating() + } + + fn get_lf_borrowed_value(account: &T::AccountId) -> Result { + let lf_borrowed_amount = + Self::current_borrow_balance(account, T::LiquidationFreeAssetId::get())?; + Self::get_asset_value(T::LiquidationFreeAssetId::get(), lf_borrowed_amount) + } + + fn get_lf_base_position(account: &T::AccountId) -> Result { + let mut total_asset_value: FixedU128 = FixedU128::zero(); + for (asset_id, _market) in Self::active_markets() + .filter(|(asset_id, _)| Self::liquidation_free_collaterals().contains(asset_id)) + { + total_asset_value = total_asset_value + .checked_add(&Self::collateral_asset_value(account, asset_id)?) + .ok_or(ArithmeticError::Overflow)?; + } + Ok(total_asset_value) + } + + fn get_lf_liquidation_base_position( + account: &T::AccountId, + ) -> Result { + let mut total_asset_value: FixedU128 = FixedU128::zero(); + for (asset_id, _market) in Self::active_markets() + .filter(|(asset_id, _)| Self::liquidation_free_collaterals().contains(asset_id)) + { + total_asset_value = total_asset_value + .checked_add(&Self::liquidation_threshold_asset_value(account, asset_id)?) + .ok_or(ArithmeticError::Overflow)?; + } + Ok(total_asset_value) + } + + pub fn get_account_liquidity( + account: &T::AccountId, + ) -> Result<(Liquidity, Shortfall, Liquidity, Shortfall), DispatchError> { + let total_borrow_value = Self::total_borrowed_value(account)?; + let total_collateral_value = Self::total_collateral_value(account)?; + let lf_borrowed_value = Self::get_lf_borrowed_value(account)?; + let lf_base_position = Self::get_lf_base_position(account)?; + + log::trace!( + target: "loans::get_account_liquidity", + "account: {:?}, total_borrow_value: {:?}, total_collateral_value: {:?}, lf_borrowed_value: {:?}, lf_base_position: {:?}", + account, + total_borrow_value.into_inner(), + total_collateral_value.into_inner(), + lf_borrowed_value.into_inner(), + lf_base_position.into_inner(), + ); + match ( + total_collateral_value > total_borrow_value, + lf_base_position > lf_borrowed_value, + ) { + (true, true) => Ok(( + total_collateral_value - total_borrow_value, + FixedU128::zero(), + lf_base_position - lf_borrowed_value, + FixedU128::zero(), + )), + (true, false) => Ok(( + total_collateral_value - total_borrow_value, + FixedU128::zero(), + FixedU128::zero(), + lf_borrowed_value - lf_base_position, + )), + (false, true) => Ok(( + FixedU128::zero(), + total_borrow_value - total_collateral_value, + lf_base_position - lf_borrowed_value, + FixedU128::zero(), + )), + (false, false) => Ok(( + FixedU128::zero(), + total_borrow_value - total_collateral_value, + FixedU128::zero(), + lf_borrowed_value - lf_base_position, + )), + } + } + + pub fn get_account_liquidation_threshold_liquidity( + account: &T::AccountId, + ) -> Result<(Liquidity, Shortfall, Liquidity, Shortfall), DispatchError> { + let total_borrow_value = Self::total_borrowed_value(account)?; + let total_collateral_value = Self::total_liquidation_threshold_value(account)?; + + let lf_borrowed_value = Self::get_lf_borrowed_value(account)?; + let lf_base_position = Self::get_lf_liquidation_base_position(account)?; + + log::trace!( + target: "loans::get_account_liquidation_threshold_liquidity", + "account: {:?}, total_borrow_value: {:?}, total_collateral_value: {:?}, lf_borrowed_value: {:?}, lf_base_position: {:?}", + account, + total_borrow_value.into_inner(), + total_collateral_value.into_inner(), + lf_borrowed_value.into_inner(), + lf_base_position.into_inner(), + ); + + match ( + total_collateral_value > total_borrow_value, + lf_base_position > lf_borrowed_value, + ) { + (true, true) => Ok(( + total_collateral_value - total_borrow_value, + FixedU128::zero(), + lf_base_position - lf_borrowed_value, + FixedU128::zero(), + )), + (true, false) => Ok(( + total_collateral_value - total_borrow_value, + FixedU128::zero(), + FixedU128::zero(), + lf_borrowed_value - lf_base_position, + )), + (false, true) => Ok(( + FixedU128::zero(), + total_borrow_value - total_collateral_value, + lf_base_position - lf_borrowed_value, + FixedU128::zero(), + )), + (false, false) => Ok(( + FixedU128::zero(), + total_borrow_value - total_collateral_value, + FixedU128::zero(), + lf_borrowed_value - lf_base_position, + )), + } + } + + fn total_borrowed_value(borrower: &T::AccountId) -> Result { + let mut total_borrow_value: FixedU128 = FixedU128::zero(); + for (asset_id, _) in Self::active_markets() { + let currency_borrow_amount = Self::current_borrow_balance(borrower, asset_id)?; + if currency_borrow_amount.is_zero() { + continue; + } + total_borrow_value = Self::get_asset_value(asset_id, currency_borrow_amount)? + .checked_add(&total_borrow_value) + .ok_or(ArithmeticError::Overflow)?; + } + + Ok(total_borrow_value) + } + + fn current_collateral_balance( + supplier: &T::AccountId, + asset_id: AssetIdOf, + ) -> Result, DispatchError> { + if !AccountDeposits::::contains_key(asset_id, supplier) { + return Ok(BalanceOf::::zero()); + } + let deposits = Self::account_deposits(asset_id, supplier); + if !deposits.is_collateral { + return Ok(BalanceOf::::zero()); + } + if deposits.voucher_balance.is_zero() { + return Ok(BalanceOf::::zero()); + } + let exchange_rate = Self::exchange_rate_stored(asset_id)?; + let underlying_amount = + Self::calc_underlying_amount(deposits.voucher_balance, exchange_rate)?; + let market = Self::market(asset_id)?; + let effects_amount = market.collateral_factor.mul_ceil(underlying_amount); + + Ok(BalanceOf::::saturated_from(effects_amount)) + } + + fn collateral_asset_value( + supplier: &T::AccountId, + asset_id: AssetIdOf, + ) -> Result { + let effects_amount = Self::current_collateral_balance(supplier, asset_id)?; + + Self::get_asset_value(asset_id, effects_amount) + } + + fn liquidation_threshold_asset_value( + borrower: &T::AccountId, + asset_id: AssetIdOf, + ) -> Result { + if !AccountDeposits::::contains_key(asset_id, borrower) { + return Ok(FixedU128::zero()); + } + let deposits = Self::account_deposits(asset_id, borrower); + if !deposits.is_collateral { + return Ok(FixedU128::zero()); + } + if deposits.voucher_balance.is_zero() { + return Ok(FixedU128::zero()); + } + let exchange_rate = Self::exchange_rate_stored(asset_id)?; + let underlying_amount = + Self::calc_underlying_amount(deposits.voucher_balance, exchange_rate)?; + let market = Self::market(asset_id)?; + let effects_amount = market.liquidation_threshold.mul_ceil(underlying_amount); + + Self::get_asset_value(asset_id, effects_amount) + } + + fn total_collateral_value(supplier: &T::AccountId) -> Result { + let mut total_asset_value: FixedU128 = FixedU128::zero(); + for (asset_id, _market) in Self::active_markets() { + total_asset_value = total_asset_value + .checked_add(&Self::collateral_asset_value(supplier, asset_id)?) + .ok_or(ArithmeticError::Overflow)?; + } + + Ok(total_asset_value) + } + + fn total_liquidation_threshold_value( + borrower: &T::AccountId, + ) -> Result { + let mut total_asset_value: FixedU128 = FixedU128::zero(); + for (asset_id, _market) in Self::active_markets() { + total_asset_value = total_asset_value + .checked_add(&Self::liquidation_threshold_asset_value( + borrower, asset_id, + )?) + .ok_or(ArithmeticError::Overflow)?; + } + + Ok(total_asset_value) + } + + /// Checks if the redeemer should be allowed to redeem tokens in given market + fn redeem_allowed( + asset_id: AssetIdOf, + redeemer: &T::AccountId, + voucher_amount: BalanceOf, + ) -> DispatchResult { + log::trace!( + target: "loans::redeem_allowed", + "asset_id: {:?}, redeemer: {:?}, voucher_amount: {:?}", + asset_id, + redeemer, + voucher_amount, + ); + let deposit = Self::account_deposits(asset_id, redeemer); + if deposit.voucher_balance < voucher_amount { + return Err(Error::::InsufficientDeposit.into()); + } + + let exchange_rate = Self::exchange_rate_stored(asset_id)?; + let redeem_amount = Self::calc_underlying_amount(voucher_amount, exchange_rate)?; + Self::ensure_enough_cash(asset_id, redeem_amount)?; + + if !deposit.is_collateral { + return Ok(()); + } + + let market = Self::market(asset_id)?; + let effects_amount = market.collateral_factor.mul_ceil(redeem_amount); + let redeem_effects_value = Self::get_asset_value(asset_id, effects_amount)?; + log::trace!( + target: "loans::redeem_allowed", + "redeem_amount: {:?}, redeem_effects_value: {:?}", + redeem_amount, + redeem_effects_value.into_inner(), + ); + + Self::ensure_liquidity( + redeemer, + redeem_effects_value, + Self::liquidation_free_collaterals().contains(&asset_id), + )?; + + Ok(()) + } + + #[require_transactional] + pub fn do_redeem_voucher( + who: &T::AccountId, + asset_id: AssetIdOf, + voucher_amount: BalanceOf, + ) -> Result, DispatchError> { + Self::redeem_allowed(asset_id, who, voucher_amount)?; + Self::update_reward_supply_index(asset_id)?; + Self::distribute_supplier_reward(asset_id, who)?; + + let exchange_rate = Self::exchange_rate_stored(asset_id)?; + let redeem_amount = Self::calc_underlying_amount(voucher_amount, exchange_rate)?; + + AccountDeposits::::try_mutate_exists(asset_id, who, |deposits| -> DispatchResult { + let mut d = deposits.unwrap_or_default(); + d.voucher_balance = d + .voucher_balance + .checked_sub(voucher_amount) + .ok_or(ArithmeticError::Underflow)?; + if d.voucher_balance.is_zero() { + // remove deposits storage if zero balance + *deposits = None; + } else { + *deposits = Some(d); + } + Ok(()) + })?; + TotalSupply::::try_mutate(asset_id, |total_balance| -> DispatchResult { + let new_balance = total_balance + .checked_sub(voucher_amount) + .ok_or(ArithmeticError::Underflow)?; + *total_balance = new_balance; + Ok(()) + })?; + + T::Assets::transfer(asset_id, &Self::account_id(), who, redeem_amount, false) + .map_err(|_| Error::::InsufficientCash)?; + Ok(redeem_amount) + } + + /// Borrower shouldn't borrow more than his total collateral value + fn borrow_allowed( + asset_id: AssetIdOf, + borrower: &T::AccountId, + borrow_amount: BalanceOf, + ) -> DispatchResult { + Self::ensure_under_borrow_cap(asset_id, borrow_amount)?; + Self::ensure_enough_cash(asset_id, borrow_amount)?; + let borrow_value = Self::get_asset_value(asset_id, borrow_amount)?; + Self::ensure_liquidity( + borrower, + borrow_value, + asset_id == T::LiquidationFreeAssetId::get(), + )?; + + Ok(()) + } + + #[require_transactional] + fn do_repay_borrow_with_amount( + borrower: &T::AccountId, + asset_id: AssetIdOf, + account_borrows: BalanceOf, + repay_amount: BalanceOf, + ) -> DispatchResult { + if account_borrows < repay_amount { + return Err(Error::::TooMuchRepay.into()); + } + Self::update_reward_borrow_index(asset_id)?; + Self::distribute_borrower_reward(asset_id, borrower)?; + + T::Assets::transfer(asset_id, borrower, &Self::account_id(), repay_amount, false)?; + let account_borrows_new = account_borrows + .checked_sub(repay_amount) + .ok_or(ArithmeticError::Underflow)?; + let total_borrows = Self::total_borrows(asset_id); + // NOTE : total_borrows use a different way to calculate interest + // so when user repays all borrows, total_borrows can be less than account_borrows + // which will cause it to fail with `ArithmeticError::Underflow` + // + // Change it back to checked_sub will cause Underflow + let total_borrows_new = total_borrows.saturating_sub(repay_amount); + AccountBorrows::::insert( + asset_id, + borrower, + BorrowSnapshot { + principal: account_borrows_new, + borrow_index: Self::borrow_index(asset_id), + }, + ); + TotalBorrows::::insert(asset_id, total_borrows_new); + + Ok(()) + } + + // Calculates and returns the most recent amount of borrowed balance of `currency_id` + // for `who`. + pub fn current_borrow_balance( + who: &T::AccountId, + asset_id: AssetIdOf, + ) -> Result, DispatchError> { + let snapshot: BorrowSnapshot> = Self::account_borrows(asset_id, who); + if snapshot.principal.is_zero() || snapshot.borrow_index.is_zero() { + return Ok(Zero::zero()); + } + // Calculate new borrow balance using the interest index: + // recent_borrow_balance = snapshot.principal * borrow_index / snapshot.borrow_index + let recent_borrow_balance = Self::borrow_index(asset_id) + .checked_div(&snapshot.borrow_index) + .and_then(|r| r.checked_mul_int(snapshot.principal)) + .ok_or(ArithmeticError::Overflow)?; + + Ok(recent_borrow_balance) + } + + #[require_transactional] + fn update_earned_stored( + who: &T::AccountId, + asset_id: AssetIdOf, + exchange_rate: Rate, + ) -> DispatchResult { + let deposits = AccountDeposits::::get(asset_id, who); + let account_earned = AccountEarned::::get(asset_id, who); + let total_earned_prior_new = exchange_rate + .checked_sub(&account_earned.exchange_rate_prior) + .and_then(|r| r.checked_mul_int(deposits.voucher_balance)) + .and_then(|r| r.checked_add(account_earned.total_earned_prior)) + .ok_or(ArithmeticError::Overflow)?; + + AccountEarned::::insert( + asset_id, + who, + EarnedSnapshot { + exchange_rate_prior: exchange_rate, + total_earned_prior: total_earned_prior_new, + }, + ); + + Ok(()) + } + + /// Checks if the liquidation should be allowed to occur + fn liquidate_borrow_allowed( + borrower: &T::AccountId, + liquidation_asset_id: AssetIdOf, + repay_amount: BalanceOf, + market: &Market>, + ) -> DispatchResult { + log::trace!( + target: "loans::liquidate_borrow_allowed", + "borrower: {:?}, liquidation_asset_id {:?}, repay_amount {:?}, market: {:?}", + borrower, + liquidation_asset_id, + repay_amount, + market + ); + let (liquidity, shortfall, lf_liquidity, _) = + Self::get_account_liquidation_threshold_liquidity(borrower)?; + + // C_other >= B_other + B_dot_over + // C_other >= B_other + max(B_dot - C_lf, 0) + // C_other + C_lf >= B_other + B_dot - B_dot + C_lf + max(B_dot - C_lf, 0) + // C_all - B_all >= max(0, C_lf - B_dot) + // C_all - B_all >= 0 && C_all - B_all >= max(0, C_lf - B_dot) + // shortfall == 0 && liquidity > lf_liquidity + if shortfall.is_zero() && liquidity >= lf_liquidity { + return Err(Error::::InsufficientShortfall.into()); + } + + // The liquidator may not repay more than 50%(close_factor) of the borrower's borrow balance. + let account_borrows = Self::current_borrow_balance(borrower, liquidation_asset_id)?; + let account_borrows_value = Self::get_asset_value(liquidation_asset_id, account_borrows)?; + let repay_value = Self::get_asset_value(liquidation_asset_id, repay_amount)?; + let effects_borrows_value = if liquidation_asset_id == T::LiquidationFreeAssetId::get() { + let base_position = Self::get_lf_base_position(borrower)?; + if account_borrows_value > base_position { + account_borrows_value - base_position + } else { + FixedU128::zero() + } + } else { + account_borrows_value + }; + + if market + .close_factor + .mul_ceil(effects_borrows_value.into_inner()) + < repay_value.into_inner() + { + return Err(Error::::TooMuchRepay.into()); + } + + Ok(()) + } + + /// Note: + /// - liquidation_asset_id is borrower's debt asset. + /// - collateral_asset_id is borrower's collateral asset. + /// - repay_amount is amount of liquidation_asset_id + /// + /// The liquidator will repay a certain amount of liquidation_asset_id from own + /// account for borrower. Then the protocol will reduce borrower's debt + /// and liquidator will receive collateral_asset_id(as voucher amount) from + /// borrower. + #[require_transactional] + pub fn do_liquidate_borrow( + liquidator: T::AccountId, + borrower: T::AccountId, + liquidation_asset_id: AssetIdOf, + repay_amount: BalanceOf, + collateral_asset_id: AssetIdOf, + ) -> DispatchResult { + Self::ensure_active_market(liquidation_asset_id)?; + Self::ensure_active_market(collateral_asset_id)?; + + let market = Self::market(liquidation_asset_id)?; + + if borrower == liquidator { + return Err(Error::::LiquidatorIsBorrower.into()); + } + Self::liquidate_borrow_allowed(&borrower, liquidation_asset_id, repay_amount, &market)?; + + let deposits = AccountDeposits::::get(collateral_asset_id, &borrower); + if !deposits.is_collateral { + return Err(Error::::DepositsAreNotCollateral.into()); + } + let exchange_rate = Self::exchange_rate_stored(collateral_asset_id)?; + let borrower_deposit_amount = exchange_rate + .checked_mul_int(deposits.voucher_balance) + .ok_or(ArithmeticError::Overflow)?; + + let collateral_value = Self::get_asset_value(collateral_asset_id, borrower_deposit_amount)?; + // liquidate_value contains the incentive of liquidator and the punishment of the borrower + let liquidate_value = Self::get_asset_value(liquidation_asset_id, repay_amount)? + .checked_mul(&market.liquidate_incentive) + .ok_or(ArithmeticError::Overflow)?; + + if collateral_value < liquidate_value { + return Err(Error::::InsufficientCollateral.into()); + } + + // Calculate the collateral will get + // + // amount: 1 Unit = 10^12 pico + // price is for 1 pico: 1$ = FixedU128::saturating_from_rational(1, 10^12) + // if price is N($) and amount is M(Unit): + // liquidate_value = price * amount = (N / 10^12) * (M * 10^12) = N * M + // if liquidate_value >= 340282366920938463463.374607431768211455, + // FixedU128::saturating_from_integer(liquidate_value) will overflow, so we use from_inner + // instead of saturating_from_integer, and after calculation use into_inner to get final value. + let collateral_token_price = Self::get_price(collateral_asset_id)?; + let real_collateral_underlying_amount = liquidate_value + .checked_div(&collateral_token_price) + .ok_or(ArithmeticError::Underflow)? + .into_inner(); + + //inside transfer token + Self::liquidated_transfer( + &liquidator, + &borrower, + liquidation_asset_id, + collateral_asset_id, + repay_amount, + real_collateral_underlying_amount, + &market, + )?; + + Ok(()) + } + + #[require_transactional] + fn liquidated_transfer( + liquidator: &T::AccountId, + borrower: &T::AccountId, + liquidation_asset_id: AssetIdOf, + collateral_asset_id: AssetIdOf, + repay_amount: BalanceOf, + collateral_underlying_amount: BalanceOf, + market: &Market>, + ) -> DispatchResult { + log::trace!( + target: "loans::liquidated_transfer", + "liquidator: {:?}, borrower: {:?}, liquidation_asset_id: {:?}, + collateral_asset_id: {:?}, repay_amount: {:?}, collateral_underlying_amount: {:?}", + liquidator, + borrower, + liquidation_asset_id, + collateral_asset_id, + repay_amount, + collateral_underlying_amount + ); + + // update borrow index after accrue interest. + Self::update_reward_borrow_index(liquidation_asset_id)?; + Self::distribute_borrower_reward(liquidation_asset_id, liquidator)?; + + // 1.liquidator repay borrower's debt, + // transfer from liquidator to module account + T::Assets::transfer( + liquidation_asset_id, + liquidator, + &Self::account_id(), + repay_amount, + false, + )?; + + // 2.the system reduce borrower's debt + let account_borrows = Self::current_borrow_balance(borrower, liquidation_asset_id)?; + let account_borrows_new = account_borrows + .checked_sub(repay_amount) + .ok_or(ArithmeticError::Underflow)?; + let total_borrows = Self::total_borrows(liquidation_asset_id); + let total_borrows_new = total_borrows + .checked_sub(repay_amount) + .ok_or(ArithmeticError::Underflow)?; + AccountBorrows::::insert( + liquidation_asset_id, + borrower, + BorrowSnapshot { + principal: account_borrows_new, + borrow_index: Self::borrow_index(liquidation_asset_id), + }, + ); + TotalBorrows::::insert(liquidation_asset_id, total_borrows_new); + + // update supply index before modify supply balance. + Self::update_reward_supply_index(collateral_asset_id)?; + Self::distribute_supplier_reward(collateral_asset_id, liquidator)?; + Self::distribute_supplier_reward(collateral_asset_id, borrower)?; + Self::distribute_supplier_reward( + collateral_asset_id, + &Self::incentive_reward_account_id()?, + )?; + + // 3.the liquidator will receive voucher token from borrower + let exchange_rate = Self::exchange_rate_stored(collateral_asset_id)?; + let collateral_amount = + Self::calc_collateral_amount(collateral_underlying_amount, exchange_rate)?; + AccountDeposits::::try_mutate( + collateral_asset_id, + borrower, + |deposits| -> DispatchResult { + deposits.voucher_balance = deposits + .voucher_balance + .checked_sub(collateral_amount) + .ok_or(ArithmeticError::Underflow)?; + Ok(()) + }, + )?; + let incentive_reserved_amount = market.liquidate_incentive_reserved_factor.mul_floor( + FixedU128::from_inner(collateral_amount) + .checked_div(&market.liquidate_incentive) + .map(|r| r.into_inner()) + .ok_or(ArithmeticError::Underflow)?, + ); + // increase liquidator's voucher_balance + AccountDeposits::::try_mutate( + collateral_asset_id, + liquidator, + |deposits| -> DispatchResult { + deposits.voucher_balance = deposits + .voucher_balance + .checked_add(collateral_amount - incentive_reserved_amount) + .ok_or(ArithmeticError::Overflow)?; + Ok(()) + }, + )?; + // increase reserve's voucher_balance + AccountDeposits::::try_mutate( + collateral_asset_id, + Self::incentive_reward_account_id()?, + |deposits| -> DispatchResult { + deposits.voucher_balance = deposits + .voucher_balance + .checked_add(incentive_reserved_amount) + .ok_or(ArithmeticError::Overflow)?; + Ok(()) + }, + )?; + + Self::deposit_event(Event::::LiquidatedBorrow( + liquidator.clone(), + borrower.clone(), + liquidation_asset_id, + collateral_asset_id, + repay_amount, + collateral_underlying_amount, + )); + + Ok(()) + } + + // Ensures a given `asset_id` is an active market. + fn ensure_active_market(asset_id: AssetIdOf) -> Result>, DispatchError> { + Self::active_markets() + .find(|(id, _)| id == &asset_id) + .map(|(_, market)| market) + .ok_or_else(|| Error::::MarketNotActivated.into()) + } + + /// Ensure market is enough to supply `amount` asset. + fn ensure_under_supply_cap(asset_id: AssetIdOf, amount: BalanceOf) -> DispatchResult { + let market = Self::market(asset_id)?; + // Assets holded by market currently. + let current_cash = T::Assets::balance(asset_id, &Self::account_id()); + let total_cash = current_cash + .checked_add(amount) + .ok_or(ArithmeticError::Overflow)?; + ensure!( + total_cash <= market.supply_cap, + Error::::SupplyCapacityExceeded + ); + + Ok(()) + } + + /// Make sure the borrowing under the borrow cap + fn ensure_under_borrow_cap(asset_id: AssetIdOf, amount: BalanceOf) -> DispatchResult { + let market = Self::market(asset_id)?; + let total_borrows = Self::total_borrows(asset_id); + let new_total_borrows = total_borrows + .checked_add(amount) + .ok_or(ArithmeticError::Overflow)?; + ensure!( + new_total_borrows <= market.borrow_cap, + Error::::BorrowCapacityExceeded + ); + + Ok(()) + } + + /// Make sure there is enough cash available in the pool + fn ensure_enough_cash(asset_id: AssetIdOf, amount: BalanceOf) -> DispatchResult { + let reducible_cash = Self::get_total_cash(asset_id) + .checked_sub(Self::total_reserves(asset_id)) + .ok_or(ArithmeticError::Underflow)?; + if reducible_cash < amount { + return Err(Error::::InsufficientCash.into()); + } + + Ok(()) + } + + // Ensures a given `ptoken_id` is unique in `Markets` and `UnderlyingAssetId`. + fn ensure_ptoken(ptoken_id: CurrencyId) -> DispatchResult { + // The ptoken id is unique, cannot be repeated + ensure!( + !UnderlyingAssetId::::contains_key(ptoken_id), + Error::::InvalidPtokenId + ); + + // The ptoken id should not be the same as the id of any asset in markets + ensure!( + !Markets::::contains_key(ptoken_id), + Error::::InvalidPtokenId + ); + + Ok(()) + } + + // Ensures that `account` have sufficient liquidity to move your assets + // Returns `Err` If InsufficientLiquidity + // `account`: account that need a liquidity check + // `reduce_amount`: values that will have an impact on liquidity + // `lf_enable`: check in liquidation free mode which means borrowing dot or redeeming assets in + // `LiquidationFreeCollaterals`. + fn ensure_liquidity( + account: &T::AccountId, + reduce_amount: FixedU128, + lf_enable: bool, + ) -> DispatchResult { + let (total_liquidity, _, lf_liquidity, _) = Self::get_account_liquidity(account)?; + + if lf_enable && max(total_liquidity, lf_liquidity) >= reduce_amount { + return Ok(()); + } + + if !lf_enable && total_liquidity >= lf_liquidity + reduce_amount { + return Ok(()); + } + Err(Error::::InsufficientLiquidity.into()) + } + + pub fn calc_underlying_amount( + voucher_amount: BalanceOf, + exchange_rate: Rate, + ) -> Result, DispatchError> { + Ok(exchange_rate + .checked_mul_int(voucher_amount) + .ok_or(ArithmeticError::Overflow)?) + } + + pub fn calc_collateral_amount( + underlying_amount: BalanceOf, + exchange_rate: Rate, + ) -> Result, DispatchError> { + Ok(FixedU128::from_inner(underlying_amount) + .checked_div(&exchange_rate) + .map(|r| r.into_inner()) + .ok_or(ArithmeticError::Underflow)?) + } + + fn get_total_cash(asset_id: AssetIdOf) -> BalanceOf { + T::Assets::reducible_balance(asset_id, &Self::account_id(), false) + } + + // Returns the uniform format price. + // Formula: `price = oracle_price * 10.pow(18 - asset_decimal)` + // This particular price makes it easy to calculate the value , + // because we don't have to consider decimal for each asset. ref: get_asset_value + // + // Returns `Err` if the oracle price not ready + pub fn get_price(asset_id: AssetIdOf) -> Result { + let (price, _) = + T::PriceFeeder::get_price(&asset_id).ok_or(Error::::PriceOracleNotReady)?; + if price.is_zero() { + return Err(Error::::PriceIsZero.into()); + } + log::trace!( + target: "loans::get_price", "price: {:?}", price.into_inner() + ); + + Ok(price) + } + + // Returns the value of the asset, in dollars. + // Formula: `value = oracle_price * balance / 1e18(oracle_price_decimal) / asset_decimal` + // As the price is a result of `oracle_price * 10.pow(18 - asset_decimal)`, + // then `value = price * balance / 1e18`. + // We use FixedU128::from_inner(balance) instead of `balance / 1e18`. + // + // Returns `Err` if oracle price not ready or arithmetic error. + pub fn get_asset_value( + asset_id: AssetIdOf, + amount: BalanceOf, + ) -> Result { + let value = Self::get_price(asset_id)? + .checked_mul(&FixedU128::from_inner(amount)) + .ok_or(ArithmeticError::Overflow)?; + + Ok(value) + } + + // Returns a stored Market. + // + // Returns `Err` if market does not exist. + pub fn market(asset_id: AssetIdOf) -> Result>, DispatchError> { + Markets::::try_get(asset_id).map_err(|_err| Error::::MarketDoesNotExist.into()) + } + + // Mutates a stored Market. + // + // Returns `Err` if market does not exist. + pub(crate) fn mutate_market( + asset_id: AssetIdOf, + cb: F, + ) -> Result>, DispatchError> + where + F: FnOnce(&mut Market>) -> Market>, + { + Markets::::try_mutate( + asset_id, + |opt| -> Result>, DispatchError> { + if let Some(market) = opt { + return Ok(cb(market)); + } + Err(Error::::MarketDoesNotExist.into()) + }, + ) + } + + // All markets that are `MarketStatus::Active`. + fn active_markets() -> impl Iterator, Market>)> { + Markets::::iter().filter(|(_, market)| market.state == MarketState::Active) + } + + // Returns a stored asset_id + // + // Returns `Err` if asset_id does not exist, it also means that ptoken_id is invalid. + pub fn underlying_id(ptoken_id: AssetIdOf) -> Result, DispatchError> { + UnderlyingAssetId::::try_get(ptoken_id) + .map_err(|_err| Error::::InvalidPtokenId.into()) + } + + // Returns the ptoken_id of the related asset + // + // Returns `Err` if market does not exist. + pub fn ptoken_id(asset_id: AssetIdOf) -> Result, DispatchError> { + if let Ok(market) = Self::market(asset_id) { + Ok(market.ptoken_id) + } else { + Err(Error::::MarketDoesNotExist.into()) + } + } + + // Returns the incentive reward account + pub fn incentive_reward_account_id() -> Result { + let account_id: T::AccountId = T::PalletId::get().into_account_truncating(); + let entropy = (b"loans/incentive", &[account_id]).using_encoded(blake2_256); + Ok(T::AccountId::decode(&mut &entropy[..]).map_err(|_| Error::::CodecError)?) + } +} + +impl LoansTrait, AccountIdOf, BalanceOf> for Pallet { + fn do_mint( + supplier: &AccountIdOf, + asset_id: AssetIdOf, + amount: BalanceOf, + ) -> Result<(), DispatchError> { + ensure!(!amount.is_zero(), Error::::InvalidAmount); + Self::ensure_active_market(asset_id)?; + Self::ensure_under_supply_cap(asset_id, amount)?; + + Self::accrue_interest(asset_id)?; + + // update supply index before modify supply balance. + Self::update_reward_supply_index(asset_id)?; + Self::distribute_supplier_reward(asset_id, supplier)?; + + let exchange_rate = Self::exchange_rate_stored(asset_id)?; + Self::update_earned_stored(supplier, asset_id, exchange_rate)?; + let voucher_amount = Self::calc_collateral_amount(amount, exchange_rate)?; + ensure!(!voucher_amount.is_zero(), Error::::InvalidExchangeRate); + + T::Assets::transfer(asset_id, supplier, &Self::account_id(), amount, false)?; + AccountDeposits::::try_mutate(asset_id, supplier, |deposits| -> DispatchResult { + deposits.voucher_balance = deposits + .voucher_balance + .checked_add(voucher_amount) + .ok_or(ArithmeticError::Overflow)?; + Ok(()) + })?; + TotalSupply::::try_mutate(asset_id, |total_balance| -> DispatchResult { + let new_balance = total_balance + .checked_add(voucher_amount) + .ok_or(ArithmeticError::Overflow)?; + *total_balance = new_balance; + Ok(()) + })?; + Self::deposit_event(Event::::Deposited(supplier.clone(), asset_id, amount)); + Ok(()) + } + + fn do_borrow( + borrower: &AccountIdOf, + asset_id: AssetIdOf, + amount: BalanceOf, + ) -> Result<(), DispatchError> { + Self::ensure_active_market(asset_id)?; + + Self::accrue_interest(asset_id)?; + Self::borrow_allowed(asset_id, borrower, amount)?; + + // update borrow index after accrue interest. + Self::update_reward_borrow_index(asset_id)?; + Self::distribute_borrower_reward(asset_id, borrower)?; + + let account_borrows = Self::current_borrow_balance(borrower, asset_id)?; + let account_borrows_new = account_borrows + .checked_add(amount) + .ok_or(ArithmeticError::Overflow)?; + let total_borrows = Self::total_borrows(asset_id); + let total_borrows_new = total_borrows + .checked_add(amount) + .ok_or(ArithmeticError::Overflow)?; + AccountBorrows::::insert( + asset_id, + borrower, + BorrowSnapshot { + principal: account_borrows_new, + borrow_index: Self::borrow_index(asset_id), + }, + ); + TotalBorrows::::insert(asset_id, total_borrows_new); + T::Assets::transfer(asset_id, &Self::account_id(), borrower, amount, false)?; + Self::deposit_event(Event::::Borrowed(borrower.clone(), asset_id, amount)); + Ok(()) + } + + fn do_collateral_asset( + supplier: &AccountIdOf, + asset_id: AssetIdOf, + enable: bool, + ) -> Result<(), DispatchError> { + Self::ensure_active_market(asset_id)?; + ensure!( + AccountDeposits::::contains_key(asset_id, supplier), + Error::::NoDeposit + ); + let mut deposits = Self::account_deposits(asset_id, supplier); + // turn on the collateral button + if enable { + deposits.is_collateral = true; + AccountDeposits::::insert(asset_id, supplier, deposits); + Self::deposit_event(Event::::CollateralAssetAdded(supplier.clone(), asset_id)); + return Ok(()); + } + // turn off the collateral button after checking the liquidity + let total_collateral_value = Self::total_collateral_value(supplier)?; + let collateral_asset_value = Self::collateral_asset_value(supplier, asset_id)?; + let total_borrowed_value = Self::total_borrowed_value(supplier)?; + log::trace!( + target: "loans::collateral_asset", + "total_collateral_value: {:?}, collateral_asset_value: {:?}, total_borrowed_value: {:?}", + total_collateral_value.into_inner(), + collateral_asset_value.into_inner(), + total_borrowed_value.into_inner(), + ); + if total_collateral_value + < total_borrowed_value + .checked_add(&collateral_asset_value) + .ok_or(ArithmeticError::Overflow)? + { + return Err(Error::::InsufficientLiquidity.into()); + } + deposits.is_collateral = false; + AccountDeposits::::insert(asset_id, supplier, deposits); + + Self::deposit_event(Event::::CollateralAssetRemoved( + supplier.clone(), + asset_id, + )); + + Ok(()) + } + + fn do_repay_borrow( + borrower: &AccountIdOf, + asset_id: AssetIdOf, + amount: BalanceOf, + ) -> Result<(), DispatchError> { + Self::ensure_active_market(asset_id)?; + Self::accrue_interest(asset_id)?; + let account_borrows = Self::current_borrow_balance(borrower, asset_id)?; + Self::do_repay_borrow_with_amount(borrower, asset_id, account_borrows, amount)?; + Self::deposit_event(Event::::RepaidBorrow(borrower.clone(), asset_id, amount)); + Ok(()) + } + + fn do_redeem( + supplier: &AccountIdOf, + asset_id: AssetIdOf, + amount: BalanceOf, + ) -> Result<(), DispatchError> { + Self::ensure_active_market(asset_id)?; + Self::accrue_interest(asset_id)?; + let exchange_rate = Self::exchange_rate_stored(asset_id)?; + Self::update_earned_stored(supplier, asset_id, exchange_rate)?; + let voucher_amount = Self::calc_collateral_amount(amount, exchange_rate)?; + let redeem_amount = Self::do_redeem_voucher(supplier, asset_id, voucher_amount)?; + Self::deposit_event(Event::::Redeemed( + supplier.clone(), + asset_id, + redeem_amount, + )); + Ok(()) + } +} + +impl LoansMarketDataProvider, BalanceOf> for Pallet { + fn get_market_info(asset_id: AssetIdOf) -> Result { + let market = Self::market(asset_id)?; + let full_rate = + Self::get_full_interest_rate(asset_id).ok_or(Error::::InvalidRateModelParam)?; + Ok(MarketInfo { + collateral_factor: market.collateral_factor, + liquidation_threshold: market.liquidation_threshold, + reserve_factor: market.reserve_factor, + close_factor: market.close_factor, + full_rate, + }) + } + + fn get_market_status(asset_id: AssetIdOf) -> Result, DispatchError> { + let ( + borrow_rate, + supply_rate, + exchange_rate, + utilization, + total_borrows, + total_reserves, + borrow_index, + ) = Self::get_market_status(asset_id)?; + Ok(MarketStatus { + borrow_rate, + supply_rate, + exchange_rate, + utilization, + total_borrows, + total_reserves, + borrow_index, + }) + } + + fn get_full_interest_rate(asset_id: AssetIdOf) -> Option { + if let Ok(market) = Self::market(asset_id) { + let rate = match market.rate_model { + InterestRateModel::Jump(jump) => Some(jump.full_rate), + _ => None, + }; + return rate; + } + None + } +} + +impl LoansPositionDataProvider, AccountIdOf, BalanceOf> + for Pallet +{ + fn get_current_borrow_balance( + borrower: &AccountIdOf, + asset_id: AssetIdOf, + ) -> Result, DispatchError> { + Self::accrue_interest(asset_id)?; + Self::current_borrow_balance(borrower, asset_id) + } + + fn get_current_collateral_balance( + supplier: &AccountIdOf, + asset_id: AssetIdOf, + ) -> Result, DispatchError> { + Self::current_collateral_balance(supplier, asset_id) + } +} diff --git a/crates/loans/src/migrations.rs b/crates/loans/src/migrations.rs new file mode 100644 index 0000000000..50117fae27 --- /dev/null +++ b/crates/loans/src/migrations.rs @@ -0,0 +1,190 @@ +// Copyright 2021-2022 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. + +use super::*; + +pub mod v3 { + use super::*; + use crate::{pallet::StorageVersion, Config, Weight}; + use frame_support::{log, traits::Get}; + + pub const DEFAULT_LIQUIDATE_INCENTIVE_RESERVED_FACTOR: Ratio = Ratio::from_percent(3); + pub const DEFAULT_LIQUIDATION_OFFSET: Ratio = Ratio::from_percent(10); + + #[cfg_attr(feature = "std", derive(serde::Deserialize, serde::Serialize))] + #[derive(Clone, PartialEq, Eq, codec::Decode, codec::Encode, RuntimeDebug, TypeInfo)] + pub struct V2Market { + /// The collateral utilization ratio + pub collateral_factor: Ratio, + /// Fraction of interest currently set aside for reserves + pub reserve_factor: Ratio, + /// The percent, ranging from 0% to 100%, of a liquidatable account's + /// borrow that can be repaid in a single liquidate transaction. + pub close_factor: Ratio, + /// Liquidation incentive ratio + pub liquidate_incentive: Rate, + /// Current interest rate model being used + pub rate_model: InterestRateModel, + /// Current market state + pub state: MarketState, + /// Upper bound of supplying + pub supply_cap: Balance, + /// Upper bound of borrowing + pub borrow_cap: Balance, + /// Ptoken asset id + pub ptoken_id: CurrencyId, + } + #[frame_support::storage_alias] + type MarketRewardSpeed = + StorageMap, Blake2_128Concat, AssetIdOf, BalanceOf>; + + #[frame_support::storage_alias] + type RewardAccured = StorageMap< + crate::Pallet, + Blake2_128Concat, + ::AccountId, + BalanceOf, + >; + + #[frame_support::storage_alias] + type LastAccruedTimestamp = StorageValue, Timestamp, ValueQuery>; + + #[cfg(feature = "try-runtime")] + pub fn pre_migrate() -> Result<(), &'static str> { + #[frame_support::storage_alias] + type Markets = + StorageMap, Blake2_128Concat, AssetIdOf, V2Market>>; + frame_support::ensure!( + StorageVersion::::get() == crate::Versions::V2, + "must upgrade linearly" + ); + Markets::::iter().for_each(|(asset_id, _)| { + log::info!("market {:#?} need to migrate", asset_id,); + }); + let reward_speed_count = MarketRewardSpeed::::iter().count(); + log::info!( + "total {:#?} reward speed items need to migrate", + reward_speed_count + ); + + let last_accrued_timestamp = LastAccruedTimestamp::::get(); + log::info!( + "LastAccruedTimestamp: {:#?} is about to move.", + last_accrued_timestamp + ); + + let old_name_items_count = RewardAccured::::iter().count(); + let new_name_items_count = RewardAccrued::::iter().count(); + log::info!( + "old_name_items_count: {:#?}, new_name_items_count: {:#?}.", + old_name_items_count, + new_name_items_count, + ); + + log::info!("👜 loans v3 migration passes PRE migrate checks ✅",); + + Ok(()) + } + + /// Migration to sorted [`SortedListProvider`]. + pub fn migrate() -> Weight { + if StorageVersion::::get() == crate::Versions::V2 { + log::info!("migrating loans to Versions::V3",); + + Markets::::translate::>, _>(|_key, market| { + Some(Market { + borrow_cap: market.borrow_cap, + supply_cap: market.supply_cap, + collateral_factor: market.collateral_factor, + liquidation_threshold: (market.collateral_factor + + market.collateral_factor * DEFAULT_LIQUIDATION_OFFSET), + reserve_factor: market.reserve_factor, + close_factor: market.close_factor, + liquidate_incentive_reserved_factor: + DEFAULT_LIQUIDATE_INCENTIVE_RESERVED_FACTOR, + liquidate_incentive: market.liquidate_incentive, + rate_model: market.rate_model, + state: market.state, + ptoken_id: market.ptoken_id, + }) + }); + + MarketRewardSpeed::::iter().for_each(|(asset_id, reward_speed)| { + RewardSupplySpeed::::insert(asset_id, reward_speed); + RewardBorrowSpeed::::insert(asset_id, reward_speed); + }); + + //remove old data. + let _ = MarketRewardSpeed::::clear(u32::max_value(), None); + LastAccruedTimestamp::::kill(); + + StorageVersion::::put(crate::Versions::V3); + log::info!("👜 completed loans migration to Versions::V3",); + + T::BlockWeights::get().max_block + } else { + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + pub fn post_migrate() -> Result<(), &'static str> { + frame_support::ensure!( + StorageVersion::::get() == crate::Versions::V3, + "must upgrade to V3" + ); + Markets::::iter().for_each(|(asset_id, market)| { + log::info!( + "market {:#?}, collateral_factor {:?}, liquidation_threshold {:?}, liquidate_incentive_reserved_factor {:?}", + asset_id, + market.collateral_factor, + market.liquidation_threshold, + market.liquidate_incentive_reserved_factor + ); + }); + RewardSupplySpeed::::iter().for_each(|(asset_id, supply_reward_speed)| { + let borrow_reward_speed = RewardBorrowSpeed::::get(asset_id); + log::info!( + "market {:#?}, supply_reward_speed {:?}, borrow_reward_speed {:?}", + asset_id, + supply_reward_speed, + borrow_reward_speed + ); + }); + + let reward_speed_count = MarketRewardSpeed::::iter().count(); + log::info!( + "total {:#?} reward speed items remains after migrate", + reward_speed_count + ); + + let last_accrued_timestamp = LastAccruedTimestamp::::get(); + log::info!( + "LastAccruedTimestamp: {:#?} after migrate.", + last_accrued_timestamp + ); + + let old_name_items_count = RewardAccured::::iter().count(); + let new_name_items_count = RewardAccrued::::iter().count(); + log::info!( + "old_name_items_count: {:#?}, new_name_items_count: {:#?}.", + old_name_items_count, + new_name_items_count, + ); + + log::info!("👜 loans v3 migration passes POST migrate checks ✅",); + + Ok(()) + } +} diff --git a/crates/loans/src/mock.rs b/crates/loans/src/mock.rs new file mode 100644 index 0000000000..66a7426291 --- /dev/null +++ b/crates/loans/src/mock.rs @@ -0,0 +1,478 @@ +// 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. + +pub use super::*; + +use frame_support::{ + construct_runtime, parameter_types, traits::Everything, traits::SortedMembers, PalletId, +}; +use frame_system::{EnsureRoot, EnsureSignedBy}; +use orml_traits::{DataFeeder, DataProvider, DataProviderExtended}; +use pallet_traits::{ + DecimalProvider, ExchangeRateProvider, LiquidStakingCurrenciesProvider, + VaultTokenCurrenciesFilter, VaultTokenExchangeRateProvider, +}; +use primitives::{ + tokens::{CDOT_6_13, PCDOT_6_13}, + *, +}; +use sp_core::H256; +use sp_runtime::{testing::Header, traits::IdentityLookup, AccountId32}; +use sp_std::vec::Vec; +use std::{cell::RefCell, collections::HashMap}; + +pub use primitives::tokens::{DOT, HKO, KSM, PDOT, PHKO, PKSM, PUSDT, SDOT, SKSM, USDT}; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Storage, Config, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Event}, + Loans: crate::{Pallet, Storage, Call, Event}, + Prices: pallet_prices::{Pallet, Storage, Call, Event}, + TimestampPallet: pallet_timestamp::{Pallet, Call, Storage, Inherent}, + Assets: pallet_assets::{Pallet, Call, Storage, Event}, + DefaultAMM: pallet_amm::{Pallet, Call, Storage, Event}, + CurrencyAdapter: pallet_currency_adapter::{Pallet, Call}, + } +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const SS58Prefix: u8 = 42; +} + +impl frame_system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Call = Call; + type Index = u64; + type BlockNumber = BlockNumber; + type Hash = H256; + type Hashing = ::sp_runtime::traits::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 = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +pub type AccountId = AccountId32; +pub type BlockNumber = u64; + +pub const ALICE: AccountId = AccountId32::new([1u8; 32]); +pub const BOB: AccountId = AccountId32::new([2u8; 32]); +pub const CHARLIE: AccountId = AccountId32::new([3u8; 32]); +pub const DAVE: AccountId = AccountId32::new([4u8; 32]); +pub const EVE: AccountId = AccountId32::new([5u8; 32]); + +parameter_types! { + pub const MinimumPeriod: u64 = 5; +} + +impl pallet_timestamp::Config for Test { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = MinimumPeriod; + type WeightInfo = (); +} + +parameter_types! { + pub const ExistentialDeposit: Balance = 1; + pub const MaxLocks: u32 = 50; +} + +impl pallet_balances::Config for Test { + type Balance = Balance; + type DustRemoval = (); + type Event = Event; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = pallet_balances::weights::SubstrateWeight; + type MaxLocks = MaxLocks; + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; +} + +// pallet-price is using for benchmark compilation +pub type TimeStampedPrice = orml_oracle::TimestampedValue; +pub struct MockDataProvider; +impl DataProvider for MockDataProvider { + fn get(_asset_id: &CurrencyId) -> Option { + Some(TimeStampedPrice { + value: Price::saturating_from_integer(100), + timestamp: 0, + }) + } +} + +impl DataProviderExtended for MockDataProvider { + fn get_no_op(_key: &CurrencyId) -> Option { + None + } + + fn get_all_values() -> Vec<(CurrencyId, Option)> { + vec![] + } +} + +impl DataFeeder for MockDataProvider { + fn feed_value(_: AccountId, _: CurrencyId, _: TimeStampedPrice) -> sp_runtime::DispatchResult { + Ok(()) + } +} + +pub struct LiquidStakingExchangeRateProvider; +impl ExchangeRateProvider for LiquidStakingExchangeRateProvider { + fn get_exchange_rate(_: &CurrencyId) -> Option { + Some(Rate::saturating_from_rational(150, 100)) + } +} + +pub struct Decimal; +impl DecimalProvider for Decimal { + fn get_decimal(asset_id: &CurrencyId) -> Option { + match *asset_id { + KSM | SKSM => Some(12), + HKO => Some(12), + USDT => Some(6), + _ => None, + } + } +} + +pub struct LiquidStaking; +impl LiquidStakingCurrenciesProvider for LiquidStaking { + fn get_staking_currency() -> Option { + Some(KSM) + } + fn get_liquid_currency() -> Option { + Some(SKSM) + } +} + +impl ExchangeRateProvider for LiquidStaking { + fn get_exchange_rate(_: &CurrencyId) -> Option { + Some(Rate::saturating_from_rational(150, 100)) + } +} + +pub struct TokenExchangeRateProvider; +impl VaultTokenExchangeRateProvider for TokenExchangeRateProvider { + fn get_exchange_rate(_: &CurrencyId, _: Rate) -> Option { + Some(Rate::saturating_from_rational(100, 150)) + } +} + +pub struct TokenCurrenciesFilter; +impl VaultTokenCurrenciesFilter for TokenCurrenciesFilter { + fn contains(_asset_id: &CurrencyId) -> bool { + return false; + } +} + +pub struct VaultLoansRateProvider; +impl LoansMarketDataProvider for VaultLoansRateProvider { + fn get_full_interest_rate(_asset_id: CurrencyId) -> Option { + Some(Rate::from_inner(450_000_000_000_000_000)) + } + + fn get_market_info(_: CurrencyId) -> Result { + Ok(Default::default()) + } + + fn get_market_status( + _: CurrencyId, + ) -> Result, sp_runtime::DispatchError> { + Ok(Default::default()) + } +} + +parameter_types! { + pub const RelayCurrency: CurrencyId = KSM; +} + +// AMM instance initialization +parameter_types! { + pub const AMMPalletId: PalletId = PalletId(*b"par/ammp"); + // pub const DefaultLpFee: Ratio = Ratio::from_rational(25u32, 10000u32); // 0.25% + // pub const DefaultProtocolFee: Ratio = Ratio::from_rational(5u32, 10000u32); + pub DefaultLpFee: Ratio = Ratio::from_rational(25u32, 10000u32); // 0.3% + pub const MinimumLiquidity: u128 = 1_000u128; + pub const LockAccountId: AccountId = ALICE; + pub const MaxLengthRoute: u8 = 10; +} + +pub struct AliceCreatePoolOrigin; +impl SortedMembers for AliceCreatePoolOrigin { + fn sorted_members() -> Vec { + vec![ALICE] + } +} + +impl pallet_amm::Config for Test { + type Event = Event; + type Assets = CurrencyAdapter; + type PalletId = AMMPalletId; + type LockAccountId = LockAccountId; + type AMMWeightInfo = (); + type CreatePoolOrigin = EnsureSignedBy; + type ProtocolFeeUpdateOrigin = EnsureSignedBy; + type LpFee = DefaultLpFee; + type MinimumLiquidity = MinimumLiquidity; + type MaxLengthRoute = MaxLengthRoute; + type GetNativeCurrencyId = NativeCurrencyId; +} + +impl pallet_prices::Config for Test { + type Event = Event; + type Source = MockDataProvider; + type FeederOrigin = EnsureRoot; + type UpdateOrigin = EnsureRoot; + type LiquidStakingExchangeRateProvider = LiquidStaking; + type LiquidStakingCurrenciesProvider = LiquidStaking; + type VaultTokenCurrenciesFilter = TokenCurrenciesFilter; + type VaultTokenExchangeRateProvider = TokenExchangeRateProvider; + type VaultLoansRateProvider = VaultLoansRateProvider; + type RelayCurrency = RelayCurrency; + type Decimal = Decimal; + type AMM = DefaultAMM; + type Assets = CurrencyAdapter; + type WeightInfo = (); +} + +pub struct MockPriceFeeder; + +impl MockPriceFeeder { + thread_local! { + pub static PRICES: RefCell>> = { + RefCell::new( + vec![HKO, DOT, KSM, USDT, SKSM, SDOT, CDOT_6_13] + .iter() + .map(|&x| (x, Some((Price::saturating_from_integer(1), 1)))) + .collect() + ) + }; + } + + pub fn set_price(asset_id: CurrencyId, price: Price) { + Self::PRICES.with(|prices| { + prices.borrow_mut().insert(asset_id, Some((price, 1u64))); + }); + } + + pub fn reset() { + Self::PRICES.with(|prices| { + for (_, val) in prices.borrow_mut().iter_mut() { + *val = Some((Price::saturating_from_integer(1), 1u64)); + } + }) + } +} + +impl PriceFeeder for MockPriceFeeder { + fn get_price(asset_id: &CurrencyId) -> Option { + Self::PRICES.with(|prices| *prices.borrow().get(asset_id).unwrap()) + } +} + +parameter_types! { + pub const AssetDeposit: u64 = 1; + pub const ApprovalDeposit: u64 = 1; + pub const AssetAccountDeposit: u64 = 1; + pub const StringLimit: u32 = 50; + pub const MetadataDepositBase: u64 = 1; + pub const MetadataDepositPerByte: u64 = 1; +} + +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 AssetAccountDeposit = AssetAccountDeposit; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = StringLimit; + type Freezer = (); + type Extra = (); + type WeightInfo = (); +} + +parameter_types! { + pub const LoansPalletId: PalletId = PalletId(*b"par/loan"); + pub const RewardAssetId: CurrencyId = HKO; + pub const LiquidationFreeAssetId: CurrencyId = DOT; +} + +impl Config for Test { + type Event = Event; + type PriceFeeder = MockPriceFeeder; + type PalletId = LoansPalletId; + type ReserveOrigin = EnsureRoot; + type UpdateOrigin = EnsureRoot; + type WeightInfo = (); + type UnixTime = TimestampPallet; + type Assets = CurrencyAdapter; + type RewardAssetId = RewardAssetId; + type LiquidationFreeAssetId = LiquidationFreeAssetId; +} + +parameter_types! { + pub const NativeCurrencyId: CurrencyId = HKO; +} + +impl pallet_currency_adapter::Config for Test { + type Assets = Assets; + type Balances = Balances; + type GetNativeCurrencyId = NativeCurrencyId; + type LockOrigin = EnsureRoot; +} + +pub(crate) fn new_test_ext() -> sp_io::TestExternalities { + let t = frame_system::GenesisConfig::default() + .build_storage::() + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + // Init assets + Balances::set_balance(Origin::root(), DAVE, unit(1000), unit(0)).unwrap(); + Assets::force_create(Origin::root(), DOT, ALICE, true, 1).unwrap(); + Assets::force_create(Origin::root(), KSM, ALICE, true, 1).unwrap(); + Assets::force_create(Origin::root(), USDT, ALICE, true, 1).unwrap(); + Assets::force_create(Origin::root(), SDOT, ALICE, true, 1).unwrap(); + Assets::force_create(Origin::root(), CDOT_6_13, ALICE, true, 1).unwrap(); + + Assets::mint(Origin::signed(ALICE), KSM, ALICE, unit(1000)).unwrap(); + Assets::mint(Origin::signed(ALICE), DOT, ALICE, unit(1000)).unwrap(); + Assets::mint(Origin::signed(ALICE), USDT, ALICE, unit(1000)).unwrap(); + Assets::mint(Origin::signed(ALICE), CDOT_6_13, ALICE, unit(1000)).unwrap(); + Assets::mint(Origin::signed(ALICE), KSM, BOB, unit(1000)).unwrap(); + Assets::mint(Origin::signed(ALICE), DOT, BOB, unit(1000)).unwrap(); + Assets::mint(Origin::signed(ALICE), DOT, DAVE, unit(1000)).unwrap(); + Assets::mint(Origin::signed(ALICE), USDT, DAVE, unit(1000)).unwrap(); + + // Init Markets + Loans::add_market(Origin::root(), HKO, market_mock(PHKO)).unwrap(); + Loans::activate_market(Origin::root(), HKO).unwrap(); + Loans::add_market(Origin::root(), KSM, market_mock(PKSM)).unwrap(); + Loans::activate_market(Origin::root(), KSM).unwrap(); + Loans::add_market(Origin::root(), DOT, market_mock(PDOT)).unwrap(); + Loans::activate_market(Origin::root(), DOT).unwrap(); + Loans::add_market(Origin::root(), USDT, market_mock(PUSDT)).unwrap(); + Loans::activate_market(Origin::root(), USDT).unwrap(); + Loans::add_market(Origin::root(), CDOT_6_13, market_mock(PCDOT_6_13)).unwrap(); + Loans::activate_market(Origin::root(), CDOT_6_13).unwrap(); + + Loans::update_liquidation_free_collateral(Origin::root(), vec![CDOT_6_13]).unwrap(); + + System::set_block_number(0); + TimestampPallet::set_timestamp(6000); + }); + ext +} + +/// Progress to the given block, and then finalize the block. +pub(crate) fn _run_to_block(n: BlockNumber) { + Loans::on_finalize(System::block_number()); + for b in (System::block_number() + 1)..=n { + System::set_block_number(b); + Loans::on_initialize(b); + TimestampPallet::set_timestamp(6000 * b); + if b != n { + Loans::on_finalize(b); + } + } +} + +pub fn almost_equal(target: u128, value: u128) -> bool { + let target = target as i128; + let value = value as i128; + let diff = (target - value).abs() as u128; + diff < micro_unit(1) +} + +pub fn accrue_interest_per_block(asset_id: CurrencyId, block_delta_secs: u64, run_to_block: u64) { + for i in 1..run_to_block { + TimestampPallet::set_timestamp(6000 + (block_delta_secs * 1000 * i)); + Loans::accrue_interest(asset_id).unwrap(); + } +} + +pub fn unit(d: u128) -> u128 { + d.saturating_mul(10_u128.pow(12)) +} + +pub fn milli_unit(d: u128) -> u128 { + d.saturating_mul(10_u128.pow(9)) +} + +pub fn micro_unit(d: u128) -> u128 { + d.saturating_mul(10_u128.pow(6)) +} + +pub fn million_unit(d: u128) -> u128 { + unit(d) * 10_u128.pow(6) +} + +pub const fn market_mock(ptoken_id: u32) -> Market { + Market { + close_factor: Ratio::from_percent(50), + collateral_factor: Ratio::from_percent(50), + liquidation_threshold: Ratio::from_percent(55), + liquidate_incentive: Rate::from_inner(Rate::DIV / 100 * 110), + liquidate_incentive_reserved_factor: Ratio::from_percent(3), + state: MarketState::Pending, + rate_model: InterestRateModel::Jump(JumpModel { + base_rate: Rate::from_inner(Rate::DIV / 100 * 2), + jump_rate: Rate::from_inner(Rate::DIV / 100 * 10), + full_rate: Rate::from_inner(Rate::DIV / 100 * 32), + jump_utilization: Ratio::from_percent(80), + }), + reserve_factor: Ratio::from_percent(15), + supply_cap: 1_000_000_000_000_000_000_000u128, // set to 1B + borrow_cap: 1_000_000_000_000_000_000_000u128, // set to 1B + ptoken_id, + } +} + +pub const MARKET_MOCK: Market = market_mock(1200); + +pub const ACTIVE_MARKET_MOCK: Market = { + let mut market = MARKET_MOCK; + market.state = MarketState::Active; + market +}; diff --git a/crates/loans/src/ptoken.rs b/crates/loans/src/ptoken.rs new file mode 100644 index 0000000000..ac92c8d24c --- /dev/null +++ b/crates/loans/src/ptoken.rs @@ -0,0 +1,232 @@ +// 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. + +use crate::{types::Deposits, AssetIdOf, BalanceOf, *}; +use frame_support::{ + require_transactional, + traits::tokens::{ + fungibles::{Inspect, Transfer}, + DepositConsequence, WithdrawConsequence, + }, +}; + +impl Inspect for Pallet { + type AssetId = AssetIdOf; + type Balance = BalanceOf; + + /// The total amount of issuance in the system. + fn total_issuance(ptoken_id: Self::AssetId) -> Self::Balance { + if let Ok(underlying_id) = Self::underlying_id(ptoken_id) { + Self::total_supply(underlying_id) + } else { + Balance::default() + } + } + + /// The minimum balance any single account may have. + fn minimum_balance(_ptoken_id: Self::AssetId) -> Self::Balance { + Zero::zero() + } + + /// Get the ptoken balance of `who`. + fn balance(ptoken_id: Self::AssetId, who: &T::AccountId) -> Self::Balance { + if let Ok(underlying_id) = Self::underlying_id(ptoken_id) { + Self::account_deposits(underlying_id, who).voucher_balance + } else { + Balance::default() + } + } + + /// Get the maximum amount that `who` can withdraw/transfer successfully. + /// For ptoken, We don't care if keep_alive is enabled + fn reducible_balance( + ptoken_id: Self::AssetId, + who: &T::AccountId, + _keep_alive: bool, + ) -> Self::Balance { + Self::reducible_asset(ptoken_id, who).unwrap_or_default() + } + + /// Returns `true` if the balance of `who` may be increased by `amount`. + fn can_deposit( + ptoken_id: Self::AssetId, + who: &T::AccountId, + amount: Self::Balance, + _mint: bool, + ) -> DepositConsequence { + let underlying_id = match Self::underlying_id(ptoken_id) { + Ok(asset_id) => asset_id, + Err(_) => return DepositConsequence::UnknownAsset, + }; + + if let Err(res) = + Self::ensure_active_market(underlying_id).map_err(|_| DepositConsequence::UnknownAsset) + { + return res; + } + + if Self::total_supply(underlying_id) + .checked_add(amount) + .is_none() + { + return DepositConsequence::Overflow; + } + + if Self::balance(ptoken_id, who) + amount < Self::minimum_balance(ptoken_id) { + return DepositConsequence::BelowMinimum; + } + + DepositConsequence::Success + } + + /// Returns `Failed` if the balance of `who` may not be decreased by `amount`, otherwise + /// the consequence. + fn can_withdraw( + ptoken_id: Self::AssetId, + who: &T::AccountId, + amount: Self::Balance, + ) -> WithdrawConsequence { + let underlying_id = match Self::underlying_id(ptoken_id) { + Ok(asset_id) => asset_id, + Err(_) => return WithdrawConsequence::UnknownAsset, + }; + + if let Err(res) = + Self::ensure_active_market(underlying_id).map_err(|_| WithdrawConsequence::UnknownAsset) + { + return res; + } + + let sub_result = Self::balance(ptoken_id, who).checked_sub(amount); + if sub_result.is_none() { + return WithdrawConsequence::NoFunds; + } + + let rest = sub_result.expect("Cannot be none; qed"); + if rest < Self::minimum_balance(ptoken_id) { + return WithdrawConsequence::ReducedToZero(rest); + } + + WithdrawConsequence::Success + } +} + +impl Transfer for Pallet { + /// Returns `Err` if the reducible ptoken of `who` is insufficient + /// + /// For ptoken, We don't care if keep_alive is enabled + #[transactional] + fn transfer( + ptoken_id: Self::AssetId, + source: &T::AccountId, + dest: &T::AccountId, + amount: Self::Balance, + _keep_alive: bool, + ) -> Result, DispatchError> { + ensure!( + amount <= Self::reducible_balance(ptoken_id, source, false), + Error::::InsufficientCollateral + ); + + Self::do_transfer_ptokens(ptoken_id, source, dest, amount)?; + Ok(amount) + } +} + +impl Pallet { + #[require_transactional] + fn do_transfer_ptokens( + ptoken_id: AssetIdOf, + source: &T::AccountId, + dest: &T::AccountId, + amount: BalanceOf, + ) -> Result<(), DispatchError> { + // update supply index before modify supply balance. + Self::update_reward_supply_index(ptoken_id)?; + Self::distribute_supplier_reward(ptoken_id, source)?; + Self::distribute_supplier_reward(ptoken_id, dest)?; + + let underlying_id = Self::underlying_id(ptoken_id)?; + AccountDeposits::::try_mutate_exists( + underlying_id, + source, + |deposits| -> DispatchResult { + let mut d = deposits.unwrap_or_default(); + d.voucher_balance = d + .voucher_balance + .checked_sub(amount) + .ok_or(ArithmeticError::Underflow)?; + if d.voucher_balance.is_zero() { + // remove deposits storage if zero balance + *deposits = None; + } else { + *deposits = Some(d); + } + Ok(()) + }, + )?; + + AccountDeposits::::try_mutate(underlying_id, &dest, |deposits| -> DispatchResult { + deposits.voucher_balance = deposits + .voucher_balance + .checked_add(amount) + .ok_or(ArithmeticError::Overflow)?; + Ok(()) + })?; + + Ok(()) + } + + fn reducible_asset( + ptoken_id: AssetIdOf, + who: &T::AccountId, + ) -> Result, DispatchError> { + let underlying_id = Self::underlying_id(ptoken_id)?; + let Deposits { + is_collateral, + voucher_balance, + } = Self::account_deposits(underlying_id, &who); + + if !is_collateral { + return Ok(voucher_balance); + } + + let market = Self::ensure_active_market(underlying_id)?; + let collateral_value = Self::collateral_asset_value(who, underlying_id)?; + + // liquidity of all assets + let (liquidity, _, _, _) = Self::get_account_liquidity(who)?; + + if liquidity >= collateral_value { + return Ok(voucher_balance); + } + + // Formula + // reducible_underlying_amount = liquidity / collateral_factor / price + let price = Self::get_price(underlying_id)?; + + let reducible_supply_value = liquidity + .checked_div(&market.collateral_factor.into()) + .ok_or(ArithmeticError::Overflow)?; + + let reducible_underlying_amount = reducible_supply_value + .checked_div(&price) + .ok_or(ArithmeticError::Underflow)? + .into_inner(); + + let exchange_rate = Self::exchange_rate(underlying_id); + let amount = Self::calc_collateral_amount(reducible_underlying_amount, exchange_rate)?; + Ok(amount) + } +} diff --git a/crates/loans/src/rate_model.rs b/crates/loans/src/rate_model.rs new file mode 100644 index 0000000000..befe77b16e --- /dev/null +++ b/crates/loans/src/rate_model.rs @@ -0,0 +1,273 @@ +// 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. + +use primitives::{Rate, Ratio}; +use scale_info::TypeInfo; +use sp_runtime::traits::{CheckedAdd, CheckedDiv, CheckedSub, Saturating}; + +use crate::*; + +/// Parallel interest rate model +#[cfg_attr(feature = "std", derive(serde::Deserialize, serde::Serialize))] +#[derive(Encode, Decode, Eq, PartialEq, Copy, Clone, RuntimeDebug, TypeInfo)] +pub enum InterestRateModel { + Jump(JumpModel), + Curve(CurveModel), +} + +impl Default for InterestRateModel { + fn default() -> Self { + Self::new_jump_model( + Rate::saturating_from_rational(2, 100), + Rate::saturating_from_rational(10, 100), + Rate::saturating_from_rational(32, 100), + Ratio::from_percent(80), + ) + } +} + +impl InterestRateModel { + pub fn new_jump_model( + base_rate: Rate, + jump_rate: Rate, + full_rate: Rate, + jump_utilization: Ratio, + ) -> Self { + Self::Jump(JumpModel::new_model( + base_rate, + jump_rate, + full_rate, + jump_utilization, + )) + } + + pub fn new_curve_model(base_rate: Rate) -> Self { + Self::Curve(CurveModel::new_model(base_rate)) + } + + pub fn check_model(&self) -> bool { + match self { + Self::Jump(jump) => jump.check_model(), + Self::Curve(curve) => curve.check_model(), + } + } + + /// Calculates the current borrow interest rate + pub fn get_borrow_rate(&self, utilization: Ratio) -> Option { + match self { + Self::Jump(jump) => jump.get_borrow_rate(utilization), + Self::Curve(curve) => curve.get_borrow_rate(utilization), + } + } + + /// Calculates the current supply interest rate + pub fn get_supply_rate(borrow_rate: Rate, util: Ratio, reserve_factor: Ratio) -> Rate { + // ((1 - reserve_factor) * borrow_rate) * utilization + let one_minus_reserve_factor = Ratio::one().saturating_sub(reserve_factor); + let rate_to_pool = borrow_rate.saturating_mul(one_minus_reserve_factor.into()); + + rate_to_pool.saturating_mul(util.into()) + } +} + +/// The jump interest rate model +#[cfg_attr(feature = "std", derive(serde::Deserialize, serde::Serialize))] +#[derive(Encode, Decode, Eq, PartialEq, Copy, Clone, RuntimeDebug, Default, TypeInfo)] +pub struct JumpModel { + /// The base interest rate when utilization rate is 0 + pub base_rate: Rate, + /// The interest rate on jump utilization point + pub jump_rate: Rate, + /// The max interest rate when utilization rate is 100% + pub full_rate: Rate, + /// The utilization point at which the jump_rate is applied + pub jump_utilization: Ratio, +} + +impl JumpModel { + pub const MAX_BASE_RATE: Rate = Rate::from_inner(100_000_000_000_000_000); // 10% + pub const MAX_JUMP_RATE: Rate = Rate::from_inner(300_000_000_000_000_000); // 30% + pub const MAX_FULL_RATE: Rate = Rate::from_inner(500_000_000_000_000_000); // 50% + + /// Create a new rate model + pub fn new_model( + base_rate: Rate, + jump_rate: Rate, + full_rate: Rate, + jump_utilization: Ratio, + ) -> JumpModel { + Self { + base_rate, + jump_rate, + full_rate, + jump_utilization, + } + } + + /// Check the jump model for sanity + pub fn check_model(&self) -> bool { + if self.base_rate > Self::MAX_BASE_RATE + || self.jump_rate > Self::MAX_JUMP_RATE + || self.full_rate > Self::MAX_FULL_RATE + { + return false; + } + if self.base_rate > self.jump_rate || self.jump_rate > self.full_rate { + return false; + } + + true + } + + /// Calculates the borrow interest rate of jump model + pub fn get_borrow_rate(&self, utilization: Ratio) -> Option { + if utilization <= self.jump_utilization { + // utilization * (jump_rate - zero_rate) / jump_utilization + zero_rate + let result = self + .jump_rate + .checked_sub(&self.base_rate)? + .saturating_mul(utilization.into()) + .checked_div(&self.jump_utilization.into())? + .checked_add(&self.base_rate)?; + + Some(result) + } else { + // (utilization - jump_utilization)*(full_rate - jump_rate) / ( 1 - jump_utilization) + jump_rate + let excess_util = utilization.saturating_sub(self.jump_utilization); + let result = self + .full_rate + .checked_sub(&self.jump_rate)? + .saturating_mul(excess_util.into()) + .checked_div(&(Ratio::one().saturating_sub(self.jump_utilization).into()))? + .checked_add(&self.jump_rate)?; + + Some(result) + } + } +} + +/// The curve interest rate model +#[cfg_attr(feature = "std", derive(serde::Deserialize, serde::Serialize))] +#[derive(Encode, Decode, Eq, PartialEq, Copy, Clone, RuntimeDebug, Default, TypeInfo)] +pub struct CurveModel { + pub base_rate: Rate, +} + +impl CurveModel { + pub const MAX_BASE_RATE: Rate = Rate::from_inner(Rate::DIV / 100 * 10); // 10% + + /// Create a new curve model + pub fn new_model(base_rate: Rate) -> CurveModel { + Self { base_rate } + } + + /// Check the curve model for sanity + pub fn check_model(&self) -> bool { + self.base_rate <= Self::MAX_BASE_RATE + } + + /// Calculates the borrow interest rate of curve model + pub fn get_borrow_rate(&self, utilization: Ratio) -> Option { + const NINE: usize = 9; + let utilization_rate: Rate = utilization.into(); + utilization_rate + .saturating_pow(NINE) + .checked_add(&self.base_rate) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use sp_runtime::FixedU128; + + // Test jump model + #[test] + fn init_jump_model_works() { + let base_rate = Rate::saturating_from_rational(2, 100); + let jump_rate = Rate::saturating_from_rational(10, 100); + let full_rate = Rate::saturating_from_rational(32, 100); + let jump_utilization = Ratio::from_percent(80); + + assert_eq!( + JumpModel::new_model(base_rate, jump_rate, full_rate, jump_utilization), + JumpModel { + base_rate: Rate::from_inner(20_000_000_000_000_000).into(), + jump_rate: Rate::from_inner(100_000_000_000_000_000).into(), + full_rate: Rate::from_inner(320_000_000_000_000_000).into(), + jump_utilization: Ratio::from_percent(80), + } + ); + } + + #[test] + fn get_borrow_rate_works() { + // init + let base_rate = Rate::saturating_from_rational(2, 100); + let jump_rate = Rate::saturating_from_rational(10, 100); + let full_rate = Rate::saturating_from_rational(32, 100); + let jump_utilization = Ratio::from_percent(80); + let jump_model = JumpModel::new_model(base_rate, jump_rate, full_rate, jump_utilization); + assert!(jump_model.check_model()); + + // normal rate + let mut cash: u128 = 500; + let borrows: u128 = 1000; + let util = Ratio::from_rational(borrows, cash + borrows); + let borrow_rate = jump_model.get_borrow_rate(util).unwrap(); + assert_eq!( + borrow_rate, + jump_model.jump_rate.saturating_mul(util.into()) + jump_model.base_rate, + ); + + // jump rate + cash = 100; + let util = Ratio::from_rational(borrows, cash + borrows); + let borrow_rate = jump_model.get_borrow_rate(util).unwrap(); + let normal_rate = + jump_model.jump_rate.saturating_mul(jump_utilization.into()) + jump_model.base_rate; + let excess_util = util.saturating_sub(jump_utilization); + assert_eq!( + borrow_rate, + (jump_model.full_rate - jump_model.jump_rate).saturating_mul(excess_util.into()) + / FixedU128::saturating_from_rational(20, 100) + + normal_rate, + ); + } + + // Test curve model + // TODO: Add test cases for curve model + + #[test] + fn get_supply_rate_works() { + let borrow_rate = Rate::saturating_from_rational(2, 100); + let util = Ratio::from_percent(50); + let reserve_factor = Ratio::zero(); + let supply_rate = InterestRateModel::get_supply_rate(borrow_rate, util, reserve_factor); + assert_eq!( + supply_rate, + borrow_rate + .saturating_mul(((Ratio::one().saturating_sub(reserve_factor)) * util).into()), + ); + } + + #[test] + fn curve_model_correctly_calculates_borrow_rate() { + let model = CurveModel::new_model(Rate::saturating_from_rational(2, 100)); + assert_eq!( + model.get_borrow_rate(Ratio::from_percent(80)).unwrap(), + Rate::from_inner(154217728000000000) + ); + } +} diff --git a/crates/loans/src/tests.rs b/crates/loans/src/tests.rs new file mode 100644 index 0000000000..b9a8d7c372 --- /dev/null +++ b/crates/loans/src/tests.rs @@ -0,0 +1,1382 @@ +// 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. + +mod edge_cases; +mod interest_rate; +mod liquidate_borrow; +mod market; +mod ptokens; + +use frame_support::{assert_err, assert_noop, assert_ok}; + +use primitives::tokens::CDOT_6_13; +use sp_runtime::{ + traits::{CheckedDiv, One, Saturating}, + FixedU128, Permill, +}; + +use crate::mock::*; + +#[test] +fn init_minting_ok() { + new_test_ext().execute_with(|| { + assert_eq!(Assets::balance(KSM, ALICE), unit(1000)); + assert_eq!(Assets::balance(DOT, ALICE), unit(1000)); + assert_eq!(Assets::balance(USDT, ALICE), unit(1000)); + assert_eq!(Assets::balance(KSM, BOB), unit(1000)); + assert_eq!(Assets::balance(DOT, BOB), unit(1000)); + }); +} + +#[test] +fn init_markets_ok() { + new_test_ext().execute_with(|| { + assert_eq!(Loans::market(KSM).unwrap().state, MarketState::Active); + assert_eq!(Loans::market(DOT).unwrap().state, MarketState::Active); + assert_eq!(Loans::market(USDT).unwrap().state, MarketState::Active); + assert_eq!(BorrowIndex::::get(HKO), Rate::one()); + assert_eq!(BorrowIndex::::get(KSM), Rate::one()); + assert_eq!(BorrowIndex::::get(DOT), Rate::one()); + assert_eq!(BorrowIndex::::get(USDT), Rate::one()); + + assert_eq!( + ExchangeRate::::get(KSM), + Rate::saturating_from_rational(2, 100) + ); + assert_eq!( + ExchangeRate::::get(DOT), + Rate::saturating_from_rational(2, 100) + ); + assert_eq!( + ExchangeRate::::get(USDT), + Rate::saturating_from_rational(2, 100) + ); + }); +} + +#[test] +fn loans_native_token_works() { + new_test_ext().execute_with(|| { + assert_eq!(::Assets::balance(HKO, &DAVE), unit(1000)); + assert_eq!(Loans::market(HKO).unwrap().state, MarketState::Active); + assert_eq!(BorrowIndex::::get(HKO), Rate::one()); + assert_eq!( + ExchangeRate::::get(HKO), + Rate::saturating_from_rational(2, 100) + ); + assert_ok!(Loans::mint(Origin::signed(DAVE), HKO, unit(1000))); + + // Redeem 1001 HKO should cause InsufficientDeposit + assert_noop!( + Loans::redeem_allowed(HKO, &DAVE, unit(50050)), + Error::::InsufficientDeposit + ); + // Redeem 1000 HKO is ok + assert_ok!(Loans::redeem_allowed(HKO, &DAVE, unit(50000),)); + + assert_ok!(Loans::collateral_asset(Origin::signed(DAVE), HKO, true)); + + // Borrow 500 HKO will reduce 500 HKO liquidity for collateral_factor is 50% + assert_ok!(Loans::borrow(Origin::signed(DAVE), HKO, unit(500))); + // Repay 400 HKO + assert_ok!(Loans::repay_borrow(Origin::signed(DAVE), HKO, unit(400))); + + // HKO collateral: deposit = 1000 + // HKO borrow balance: borrow - repay = 500 - 400 = 100 + // HKO: cash - deposit + borrow - repay = 1000 - 1000 + 500 - 400 = 100 + assert_eq!( + Loans::exchange_rate(HKO) + .saturating_mul_int(Loans::account_deposits(HKO, DAVE).voucher_balance), + unit(1000) + ); + let borrow_snapshot = Loans::account_borrows(HKO, DAVE); + assert_eq!(borrow_snapshot.principal, unit(100)); + assert_eq!(borrow_snapshot.borrow_index, Loans::borrow_index(HKO)); + assert_eq!(::Assets::balance(HKO, &DAVE), unit(100),); + }) +} + +#[test] +fn mint_works() { + new_test_ext().execute_with(|| { + // Deposit 100 DOT + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(100))); + + // DOT collateral: deposit = 100 + // DOT: cash - deposit = 1000 - 100 = 900 + assert_eq!( + Loans::exchange_rate(DOT) + .saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), + unit(100) + ); + assert_eq!(::Assets::balance(DOT, &ALICE), unit(900),); + assert_eq!( + ::Assets::balance(DOT, &Loans::account_id()), + unit(100), + ); + }) +} + +#[test] +fn mint_must_return_err_when_overflows_occur() { + new_test_ext().execute_with(|| { + Loans::force_update_market( + Origin::root(), + DOT, + Market { + supply_cap: u128::MAX, + ..ACTIVE_MARKET_MOCK + }, + ) + .unwrap(); + // MAX_DEPOSIT = u128::MAX * exchangeRate + const OVERFLOW_DEPOSIT: u128 = u128::MAX / 50 + 1; + + // Verify token balance first + assert_noop!( + Loans::mint(Origin::signed(CHARLIE), DOT, OVERFLOW_DEPOSIT), + ArithmeticError::Underflow + ); + + // Deposit OVERFLOW_DEPOSIT DOT for CHARLIE + assert_ok!(Assets::mint( + Origin::signed(ALICE), + DOT, + CHARLIE, + OVERFLOW_DEPOSIT + )); + + // Amount is too large, OVERFLOW_DEPOSIT / 0.0X == Overflow + // Underflow is used here redeem could also be 0 + assert_noop!( + Loans::mint(Origin::signed(CHARLIE), DOT, OVERFLOW_DEPOSIT), + ArithmeticError::Underflow + ); + + // Exchange rate must ge greater than zero + // ExchangeRate::::insert(DOT, Rate::zero()); + // assert_noop!( + // Loans::mint(Origin::signed(CHARLIE), DOT, 100), + // ArithmeticError::Underflow + // ); + }) +} + +#[test] +fn redeem_allowed_works() { + new_test_ext().execute_with(|| { + // Prepare: Bob Deposit 200 DOT + assert_ok!(Loans::mint(Origin::signed(BOB), DOT, 200)); + + // Deposit 200 KSM as collateral + assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, 200)); + // Redeem 201 KSM should cause InsufficientDeposit + assert_noop!( + Loans::redeem_allowed(KSM, &ALICE, 10050), + Error::::InsufficientDeposit + ); + // Redeem 1 DOT should cause InsufficientDeposit + assert_noop!( + Loans::redeem_allowed(DOT, &ALICE, 50), + Error::::InsufficientDeposit + ); + // Redeem 200 KSM is ok + assert_ok!(Loans::redeem_allowed(KSM, &ALICE, 10000)); + + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), KSM, true)); + // Borrow 50 DOT will reduce 100 KSM liquidity for collateral_factor is 50% + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, 50)); + // Redeem 101 KSM should cause InsufficientLiquidity + assert_noop!( + Loans::redeem_allowed(KSM, &ALICE, 5050), + Error::::InsufficientLiquidity + ); + // Redeem 100 KSM is ok + assert_ok!(Loans::redeem_allowed(KSM, &ALICE, 5000)); + }) +} + +#[test] +fn lf_redeem_allowed_works() { + new_test_ext().execute_with(|| { + // Set CDOT as lf collateral + Loans::update_liquidation_free_collateral(Origin::root(), vec![CDOT_6_13]).unwrap(); + Loans::mint(Origin::signed(ALICE), CDOT_6_13, unit(200)).unwrap(); + + Loans::mint(Origin::signed(DAVE), USDT, unit(200)).unwrap(); + Loans::mint(Origin::signed(DAVE), DOT, unit(200)).unwrap(); + // Lend $200 CDOT + Loans::collateral_asset(Origin::signed(ALICE), CDOT_6_13, true).unwrap(); + + Loans::borrow(Origin::signed(ALICE), DOT, unit(50)).unwrap(); + + // (200 - 100) * 50% >= 50 + assert_ok!(Loans::redeem_allowed(CDOT_6_13, &ALICE, unit(100))); + + // Set KSM as collateral, and borrow USDT + Loans::mint(Origin::signed(ALICE), KSM, unit(200)).unwrap(); + Loans::collateral_asset(Origin::signed(ALICE), KSM, true).unwrap(); + Loans::borrow(Origin::signed(ALICE), USDT, unit(100)).unwrap(); + + assert_err!( + Loans::redeem_allowed(KSM, &ALICE, unit(100)), + Error::::InsufficientLiquidity + ); + // But it'll success when redeem cdot + assert_ok!(Loans::redeem_allowed(CDOT_6_13, &ALICE, unit(100))); + + // Remove CDOT from lf collateral + Loans::update_liquidation_free_collateral(Origin::root(), vec![]).unwrap(); + // Then it can be redeemed + assert_ok!(Loans::redeem_allowed(KSM, &ALICE, unit(100))); + }) +} + +#[test] +fn redeem_works() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(100))); + assert_ok!(Loans::redeem(Origin::signed(ALICE), DOT, unit(20))); + + // DOT collateral: deposit - redeem = 100 - 20 = 80 + // DOT: cash - deposit + redeem = 1000 - 100 + 20 = 920 + assert_eq!( + Loans::exchange_rate(DOT) + .saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), + unit(80) + ); + assert_eq!(::Assets::balance(DOT, &ALICE), unit(920),); + }) +} + +#[test] +fn redeem_fails() { + new_test_ext().execute_with(|| { + assert_noop!( + Loans::redeem(Origin::signed(ALICE), DOT, unit(0)), + Error::::InvalidAmount + ); + }) +} + +#[test] +fn redeem_fails_when_insufficient_liquidity() { + new_test_ext().execute_with(|| { + // Prepare: Bob Deposit 200 DOT + assert_ok!(Loans::mint(Origin::signed(BOB), DOT, 200)); + + // Deposit 200 KSM as collateral + assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, 200)); + + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), KSM, true)); + // Borrow 50 DOT will reduce 100 KSM liquidity for collateral_factor is 50% + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, 50)); + + assert_noop!( + Loans::redeem(Origin::signed(BOB), DOT, 151), + Error::::InsufficientCash + ); + }) +} + +#[test] +fn redeem_fails_when_would_use_reserved_balanace() { + new_test_ext().execute_with(|| { + // Prepare: Bob Deposit 200 DOT + assert_ok!(Loans::mint(Origin::signed(BOB), DOT, 200)); + + // Deposit 200 KSM as collateral + assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, 200)); + + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), KSM, true)); + // Borrow 50 DOT will reduce 100 KSM liquidity for collateral_factor is 50% + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, 50)); + assert_ok!(Loans::add_reserves(Origin::root(), ALICE, DOT, 50)); + + assert_noop!( + Loans::redeem(Origin::signed(BOB), DOT, 151), + Error::::InsufficientCash + ); + }) +} + +#[test] +fn redeem_must_return_err_when_overflows_occur() { + new_test_ext().execute_with(|| { + // Amount is too large, max_value / 0.0X == Overflow + // Underflow is used here redeem could also be 0 + assert_noop!( + Loans::redeem(Origin::signed(ALICE), DOT, u128::MAX), + ArithmeticError::Underflow, + ); + + // Exchange rate must ge greater than zero + // ExchangeRate::::insert(DOT, Rate::zero()); + // assert_noop!( + // Loans::redeem(Origin::signed(ALICE), DOT, 100), + // ArithmeticError::Underflow + // ); + }) +} + +#[test] +fn redeem_all_works() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(100))); + assert_ok!(Loans::redeem_all(Origin::signed(ALICE), DOT)); + + // DOT: cash - deposit + redeem = 1000 - 100 + 100 = 1000 + // DOT collateral: deposit - redeem = 100 - 100 = 0 + assert_eq!( + Loans::exchange_rate(DOT) + .saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), + 0, + ); + assert_eq!(::Assets::balance(DOT, &ALICE), unit(1000),); + assert!(!AccountDeposits::::contains_key(DOT, &ALICE)) + }) +} + +#[test] +fn borrow_allowed_works() { + new_test_ext().execute_with(|| { + // Deposit 200 DOT as collateral + assert_ok!(Loans::mint(Origin::signed(BOB), DOT, 200)); + assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, 200)); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), KSM, true)); + // Borrow 101 DOT should cause InsufficientLiquidity + assert_noop!( + Loans::borrow_allowed(DOT, &ALICE, 101), + Error::::InsufficientLiquidity + ); + // Borrow 100 DOT is ok + assert_ok!(Loans::borrow_allowed(DOT, &ALICE, 100)); + + // Set borrow limit to 10 + assert_ok!(Loans::force_update_market( + Origin::root(), + DOT, + Market { + borrow_cap: 10, + ..ACTIVE_MARKET_MOCK + }, + )); + // Borrow 10 DOT is ok + assert_ok!(Loans::borrow_allowed(DOT, &ALICE, 10)); + // Borrow 11 DOT should cause BorrowLimitExceeded + assert_noop!( + Loans::borrow_allowed(DOT, &ALICE, 11), + Error::::BorrowCapacityExceeded + ); + }) +} + +#[test] +fn update_liquidation_free_collateral_works() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::update_liquidation_free_collateral( + Origin::root(), + vec![CDOT_6_13] + )); + assert_eq!(Loans::liquidation_free_collaterals(), vec![CDOT_6_13]); + }) +} + +#[test] +fn get_account_liquidity_works() { + new_test_ext().execute_with(|| { + Loans::mint(Origin::signed(ALICE), CDOT_6_13, unit(200)).unwrap(); + Loans::collateral_asset(Origin::signed(ALICE), CDOT_6_13, true).unwrap(); + + let (liquidity, _, lf_liquidity, _) = Loans::get_account_liquidity(&ALICE).unwrap(); + + assert_eq!(liquidity, FixedU128::from_inner(unit(100))); + assert_eq!(lf_liquidity, FixedU128::from_inner(unit(100))); + }) +} + +#[test] +fn get_account_liquidation_threshold_liquidity_works() { + new_test_ext().execute_with(|| { + Loans::mint(Origin::signed(BOB), DOT, unit(200)).unwrap(); + Loans::mint(Origin::signed(BOB), KSM, unit(200)).unwrap(); + + Loans::mint(Origin::signed(ALICE), CDOT_6_13, unit(200)).unwrap(); + Loans::collateral_asset(Origin::signed(ALICE), CDOT_6_13, true).unwrap(); + + Loans::mint(Origin::signed(ALICE), USDT, unit(200)).unwrap(); + Loans::collateral_asset(Origin::signed(ALICE), USDT, true).unwrap(); + + Loans::borrow(Origin::signed(ALICE), KSM, unit(100)).unwrap(); + Loans::borrow(Origin::signed(ALICE), DOT, unit(100)).unwrap(); + + let (liquidity, _, lf_liquidity, _) = + Loans::get_account_liquidation_threshold_liquidity(&ALICE).unwrap(); + + assert_eq!(liquidity, FixedU128::from_inner(unit(20))); + assert_eq!(lf_liquidity, FixedU128::from_inner(unit(10))); + + MockPriceFeeder::set_price(KSM, 2.into()); + let (liquidity, shortfall, lf_liquidity, _) = + Loans::get_account_liquidation_threshold_liquidity(&ALICE).unwrap(); + + assert_eq!(liquidity, FixedU128::from_inner(unit(0))); + assert_eq!(shortfall, FixedU128::from_inner(unit(80))); + assert_eq!(lf_liquidity, FixedU128::from_inner(unit(10))); + }) +} + +#[test] +fn lf_borrow_allowed_works() { + new_test_ext().execute_with(|| { + Loans::mint(Origin::signed(ALICE), CDOT_6_13, unit(200)).unwrap(); + Loans::mint(Origin::signed(DAVE), USDT, unit(200)).unwrap(); + Loans::mint(Origin::signed(DAVE), DOT, unit(200)).unwrap(); + // Lend $200 CDOT + Loans::collateral_asset(Origin::signed(ALICE), CDOT_6_13, true).unwrap(); + + assert_eq!( + Loans::get_asset_value(DOT, unit(100)).unwrap(), + Loans::get_asset_value(USDT, unit(100)).unwrap() + ); + + assert_noop!( + Loans::borrow_allowed(USDT, &ALICE, unit(100)), + Error::::InsufficientLiquidity + ); + assert_ok!(Loans::borrow_allowed(DOT, &ALICE, unit(100))); + }) +} + +#[test] +fn borrow_works() { + new_test_ext().execute_with(|| { + // Deposit 200 DOT as collateral + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + // Borrow 100 DOT + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(100))); + + // DOT collateral: deposit = 200 + // DOT borrow balance: borrow = 100 + // DOT: cash - deposit + borrow = 1000 - 200 + 100 = 900 + assert_eq!( + Loans::exchange_rate(DOT) + .saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), + unit(200) + ); + let borrow_snapshot = Loans::account_borrows(DOT, ALICE); + assert_eq!(borrow_snapshot.principal, unit(100)); + assert_eq!(borrow_snapshot.borrow_index, Loans::borrow_index(DOT)); + assert_eq!(::Assets::balance(DOT, &ALICE), unit(900),); + }) +} + +#[test] +fn lf_borrow_works() { + new_test_ext().execute_with(|| { + // Deposit 200 DOT as collateral + Loans::mint(Origin::signed(ALICE), CDOT_6_13, unit(200)).unwrap(); + Loans::mint(Origin::signed(DAVE), DOT, unit(200)).unwrap(); + Loans::collateral_asset(Origin::signed(ALICE), CDOT_6_13, true).unwrap(); + + // Borrow 100 DOT + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(100))); + + // CDOT collateral: deposit = 200 + // DOT borrow balance: borrow = 100 + // DOT: cash - deposit + borrow = 1000 + 100 = 1100 + assert_eq!( + Loans::exchange_rate(CDOT_6_13) + .saturating_mul_int(Loans::account_deposits(CDOT_6_13, ALICE).voucher_balance), + unit(200) + ); + let borrow_snapshot = Loans::account_borrows(DOT, ALICE); + assert_eq!(borrow_snapshot.principal, unit(100)); + assert_eq!(borrow_snapshot.borrow_index, Loans::borrow_index(DOT)); + assert_eq!(::Assets::balance(DOT, &ALICE), unit(1100),); + }) +} + +#[test] +fn repay_borrow_works() { + new_test_ext().execute_with(|| { + // Deposit 200 DOT as collateral + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + // Borrow 100 DOT + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(100))); + // Repay 30 DOT + assert_ok!(Loans::repay_borrow(Origin::signed(ALICE), DOT, unit(30))); + + // DOT collateral: deposit = 200 + // DOT borrow balance: borrow - repay = 100 - 30 = 70 + // DOT: cash - deposit + borrow - repay = 1000 - 200 + 100 - 30 = 870 + assert_eq!( + Loans::exchange_rate(DOT) + .saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), + unit(200) + ); + let borrow_snapshot = Loans::account_borrows(DOT, ALICE); + assert_eq!(borrow_snapshot.principal, unit(70)); + assert_eq!(borrow_snapshot.borrow_index, Loans::borrow_index(DOT)); + assert_eq!(::Assets::balance(DOT, &ALICE), unit(870),); + }) +} + +#[test] +fn repay_borrow_all_works() { + new_test_ext().execute_with(|| { + // Bob deposits 200 KSM + assert_ok!(Loans::mint(Origin::signed(BOB), KSM, unit(200))); + // Alice deposit 200 DOT as collateral + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + // Alice borrow 50 KSM + assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(50))); + + // Alice repay all borrow balance + assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), KSM)); + + // DOT: cash - deposit + = 1000 - 200 = 800 + // DOT collateral: deposit = 200 + // KSM: cash + borrow - repay = 1000 + 50 - 50 = 1000 + // KSM borrow balance: borrow - repay = 50 - 50 = 0 + assert_eq!(::Assets::balance(DOT, &ALICE), unit(800),); + assert_eq!( + Loans::exchange_rate(DOT) + .saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), + unit(200) + ); + let borrow_snapshot = Loans::account_borrows(KSM, ALICE); + assert_eq!(borrow_snapshot.principal, 0); + assert_eq!(borrow_snapshot.borrow_index, Loans::borrow_index(KSM)); + }) +} + +#[test] +fn collateral_asset_works() { + new_test_ext().execute_with(|| { + // No collateral assets + assert_noop!( + Loans::collateral_asset(Origin::signed(ALICE), DOT, true), + Error::::NoDeposit + ); + // Deposit 200 DOT as collateral + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, 200)); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + assert_eq!(Loans::account_deposits(DOT, ALICE).is_collateral, true); + assert_noop!( + Loans::collateral_asset(Origin::signed(ALICE), DOT, true), + Error::::DuplicateOperation + ); + // Borrow 100 DOT base on the collateral of 200 DOT + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, 100)); + assert_noop!( + Loans::collateral_asset(Origin::signed(ALICE), DOT, false), + Error::::InsufficientLiquidity + ); + // Repay all the borrows + assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), DOT)); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, false)); + assert_eq!(Loans::account_deposits(DOT, ALICE).is_collateral, false); + assert_noop!( + Loans::collateral_asset(Origin::signed(ALICE), DOT, false), + Error::::DuplicateOperation + ); + }) +} + +#[test] +fn total_collateral_value_works() { + new_test_ext().execute_with(|| { + // Mock the price for DOT = 1, KSM = 1 + let collateral_factor = Rate::saturating_from_rational(50, 100); + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(100))); + assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, unit(200))); + assert_ok!(Loans::mint(Origin::signed(ALICE), USDT, unit(300))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), KSM, true)); + assert_eq!( + Loans::total_collateral_value(&ALICE).unwrap(), + (collateral_factor.saturating_mul(FixedU128::from_inner(unit(100) + unit(200)))) + ); + }) +} + +#[test] +fn add_reserves_works() { + new_test_ext().execute_with(|| { + // Add 100 DOT reserves + assert_ok!(Loans::add_reserves(Origin::root(), ALICE, DOT, unit(100))); + + assert_eq!(Loans::total_reserves(DOT), unit(100)); + assert_eq!( + ::Assets::balance(DOT, &Loans::account_id()), + unit(100), + ); + assert_eq!(::Assets::balance(DOT, &ALICE), unit(900),); + }) +} + +#[test] +fn reduce_reserves_works() { + new_test_ext().execute_with(|| { + // Add 100 DOT reserves + assert_ok!(Loans::add_reserves(Origin::root(), ALICE, DOT, unit(100))); + + // Reduce 20 DOT reserves + assert_ok!(Loans::reduce_reserves(Origin::root(), ALICE, DOT, unit(20))); + + assert_eq!(Loans::total_reserves(DOT), unit(80)); + assert_eq!( + ::Assets::balance(DOT, &Loans::account_id()), + unit(80), + ); + assert_eq!(::Assets::balance(DOT, &ALICE), unit(920),); + }) +} + +#[test] +fn reduce_reserve_reduce_amount_must_be_less_than_total_reserves() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::add_reserves(Origin::root(), ALICE, DOT, unit(100))); + assert_noop!( + Loans::reduce_reserves(Origin::root(), ALICE, DOT, unit(200)), + Error::::InsufficientReserves + ); + }) +} + +#[test] +fn ratio_and_rate_works() { + new_test_ext().execute_with(|| { + // Permill to FixedU128 + let ratio = Permill::from_percent(50); + let rate: FixedU128 = ratio.into(); + assert_eq!(rate, FixedU128::saturating_from_rational(1, 2)); + + // Permill (one = 1_000_000) + let permill = Permill::from_percent(50); + assert_eq!(permill.mul_floor(100_u128), 50_u128); + + // FixedU128 (one = 1_000_000_000_000_000_000_000) + let value1 = FixedU128::saturating_from_integer(100); + let value2 = FixedU128::saturating_from_integer(10); + assert_eq!( + value1.checked_mul(&value2), + Some(FixedU128::saturating_from_integer(1000)) + ); + assert_eq!( + value1.checked_div(&value2), + Some(FixedU128::saturating_from_integer(10)) + ); + assert_eq!( + value1.saturating_mul(permill.into()), + FixedU128::saturating_from_integer(50) + ); + + let value1 = FixedU128::saturating_from_rational(9, 10); + let value2 = 10_u128; + let value3 = FixedU128::saturating_from_integer(10_u128); + assert_eq!( + value1.reciprocal(), + Some(FixedU128::saturating_from_rational(10, 9)) + ); + // u128 div FixedU128 + assert_eq!( + FixedU128::saturating_from_integer(value2).checked_div(&value1), + Some(FixedU128::saturating_from_rational(100, 9)) + ); + + // FixedU128 div u128 + assert_eq!( + value1.reciprocal().and_then(|r| r.checked_mul_int(value2)), + Some(11) + ); + assert_eq!( + FixedU128::from_inner(17_777_777_777_777_777_777).checked_div_int(value2), + Some(1) + ); + // FixedU128 mul u128 + assert_eq!( + FixedU128::from_inner(17_777_777_777_777_777_777).checked_mul_int(value2), + Some(177) + ); + + // reciprocal + assert_eq!( + FixedU128::saturating_from_integer(value2).checked_div(&value1), + Some(FixedU128::saturating_from_rational(100, 9)) + ); + assert_eq!( + value1 + .reciprocal() + .and_then(|r| r.checked_mul(&FixedU128::saturating_from_integer(value2))), + Some(FixedU128::from_inner(11_111_111_111_111_111_110)) + ); + assert_eq!( + FixedU128::saturating_from_integer(value2) + .checked_mul(&value3) + .and_then(|v| v.checked_div(&value1)), + Some(FixedU128::saturating_from_rational(1000, 9)) + ); + assert_eq!( + FixedU128::saturating_from_integer(value2) + .checked_div(&value1) + .and_then(|v| v.checked_mul(&value3)), + Some(FixedU128::from_inner(111_111_111_111_111_111_110)) + ); + + // FixedU128 div Permill + let value1 = Permill::from_percent(30); + let value2 = Permill::from_percent(40); + let value3 = FixedU128::saturating_from_integer(10); + assert_eq!( + value3.checked_div(&value1.into()), + Some(FixedU128::saturating_from_rational(100, 3)) // 10/0.3 + ); + + // u128 div Permill + assert_eq!(value1.saturating_reciprocal_mul_floor(5_u128), 16); // (1/0.3) * 5 = 16.66666666.. + assert_eq!(value1.saturating_reciprocal_mul_floor(5_u128), 16); // (1/0.3) * 5 = 16.66666666.. + assert_eq!(value2.saturating_reciprocal_mul_floor(5_u128), 12); // (1/0.4) * 5 = 12.5 + + // Permill * u128 + let value1 = Permill::from_percent(34); + let value2 = Permill::from_percent(36); + let value3 = Permill::from_percent(30); + let value4 = Permill::from_percent(20); + assert_eq!(value1 * 10_u64, 3); // 0.34 * 10 + assert_eq!(value2 * 10_u64, 4); // 0.36 * 10 + assert_eq!(value3 * 5_u64, 1); // 0.3 * 5 + assert_eq!(value4 * 8_u64, 2); // 0.2 * 8 + assert_eq!(value4.mul_floor(8_u64), 1); // 0.2 mul_floor 8 + }) +} + +#[test] +fn update_exchange_rate_works() { + new_test_ext().execute_with(|| { + // Initialize value of exchange rate is 0.02 + assert_eq!( + Loans::exchange_rate(DOT), + Rate::saturating_from_rational(2, 100) + ); + + // total_supply = 0 + TotalSupply::::insert(DOT, 0); + // assert_ok!(Loans::update_exchange_rate(DOT)); + assert_eq!( + Loans::exchange_rate_stored(DOT).unwrap(), + Rate::saturating_from_rational(2, 100) + ); + + // exchange_rate = total_cash + total_borrows - total_reverse / total_supply + // total_cash = 10, total_supply = 500 + // exchange_rate = 10 + 5 - 1 / 500 + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(10))); + TotalBorrows::::insert(DOT, unit(5)); + TotalReserves::::insert(DOT, unit(1)); + // assert_ok!(Loans::update_exchange_rate(DOT)); + assert_eq!( + Loans::exchange_rate_stored(DOT).unwrap(), + Rate::saturating_from_rational(14, 500) + ); + }) +} + +#[test] +fn current_borrow_balance_works() { + new_test_ext().execute_with(|| { + // snapshot.principal = 0 + AccountBorrows::::insert( + DOT, + ALICE, + BorrowSnapshot { + principal: 0, + borrow_index: Rate::one(), + }, + ); + assert_eq!(Loans::current_borrow_balance(&ALICE, DOT).unwrap(), 0); + + // snapshot.borrow_index = 0 + AccountBorrows::::insert( + DOT, + ALICE, + BorrowSnapshot { + principal: 100, + borrow_index: Rate::zero(), + }, + ); + assert_eq!(Loans::current_borrow_balance(&ALICE, DOT).unwrap(), 0); + + // borrow_index = 1.2, snapshot.borrow_index = 1, snapshot.principal = 100 + BorrowIndex::::insert(DOT, Rate::saturating_from_rational(12, 10)); + AccountBorrows::::insert( + DOT, + ALICE, + BorrowSnapshot { + principal: 100, + borrow_index: Rate::one(), + }, + ); + assert_eq!(Loans::current_borrow_balance(&ALICE, DOT).unwrap(), 120); + }) +} + +#[test] +fn calc_collateral_amount_works() { + let exchange_rate = Rate::saturating_from_rational(3, 10); + assert_eq!( + Loans::calc_collateral_amount(1000, exchange_rate).unwrap(), + 3333 + ); + assert_eq!( + Loans::calc_collateral_amount(u128::MAX, exchange_rate), + Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) + ); + + // relative test: prevent_the_exchange_rate_attack + let exchange_rate = Rate::saturating_from_rational(30000, 1); + assert_eq!( + Loans::calc_collateral_amount(10000, exchange_rate).unwrap(), + 0 + ); +} + +#[test] +fn get_price_works() { + new_test_ext().execute_with(|| { + MockPriceFeeder::set_price(DOT, 0.into()); + assert_noop!(Loans::get_price(DOT), Error::::PriceIsZero); + + MockPriceFeeder::set_price(DOT, 2.into()); + assert_eq!( + Loans::get_price(DOT).unwrap(), + Price::saturating_from_integer(2) + ); + }) +} + +#[test] +fn ensure_enough_cash_works() { + new_test_ext().execute_with(|| { + assert_ok!(Assets::mint( + Origin::signed(ALICE), + KSM, + Loans::account_id(), + unit(1000) + )); + assert_ok!(Loans::ensure_enough_cash(KSM, unit(1000))); + TotalReserves::::insert(KSM, unit(10)); + assert_noop!( + Loans::ensure_enough_cash(KSM, unit(1000)), + Error::::InsufficientCash, + ); + assert_ok!(Loans::ensure_enough_cash(KSM, unit(990))); + }) +} + +#[test] +fn ensure_valid_exchange_rate_works() { + new_test_ext().execute_with(|| { + assert_noop!( + Loans::ensure_valid_exchange_rate(FixedU128::saturating_from_rational(1, 100)), + Error::::InvalidExchangeRate + ); + assert_ok!(Loans::ensure_valid_exchange_rate( + FixedU128::saturating_from_rational(2, 100) + )); + assert_ok!(Loans::ensure_valid_exchange_rate( + FixedU128::saturating_from_rational(3, 100) + )); + assert_ok!(Loans::ensure_valid_exchange_rate( + FixedU128::saturating_from_rational(99, 100) + )); + assert_noop!( + Loans::ensure_valid_exchange_rate(Rate::one()), + Error::::InvalidExchangeRate, + ); + assert_noop!( + Loans::ensure_valid_exchange_rate(Rate::saturating_from_rational(101, 100)), + Error::::InvalidExchangeRate, + ); + }) +} + +#[test] +fn withdraw_missing_reward_works() { + new_test_ext().execute_with(|| { + assert_eq!(::Assets::balance(HKO, &DAVE), unit(1000)); + + assert_ok!(Loans::add_reward(Origin::signed(DAVE), unit(100))); + + assert_ok!(Loans::withdraw_missing_reward( + Origin::root(), + ALICE, + unit(40), + )); + + assert_eq!(::Assets::balance(HKO, &DAVE), unit(900)); + + assert_eq!(::Assets::balance(HKO, &ALICE), unit(40)); + + assert_eq!( + ::Assets::balance(HKO, &Loans::reward_account_id().unwrap()), + unit(60) + ); + }) +} + +#[test] +fn update_market_reward_speed_works() { + new_test_ext().execute_with(|| { + assert_eq!(Loans::reward_supply_speed(DOT), 0); + assert_eq!(Loans::reward_borrow_speed(DOT), 0); + + assert_ok!(Loans::update_market_reward_speed( + Origin::root(), + DOT, + Some(unit(1)), + Some(unit(2)), + )); + assert_eq!(Loans::reward_supply_speed(DOT), unit(1)); + assert_eq!(Loans::reward_borrow_speed(DOT), unit(2)); + + assert_ok!(Loans::update_market_reward_speed( + Origin::root(), + DOT, + Some(unit(2)), + Some(0), + )); + assert_eq!(Loans::reward_supply_speed(DOT), unit(2)); + assert_eq!(Loans::reward_borrow_speed(DOT), unit(0)); + + assert_ok!(Loans::update_market_reward_speed( + Origin::root(), + DOT, + Some(0), + Some(0) + )); + assert_eq!(Loans::reward_supply_speed(DOT), unit(0)); + assert_eq!(Loans::reward_borrow_speed(DOT), unit(0)); + }) +} + +#[test] +fn reward_calculation_one_palyer_in_multi_markets_works() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(100))); + assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, unit(100))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), KSM, true)); + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(10))); + assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(10))); + + _run_to_block(10); + assert_ok!(Loans::update_market_reward_speed( + Origin::root(), + DOT, + Some(unit(1)), + Some(unit(2)), + )); + + // check status + let supply_state = Loans::reward_supply_state(DOT); + assert_eq!(supply_state.block, 10); + assert_eq!(Loans::reward_supplier_index(DOT, ALICE), 0); + let borrow_state = Loans::reward_borrow_state(DOT); + assert_eq!(borrow_state.block, 10); + assert_eq!(Loans::reward_borrower_index(DOT, ALICE), 0); + // DOT supply:100 DOT supply reward: 0 + // DOT borrow:10 DOT borrow reward: 0 + // KSM supply:100 KSM supply reward: 0 + // KSM borrow:10 KSM borrow reward: 0 + assert_eq!(Loans::reward_accrued(ALICE), 0); + + _run_to_block(20); + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(100))); + assert_ok!(Loans::update_market_reward_speed( + Origin::root(), + KSM, + Some(unit(1)), + Some(unit(1)), + )); + + // check status + let supply_state = Loans::reward_supply_state(DOT); + assert_eq!(supply_state.block, 20); + let borrow_state = Loans::reward_borrow_state(DOT); + assert_eq!(borrow_state.block, 10); + // DOT supply:200 DOT supply reward: 10 + // DOT borrow:10 DOT borrow reward: 0 + // KSM supply:100 KSM supply reward: 0 + // KSM borrow:10 KSM borrow reward: 0 + // borrow reward not accrued + assert_eq!(Loans::reward_accrued(ALICE), unit(10)); + + _run_to_block(30); + assert_ok!(Loans::update_market_reward_speed( + Origin::root(), + DOT, + Some(0), + Some(0) + )); + assert_ok!(Loans::redeem(Origin::signed(ALICE), DOT, unit(100))); + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(10))); + assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, unit(100))); + assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(10))); + + let supply_state = Loans::reward_supply_state(DOT); + assert_eq!(supply_state.block, 30); + let borrow_state = Loans::reward_borrow_state(DOT); + assert_eq!(borrow_state.block, 30); + // DOT supply:100 DOT supply reward: 20 + // DOT borrow:20 DOT borrow reward: 40 + // KSM supply:200 KSM supply reward: 10 + // KSM borrow:20 KSM borrow reward: 10 + assert_eq!(almost_equal(Loans::reward_accrued(ALICE), unit(80)), true); + + _run_to_block(40); + assert_ok!(Loans::update_market_reward_speed( + Origin::root(), + KSM, + Some(0), + Some(0) + )); + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(100))); + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(10))); + assert_ok!(Loans::redeem(Origin::signed(ALICE), KSM, unit(100))); + assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(10))); + + let supply_state = Loans::reward_supply_state(DOT); + assert_eq!(supply_state.block, 40); + let borrow_state = Loans::reward_borrow_state(DOT); + assert_eq!(borrow_state.block, 40); + // DOT supply:200 DOT supply reward: 20 + // DOT borrow:30 DOT borrow reward: 40 + // KSM supply:100 KSM supply reward: 20 + // KSM borrow:30 KSM borrow reward: 20 + assert_eq!(almost_equal(Loans::reward_accrued(ALICE), unit(100)), true,); + + _run_to_block(50); + assert_ok!(Loans::update_market_reward_speed( + Origin::root(), + DOT, + Some(unit(1)), + Some(unit(1)), + )); + assert_ok!(Loans::redeem(Origin::signed(ALICE), DOT, unit(100))); + assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), DOT)); + assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, unit(100))); + assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(10))); + + let supply_state = Loans::reward_supply_state(DOT); + assert_eq!(supply_state.block, 50); + let borrow_state = Loans::reward_borrow_state(DOT); + assert_eq!(borrow_state.block, 50); + // DOT supply:100 DOT supply reward: 20 + // DOT borrow:0 DOT borrow reward: 40 + // KSM supply:200 KSM supply reward: 20 + // KSM borrow:40 KSM borrow reward: 20 + assert_eq!(almost_equal(Loans::reward_accrued(ALICE), unit(100)), true,); + + _run_to_block(60); + assert_ok!(Loans::update_market_reward_speed( + Origin::root(), + KSM, + Some(unit(1)), + Some(unit(1)), + )); + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(100))); + assert_ok!(Loans::redeem(Origin::signed(ALICE), KSM, unit(100))); + assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), KSM)); + + let supply_state = Loans::reward_supply_state(DOT); + assert_eq!(supply_state.block, 60); + let borrow_state = Loans::reward_borrow_state(DOT); + assert_eq!(borrow_state.block, 50); + // DOT supply:200 DOT supply reward: 30 + // DOT borrow:0 DOT borrow reward: 40 + // KSM supply:100 KSM supply reward: 20 + // KSM borrow:0 KSM borrow reward: 20 + assert_eq!(almost_equal(Loans::reward_accrued(ALICE), unit(110)), true,); + + _run_to_block(70); + assert_ok!(Loans::update_market_reward_speed( + Origin::root(), + DOT, + Some(0), + Some(0) + )); + assert_ok!(Loans::update_market_reward_speed( + Origin::root(), + KSM, + Some(0), + Some(0) + )); + assert_ok!(Loans::redeem(Origin::signed(ALICE), DOT, unit(100))); + assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, unit(100))); + + let supply_state = Loans::reward_supply_state(DOT); + assert_eq!(supply_state.block, 70); + let borrow_state = Loans::reward_borrow_state(DOT); + assert_eq!(borrow_state.block, 70); + // DOT supply:500 DOT supply reward: 40 + // DOT borrow:0 DOT borrow reward: 40 + // KSM supply:600 KSM supply reward: 30 + // KSM borrow:0 KSM borrow reward: 20 + assert_eq!(almost_equal(Loans::reward_accrued(ALICE), unit(130)), true); + + _run_to_block(80); + assert_ok!(Loans::add_reward(Origin::signed(DAVE), unit(200))); + assert_ok!(Loans::claim_reward(Origin::signed(ALICE))); + assert_eq!(::Assets::balance(HKO, &DAVE), unit(800)); + assert_eq!( + almost_equal(::Assets::balance(HKO, &ALICE), unit(130)), + true + ); + assert_eq!( + almost_equal( + ::Assets::balance(HKO, &Loans::reward_account_id().unwrap()), + unit(70) + ), + true + ); + assert_ok!(Loans::update_market_reward_speed( + Origin::root(), + DOT, + Some(unit(1)), + Some(0), + )); + + // DOT supply:500 DOT supply reward: 50 + // DOT borrow:0 DOT borrow reward: 40 + // KSM supply:600 KSM supply reward: 30 + // KSM borrow:0 KSM borrow reward: 20 + _run_to_block(90); + assert_ok!(Loans::claim_reward(Origin::signed(ALICE))); + assert_eq!( + almost_equal(::Assets::balance(HKO, &ALICE), unit(140)), + true + ); + }) +} + +#[test] +fn reward_calculation_multi_player_in_one_market_works() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(10))); + assert_ok!(Loans::mint(Origin::signed(BOB), DOT, unit(10))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + assert_ok!(Loans::collateral_asset(Origin::signed(BOB), DOT, true)); + + _run_to_block(10); + assert_ok!(Loans::update_market_reward_speed( + Origin::root(), + DOT, + Some(unit(1)), + Some(unit(1)), + )); + // Alice supply:10 supply reward: 0 + // Alice borrow:0 borrow reward: 0 + // BOB supply:10 supply reward: 0 + // BOB borrow:0 borrow reward: 0 + assert_eq!(Loans::reward_accrued(ALICE), 0); + assert_eq!(Loans::reward_accrued(BOB), 0); + + _run_to_block(20); + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(70))); + assert_ok!(Loans::mint(Origin::signed(BOB), DOT, unit(10))); + // Alice supply:80 supply reward: 5 + // Alice borrow:0 borrow reward: 0 + // BOB supply:20 supply reward: 5 + // BOB borrow:10 borrow reward: 0 + assert_eq!(Loans::reward_accrued(ALICE), unit(5)); + assert_eq!(Loans::reward_accrued(BOB), unit(5)); + + _run_to_block(30); + assert_ok!(Loans::redeem(Origin::signed(ALICE), DOT, unit(70))); + assert_ok!(Loans::redeem(Origin::signed(BOB), DOT, unit(10))); + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(1))); + assert_ok!(Loans::borrow(Origin::signed(BOB), DOT, unit(1))); + // Alice supply:10 supply reward: 13 + // Alice borrow:1 borrow reward: 0 + // BOB supply:10 supply reward: 7 + // BOB borrow:1 borrow reward: 0 + assert_eq!(Loans::reward_accrued(ALICE), unit(13)); + assert_eq!(Loans::reward_accrued(BOB), unit(7)); + + _run_to_block(40); + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(10))); + assert_ok!(Loans::mint(Origin::signed(BOB), DOT, unit(10))); + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(1))); + assert_ok!(Loans::repay_borrow_all(Origin::signed(BOB), DOT)); + // Alice supply:20 supply reward: 18 + // Alice borrow:2 borrow reward: 5 + // BOB supply:20 supply reward: 12 + // BOB borrow:0 borrow reward: 5 + assert_eq!(almost_equal(Loans::reward_accrued(ALICE), unit(23)), true); + assert_eq!(almost_equal(Loans::reward_accrued(BOB), unit(17)), true); + + _run_to_block(50); + assert_ok!(Loans::redeem(Origin::signed(ALICE), DOT, unit(10))); + assert_ok!(Loans::redeem_all(Origin::signed(BOB), DOT)); + assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), DOT)); + assert_ok!(Loans::repay_borrow_all(Origin::signed(BOB), DOT)); + // Alice supply:10 supply reward: 23 + // Alice borrow:0 borrow reward: 15 + // BOB supply:0 supply reward: 17 + // BOB borrow:0 borrow reward: 5 + assert_eq!(almost_equal(Loans::reward_accrued(ALICE), unit(38)), true); + assert_eq!(almost_equal(Loans::reward_accrued(BOB), unit(22)), true); + + _run_to_block(60); + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(10))); + assert_ok!(Loans::redeem_all(Origin::signed(BOB), DOT)); + assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), DOT)); + assert_ok!(Loans::repay_borrow_all(Origin::signed(BOB), DOT)); + // Alice supply:10 supply reward: 33 + // Alice borrow:0 borrow reward: 15 + // BOB supply:0 supply reward: 17 + // BOB borrow:0 borrow reward: 5 + assert_eq!(almost_equal(Loans::reward_accrued(ALICE), unit(48)), true); + assert_eq!(almost_equal(Loans::reward_accrued(BOB), unit(22)), true); + + _run_to_block(70); + assert_ok!(Loans::add_reward(Origin::signed(DAVE), unit(200))); + assert_ok!(Loans::claim_reward_for_market(Origin::signed(ALICE), DOT)); + assert_ok!(Loans::claim_reward_for_market(Origin::signed(BOB), DOT)); + assert_eq!(::Assets::balance(HKO, &DAVE), unit(800)); + assert_eq!( + almost_equal(::Assets::balance(HKO, &ALICE), unit(58)), + true + ); + assert_eq!( + almost_equal(::Assets::balance(HKO, &BOB), unit(22)), + true + ); + assert_eq!( + almost_equal( + ::Assets::balance(HKO, &Loans::reward_account_id().unwrap()), + unit(120) + ), + true + ); + }) +} + +#[test] +fn reward_calculation_after_liquidate_borrow_works() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + assert_ok!(Loans::mint(Origin::signed(BOB), KSM, unit(500))); + assert_ok!(Loans::collateral_asset(Origin::signed(BOB), KSM, true)); + assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(50))); + assert_ok!(Loans::borrow(Origin::signed(BOB), KSM, unit(75))); + + _run_to_block(10); + assert_ok!(Loans::update_market_reward_speed( + Origin::root(), + DOT, + Some(unit(1)), + Some(unit(1)), + )); + assert_ok!(Loans::update_market_reward_speed( + Origin::root(), + KSM, + Some(unit(1)), + Some(unit(1)), + )); + + _run_to_block(20); + assert_ok!(Loans::update_reward_supply_index(DOT)); + assert_ok!(Loans::distribute_supplier_reward(DOT, &ALICE)); + assert_ok!(Loans::distribute_supplier_reward(DOT, &BOB)); + assert_ok!(Loans::update_reward_borrow_index(DOT)); + assert_ok!(Loans::distribute_borrower_reward(DOT, &ALICE)); + assert_ok!(Loans::distribute_borrower_reward(DOT, &BOB)); + + assert_ok!(Loans::update_reward_supply_index(KSM)); + assert_ok!(Loans::distribute_supplier_reward(KSM, &ALICE)); + assert_ok!(Loans::distribute_supplier_reward(KSM, &BOB)); + assert_ok!(Loans::update_reward_borrow_index(KSM)); + assert_ok!(Loans::distribute_borrower_reward(KSM, &ALICE)); + assert_ok!(Loans::distribute_borrower_reward(KSM, &BOB)); + + assert_eq!(almost_equal(Loans::reward_accrued(ALICE), unit(14)), true); + assert_eq!(almost_equal(Loans::reward_accrued(BOB), unit(16)), true); + + MockPriceFeeder::set_price(KSM, 2.into()); + // since we set liquidate_threshold more than collateral_factor,with KSM price as 2 alice not shortfall yet. + // so we can not liquidate_borrow here + assert_noop!( + Loans::liquidate_borrow(Origin::signed(BOB), ALICE, KSM, unit(25), DOT), + Error::::InsufficientShortfall + ); + // then we change KSM price = 3 to make alice shortfall + // incentive = repay KSM value * 1.1 = (25 * 3) * 1.1 = 82.5 + // Alice DOT Deposit: 200 - 82.5 = 117.5 + // Alice KSM Borrow: 50 - 25 = 25 + // Bob DOT Deposit: 75 + 75*0.07 = 80.25 + // Bob KSM Deposit: 500 + // Bob KSM Borrow: 75 + // incentive_reward_account DOT Deposit: 75*0.03 = 2.25 + MockPriceFeeder::set_price(KSM, 3.into()); + assert_ok!(Loans::liquidate_borrow( + Origin::signed(BOB), + ALICE, + KSM, + unit(25), + DOT + )); + + _run_to_block(30); + assert_ok!(Loans::update_reward_supply_index(DOT)); + assert_ok!(Loans::distribute_supplier_reward(DOT, &ALICE)); + assert_ok!(Loans::distribute_supplier_reward(DOT, &BOB)); + assert_ok!(Loans::update_reward_borrow_index(DOT)); + assert_ok!(Loans::distribute_borrower_reward(DOT, &ALICE)); + assert_ok!(Loans::distribute_borrower_reward(DOT, &BOB)); + + assert_ok!(Loans::update_reward_supply_index(KSM)); + assert_ok!(Loans::distribute_supplier_reward(KSM, &ALICE)); + assert_ok!(Loans::distribute_supplier_reward(KSM, &BOB)); + assert_ok!(Loans::update_reward_borrow_index(KSM)); + assert_ok!(Loans::distribute_borrower_reward(KSM, &ALICE)); + assert_ok!(Loans::distribute_borrower_reward(KSM, &BOB)); + assert_ok!(Loans::distribute_supplier_reward( + DOT, + &Loans::incentive_reward_account_id().unwrap(), + )); + + assert_eq!( + almost_equal(Loans::reward_accrued(ALICE), milli_unit(22375)), + true + ); + assert_eq!( + almost_equal(Loans::reward_accrued(BOB), micro_unit(37512500)), + true + ); + assert_eq!( + almost_equal( + Loans::reward_accrued(Loans::incentive_reward_account_id().unwrap()), + micro_unit(112500), + ), + true, + ); + }) +} diff --git a/crates/loans/src/tests/edge_cases.rs b/crates/loans/src/tests/edge_cases.rs new file mode 100644 index 0000000000..d5f054b11b --- /dev/null +++ b/crates/loans/src/tests/edge_cases.rs @@ -0,0 +1,135 @@ +use super::*; +use crate::tests::Loans; +use crate::{mock::*, Error}; +use frame_support::{assert_err, assert_ok}; +use sp_runtime::FixedPointNumber; + +#[test] +fn exceeded_supply_cap() { + new_test_ext().execute_with(|| { + Assets::mint(Origin::signed(ALICE), DOT, ALICE, million_unit(1001)).unwrap(); + let amount = million_unit(501); + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, amount)); + // Exceed upper bound. + assert_err!( + Loans::mint(Origin::signed(ALICE), DOT, amount), + Error::::SupplyCapacityExceeded + ); + + Loans::redeem(Origin::signed(ALICE), DOT, amount).unwrap(); + // Here should work, cause we redeemed already. + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, amount)); + }) +} + +#[test] +fn repay_borrow_all_no_underflow() { + new_test_ext().execute_with(|| { + // Alice deposits 200 KSM as collateral + assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), KSM, true)); + + // Alice borrow only 1/1e5 KSM which is hard to accrue total borrows interest in 100 seconds + assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, 10_u128.pow(7))); + + accrue_interest_per_block(KSM, 100, 9); + + assert_eq!(Loans::current_borrow_balance(&ALICE, KSM), Ok(10000005)); + // FIXME since total_borrows is too small and we accrue internal on it every 100 seconds + // accrue_interest fails every time + // as you can see the current borrow balance is not equal to total_borrows anymore + assert_eq!(Loans::total_borrows(KSM), 10000000); + + // Alice repay all borrow balance. total_borrows = total_borrows.saturating_sub(10000005) = 0. + assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), KSM)); + + assert_eq!(Assets::balance(KSM, &ALICE), unit(800) - 5); + + assert_eq!( + Loans::exchange_rate(DOT) + .saturating_mul_int(Loans::account_deposits(KSM, ALICE).voucher_balance), + unit(200) + ); + + let borrow_snapshot = Loans::account_borrows(KSM, ALICE); + assert_eq!(borrow_snapshot.principal, 0); + assert_eq!(borrow_snapshot.borrow_index, Loans::borrow_index(KSM)); + }) +} + +#[test] +fn ensure_capacity_fails_when_market_not_existed() { + new_test_ext().execute_with(|| { + assert_err!( + Loans::ensure_under_supply_cap(SDOT, unit(100)), + Error::::MarketDoesNotExist + ); + }); +} + +#[test] +fn redeem_all_should_be_accurate() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), KSM, true)); + assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(50))); + + // let exchange_rate greater than 0.02 + accrue_interest_per_block(KSM, 6, 2); + assert_eq!( + Loans::exchange_rate(KSM), + Rate::from_inner(20000000036387000) + ); + + assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), KSM)); + // It failed with InsufficientLiquidity before #839 + assert_ok!(Loans::redeem_all(Origin::signed(ALICE), KSM)); + }) +} + +#[test] +fn prevent_the_exchange_rate_attack() { + new_test_ext().execute_with(|| { + // Initialize Eve's balance + assert_ok!(::Assets::transfer( + DOT, + &ALICE, + &EVE, + unit(200), + false + )); + // Eve deposits a small amount + assert_ok!(Loans::mint(Origin::signed(EVE), DOT, 1)); + // !!! Eve transfer a big amount to Loans::account_id + assert_ok!(::Assets::transfer( + DOT, + &EVE, + &Loans::account_id(), + unit(100), + false + )); + assert_eq!(::Assets::balance(DOT, &EVE), 99999999999999); + assert_eq!( + ::Assets::balance(DOT, &Loans::account_id()), + 100000000000001 + ); + assert_eq!( + Loans::total_supply(DOT), + 1 * 50, // 1 / 0.02 + ); + TimestampPallet::set_timestamp(12000); + // Eve can not let the exchange rate greater than 1 + assert!(Loans::accrue_interest(DOT).is_err()); + + // Mock a BIG exchange_rate: 100000000000.02 + ExchangeRate::::insert( + DOT, + Rate::saturating_from_rational(100000000000020u128, 20 * 50), + ); + // Bob can not deposit 0.1 DOT because the voucher_balance can not be 0. + assert_noop!( + Loans::mint(Origin::signed(BOB), DOT, 100000000000), + Error::::InvalidExchangeRate + ); + }) +} diff --git a/crates/loans/src/tests/interest_rate.rs b/crates/loans/src/tests/interest_rate.rs new file mode 100644 index 0000000000..d0c5350624 --- /dev/null +++ b/crates/loans/src/tests/interest_rate.rs @@ -0,0 +1,344 @@ +use crate::tests::Loans; +use crate::{mock::*, Markets}; +use frame_support::assert_ok; +use primitives::{Rate, Ratio, SECONDS_PER_YEAR}; +use sp_runtime::{ + traits::{CheckedDiv, One, Saturating}, + FixedPointNumber, +}; + +#[test] +fn utilization_rate_works() { + // 50% borrow + assert_eq!( + Loans::calc_utilization_ratio(1, 1, 0).unwrap(), + Ratio::from_percent(50) + ); + assert_eq!( + Loans::calc_utilization_ratio(100, 100, 0).unwrap(), + Ratio::from_percent(50) + ); + // no borrow + assert_eq!( + Loans::calc_utilization_ratio(1, 0, 0).unwrap(), + Ratio::zero() + ); + // full borrow + assert_eq!( + Loans::calc_utilization_ratio(0, 1, 0).unwrap(), + Ratio::from_percent(100) + ); +} + +#[test] +fn interest_rate_model_works() { + new_test_ext().execute_with(|| { + let rate_decimal: u128 = 1_000_000_000_000_000_000; + Assets::mint( + Origin::signed(ALICE), + DOT, + ALICE, + million_unit(1000) - unit(1000), + ) + .unwrap(); + // Deposit 200 DOT and borrow 100 DOT + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, million_unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, million_unit(100))); + + let total_cash = million_unit(200) - million_unit(100); + let total_supply = + Loans::calc_collateral_amount(million_unit(200), Loans::exchange_rate(DOT)).unwrap(); + assert_eq!(Loans::total_supply(DOT), total_supply); + + let borrow_snapshot = Loans::account_borrows(DOT, ALICE); + assert_eq!(borrow_snapshot.principal, million_unit(100)); + assert_eq!(borrow_snapshot.borrow_index, Rate::one()); + + let base_rate = Rate::saturating_from_rational(2, 100); + let jump_rate = Rate::saturating_from_rational(10, 100); + // let full_rate = Rate::saturating_from_rational(32, 100); + let jump_utilization = Ratio::from_percent(80); + + let mut borrow_index = Rate::one(); + let mut total_borrows = borrow_snapshot.principal; + let mut total_reserves: u128 = 0; + + // Interest accrued from blocks 1 to 49 + for i in 1..49 { + let delta_time = 6u128; + TimestampPallet::set_timestamp(6000 * (i + 1)); + assert_ok!(Loans::accrue_interest(DOT)); + // utilizationRatio = totalBorrows / (totalCash + totalBorrows) + let util_ratio = Ratio::from_rational(total_borrows, total_cash + total_borrows); + assert_eq!(Loans::utilization_ratio(DOT), util_ratio); + + let borrow_rate = + (jump_rate - base_rate) * util_ratio.into() / jump_utilization.into() + base_rate; + let interest_accumulated: u128 = borrow_rate + .saturating_mul_int(total_borrows) + .saturating_mul(delta_time.into()) + .checked_div(SECONDS_PER_YEAR.into()) + .unwrap(); + total_borrows = interest_accumulated + total_borrows; + assert_eq!(Loans::total_borrows(DOT), total_borrows); + total_reserves = Markets::::get(&DOT) + .unwrap() + .reserve_factor + .mul_floor(interest_accumulated) + + total_reserves; + assert_eq!(Loans::total_reserves(DOT), total_reserves); + + // exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply + assert_eq!( + Loans::exchange_rate(DOT).into_inner(), + (total_cash + total_borrows - total_reserves) * rate_decimal / total_supply + ); + let numerator = borrow_index + .saturating_mul(borrow_rate) + .saturating_mul(Rate::saturating_from_integer(delta_time)) + .checked_div(&Rate::saturating_from_integer(SECONDS_PER_YEAR)) + .unwrap(); + borrow_index = numerator + borrow_index; + assert_eq!(Loans::borrow_index(DOT), borrow_index); + } + assert_eq!(total_borrows, 100000063926960646826); + assert_eq!(total_reserves, 9589044097001); + assert_eq!(borrow_index, Rate::from_inner(1000000639269606444)); + assert_eq!( + Loans::exchange_rate(DOT), + Rate::from_inner(20000005433791654) + ); + + // Calculate borrow accrued interest + let borrow_principal = (borrow_index / borrow_snapshot.borrow_index) + .saturating_mul_int(borrow_snapshot.principal); + let supply_interest = + Loans::exchange_rate(DOT).saturating_mul_int(total_supply) - million_unit(200); + assert_eq!(supply_interest, 54337916540000); + assert_eq!(borrow_principal, 100000063926960644400); + assert_eq!(total_borrows / 10000, borrow_principal / 10000); + assert_eq!( + (total_borrows - million_unit(100) - total_reserves) / 10000, + supply_interest / 10000 + ); + }) +} + +#[test] +fn last_accrued_interest_time_should_be_update_correctly() { + new_test_ext().execute_with(|| { + assert_eq!(Loans::borrow_index(DOT), Rate::one()); + assert_eq!(Loans::last_accrued_interest_time(DOT), 0); + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); + assert_eq!(Loans::last_accrued_interest_time(DOT), 6); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(100))); + assert_eq!(Loans::borrow_index(DOT), Rate::one()); + TimestampPallet::set_timestamp(12000); + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(100))); + assert_eq!( + Loans::borrow_index(DOT), + Rate::from_inner(1000000013318112633), + ); + }) +} + +#[test] +fn accrue_interest_works_after_mint() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(100))); + assert_eq!(Loans::borrow_index(DOT), Rate::one()); + TimestampPallet::set_timestamp(12000); + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(100))); + assert_eq!( + Loans::borrow_index(DOT), + Rate::from_inner(1000000013318112633), + ); + }) +} + +#[test] +fn accrue_interest_works_after_borrow() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + assert_eq!(Loans::borrow_index(DOT), Rate::one()); + TimestampPallet::set_timestamp(12000); + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(100))); + assert_eq!( + Loans::borrow_index(DOT), + Rate::from_inner(1000000003805175038), + ); + }) +} + +#[test] +fn accrue_interest_works_after_redeem() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(10))); + assert_eq!(Loans::borrow_index(DOT), Rate::one()); + TimestampPallet::set_timestamp(12000); + assert_ok!(Loans::redeem(Origin::signed(ALICE), DOT, unit(10))); + assert_eq!( + Loans::borrow_index(DOT), + Rate::from_inner(1000000004756468797), + ); + assert_eq!( + Loans::exchange_rate(DOT) + .saturating_mul_int(Loans::account_deposits(DOT, BOB).voucher_balance), + 0, + ); + assert_eq!( + ::Assets::balance(DOT, &ALICE), + 819999999999999 + ); + }) +} + +#[test] +fn accrue_interest_works_after_redeem_all() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::mint(Origin::signed(BOB), DOT, unit(20))); + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(10))); + assert_eq!(Loans::borrow_index(DOT), Rate::one()); + TimestampPallet::set_timestamp(12000); + assert_ok!(Loans::redeem_all(Origin::signed(BOB), DOT)); + assert_eq!( + Loans::borrow_index(DOT), + Rate::from_inner(1000000004669977168), + ); + assert_eq!( + Loans::exchange_rate(DOT) + .saturating_mul_int(Loans::account_deposits(DOT, BOB).voucher_balance), + 0, + ); + assert_eq!( + ::Assets::balance(DOT, &BOB), + 1000000000003608 + ); + assert!(!AccountDeposits::::contains_key(DOT, &BOB)) + }) +} + +#[test] +fn accrue_interest_works_after_repay() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(20))); + assert_eq!(Loans::borrow_index(DOT), Rate::one()); + TimestampPallet::set_timestamp(12000); + assert_ok!(Loans::repay_borrow(Origin::signed(ALICE), DOT, unit(10))); + assert_eq!( + Loans::borrow_index(DOT), + Rate::from_inner(1000000005707762557), + ); + }) +} + +#[test] +fn accrue_interest_works_after_repay_all() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::mint(Origin::signed(BOB), KSM, unit(200))); + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(50))); + assert_eq!(Loans::borrow_index(KSM), Rate::one()); + TimestampPallet::set_timestamp(12000); + assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), KSM)); + assert_eq!( + Loans::borrow_index(KSM), + Rate::from_inner(1000000008561643835), + ); + assert_eq!( + ::Assets::balance(KSM, &ALICE), + 999999999571918 + ); + let borrow_snapshot = Loans::account_borrows(KSM, ALICE); + assert_eq!(borrow_snapshot.principal, 0); + assert_eq!(borrow_snapshot.borrow_index, Loans::borrow_index(KSM)); + }) +} + +#[test] +fn accrue_interest_works_after_liquidate_borrow() { + new_test_ext().execute_with(|| { + // Bob deposits 200 KSM + assert_ok!(Loans::mint(Origin::signed(BOB), KSM, unit(200))); + // Alice deposits 300 DOT as collateral + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(300))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + // Alice borrows 100 KSM and 50 DOT + assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(100))); + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(50))); + assert_eq!(Loans::borrow_index(DOT), Rate::one()); + assert_eq!(Loans::borrow_index(KSM), Rate::one()); + TimestampPallet::set_timestamp(12000); + // Adjust KSM price to make shortfall + MockPriceFeeder::set_price(KSM, 2.into()); + // BOB repay the KSM loan and get DOT callateral from ALICE + assert_ok!(Loans::liquidate_borrow( + Origin::signed(BOB), + ALICE, + KSM, + unit(50), + DOT + )); + assert_eq!( + Loans::borrow_index(KSM), + Rate::from_inner(1000000013318112633), + ); + assert_eq!( + Loans::borrow_index(DOT), + Rate::from_inner(1000000006976141552), + ); + }) +} + +#[test] +fn different_markets_can_accrue_interest_in_one_block() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), KSM, true)); + assert_eq!(Loans::borrow_index(DOT), Rate::one()); + assert_eq!(Loans::borrow_index(KSM), Rate::one()); + TimestampPallet::set_timestamp(12000); + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(100))); + assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(100))); + assert_eq!( + Loans::borrow_index(DOT), + Rate::from_inner(1000000003805175038), + ); + assert_eq!( + Loans::borrow_index(KSM), + Rate::from_inner(1000000003805175038), + ); + }) +} + +#[test] +fn a_market_can_only_accrue_interest_once_in_a_block() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + assert_ok!(Loans::mint(Origin::signed(BOB), DOT, unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(BOB), DOT, true)); + assert_eq!(Loans::borrow_index(DOT), Rate::one()); + TimestampPallet::set_timestamp(12000); + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(100))); + assert_ok!(Loans::borrow(Origin::signed(BOB), DOT, unit(100))); + assert_eq!( + Loans::borrow_index(DOT), + Rate::from_inner(1000000003805175038), + ); + }) +} diff --git a/crates/loans/src/tests/liquidate_borrow.rs b/crates/loans/src/tests/liquidate_borrow.rs new file mode 100644 index 0000000000..e086c77795 --- /dev/null +++ b/crates/loans/src/tests/liquidate_borrow.rs @@ -0,0 +1,279 @@ +use crate::{ + mock::{ + new_test_ext, Assets, Loans, MockPriceFeeder, Origin, Test, ALICE, BOB, DOT, KSM, USDT, + }, + tests::unit, + Error, MarketState, +}; +use frame_support::{assert_err, assert_noop, assert_ok}; +use primitives::{tokens::CDOT_6_13, Rate, DOT_U}; +use sp_runtime::FixedPointNumber; + +#[test] +fn liquidate_borrow_allowed_works() { + new_test_ext().execute_with(|| { + // Borrower should have a positive shortfall + let dot_market = Loans::market(DOT).unwrap(); + assert_noop!( + Loans::liquidate_borrow_allowed(&ALICE, DOT, 100, &dot_market), + Error::::InsufficientShortfall + ); + initial_setup(); + alice_borrows_100_ksm(); + // Adjust KSM price to make shortfall + MockPriceFeeder::set_price(KSM, 2.into()); + let ksm_market = Loans::market(KSM).unwrap(); + // Here the balance sheet of Alice is: + // Collateral Loans + // CDOT $200 KSM $400 + // USDT $200 + assert_noop!( + Loans::liquidate_borrow_allowed(&ALICE, KSM, unit(51), &ksm_market), + Error::::TooMuchRepay + ); + assert_ok!(Loans::liquidate_borrow_allowed( + &ALICE, + KSM, + unit(50), + &ksm_market + )); + }) +} + +#[test] +fn lf_liquidate_borrow_fails_due_to_lf_collateral() { + new_test_ext().execute_with(|| { + Loans::update_liquidation_free_collateral(Origin::root(), vec![CDOT_6_13]).unwrap(); + + assert_err!( + Loans::liquidate_borrow(Origin::signed(ALICE), BOB, DOT, unit(100), CDOT_6_13), + Error::::CollateralReserved + ); + assert_err!( + Loans::liquidate_borrow(Origin::signed(ALICE), BOB, DOT, unit(100), DOT_U), + Error::::CollateralReserved + ); + }) +} + +#[test] +fn lf_liquidate_borrow_allowed_works() { + new_test_ext().execute_with(|| { + Loans::update_liquidation_free_collateral(Origin::root(), vec![CDOT_6_13]).unwrap(); + // Bob deposits $200 DOT + Loans::mint(Origin::signed(BOB), DOT, unit(200)).unwrap(); + Loans::mint(Origin::signed(ALICE), USDT, unit(200)).unwrap(); + Loans::mint(Origin::signed(ALICE), CDOT_6_13, unit(200)).unwrap(); + Loans::collateral_asset(Origin::signed(ALICE), USDT, true).unwrap(); + Loans::collateral_asset(Origin::signed(ALICE), CDOT_6_13, true).unwrap(); + + // ALICE + // Collateral Borrowed + // USDT $100 DOT $200 + // CDOT $100 + Loans::borrow(Origin::signed(ALICE), DOT, unit(200)).unwrap(); + + // CDOT's price is highly relative to DOT's price in real runtime. Thus we must update them + // at the same time. + MockPriceFeeder::set_price(DOT, 2.into()); + MockPriceFeeder::set_price(CDOT_6_13, 2.into()); + // ALICE + // Collateral Borrowed + // USDT $100 DOT $400 + // CDOT $200 + + let dot_market = Loans::market(DOT).unwrap(); + // The max repay amount = (400 - 200) * 50% = $100 + assert_err!( + Loans::liquidate_borrow_allowed(&ALICE, DOT, unit(51), &dot_market), + Error::::TooMuchRepay + ); + assert_ok!(Loans::liquidate_borrow_allowed( + &ALICE, + DOT, + unit(50), + &dot_market + )); + + // Remove CDOT from lf collateral + Loans::update_liquidation_free_collateral(Origin::root(), vec![]).unwrap(); + // The max repay amount = 400 * 50 = $200 + assert_ok!(Loans::liquidate_borrow_allowed( + &ALICE, + DOT, + unit(100), + &dot_market + )); + }) +} + +#[test] +fn deposit_of_borrower_must_be_collateral() { + new_test_ext().execute_with(|| { + initial_setup(); + alice_borrows_100_ksm(); + // Adjust KSM price to make shortfall + MockPriceFeeder::set_price(KSM, 2.into()); + let market = Loans::market(KSM).unwrap(); + assert_noop!( + Loans::liquidate_borrow_allowed(&ALICE, KSM, unit(51), &market), + Error::::TooMuchRepay + ); + assert_noop!( + Loans::liquidate_borrow(Origin::signed(BOB), ALICE, KSM, 10, DOT), + Error::::DepositsAreNotCollateral + ); + }) +} + +#[test] +fn collateral_value_must_be_greater_than_liquidation_value() { + new_test_ext().execute_with(|| { + initial_setup(); + alice_borrows_100_ksm(); + MockPriceFeeder::set_price(KSM, Rate::from_float(2000.0)); + Loans::mutate_market(KSM, |market| { + market.liquidate_incentive = Rate::from_float(200.0); + market.clone() + }) + .unwrap(); + assert_noop!( + Loans::liquidate_borrow(Origin::signed(BOB), ALICE, KSM, unit(50), USDT), + Error::::InsufficientCollateral + ); + }) +} + +#[test] +fn full_workflow_works_as_expected() { + new_test_ext().execute_with(|| { + initial_setup(); + alice_borrows_100_ksm(); + // adjust KSM price to make ALICE generate shortfall + MockPriceFeeder::set_price(KSM, 2.into()); + // BOB repay the KSM borrow balance and get DOT from ALICE + assert_ok!(Loans::liquidate_borrow( + Origin::signed(BOB), + ALICE, + KSM, + unit(50), + USDT + )); + + // KSM price = 2 + // incentive = repay KSM value * 1.1 = (50 * 2) * 1.1 = 110 + // Alice USDT: cash - deposit = 1000 - 200 = 800 + // Alice USDT collateral: deposit - incentive = 200 - 110 = 90 + // Alice KSM: cash + borrow = 1000 + 100 = 1100 + // Alice KSM borrow balance: origin borrow balance - liquidate amount = 100 - 50 = 50 + // Bob KSM: cash - deposit - repay = 1000 - 200 - 50 = 750 + // Bob DOT collateral: incentive = 110-(110/1.1*0.03)=107 + assert_eq!(Assets::balance(USDT, &ALICE), unit(800),); + assert_eq!( + Loans::exchange_rate(USDT) + .saturating_mul_int(Loans::account_deposits(USDT, ALICE).voucher_balance), + unit(90), + ); + assert_eq!(Assets::balance(KSM, &ALICE), unit(1100),); + assert_eq!(Loans::account_borrows(KSM, ALICE).principal, unit(50)); + assert_eq!(Assets::balance(KSM, &BOB), unit(750)); + assert_eq!( + Loans::exchange_rate(USDT) + .saturating_mul_int(Loans::account_deposits(USDT, BOB).voucher_balance), + unit(107), + ); + // 3 dollar reserved in our incentive reward account + let incentive_reward_account = Loans::incentive_reward_account_id().unwrap(); + println!( + "incentive reserve account:{:?}", + incentive_reward_account.clone() + ); + assert_eq!( + Loans::exchange_rate(USDT).saturating_mul_int( + Loans::account_deposits(USDT, incentive_reward_account.clone()).voucher_balance + ), + unit(3), + ); + assert_eq!(Assets::balance(USDT, &ALICE), unit(800),); + // reduce 2 dollar from incentive reserve to alice account + assert_ok!(Loans::reduce_incentive_reserves( + Origin::root(), + ALICE, + USDT, + unit(2), + )); + // still 1 dollar left in reserve account + assert_eq!( + Loans::exchange_rate(USDT).saturating_mul_int( + Loans::account_deposits(USDT, incentive_reward_account).voucher_balance + ), + unit(1), + ); + // 2 dollar transfer to alice + assert_eq!(Assets::balance(USDT, &ALICE), unit(800) + unit(2),); + }) +} + +#[test] +fn liquidator_cannot_take_inactive_market_currency() { + new_test_ext().execute_with(|| { + initial_setup(); + alice_borrows_100_ksm(); + // Adjust KSM price to make shortfall + MockPriceFeeder::set_price(KSM, 2.into()); + assert_ok!(Loans::mutate_market(DOT, |stored_market| { + stored_market.state = MarketState::Supervision; + stored_market.clone() + })); + assert_noop!( + Loans::liquidate_borrow(Origin::signed(BOB), ALICE, KSM, unit(50), DOT), + Error::::MarketNotActivated + ); + }) +} + +#[test] +fn liquidator_can_not_repay_more_than_the_close_factor_pct_multiplier() { + new_test_ext().execute_with(|| { + initial_setup(); + alice_borrows_100_ksm(); + MockPriceFeeder::set_price(KSM, 20.into()); + assert_noop!( + Loans::liquidate_borrow(Origin::signed(BOB), ALICE, KSM, unit(51), DOT), + Error::::TooMuchRepay + ); + }) +} + +#[test] +fn liquidator_must_not_be_borrower() { + new_test_ext().execute_with(|| { + initial_setup(); + assert_noop!( + Loans::liquidate_borrow(Origin::signed(ALICE), ALICE, KSM, 0, DOT), + Error::::LiquidatorIsBorrower + ); + }) +} + +fn alice_borrows_100_ksm() { + assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(100))); +} + +fn initial_setup() { + // Bob deposits 200 KSM + assert_ok!(Loans::mint(Origin::signed(BOB), KSM, unit(200))); + // Alice deposits 200 DOT as collateral + assert_ok!(Loans::mint(Origin::signed(ALICE), USDT, unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), USDT, true)); + assert_ok!(Loans::mint(Origin::signed(ALICE), CDOT_6_13, unit(200))); + assert_ok!(Loans::collateral_asset( + Origin::signed(ALICE), + CDOT_6_13, + true + )); + assert_ok!(Loans::update_liquidation_free_collateral( + Origin::root(), + vec![CDOT_6_13] + )); +} diff --git a/crates/loans/src/tests/market.rs b/crates/loans/src/tests/market.rs new file mode 100644 index 0000000000..ac5f70ea47 --- /dev/null +++ b/crates/loans/src/tests/market.rs @@ -0,0 +1,422 @@ +use crate::{ + mock::{ + market_mock, new_test_ext, Loans, Origin, Test, ACTIVE_MARKET_MOCK, ALICE, DOT, + MARKET_MOCK, PDOT, PUSDT, SDOT, + }, + Error, InterestRateModel, MarketState, +}; +use frame_support::{assert_noop, assert_ok, error::BadOrigin}; +use primitives::{Rate, Ratio}; +use sp_runtime::{traits::Zero, FixedPointNumber}; + +macro_rules! rate_model_sanity_check { + ($call:ident) => { + new_test_ext().execute_with(|| { + // Invalid base_rate + assert_noop!( + Loans::$call(Origin::root(), SDOT, { + let mut market = MARKET_MOCK; + market.rate_model = InterestRateModel::new_jump_model( + Rate::saturating_from_rational(36, 100), + Rate::saturating_from_rational(15, 100), + Rate::saturating_from_rational(35, 100), + Ratio::from_percent(80), + ); + market + }), + Error::::InvalidRateModelParam + ); + // Invalid jump_rate + assert_noop!( + Loans::$call(Origin::root(), SDOT, { + let mut market = MARKET_MOCK; + market.rate_model = InterestRateModel::new_jump_model( + Rate::saturating_from_rational(5, 100), + Rate::saturating_from_rational(36, 100), + Rate::saturating_from_rational(37, 100), + Ratio::from_percent(80), + ); + market + }), + Error::::InvalidRateModelParam + ); + // Invalid full_rate + assert_noop!( + Loans::$call(Origin::root(), SDOT, { + let mut market = MARKET_MOCK; + market.rate_model = InterestRateModel::new_jump_model( + Rate::saturating_from_rational(5, 100), + Rate::saturating_from_rational(15, 100), + Rate::saturating_from_rational(57, 100), + Ratio::from_percent(80), + ); + market + }), + Error::::InvalidRateModelParam + ); + // base_rate greater than jump_rate + assert_noop!( + Loans::$call(Origin::root(), SDOT, { + let mut market = MARKET_MOCK; + market.rate_model = InterestRateModel::new_jump_model( + Rate::saturating_from_rational(10, 100), + Rate::saturating_from_rational(9, 100), + Rate::saturating_from_rational(14, 100), + Ratio::from_percent(80), + ); + market + }), + Error::::InvalidRateModelParam + ); + // jump_rate greater than full_rate + assert_noop!( + Loans::$call(Origin::root(), SDOT, { + let mut market = MARKET_MOCK; + market.rate_model = InterestRateModel::new_jump_model( + Rate::saturating_from_rational(5, 100), + Rate::saturating_from_rational(15, 100), + Rate::saturating_from_rational(14, 100), + Ratio::from_percent(80), + ); + market + }), + Error::::InvalidRateModelParam + ); + }) + }; +} + +#[test] +fn active_market_sets_state_to_active() { + new_test_ext().execute_with(|| { + Loans::add_market(Origin::root(), SDOT, MARKET_MOCK).unwrap(); + assert_eq!(Loans::market(SDOT).unwrap().state, MarketState::Pending); + Loans::activate_market(Origin::root(), SDOT).unwrap(); + assert_eq!(Loans::market(SDOT).unwrap().state, MarketState::Active); + }) +} + +#[test] +fn active_market_does_not_modify_unknown_market_currencies() { + new_test_ext().execute_with(|| { + assert_noop!( + Loans::activate_market(Origin::root(), SDOT), + Error::::MarketDoesNotExist + ); + }) +} + +#[test] +fn add_market_can_only_be_used_by_root() { + new_test_ext().execute_with(|| { + assert_noop!( + Loans::add_market(Origin::signed(ALICE), DOT, MARKET_MOCK), + BadOrigin + ); + }) +} + +#[test] +fn add_market_ensures_that_market_state_must_be_pending() { + new_test_ext().execute_with(|| { + assert_noop!( + Loans::add_market(Origin::root(), SDOT, ACTIVE_MARKET_MOCK), + Error::::NewMarketMustHavePendingState + ); + }) +} + +#[test] +fn add_market_has_sanity_checks_for_rate_models() { + rate_model_sanity_check!(add_market); +} + +#[test] +fn add_market_successfully_stores_a_new_market() { + new_test_ext().execute_with(|| { + Loans::add_market(Origin::root(), SDOT, MARKET_MOCK).unwrap(); + assert_eq!(Loans::market(SDOT).unwrap(), MARKET_MOCK); + }) +} + +#[test] +fn add_market_ensures_that_market_does_not_exist() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::add_market(Origin::root(), SDOT, MARKET_MOCK)); + assert_noop!( + Loans::add_market(Origin::root(), SDOT, MARKET_MOCK), + Error::::MarketAlreadyExists + ); + }) +} + +#[test] +fn force_update_market_can_only_be_used_by_root() { + new_test_ext().execute_with(|| { + assert_noop!( + Loans::force_update_market(Origin::signed(ALICE), DOT, MARKET_MOCK), + BadOrigin + ); + }) +} + +#[test] +fn force_update_market_works() { + new_test_ext().execute_with(|| { + let mut new_market = market_mock(PDOT); + new_market.state = MarketState::Active; + Loans::force_update_market(Origin::root(), DOT, new_market).unwrap(); + assert_eq!(Loans::market(DOT).unwrap().state, MarketState::Active); + assert_eq!(Loans::market(DOT).unwrap().ptoken_id, PDOT); + + // New ptoken_id must not be in use + assert_noop!( + Loans::force_update_market(Origin::root(), DOT, market_mock(PUSDT)), + Error::::InvalidPtokenId + ); + assert_ok!(Loans::force_update_market( + Origin::root(), + DOT, + market_mock(1234) + )); + assert_eq!(Loans::market(DOT).unwrap().ptoken_id, 1234); + }) +} + +#[test] +fn force_update_market_ensures_that_it_is_not_possible_to_modify_unknown_market_currencies() { + new_test_ext().execute_with(|| { + assert_noop!( + Loans::force_update_market(Origin::root(), SDOT, MARKET_MOCK), + Error::::MarketDoesNotExist + ); + }) +} + +#[test] +fn update_market_has_sanity_checks_for_rate_models() { + rate_model_sanity_check!(force_update_market); +} + +#[test] +fn update_market_ensures_that_it_is_not_possible_to_modify_unknown_market_currencies() { + new_test_ext().execute_with(|| { + assert_noop!( + Loans::update_market( + Origin::root(), + SDOT, + None, + None, + None, + None, + None, + None, + None, + None, + ), + Error::::MarketDoesNotExist + ); + }) +} + +#[test] +fn update_market_works() { + new_test_ext().execute_with(|| { + assert_eq!( + Loans::market(DOT).unwrap().close_factor, + Ratio::from_percent(50) + ); + + let market = MARKET_MOCK; + assert_ok!(Loans::update_market( + Origin::root(), + DOT, + None, + None, + None, + Some(Default::default()), + None, + None, + None, + None, + )); + + assert_eq!(Loans::market(DOT).unwrap().close_factor, Default::default()); + assert_eq!(Loans::market(DOT).unwrap().supply_cap, market.supply_cap); + }) +} + +#[test] +fn update_market_should_not_work_if_with_invalid_params() { + new_test_ext().execute_with(|| { + assert_eq!( + Loans::market(DOT).unwrap().close_factor, + Ratio::from_percent(50) + ); + + // check error code while collateral_factor is [0%, 100%) + assert_ok!(Loans::update_market( + Origin::root(), + DOT, + Some(Ratio::zero()), + None, + None, + Some(Default::default()), + None, + None, + None, + None, + )); + assert_noop!( + Loans::update_market( + Origin::root(), + DOT, + Some(Ratio::one()), + None, + None, + Some(Default::default()), + None, + None, + None, + None, + ), + Error::::InvalidFactor + ); + // check error code while reserve_factor is 0% or bigger than 100% + assert_noop!( + Loans::update_market( + Origin::root(), + DOT, + None, + None, + Some(Ratio::zero()), + Some(Default::default()), + None, + None, + None, + None, + ), + Error::::InvalidFactor + ); + assert_noop!( + Loans::update_market( + Origin::root(), + DOT, + None, + None, + Some(Ratio::one()), + Some(Default::default()), + None, + None, + None, + None, + ), + Error::::InvalidFactor + ); + // check error code while cap is zero + assert_noop!( + Loans::update_market( + Origin::root(), + DOT, + None, + None, + None, + Some(Default::default()), + None, + Some(Rate::from_inner(Rate::DIV / 100 * 90)), + Some(Zero::zero()), + None, + ), + Error::::InvalidSupplyCap + ); + }) +} + +#[test] +fn update_rate_model_works() { + new_test_ext().execute_with(|| { + let new_rate_model = InterestRateModel::new_jump_model( + Rate::saturating_from_rational(6, 100), + Rate::saturating_from_rational(15, 100), + Rate::saturating_from_rational(35, 100), + Ratio::from_percent(80), + ); + assert_ok!(Loans::update_rate_model( + Origin::root(), + DOT, + new_rate_model, + )); + assert_eq!(Loans::market(DOT).unwrap().rate_model, new_rate_model); + + // Invalid base_rate + assert_noop!( + Loans::update_rate_model( + Origin::root(), + SDOT, + InterestRateModel::new_jump_model( + Rate::saturating_from_rational(36, 100), + Rate::saturating_from_rational(15, 100), + Rate::saturating_from_rational(35, 100), + Ratio::from_percent(80), + ) + ), + Error::::InvalidRateModelParam + ); + // Invalid jump_rate + assert_noop!( + Loans::update_rate_model( + Origin::root(), + SDOT, + InterestRateModel::new_jump_model( + Rate::saturating_from_rational(5, 100), + Rate::saturating_from_rational(36, 100), + Rate::saturating_from_rational(37, 100), + Ratio::from_percent(80), + ) + ), + Error::::InvalidRateModelParam + ); + // Invalid full_rate + assert_noop!( + Loans::update_rate_model( + Origin::root(), + SDOT, + InterestRateModel::new_jump_model( + Rate::saturating_from_rational(5, 100), + Rate::saturating_from_rational(15, 100), + Rate::saturating_from_rational(57, 100), + Ratio::from_percent(80), + ) + ), + Error::::InvalidRateModelParam + ); + // base_rate greater than jump_rate + assert_noop!( + Loans::update_rate_model( + Origin::root(), + SDOT, + InterestRateModel::new_jump_model( + Rate::saturating_from_rational(10, 100), + Rate::saturating_from_rational(9, 100), + Rate::saturating_from_rational(14, 100), + Ratio::from_percent(80), + ) + ), + Error::::InvalidRateModelParam + ); + // jump_rate greater than full_rate + assert_noop!( + Loans::update_rate_model( + Origin::root(), + SDOT, + InterestRateModel::new_jump_model( + Rate::saturating_from_rational(5, 100), + Rate::saturating_from_rational(15, 100), + Rate::saturating_from_rational(14, 100), + Ratio::from_percent(80), + ) + ), + Error::::InvalidRateModelParam + ); + }) +} diff --git a/crates/loans/src/tests/ptokens.rs b/crates/loans/src/tests/ptokens.rs new file mode 100644 index 0000000000..aa66e03e30 --- /dev/null +++ b/crates/loans/src/tests/ptokens.rs @@ -0,0 +1,185 @@ +use crate::{ + mock::{ + market_mock, new_test_ext, Loans, Origin, Test, ALICE, DAVE, HKO, KSM, PHKO, PKSM, PUSDT, + SDOT, USDT, + }, + tests::unit, + Error, +}; +use frame_support::{ + assert_err, assert_noop, assert_ok, + traits::tokens::fungibles::{Inspect, Transfer}, +}; +use sp_runtime::{FixedPointNumber, TokenError}; + +#[test] +fn trait_inspect_methods_works() { + new_test_ext().execute_with(|| { + // No Deposits can't not withdraw + assert_err!( + Loans::can_withdraw(PHKO, &DAVE, 100).into_result(), + TokenError::NoFunds + ); + assert_eq!(Loans::total_issuance(PHKO), 0); + assert_eq!(Loans::total_issuance(PKSM), 0); + + let minimum_balance = Loans::minimum_balance(PHKO); + assert_eq!(minimum_balance, 0); + + assert_eq!(Loans::balance(PHKO, &DAVE), 0); + + // DAVE Deposit 100 HKO + assert_ok!(Loans::mint(Origin::signed(DAVE), HKO, unit(100))); + assert_eq!(Loans::balance(PHKO, &DAVE), unit(100) * 50); + + assert_eq!(Loans::reducible_balance(PHKO, &DAVE, true), unit(100) * 50); + assert_ok!(Loans::collateral_asset(Origin::signed(DAVE), HKO, true)); + // Borrow 25 HKO will reduce 25 HKO liquidity for collateral_factor is 50% + assert_ok!(Loans::borrow(Origin::signed(DAVE), HKO, unit(25))); + + assert_eq!( + Loans::exchange_rate(HKO) + .saturating_mul_int(Loans::account_deposits(HKO, DAVE).voucher_balance), + unit(100) + ); + + // DAVE Deposit 100 HKO, Borrow 25 HKO + // Liquidity HKO 25 + // Formula: ptokens = liquidity / price(1) / collateral(0.5) / exchange_rate(0.02) + assert_eq!( + Loans::reducible_balance(PHKO, &DAVE, true), + unit(25) * 2 * 50 + ); + + // Multi-asset case, additional deposit USDT + // DAVE Deposit 100 HKO, 50 USDT, Borrow 25 HKO + // Liquidity HKO = 25, USDT = 25 + // ptokens = dollar(25 + 25) / 1 / 0.5 / 0.02 = dollar(50) * 100 + assert_ok!(Loans::mint(Origin::signed(DAVE), USDT, unit(50))); + assert_eq!(Loans::balance(PUSDT, &DAVE), unit(50) * 50); + assert_eq!( + Loans::reducible_balance(PUSDT, &DAVE, true), + unit(25) * 2 * 50 + ); + // enable USDT collateral + assert_ok!(Loans::collateral_asset(Origin::signed(DAVE), USDT, true)); + assert_eq!( + Loans::reducible_balance(PHKO, &DAVE, true), + unit(25 + 25) * 2 * 50 + ); + + assert_ok!(Loans::borrow(Origin::signed(DAVE), HKO, unit(50))); + assert_eq!(Loans::reducible_balance(PHKO, &DAVE, true), 0); + + assert_eq!(Loans::total_issuance(PHKO), unit(100) * 50); + assert_ok!(Loans::can_deposit(PHKO, &DAVE, 100, true).into_result()); + assert_ok!(Loans::can_withdraw(PHKO, &DAVE, 1000).into_result()); + }) +} + +#[test] +fn ptoken_unique_works() { + new_test_ext().execute_with(|| { + // ptoken_id already exists in `UnderlyingAssetId` + assert_noop!( + Loans::add_market(Origin::root(), SDOT, market_mock(PHKO)), + Error::::InvalidPtokenId + ); + + // ptoken_id cannot as the same as the asset id in `Markets` + assert_noop!( + Loans::add_market(Origin::root(), SDOT, market_mock(KSM)), + Error::::InvalidPtokenId + ); + }) +} + +#[test] +fn transfer_ptoken_works() { + new_test_ext().execute_with(|| { + // DAVE Deposit 100 HKO + assert_ok!(Loans::mint(Origin::signed(DAVE), HKO, unit(100))); + + // DAVE HKO collateral: deposit = 100 + // HKO: cash - deposit = 1000 - 100 = 900 + assert_eq!( + Loans::exchange_rate(HKO) + .saturating_mul_int(Loans::account_deposits(HKO, DAVE).voucher_balance), + unit(100) + ); + + // ALICE HKO collateral: deposit = 0 + assert_eq!( + Loans::exchange_rate(HKO) + .saturating_mul_int(Loans::account_deposits(HKO, ALICE).voucher_balance), + unit(0) + ); + + // Transfer ptokens from DAVE to ALICE + Loans::transfer(PHKO, &DAVE, &ALICE, unit(50) * 50, true).unwrap(); + // Loans::transfer_ptokens(Origin::signed(DAVE), ALICE, HKO, dollar(50) * 50).unwrap(); + + // DAVE HKO collateral: deposit = 50 + assert_eq!( + Loans::exchange_rate(HKO) + .saturating_mul_int(Loans::account_deposits(HKO, DAVE).voucher_balance), + unit(50) + ); + // DAVE Redeem 51 HKO should cause InsufficientDeposit + assert_noop!( + Loans::redeem_allowed(HKO, &DAVE, unit(51) * 50), + Error::::InsufficientDeposit + ); + + // ALICE HKO collateral: deposit = 50 + assert_eq!( + Loans::exchange_rate(HKO) + .saturating_mul_int(Loans::account_deposits(HKO, ALICE).voucher_balance), + unit(50) + ); + // ALICE Redeem 50 HKO should be succeeded + assert_ok!(Loans::redeem_allowed(HKO, &ALICE, unit(50) * 50)); + }) +} + +#[test] +fn transfer_ptokens_under_collateral_works() { + new_test_ext().execute_with(|| { + // DAVE Deposit 100 HKO + assert_ok!(Loans::mint(Origin::signed(DAVE), HKO, unit(100))); + assert_ok!(Loans::collateral_asset(Origin::signed(DAVE), HKO, true)); + + // Borrow 50 HKO will reduce 50 HKO liquidity for collateral_factor is 50% + assert_ok!(Loans::borrow(Origin::signed(DAVE), HKO, unit(50))); + // Repay 40 HKO + assert_ok!(Loans::repay_borrow(Origin::signed(DAVE), HKO, unit(40))); + + // Transfer 20 ptokens from DAVE to ALICE + Loans::transfer(PHKO, &DAVE, &ALICE, unit(20) * 50, true).unwrap(); + + // DAVE Deposit HKO = 100 - 20 = 80 + // DAVE Borrow HKO = 0 + 50 - 40 = 10 + // DAVE liquidity HKO = 80 * 0.5 - 10 = 30 + assert_eq!( + Loans::exchange_rate(HKO) + .saturating_mul_int(Loans::account_deposits(HKO, DAVE).voucher_balance), + unit(80) + ); + // DAVE Borrow 31 HKO should cause InsufficientLiquidity + assert_noop!( + Loans::borrow(Origin::signed(DAVE), HKO, unit(31)), + Error::::InsufficientLiquidity + ); + assert_ok!(Loans::borrow(Origin::signed(DAVE), HKO, unit(30))); + + // Assert ALICE Supply HKO 20 + assert_eq!( + Loans::exchange_rate(HKO) + .saturating_mul_int(Loans::account_deposits(HKO, ALICE).voucher_balance), + unit(20) + ); + // ALICE Redeem 20 HKO should be succeeded + // Also means that transfer ptoken succeed + assert_ok!(Loans::redeem_allowed(HKO, &ALICE, unit(20) * 50,)); + }) +} diff --git a/crates/loans/src/types.rs b/crates/loans/src/types.rs new file mode 100644 index 0000000000..a820e9ee3c --- /dev/null +++ b/crates/loans/src/types.rs @@ -0,0 +1,78 @@ +use crate::InterestRateModel; +use frame_support::pallet_prelude::*; +use primitives::{CurrencyId, Rate, Ratio}; +use scale_info::TypeInfo; + +/// Container for borrow balance information +#[derive(Encode, Decode, Eq, PartialEq, Copy, Clone, RuntimeDebug, Default, TypeInfo)] +pub struct BorrowSnapshot { + /// Principal Total balance (with accrued interest), after applying the most recent balance-changing action + pub principal: Balance, + /// InterestIndex Global borrowIndex as of the most recent balance-changing action + pub borrow_index: Rate, +} + +/// Container for earned amount information +#[derive(Encode, Decode, Eq, PartialEq, Copy, Clone, RuntimeDebug, Default, TypeInfo)] +pub struct EarnedSnapshot { + /// Total deposit interest, after applying the most recent balance-changing action + pub total_earned_prior: Balance, + /// Exchange rate, after applying the most recent balance-changing action + pub exchange_rate_prior: Rate, +} + +/// Deposit information +#[derive(Encode, Decode, Eq, PartialEq, Copy, Clone, RuntimeDebug, Default, TypeInfo)] +pub struct Deposits { + /// The voucher amount of the deposit + pub voucher_balance: Balance, + /// Can this deposit be used as collateral + pub is_collateral: bool, +} + +/// The current state of a market. For more information, see [Market]. +#[cfg_attr(feature = "std", derive(serde::Deserialize, serde::Serialize))] +#[derive(Clone, Copy, PartialEq, Eq, codec::Decode, codec::Encode, RuntimeDebug, TypeInfo)] +pub enum MarketState { + Active, + Pending, + Supervision, +} + +/// Market. +/// +/// A large pool of liquidity where accounts can lend and borrow. +#[cfg_attr(feature = "std", derive(serde::Deserialize, serde::Serialize))] +#[derive(Clone, PartialEq, Eq, codec::Decode, codec::Encode, RuntimeDebug, TypeInfo)] +pub struct Market { + /// The collateral utilization ratio + pub collateral_factor: Ratio, + /// A liquidation_threshold ratio more than collateral_factor to avoid liquidate_borrow too casual + pub liquidation_threshold: Ratio, + /// Fraction of interest currently set aside for reserves + pub reserve_factor: Ratio, + /// The percent, ranging from 0% to 100%, of a liquidatable account's + /// borrow that can be repaid in a single liquidate transaction. + pub close_factor: Ratio, + /// Liquidation incentive ratio + pub liquidate_incentive: Rate, + /// Liquidation incentive reserved ratio + pub liquidate_incentive_reserved_factor: Ratio, + /// Current interest rate model being used + pub rate_model: InterestRateModel, + /// Current market state + pub state: MarketState, + /// Upper bound of supplying + pub supply_cap: Balance, + /// Upper bound of borrowing + pub borrow_cap: Balance, + /// Ptoken asset id + pub ptoken_id: CurrencyId, +} + +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, Default)] +pub struct RewardMarketState { + pub index: Balance, + /// total amount of staking asset user deposited + pub block: BlockNumber, +} diff --git a/crates/loans/src/weights.rs b/crates/loans/src/weights.rs new file mode 100644 index 0000000000..30831de0dd --- /dev/null +++ b/crates/loans/src/weights.rs @@ -0,0 +1,654 @@ +// This file is part of Parallel Finance. + +// Copyright (C) 2022 Parallel Finance Developer. +// SPDX-License-Identifier: Apache-2.0 + +// 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. + +//! Autogenerated weights for pallet_loans +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-05-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kerria-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/parallel +// benchmark +// pallet +// --chain=kerria-dev +// --execution=wasm +// --wasm-execution=compiled +// --pallet=pallet-loans +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs +// --output=./pallets/loans/src/weights.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_loans. +pub trait WeightInfo { + fn add_market() -> Weight; + fn activate_market() -> Weight; + fn update_rate_model() -> Weight; + fn update_market() -> Weight; + fn force_update_market() -> Weight; + fn add_reward() -> Weight; + fn withdraw_missing_reward() -> Weight; + fn update_market_reward_speed() -> Weight; + fn claim_reward() -> Weight; + fn claim_reward_for_market() -> Weight; + fn mint() -> Weight; + fn borrow() -> Weight; + fn redeem() -> Weight; + fn redeem_all() -> Weight; + fn repay_borrow() -> Weight; + fn repay_borrow_all() -> Weight; + fn collateral_asset() -> Weight; + fn liquidate_borrow() -> Weight; + fn add_reserves() -> Weight; + fn reduce_reserves() -> Weight; + fn update_liquidation_free_collateral() -> Weight; +} + +/// Weights for pallet_loans using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:1) + // Storage: Loans UnderlyingAssetId (r:1 w:1) + // Storage: Loans ExchangeRate (r:0 w:1) + // Storage: Loans BorrowIndex (r:0 w:1) + fn add_market() -> Weight { + (61_518_000 as Weight) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(5 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:1 w:1) + fn activate_market() -> Weight { + (43_556_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:1 w:1) + fn update_rate_model() -> Weight { + (45_600_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:1 w:1) + fn update_market() -> Weight { + (45_777_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans UnderlyingAssetId (r:1 w:1) + // Storage: Loans Markets (r:1 w:1) + fn force_update_market() -> Weight { + (56_536_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn add_reward() -> Weight { + (98_928_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn withdraw_missing_reward() -> Weight { + (81_317_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Loans RewardSupplySpeed (r:1 w:1) + // Storage: Loans RewardBorrowSpeed (r:1 w:1) + // Storage: Loans RewardSupplyState (r:1 w:1) + // Storage: Loans RewardBorrowState (r:1 w:1) + fn update_market_reward_speed() -> Weight { + (86_330_000 as Weight) + .saturating_add(T::DbWeight::get().reads(7 as Weight)) + .saturating_add(T::DbWeight::get().writes(5 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Loans RewardSupplyState (r:1 w:1) + // Storage: Loans RewardSupplySpeed (r:1 w:0) + // Storage: Loans TotalSupply (r:1 w:0) + // Storage: Loans RewardSupplierIndex (r:1 w:1) + // Storage: Loans RewardAccured (r:1 w:1) + // Storage: Loans AccountDeposits (r:1 w:0) + // Storage: Loans RewardBorrowState (r:1 w:1) + // Storage: Loans RewardBorrowSpeed (r:1 w:0) + // Storage: Loans TotalBorrows (r:1 w:0) + // Storage: Loans BorrowIndex (r:1 w:0) + // Storage: Loans RewardBorrowerIndex (r:1 w:1) + // Storage: Loans AccountBorrows (r:1 w:0) + // Storage: System Account (r:1 w:1) + fn claim_reward() -> Weight { + (234_251_000 as Weight) + .saturating_add(T::DbWeight::get().reads(16 as Weight)) + .saturating_add(T::DbWeight::get().writes(7 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans RewardSupplyState (r:1 w:1) + // Storage: Loans RewardSupplySpeed (r:1 w:0) + // Storage: Loans TotalSupply (r:1 w:0) + // Storage: Loans RewardSupplierIndex (r:1 w:1) + // Storage: Loans RewardAccured (r:1 w:1) + // Storage: Loans AccountDeposits (r:1 w:0) + // Storage: Loans RewardBorrowState (r:1 w:1) + // Storage: Loans RewardBorrowSpeed (r:1 w:0) + // Storage: Loans TotalBorrows (r:1 w:0) + // Storage: Loans BorrowIndex (r:1 w:0) + // Storage: Loans RewardBorrowerIndex (r:1 w:1) + // Storage: Loans AccountBorrows (r:1 w:0) + // Storage: System Account (r:1 w:1) + fn claim_reward_for_market() -> Weight { + (214_273_000 as Weight) + .saturating_add(T::DbWeight::get().reads(14 as Weight)) + .saturating_add(T::DbWeight::get().writes(7 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Assets Account (r:2 w:2) + // Storage: Timestamp Now (r:1 w:0) + // Storage: Loans LastAccruedInterestTime (r:1 w:1) + // Storage: Loans RewardSupplyState (r:1 w:1) + // Storage: Loans RewardSupplySpeed (r:1 w:0) + // Storage: Loans RewardSupplierIndex (r:1 w:1) + // Storage: Loans RewardAccured (r:1 w:1) + // Storage: Loans AccountDeposits (r:1 w:1) + // Storage: Loans TotalSupply (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Loans TotalBorrows (r:1 w:0) + // Storage: Loans TotalReserves (r:1 w:0) + // Storage: Loans AccountEarned (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn mint() -> Weight { + (250_616_000 as Weight) + .saturating_add(T::DbWeight::get().reads(18 as Weight)) + .saturating_add(T::DbWeight::get().writes(12 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Timestamp Now (r:1 w:0) + // Storage: Loans LastAccruedInterestTime (r:1 w:1) + // Storage: Loans TotalBorrows (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: Loans TotalReserves (r:1 w:0) + // Storage: Prices EmergencyPrice (r:2 w:0) + // Storage: Assets Metadata (r:2 w:0) + // Storage: Loans AccountBorrows (r:2 w:1) + // Storage: Loans AccountDeposits (r:1 w:0) + // Storage: Loans TotalSupply (r:1 w:0) + // Storage: Loans LiquidationFreeCollaterals (r:1 w:0) + // Storage: Loans RewardBorrowState (r:1 w:1) + // Storage: Loans RewardBorrowSpeed (r:1 w:0) + // Storage: Loans RewardBorrowerIndex (r:1 w:1) + // Storage: Loans RewardAccured (r:1 w:1) + // Storage: Loans BorrowIndex (r:1 w:0) + fn borrow() -> Weight { + (356_136_000 as Weight) + .saturating_add(T::DbWeight::get().reads(24 as Weight)) + .saturating_add(T::DbWeight::get().writes(10 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Timestamp Now (r:1 w:0) + // Storage: Loans LastAccruedInterestTime (r:1 w:1) + // Storage: Loans TotalSupply (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: Loans TotalBorrows (r:1 w:0) + // Storage: Loans TotalReserves (r:1 w:0) + // Storage: Loans AccountDeposits (r:1 w:1) + // Storage: Loans AccountEarned (r:1 w:1) + // Storage: Loans RewardSupplyState (r:1 w:1) + // Storage: Loans RewardSupplySpeed (r:1 w:0) + // Storage: Loans RewardSupplierIndex (r:1 w:1) + // Storage: Loans RewardAccured (r:1 w:1) + fn redeem() -> Weight { + (259_224_000 as Weight) + .saturating_add(T::DbWeight::get().reads(17 as Weight)) + .saturating_add(T::DbWeight::get().writes(11 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Timestamp Now (r:1 w:0) + // Storage: Loans LastAccruedInterestTime (r:1 w:1) + // Storage: Loans TotalSupply (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: Loans TotalBorrows (r:1 w:0) + // Storage: Loans TotalReserves (r:1 w:0) + // Storage: Loans AccountDeposits (r:1 w:1) + // Storage: Loans AccountEarned (r:1 w:1) + // Storage: Loans RewardSupplyState (r:1 w:1) + // Storage: Loans RewardSupplySpeed (r:1 w:0) + // Storage: Loans RewardSupplierIndex (r:1 w:1) + // Storage: Loans RewardAccured (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn redeem_all() -> Weight { + (277_962_000 as Weight) + .saturating_add(T::DbWeight::get().reads(18 as Weight)) + .saturating_add(T::DbWeight::get().writes(12 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Timestamp Now (r:1 w:0) + // Storage: Loans LastAccruedInterestTime (r:1 w:1) + // Storage: Loans AccountBorrows (r:1 w:1) + // Storage: Loans BorrowIndex (r:1 w:0) + // Storage: Loans RewardBorrowState (r:1 w:1) + // Storage: Loans RewardBorrowSpeed (r:1 w:0) + // Storage: Loans RewardBorrowerIndex (r:1 w:1) + // Storage: Loans RewardAccured (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: Loans TotalBorrows (r:1 w:1) + fn repay_borrow() -> Weight { + (226_122_000 as Weight) + .saturating_add(T::DbWeight::get().reads(15 as Weight)) + .saturating_add(T::DbWeight::get().writes(10 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Timestamp Now (r:1 w:0) + // Storage: Loans LastAccruedInterestTime (r:1 w:1) + // Storage: Loans AccountBorrows (r:1 w:1) + // Storage: Loans BorrowIndex (r:1 w:0) + // Storage: Loans RewardBorrowState (r:1 w:1) + // Storage: Loans RewardBorrowSpeed (r:1 w:0) + // Storage: Loans RewardBorrowerIndex (r:1 w:1) + // Storage: Loans RewardAccured (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: Loans TotalBorrows (r:1 w:1) + fn repay_borrow_all() -> Weight { + (225_556_000 as Weight) + .saturating_add(T::DbWeight::get().reads(15 as Weight)) + .saturating_add(T::DbWeight::get().writes(10 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Loans AccountDeposits (r:1 w:1) + fn collateral_asset() -> Weight { + (73_911_000 as Weight) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans LiquidationFreeCollaterals (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) + // Storage: Loans LastAccruedInterestTime (r:2 w:2) + // Storage: Loans Markets (r:3 w:0) + // Storage: Loans AccountBorrows (r:3 w:1) + // Storage: Loans BorrowIndex (r:1 w:0) + // Storage: Prices EmergencyPrice (r:2 w:0) + // Storage: Assets Metadata (r:2 w:0) + // Storage: Loans AccountDeposits (r:4 w:3) + // Storage: Loans TotalSupply (r:1 w:0) + // Storage: Assets Asset (r:2 w:1) + // Storage: Assets Account (r:3 w:2) + // Storage: Loans TotalBorrows (r:2 w:1) + // Storage: Loans TotalReserves (r:1 w:0) + // Storage: Loans RewardBorrowState (r:1 w:1) + // Storage: Loans RewardBorrowSpeed (r:1 w:0) + // Storage: Loans RewardBorrowerIndex (r:1 w:1) + // Storage: Loans RewardAccured (r:3 w:3) + // Storage: Loans RewardSupplyState (r:1 w:1) + // Storage: Loans RewardSupplySpeed (r:1 w:0) + // Storage: Loans RewardSupplierIndex (r:3 w:3) + fn liquidate_borrow() -> Weight { + (637_956_000 as Weight) + .saturating_add(T::DbWeight::get().reads(40 as Weight)) + .saturating_add(T::DbWeight::get().writes(20 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: System Account (r:1 w:1) + // Storage: Loans TotalReserves (r:1 w:1) + fn add_reserves() -> Weight { + (146_456_000 as Weight) + .saturating_add(T::DbWeight::get().reads(8 as Weight)) + .saturating_add(T::DbWeight::get().writes(6 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Loans TotalReserves (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + fn reduce_reserves() -> Weight { + (131_943_000 as Weight) + .saturating_add(T::DbWeight::get().reads(7 as Weight)) + .saturating_add(T::DbWeight::get().writes(5 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans LiquidationFreeCollaterals (r:1 w:1) + fn update_liquidation_free_collateral() -> Weight { + (37_654_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:1) + // Storage: Loans UnderlyingAssetId (r:1 w:1) + // Storage: Loans ExchangeRate (r:0 w:1) + // Storage: Loans BorrowIndex (r:0 w:1) + fn add_market() -> Weight { + (61_518_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:1 w:1) + fn activate_market() -> Weight { + (43_556_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:1 w:1) + fn update_rate_model() -> Weight { + (45_600_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:1 w:1) + fn update_market() -> Weight { + (45_777_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans UnderlyingAssetId (r:1 w:1) + // Storage: Loans Markets (r:1 w:1) + fn force_update_market() -> Weight { + (56_536_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn add_reward() -> Weight { + (98_928_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn withdraw_missing_reward() -> Weight { + (81_317_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Loans RewardSupplySpeed (r:1 w:1) + // Storage: Loans RewardBorrowSpeed (r:1 w:1) + // Storage: Loans RewardSupplyState (r:1 w:1) + // Storage: Loans RewardBorrowState (r:1 w:1) + fn update_market_reward_speed() -> Weight { + (86_330_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(7 as Weight)) + .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Loans RewardSupplyState (r:1 w:1) + // Storage: Loans RewardSupplySpeed (r:1 w:0) + // Storage: Loans TotalSupply (r:1 w:0) + // Storage: Loans RewardSupplierIndex (r:1 w:1) + // Storage: Loans RewardAccured (r:1 w:1) + // Storage: Loans AccountDeposits (r:1 w:0) + // Storage: Loans RewardBorrowState (r:1 w:1) + // Storage: Loans RewardBorrowSpeed (r:1 w:0) + // Storage: Loans TotalBorrows (r:1 w:0) + // Storage: Loans BorrowIndex (r:1 w:0) + // Storage: Loans RewardBorrowerIndex (r:1 w:1) + // Storage: Loans AccountBorrows (r:1 w:0) + // Storage: System Account (r:1 w:1) + fn claim_reward() -> Weight { + (234_251_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(16 as Weight)) + .saturating_add(RocksDbWeight::get().writes(7 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans RewardSupplyState (r:1 w:1) + // Storage: Loans RewardSupplySpeed (r:1 w:0) + // Storage: Loans TotalSupply (r:1 w:0) + // Storage: Loans RewardSupplierIndex (r:1 w:1) + // Storage: Loans RewardAccured (r:1 w:1) + // Storage: Loans AccountDeposits (r:1 w:0) + // Storage: Loans RewardBorrowState (r:1 w:1) + // Storage: Loans RewardBorrowSpeed (r:1 w:0) + // Storage: Loans TotalBorrows (r:1 w:0) + // Storage: Loans BorrowIndex (r:1 w:0) + // Storage: Loans RewardBorrowerIndex (r:1 w:1) + // Storage: Loans AccountBorrows (r:1 w:0) + // Storage: System Account (r:1 w:1) + fn claim_reward_for_market() -> Weight { + (214_273_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(14 as Weight)) + .saturating_add(RocksDbWeight::get().writes(7 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Assets Account (r:2 w:2) + // Storage: Timestamp Now (r:1 w:0) + // Storage: Loans LastAccruedInterestTime (r:1 w:1) + // Storage: Loans RewardSupplyState (r:1 w:1) + // Storage: Loans RewardSupplySpeed (r:1 w:0) + // Storage: Loans RewardSupplierIndex (r:1 w:1) + // Storage: Loans RewardAccured (r:1 w:1) + // Storage: Loans AccountDeposits (r:1 w:1) + // Storage: Loans TotalSupply (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Loans TotalBorrows (r:1 w:0) + // Storage: Loans TotalReserves (r:1 w:0) + // Storage: Loans AccountEarned (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn mint() -> Weight { + (250_616_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(18 as Weight)) + .saturating_add(RocksDbWeight::get().writes(12 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Timestamp Now (r:1 w:0) + // Storage: Loans LastAccruedInterestTime (r:1 w:1) + // Storage: Loans TotalBorrows (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: Loans TotalReserves (r:1 w:0) + // Storage: Prices EmergencyPrice (r:2 w:0) + // Storage: Assets Metadata (r:2 w:0) + // Storage: Loans AccountBorrows (r:2 w:1) + // Storage: Loans AccountDeposits (r:1 w:0) + // Storage: Loans TotalSupply (r:1 w:0) + // Storage: Loans LiquidationFreeCollaterals (r:1 w:0) + // Storage: Loans RewardBorrowState (r:1 w:1) + // Storage: Loans RewardBorrowSpeed (r:1 w:0) + // Storage: Loans RewardBorrowerIndex (r:1 w:1) + // Storage: Loans RewardAccured (r:1 w:1) + // Storage: Loans BorrowIndex (r:1 w:0) + fn borrow() -> Weight { + (356_136_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(24 as Weight)) + .saturating_add(RocksDbWeight::get().writes(10 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Timestamp Now (r:1 w:0) + // Storage: Loans LastAccruedInterestTime (r:1 w:1) + // Storage: Loans TotalSupply (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: Loans TotalBorrows (r:1 w:0) + // Storage: Loans TotalReserves (r:1 w:0) + // Storage: Loans AccountDeposits (r:1 w:1) + // Storage: Loans AccountEarned (r:1 w:1) + // Storage: Loans RewardSupplyState (r:1 w:1) + // Storage: Loans RewardSupplySpeed (r:1 w:0) + // Storage: Loans RewardSupplierIndex (r:1 w:1) + // Storage: Loans RewardAccured (r:1 w:1) + fn redeem() -> Weight { + (259_224_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(17 as Weight)) + .saturating_add(RocksDbWeight::get().writes(11 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Timestamp Now (r:1 w:0) + // Storage: Loans LastAccruedInterestTime (r:1 w:1) + // Storage: Loans TotalSupply (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: Loans TotalBorrows (r:1 w:0) + // Storage: Loans TotalReserves (r:1 w:0) + // Storage: Loans AccountDeposits (r:1 w:1) + // Storage: Loans AccountEarned (r:1 w:1) + // Storage: Loans RewardSupplyState (r:1 w:1) + // Storage: Loans RewardSupplySpeed (r:1 w:0) + // Storage: Loans RewardSupplierIndex (r:1 w:1) + // Storage: Loans RewardAccured (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn redeem_all() -> Weight { + (277_962_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(18 as Weight)) + .saturating_add(RocksDbWeight::get().writes(12 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Timestamp Now (r:1 w:0) + // Storage: Loans LastAccruedInterestTime (r:1 w:1) + // Storage: Loans AccountBorrows (r:1 w:1) + // Storage: Loans BorrowIndex (r:1 w:0) + // Storage: Loans RewardBorrowState (r:1 w:1) + // Storage: Loans RewardBorrowSpeed (r:1 w:0) + // Storage: Loans RewardBorrowerIndex (r:1 w:1) + // Storage: Loans RewardAccured (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: Loans TotalBorrows (r:1 w:1) + fn repay_borrow() -> Weight { + (226_122_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(15 as Weight)) + .saturating_add(RocksDbWeight::get().writes(10 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Timestamp Now (r:1 w:0) + // Storage: Loans LastAccruedInterestTime (r:1 w:1) + // Storage: Loans AccountBorrows (r:1 w:1) + // Storage: Loans BorrowIndex (r:1 w:0) + // Storage: Loans RewardBorrowState (r:1 w:1) + // Storage: Loans RewardBorrowSpeed (r:1 w:0) + // Storage: Loans RewardBorrowerIndex (r:1 w:1) + // Storage: Loans RewardAccured (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: Loans TotalBorrows (r:1 w:1) + fn repay_borrow_all() -> Weight { + (225_556_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(15 as Weight)) + .saturating_add(RocksDbWeight::get().writes(10 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Loans AccountDeposits (r:1 w:1) + fn collateral_asset() -> Weight { + (73_911_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans LiquidationFreeCollaterals (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) + // Storage: Loans LastAccruedInterestTime (r:2 w:2) + // Storage: Loans Markets (r:3 w:0) + // Storage: Loans AccountBorrows (r:3 w:1) + // Storage: Loans BorrowIndex (r:1 w:0) + // Storage: Prices EmergencyPrice (r:2 w:0) + // Storage: Assets Metadata (r:2 w:0) + // Storage: Loans AccountDeposits (r:4 w:3) + // Storage: Loans TotalSupply (r:1 w:0) + // Storage: Assets Asset (r:2 w:1) + // Storage: Assets Account (r:3 w:2) + // Storage: Loans TotalBorrows (r:2 w:1) + // Storage: Loans TotalReserves (r:1 w:0) + // Storage: Loans RewardBorrowState (r:1 w:1) + // Storage: Loans RewardBorrowSpeed (r:1 w:0) + // Storage: Loans RewardBorrowerIndex (r:1 w:1) + // Storage: Loans RewardAccured (r:3 w:3) + // Storage: Loans RewardSupplyState (r:1 w:1) + // Storage: Loans RewardSupplySpeed (r:1 w:0) + // Storage: Loans RewardSupplierIndex (r:3 w:3) + fn liquidate_borrow() -> Weight { + (637_956_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(40 as Weight)) + .saturating_add(RocksDbWeight::get().writes(20 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: System Account (r:1 w:1) + // Storage: Loans TotalReserves (r:1 w:1) + fn add_reserves() -> Weight { + (146_456_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(8 as Weight)) + .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans Markets (r:2 w:0) + // Storage: Loans TotalReserves (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + fn reduce_reserves() -> Weight { + (131_943_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(7 as Weight)) + .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Loans LiquidationFreeCollaterals (r:1 w:1) + fn update_liquidation_free_collateral() -> Weight { + (37_654_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } +} diff --git a/crates/traits/Cargo.toml b/crates/traits/Cargo.toml new file mode 100644 index 0000000000..886a1837a4 --- /dev/null +++ b/crates/traits/Cargo.toml @@ -0,0 +1,53 @@ +[package] +authors = ['Parallel Team'] +edition = '2021' +name = 'pallet-traits' +version = '1.9.3' + +[package.metadata.docs.rs] +targets = ['x86_64-unknown-linux-gnu'] + +[dependencies] +serde = { version = '1.0.136', features = ['derive'], optional = true } +codec = { package = 'parity-scale-codec', version = '3.1.5', features = ['max-encoded-len'], default-features = false } +frame-support = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +frame-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +log = { version = "0.4", default-features = false } +num-bigint = { default-features = false, version = '0.4' } +num-traits = { default-features = false, version = '0.2' } +primitives = { package = 'parallel-primitives', path = '../../primitives', default-features = false } +scale-info = { version = '2.1', default-features = false, features = ['derive'] } +sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +sp-io = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +sp-std = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +xcm = { git = 'https://github.com/paritytech/polkadot.git', branch = 'release-v0.9.28', default-features = false } +xcm-builder = { git = 'https://github.com/paritytech/polkadot.git', branch = 'release-v0.9.28', default-features = false } +xcm-executor = { git = 'https://github.com/paritytech/polkadot.git', branch = 'release-v0.9.28', default-features = false } + +[dev-dependencies] +sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28' } + +[features] +default = ['std'] +std = [ + 'serde', + 'codec/std', + 'frame-support/std', + 'frame-system/std', + 'sp-runtime/std', + 'scale-info/std', + 'sp-std/std', + 'primitives/std', + 'num-bigint/std', + 'num-traits/std', + 'sp-core/std', + 'xcm-executor/std', + 'xcm/std', + 'xcm-builder/std', +] + +try-runtime = ['frame-support/try-runtime'] + +[lib] +doctest = false diff --git a/crates/traits/src/lib.rs b/crates/traits/src/lib.rs new file mode 100644 index 0000000000..7dd4e05793 --- /dev/null +++ b/crates/traits/src/lib.rs @@ -0,0 +1,252 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{dispatch::DispatchError, traits::tokens::Balance as BalanceT}; +use num_bigint::{BigUint, ToBigUint}; +use scale_info::TypeInfo; +use sp_runtime::{traits::Zero, RuntimeDebug}; +use sp_std::prelude::*; + +use primitives::{ + CurrencyId, DerivativeIndex, PersistedValidationData, PriceDetail, Rate, Timestamp, +}; + +pub mod loans; +pub mod ump; +pub mod xcm; +pub use loans::*; + +pub trait EmergencyCallFilter { + fn contains(call: &Call) -> bool; +} + +pub trait PriceFeeder { + fn get_price(asset_id: &CurrencyId) -> Option; +} + +pub trait DecimalProvider { + fn get_decimal(asset_id: &CurrencyId) -> Option; +} + +pub trait EmergencyPriceFeeder { + fn set_emergency_price(asset_id: CurrencyId, price: Price); + fn reset_emergency_price(asset_id: CurrencyId); +} + +pub trait ExchangeRateProvider { + fn get_exchange_rate(asset_id: &CurrencyId) -> Option; +} + +pub trait LiquidStakingConvert { + fn staking_to_liquid(amount: Balance) -> Option; + fn liquid_to_staking(liquid_amount: Balance) -> Option; +} + +pub trait LiquidStakingCurrenciesProvider { + fn get_staking_currency() -> Option; + fn get_liquid_currency() -> Option; +} + +pub trait VaultTokenExchangeRateProvider { + fn get_exchange_rate(asset_id: &CurrencyId, init_rate: Rate) -> Option; +} + +pub trait LPVaultTokenExchangeRateProvider { + fn get_exchange_rate(lp_asset_id: &CurrencyId) -> Option; +} + +pub trait VaultTokenCurrenciesFilter { + fn contains(asset_id: &CurrencyId) -> bool; +} + +pub trait LPVaultTokenCurrenciesFilter { + fn contains(lp_asset_id: &CurrencyId) -> bool; +} + +#[derive( + Encode, + Decode, + Eq, + PartialEq, + Copy, + Clone, + RuntimeDebug, + PartialOrd, + Ord, + TypeInfo, + MaxEncodedLen, +)] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +pub struct Pool { + pub base_amount: Balance, + pub quote_amount: Balance, + pub base_amount_last: Balance, + pub quote_amount_last: Balance, + pub lp_token_id: CurrencyId, + pub block_timestamp_last: BlockNumber, + pub price_0_cumulative_last: Balance, + pub price_1_cumulative_last: Balance, +} + +impl Pool { + pub fn new(lp_token_id: CurrencyId) -> Self { + Self { + base_amount: Zero::zero(), + quote_amount: Zero::zero(), + base_amount_last: Zero::zero(), + quote_amount_last: Zero::zero(), + lp_token_id, + block_timestamp_last: Zero::zero(), + price_0_cumulative_last: Zero::zero(), + price_1_cumulative_last: Zero::zero(), + } + } + + pub fn is_empty(&self) -> bool { + self.base_amount.is_zero() && self.quote_amount.is_zero() + } +} + +/// Exported traits from our AMM pallet. These functions are to be used +/// by the router to enable multi route token swaps +pub trait AMM { + /// Based on the path specified and the available pool balances + /// this will return the amounts outs when trading the specified + /// amount in + fn get_amounts_out( + amount_in: Balance, + path: Vec, + ) -> Result, DispatchError>; + + /// Based on the path specified and the available pool balances + /// this will return the amounts in needed to produce the specified + /// amount out + fn get_amounts_in( + amount_out: Balance, + path: Vec, + ) -> Result, DispatchError>; + + /// Handles a "swap" on the AMM side for "who". + /// This will move the `amount_in` funds to the AMM PalletId, + /// trade `pair.0` to `pair.1` and return a result with the amount + /// of currency that was sent back to the user. + fn swap( + who: &AccountId, + pair: (CurrencyId, CurrencyId), + amount_in: Balance, + ) -> Result<(), DispatchError>; + + /// Iterate keys of asset pair in AMM Pools + fn get_pools() -> Result, DispatchError>; + + /// Returns pool by lp_asset + fn get_pool_by_lp_asset( + asset_id: CurrencyId, + ) -> Option<( + CurrencyId, + CurrencyId, + Pool, + )>; + + /// Returns pool by asset pair + fn get_pool_by_asset_pair( + pair: (CurrencyId, CurrencyId), + ) -> Option>; +} + +/// Exported traits from StableSwap pallet. These functions are to be used +/// by the router. +pub trait StableSwap { + /// Based on the path specified and the available pool balances + /// this will return the amounts outs when trading the specified + /// amount in + fn get_amounts_out( + amount_in: Balance, + path: Vec, + ) -> Result, DispatchError>; + + /// Based on the path specified and the available pool balances + /// this will return the amounts in needed to produce the specified + /// amount out + fn get_amounts_in( + amount_out: Balance, + path: Vec, + ) -> Result, DispatchError>; + + /// Handles a "swap" on the AMM side for "who". + /// This will move the `amount_in` funds to the AMM PalletId, + /// trade `pair.0` to `pair.1` and return a result with the amount + /// of currency that was sent back to the user. + fn swap( + who: &AccountId, + pair: (CurrencyId, CurrencyId), + amount_in: Balance, + ) -> Result<(), DispatchError>; + + fn get_pools() -> Result, DispatchError>; + + fn get_reserves( + asset_in: CurrencyId, + asset_out: CurrencyId, + ) -> Result<(Balance, Balance), DispatchError>; +} + +pub trait ConvertToBigUint { + fn get_big_uint(&self) -> BigUint; +} + +impl ConvertToBigUint for u128 { + fn get_big_uint(&self) -> BigUint { + self.to_biguint().unwrap() + } +} + +/// Get relaychain validation data +pub trait ValidationDataProvider { + fn validation_data() -> Option; +} + +/// Distribute liquidstaking asset to multi-accounts +pub trait DistributionStrategy { + fn get_bond_distributions( + bonded_amounts: Vec<(DerivativeIndex, Balance, Balance)>, + input: Balance, + cap: Balance, + min_nominator_bond: Balance, + ) -> Vec<(DerivativeIndex, Balance)>; + fn get_unbond_distributions( + active_bonded_amounts: Vec<(DerivativeIndex, Balance)>, + input: Balance, + min_nominator_bond: Balance, + ) -> Vec<(DerivativeIndex, Balance)>; + fn get_rebond_distributions( + unbonding_amounts: Vec<(DerivativeIndex, Balance)>, + input: Balance, + ) -> Vec<(DerivativeIndex, Balance)>; +} + +pub trait Streaming { + fn create( + sender: AccountId, + recipient: AccountId, + deposit: Balance, + asset_id: CurrencyId, + start_time: Timestamp, + end_time: Timestamp, + cancellable: bool, + ) -> Result<(), DispatchError>; +} + +impl Streaming for () { + fn create( + _sender: AccountId, + _recipient: AccountId, + _deposit: Balance, + _asset_id: CurrencyId, + _start_time: Timestamp, + _end_time: Timestamp, + _cancellable: bool, + ) -> Result<(), DispatchError> { + Ok(()) + } +} diff --git a/crates/traits/src/loans.rs b/crates/traits/src/loans.rs new file mode 100644 index 0000000000..5002009740 --- /dev/null +++ b/crates/traits/src/loans.rs @@ -0,0 +1,89 @@ +// 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. + +use codec::{Decode, Encode}; +use frame_support::dispatch::DispatchError; +use primitives::{Rate, Ratio}; +use scale_info::TypeInfo; +use sp_runtime::{FixedU128, RuntimeDebug}; +use sp_std::prelude::*; + +pub trait Loans { + fn do_mint( + supplier: &AccountId, + asset_id: CurrencyId, + amount: Balance, + ) -> Result<(), DispatchError>; + fn do_borrow( + borrower: &AccountId, + asset_id: CurrencyId, + amount: Balance, + ) -> Result<(), DispatchError>; + fn do_collateral_asset( + supplier: &AccountId, + asset_id: CurrencyId, + enable: bool, + ) -> Result<(), DispatchError>; + fn do_repay_borrow( + borrower: &AccountId, + asset_id: CurrencyId, + amount: Balance, + ) -> Result<(), DispatchError>; + fn do_redeem( + supplier: &AccountId, + asset_id: CurrencyId, + amount: Balance, + ) -> Result<(), DispatchError>; +} + +pub trait LoansPositionDataProvider { + fn get_current_borrow_balance( + borrower: &AccountId, + asset_id: CurrencyId, + ) -> Result; + + fn get_current_collateral_balance( + supplier: &AccountId, + asset_id: CurrencyId, + ) -> Result; +} + +pub trait LoansMarketDataProvider { + fn get_market_info(asset_id: CurrencyId) -> Result; + fn get_market_status(asset_id: CurrencyId) -> Result, DispatchError>; + // for compatibility we keep this func + fn get_full_interest_rate(asset_id: CurrencyId) -> Option; +} + +/// MarketInfo contains some static attrs as a subset of Market struct in Loans +#[derive(Default, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct MarketInfo { + pub collateral_factor: Ratio, + pub liquidation_threshold: Ratio, + pub reserve_factor: Ratio, + pub close_factor: Ratio, + pub full_rate: Rate, +} + +/// MarketStatus contains some dynamic calculated attrs of Market +#[derive(Default, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct MarketStatus { + pub borrow_rate: Rate, + pub supply_rate: Rate, + pub exchange_rate: Rate, + pub utilization: Ratio, + pub total_borrows: Balance, + pub total_reserves: Balance, + pub borrow_index: FixedU128, +} diff --git a/crates/traits/src/ump.rs b/crates/traits/src/ump.rs new file mode 100644 index 0000000000..47aaef04bf --- /dev/null +++ b/crates/traits/src/ump.rs @@ -0,0 +1,340 @@ +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::pallet_prelude::Weight; +use frame_system::Config; +use primitives::{AccountId, Balance, BlockNumber, ParaId}; +use scale_info::TypeInfo; +use sp_runtime::{traits::StaticLookup, MultiSignature, RuntimeDebug}; +use sp_std::{boxed::Box, vec::Vec}; +use xcm::latest::MultiLocation; + +/// A destination account for payment. +#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum RewardDestination { + /// Pay into the stash account, increasing the amount at stake accordingly. + Staked, + /// Pay into the stash account, not increasing the amount at stake. + Stash, + /// Pay into the controller account. + Controller, + /// Pay into a specified account. + Account(AccountId), + /// Receive no reward. + None, +} + +/// Relaychain staking.bond call arguments +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct StakingBondCall { + /// Controller account + pub controller: ::Source, + /// Bond amount + #[codec(compact)] + pub value: u128, + /// A destination account for payment. + pub payee: RewardDestination, +} + +/// Relaychain staking.bond_extra call arguments +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct StakingBondExtraCall { + /// Rebond amount + #[codec(compact)] + pub value: u128, +} + +/// Relaychain staking.unbond call arguments +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct StakingUnbondCall { + /// Unbond amount + #[codec(compact)] + pub value: u128, +} + +/// Relaychain staking.rebond call arguments +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct StakingRebondCall { + /// Rebond amount + #[codec(compact)] + pub value: u128, +} + +/// Relaychain staking.withdraw_unbonded call arguments +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct StakingWithdrawUnbondedCall { + /// Withdraw amount + pub num_slashing_spans: u32, +} + +/// Relaychain staking.nominate call arguments +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct StakingNominateCall { + /// List of nominate `targets` + pub targets: Vec<::Source>, +} + +/// Relaychain staking.payout_stakers call arguments +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct StakingPayoutStakersCall { + /// Stash account of validator + pub validator_stash: T::AccountId, + /// EraIndex + pub era: u32, +} + +#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum StakingCall { + #[codec(index = 0)] + Bond(StakingBondCall), + #[codec(index = 1)] + BondExtra(StakingBondExtraCall), + #[codec(index = 2)] + Unbond(StakingUnbondCall), + #[codec(index = 3)] + WithdrawUnbonded(StakingWithdrawUnbondedCall), + #[codec(index = 5)] + Nominate(StakingNominateCall), + #[codec(index = 18)] + PayoutStakers(StakingPayoutStakersCall), + #[codec(index = 19)] + Rebond(StakingRebondCall), +} + +/// Relaychain balances.transfer_keep_alive call arguments +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct BalancesTransferKeepAliveCall { + /// dest account + pub dest: ::Source, + /// transfer amount + #[codec(compact)] + pub value: u128, +} + +/// Relaychain balances.transfer_all call arguments +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct BalancesTransferAllCall { + /// dest account + pub dest: ::Source, + pub keep_alive: bool, +} + +#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum BalancesCall { + #[codec(index = 3)] + TransferKeepAlive(BalancesTransferKeepAliveCall), + #[codec(index = 4)] + TransferAll(BalancesTransferAllCall), +} + +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct CrowdloansContributeCall { + /// - `crowdloan`: The crowdloan who you are contributing to + #[codec(compact)] + pub index: ParaId, + /// - `value`: The amount of tokens you want to contribute to a parachain. + #[codec(compact)] + pub value: u128, + // `signature`: The signature if the fund has a verifier + pub signature: Option, +} + +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct CrowdloansWithdrawCall { + /// - `who`: The account whose contribution should be withdrawn. + pub who: T::AccountId, + /// - `index`: The parachain to whose crowdloan the contribution was made. + #[codec(compact)] + pub index: ParaId, +} + +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct CrowdloansAddMemoCall { + /// - `index`: The parachain to whose crowdloan the contribution was made. + pub index: ParaId, + pub memo: Vec, +} + +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum CrowdloansCall { + #[codec(index = 1)] + Contribute(CrowdloansContributeCall), + #[codec(index = 2)] + Withdraw(CrowdloansWithdrawCall), + #[codec(index = 6)] + AddMemo(CrowdloansAddMemoCall), +} + +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct SystemRemarkCall { + pub remark: Vec, +} + +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum SystemCall { + #[codec(index = 1)] + Remark(SystemRemarkCall), +} + +#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct ProxyProxyCall { + pub real: AccountId, + pub force_proxy_type: Option, + pub call: RelaychainCall, +} + +#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct ProxyAddProxyCall { + pub delegate: AccountId, + pub proxy_type: Option, + pub delay: BlockNumber, +} + +#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct ProxyRemoveProxyCall { + pub delegate: AccountId, + pub proxy_type: Option, + pub delay: BlockNumber, +} + +/// The type used to represent the kinds of proxying allowed. +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + RuntimeDebug, + MaxEncodedLen, + TypeInfo, +)] +pub enum ProxyType { + Any = 0_isize, + NonTransfer = 1_isize, + Governance = 2_isize, + Staking = 3_isize, +} + +impl Default for ProxyType { + fn default() -> Self { + Self::Any + } +} + +#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum ProxyCall { + #[codec(index = 0)] + Proxy(ProxyProxyCall), + #[codec(index = 1)] + AddProxy(ProxyAddProxyCall), + #[codec(index = 2)] + RemoveProxy(ProxyRemoveProxyCall), +} + +/// Relaychain utility.as_derivative call arguments +#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct UtilityAsDerivativeCall { + /// derivative index + pub index: u16, + /// call + pub call: RelaychainCall, +} + +/// Relaychain utility.batch_all call arguments +#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct UtilityBatchAllCall { + /// calls + pub calls: Vec, +} + +#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum UtilityCall { + #[codec(index = 1)] + AsDerivative(UtilityAsDerivativeCall), + #[codec(index = 2)] + BatchAll(UtilityBatchAllCall), +} + +#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum KusamaCall { + #[codec(index = 0)] + System(SystemCall), + #[codec(index = 4)] + Balances(BalancesCall), + #[codec(index = 6)] + Staking(StakingCall), + #[codec(index = 22)] + Proxy(Box>), + #[codec(index = 24)] + Utility(Box>), + #[codec(index = 73)] + Crowdloans(CrowdloansCall), +} + +#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum PolkadotCall { + #[codec(index = 0)] + System(SystemCall), + #[codec(index = 5)] + Balances(BalancesCall), + #[codec(index = 7)] + Staking(StakingCall), + #[codec(index = 26)] + Utility(Box>), + #[codec(index = 29)] + Proxy(Box>), + #[codec(index = 73)] + Crowdloans(CrowdloansCall), +} + +#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct XcmWeightFeeMisc { + pub weight: Weight, + pub fee: Balance, +} + +impl Default for XcmWeightFeeMisc { + fn default() -> Self { + let default_weight = 10_000_000_000; + let default_fee = 10_000_000_000; + XcmWeightFeeMisc { + weight: default_weight, + fee: default_fee, + } + } +} + +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum XcmCall { + Bond, + BondExtra, + Unbond, + Rebond, + WithdrawUnbonded, + Nominate, + Contribute, + Withdraw, + AddMemo, + TransferToSiblingchain(Box), + Proxy, + AddProxy, + RemoveProxy, +} + +#[macro_export] +macro_rules! switch_relay { + ({ $( $code:tt )* }) => { + if ::RelayNetwork::get() == NetworkId::Polkadot { + use pallet_traits::ump::PolkadotCall as RelaychainCall; + + $( $code )* + } else if ::RelayNetwork::get() == NetworkId::Kusama { + use pallet_traits::ump::KusamaCall as RelaychainCall; + + $( $code )* + } else { + unreachable!() + } + } +} diff --git a/crates/traits/src/xcm.rs b/crates/traits/src/xcm.rs new file mode 100644 index 0000000000..165d27c7ac --- /dev/null +++ b/crates/traits/src/xcm.rs @@ -0,0 +1,504 @@ +// 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. + +use crate::CurrencyId; + +use codec::{Decode, Encode}; +use frame_support::{ + traits::{ + tokens::{ + fungibles::{Inspect, Mutate, Transfer}, + BalanceConversion, + }, + Get, + }, + weights::{constants::WEIGHT_PER_SECOND, Weight}, +}; +use scale_info::TypeInfo; +use sp_core::H256; +use sp_runtime::traits::{BlakeTwo256, Convert, Hash as THash, SaturatedConversion, Zero}; +use sp_std::{borrow::Borrow, marker::PhantomData, result}; +use xcm::latest::{ + prelude::*, AssetId as xcmAssetId, Error as XcmError, Fungibility, Junction::AccountId32, + MultiLocation, NetworkId, +}; +use xcm_builder::TakeRevenue; +use xcm_executor::traits::{ + Convert as MoreConvert, MatchesFungible, MatchesFungibles, TransactAsset, WeightTrader, +}; + +/// Converter struct implementing `AssetIdConversion` converting a numeric asset ID +/// (must be `TryFrom/TryInto`) into a MultiLocation Value and Viceversa through +/// an intermediate generic type AssetType. +/// The trait bounds enforce is that the AssetTypeGetter trait is also implemented for +/// AssetIdInfoGetter +pub struct AsAssetType( + PhantomData<(AssetId, AssetType, AssetIdInfoGetter)>, +); +impl xcm_executor::traits::Convert + for AsAssetType +where + AssetId: Clone, + AssetType: From + Into> + Clone, + AssetIdInfoGetter: AssetTypeGetter, +{ + fn convert_ref(id: impl Borrow) -> Result { + if let Some(asset_id) = AssetIdInfoGetter::get_asset_id(id.borrow().clone().into()) { + Ok(asset_id) + } else { + Err(()) + } + } + + fn reverse_ref(what: impl Borrow) -> Result { + if let Some(asset_type) = AssetIdInfoGetter::get_asset_type(what.borrow().clone()) { + if let Some(location) = asset_type.into() { + Ok(location) + } else { + Err(()) + } + } else { + Err(()) + } + } +} + +/// Instructs how to convert accountId into a MultiLocation +pub struct AccountIdToMultiLocation(sp_std::marker::PhantomData); +impl sp_runtime::traits::Convert + for AccountIdToMultiLocation +where + AccountId: Into<[u8; 32]>, +{ + fn convert(account: AccountId) -> MultiLocation { + MultiLocation { + parents: 0, + interior: X1(AccountId32 { + network: NetworkId::Any, + id: account.into(), + }), + } + } +} + +// We need to know how to charge for incoming assets +// This takes the first fungible asset, and takes whatever UnitPerSecondGetter establishes +// UnitsToWeightRatio trait, which needs to be implemented by AssetIdInfoGetter +pub struct FirstAssetTrader< + AssetType: From + Clone, + AssetIdInfoGetter: UnitsToWeightRatio, + R: TakeRevenue, +>( + Weight, + Option<(MultiLocation, u128, u128)>, + PhantomData<(AssetType, AssetIdInfoGetter, R)>, +); +impl< + AssetType: From + Clone, + AssetIdInfoGetter: UnitsToWeightRatio, + R: TakeRevenue, + > WeightTrader for FirstAssetTrader +{ + fn new() -> Self { + FirstAssetTrader(0, None, PhantomData) + } + + fn buy_weight( + &mut self, + weight: Weight, + payment: xcm_executor::Assets, + ) -> Result { + let first_asset = payment + .fungible_assets_iter() + .next() + .ok_or(XcmError::TooExpensive)?; + + // We are only going to check first asset for now. This should be sufficient for simple token + // transfers. We will see later if we change this. + match (first_asset.id, first_asset.fun) { + (xcmAssetId::Concrete(id), Fungibility::Fungible(_)) => { + let asset_type: AssetType = id.clone().into(); + // Shortcut if we know the asset is not supported + // This involves the same db read per block, mitigating any attack based on + // non-supported assets + if !AssetIdInfoGetter::payment_is_supported(asset_type.clone()) { + return Err(XcmError::TooExpensive); + } + + let units_per_second = AssetIdInfoGetter::get_units_per_second(asset_type) + .ok_or(XcmError::TooExpensive)?; + let amount = + units_per_second.saturating_mul(weight as u128) / (WEIGHT_PER_SECOND as u128); + + // We dont need to proceed if the amount is 0 + // For cases (specially tests) where the asset is very cheap with respect + // to the weight needed + if amount.is_zero() { + return Ok(payment); + } + + let required = MultiAsset { + fun: Fungibility::Fungible(amount), + id: xcmAssetId::Concrete(id.clone()), + }; + let unused = payment + .checked_sub(required) + .map_err(|_| XcmError::TooExpensive)?; + self.0 = self.0.saturating_add(weight); + + // In case the asset matches the one the trader already stored before, add + // to later refund + + // Else we are always going to subtract the weight if we can, but we latter do + // not refund it + + // In short, we only refund on the asset the trader first successfully was able + // to pay for an execution + let new_asset = match self.1.clone() { + Some((prev_id, prev_amount, units_per_second)) => { + if prev_id == id { + Some((id, prev_amount.saturating_add(amount), units_per_second)) + } else { + None + } + } + None => Some((id, amount, units_per_second)), + }; + + // Due to the trait bound, we can only refund one asset. + if let Some(new_asset) = new_asset { + self.0 = self.0.saturating_add(weight); + self.1 = Some(new_asset); + }; + + Ok(unused) + } + _ => Err(XcmError::TooExpensive), + } + } + + fn refund_weight(&mut self, weight: Weight) -> Option { + if let Some((id, prev_amount, units_per_second)) = self.1.clone() { + let weight = weight.min(self.0); + self.0 -= weight; + let amount = units_per_second * (weight as u128) / (WEIGHT_PER_SECOND as u128); + self.1 = Some(( + id.clone(), + prev_amount.saturating_sub(amount), + units_per_second, + )); + Some(MultiAsset { + fun: Fungibility::Fungible(amount), + id: xcmAssetId::Concrete(id), + }) + } else { + None + } + } +} + +/// Deal with spent fees, deposit them as dictated by R +impl< + AssetType: From + Clone, + AssetIdInfoGetter: UnitsToWeightRatio, + R: TakeRevenue, + > Drop for FirstAssetTrader +{ + fn drop(&mut self) { + if let Some((id, amount, _)) = self.1.clone() { + R::take_revenue((id, amount).into()); + } + } +} + +// Defines the trait to obtain a generic AssetType from a generic AssetId and viceversa +pub trait AssetTypeGetter { + // Get asset type from assetId + fn get_asset_type(asset_id: AssetId) -> Option; + + // Get assetId from assetType + fn get_asset_id(asset_type: AssetType) -> Option; +} + +// Defines the trait to obtain the units per second of a give asset_type for local execution +// This parameter will be used to charge for fees upon asset_type deposit +pub trait UnitsToWeightRatio { + // Whether payment in a particular asset_type is suppotrted + fn payment_is_supported(asset_type: AssetType) -> bool; + // Get units per second from asset type + fn get_units_per_second(asset_type: AssetType) -> Option; +} + +/// XCM fee depositor to which we implement the TakeRevenue trait +/// It receives a fungibles::Mutate implemented argument, a matcher to convert MultiAsset into +/// AssetId and amount, and the fee receiver account +pub struct XcmFeesToAccount( + PhantomData<(Assets, Matcher, AccountId, ReceiverAccount)>, +); +impl< + Assets: Mutate, + Matcher: MatchesFungibles, + AccountId: Clone, + ReceiverAccount: Get, + > TakeRevenue for XcmFeesToAccount +{ + fn take_revenue(revenue: MultiAsset) { + match Matcher::matches_fungibles(&revenue) { + Ok((asset_id, amount)) => { + if !amount.is_zero() { + let ok = Assets::mint_into(asset_id, &ReceiverAccount::get(), amount).is_ok(); + debug_assert!(ok, "`mint_into` cannot generally fail; qed"); + } + } + Err(_) => log::debug!( + target: "xcm", + "take revenue failed matching fungible" + ), + } + } +} + +// Our AssetType. For now we only handle Xcm Assets +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum AssetType { + Xcm(MultiLocation), +} + +impl Default for AssetType { + fn default() -> Self { + Self::Xcm(MultiLocation::here()) + } +} + +impl From for AssetType { + fn from(location: MultiLocation) -> Self { + Self::Xcm(location) + } +} + +impl From for Option { + fn from(asset: AssetType) -> Option { + match asset { + AssetType::Xcm(location) => Some(location), + } + } +} + +// Implementation on how to retrieve the AssetId from an AssetType +// We simply hash the AssetType and take the lowest 32 bits +impl From for CurrencyId { + fn from(asset: AssetType) -> CurrencyId { + match asset { + AssetType::Xcm(id) => { + let mut result: [u8; 4] = [0u8; 4]; + let hash: H256 = id.using_encoded(BlakeTwo256::hash); + result.copy_from_slice(&hash.as_fixed_bytes()[0..4]); + u32::from_le_bytes(result) + } + } + } +} + +// How to convert from CurrencyId to MultiLocation +pub struct CurrencyIdtoMultiLocation( + sp_std::marker::PhantomData<(LegacyAssetConverter, ForeignAssetConverter)>, +); +impl + sp_runtime::traits::Convert> + for CurrencyIdtoMultiLocation +where + LegacyAssetConverter: Convert>, + ForeignAssetConverter: xcm_executor::traits::Convert, +{ + fn convert(currency_id: CurrencyId) -> Option { + let mut multi_location = LegacyAssetConverter::convert(currency_id); + multi_location = match multi_location { + Some(_) => multi_location, + None => ForeignAssetConverter::reverse_ref(¤cy_id).ok(), + }; + multi_location + } +} + +pub struct MultiCurrencyAdapter< + MultiCurrency, + Match, + AccountId, + Balance, + AccountIdConvert, + CurrencyIdConvert, + NativeCurrencyId, + ExistentialDeposit, + GiftAccount, + GiftConvert, +>( + PhantomData<( + MultiCurrency, + Match, + AccountId, + Balance, + AccountIdConvert, + CurrencyIdConvert, + NativeCurrencyId, + ExistentialDeposit, + GiftAccount, + GiftConvert, + )>, +); + +enum Error { + /// `MultiLocation` to `AccountId` Conversion failed. + AccountIdConversionFailed, + /// `CurrencyId` conversion failed. + CurrencyIdConversionFailed, +} + +impl From for XcmError { + fn from(e: Error) -> Self { + match e { + Error::AccountIdConversionFailed => { + XcmError::FailedToTransactAsset("AccountIdConversionFailed") + } + Error::CurrencyIdConversionFailed => { + XcmError::FailedToTransactAsset("CurrencyIdConversionFailed") + } + } + } +} + +impl< + MultiCurrency: Inspect + + Mutate + + Transfer, + Match: MatchesFungible, + AccountId: sp_std::fmt::Debug + Clone, + Balance: frame_support::traits::tokens::Balance, + AccountIdConvert: MoreConvert, + CurrencyIdConvert: Convert>, + NativeCurrencyId: Get, + ExistentialDeposit: Get, + GiftAccount: Get, + GiftConvert: BalanceConversion, + > TransactAsset + for MultiCurrencyAdapter< + MultiCurrency, + Match, + AccountId, + Balance, + AccountIdConvert, + CurrencyIdConvert, + NativeCurrencyId, + ExistentialDeposit, + GiftAccount, + GiftConvert, + > +{ + fn deposit_asset(asset: &MultiAsset, location: &MultiLocation) -> XcmResult { + match ( + AccountIdConvert::convert_ref(location), + CurrencyIdConvert::convert(asset.clone()), + Match::matches_fungible(asset), + ) { + // known asset + (Ok(who), Some(currency_id), Some(amount)) => { + if let MultiAsset { + id: + AssetId::Concrete(MultiLocation { + parents: 1, + interior: Here, + }), + .. + } = asset + { + let gift_account = GiftAccount::get(); + let native_currency_id = NativeCurrencyId::get(); + let gift_amount = + GiftConvert::to_asset_balance(amount.saturated_into(), currency_id) + .unwrap_or_else(|_| Zero::zero()); + let beneficiary_native_balance = + MultiCurrency::reducible_balance(native_currency_id, &who, true); + let reducible_balance = + MultiCurrency::reducible_balance(native_currency_id, &gift_account, false); + + if !gift_amount.is_zero() + && reducible_balance >= gift_amount + && beneficiary_native_balance < gift_amount + { + let diff = gift_amount - beneficiary_native_balance; + if let Err(e) = MultiCurrency::transfer( + native_currency_id, + &gift_account, + &who, + diff, + false, + ) { + log::error!( + target: "xcm::deposit_asset", + "who: {:?}, currency_id: {:?}, amount: {:?}, native_currency_id: {:?}, gift_amount: {:?}, err: {:?}", + who, + currency_id, + amount, + native_currency_id, + diff, + e + ); + } + } + } + + MultiCurrency::mint_into(currency_id, &who, amount) + .map_err(|e| XcmError::FailedToTransactAsset(e.into())) + } + _ => Err(XcmError::AssetNotFound), + } + } + + fn withdraw_asset( + asset: &MultiAsset, + location: &MultiLocation, + ) -> result::Result { + // throw AssetNotFound error here if not match in order to reach the next foreign transact in tuple + let amount: MultiCurrency::Balance = Match::matches_fungible(asset) + .ok_or(XcmError::AssetNotFound)? + .saturated_into(); + let who = AccountIdConvert::convert_ref(location) + .map_err(|_| XcmError::from(Error::AccountIdConversionFailed))?; + let currency_id = CurrencyIdConvert::convert(asset.clone()) + .ok_or_else(|| XcmError::from(Error::CurrencyIdConversionFailed))?; + MultiCurrency::burn_from(currency_id, &who, amount) + .map_err(|e| XcmError::FailedToTransactAsset(e.into()))?; + + Ok(asset.clone().into()) + } + + fn internal_transfer_asset( + asset: &MultiAsset, + from: &MultiLocation, + to: &MultiLocation, + ) -> result::Result { + let from_account = AccountIdConvert::convert_ref(from) + .map_err(|_| XcmError::from(Error::AccountIdConversionFailed))?; + let to_account = AccountIdConvert::convert_ref(to) + .map_err(|_| XcmError::from(Error::AccountIdConversionFailed))?; + let currency_id = CurrencyIdConvert::convert(asset.clone()) + .ok_or_else(|| XcmError::from(Error::CurrencyIdConversionFailed))?; + let amount: MultiCurrency::Balance = Match::matches_fungible(asset) + .ok_or(XcmError::AssetNotFound)? + .saturated_into(); + MultiCurrency::transfer(currency_id, &from_account, &to_account, amount, true) + .map_err(|e| XcmError::FailedToTransactAsset(e.into()))?; + + Ok(asset.clone().into()) + } +} diff --git a/primitives/src/tokens.rs b/primitives/src/tokens.rs new file mode 100644 index 0000000000..ea4855b6fe --- /dev/null +++ b/primitives/src/tokens.rs @@ -0,0 +1,204 @@ +// 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. + +use crate::CurrencyId; + +// Native Token +pub const HKO: CurrencyId = 0; +pub const PARA: CurrencyId = 1; + +// Polkadot ecosystem +pub const KSM: CurrencyId = 100; +pub const DOT: CurrencyId = 101; +pub const USDT: CurrencyId = 102; +pub const KUSD: CurrencyId = 103; +pub const AUSD: CurrencyId = 104; +pub const LC_KSM: CurrencyId = 105; +pub const LC_DOT: CurrencyId = 106; +pub const KAR: CurrencyId = 107; +pub const ACA: CurrencyId = 108; +pub const LKSM: CurrencyId = 109; +pub const LDOT: CurrencyId = 110; +pub const SDN: CurrencyId = 111; +pub const ASTR: CurrencyId = 112; +pub const MOVR: CurrencyId = 113; +pub const GLMR: CurrencyId = 114; +pub const PHA: CurrencyId = 115; +pub const KMA: CurrencyId = 117; +pub const MA: CurrencyId = 118; +pub const KINT: CurrencyId = 119; +pub const INTR: CurrencyId = 120; +pub const KBTC: CurrencyId = 121; +pub const IBTC: CurrencyId = 122; +pub const GENS: CurrencyId = 123; +pub const EQ: CurrencyId = 124; +pub const TUR: CurrencyId = 125; +pub const LIT: CurrencyId = 127; +pub const CLV: CurrencyId = 130; + +// Ethereum ecosystem +pub const EUSDT: CurrencyId = 201; +pub const EUSDC: CurrencyId = 202; +pub const HBTC: CurrencyId = 203; + +// Liquid Staking Derivative +pub const SKSM: CurrencyId = 1000; +pub const SDOT: CurrencyId = 1001; + +// Money Market Derivative +pub const PHKO: CurrencyId = 2000; +pub const PPARA: CurrencyId = 2001; +pub const PKSM: CurrencyId = 2100; +pub const PDOT: CurrencyId = 2101; +pub const PUSDT: CurrencyId = 2102; +pub const PKUSD: CurrencyId = 2103; +pub const PAUSD: CurrencyId = 2104; +pub const PLC_KSM: CurrencyId = 2105; +pub const PLC_DOT: CurrencyId = 2106; +pub const PKAR: CurrencyId = 2107; +pub const PACA: CurrencyId = 2108; +pub const PLKSM: CurrencyId = 2109; +pub const PLDOT: CurrencyId = 2110; + +pub const PEUSDT: CurrencyId = 2201; +pub const PEUSDC: CurrencyId = 2202; + +pub const PSKSM: CurrencyId = 3000; +pub const PSDOT: CurrencyId = 3001; +pub const PKSM_U: CurrencyId = 3002; +pub const PDOT_U: CurrencyId = 3003; + +pub const PCDOT_6_13: CurrencyId = 200062013; +pub const PCDOT_7_14: CurrencyId = 200072014; + +// AMM LP Token +pub const LP_USDT_HKO: CurrencyId = 5000; +pub const LP_KSM_USDT: CurrencyId = 5001; +pub const LP_KSM_HKO: CurrencyId = 5002; +pub const LP_KSM_SKSM: CurrencyId = 5003; +pub const LP_KSM_CKSM_20_27: CurrencyId = 5004; + +pub const LP_USDT_PARA: CurrencyId = 6000; +pub const LP_DOT_USDT: CurrencyId = 6001; +pub const LP_DOT_PARA: CurrencyId = 6002; +pub const LP_DOT_SDOT: CurrencyId = 6003; +pub const LP_DOT_CDOT_6_13: CurrencyId = 6004; +pub const LP_DOT_CDOT_7_14: CurrencyId = 6005; +pub const LP_PARA_CDOT_6_13: CurrencyId = 6006; +pub const LP_DOT_CDOT_8_15: CurrencyId = 6007; + +pub const PLP_USDT_HKO: CurrencyId = 7000; +pub const PLP_KSM_USDT: CurrencyId = 7001; +pub const PLP_KSM_HKO: CurrencyId = 7002; +pub const PLP_KSM_SKSM: CurrencyId = 7003; +pub const PLP_KSM_CKSM_20_27: CurrencyId = 7004; + +pub const PLP_USDT_PARA: CurrencyId = 8000; +pub const PLP_DOT_USDT: CurrencyId = 8001; +pub const PLP_DOT_PARA: CurrencyId = 8002; +pub const PLP_DOT_SDOT: CurrencyId = 8003; +pub const PLP_DOT_CDOT_6_13: CurrencyId = 8004; +pub const PLP_DOT_CDOT_7_14: CurrencyId = 8005; +pub const PLP_PARA_CDOT_6_13: CurrencyId = 8006; +pub const PLP_DOT_CDOT_8_15: CurrencyId = 8007; + +// Crowdloan Derivative +pub const CKSM_15_22: CurrencyId = 100150022; +pub const CKSM_20_27: CurrencyId = 100200027; +pub const CKSM_21_28: CurrencyId = 100210028; +pub const CDOT_6_13: CurrencyId = 200060013; +pub const CDOT_7_14: CurrencyId = 200070014; +pub const CDOT_8_15: CurrencyId = 200080015; + +// Relay Currency Auxiliary +pub const KSM_U: CurrencyId = 4294957295; +pub const DOT_U: CurrencyId = 4294957296; + +// assume all vault token are liquidation free and within range here +pub fn is_vault_token(asset_id: CurrencyId) -> bool { + asset_id > 100000000 && asset_id < 300000000 +} + +// we only care about liquidation fee lp tokens here +// which constructed with vault token and relay token +pub fn is_lf_lp_token(asset_id: CurrencyId) -> bool { + (asset_id > 5003 && asset_id < 6000) || (asset_id > 6003 && asset_id < 7000) +} + +pub fn is_ls_token(asset_id: CurrencyId) -> bool { + asset_id == SKSM || asset_id == SDOT +} + +pub fn is_auxiliary_token(asset_id: CurrencyId) -> bool { + asset_id >= u32::MAX - 10000 +} +// Token Registration Information +// +───────────+──────────────+────────────────────+ +// | Network | Token | Register in block | +// +───────────+──────────────+────────────────────+ +// | Heiko | HKO | Native | +// | Heiko | KSM | N/A | +// | Heiko | USDT | N/A | +// | Heiko | KUSD | N/A | +// | Heiko | EUSDC | N/A | +// | Heiko | EUSDT | N/A | +// | Heiko | KAR | N/A | +// | Heiko | SKSM | N/A | +// | Heiko | CKSM | N/A | +// | Heiko | LKSM | N/A | +// | Heiko | MOVR | N/A | +// | Heiko | SDN | N/A | +// | Heiko | PHA | N/A | +// | Heiko | KMA | N/A | +// | Heiko | KINT | N/A | +// | Heiko | KBTC | N/A | +// | Heiko | GENS | N/A | +// | Heiko | PHKO | N/A | +// | Heiko | PKSM | N/A | +// | Heiko | PUSDT | N/A | +// | Heiko | PKUSD | N/A | +// | Heiko | PEUSDT | N/A | +// | Heiko | PEUSDC | N/A | +// | Heiko | PKAR | N/A | +// | Heiko | PSKSM | N/A | +// | Heiko | PLKSM | N/A | +// | Heiko | PLCKSM | N/A | +// | Heiko | PCKSM | N/A | +// | Parallel | PARA | Native | +// | Parallel | KSM | N/A | +// | Parallel | DOT | N/A | +// | Parallel | USDT | N/A | +// | Parallel | AUSD | N/A | +// | Parallel | EUSDC | N/A | +// | Parallel | EUSDT | N/A | +// | Parallel | ACA | N/A | +// | Parallel | SDOT | N/A | +// | Parallel | CDOT | N/A | +// | Parallel | LDOT | N/A | +// | Parallel | LCDOT | N/A | +// | Parallel | GLMR | N/A | +// | Parallel | ASTR | N/A | +// | Parallel | PPARA | Native | +// | Parallel | PKSM | N/A | +// | Parallel | PDOT | N/A | +// | Parallel | PUSDT | N/A | +// | Parallel | PAUSD | N/A | +// | Parallel | PEUSDC | N/A | +// | Parallel | PEUSDT | N/A | +// | Parallel | PACA | N/A | +// | Parallel | PSDOT | N/A | +// | Parallel | PLDOT | N/A | +// | Parallel | PLCDOT | N/A | +// | Parallel | PCDOT | N/A | +// +──────────+───────────────+────────────────────+ From 30100fe363263afc941ee9f16baafb403bf6062c Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Mon, 19 Sep 2022 18:32:52 +0200 Subject: [PATCH 02/58] feat(lend): get unit tests to run --- Cargo.lock | 107 ++++- crates/currency-adapter/Cargo.toml | 2 +- crates/currency-adapter/src/lib.rs | 2 +- crates/loans/Cargo.toml | 10 +- crates/loans/src/lib.rs | 3 +- crates/loans/src/migrations.rs | 190 -------- crates/loans/src/mock.rs | 47 +- crates/loans/src/tests/liquidate_borrow.rs | 2 +- crates/loans/src/types.rs | 2 +- crates/traits/Cargo.toml | 2 +- crates/traits/src/lib.rs | 28 +- crates/traits/src/ump.rs | 340 -------------- crates/traits/src/xcm.rs | 504 --------------------- primitives/src/lib.rs | 19 +- primitives/src/tokens.rs | 2 +- standalone/runtime/Cargo.toml | 1 + 16 files changed, 138 insertions(+), 1123 deletions(-) delete mode 100644 crates/loans/src/migrations.rs delete mode 100644 crates/traits/src/ump.rs delete mode 100644 crates/traits/src/xcm.rs diff --git a/Cargo.lock b/Cargo.lock index a0869bca3c..51483ce82a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3619,6 +3619,7 @@ dependencies = [ "pallet-collective", "pallet-grandpa", "pallet-identity", + "pallet-loans", "pallet-membership", "pallet-multisig", "pallet-preimage", @@ -5726,6 +5727,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg 1.1.0", + "num-integer", + "num-traits", +] + [[package]] name = "num-complex" version = "0.4.2" @@ -5762,7 +5774,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" dependencies = [ "autocfg 1.1.0", - "num-bigint", + "num-bigint 0.2.6", "num-integer", "num-traits", ] @@ -5925,6 +5937,24 @@ dependencies = [ "xcm-executor", ] +[[package]] +name = "orml-oracle" +version = "0.4.1-dev" +source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=8c625a5ab43c1c56cdeed5f8d814a891566d4cf8#8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" +dependencies = [ + "frame-support", + "frame-system", + "orml-traits", + "orml-utilities", + "parity-scale-codec", + "scale-info", + "serde", + "sp-application-crypto", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "orml-tokens" version = "0.4.1-dev" @@ -6075,6 +6105,20 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "pallet-assets" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.28#34a0621761c4a333cb2074ff720f7acbfb92dbb8" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-aura" version = "4.0.0-dev" @@ -6274,6 +6318,18 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-currency-adapter" +version = "1.9.3" +dependencies = [ + "frame-support", + "frame-system", + "interbtc-primitives", + "parity-scale-codec", + "scale-info", + "sp-runtime", +] + [[package]] name = "pallet-democracy" version = "4.0.0-dev" @@ -6435,6 +6491,31 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-loans" +version = "1.9.3" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "interbtc-primitives", + "num-traits", + "orml-oracle", + "orml-traits", + "pallet-assets", + "pallet-balances", + "pallet-currency-adapter", + "pallet-timestamp", + "pallet-traits", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-membership" version = "4.0.0-dev" @@ -6783,6 +6864,28 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-traits" +version = "1.9.3" +dependencies = [ + "frame-support", + "frame-system", + "interbtc-primitives", + "log", + "num-bigint 0.4.3", + "num-traits", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "xcm", + "xcm-builder", + "xcm-executor", +] + [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" @@ -9708,7 +9811,7 @@ dependencies = [ "futures", "log", "merlin", - "num-bigint", + "num-bigint 0.2.6", "num-rational 0.2.4", "num-traits", "parity-scale-codec", diff --git a/crates/currency-adapter/Cargo.toml b/crates/currency-adapter/Cargo.toml index d741f8f768..410ecc43dc 100644 --- a/crates/currency-adapter/Cargo.toml +++ b/crates/currency-adapter/Cargo.toml @@ -11,7 +11,7 @@ targets = ['x86_64-unknown-linux-gnu'] codec = { package = 'parity-scale-codec', version = '3.1.5', features = ['max-encoded-len'], default-features = false } frame-support = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } frame-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } -primitives = { package = 'parallel-primitives', path = '../../primitives', default-features = false } +primitives = { package = 'interbtc-primitives', path = '../../primitives', default-features = false } scale-info = { version = '2.1', default-features = false, features = ['derive'] } sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } diff --git a/crates/currency-adapter/src/lib.rs b/crates/currency-adapter/src/lib.rs index 43f87e5ee2..1fcf314076 100644 --- a/crates/currency-adapter/src/lib.rs +++ b/crates/currency-adapter/src/lib.rs @@ -34,7 +34,7 @@ use frame_support::{ Get, LockIdentifier, WithdrawReasons, }, }; -use primitives::{Balance, CurrencyId}; +use primitives::{Balance, LendingPoolCurrencyId as CurrencyId}; use sp_runtime::DispatchError; type AssetIdOf = diff --git a/crates/loans/Cargo.toml b/crates/loans/Cargo.toml index 3d17f85cff..450d13e644 100644 --- a/crates/loans/Cargo.toml +++ b/crates/loans/Cargo.toml @@ -13,13 +13,14 @@ frame-benchmarking = { git = 'https://github.com/paritytech/substrate.git', bran frame-support = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } frame-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } num-traits = { default-features = false, version = '0.2' } -orml-traits = { version = '0.4.1-dev', default-features = false } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" } +orml-oracle = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" } pallet-assets = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } pallet-balances = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } -pallet-prices = { path = '../prices', default-features = false } + pallet-timestamp = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } pallet-traits = { path = '../traits', default-features = false } -primitives = { package = 'parallel-primitives', path = '../../primitives', default-features = false } +primitives = { package = 'interbtc-primitives', path = '../../primitives', default-features = false } scale-info = { version = '2.1', default-features = false, features = ['derive'] } serde = { version = '1.0.136', features = ['derive'], optional = true } sp-io = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } @@ -27,8 +28,6 @@ sp-runtime = { git = 'https://github.com/paritytech/substrate.git', bran sp-std = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } [dev-dependencies] -orml-oracle = { version = '0.4.1-dev' } -pallet-amm = { path = '../amm' } pallet-currency-adapter = { path = '../currency-adapter' } sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28' } @@ -46,7 +45,6 @@ std = [ 'sp-std/std', 'sp-io/std', 'pallet-assets/std', - 'pallet-prices/std', 'pallet-balances/std', 'pallet-timestamp/std', 'serde', diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 5b16d73b36..8edd9e8ca0 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -44,7 +44,7 @@ use pallet_traits::{ MarketInfo, MarketStatus, PriceFeeder, }; use primitives::{ - is_auxiliary_token, Balance, CurrencyId, Liquidity, Price, Rate, Ratio, Shortfall, Timestamp, + tokens::is_auxiliary_token, Balance, LendingPoolCurrencyId as CurrencyId, Liquidity, Price, Rate, Ratio, Shortfall, Timestamp, }; use sp_runtime::{ traits::{ @@ -72,7 +72,6 @@ mod ptoken; mod rate_model; mod types; -pub mod migrations; pub mod weights; pub const MAX_INTEREST_CALCULATING_INTERVAL: u64 = 5 * 24 * 3600; // 5 days diff --git a/crates/loans/src/migrations.rs b/crates/loans/src/migrations.rs deleted file mode 100644 index 50117fae27..0000000000 --- a/crates/loans/src/migrations.rs +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2021-2022 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. - -use super::*; - -pub mod v3 { - use super::*; - use crate::{pallet::StorageVersion, Config, Weight}; - use frame_support::{log, traits::Get}; - - pub const DEFAULT_LIQUIDATE_INCENTIVE_RESERVED_FACTOR: Ratio = Ratio::from_percent(3); - pub const DEFAULT_LIQUIDATION_OFFSET: Ratio = Ratio::from_percent(10); - - #[cfg_attr(feature = "std", derive(serde::Deserialize, serde::Serialize))] - #[derive(Clone, PartialEq, Eq, codec::Decode, codec::Encode, RuntimeDebug, TypeInfo)] - pub struct V2Market { - /// The collateral utilization ratio - pub collateral_factor: Ratio, - /// Fraction of interest currently set aside for reserves - pub reserve_factor: Ratio, - /// The percent, ranging from 0% to 100%, of a liquidatable account's - /// borrow that can be repaid in a single liquidate transaction. - pub close_factor: Ratio, - /// Liquidation incentive ratio - pub liquidate_incentive: Rate, - /// Current interest rate model being used - pub rate_model: InterestRateModel, - /// Current market state - pub state: MarketState, - /// Upper bound of supplying - pub supply_cap: Balance, - /// Upper bound of borrowing - pub borrow_cap: Balance, - /// Ptoken asset id - pub ptoken_id: CurrencyId, - } - #[frame_support::storage_alias] - type MarketRewardSpeed = - StorageMap, Blake2_128Concat, AssetIdOf, BalanceOf>; - - #[frame_support::storage_alias] - type RewardAccured = StorageMap< - crate::Pallet, - Blake2_128Concat, - ::AccountId, - BalanceOf, - >; - - #[frame_support::storage_alias] - type LastAccruedTimestamp = StorageValue, Timestamp, ValueQuery>; - - #[cfg(feature = "try-runtime")] - pub fn pre_migrate() -> Result<(), &'static str> { - #[frame_support::storage_alias] - type Markets = - StorageMap, Blake2_128Concat, AssetIdOf, V2Market>>; - frame_support::ensure!( - StorageVersion::::get() == crate::Versions::V2, - "must upgrade linearly" - ); - Markets::::iter().for_each(|(asset_id, _)| { - log::info!("market {:#?} need to migrate", asset_id,); - }); - let reward_speed_count = MarketRewardSpeed::::iter().count(); - log::info!( - "total {:#?} reward speed items need to migrate", - reward_speed_count - ); - - let last_accrued_timestamp = LastAccruedTimestamp::::get(); - log::info!( - "LastAccruedTimestamp: {:#?} is about to move.", - last_accrued_timestamp - ); - - let old_name_items_count = RewardAccured::::iter().count(); - let new_name_items_count = RewardAccrued::::iter().count(); - log::info!( - "old_name_items_count: {:#?}, new_name_items_count: {:#?}.", - old_name_items_count, - new_name_items_count, - ); - - log::info!("👜 loans v3 migration passes PRE migrate checks ✅",); - - Ok(()) - } - - /// Migration to sorted [`SortedListProvider`]. - pub fn migrate() -> Weight { - if StorageVersion::::get() == crate::Versions::V2 { - log::info!("migrating loans to Versions::V3",); - - Markets::::translate::>, _>(|_key, market| { - Some(Market { - borrow_cap: market.borrow_cap, - supply_cap: market.supply_cap, - collateral_factor: market.collateral_factor, - liquidation_threshold: (market.collateral_factor - + market.collateral_factor * DEFAULT_LIQUIDATION_OFFSET), - reserve_factor: market.reserve_factor, - close_factor: market.close_factor, - liquidate_incentive_reserved_factor: - DEFAULT_LIQUIDATE_INCENTIVE_RESERVED_FACTOR, - liquidate_incentive: market.liquidate_incentive, - rate_model: market.rate_model, - state: market.state, - ptoken_id: market.ptoken_id, - }) - }); - - MarketRewardSpeed::::iter().for_each(|(asset_id, reward_speed)| { - RewardSupplySpeed::::insert(asset_id, reward_speed); - RewardBorrowSpeed::::insert(asset_id, reward_speed); - }); - - //remove old data. - let _ = MarketRewardSpeed::::clear(u32::max_value(), None); - LastAccruedTimestamp::::kill(); - - StorageVersion::::put(crate::Versions::V3); - log::info!("👜 completed loans migration to Versions::V3",); - - T::BlockWeights::get().max_block - } else { - T::DbWeight::get().reads(1) - } - } - - #[cfg(feature = "try-runtime")] - pub fn post_migrate() -> Result<(), &'static str> { - frame_support::ensure!( - StorageVersion::::get() == crate::Versions::V3, - "must upgrade to V3" - ); - Markets::::iter().for_each(|(asset_id, market)| { - log::info!( - "market {:#?}, collateral_factor {:?}, liquidation_threshold {:?}, liquidate_incentive_reserved_factor {:?}", - asset_id, - market.collateral_factor, - market.liquidation_threshold, - market.liquidate_incentive_reserved_factor - ); - }); - RewardSupplySpeed::::iter().for_each(|(asset_id, supply_reward_speed)| { - let borrow_reward_speed = RewardBorrowSpeed::::get(asset_id); - log::info!( - "market {:#?}, supply_reward_speed {:?}, borrow_reward_speed {:?}", - asset_id, - supply_reward_speed, - borrow_reward_speed - ); - }); - - let reward_speed_count = MarketRewardSpeed::::iter().count(); - log::info!( - "total {:#?} reward speed items remains after migrate", - reward_speed_count - ); - - let last_accrued_timestamp = LastAccruedTimestamp::::get(); - log::info!( - "LastAccruedTimestamp: {:#?} after migrate.", - last_accrued_timestamp - ); - - let old_name_items_count = RewardAccured::::iter().count(); - let new_name_items_count = RewardAccrued::::iter().count(); - log::info!( - "old_name_items_count: {:#?}, new_name_items_count: {:#?}.", - old_name_items_count, - new_name_items_count, - ); - - log::info!("👜 loans v3 migration passes POST migrate checks ✅",); - - Ok(()) - } -} diff --git a/crates/loans/src/mock.rs b/crates/loans/src/mock.rs index 66a7426291..2decde1c3e 100644 --- a/crates/loans/src/mock.rs +++ b/crates/loans/src/mock.rs @@ -25,7 +25,8 @@ use pallet_traits::{ }; use primitives::{ tokens::{CDOT_6_13, PCDOT_6_13}, - *, + LendingPoolCurrencyId as CurrencyId, + Moment, PriceDetail }; use sp_core::H256; use sp_runtime::{testing::Header, traits::IdentityLookup, AccountId32}; @@ -46,10 +47,8 @@ construct_runtime!( System: frame_system::{Pallet, Call, Storage, Config, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Event}, Loans: crate::{Pallet, Storage, Call, Event}, - Prices: pallet_prices::{Pallet, Storage, Call, Event}, TimestampPallet: pallet_timestamp::{Pallet, Call, Storage, Inherent}, Assets: pallet_assets::{Pallet, Call, Storage, Event}, - DefaultAMM: pallet_amm::{Pallet, Call, Storage, Event}, CurrencyAdapter: pallet_currency_adapter::{Pallet, Call}, } ); @@ -221,17 +220,6 @@ parameter_types! { pub const RelayCurrency: CurrencyId = KSM; } -// AMM instance initialization -parameter_types! { - pub const AMMPalletId: PalletId = PalletId(*b"par/ammp"); - // pub const DefaultLpFee: Ratio = Ratio::from_rational(25u32, 10000u32); // 0.25% - // pub const DefaultProtocolFee: Ratio = Ratio::from_rational(5u32, 10000u32); - pub DefaultLpFee: Ratio = Ratio::from_rational(25u32, 10000u32); // 0.3% - pub const MinimumLiquidity: u128 = 1_000u128; - pub const LockAccountId: AccountId = ALICE; - pub const MaxLengthRoute: u8 = 10; -} - pub struct AliceCreatePoolOrigin; impl SortedMembers for AliceCreatePoolOrigin { fn sorted_members() -> Vec { @@ -239,37 +227,6 @@ impl SortedMembers for AliceCreatePoolOrigin { } } -impl pallet_amm::Config for Test { - type Event = Event; - type Assets = CurrencyAdapter; - type PalletId = AMMPalletId; - type LockAccountId = LockAccountId; - type AMMWeightInfo = (); - type CreatePoolOrigin = EnsureSignedBy; - type ProtocolFeeUpdateOrigin = EnsureSignedBy; - type LpFee = DefaultLpFee; - type MinimumLiquidity = MinimumLiquidity; - type MaxLengthRoute = MaxLengthRoute; - type GetNativeCurrencyId = NativeCurrencyId; -} - -impl pallet_prices::Config for Test { - type Event = Event; - type Source = MockDataProvider; - type FeederOrigin = EnsureRoot; - type UpdateOrigin = EnsureRoot; - type LiquidStakingExchangeRateProvider = LiquidStaking; - type LiquidStakingCurrenciesProvider = LiquidStaking; - type VaultTokenCurrenciesFilter = TokenCurrenciesFilter; - type VaultTokenExchangeRateProvider = TokenExchangeRateProvider; - type VaultLoansRateProvider = VaultLoansRateProvider; - type RelayCurrency = RelayCurrency; - type Decimal = Decimal; - type AMM = DefaultAMM; - type Assets = CurrencyAdapter; - type WeightInfo = (); -} - pub struct MockPriceFeeder; impl MockPriceFeeder { diff --git a/crates/loans/src/tests/liquidate_borrow.rs b/crates/loans/src/tests/liquidate_borrow.rs index e086c77795..f0d107ee18 100644 --- a/crates/loans/src/tests/liquidate_borrow.rs +++ b/crates/loans/src/tests/liquidate_borrow.rs @@ -6,7 +6,7 @@ use crate::{ Error, MarketState, }; use frame_support::{assert_err, assert_noop, assert_ok}; -use primitives::{tokens::CDOT_6_13, Rate, DOT_U}; +use primitives::{tokens::{CDOT_6_13, DOT_U}, Rate}; use sp_runtime::FixedPointNumber; #[test] diff --git a/crates/loans/src/types.rs b/crates/loans/src/types.rs index a820e9ee3c..c79ac0b876 100644 --- a/crates/loans/src/types.rs +++ b/crates/loans/src/types.rs @@ -1,6 +1,6 @@ use crate::InterestRateModel; use frame_support::pallet_prelude::*; -use primitives::{CurrencyId, Rate, Ratio}; +use primitives::{LendingPoolCurrencyId as CurrencyId, Rate, Ratio}; use scale_info::TypeInfo; /// Container for borrow balance information diff --git a/crates/traits/Cargo.toml b/crates/traits/Cargo.toml index 886a1837a4..adb32d7b3d 100644 --- a/crates/traits/Cargo.toml +++ b/crates/traits/Cargo.toml @@ -15,7 +15,7 @@ frame-system = { git = 'https://github.com/paritytech/substrate.git', branch = log = { version = "0.4", default-features = false } num-bigint = { default-features = false, version = '0.4' } num-traits = { default-features = false, version = '0.2' } -primitives = { package = 'parallel-primitives', path = '../../primitives', default-features = false } +primitives = { package = 'interbtc-primitives', path = '../../primitives', default-features = false } scale-info = { version = '2.1', default-features = false, features = ['derive'] } sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } sp-io = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } diff --git a/crates/traits/src/lib.rs b/crates/traits/src/lib.rs index 7dd4e05793..6db76f0080 100644 --- a/crates/traits/src/lib.rs +++ b/crates/traits/src/lib.rs @@ -8,12 +8,10 @@ use sp_runtime::{traits::Zero, RuntimeDebug}; use sp_std::prelude::*; use primitives::{ - CurrencyId, DerivativeIndex, PersistedValidationData, PriceDetail, Rate, Timestamp, + LendingPoolCurrencyId as CurrencyId, PriceDetail, Rate, Timestamp, }; pub mod loans; -pub mod ump; -pub mod xcm; pub use loans::*; pub trait EmergencyCallFilter { @@ -201,30 +199,6 @@ impl ConvertToBigUint for u128 { } } -/// Get relaychain validation data -pub trait ValidationDataProvider { - fn validation_data() -> Option; -} - -/// Distribute liquidstaking asset to multi-accounts -pub trait DistributionStrategy { - fn get_bond_distributions( - bonded_amounts: Vec<(DerivativeIndex, Balance, Balance)>, - input: Balance, - cap: Balance, - min_nominator_bond: Balance, - ) -> Vec<(DerivativeIndex, Balance)>; - fn get_unbond_distributions( - active_bonded_amounts: Vec<(DerivativeIndex, Balance)>, - input: Balance, - min_nominator_bond: Balance, - ) -> Vec<(DerivativeIndex, Balance)>; - fn get_rebond_distributions( - unbonding_amounts: Vec<(DerivativeIndex, Balance)>, - input: Balance, - ) -> Vec<(DerivativeIndex, Balance)>; -} - pub trait Streaming { fn create( sender: AccountId, diff --git a/crates/traits/src/ump.rs b/crates/traits/src/ump.rs deleted file mode 100644 index 47aaef04bf..0000000000 --- a/crates/traits/src/ump.rs +++ /dev/null @@ -1,340 +0,0 @@ -use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::pallet_prelude::Weight; -use frame_system::Config; -use primitives::{AccountId, Balance, BlockNumber, ParaId}; -use scale_info::TypeInfo; -use sp_runtime::{traits::StaticLookup, MultiSignature, RuntimeDebug}; -use sp_std::{boxed::Box, vec::Vec}; -use xcm::latest::MultiLocation; - -/// A destination account for payment. -#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum RewardDestination { - /// Pay into the stash account, increasing the amount at stake accordingly. - Staked, - /// Pay into the stash account, not increasing the amount at stake. - Stash, - /// Pay into the controller account. - Controller, - /// Pay into a specified account. - Account(AccountId), - /// Receive no reward. - None, -} - -/// Relaychain staking.bond call arguments -#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct StakingBondCall { - /// Controller account - pub controller: ::Source, - /// Bond amount - #[codec(compact)] - pub value: u128, - /// A destination account for payment. - pub payee: RewardDestination, -} - -/// Relaychain staking.bond_extra call arguments -#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct StakingBondExtraCall { - /// Rebond amount - #[codec(compact)] - pub value: u128, -} - -/// Relaychain staking.unbond call arguments -#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct StakingUnbondCall { - /// Unbond amount - #[codec(compact)] - pub value: u128, -} - -/// Relaychain staking.rebond call arguments -#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct StakingRebondCall { - /// Rebond amount - #[codec(compact)] - pub value: u128, -} - -/// Relaychain staking.withdraw_unbonded call arguments -#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct StakingWithdrawUnbondedCall { - /// Withdraw amount - pub num_slashing_spans: u32, -} - -/// Relaychain staking.nominate call arguments -#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct StakingNominateCall { - /// List of nominate `targets` - pub targets: Vec<::Source>, -} - -/// Relaychain staking.payout_stakers call arguments -#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct StakingPayoutStakersCall { - /// Stash account of validator - pub validator_stash: T::AccountId, - /// EraIndex - pub era: u32, -} - -#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum StakingCall { - #[codec(index = 0)] - Bond(StakingBondCall), - #[codec(index = 1)] - BondExtra(StakingBondExtraCall), - #[codec(index = 2)] - Unbond(StakingUnbondCall), - #[codec(index = 3)] - WithdrawUnbonded(StakingWithdrawUnbondedCall), - #[codec(index = 5)] - Nominate(StakingNominateCall), - #[codec(index = 18)] - PayoutStakers(StakingPayoutStakersCall), - #[codec(index = 19)] - Rebond(StakingRebondCall), -} - -/// Relaychain balances.transfer_keep_alive call arguments -#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct BalancesTransferKeepAliveCall { - /// dest account - pub dest: ::Source, - /// transfer amount - #[codec(compact)] - pub value: u128, -} - -/// Relaychain balances.transfer_all call arguments -#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct BalancesTransferAllCall { - /// dest account - pub dest: ::Source, - pub keep_alive: bool, -} - -#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum BalancesCall { - #[codec(index = 3)] - TransferKeepAlive(BalancesTransferKeepAliveCall), - #[codec(index = 4)] - TransferAll(BalancesTransferAllCall), -} - -#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct CrowdloansContributeCall { - /// - `crowdloan`: The crowdloan who you are contributing to - #[codec(compact)] - pub index: ParaId, - /// - `value`: The amount of tokens you want to contribute to a parachain. - #[codec(compact)] - pub value: u128, - // `signature`: The signature if the fund has a verifier - pub signature: Option, -} - -#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct CrowdloansWithdrawCall { - /// - `who`: The account whose contribution should be withdrawn. - pub who: T::AccountId, - /// - `index`: The parachain to whose crowdloan the contribution was made. - #[codec(compact)] - pub index: ParaId, -} - -#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct CrowdloansAddMemoCall { - /// - `index`: The parachain to whose crowdloan the contribution was made. - pub index: ParaId, - pub memo: Vec, -} - -#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum CrowdloansCall { - #[codec(index = 1)] - Contribute(CrowdloansContributeCall), - #[codec(index = 2)] - Withdraw(CrowdloansWithdrawCall), - #[codec(index = 6)] - AddMemo(CrowdloansAddMemoCall), -} - -#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct SystemRemarkCall { - pub remark: Vec, -} - -#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum SystemCall { - #[codec(index = 1)] - Remark(SystemRemarkCall), -} - -#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct ProxyProxyCall { - pub real: AccountId, - pub force_proxy_type: Option, - pub call: RelaychainCall, -} - -#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct ProxyAddProxyCall { - pub delegate: AccountId, - pub proxy_type: Option, - pub delay: BlockNumber, -} - -#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct ProxyRemoveProxyCall { - pub delegate: AccountId, - pub proxy_type: Option, - pub delay: BlockNumber, -} - -/// The type used to represent the kinds of proxying allowed. -#[derive( - Copy, - Clone, - Eq, - PartialEq, - Ord, - PartialOrd, - Encode, - Decode, - RuntimeDebug, - MaxEncodedLen, - TypeInfo, -)] -pub enum ProxyType { - Any = 0_isize, - NonTransfer = 1_isize, - Governance = 2_isize, - Staking = 3_isize, -} - -impl Default for ProxyType { - fn default() -> Self { - Self::Any - } -} - -#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum ProxyCall { - #[codec(index = 0)] - Proxy(ProxyProxyCall), - #[codec(index = 1)] - AddProxy(ProxyAddProxyCall), - #[codec(index = 2)] - RemoveProxy(ProxyRemoveProxyCall), -} - -/// Relaychain utility.as_derivative call arguments -#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct UtilityAsDerivativeCall { - /// derivative index - pub index: u16, - /// call - pub call: RelaychainCall, -} - -/// Relaychain utility.batch_all call arguments -#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct UtilityBatchAllCall { - /// calls - pub calls: Vec, -} - -#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum UtilityCall { - #[codec(index = 1)] - AsDerivative(UtilityAsDerivativeCall), - #[codec(index = 2)] - BatchAll(UtilityBatchAllCall), -} - -#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum KusamaCall { - #[codec(index = 0)] - System(SystemCall), - #[codec(index = 4)] - Balances(BalancesCall), - #[codec(index = 6)] - Staking(StakingCall), - #[codec(index = 22)] - Proxy(Box>), - #[codec(index = 24)] - Utility(Box>), - #[codec(index = 73)] - Crowdloans(CrowdloansCall), -} - -#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum PolkadotCall { - #[codec(index = 0)] - System(SystemCall), - #[codec(index = 5)] - Balances(BalancesCall), - #[codec(index = 7)] - Staking(StakingCall), - #[codec(index = 26)] - Utility(Box>), - #[codec(index = 29)] - Proxy(Box>), - #[codec(index = 73)] - Crowdloans(CrowdloansCall), -} - -#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct XcmWeightFeeMisc { - pub weight: Weight, - pub fee: Balance, -} - -impl Default for XcmWeightFeeMisc { - fn default() -> Self { - let default_weight = 10_000_000_000; - let default_fee = 10_000_000_000; - XcmWeightFeeMisc { - weight: default_weight, - fee: default_fee, - } - } -} - -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum XcmCall { - Bond, - BondExtra, - Unbond, - Rebond, - WithdrawUnbonded, - Nominate, - Contribute, - Withdraw, - AddMemo, - TransferToSiblingchain(Box), - Proxy, - AddProxy, - RemoveProxy, -} - -#[macro_export] -macro_rules! switch_relay { - ({ $( $code:tt )* }) => { - if ::RelayNetwork::get() == NetworkId::Polkadot { - use pallet_traits::ump::PolkadotCall as RelaychainCall; - - $( $code )* - } else if ::RelayNetwork::get() == NetworkId::Kusama { - use pallet_traits::ump::KusamaCall as RelaychainCall; - - $( $code )* - } else { - unreachable!() - } - } -} diff --git a/crates/traits/src/xcm.rs b/crates/traits/src/xcm.rs deleted file mode 100644 index 165d27c7ac..0000000000 --- a/crates/traits/src/xcm.rs +++ /dev/null @@ -1,504 +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. - -use crate::CurrencyId; - -use codec::{Decode, Encode}; -use frame_support::{ - traits::{ - tokens::{ - fungibles::{Inspect, Mutate, Transfer}, - BalanceConversion, - }, - Get, - }, - weights::{constants::WEIGHT_PER_SECOND, Weight}, -}; -use scale_info::TypeInfo; -use sp_core::H256; -use sp_runtime::traits::{BlakeTwo256, Convert, Hash as THash, SaturatedConversion, Zero}; -use sp_std::{borrow::Borrow, marker::PhantomData, result}; -use xcm::latest::{ - prelude::*, AssetId as xcmAssetId, Error as XcmError, Fungibility, Junction::AccountId32, - MultiLocation, NetworkId, -}; -use xcm_builder::TakeRevenue; -use xcm_executor::traits::{ - Convert as MoreConvert, MatchesFungible, MatchesFungibles, TransactAsset, WeightTrader, -}; - -/// Converter struct implementing `AssetIdConversion` converting a numeric asset ID -/// (must be `TryFrom/TryInto`) into a MultiLocation Value and Viceversa through -/// an intermediate generic type AssetType. -/// The trait bounds enforce is that the AssetTypeGetter trait is also implemented for -/// AssetIdInfoGetter -pub struct AsAssetType( - PhantomData<(AssetId, AssetType, AssetIdInfoGetter)>, -); -impl xcm_executor::traits::Convert - for AsAssetType -where - AssetId: Clone, - AssetType: From + Into> + Clone, - AssetIdInfoGetter: AssetTypeGetter, -{ - fn convert_ref(id: impl Borrow) -> Result { - if let Some(asset_id) = AssetIdInfoGetter::get_asset_id(id.borrow().clone().into()) { - Ok(asset_id) - } else { - Err(()) - } - } - - fn reverse_ref(what: impl Borrow) -> Result { - if let Some(asset_type) = AssetIdInfoGetter::get_asset_type(what.borrow().clone()) { - if let Some(location) = asset_type.into() { - Ok(location) - } else { - Err(()) - } - } else { - Err(()) - } - } -} - -/// Instructs how to convert accountId into a MultiLocation -pub struct AccountIdToMultiLocation(sp_std::marker::PhantomData); -impl sp_runtime::traits::Convert - for AccountIdToMultiLocation -where - AccountId: Into<[u8; 32]>, -{ - fn convert(account: AccountId) -> MultiLocation { - MultiLocation { - parents: 0, - interior: X1(AccountId32 { - network: NetworkId::Any, - id: account.into(), - }), - } - } -} - -// We need to know how to charge for incoming assets -// This takes the first fungible asset, and takes whatever UnitPerSecondGetter establishes -// UnitsToWeightRatio trait, which needs to be implemented by AssetIdInfoGetter -pub struct FirstAssetTrader< - AssetType: From + Clone, - AssetIdInfoGetter: UnitsToWeightRatio, - R: TakeRevenue, ->( - Weight, - Option<(MultiLocation, u128, u128)>, - PhantomData<(AssetType, AssetIdInfoGetter, R)>, -); -impl< - AssetType: From + Clone, - AssetIdInfoGetter: UnitsToWeightRatio, - R: TakeRevenue, - > WeightTrader for FirstAssetTrader -{ - fn new() -> Self { - FirstAssetTrader(0, None, PhantomData) - } - - fn buy_weight( - &mut self, - weight: Weight, - payment: xcm_executor::Assets, - ) -> Result { - let first_asset = payment - .fungible_assets_iter() - .next() - .ok_or(XcmError::TooExpensive)?; - - // We are only going to check first asset for now. This should be sufficient for simple token - // transfers. We will see later if we change this. - match (first_asset.id, first_asset.fun) { - (xcmAssetId::Concrete(id), Fungibility::Fungible(_)) => { - let asset_type: AssetType = id.clone().into(); - // Shortcut if we know the asset is not supported - // This involves the same db read per block, mitigating any attack based on - // non-supported assets - if !AssetIdInfoGetter::payment_is_supported(asset_type.clone()) { - return Err(XcmError::TooExpensive); - } - - let units_per_second = AssetIdInfoGetter::get_units_per_second(asset_type) - .ok_or(XcmError::TooExpensive)?; - let amount = - units_per_second.saturating_mul(weight as u128) / (WEIGHT_PER_SECOND as u128); - - // We dont need to proceed if the amount is 0 - // For cases (specially tests) where the asset is very cheap with respect - // to the weight needed - if amount.is_zero() { - return Ok(payment); - } - - let required = MultiAsset { - fun: Fungibility::Fungible(amount), - id: xcmAssetId::Concrete(id.clone()), - }; - let unused = payment - .checked_sub(required) - .map_err(|_| XcmError::TooExpensive)?; - self.0 = self.0.saturating_add(weight); - - // In case the asset matches the one the trader already stored before, add - // to later refund - - // Else we are always going to subtract the weight if we can, but we latter do - // not refund it - - // In short, we only refund on the asset the trader first successfully was able - // to pay for an execution - let new_asset = match self.1.clone() { - Some((prev_id, prev_amount, units_per_second)) => { - if prev_id == id { - Some((id, prev_amount.saturating_add(amount), units_per_second)) - } else { - None - } - } - None => Some((id, amount, units_per_second)), - }; - - // Due to the trait bound, we can only refund one asset. - if let Some(new_asset) = new_asset { - self.0 = self.0.saturating_add(weight); - self.1 = Some(new_asset); - }; - - Ok(unused) - } - _ => Err(XcmError::TooExpensive), - } - } - - fn refund_weight(&mut self, weight: Weight) -> Option { - if let Some((id, prev_amount, units_per_second)) = self.1.clone() { - let weight = weight.min(self.0); - self.0 -= weight; - let amount = units_per_second * (weight as u128) / (WEIGHT_PER_SECOND as u128); - self.1 = Some(( - id.clone(), - prev_amount.saturating_sub(amount), - units_per_second, - )); - Some(MultiAsset { - fun: Fungibility::Fungible(amount), - id: xcmAssetId::Concrete(id), - }) - } else { - None - } - } -} - -/// Deal with spent fees, deposit them as dictated by R -impl< - AssetType: From + Clone, - AssetIdInfoGetter: UnitsToWeightRatio, - R: TakeRevenue, - > Drop for FirstAssetTrader -{ - fn drop(&mut self) { - if let Some((id, amount, _)) = self.1.clone() { - R::take_revenue((id, amount).into()); - } - } -} - -// Defines the trait to obtain a generic AssetType from a generic AssetId and viceversa -pub trait AssetTypeGetter { - // Get asset type from assetId - fn get_asset_type(asset_id: AssetId) -> Option; - - // Get assetId from assetType - fn get_asset_id(asset_type: AssetType) -> Option; -} - -// Defines the trait to obtain the units per second of a give asset_type for local execution -// This parameter will be used to charge for fees upon asset_type deposit -pub trait UnitsToWeightRatio { - // Whether payment in a particular asset_type is suppotrted - fn payment_is_supported(asset_type: AssetType) -> bool; - // Get units per second from asset type - fn get_units_per_second(asset_type: AssetType) -> Option; -} - -/// XCM fee depositor to which we implement the TakeRevenue trait -/// It receives a fungibles::Mutate implemented argument, a matcher to convert MultiAsset into -/// AssetId and amount, and the fee receiver account -pub struct XcmFeesToAccount( - PhantomData<(Assets, Matcher, AccountId, ReceiverAccount)>, -); -impl< - Assets: Mutate, - Matcher: MatchesFungibles, - AccountId: Clone, - ReceiverAccount: Get, - > TakeRevenue for XcmFeesToAccount -{ - fn take_revenue(revenue: MultiAsset) { - match Matcher::matches_fungibles(&revenue) { - Ok((asset_id, amount)) => { - if !amount.is_zero() { - let ok = Assets::mint_into(asset_id, &ReceiverAccount::get(), amount).is_ok(); - debug_assert!(ok, "`mint_into` cannot generally fail; qed"); - } - } - Err(_) => log::debug!( - target: "xcm", - "take revenue failed matching fungible" - ), - } - } -} - -// Our AssetType. For now we only handle Xcm Assets -#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] -pub enum AssetType { - Xcm(MultiLocation), -} - -impl Default for AssetType { - fn default() -> Self { - Self::Xcm(MultiLocation::here()) - } -} - -impl From for AssetType { - fn from(location: MultiLocation) -> Self { - Self::Xcm(location) - } -} - -impl From for Option { - fn from(asset: AssetType) -> Option { - match asset { - AssetType::Xcm(location) => Some(location), - } - } -} - -// Implementation on how to retrieve the AssetId from an AssetType -// We simply hash the AssetType and take the lowest 32 bits -impl From for CurrencyId { - fn from(asset: AssetType) -> CurrencyId { - match asset { - AssetType::Xcm(id) => { - let mut result: [u8; 4] = [0u8; 4]; - let hash: H256 = id.using_encoded(BlakeTwo256::hash); - result.copy_from_slice(&hash.as_fixed_bytes()[0..4]); - u32::from_le_bytes(result) - } - } - } -} - -// How to convert from CurrencyId to MultiLocation -pub struct CurrencyIdtoMultiLocation( - sp_std::marker::PhantomData<(LegacyAssetConverter, ForeignAssetConverter)>, -); -impl - sp_runtime::traits::Convert> - for CurrencyIdtoMultiLocation -where - LegacyAssetConverter: Convert>, - ForeignAssetConverter: xcm_executor::traits::Convert, -{ - fn convert(currency_id: CurrencyId) -> Option { - let mut multi_location = LegacyAssetConverter::convert(currency_id); - multi_location = match multi_location { - Some(_) => multi_location, - None => ForeignAssetConverter::reverse_ref(¤cy_id).ok(), - }; - multi_location - } -} - -pub struct MultiCurrencyAdapter< - MultiCurrency, - Match, - AccountId, - Balance, - AccountIdConvert, - CurrencyIdConvert, - NativeCurrencyId, - ExistentialDeposit, - GiftAccount, - GiftConvert, ->( - PhantomData<( - MultiCurrency, - Match, - AccountId, - Balance, - AccountIdConvert, - CurrencyIdConvert, - NativeCurrencyId, - ExistentialDeposit, - GiftAccount, - GiftConvert, - )>, -); - -enum Error { - /// `MultiLocation` to `AccountId` Conversion failed. - AccountIdConversionFailed, - /// `CurrencyId` conversion failed. - CurrencyIdConversionFailed, -} - -impl From for XcmError { - fn from(e: Error) -> Self { - match e { - Error::AccountIdConversionFailed => { - XcmError::FailedToTransactAsset("AccountIdConversionFailed") - } - Error::CurrencyIdConversionFailed => { - XcmError::FailedToTransactAsset("CurrencyIdConversionFailed") - } - } - } -} - -impl< - MultiCurrency: Inspect - + Mutate - + Transfer, - Match: MatchesFungible, - AccountId: sp_std::fmt::Debug + Clone, - Balance: frame_support::traits::tokens::Balance, - AccountIdConvert: MoreConvert, - CurrencyIdConvert: Convert>, - NativeCurrencyId: Get, - ExistentialDeposit: Get, - GiftAccount: Get, - GiftConvert: BalanceConversion, - > TransactAsset - for MultiCurrencyAdapter< - MultiCurrency, - Match, - AccountId, - Balance, - AccountIdConvert, - CurrencyIdConvert, - NativeCurrencyId, - ExistentialDeposit, - GiftAccount, - GiftConvert, - > -{ - fn deposit_asset(asset: &MultiAsset, location: &MultiLocation) -> XcmResult { - match ( - AccountIdConvert::convert_ref(location), - CurrencyIdConvert::convert(asset.clone()), - Match::matches_fungible(asset), - ) { - // known asset - (Ok(who), Some(currency_id), Some(amount)) => { - if let MultiAsset { - id: - AssetId::Concrete(MultiLocation { - parents: 1, - interior: Here, - }), - .. - } = asset - { - let gift_account = GiftAccount::get(); - let native_currency_id = NativeCurrencyId::get(); - let gift_amount = - GiftConvert::to_asset_balance(amount.saturated_into(), currency_id) - .unwrap_or_else(|_| Zero::zero()); - let beneficiary_native_balance = - MultiCurrency::reducible_balance(native_currency_id, &who, true); - let reducible_balance = - MultiCurrency::reducible_balance(native_currency_id, &gift_account, false); - - if !gift_amount.is_zero() - && reducible_balance >= gift_amount - && beneficiary_native_balance < gift_amount - { - let diff = gift_amount - beneficiary_native_balance; - if let Err(e) = MultiCurrency::transfer( - native_currency_id, - &gift_account, - &who, - diff, - false, - ) { - log::error!( - target: "xcm::deposit_asset", - "who: {:?}, currency_id: {:?}, amount: {:?}, native_currency_id: {:?}, gift_amount: {:?}, err: {:?}", - who, - currency_id, - amount, - native_currency_id, - diff, - e - ); - } - } - } - - MultiCurrency::mint_into(currency_id, &who, amount) - .map_err(|e| XcmError::FailedToTransactAsset(e.into())) - } - _ => Err(XcmError::AssetNotFound), - } - } - - fn withdraw_asset( - asset: &MultiAsset, - location: &MultiLocation, - ) -> result::Result { - // throw AssetNotFound error here if not match in order to reach the next foreign transact in tuple - let amount: MultiCurrency::Balance = Match::matches_fungible(asset) - .ok_or(XcmError::AssetNotFound)? - .saturated_into(); - let who = AccountIdConvert::convert_ref(location) - .map_err(|_| XcmError::from(Error::AccountIdConversionFailed))?; - let currency_id = CurrencyIdConvert::convert(asset.clone()) - .ok_or_else(|| XcmError::from(Error::CurrencyIdConversionFailed))?; - MultiCurrency::burn_from(currency_id, &who, amount) - .map_err(|e| XcmError::FailedToTransactAsset(e.into()))?; - - Ok(asset.clone().into()) - } - - fn internal_transfer_asset( - asset: &MultiAsset, - from: &MultiLocation, - to: &MultiLocation, - ) -> result::Result { - let from_account = AccountIdConvert::convert_ref(from) - .map_err(|_| XcmError::from(Error::AccountIdConversionFailed))?; - let to_account = AccountIdConvert::convert_ref(to) - .map_err(|_| XcmError::from(Error::AccountIdConversionFailed))?; - let currency_id = CurrencyIdConvert::convert(asset.clone()) - .ok_or_else(|| XcmError::from(Error::CurrencyIdConversionFailed))?; - let amount: MultiCurrency::Balance = Match::matches_fungible(asset) - .ok_or(XcmError::AssetNotFound)? - .saturated_into(); - MultiCurrency::transfer(currency_id, &from_account, &to_account, amount, true) - .map_err(|e| XcmError::FailedToTransactAsset(e.into()))?; - - Ok(asset.clone().into()) - } -} diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 2ef88eda30..76482b9210 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -11,13 +11,15 @@ pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; use sp_runtime::{ generic, traits::{BlakeTwo256, IdentifyAccount, Verify}, - FixedI128, FixedPointNumber, FixedU128, MultiSignature, RuntimeDebug, + FixedI128, FixedPointNumber, FixedU128, MultiSignature, RuntimeDebug, Permill, }; use sp_std::{ convert::{TryFrom, TryInto}, prelude::*, }; +pub mod tokens; + pub use bitcoin::types::H256Le; pub const BITCOIN_TESTNET: &str = "bitcoin-testnet"; @@ -358,6 +360,21 @@ pub type UnsignedFixedPoint = FixedU128; /// The `Inner` type of the `UnsignedFixedPoint`. pub type UnsignedInner = u128; + +/// Loans pallet types + +pub type Price = FixedU128; +pub type Timestamp = u64; +pub type PriceDetail = (Price, Timestamp); +pub type Rate = FixedU128; +pub type Ratio = Permill; +pub type Shortfall = FixedU128; +pub type Liquidity = FixedU128; +pub const SECONDS_PER_YEAR: Timestamp = 365 * 24 * 60 * 60; +pub type LendingPoolCurrencyId = u32; + + + pub trait CurrencyInfo { fn name(&self) -> &str; fn symbol(&self) -> &str; diff --git a/primitives/src/tokens.rs b/primitives/src/tokens.rs index ea4855b6fe..c8c4207b13 100644 --- a/primitives/src/tokens.rs +++ b/primitives/src/tokens.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::CurrencyId; +use crate::LendingPoolCurrencyId as CurrencyId; // Native Token pub const HKO: CurrencyId = 0; diff --git a/standalone/runtime/Cargo.toml b/standalone/runtime/Cargo.toml index cb70c3e431..50ff00cb90 100644 --- a/standalone/runtime/Cargo.toml +++ b/standalone/runtime/Cargo.toml @@ -74,6 +74,7 @@ democracy = { path = "../../crates/democracy", default-features = false } annuity = { path = "../../crates/annuity", default-features = false } supply = { path = "../../crates/supply", default-features = false } clients-info = { path = "../../crates/clients-info", default-features = false } +pallet-loans = { path = "../../crates/loans", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } From 9122745aac2628539b32001f7b943212e2a1c03c Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Tue, 20 Sep 2022 13:08:32 +0200 Subject: [PATCH 03/58] feat(lend): use orml-tokens instead of pallet-assets --- Cargo.lock | 30 +-- crates/currency-adapter/Cargo.toml | 31 --- crates/currency-adapter/src/lib.rs | 221 --------------------- crates/loans/Cargo.toml | 7 +- crates/loans/src/mock.rs | 99 +++------ crates/loans/src/tests.rs | 80 ++++---- crates/loans/src/tests/edge_cases.rs | 12 +- crates/loans/src/tests/interest_rate.rs | 13 +- crates/loans/src/tests/liquidate_borrow.rs | 14 +- 9 files changed, 97 insertions(+), 410 deletions(-) delete mode 100644 crates/currency-adapter/Cargo.toml delete mode 100644 crates/currency-adapter/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 51483ce82a..cbc55821e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6105,20 +6105,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "pallet-assets" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.28#34a0621761c4a333cb2074ff720f7acbfb92dbb8" -dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "parity-scale-codec", - "scale-info", - "sp-runtime", - "sp-std", -] - [[package]] name = "pallet-aura" version = "4.0.0-dev" @@ -6318,18 +6304,6 @@ dependencies = [ "sp-std", ] -[[package]] -name = "pallet-currency-adapter" -version = "1.9.3" -dependencies = [ - "frame-support", - "frame-system", - "interbtc-primitives", - "parity-scale-codec", - "scale-info", - "sp-runtime", -] - [[package]] name = "pallet-democracy" version = "4.0.0-dev" @@ -6501,10 +6475,8 @@ dependencies = [ "interbtc-primitives", "num-traits", "orml-oracle", + "orml-tokens", "orml-traits", - "pallet-assets", - "pallet-balances", - "pallet-currency-adapter", "pallet-timestamp", "pallet-traits", "parity-scale-codec", diff --git a/crates/currency-adapter/Cargo.toml b/crates/currency-adapter/Cargo.toml deleted file mode 100644 index 410ecc43dc..0000000000 --- a/crates/currency-adapter/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -authors = ['Parallel Team'] -edition = '2021' -name = 'pallet-currency-adapter' -version = '1.9.3' - -[package.metadata.docs.rs] -targets = ['x86_64-unknown-linux-gnu'] - -[dependencies] -codec = { package = 'parity-scale-codec', version = '3.1.5', features = ['max-encoded-len'], default-features = false } -frame-support = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } -frame-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } -primitives = { package = 'interbtc-primitives', path = '../../primitives', default-features = false } -scale-info = { version = '2.1', default-features = false, features = ['derive'] } -sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } - -[features] -default = ['std'] -std = [ - 'codec/std', - 'frame-support/std', - 'frame-system/std', - 'sp-runtime/std', - 'scale-info/std', - 'primitives/std', -] -try-runtime = ['frame-support/try-runtime'] - -[lib] -doctest = false diff --git a/crates/currency-adapter/src/lib.rs b/crates/currency-adapter/src/lib.rs deleted file mode 100644 index 1fcf314076..0000000000 --- a/crates/currency-adapter/src/lib.rs +++ /dev/null @@ -1,221 +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. - -//! # Currency adapter pallet -//! -//! ## Overview -//! -//! This pallet works like a bridge between pallet-balances & pallet-assets - -#![cfg_attr(not(feature = "std"), no_std)] - -pub use pallet::*; - -use frame_support::{ - dispatch::DispatchResult, - pallet_prelude::*, - traits::{ - tokens::{ - fungible::{Inspect, Mutate, Transfer}, - fungibles::{Inspect as Inspects, Mutate as Mutates, Transfer as Transfers}, - DepositConsequence, WithdrawConsequence, - }, - Get, LockIdentifier, WithdrawReasons, - }, -}; -use primitives::{Balance, LendingPoolCurrencyId as CurrencyId}; -use sp_runtime::DispatchError; - -type AssetIdOf = - <::Assets as Inspects<::AccountId>>::AssetId; -type BalanceOf = - <::Assets as Inspects<::AccountId>>::Balance; - -const CURRENCY_ADAPTER_ID: LockIdentifier = *b"cadapter"; - -#[frame_support::pallet] -pub mod pallet { - use super::*; - use frame_support::traits::LockableCurrency; - use frame_system::pallet_prelude::OriginFor; - - #[pallet::config] - pub trait Config: frame_system::Config { - type Assets: Transfers - + Inspects - + Mutates; - - type Balances: Inspect - + Mutate - + Transfer - + LockableCurrency; - - #[pallet::constant] - type GetNativeCurrencyId: Get>; - - // Origin which can lock asset balance - type LockOrigin: EnsureOrigin<::Origin>; - } - - #[pallet::pallet] - pub struct Pallet(_); - - #[pallet::error] - pub enum Error { - /// Not a native token - NotANativeToken, - } - - #[pallet::call] - impl Pallet { - #[pallet::weight(10_000)] - pub fn force_set_lock( - origin: OriginFor, - asset: AssetIdOf, - who: T::AccountId, - #[pallet::compact] amount: BalanceOf, - ) -> DispatchResult { - T::LockOrigin::ensure_origin(origin)?; - ensure!( - asset == T::GetNativeCurrencyId::get(), - Error::::NotANativeToken - ); - T::Balances::set_lock(CURRENCY_ADAPTER_ID, &who, amount, WithdrawReasons::all()); - Ok(()) - } - - #[pallet::weight(10_000)] - pub fn force_remove_lock( - origin: OriginFor, - asset: AssetIdOf, - who: T::AccountId, - ) -> DispatchResult { - T::LockOrigin::ensure_origin(origin)?; - ensure!( - asset == T::GetNativeCurrencyId::get(), - Error::::NotANativeToken - ); - T::Balances::remove_lock(CURRENCY_ADAPTER_ID, &who); - Ok(()) - } - } -} - -impl Inspects for Pallet { - type AssetId = AssetIdOf; - type Balance = BalanceOf; - - fn total_issuance(asset: Self::AssetId) -> Self::Balance { - if asset == T::GetNativeCurrencyId::get() { - T::Balances::total_issuance() - } else { - T::Assets::total_issuance(asset) - } - } - - fn minimum_balance(asset: Self::AssetId) -> Self::Balance { - if asset == T::GetNativeCurrencyId::get() { - T::Balances::minimum_balance() - } else { - T::Assets::minimum_balance(asset) - } - } - - fn balance(asset: Self::AssetId, who: &T::AccountId) -> Self::Balance { - if asset == T::GetNativeCurrencyId::get() { - T::Balances::balance(who) - } else { - T::Assets::balance(asset, who) - } - } - - fn reducible_balance( - asset: Self::AssetId, - who: &T::AccountId, - keep_alive: bool, - ) -> Self::Balance { - if asset == T::GetNativeCurrencyId::get() { - T::Balances::reducible_balance(who, keep_alive) - } else { - T::Assets::reducible_balance(asset, who, keep_alive) - } - } - - fn can_deposit( - asset: Self::AssetId, - who: &T::AccountId, - amount: Self::Balance, - mint: bool, - ) -> DepositConsequence { - if asset == T::GetNativeCurrencyId::get() { - T::Balances::can_deposit(who, amount, mint) - } else { - T::Assets::can_deposit(asset, who, amount, mint) - } - } - - fn can_withdraw( - asset: Self::AssetId, - who: &T::AccountId, - amount: Self::Balance, - ) -> WithdrawConsequence { - if asset == T::GetNativeCurrencyId::get() { - T::Balances::can_withdraw(who, amount) - } else { - T::Assets::can_withdraw(asset, who, amount) - } - } -} - -impl Mutates for Pallet { - fn mint_into( - asset: Self::AssetId, - who: &T::AccountId, - amount: Self::Balance, - ) -> DispatchResult { - if asset == T::GetNativeCurrencyId::get() { - T::Balances::mint_into(who, amount) - } else { - T::Assets::mint_into(asset, who, amount) - } - } - - fn burn_from( - asset: Self::AssetId, - who: &T::AccountId, - amount: Self::Balance, - ) -> Result { - if asset == T::GetNativeCurrencyId::get() { - T::Balances::burn_from(who, amount) - } else { - T::Assets::burn_from(asset, who, amount) - } - } -} - -impl Transfers for Pallet { - fn transfer( - asset: Self::AssetId, - source: &T::AccountId, - dest: &T::AccountId, - amount: Self::Balance, - keep_alive: bool, - ) -> Result { - if asset == T::GetNativeCurrencyId::get() { - T::Balances::transfer(source, dest, amount, keep_alive) - } else { - T::Assets::transfer(asset, source, dest, amount, keep_alive) - } - } -} diff --git a/crates/loans/Cargo.toml b/crates/loans/Cargo.toml index 450d13e644..6147f34a9a 100644 --- a/crates/loans/Cargo.toml +++ b/crates/loans/Cargo.toml @@ -15,8 +15,7 @@ frame-system = { git = 'https://github.com/paritytech/substrate.git', bran num-traits = { default-features = false, version = '0.2' } orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" } orml-oracle = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" } -pallet-assets = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } -pallet-balances = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } pallet-timestamp = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } pallet-traits = { path = '../traits', default-features = false } @@ -28,7 +27,6 @@ sp-runtime = { git = 'https://github.com/paritytech/substrate.git', bran sp-std = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } [dev-dependencies] -pallet-currency-adapter = { path = '../currency-adapter' } sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28' } [features] @@ -39,13 +37,12 @@ std = [ 'frame-support/std', 'frame-system/std', 'frame-benchmarking/std', + "orml-tokens/std", 'orml-traits/std', 'primitives/std', 'sp-runtime/std', 'sp-std/std', 'sp-io/std', - 'pallet-assets/std', - 'pallet-balances/std', 'pallet-timestamp/std', 'serde', 'scale-info/std', diff --git a/crates/loans/src/mock.rs b/crates/loans/src/mock.rs index 2decde1c3e..9f50518494 100644 --- a/crates/loans/src/mock.rs +++ b/crates/loans/src/mock.rs @@ -18,7 +18,7 @@ use frame_support::{ construct_runtime, parameter_types, traits::Everything, traits::SortedMembers, PalletId, }; use frame_system::{EnsureRoot, EnsureSignedBy}; -use orml_traits::{DataFeeder, DataProvider, DataProviderExtended}; +use orml_traits::{DataFeeder, DataProvider, DataProviderExtended, parameter_type_with_key}; use pallet_traits::{ DecimalProvider, ExchangeRateProvider, LiquidStakingCurrenciesProvider, VaultTokenCurrenciesFilter, VaultTokenExchangeRateProvider, @@ -45,11 +45,9 @@ construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system::{Pallet, Call, Storage, Config, Event}, - Balances: pallet_balances::{Pallet, Call, Storage, Event}, Loans: crate::{Pallet, Storage, Call, Event}, TimestampPallet: pallet_timestamp::{Pallet, Call, Storage, Inherent}, - Assets: pallet_assets::{Pallet, Call, Storage, Event}, - CurrencyAdapter: pallet_currency_adapter::{Pallet, Call}, + Tokens: orml_tokens::{Pallet, Call, Storage, Config, Event}, } ); @@ -76,7 +74,7 @@ impl frame_system::Config for Test { type BlockHashCount = BlockHashCount; type Version = (); type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; + type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); @@ -105,21 +103,28 @@ impl pallet_timestamp::Config for Test { type WeightInfo = (); } -parameter_types! { - pub const ExistentialDeposit: Balance = 1; - pub const MaxLocks: u32 = 50; +parameter_type_with_key! { + pub ExistentialDeposits: |_currency_id: CurrencyId| -> Balance { + Zero::zero() + }; } -impl pallet_balances::Config for Test { - type Balance = Balance; - type DustRemoval = (); +pub type RawAmount = i128; + +impl orml_tokens::Config for Test { type Event = Event; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = pallet_balances::weights::SubstrateWeight; + type Balance = Balance; + type Amount = RawAmount; + type CurrencyId = CurrencyId; + type WeightInfo = (); + type ExistentialDeposits = ExistentialDeposits; + type OnDust = (); type MaxLocks = MaxLocks; - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; + type DustRemovalWhitelist = Everything; + type MaxReserves = ConstU32<0>; // we don't use named reserves + type ReserveIdentifier = (); // we don't use named reserves + type OnNewTokenAccount = (); + type OnKilledTokenAccount = (); } // pallet-price is using for benchmark compilation @@ -263,29 +268,7 @@ impl PriceFeeder for MockPriceFeeder { } parameter_types! { - pub const AssetDeposit: u64 = 1; - pub const ApprovalDeposit: u64 = 1; - pub const AssetAccountDeposit: u64 = 1; - pub const StringLimit: u32 = 50; - pub const MetadataDepositBase: u64 = 1; - pub const MetadataDepositPerByte: u64 = 1; -} - -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 AssetAccountDeposit = AssetAccountDeposit; - type ApprovalDeposit = ApprovalDeposit; - type StringLimit = StringLimit; - type Freezer = (); - type Extra = (); - type WeightInfo = (); + pub const MaxLocks: u32 = 50; } parameter_types! { @@ -302,22 +285,11 @@ impl Config for Test { type UpdateOrigin = EnsureRoot; type WeightInfo = (); type UnixTime = TimestampPallet; - type Assets = CurrencyAdapter; + type Assets = Tokens; type RewardAssetId = RewardAssetId; type LiquidationFreeAssetId = LiquidationFreeAssetId; } -parameter_types! { - pub const NativeCurrencyId: CurrencyId = HKO; -} - -impl pallet_currency_adapter::Config for Test { - type Assets = Assets; - type Balances = Balances; - type GetNativeCurrencyId = NativeCurrencyId; - type LockOrigin = EnsureRoot; -} - pub(crate) fn new_test_ext() -> sp_io::TestExternalities { let t = frame_system::GenesisConfig::default() .build_storage::() @@ -326,21 +298,16 @@ pub(crate) fn new_test_ext() -> sp_io::TestExternalities { let mut ext = sp_io::TestExternalities::new(t); ext.execute_with(|| { // Init assets - Balances::set_balance(Origin::root(), DAVE, unit(1000), unit(0)).unwrap(); - Assets::force_create(Origin::root(), DOT, ALICE, true, 1).unwrap(); - Assets::force_create(Origin::root(), KSM, ALICE, true, 1).unwrap(); - Assets::force_create(Origin::root(), USDT, ALICE, true, 1).unwrap(); - Assets::force_create(Origin::root(), SDOT, ALICE, true, 1).unwrap(); - Assets::force_create(Origin::root(), CDOT_6_13, ALICE, true, 1).unwrap(); - - Assets::mint(Origin::signed(ALICE), KSM, ALICE, unit(1000)).unwrap(); - Assets::mint(Origin::signed(ALICE), DOT, ALICE, unit(1000)).unwrap(); - Assets::mint(Origin::signed(ALICE), USDT, ALICE, unit(1000)).unwrap(); - Assets::mint(Origin::signed(ALICE), CDOT_6_13, ALICE, unit(1000)).unwrap(); - Assets::mint(Origin::signed(ALICE), KSM, BOB, unit(1000)).unwrap(); - Assets::mint(Origin::signed(ALICE), DOT, BOB, unit(1000)).unwrap(); - Assets::mint(Origin::signed(ALICE), DOT, DAVE, unit(1000)).unwrap(); - Assets::mint(Origin::signed(ALICE), USDT, DAVE, unit(1000)).unwrap(); + + Tokens::set_balance(Origin::root(), ALICE, KSM, 1000_000000000000, 0).unwrap(); + Tokens::set_balance(Origin::root(), ALICE, DOT, 1000_000000000000, 0).unwrap(); + Tokens::set_balance(Origin::root(), ALICE, USDT, 1000_000000000000, 0).unwrap(); + Tokens::set_balance(Origin::root(), ALICE, CDOT_6_13, 1000_000000000000, 0).unwrap(); + Tokens::set_balance(Origin::root(), BOB, KSM, 1000_000000000000, 0).unwrap(); + Tokens::set_balance(Origin::root(), BOB, DOT, 1000_000000000000, 0).unwrap(); + Tokens::set_balance(Origin::root(), DAVE, DOT, 1000_000000000000, 0).unwrap(); + Tokens::set_balance(Origin::root(), DAVE, USDT, 1000_000000000000, 0).unwrap(); + Tokens::set_balance(Origin::root(), DAVE, HKO, 1000_000000000000, 0).unwrap(); // Init Markets Loans::add_market(Origin::root(), HKO, market_mock(PHKO)).unwrap(); diff --git a/crates/loans/src/tests.rs b/crates/loans/src/tests.rs index b9a8d7c372..1cd92bc2b2 100644 --- a/crates/loans/src/tests.rs +++ b/crates/loans/src/tests.rs @@ -31,11 +31,11 @@ use crate::mock::*; #[test] fn init_minting_ok() { new_test_ext().execute_with(|| { - assert_eq!(Assets::balance(KSM, ALICE), unit(1000)); - assert_eq!(Assets::balance(DOT, ALICE), unit(1000)); - assert_eq!(Assets::balance(USDT, ALICE), unit(1000)); - assert_eq!(Assets::balance(KSM, BOB), unit(1000)); - assert_eq!(Assets::balance(DOT, BOB), unit(1000)); + assert_eq!(Tokens::balance(KSM, &ALICE), unit(1000)); + assert_eq!(Tokens::balance(DOT, &ALICE), unit(1000)); + assert_eq!(Tokens::balance(USDT, &ALICE), unit(1000)); + assert_eq!(Tokens::balance(KSM, &BOB), unit(1000)); + assert_eq!(Tokens::balance(DOT, &BOB), unit(1000)); }); } @@ -68,7 +68,7 @@ fn init_markets_ok() { #[test] fn loans_native_token_works() { new_test_ext().execute_with(|| { - assert_eq!(::Assets::balance(HKO, &DAVE), unit(1000)); + assert_eq!(Tokens::balance(HKO, &DAVE), unit(1000)); assert_eq!(Loans::market(HKO).unwrap().state, MarketState::Active); assert_eq!(BorrowIndex::::get(HKO), Rate::one()); assert_eq!( @@ -103,7 +103,7 @@ fn loans_native_token_works() { let borrow_snapshot = Loans::account_borrows(HKO, DAVE); assert_eq!(borrow_snapshot.principal, unit(100)); assert_eq!(borrow_snapshot.borrow_index, Loans::borrow_index(HKO)); - assert_eq!(::Assets::balance(HKO, &DAVE), unit(100),); + assert_eq!(Tokens::balance(HKO, &DAVE), unit(100),); }) } @@ -120,9 +120,9 @@ fn mint_works() { .saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), unit(100) ); - assert_eq!(::Assets::balance(DOT, &ALICE), unit(900),); + assert_eq!(Tokens::balance(DOT, &ALICE), unit(900),); assert_eq!( - ::Assets::balance(DOT, &Loans::account_id()), + Tokens::balance(DOT, &Loans::account_id()), unit(100), ); }) @@ -150,11 +150,12 @@ fn mint_must_return_err_when_overflows_occur() { ); // Deposit OVERFLOW_DEPOSIT DOT for CHARLIE - assert_ok!(Assets::mint( - Origin::signed(ALICE), - DOT, + assert_ok!(Tokens::set_balance( + Origin::root(), CHARLIE, - OVERFLOW_DEPOSIT + DOT, + OVERFLOW_DEPOSIT, + 0 )); // Amount is too large, OVERFLOW_DEPOSIT / 0.0X == Overflow @@ -256,7 +257,7 @@ fn redeem_works() { .saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), unit(80) ); - assert_eq!(::Assets::balance(DOT, &ALICE), unit(920),); + assert_eq!(Tokens::balance(DOT, &ALICE), unit(920),); }) } @@ -343,7 +344,7 @@ fn redeem_all_works() { .saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), 0, ); - assert_eq!(::Assets::balance(DOT, &ALICE), unit(1000),); + assert_eq!(Tokens::balance(DOT, &ALICE), unit(1000),); assert!(!AccountDeposits::::contains_key(DOT, &ALICE)) }) } @@ -479,7 +480,7 @@ fn borrow_works() { let borrow_snapshot = Loans::account_borrows(DOT, ALICE); assert_eq!(borrow_snapshot.principal, unit(100)); assert_eq!(borrow_snapshot.borrow_index, Loans::borrow_index(DOT)); - assert_eq!(::Assets::balance(DOT, &ALICE), unit(900),); + assert_eq!(Tokens::balance(DOT, &ALICE), unit(900),); }) } @@ -505,7 +506,7 @@ fn lf_borrow_works() { let borrow_snapshot = Loans::account_borrows(DOT, ALICE); assert_eq!(borrow_snapshot.principal, unit(100)); assert_eq!(borrow_snapshot.borrow_index, Loans::borrow_index(DOT)); - assert_eq!(::Assets::balance(DOT, &ALICE), unit(1100),); + assert_eq!(Tokens::balance(DOT, &ALICE), unit(1100),); }) } @@ -531,7 +532,7 @@ fn repay_borrow_works() { let borrow_snapshot = Loans::account_borrows(DOT, ALICE); assert_eq!(borrow_snapshot.principal, unit(70)); assert_eq!(borrow_snapshot.borrow_index, Loans::borrow_index(DOT)); - assert_eq!(::Assets::balance(DOT, &ALICE), unit(870),); + assert_eq!(Tokens::balance(DOT, &ALICE), unit(870),); }) } @@ -553,7 +554,7 @@ fn repay_borrow_all_works() { // DOT collateral: deposit = 200 // KSM: cash + borrow - repay = 1000 + 50 - 50 = 1000 // KSM borrow balance: borrow - repay = 50 - 50 = 0 - assert_eq!(::Assets::balance(DOT, &ALICE), unit(800),); + assert_eq!(Tokens::balance(DOT, &ALICE), unit(800),); assert_eq!( Loans::exchange_rate(DOT) .saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), @@ -623,10 +624,10 @@ fn add_reserves_works() { assert_eq!(Loans::total_reserves(DOT), unit(100)); assert_eq!( - ::Assets::balance(DOT, &Loans::account_id()), + Tokens::balance(DOT, &Loans::account_id()), unit(100), ); - assert_eq!(::Assets::balance(DOT, &ALICE), unit(900),); + assert_eq!(Tokens::balance(DOT, &ALICE), unit(900),); }) } @@ -641,10 +642,10 @@ fn reduce_reserves_works() { assert_eq!(Loans::total_reserves(DOT), unit(80)); assert_eq!( - ::Assets::balance(DOT, &Loans::account_id()), + Tokens::balance(DOT, &Loans::account_id()), unit(80), ); - assert_eq!(::Assets::balance(DOT, &ALICE), unit(920),); + assert_eq!(Tokens::balance(DOT, &ALICE), unit(920),); }) } @@ -873,11 +874,12 @@ fn get_price_works() { #[test] fn ensure_enough_cash_works() { new_test_ext().execute_with(|| { - assert_ok!(Assets::mint( - Origin::signed(ALICE), - KSM, + assert_ok!(Tokens::set_balance( + Origin::root(), Loans::account_id(), - unit(1000) + KSM, + unit(1000), + 0 )); assert_ok!(Loans::ensure_enough_cash(KSM, unit(1000))); TotalReserves::::insert(KSM, unit(10)); @@ -919,7 +921,7 @@ fn ensure_valid_exchange_rate_works() { #[test] fn withdraw_missing_reward_works() { new_test_ext().execute_with(|| { - assert_eq!(::Assets::balance(HKO, &DAVE), unit(1000)); + assert_eq!(Tokens::balance(HKO, &DAVE), unit(1000)); assert_ok!(Loans::add_reward(Origin::signed(DAVE), unit(100))); @@ -929,12 +931,12 @@ fn withdraw_missing_reward_works() { unit(40), )); - assert_eq!(::Assets::balance(HKO, &DAVE), unit(900)); + assert_eq!(Tokens::balance(HKO, &DAVE), unit(900)); - assert_eq!(::Assets::balance(HKO, &ALICE), unit(40)); + assert_eq!(Tokens::balance(HKO, &ALICE), unit(40)); assert_eq!( - ::Assets::balance(HKO, &Loans::reward_account_id().unwrap()), + Tokens::balance(HKO, &Loans::reward_account_id().unwrap()), unit(60) ); }) @@ -1143,14 +1145,14 @@ fn reward_calculation_one_palyer_in_multi_markets_works() { _run_to_block(80); assert_ok!(Loans::add_reward(Origin::signed(DAVE), unit(200))); assert_ok!(Loans::claim_reward(Origin::signed(ALICE))); - assert_eq!(::Assets::balance(HKO, &DAVE), unit(800)); + assert_eq!(Tokens::balance(HKO, &DAVE), unit(800)); assert_eq!( - almost_equal(::Assets::balance(HKO, &ALICE), unit(130)), + almost_equal(Tokens::balance(HKO, &ALICE), unit(130)), true ); assert_eq!( almost_equal( - ::Assets::balance(HKO, &Loans::reward_account_id().unwrap()), + Tokens::balance(HKO, &Loans::reward_account_id().unwrap()), unit(70) ), true @@ -1169,7 +1171,7 @@ fn reward_calculation_one_palyer_in_multi_markets_works() { _run_to_block(90); assert_ok!(Loans::claim_reward(Origin::signed(ALICE))); assert_eq!( - almost_equal(::Assets::balance(HKO, &ALICE), unit(140)), + almost_equal(Tokens::balance(HKO, &ALICE), unit(140)), true ); }) @@ -1259,18 +1261,18 @@ fn reward_calculation_multi_player_in_one_market_works() { assert_ok!(Loans::add_reward(Origin::signed(DAVE), unit(200))); assert_ok!(Loans::claim_reward_for_market(Origin::signed(ALICE), DOT)); assert_ok!(Loans::claim_reward_for_market(Origin::signed(BOB), DOT)); - assert_eq!(::Assets::balance(HKO, &DAVE), unit(800)); + assert_eq!(Tokens::balance(HKO, &DAVE), unit(800)); assert_eq!( - almost_equal(::Assets::balance(HKO, &ALICE), unit(58)), + almost_equal(Tokens::balance(HKO, &ALICE), unit(58)), true ); assert_eq!( - almost_equal(::Assets::balance(HKO, &BOB), unit(22)), + almost_equal(Tokens::balance(HKO, &BOB), unit(22)), true ); assert_eq!( almost_equal( - ::Assets::balance(HKO, &Loans::reward_account_id().unwrap()), + Tokens::balance(HKO, &Loans::reward_account_id().unwrap()), unit(120) ), true diff --git a/crates/loans/src/tests/edge_cases.rs b/crates/loans/src/tests/edge_cases.rs index d5f054b11b..3a69b168be 100644 --- a/crates/loans/src/tests/edge_cases.rs +++ b/crates/loans/src/tests/edge_cases.rs @@ -7,7 +7,7 @@ use sp_runtime::FixedPointNumber; #[test] fn exceeded_supply_cap() { new_test_ext().execute_with(|| { - Assets::mint(Origin::signed(ALICE), DOT, ALICE, million_unit(1001)).unwrap(); + Tokens::set_balance(Origin::root(), ALICE, DOT, million_unit(1001), 0).unwrap(); let amount = million_unit(501); assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, amount)); // Exceed upper bound. @@ -43,7 +43,7 @@ fn repay_borrow_all_no_underflow() { // Alice repay all borrow balance. total_borrows = total_borrows.saturating_sub(10000005) = 0. assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), KSM)); - assert_eq!(Assets::balance(KSM, &ALICE), unit(800) - 5); + assert_eq!(Tokens::balance(KSM, &ALICE), unit(800) - 5); assert_eq!( Loans::exchange_rate(DOT) @@ -91,7 +91,7 @@ fn redeem_all_should_be_accurate() { fn prevent_the_exchange_rate_attack() { new_test_ext().execute_with(|| { // Initialize Eve's balance - assert_ok!(::Assets::transfer( + assert_ok!(>::transfer( DOT, &ALICE, &EVE, @@ -101,16 +101,16 @@ fn prevent_the_exchange_rate_attack() { // Eve deposits a small amount assert_ok!(Loans::mint(Origin::signed(EVE), DOT, 1)); // !!! Eve transfer a big amount to Loans::account_id - assert_ok!(::Assets::transfer( + assert_ok!(>::transfer( DOT, &EVE, &Loans::account_id(), unit(100), false )); - assert_eq!(::Assets::balance(DOT, &EVE), 99999999999999); + assert_eq!(Tokens::balance(DOT, &EVE), 99999999999999); assert_eq!( - ::Assets::balance(DOT, &Loans::account_id()), + Tokens::balance(DOT, &Loans::account_id()), 100000000000001 ); assert_eq!( diff --git a/crates/loans/src/tests/interest_rate.rs b/crates/loans/src/tests/interest_rate.rs index d0c5350624..70fc3e963f 100644 --- a/crates/loans/src/tests/interest_rate.rs +++ b/crates/loans/src/tests/interest_rate.rs @@ -34,11 +34,12 @@ fn utilization_rate_works() { fn interest_rate_model_works() { new_test_ext().execute_with(|| { let rate_decimal: u128 = 1_000_000_000_000_000_000; - Assets::mint( - Origin::signed(ALICE), - DOT, + Tokens::set_balance( + Origin::root(), ALICE, + DOT, million_unit(1000) - unit(1000), + 0 ) .unwrap(); // Deposit 200 DOT and borrow 100 DOT @@ -194,7 +195,7 @@ fn accrue_interest_works_after_redeem() { 0, ); assert_eq!( - ::Assets::balance(DOT, &ALICE), + Tokens::balance(DOT, &ALICE), 819999999999999 ); }) @@ -220,7 +221,7 @@ fn accrue_interest_works_after_redeem_all() { 0, ); assert_eq!( - ::Assets::balance(DOT, &BOB), + Tokens::balance(DOT, &BOB), 1000000000003608 ); assert!(!AccountDeposits::::contains_key(DOT, &BOB)) @@ -258,7 +259,7 @@ fn accrue_interest_works_after_repay_all() { Rate::from_inner(1000000008561643835), ); assert_eq!( - ::Assets::balance(KSM, &ALICE), + Tokens::balance(KSM, &ALICE), 999999999571918 ); let borrow_snapshot = Loans::account_borrows(KSM, ALICE); diff --git a/crates/loans/src/tests/liquidate_borrow.rs b/crates/loans/src/tests/liquidate_borrow.rs index f0d107ee18..9dbd4fd4ea 100644 --- a/crates/loans/src/tests/liquidate_borrow.rs +++ b/crates/loans/src/tests/liquidate_borrow.rs @@ -1,11 +1,11 @@ use crate::{ mock::{ - new_test_ext, Assets, Loans, MockPriceFeeder, Origin, Test, ALICE, BOB, DOT, KSM, USDT, + new_test_ext, Tokens, Loans, MockPriceFeeder, Origin, Test, ALICE, BOB, DOT, KSM, USDT, }, tests::unit, Error, MarketState, }; -use frame_support::{assert_err, assert_noop, assert_ok}; +use frame_support::{assert_err, assert_noop, assert_ok, traits::fungibles::Inspect}; use primitives::{tokens::{CDOT_6_13, DOT_U}, Rate}; use sp_runtime::FixedPointNumber; @@ -168,15 +168,15 @@ fn full_workflow_works_as_expected() { // Alice KSM borrow balance: origin borrow balance - liquidate amount = 100 - 50 = 50 // Bob KSM: cash - deposit - repay = 1000 - 200 - 50 = 750 // Bob DOT collateral: incentive = 110-(110/1.1*0.03)=107 - assert_eq!(Assets::balance(USDT, &ALICE), unit(800),); + assert_eq!(Tokens::balance(USDT, &ALICE), unit(800),); assert_eq!( Loans::exchange_rate(USDT) .saturating_mul_int(Loans::account_deposits(USDT, ALICE).voucher_balance), unit(90), ); - assert_eq!(Assets::balance(KSM, &ALICE), unit(1100),); + assert_eq!(Tokens::balance(KSM, &ALICE), unit(1100),); assert_eq!(Loans::account_borrows(KSM, ALICE).principal, unit(50)); - assert_eq!(Assets::balance(KSM, &BOB), unit(750)); + assert_eq!(Tokens::balance(KSM, &BOB), unit(750)); assert_eq!( Loans::exchange_rate(USDT) .saturating_mul_int(Loans::account_deposits(USDT, BOB).voucher_balance), @@ -194,7 +194,7 @@ fn full_workflow_works_as_expected() { ), unit(3), ); - assert_eq!(Assets::balance(USDT, &ALICE), unit(800),); + assert_eq!(Tokens::balance(USDT, &ALICE), unit(800),); // reduce 2 dollar from incentive reserve to alice account assert_ok!(Loans::reduce_incentive_reserves( Origin::root(), @@ -210,7 +210,7 @@ fn full_workflow_works_as_expected() { unit(1), ); // 2 dollar transfer to alice - assert_eq!(Assets::balance(USDT, &ALICE), unit(800) + unit(2),); + assert_eq!(Tokens::balance(USDT, &ALICE), unit(800) + unit(2),); }) } From d1be2411f8a336abe5d9693475de3978ed26f26b Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Tue, 20 Sep 2022 18:32:37 +0200 Subject: [PATCH 04/58] feat(lend): configure lending pallet --- standalone/runtime/src/lib.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/standalone/runtime/src/lib.rs b/standalone/runtime/src/lib.rs index 235b999439..0a4096b387 100644 --- a/standalone/runtime/src/lib.rs +++ b/standalone/runtime/src/lib.rs @@ -65,7 +65,7 @@ pub use security::StatusCode; pub use primitives::{ self, AccountId, Balance, BlockNumber, CurrencyId, CurrencyId::Token, CurrencyInfo, Hash, Moment, Nonce, Signature, - SignedFixedPoint, SignedInner, TokenSymbol, UnsignedFixedPoint, UnsignedInner, DOT, IBTC, INTR, KBTC, KINT, KSM, + SignedFixedPoint, SignedInner, TokenSymbol, UnsignedFixedPoint, UnsignedInner, DOT, IBTC, INTR, KBTC, KINT, KSM, PriceDetail }; type VaultId = primitives::VaultId; @@ -573,6 +573,7 @@ parameter_types! { pub const VaultAnnuityPalletId: PalletId = PalletId(*b"vlt/annu"); pub const TreasuryPalletId: PalletId = PalletId(*b"mod/trsy"); pub const VaultRegistryPalletId: PalletId = PalletId(*b"mod/vreg"); + pub const LoansPalletId: PalletId = PalletId(*b"mod/loan"); } parameter_types! { @@ -807,6 +808,28 @@ impl currency::CurrencyConversion, CurrencyId> for Cur } } +pub struct PriceFeed; +impl pallet_loans::PriceFeeder for PriceFeed { + fn get_price(asset_id: &CurrencyId) -> Option { + Oracle::get_price(oracle::OracleKey::ExchangeRate(asset_id)) + .ok() + .map(|price| (price, Timestamp::now())) + } +} + +impl pallet_loans::Config for Runtime { + type Event = Event; + type PalletId = LoansPalletId; + type PriceFeeder = PriceFeed; + type ReserveOrigin = EnsureRoot; + type UpdateOrigin = EnsureRoot; + type WeightInfo = (); + type UnixTime = Timestamp; + type Assets = Tokens; + type RewardAssetId = GetNativeCurrencyId; + type LiquidationFreeAssetId = GetRelayChainCurrencyId; +} + impl currency::Config for Runtime { type SignedInner = SignedInner; type SignedFixedPoint = SignedFixedPoint; From 66b45729bf85b421c3070f160d4f2a1f4ef67b08 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Tue, 20 Sep 2022 18:43:01 +0200 Subject: [PATCH 05/58] chore: bump toolchain to match lending pallet --- rust-toolchain.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 0dba4b87e5..b5ad165f66 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2022-06-20" -components = [ "rustfmt", "rls" ] +channel = "nightly-2022-07-24" +components = [ "rustfmt", "rls", "clippy" ] targets = [ "wasm32-unknown-unknown" ] From d45d68d204c6d3e1061e88650cfed02f5acb0948 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Tue, 20 Sep 2022 21:16:41 +0100 Subject: [PATCH 06/58] chore: fix toml files Co-authored-by: Sander Bosma --- crates/loans/Cargo.toml | 54 ++++++++++++------------- crates/loans/rpc/Cargo.toml | 10 ++--- crates/loans/rpc/runtime-api/Cargo.toml | 4 +- crates/traits/Cargo.toml | 46 +++++++++++---------- rust-toolchain.toml | 4 +- standalone/runtime/Cargo.toml | 1 + 6 files changed, 61 insertions(+), 58 deletions(-) diff --git a/crates/loans/Cargo.toml b/crates/loans/Cargo.toml index 6147f34a9a..96f4f4b51a 100644 --- a/crates/loans/Cargo.toml +++ b/crates/loans/Cargo.toml @@ -9,45 +9,45 @@ targets = ['x86_64-unknown-linux-gnu'] [dependencies] codec = { package = 'parity-scale-codec', version = '3.1.5', default-features = false } -frame-benchmarking = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false, optional = true } -frame-support = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } -frame-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +frame-benchmarking = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false, optional = true } +frame-support = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } +frame-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } num-traits = { default-features = false, version = '0.2' } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" } -orml-oracle = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } +orml-oracle = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } - -pallet-timestamp = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +pallet-timestamp = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } pallet-traits = { path = '../traits', default-features = false } primitives = { package = 'interbtc-primitives', path = '../../primitives', default-features = false } scale-info = { version = '2.1', default-features = false, features = ['derive'] } -serde = { version = '1.0.136', features = ['derive'], optional = true } -sp-io = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } -sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } -sp-std = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +serde = { version = '1.0.136', default-features = false, features = ['derive'], optional = true } +sp-io = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } +sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } +sp-std = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } +sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } [dev-dependencies] -sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28' } [features] default = ['std'] runtime-benchmarks = ['frame-benchmarking'] std = [ - 'codec/std', - 'frame-support/std', - 'frame-system/std', - 'frame-benchmarking/std', - "orml-tokens/std", - 'orml-traits/std', - 'primitives/std', - 'sp-runtime/std', - 'sp-std/std', - 'sp-io/std', - 'pallet-timestamp/std', - 'serde', - 'scale-info/std', - 'num-traits/std', - 'pallet-traits/std', + "codec/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", + "num-traits/std", + "orml-traits/std", + "orml-oracle/std", + "orml-tokens/std", + "pallet-timestamp/std", + "pallet-traits/std", + "primitives/std", + "scale-info/std", + "serde/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std" ] try-runtime = ['frame-support/try-runtime'] diff --git a/crates/loans/rpc/Cargo.toml b/crates/loans/rpc/Cargo.toml index d56b6b036c..3d50d19294 100644 --- a/crates/loans/rpc/Cargo.toml +++ b/crates/loans/rpc/Cargo.toml @@ -9,11 +9,11 @@ codec = { package = 'parity-scale-codec', version = '3.1.5' } jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } primitives = { package = 'parallel-primitives', path = '../../../primitives', default-features = false } serde = { version = '1.0.136', features = ['derive'] } -sp-api = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28' } -sp-blockchain = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28' } -sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28' } -sp-rpc = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } -sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28' } +sp-api = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26' } +sp-blockchain = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26' } +sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26' } +sp-rpc = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } +sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26' } pallet-loans-rpc-runtime-api = { path = 'runtime-api', default-features = false } diff --git a/crates/loans/rpc/runtime-api/Cargo.toml b/crates/loans/rpc/runtime-api/Cargo.toml index 55ddee224e..f3fccc5836 100644 --- a/crates/loans/rpc/runtime-api/Cargo.toml +++ b/crates/loans/rpc/runtime-api/Cargo.toml @@ -7,8 +7,8 @@ version = '1.9.3' [dependencies] codec = { package = 'parity-scale-codec', version = '3.1.5', default-features = false, features = ['derive'] } primitives = { package = 'parallel-primitives', path = '../../../../primitives', default-features = false } -sp-api = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } -sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +sp-api = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } +sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } [features] default = ['std'] diff --git a/crates/traits/Cargo.toml b/crates/traits/Cargo.toml index adb32d7b3d..00372c4ac7 100644 --- a/crates/traits/Cargo.toml +++ b/crates/traits/Cargo.toml @@ -8,43 +8,45 @@ version = '1.9.3' targets = ['x86_64-unknown-linux-gnu'] [dependencies] -serde = { version = '1.0.136', features = ['derive'], optional = true } +serde = { version = '1.0.136',default-features=false, features = ['derive'], optional = true } codec = { package = 'parity-scale-codec', version = '3.1.5', features = ['max-encoded-len'], default-features = false } -frame-support = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } -frame-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +frame-support = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } +frame-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } log = { version = "0.4", default-features = false } num-bigint = { default-features = false, version = '0.4' } num-traits = { default-features = false, version = '0.2' } primitives = { package = 'interbtc-primitives', path = '../../primitives', default-features = false } scale-info = { version = '2.1', default-features = false, features = ['derive'] } -sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } -sp-io = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } -sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } -sp-std = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28', default-features = false } +sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } +sp-io = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } +sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } +sp-std = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } xcm = { git = 'https://github.com/paritytech/polkadot.git', branch = 'release-v0.9.28', default-features = false } xcm-builder = { git = 'https://github.com/paritytech/polkadot.git', branch = 'release-v0.9.28', default-features = false } xcm-executor = { git = 'https://github.com/paritytech/polkadot.git', branch = 'release-v0.9.28', default-features = false } [dev-dependencies] -sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.28' } +sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26' } [features] default = ['std'] std = [ - 'serde', - 'codec/std', - 'frame-support/std', - 'frame-system/std', - 'sp-runtime/std', - 'scale-info/std', - 'sp-std/std', - 'primitives/std', - 'num-bigint/std', - 'num-traits/std', - 'sp-core/std', - 'xcm-executor/std', - 'xcm/std', - 'xcm-builder/std', + "serde/std", + "codec/std", + "frame-support/std", + "frame-system/std", + "log/std", + "num-bigint/std", + "num-traits/std", + "primitives/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", + "xcm/std", + "xcm-builder/std", + "xcm-executor/std" ] try-runtime = ['frame-support/try-runtime'] diff --git a/rust-toolchain.toml b/rust-toolchain.toml index b5ad165f66..0dba4b87e5 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2022-07-24" -components = [ "rustfmt", "rls", "clippy" ] +channel = "nightly-2022-06-20" +components = [ "rustfmt", "rls" ] targets = [ "wasm32-unknown-unknown" ] diff --git a/standalone/runtime/Cargo.toml b/standalone/runtime/Cargo.toml index 50ff00cb90..dca63783bf 100644 --- a/standalone/runtime/Cargo.toml +++ b/standalone/runtime/Cargo.toml @@ -172,6 +172,7 @@ std = [ "democracy/std", "annuity/std", "supply/std", + "pallet-loans/std", "primitives/std", From 8ad2319dddd7c8259a9d91f0a26e8c1750d9ee7e Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Wed, 21 Sep 2022 09:50:02 +0200 Subject: [PATCH 07/58] fix(lend): PriceFeeder trait import --- Cargo.lock | 1 + standalone/runtime/Cargo.toml | 2 ++ standalone/runtime/src/lib.rs | 4 ++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cbc55821e5..57a35fe0fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3627,6 +3627,7 @@ dependencies = [ "pallet-society", "pallet-sudo", "pallet-timestamp", + "pallet-traits", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-treasury", diff --git a/standalone/runtime/Cargo.toml b/standalone/runtime/Cargo.toml index dca63783bf..55759b42d4 100644 --- a/standalone/runtime/Cargo.toml +++ b/standalone/runtime/Cargo.toml @@ -75,6 +75,7 @@ annuity = { path = "../../crates/annuity", default-features = false } supply = { path = "../../crates/supply", default-features = false } clients-info = { path = "../../crates/clients-info", default-features = false } pallet-loans = { path = "../../crates/loans", default-features = false } +pallet-traits = { path = "../../crates/traits", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } @@ -173,6 +174,7 @@ std = [ "annuity/std", "supply/std", "pallet-loans/std", + "pallet-traits/std", "primitives/std", diff --git a/standalone/runtime/src/lib.rs b/standalone/runtime/src/lib.rs index 0a4096b387..09da486cdd 100644 --- a/standalone/runtime/src/lib.rs +++ b/standalone/runtime/src/lib.rs @@ -809,9 +809,9 @@ impl currency::CurrencyConversion, CurrencyId> for Cur } pub struct PriceFeed; -impl pallet_loans::PriceFeeder for PriceFeed { +impl pallet_traits::PriceFeeder for PriceFeed { fn get_price(asset_id: &CurrencyId) -> Option { - Oracle::get_price(oracle::OracleKey::ExchangeRate(asset_id)) + Oracle::get_price(oracle::OracleKey::ExchangeRate(*asset_id)) .ok() .map(|price| (price, Timestamp::now())) } From 64af00e81fddec46090279a0b958a6d4d8e971e6 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Wed, 21 Sep 2022 15:32:41 +0200 Subject: [PATCH 08/58] feat(lend): add loans pallet to standalone runtime --- crates/loans/src/lib.rs | 7 +- crates/loans/src/mock.rs | 104 ++++------- crates/loans/src/tests.rs | 21 ++- crates/loans/src/tests/edge_cases.rs | 73 ++++---- crates/loans/src/tests/interest_rate.rs | 206 ++++++++++----------- crates/loans/src/tests/liquidate_borrow.rs | 15 +- crates/loans/src/tests/market.rs | 15 +- crates/loans/src/tests/ptokens.rs | 16 +- crates/loans/src/types.rs | 2 +- crates/traits/src/lib.rs | 2 +- primitives/src/lib.rs | 12 +- primitives/src/tokens.rs | 204 -------------------- standalone/runtime/src/lib.rs | 30 +-- 13 files changed, 258 insertions(+), 449 deletions(-) delete mode 100644 primitives/src/tokens.rs diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 8edd9e8ca0..eb7c0ebf60 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -44,7 +44,7 @@ use pallet_traits::{ MarketInfo, MarketStatus, PriceFeeder, }; use primitives::{ - tokens::is_auxiliary_token, Balance, LendingPoolCurrencyId as CurrencyId, Liquidity, Price, Rate, Ratio, Shortfall, Timestamp, + Balance, CurrencyId, Liquidity, Price, Rate, Ratio, Shortfall, Timestamp, }; use sp_runtime::{ traits::{ @@ -970,11 +970,6 @@ pub mod pallet { collateral_asset_id: AssetIdOf, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - ensure!( - !Self::liquidation_free_collaterals().contains(&collateral_asset_id) - && !is_auxiliary_token(collateral_asset_id), - Error::::CollateralReserved - ); Self::accrue_interest(liquidation_asset_id)?; Self::accrue_interest(collateral_asset_id)?; Self::do_liquidate_borrow( diff --git a/crates/loans/src/mock.rs b/crates/loans/src/mock.rs index 9f50518494..95d9a3f207 100644 --- a/crates/loans/src/mock.rs +++ b/crates/loans/src/mock.rs @@ -24,17 +24,14 @@ use pallet_traits::{ VaultTokenCurrenciesFilter, VaultTokenExchangeRateProvider, }; use primitives::{ - tokens::{CDOT_6_13, PCDOT_6_13}, - LendingPoolCurrencyId as CurrencyId, - Moment, PriceDetail + CurrencyId::{Token, ForeignAsset}, + Moment, PriceDetail, KSM, CKINT, CKSM, CDOT, CKBTC, KINT, DOT, KBTC, INTR, IBTC, CIBTC, }; use sp_core::H256; use sp_runtime::{testing::Header, traits::IdentityLookup, AccountId32}; use sp_std::vec::Vec; use std::{cell::RefCell, collections::HashMap}; -pub use primitives::tokens::{DOT, HKO, KSM, PDOT, PHKO, PKSM, PUSDT, SDOT, SKSM, USDT}; - type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -155,41 +152,6 @@ impl DataFeeder for MockDataProvider { } } -pub struct LiquidStakingExchangeRateProvider; -impl ExchangeRateProvider for LiquidStakingExchangeRateProvider { - fn get_exchange_rate(_: &CurrencyId) -> Option { - Some(Rate::saturating_from_rational(150, 100)) - } -} - -pub struct Decimal; -impl DecimalProvider for Decimal { - fn get_decimal(asset_id: &CurrencyId) -> Option { - match *asset_id { - KSM | SKSM => Some(12), - HKO => Some(12), - USDT => Some(6), - _ => None, - } - } -} - -pub struct LiquidStaking; -impl LiquidStakingCurrenciesProvider for LiquidStaking { - fn get_staking_currency() -> Option { - Some(KSM) - } - fn get_liquid_currency() -> Option { - Some(SKSM) - } -} - -impl ExchangeRateProvider for LiquidStaking { - fn get_exchange_rate(_: &CurrencyId) -> Option { - Some(Rate::saturating_from_rational(150, 100)) - } -} - pub struct TokenExchangeRateProvider; impl VaultTokenExchangeRateProvider for TokenExchangeRateProvider { fn get_exchange_rate(_: &CurrencyId, _: Rate) -> Option { @@ -222,7 +184,7 @@ impl LoansMarketDataProvider for VaultLoansRateProvider { } parameter_types! { - pub const RelayCurrency: CurrencyId = KSM; + pub const RelayCurrency: CurrencyId = Token(KSM); } pub struct AliceCreatePoolOrigin; @@ -238,7 +200,9 @@ impl MockPriceFeeder { thread_local! { pub static PRICES: RefCell>> = { RefCell::new( - vec![HKO, DOT, KSM, USDT, SKSM, SDOT, CDOT_6_13] + // Include a foreign assets to act as a liquidation-free collateral for now. + // TODO: Remove liquidation-free collateral + vec![Token(KINT), Token(DOT), Token(KSM), Token(KBTC), Token(INTR), Token(IBTC), ForeignAsset(100000)] .iter() .map(|&x| (x, Some((Price::saturating_from_integer(1), 1)))) .collect() @@ -263,7 +227,11 @@ impl MockPriceFeeder { impl PriceFeeder for MockPriceFeeder { fn get_price(asset_id: &CurrencyId) -> Option { - Self::PRICES.with(|prices| *prices.borrow().get(asset_id).unwrap()) + Self::PRICES.with(|prices| { + let p = prices.borrow(); + let v = p.get(asset_id).unwrap(); + *v + }) } } @@ -273,8 +241,10 @@ parameter_types! { parameter_types! { pub const LoansPalletId: PalletId = PalletId(*b"par/loan"); - pub const RewardAssetId: CurrencyId = HKO; - pub const LiquidationFreeAssetId: CurrencyId = DOT; + pub const RewardAssetId: CurrencyId = Token(KINT); + + // Until this is removed, set to a value that's not in use. + pub const LiquidationFreeAssetId: CurrencyId = ForeignAsset(100000); } impl Config for Test { @@ -299,29 +269,27 @@ pub(crate) fn new_test_ext() -> sp_io::TestExternalities { ext.execute_with(|| { // Init assets - Tokens::set_balance(Origin::root(), ALICE, KSM, 1000_000000000000, 0).unwrap(); - Tokens::set_balance(Origin::root(), ALICE, DOT, 1000_000000000000, 0).unwrap(); - Tokens::set_balance(Origin::root(), ALICE, USDT, 1000_000000000000, 0).unwrap(); - Tokens::set_balance(Origin::root(), ALICE, CDOT_6_13, 1000_000000000000, 0).unwrap(); - Tokens::set_balance(Origin::root(), BOB, KSM, 1000_000000000000, 0).unwrap(); - Tokens::set_balance(Origin::root(), BOB, DOT, 1000_000000000000, 0).unwrap(); - Tokens::set_balance(Origin::root(), DAVE, DOT, 1000_000000000000, 0).unwrap(); - Tokens::set_balance(Origin::root(), DAVE, USDT, 1000_000000000000, 0).unwrap(); - Tokens::set_balance(Origin::root(), DAVE, HKO, 1000_000000000000, 0).unwrap(); + Tokens::set_balance(Origin::root(), ALICE, Token(KSM), 1000_000000000000, 0).unwrap(); + Tokens::set_balance(Origin::root(), ALICE, Token(DOT), 1000_000000000000, 0).unwrap(); + Tokens::set_balance(Origin::root(), ALICE, Token(KBTC), 1000_000000000000, 0).unwrap(); + Tokens::set_balance(Origin::root(), ALICE, Token(IBTC), 1000_000000000000, 0).unwrap(); + Tokens::set_balance(Origin::root(), BOB, Token(KSM), 1000_000000000000, 0).unwrap(); + Tokens::set_balance(Origin::root(), BOB, Token(DOT), 1000_000000000000, 0).unwrap(); + Tokens::set_balance(Origin::root(), DAVE, Token(DOT), 1000_000000000000, 0).unwrap(); + Tokens::set_balance(Origin::root(), DAVE, Token(KBTC), 1000_000000000000, 0).unwrap(); + Tokens::set_balance(Origin::root(), DAVE, Token(KINT), 1000_000000000000, 0).unwrap(); // Init Markets - Loans::add_market(Origin::root(), HKO, market_mock(PHKO)).unwrap(); - Loans::activate_market(Origin::root(), HKO).unwrap(); - Loans::add_market(Origin::root(), KSM, market_mock(PKSM)).unwrap(); - Loans::activate_market(Origin::root(), KSM).unwrap(); - Loans::add_market(Origin::root(), DOT, market_mock(PDOT)).unwrap(); - Loans::activate_market(Origin::root(), DOT).unwrap(); - Loans::add_market(Origin::root(), USDT, market_mock(PUSDT)).unwrap(); - Loans::activate_market(Origin::root(), USDT).unwrap(); - Loans::add_market(Origin::root(), CDOT_6_13, market_mock(PCDOT_6_13)).unwrap(); - Loans::activate_market(Origin::root(), CDOT_6_13).unwrap(); - - Loans::update_liquidation_free_collateral(Origin::root(), vec![CDOT_6_13]).unwrap(); + Loans::add_market(Origin::root(), Token(KINT), market_mock(Token(CKINT))).unwrap(); + Loans::activate_market(Origin::root(), Token(KINT)).unwrap(); + Loans::add_market(Origin::root(), Token(KSM), market_mock(Token(CKSM))).unwrap(); + Loans::activate_market(Origin::root(), Token(KSM)).unwrap(); + Loans::add_market(Origin::root(), Token(DOT), market_mock(Token(CDOT))).unwrap(); + Loans::activate_market(Origin::root(), Token(DOT)).unwrap(); + Loans::add_market(Origin::root(), Token(KBTC), market_mock(Token(CKBTC))).unwrap(); + Loans::activate_market(Origin::root(), Token(KBTC)).unwrap(); + Loans::add_market(Origin::root(), Token(IBTC), market_mock(Token(CIBTC))).unwrap(); + Loans::activate_market(Origin::root(), Token(IBTC)).unwrap(); System::set_block_number(0); TimestampPallet::set_timestamp(6000); @@ -372,7 +340,7 @@ pub fn million_unit(d: u128) -> u128 { unit(d) * 10_u128.pow(6) } -pub const fn market_mock(ptoken_id: u32) -> Market { +pub const fn market_mock(ptoken_id: CurrencyId) -> Market { Market { close_factor: Ratio::from_percent(50), collateral_factor: Ratio::from_percent(50), @@ -393,7 +361,7 @@ pub const fn market_mock(ptoken_id: u32) -> Market { } } -pub const MARKET_MOCK: Market = market_mock(1200); +pub const MARKET_MOCK: Market = market_mock(ForeignAsset(1200)); pub const ACTIVE_MARKET_MOCK: Market = { let mut market = MARKET_MOCK; diff --git a/crates/loans/src/tests.rs b/crates/loans/src/tests.rs index 1cd92bc2b2..8be07196b1 100644 --- a/crates/loans/src/tests.rs +++ b/crates/loans/src/tests.rs @@ -20,14 +20,22 @@ mod ptokens; use frame_support::{assert_err, assert_noop, assert_ok}; -use primitives::tokens::CDOT_6_13; use sp_runtime::{ traits::{CheckedDiv, One, Saturating}, FixedU128, Permill, }; +use primitives::{CurrencyId::Token, DOT as DOT_CURRENCY, KSM as KSM_CURRENCY, KBTC, IBTC, KINT}; + use crate::mock::*; +const DOT: CurrencyId = Token(DOT_CURRENCY); +const KSM: CurrencyId = Token(KSM_CURRENCY); +const USDT: CurrencyId = Token(KBTC); +const CDOT_6_13: CurrencyId = Token(IBTC); +const HKO: CurrencyId = Token(KINT); + + #[test] fn init_minting_ok() { new_test_ext().execute_with(|| { @@ -208,6 +216,9 @@ fn redeem_allowed_works() { }) } + +// ignore: tests liquidation-free collateral +#[ignore] #[test] fn lf_redeem_allowed_works() { new_test_ext().execute_with(|| { @@ -403,7 +414,7 @@ fn get_account_liquidity_works() { let (liquidity, _, lf_liquidity, _) = Loans::get_account_liquidity(&ALICE).unwrap(); assert_eq!(liquidity, FixedU128::from_inner(unit(100))); - assert_eq!(lf_liquidity, FixedU128::from_inner(unit(100))); + assert_eq!(lf_liquidity, FixedU128::from_inner(unit(0))); }) } @@ -426,7 +437,7 @@ fn get_account_liquidation_threshold_liquidity_works() { Loans::get_account_liquidation_threshold_liquidity(&ALICE).unwrap(); assert_eq!(liquidity, FixedU128::from_inner(unit(20))); - assert_eq!(lf_liquidity, FixedU128::from_inner(unit(10))); + assert_eq!(lf_liquidity, FixedU128::from_inner(unit(0))); MockPriceFeeder::set_price(KSM, 2.into()); let (liquidity, shortfall, lf_liquidity, _) = @@ -434,10 +445,12 @@ fn get_account_liquidation_threshold_liquidity_works() { assert_eq!(liquidity, FixedU128::from_inner(unit(0))); assert_eq!(shortfall, FixedU128::from_inner(unit(80))); - assert_eq!(lf_liquidity, FixedU128::from_inner(unit(10))); + assert_eq!(lf_liquidity, FixedU128::from_inner(unit(0))); }) } +// ignore: tests liquidation-free collateral +#[ignore] #[test] fn lf_borrow_allowed_works() { new_test_ext().execute_with(|| { diff --git a/crates/loans/src/tests/edge_cases.rs b/crates/loans/src/tests/edge_cases.rs index 3a69b168be..6d4f915d82 100644 --- a/crates/loans/src/tests/edge_cases.rs +++ b/crates/loans/src/tests/edge_cases.rs @@ -2,23 +2,28 @@ use super::*; use crate::tests::Loans; use crate::{mock::*, Error}; use frame_support::{assert_err, assert_ok}; +use primitives::{KSM, IBTC}; +use primitives::{ + CurrencyId::{Token, ForeignAsset}, + DOT +}; use sp_runtime::FixedPointNumber; #[test] fn exceeded_supply_cap() { new_test_ext().execute_with(|| { - Tokens::set_balance(Origin::root(), ALICE, DOT, million_unit(1001), 0).unwrap(); + Tokens::set_balance(Origin::root(), ALICE, Token(DOT), million_unit(1001), 0).unwrap(); let amount = million_unit(501); - assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, amount)); + assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), amount)); // Exceed upper bound. assert_err!( - Loans::mint(Origin::signed(ALICE), DOT, amount), + Loans::mint(Origin::signed(ALICE), Token(DOT), amount), Error::::SupplyCapacityExceeded ); - Loans::redeem(Origin::signed(ALICE), DOT, amount).unwrap(); + Loans::redeem(Origin::signed(ALICE), Token(DOT), amount).unwrap(); // Here should work, cause we redeemed already. - assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, amount)); + assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), amount)); }) } @@ -26,34 +31,34 @@ fn exceeded_supply_cap() { fn repay_borrow_all_no_underflow() { new_test_ext().execute_with(|| { // Alice deposits 200 KSM as collateral - assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), KSM, true)); + assert_ok!(Loans::mint(Origin::signed(ALICE), Token(KSM), unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(KSM), true)); // Alice borrow only 1/1e5 KSM which is hard to accrue total borrows interest in 100 seconds - assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, 10_u128.pow(7))); + assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(KSM), 10_u128.pow(7))); - accrue_interest_per_block(KSM, 100, 9); + accrue_interest_per_block(Token(KSM), 100, 9); - assert_eq!(Loans::current_borrow_balance(&ALICE, KSM), Ok(10000005)); + assert_eq!(Loans::current_borrow_balance(&ALICE, Token(KSM)), Ok(10000005)); // FIXME since total_borrows is too small and we accrue internal on it every 100 seconds // accrue_interest fails every time // as you can see the current borrow balance is not equal to total_borrows anymore - assert_eq!(Loans::total_borrows(KSM), 10000000); + assert_eq!(Loans::total_borrows(Token(KSM)), 10000000); // Alice repay all borrow balance. total_borrows = total_borrows.saturating_sub(10000005) = 0. - assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), KSM)); + assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), Token(KSM))); - assert_eq!(Tokens::balance(KSM, &ALICE), unit(800) - 5); + assert_eq!(Tokens::balance(Token(KSM), &ALICE), unit(800) - 5); assert_eq!( - Loans::exchange_rate(DOT) - .saturating_mul_int(Loans::account_deposits(KSM, ALICE).voucher_balance), + Loans::exchange_rate(Token(DOT)) + .saturating_mul_int(Loans::account_deposits(Token(KSM), ALICE).voucher_balance), unit(200) ); - let borrow_snapshot = Loans::account_borrows(KSM, ALICE); + let borrow_snapshot = Loans::account_borrows(Token(KSM), ALICE); assert_eq!(borrow_snapshot.principal, 0); - assert_eq!(borrow_snapshot.borrow_index, Loans::borrow_index(KSM)); + assert_eq!(borrow_snapshot.borrow_index, Loans::borrow_index(Token(KSM))); }) } @@ -61,7 +66,7 @@ fn repay_borrow_all_no_underflow() { fn ensure_capacity_fails_when_market_not_existed() { new_test_ext().execute_with(|| { assert_err!( - Loans::ensure_under_supply_cap(SDOT, unit(100)), + Loans::ensure_under_supply_cap(ForeignAsset(987997280), unit(100)), Error::::MarketDoesNotExist ); }); @@ -70,20 +75,20 @@ fn ensure_capacity_fails_when_market_not_existed() { #[test] fn redeem_all_should_be_accurate() { new_test_ext().execute_with(|| { - assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), KSM, true)); - assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(50))); + assert_ok!(Loans::mint(Origin::signed(ALICE), Token(KSM), unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(KSM), true)); + assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(KSM), unit(50))); // let exchange_rate greater than 0.02 - accrue_interest_per_block(KSM, 6, 2); + accrue_interest_per_block(Token(KSM), 6, 2); assert_eq!( - Loans::exchange_rate(KSM), + Loans::exchange_rate(Token(KSM)), Rate::from_inner(20000000036387000) ); - assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), KSM)); + assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), Token(KSM))); // It failed with InsufficientLiquidity before #839 - assert_ok!(Loans::redeem_all(Origin::signed(ALICE), KSM)); + assert_ok!(Loans::redeem_all(Origin::signed(ALICE), Token(KSM))); }) } @@ -92,43 +97,43 @@ fn prevent_the_exchange_rate_attack() { new_test_ext().execute_with(|| { // Initialize Eve's balance assert_ok!(>::transfer( - DOT, + Token(DOT), &ALICE, &EVE, unit(200), false )); // Eve deposits a small amount - assert_ok!(Loans::mint(Origin::signed(EVE), DOT, 1)); + assert_ok!(Loans::mint(Origin::signed(EVE), Token(DOT), 1)); // !!! Eve transfer a big amount to Loans::account_id assert_ok!(>::transfer( - DOT, + Token(DOT), &EVE, &Loans::account_id(), unit(100), false )); - assert_eq!(Tokens::balance(DOT, &EVE), 99999999999999); + assert_eq!(Tokens::balance(Token(DOT), &EVE), 99999999999999); assert_eq!( - Tokens::balance(DOT, &Loans::account_id()), + Tokens::balance(Token(DOT), &Loans::account_id()), 100000000000001 ); assert_eq!( - Loans::total_supply(DOT), + Loans::total_supply(Token(DOT)), 1 * 50, // 1 / 0.02 ); TimestampPallet::set_timestamp(12000); // Eve can not let the exchange rate greater than 1 - assert!(Loans::accrue_interest(DOT).is_err()); + assert!(Loans::accrue_interest(Token(DOT)).is_err()); // Mock a BIG exchange_rate: 100000000000.02 ExchangeRate::::insert( - DOT, + Token(DOT), Rate::saturating_from_rational(100000000000020u128, 20 * 50), ); // Bob can not deposit 0.1 DOT because the voucher_balance can not be 0. assert_noop!( - Loans::mint(Origin::signed(BOB), DOT, 100000000000), + Loans::mint(Origin::signed(BOB), Token(DOT), 100000000000), Error::::InvalidExchangeRate ); }) diff --git a/crates/loans/src/tests/interest_rate.rs b/crates/loans/src/tests/interest_rate.rs index 70fc3e963f..a1008e494f 100644 --- a/crates/loans/src/tests/interest_rate.rs +++ b/crates/loans/src/tests/interest_rate.rs @@ -1,7 +1,7 @@ use crate::tests::Loans; use crate::{mock::*, Markets}; use frame_support::assert_ok; -use primitives::{Rate, Ratio, SECONDS_PER_YEAR}; +use primitives::{Rate, Ratio, SECONDS_PER_YEAR, DOT, KSM, CurrencyId::Token}; use sp_runtime::{ traits::{CheckedDiv, One, Saturating}, FixedPointNumber, @@ -37,22 +37,22 @@ fn interest_rate_model_works() { Tokens::set_balance( Origin::root(), ALICE, - DOT, + Token(DOT), million_unit(1000) - unit(1000), 0 ) .unwrap(); // Deposit 200 DOT and borrow 100 DOT - assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, million_unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); - assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, million_unit(100))); + assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), million_unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); + assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), million_unit(100))); let total_cash = million_unit(200) - million_unit(100); let total_supply = - Loans::calc_collateral_amount(million_unit(200), Loans::exchange_rate(DOT)).unwrap(); - assert_eq!(Loans::total_supply(DOT), total_supply); + Loans::calc_collateral_amount(million_unit(200), Loans::exchange_rate(Token(DOT))).unwrap(); + assert_eq!(Loans::total_supply(Token(DOT)), total_supply); - let borrow_snapshot = Loans::account_borrows(DOT, ALICE); + let borrow_snapshot = Loans::account_borrows(Token(DOT), ALICE); assert_eq!(borrow_snapshot.principal, million_unit(100)); assert_eq!(borrow_snapshot.borrow_index, Rate::one()); @@ -69,10 +69,10 @@ fn interest_rate_model_works() { for i in 1..49 { let delta_time = 6u128; TimestampPallet::set_timestamp(6000 * (i + 1)); - assert_ok!(Loans::accrue_interest(DOT)); + assert_ok!(Loans::accrue_interest(Token(DOT))); // utilizationRatio = totalBorrows / (totalCash + totalBorrows) let util_ratio = Ratio::from_rational(total_borrows, total_cash + total_borrows); - assert_eq!(Loans::utilization_ratio(DOT), util_ratio); + assert_eq!(Loans::utilization_ratio(Token(DOT)), util_ratio); let borrow_rate = (jump_rate - base_rate) * util_ratio.into() / jump_utilization.into() + base_rate; @@ -82,17 +82,17 @@ fn interest_rate_model_works() { .checked_div(SECONDS_PER_YEAR.into()) .unwrap(); total_borrows = interest_accumulated + total_borrows; - assert_eq!(Loans::total_borrows(DOT), total_borrows); - total_reserves = Markets::::get(&DOT) + assert_eq!(Loans::total_borrows(Token(DOT)), total_borrows); + total_reserves = Markets::::get(&Token(DOT)) .unwrap() .reserve_factor .mul_floor(interest_accumulated) + total_reserves; - assert_eq!(Loans::total_reserves(DOT), total_reserves); + assert_eq!(Loans::total_reserves(Token(DOT)), total_reserves); // exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply assert_eq!( - Loans::exchange_rate(DOT).into_inner(), + Loans::exchange_rate(Token(DOT)).into_inner(), (total_cash + total_borrows - total_reserves) * rate_decimal / total_supply ); let numerator = borrow_index @@ -101,13 +101,13 @@ fn interest_rate_model_works() { .checked_div(&Rate::saturating_from_integer(SECONDS_PER_YEAR)) .unwrap(); borrow_index = numerator + borrow_index; - assert_eq!(Loans::borrow_index(DOT), borrow_index); + assert_eq!(Loans::borrow_index(Token(DOT)), borrow_index); } assert_eq!(total_borrows, 100000063926960646826); assert_eq!(total_reserves, 9589044097001); assert_eq!(borrow_index, Rate::from_inner(1000000639269606444)); assert_eq!( - Loans::exchange_rate(DOT), + Loans::exchange_rate(Token(DOT)), Rate::from_inner(20000005433791654) ); @@ -115,7 +115,7 @@ fn interest_rate_model_works() { let borrow_principal = (borrow_index / borrow_snapshot.borrow_index) .saturating_mul_int(borrow_snapshot.principal); let supply_interest = - Loans::exchange_rate(DOT).saturating_mul_int(total_supply) - million_unit(200); + Loans::exchange_rate(Token(DOT)).saturating_mul_int(total_supply) - million_unit(200); assert_eq!(supply_interest, 54337916540000); assert_eq!(borrow_principal, 100000063926960644400); assert_eq!(total_borrows / 10000, borrow_principal / 10000); @@ -129,17 +129,17 @@ fn interest_rate_model_works() { #[test] fn last_accrued_interest_time_should_be_update_correctly() { new_test_ext().execute_with(|| { - assert_eq!(Loans::borrow_index(DOT), Rate::one()); - assert_eq!(Loans::last_accrued_interest_time(DOT), 0); - assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); - assert_eq!(Loans::last_accrued_interest_time(DOT), 6); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); - assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(100))); - assert_eq!(Loans::borrow_index(DOT), Rate::one()); + assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); + assert_eq!(Loans::last_accrued_interest_time(Token(DOT)), 0); + assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); + assert_eq!(Loans::last_accrued_interest_time(Token(DOT)), 6); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); + assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), unit(100))); + assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); TimestampPallet::set_timestamp(12000); - assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(100))); + assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(100))); assert_eq!( - Loans::borrow_index(DOT), + Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000013318112633), ); }) @@ -148,14 +148,14 @@ fn last_accrued_interest_time_should_be_update_correctly() { #[test] fn accrue_interest_works_after_mint() { new_test_ext().execute_with(|| { - assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); - assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(100))); - assert_eq!(Loans::borrow_index(DOT), Rate::one()); + assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); + assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), unit(100))); + assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); TimestampPallet::set_timestamp(12000); - assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(100))); + assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(100))); assert_eq!( - Loans::borrow_index(DOT), + Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000013318112633), ); }) @@ -164,13 +164,13 @@ fn accrue_interest_works_after_mint() { #[test] fn accrue_interest_works_after_borrow() { new_test_ext().execute_with(|| { - assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); - assert_eq!(Loans::borrow_index(DOT), Rate::one()); + assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); + assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); TimestampPallet::set_timestamp(12000); - assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(100))); + assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), unit(100))); assert_eq!( - Loans::borrow_index(DOT), + Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000003805175038), ); }) @@ -179,23 +179,23 @@ fn accrue_interest_works_after_borrow() { #[test] fn accrue_interest_works_after_redeem() { new_test_ext().execute_with(|| { - assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); - assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(10))); - assert_eq!(Loans::borrow_index(DOT), Rate::one()); + assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); + assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), unit(10))); + assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); TimestampPallet::set_timestamp(12000); - assert_ok!(Loans::redeem(Origin::signed(ALICE), DOT, unit(10))); + assert_ok!(Loans::redeem(Origin::signed(ALICE), Token(DOT), unit(10))); assert_eq!( - Loans::borrow_index(DOT), + Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000004756468797), ); assert_eq!( - Loans::exchange_rate(DOT) - .saturating_mul_int(Loans::account_deposits(DOT, BOB).voucher_balance), + Loans::exchange_rate(Token(DOT)) + .saturating_mul_int(Loans::account_deposits(Token(DOT), BOB).voucher_balance), 0, ); assert_eq!( - Tokens::balance(DOT, &ALICE), + Tokens::balance(Token(DOT), &ALICE), 819999999999999 ); }) @@ -204,41 +204,41 @@ fn accrue_interest_works_after_redeem() { #[test] fn accrue_interest_works_after_redeem_all() { new_test_ext().execute_with(|| { - assert_ok!(Loans::mint(Origin::signed(BOB), DOT, unit(20))); - assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); - assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(10))); - assert_eq!(Loans::borrow_index(DOT), Rate::one()); + assert_ok!(Loans::mint(Origin::signed(BOB), Token(DOT), unit(20))); + assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); + assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), unit(10))); + assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); TimestampPallet::set_timestamp(12000); - assert_ok!(Loans::redeem_all(Origin::signed(BOB), DOT)); + assert_ok!(Loans::redeem_all(Origin::signed(BOB), Token(DOT))); assert_eq!( - Loans::borrow_index(DOT), + Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000004669977168), ); assert_eq!( - Loans::exchange_rate(DOT) - .saturating_mul_int(Loans::account_deposits(DOT, BOB).voucher_balance), + Loans::exchange_rate(Token(DOT)) + .saturating_mul_int(Loans::account_deposits(Token(DOT), BOB).voucher_balance), 0, ); assert_eq!( - Tokens::balance(DOT, &BOB), + Tokens::balance(Token(DOT), &BOB), 1000000000003608 ); - assert!(!AccountDeposits::::contains_key(DOT, &BOB)) + assert!(!AccountDeposits::::contains_key(Token(DOT), &BOB)) }) } #[test] fn accrue_interest_works_after_repay() { new_test_ext().execute_with(|| { - assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); - assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(20))); - assert_eq!(Loans::borrow_index(DOT), Rate::one()); + assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); + assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), unit(20))); + assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); TimestampPallet::set_timestamp(12000); - assert_ok!(Loans::repay_borrow(Origin::signed(ALICE), DOT, unit(10))); + assert_ok!(Loans::repay_borrow(Origin::signed(ALICE), Token(DOT), unit(10))); assert_eq!( - Loans::borrow_index(DOT), + Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000005707762557), ); }) @@ -247,24 +247,24 @@ fn accrue_interest_works_after_repay() { #[test] fn accrue_interest_works_after_repay_all() { new_test_ext().execute_with(|| { - assert_ok!(Loans::mint(Origin::signed(BOB), KSM, unit(200))); - assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); - assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(50))); - assert_eq!(Loans::borrow_index(KSM), Rate::one()); + assert_ok!(Loans::mint(Origin::signed(BOB), Token(KSM), unit(200))); + assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); + assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(KSM), unit(50))); + assert_eq!(Loans::borrow_index(Token(KSM)), Rate::one()); TimestampPallet::set_timestamp(12000); - assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), KSM)); + assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), Token(KSM))); assert_eq!( - Loans::borrow_index(KSM), + Loans::borrow_index(Token(KSM)), Rate::from_inner(1000000008561643835), ); assert_eq!( - Tokens::balance(KSM, &ALICE), + Tokens::balance(Token(KSM), &ALICE), 999999999571918 ); - let borrow_snapshot = Loans::account_borrows(KSM, ALICE); + let borrow_snapshot = Loans::account_borrows(Token(KSM), ALICE); assert_eq!(borrow_snapshot.principal, 0); - assert_eq!(borrow_snapshot.borrow_index, Loans::borrow_index(KSM)); + assert_eq!(borrow_snapshot.borrow_index, Loans::borrow_index(Token(KSM))); }) } @@ -272,32 +272,32 @@ fn accrue_interest_works_after_repay_all() { fn accrue_interest_works_after_liquidate_borrow() { new_test_ext().execute_with(|| { // Bob deposits 200 KSM - assert_ok!(Loans::mint(Origin::signed(BOB), KSM, unit(200))); + assert_ok!(Loans::mint(Origin::signed(BOB), Token(KSM), unit(200))); // Alice deposits 300 DOT as collateral - assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(300))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(300))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); // Alice borrows 100 KSM and 50 DOT - assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(100))); - assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(50))); - assert_eq!(Loans::borrow_index(DOT), Rate::one()); - assert_eq!(Loans::borrow_index(KSM), Rate::one()); + assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(KSM), unit(100))); + assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), unit(50))); + assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); + assert_eq!(Loans::borrow_index(Token(KSM)), Rate::one()); TimestampPallet::set_timestamp(12000); // Adjust KSM price to make shortfall - MockPriceFeeder::set_price(KSM, 2.into()); + MockPriceFeeder::set_price(Token(KSM), 2.into()); // BOB repay the KSM loan and get DOT callateral from ALICE assert_ok!(Loans::liquidate_borrow( Origin::signed(BOB), ALICE, - KSM, + Token(KSM), unit(50), - DOT + Token(DOT) )); assert_eq!( - Loans::borrow_index(KSM), + Loans::borrow_index(Token(KSM)), Rate::from_inner(1000000013318112633), ); assert_eq!( - Loans::borrow_index(DOT), + Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000006976141552), ); }) @@ -306,21 +306,21 @@ fn accrue_interest_works_after_liquidate_borrow() { #[test] fn different_markets_can_accrue_interest_in_one_block() { new_test_ext().execute_with(|| { - assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); - assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), KSM, true)); - assert_eq!(Loans::borrow_index(DOT), Rate::one()); - assert_eq!(Loans::borrow_index(KSM), Rate::one()); + assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); + assert_ok!(Loans::mint(Origin::signed(ALICE), Token(KSM), unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(KSM), true)); + assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); + assert_eq!(Loans::borrow_index(Token(KSM)), Rate::one()); TimestampPallet::set_timestamp(12000); - assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(100))); - assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(100))); + assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), unit(100))); + assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(KSM), unit(100))); assert_eq!( - Loans::borrow_index(DOT), + Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000003805175038), ); assert_eq!( - Loans::borrow_index(KSM), + Loans::borrow_index(Token(KSM)), Rate::from_inner(1000000003805175038), ); }) @@ -329,16 +329,16 @@ fn different_markets_can_accrue_interest_in_one_block() { #[test] fn a_market_can_only_accrue_interest_once_in_a_block() { new_test_ext().execute_with(|| { - assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); - assert_ok!(Loans::mint(Origin::signed(BOB), DOT, unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(BOB), DOT, true)); - assert_eq!(Loans::borrow_index(DOT), Rate::one()); + assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); + assert_ok!(Loans::mint(Origin::signed(BOB), Token(DOT), unit(200))); + assert_ok!(Loans::collateral_asset(Origin::signed(BOB), Token(DOT), true)); + assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); TimestampPallet::set_timestamp(12000); - assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(100))); - assert_ok!(Loans::borrow(Origin::signed(BOB), DOT, unit(100))); + assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), unit(100))); + assert_ok!(Loans::borrow(Origin::signed(BOB), Token(DOT), unit(100))); assert_eq!( - Loans::borrow_index(DOT), + Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000003805175038), ); }) diff --git a/crates/loans/src/tests/liquidate_borrow.rs b/crates/loans/src/tests/liquidate_borrow.rs index 9dbd4fd4ea..2ba058ed81 100644 --- a/crates/loans/src/tests/liquidate_borrow.rs +++ b/crates/loans/src/tests/liquidate_borrow.rs @@ -1,14 +1,21 @@ use crate::{ mock::{ - new_test_ext, Tokens, Loans, MockPriceFeeder, Origin, Test, ALICE, BOB, DOT, KSM, USDT, + new_test_ext, Tokens, Loans, MockPriceFeeder, Origin, Test, ALICE, BOB, }, tests::unit, Error, MarketState, }; use frame_support::{assert_err, assert_noop, assert_ok, traits::fungibles::Inspect}; -use primitives::{tokens::{CDOT_6_13, DOT_U}, Rate}; +use primitives::{CurrencyId::{Token, self}, Rate, DOT as DOT_CURRENCY, KSM as KSM_CURRENCY, +KBTC as KBTC_CURRENCY, IBTC as IBTC_CURRENCY, KINT as KINT_CURRENCY}; use sp_runtime::FixedPointNumber; +const DOT: CurrencyId = Token(DOT_CURRENCY); +const KSM: CurrencyId = Token(KSM_CURRENCY); +const USDT: CurrencyId = Token(KBTC_CURRENCY); +const CDOT_6_13: CurrencyId = Token(IBTC_CURRENCY); +const DOT_U: CurrencyId = Token(KINT_CURRENCY); + #[test] fn liquidate_borrow_allowed_works() { new_test_ext().execute_with(|| { @@ -40,6 +47,8 @@ fn liquidate_borrow_allowed_works() { }) } +// ignore: tests liquidation-free collateral +#[ignore] #[test] fn lf_liquidate_borrow_fails_due_to_lf_collateral() { new_test_ext().execute_with(|| { @@ -56,6 +65,8 @@ fn lf_liquidate_borrow_fails_due_to_lf_collateral() { }) } +// ignore: tests liquidation-free collateral +#[ignore] #[test] fn lf_liquidate_borrow_allowed_works() { new_test_ext().execute_with(|| { diff --git a/crates/loans/src/tests/market.rs b/crates/loans/src/tests/market.rs index ac5f70ea47..2995227307 100644 --- a/crates/loans/src/tests/market.rs +++ b/crates/loans/src/tests/market.rs @@ -1,14 +1,19 @@ use crate::{ mock::{ - market_mock, new_test_ext, Loans, Origin, Test, ACTIVE_MARKET_MOCK, ALICE, DOT, - MARKET_MOCK, PDOT, PUSDT, SDOT, + market_mock, new_test_ext, Loans, Origin, Test, ACTIVE_MARKET_MOCK, ALICE, + MARKET_MOCK, }, Error, InterestRateModel, MarketState, }; use frame_support::{assert_noop, assert_ok, error::BadOrigin}; -use primitives::{Rate, Ratio}; +use primitives::{Rate, Ratio, CDOT, CKBTC, IBTC, CurrencyId::{self, Token, ForeignAsset}, DOT as DOT_CURRENCY, CKSM,}; use sp_runtime::{traits::Zero, FixedPointNumber}; +const DOT: CurrencyId = Token(DOT_CURRENCY); +const PDOT: CurrencyId = Token(CDOT); +const PUSDT: CurrencyId = Token(CKBTC); +const SDOT: CurrencyId = ForeignAsset(987997280); + macro_rules! rate_model_sanity_check { ($call:ident) => { new_test_ext().execute_with(|| { @@ -177,9 +182,9 @@ fn force_update_market_works() { assert_ok!(Loans::force_update_market( Origin::root(), DOT, - market_mock(1234) + market_mock(ForeignAsset(1234)) )); - assert_eq!(Loans::market(DOT).unwrap().ptoken_id, 1234); + assert_eq!(Loans::market(DOT).unwrap().ptoken_id, ForeignAsset(1234)); }) } diff --git a/crates/loans/src/tests/ptokens.rs b/crates/loans/src/tests/ptokens.rs index aa66e03e30..3260f6ae5c 100644 --- a/crates/loans/src/tests/ptokens.rs +++ b/crates/loans/src/tests/ptokens.rs @@ -1,7 +1,6 @@ use crate::{ mock::{ - market_mock, new_test_ext, Loans, Origin, Test, ALICE, DAVE, HKO, KSM, PHKO, PKSM, PUSDT, - SDOT, USDT, + market_mock, new_test_ext, Loans, Origin, Test, ALICE, DAVE, }, tests::unit, Error, @@ -10,8 +9,17 @@ use frame_support::{ assert_err, assert_noop, assert_ok, traits::tokens::fungibles::{Inspect, Transfer}, }; +use primitives::{KINT, CKBTC, CKSM, CKINT, KSM as KSM_CURRENCY, CurrencyId::{self, Token, ForeignAsset}, KBTC}; use sp_runtime::{FixedPointNumber, TokenError}; +const HKO: CurrencyId = Token(KINT); +const KSM: CurrencyId = Token(KSM_CURRENCY); +const PHKO: CurrencyId = Token(CKINT); +const PKSM: CurrencyId = Token(CKSM); +const PUSDT: CurrencyId = Token(CKBTC); +const USDT: CurrencyId = Token(KBTC); + + #[test] fn trait_inspect_methods_works() { new_test_ext().execute_with(|| { @@ -82,13 +90,13 @@ fn ptoken_unique_works() { new_test_ext().execute_with(|| { // ptoken_id already exists in `UnderlyingAssetId` assert_noop!( - Loans::add_market(Origin::root(), SDOT, market_mock(PHKO)), + Loans::add_market(Origin::root(), ForeignAsset(1000000), market_mock(PHKO)), Error::::InvalidPtokenId ); // ptoken_id cannot as the same as the asset id in `Markets` assert_noop!( - Loans::add_market(Origin::root(), SDOT, market_mock(KSM)), + Loans::add_market(Origin::root(), ForeignAsset(1000000), market_mock(KSM)), Error::::InvalidPtokenId ); }) diff --git a/crates/loans/src/types.rs b/crates/loans/src/types.rs index c79ac0b876..a820e9ee3c 100644 --- a/crates/loans/src/types.rs +++ b/crates/loans/src/types.rs @@ -1,6 +1,6 @@ use crate::InterestRateModel; use frame_support::pallet_prelude::*; -use primitives::{LendingPoolCurrencyId as CurrencyId, Rate, Ratio}; +use primitives::{CurrencyId, Rate, Ratio}; use scale_info::TypeInfo; /// Container for borrow balance information diff --git a/crates/traits/src/lib.rs b/crates/traits/src/lib.rs index 6db76f0080..b3ed9828a2 100644 --- a/crates/traits/src/lib.rs +++ b/crates/traits/src/lib.rs @@ -8,7 +8,7 @@ use sp_runtime::{traits::Zero, RuntimeDebug}; use sp_std::prelude::*; use primitives::{ - LendingPoolCurrencyId as CurrencyId, PriceDetail, Rate, Timestamp, + CurrencyId, PriceDetail, Rate, Timestamp, }; pub mod loans; diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 76482b9210..f6f51dcef8 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -18,8 +18,6 @@ use sp_std::{ prelude::*, }; -pub mod tokens; - pub use bitcoin::types::H256Le; pub const BITCOIN_TESTNET: &str = "bitcoin-testnet"; @@ -371,7 +369,6 @@ pub type Ratio = Permill; pub type Shortfall = FixedU128; pub type Liquidity = FixedU128; pub const SECONDS_PER_YEAR: Timestamp = 365 * 24 * 60 * 60; -pub type LendingPoolCurrencyId = u32; @@ -470,6 +467,15 @@ create_currency_id! { KSM("Kusama", 12) = 10, KBTC("kBTC", 8) = 11, KINT("Kintsugi", 12) = 12, + + // cTokens + CDOT("cPolkadot", 10) = 20, + CIBTC("cinterBTC", 8) = 21, + CINTR("cInterlay", 10) = 22, + + CKSM("cKusama", 12) = 30, + CKBTC("ckBTC", 8) = 31, + CKINT("cKintsugi", 12) = 32, } } diff --git a/primitives/src/tokens.rs b/primitives/src/tokens.rs deleted file mode 100644 index c8c4207b13..0000000000 --- a/primitives/src/tokens.rs +++ /dev/null @@ -1,204 +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. - -use crate::LendingPoolCurrencyId as CurrencyId; - -// Native Token -pub const HKO: CurrencyId = 0; -pub const PARA: CurrencyId = 1; - -// Polkadot ecosystem -pub const KSM: CurrencyId = 100; -pub const DOT: CurrencyId = 101; -pub const USDT: CurrencyId = 102; -pub const KUSD: CurrencyId = 103; -pub const AUSD: CurrencyId = 104; -pub const LC_KSM: CurrencyId = 105; -pub const LC_DOT: CurrencyId = 106; -pub const KAR: CurrencyId = 107; -pub const ACA: CurrencyId = 108; -pub const LKSM: CurrencyId = 109; -pub const LDOT: CurrencyId = 110; -pub const SDN: CurrencyId = 111; -pub const ASTR: CurrencyId = 112; -pub const MOVR: CurrencyId = 113; -pub const GLMR: CurrencyId = 114; -pub const PHA: CurrencyId = 115; -pub const KMA: CurrencyId = 117; -pub const MA: CurrencyId = 118; -pub const KINT: CurrencyId = 119; -pub const INTR: CurrencyId = 120; -pub const KBTC: CurrencyId = 121; -pub const IBTC: CurrencyId = 122; -pub const GENS: CurrencyId = 123; -pub const EQ: CurrencyId = 124; -pub const TUR: CurrencyId = 125; -pub const LIT: CurrencyId = 127; -pub const CLV: CurrencyId = 130; - -// Ethereum ecosystem -pub const EUSDT: CurrencyId = 201; -pub const EUSDC: CurrencyId = 202; -pub const HBTC: CurrencyId = 203; - -// Liquid Staking Derivative -pub const SKSM: CurrencyId = 1000; -pub const SDOT: CurrencyId = 1001; - -// Money Market Derivative -pub const PHKO: CurrencyId = 2000; -pub const PPARA: CurrencyId = 2001; -pub const PKSM: CurrencyId = 2100; -pub const PDOT: CurrencyId = 2101; -pub const PUSDT: CurrencyId = 2102; -pub const PKUSD: CurrencyId = 2103; -pub const PAUSD: CurrencyId = 2104; -pub const PLC_KSM: CurrencyId = 2105; -pub const PLC_DOT: CurrencyId = 2106; -pub const PKAR: CurrencyId = 2107; -pub const PACA: CurrencyId = 2108; -pub const PLKSM: CurrencyId = 2109; -pub const PLDOT: CurrencyId = 2110; - -pub const PEUSDT: CurrencyId = 2201; -pub const PEUSDC: CurrencyId = 2202; - -pub const PSKSM: CurrencyId = 3000; -pub const PSDOT: CurrencyId = 3001; -pub const PKSM_U: CurrencyId = 3002; -pub const PDOT_U: CurrencyId = 3003; - -pub const PCDOT_6_13: CurrencyId = 200062013; -pub const PCDOT_7_14: CurrencyId = 200072014; - -// AMM LP Token -pub const LP_USDT_HKO: CurrencyId = 5000; -pub const LP_KSM_USDT: CurrencyId = 5001; -pub const LP_KSM_HKO: CurrencyId = 5002; -pub const LP_KSM_SKSM: CurrencyId = 5003; -pub const LP_KSM_CKSM_20_27: CurrencyId = 5004; - -pub const LP_USDT_PARA: CurrencyId = 6000; -pub const LP_DOT_USDT: CurrencyId = 6001; -pub const LP_DOT_PARA: CurrencyId = 6002; -pub const LP_DOT_SDOT: CurrencyId = 6003; -pub const LP_DOT_CDOT_6_13: CurrencyId = 6004; -pub const LP_DOT_CDOT_7_14: CurrencyId = 6005; -pub const LP_PARA_CDOT_6_13: CurrencyId = 6006; -pub const LP_DOT_CDOT_8_15: CurrencyId = 6007; - -pub const PLP_USDT_HKO: CurrencyId = 7000; -pub const PLP_KSM_USDT: CurrencyId = 7001; -pub const PLP_KSM_HKO: CurrencyId = 7002; -pub const PLP_KSM_SKSM: CurrencyId = 7003; -pub const PLP_KSM_CKSM_20_27: CurrencyId = 7004; - -pub const PLP_USDT_PARA: CurrencyId = 8000; -pub const PLP_DOT_USDT: CurrencyId = 8001; -pub const PLP_DOT_PARA: CurrencyId = 8002; -pub const PLP_DOT_SDOT: CurrencyId = 8003; -pub const PLP_DOT_CDOT_6_13: CurrencyId = 8004; -pub const PLP_DOT_CDOT_7_14: CurrencyId = 8005; -pub const PLP_PARA_CDOT_6_13: CurrencyId = 8006; -pub const PLP_DOT_CDOT_8_15: CurrencyId = 8007; - -// Crowdloan Derivative -pub const CKSM_15_22: CurrencyId = 100150022; -pub const CKSM_20_27: CurrencyId = 100200027; -pub const CKSM_21_28: CurrencyId = 100210028; -pub const CDOT_6_13: CurrencyId = 200060013; -pub const CDOT_7_14: CurrencyId = 200070014; -pub const CDOT_8_15: CurrencyId = 200080015; - -// Relay Currency Auxiliary -pub const KSM_U: CurrencyId = 4294957295; -pub const DOT_U: CurrencyId = 4294957296; - -// assume all vault token are liquidation free and within range here -pub fn is_vault_token(asset_id: CurrencyId) -> bool { - asset_id > 100000000 && asset_id < 300000000 -} - -// we only care about liquidation fee lp tokens here -// which constructed with vault token and relay token -pub fn is_lf_lp_token(asset_id: CurrencyId) -> bool { - (asset_id > 5003 && asset_id < 6000) || (asset_id > 6003 && asset_id < 7000) -} - -pub fn is_ls_token(asset_id: CurrencyId) -> bool { - asset_id == SKSM || asset_id == SDOT -} - -pub fn is_auxiliary_token(asset_id: CurrencyId) -> bool { - asset_id >= u32::MAX - 10000 -} -// Token Registration Information -// +───────────+──────────────+────────────────────+ -// | Network | Token | Register in block | -// +───────────+──────────────+────────────────────+ -// | Heiko | HKO | Native | -// | Heiko | KSM | N/A | -// | Heiko | USDT | N/A | -// | Heiko | KUSD | N/A | -// | Heiko | EUSDC | N/A | -// | Heiko | EUSDT | N/A | -// | Heiko | KAR | N/A | -// | Heiko | SKSM | N/A | -// | Heiko | CKSM | N/A | -// | Heiko | LKSM | N/A | -// | Heiko | MOVR | N/A | -// | Heiko | SDN | N/A | -// | Heiko | PHA | N/A | -// | Heiko | KMA | N/A | -// | Heiko | KINT | N/A | -// | Heiko | KBTC | N/A | -// | Heiko | GENS | N/A | -// | Heiko | PHKO | N/A | -// | Heiko | PKSM | N/A | -// | Heiko | PUSDT | N/A | -// | Heiko | PKUSD | N/A | -// | Heiko | PEUSDT | N/A | -// | Heiko | PEUSDC | N/A | -// | Heiko | PKAR | N/A | -// | Heiko | PSKSM | N/A | -// | Heiko | PLKSM | N/A | -// | Heiko | PLCKSM | N/A | -// | Heiko | PCKSM | N/A | -// | Parallel | PARA | Native | -// | Parallel | KSM | N/A | -// | Parallel | DOT | N/A | -// | Parallel | USDT | N/A | -// | Parallel | AUSD | N/A | -// | Parallel | EUSDC | N/A | -// | Parallel | EUSDT | N/A | -// | Parallel | ACA | N/A | -// | Parallel | SDOT | N/A | -// | Parallel | CDOT | N/A | -// | Parallel | LDOT | N/A | -// | Parallel | LCDOT | N/A | -// | Parallel | GLMR | N/A | -// | Parallel | ASTR | N/A | -// | Parallel | PPARA | Native | -// | Parallel | PKSM | N/A | -// | Parallel | PDOT | N/A | -// | Parallel | PUSDT | N/A | -// | Parallel | PAUSD | N/A | -// | Parallel | PEUSDC | N/A | -// | Parallel | PEUSDT | N/A | -// | Parallel | PACA | N/A | -// | Parallel | PSDOT | N/A | -// | Parallel | PLDOT | N/A | -// | Parallel | PLCDOT | N/A | -// | Parallel | PCDOT | N/A | -// +──────────+───────────────+────────────────────+ diff --git a/standalone/runtime/src/lib.rs b/standalone/runtime/src/lib.rs index 09da486cdd..a75631f96f 100644 --- a/standalone/runtime/src/lib.rs +++ b/standalone/runtime/src/lib.rs @@ -64,7 +64,7 @@ pub use module_oracle_rpc_runtime_api::BalanceWrapper; pub use security::StatusCode; pub use primitives::{ - self, AccountId, Balance, BlockNumber, CurrencyId, CurrencyId::Token, CurrencyInfo, Hash, Moment, Nonce, Signature, + self, AccountId, Balance, BlockNumber, CurrencyId, CurrencyId::{Token, ForeignAsset}, CurrencyInfo, Hash, Moment, Nonce, Signature, SignedFixedPoint, SignedInner, TokenSymbol, UnsignedFixedPoint, UnsignedInner, DOT, IBTC, INTR, KBTC, KINT, KSM, PriceDetail }; @@ -817,19 +817,6 @@ impl pallet_traits::PriceFeeder for PriceFeed { } } -impl pallet_loans::Config for Runtime { - type Event = Event; - type PalletId = LoansPalletId; - type PriceFeeder = PriceFeed; - type ReserveOrigin = EnsureRoot; - type UpdateOrigin = EnsureRoot; - type WeightInfo = (); - type UnixTime = Timestamp; - type Assets = Tokens; - type RewardAssetId = GetNativeCurrencyId; - type LiquidationFreeAssetId = GetRelayChainCurrencyId; -} - impl currency::Config for Runtime { type SignedInner = SignedInner; type SignedFixedPoint = SignedFixedPoint; @@ -992,6 +979,19 @@ impl clients_info::Config for Runtime { type WeightInfo = (); } +impl pallet_loans::Config for Runtime { + type Event = Event; + type PalletId = LoansPalletId; + type PriceFeeder = PriceFeed; + type ReserveOrigin = EnsureRoot; + type UpdateOrigin = EnsureRoot; + type WeightInfo = (); + type UnixTime = Timestamp; + type Assets = Tokens; + type RewardAssetId = GetNativeCurrencyId; + type LiquidationFreeAssetId = GetRelayChainCurrencyId; +} + construct_runtime! { pub enum Runtime where Block = Block, @@ -1038,6 +1038,8 @@ construct_runtime! { // Refund: 27 Nomination: nomination::{Pallet, Call, Config, Storage, Event} = 28, + Loans: pallet_loans::{Pallet, Call, Storage, Event} = 39, + Identity: pallet_identity::{Pallet, Call, Storage, Event} = 36, ClientsInfo: clients_info::{Pallet, Call, Storage, Event} = 38, From 89a60328ac455ef928b0c18f38566b05c4978877 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Wed, 21 Sep 2022 19:19:10 +0200 Subject: [PATCH 09/58] chore(lend): remove liquidate-free collateral --- crates/loans/src/benchmarking.rs | 7 -- crates/loans/src/lib.rs | 79 +++------------------- crates/loans/src/mock.rs | 4 -- crates/loans/src/tests.rs | 14 ---- crates/loans/src/tests/liquidate_borrow.rs | 32 +-------- crates/loans/src/weights.rs | 15 ---- standalone/runtime/src/lib.rs | 1 - 7 files changed, 10 insertions(+), 142 deletions(-) diff --git a/crates/loans/src/benchmarking.rs b/crates/loans/src/benchmarking.rs index 7e9ea937c7..e0fcceaf26 100644 --- a/crates/loans/src/benchmarking.rs +++ b/crates/loans/src/benchmarking.rs @@ -440,13 +440,6 @@ benchmarks! { verify { assert_last_event::(Event::::ReservesReduced(caller, USDT, reduce_amount.into(), (add_amount-reduce_amount).into()).into()); } - - update_liquidation_free_collateral { - - }: _(SystemOrigin::Root, vec![CDOT_6_13]) - verify { - assert_last_event::(Event::::LiquidationFreeCollateralsUpdated(vec![CDOT_6_13]).into()); - } } impl_benchmark_test_suite!(Loans, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index eb7c0ebf60..89c2140b9f 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -134,9 +134,6 @@ pub mod pallet { /// Reward asset id. #[pallet::constant] type RewardAssetId: Get>; - - #[pallet::constant] - type LiquidationFreeAssetId: Get>; } #[pallet::error] @@ -262,8 +259,6 @@ pub mod pallet { /// Event emitted when the incentive reserves are redeemed and transfer to receiver's account /// [receive_account_id, asset_id, reduced_amount] IncentiveReservesReduced(T::AccountId, AssetIdOf, BalanceOf), - /// Liquidation free collaterals has been updated - LiquidationFreeCollateralsUpdated(Vec>), } /// The timestamp of the last calculation of accrued interest @@ -272,11 +267,6 @@ pub mod pallet { pub type LastAccruedInterestTime = StorageMap<_, Blake2_128Concat, AssetIdOf, Timestamp, ValueQuery>; - /// Liquidation free collateral. - #[pallet::storage] - #[pallet::getter(fn liquidation_free_collaterals)] - pub type LiquidationFreeCollaterals = StorageValue<_, Vec>, ValueQuery>; - /// Total number of collateral tokens in circulation /// CollateralType -> Balance #[pallet::storage] @@ -1092,22 +1082,6 @@ pub mod pallet { Ok(().into()) } - /// Update liquidation free collateral. - /// - /// The `assets` won't be counted when do general - #[pallet::weight(T::WeightInfo::update_liquidation_free_collateral())] - #[transactional] - pub fn update_liquidation_free_collateral( - origin: OriginFor, - collaterals: Vec>, - ) -> DispatchResultWithPostInfo { - T::UpdateOrigin::ensure_origin(origin)?; - LiquidationFreeCollaterals::::mutate(|liquidation_free_collaterals| { - *liquidation_free_collaterals = collaterals.clone() - }); - Self::deposit_event(Event::::LiquidationFreeCollateralsUpdated(collaterals)); - Ok(().into()) - } } } @@ -1116,36 +1090,18 @@ impl Pallet { T::PalletId::get().into_account_truncating() } - fn get_lf_borrowed_value(account: &T::AccountId) -> Result { - let lf_borrowed_amount = - Self::current_borrow_balance(account, T::LiquidationFreeAssetId::get())?; - Self::get_asset_value(T::LiquidationFreeAssetId::get(), lf_borrowed_amount) + fn get_lf_borrowed_value(_account: &T::AccountId) -> Result { + Ok(FixedU128::zero()) } - fn get_lf_base_position(account: &T::AccountId) -> Result { - let mut total_asset_value: FixedU128 = FixedU128::zero(); - for (asset_id, _market) in Self::active_markets() - .filter(|(asset_id, _)| Self::liquidation_free_collaterals().contains(asset_id)) - { - total_asset_value = total_asset_value - .checked_add(&Self::collateral_asset_value(account, asset_id)?) - .ok_or(ArithmeticError::Overflow)?; - } - Ok(total_asset_value) + fn get_lf_base_position(_account: &T::AccountId) -> Result { + Ok(FixedU128::zero()) } fn get_lf_liquidation_base_position( - account: &T::AccountId, + _account: &T::AccountId, ) -> Result { - let mut total_asset_value: FixedU128 = FixedU128::zero(); - for (asset_id, _market) in Self::active_markets() - .filter(|(asset_id, _)| Self::liquidation_free_collaterals().contains(asset_id)) - { - total_asset_value = total_asset_value - .checked_add(&Self::liquidation_threshold_asset_value(account, asset_id)?) - .ok_or(ArithmeticError::Overflow)?; - } - Ok(total_asset_value) + Ok(FixedU128::zero()) } pub fn get_account_liquidity( @@ -1381,7 +1337,6 @@ impl Pallet { Self::ensure_liquidity( redeemer, redeem_effects_value, - Self::liquidation_free_collaterals().contains(&asset_id), )?; Ok(()) @@ -1439,7 +1394,6 @@ impl Pallet { Self::ensure_liquidity( borrower, borrow_value, - asset_id == T::LiquidationFreeAssetId::get(), )?; Ok(()) @@ -1560,16 +1514,7 @@ impl Pallet { let account_borrows = Self::current_borrow_balance(borrower, liquidation_asset_id)?; let account_borrows_value = Self::get_asset_value(liquidation_asset_id, account_borrows)?; let repay_value = Self::get_asset_value(liquidation_asset_id, repay_amount)?; - let effects_borrows_value = if liquidation_asset_id == T::LiquidationFreeAssetId::get() { - let base_position = Self::get_lf_base_position(borrower)?; - if account_borrows_value > base_position { - account_borrows_value - base_position - } else { - FixedU128::zero() - } - } else { - account_borrows_value - }; + let effects_borrows_value = account_borrows_value; if market .close_factor @@ -1851,20 +1796,12 @@ impl Pallet { // Returns `Err` If InsufficientLiquidity // `account`: account that need a liquidity check // `reduce_amount`: values that will have an impact on liquidity - // `lf_enable`: check in liquidation free mode which means borrowing dot or redeeming assets in - // `LiquidationFreeCollaterals`. fn ensure_liquidity( account: &T::AccountId, reduce_amount: FixedU128, - lf_enable: bool, ) -> DispatchResult { let (total_liquidity, _, lf_liquidity, _) = Self::get_account_liquidity(account)?; - - if lf_enable && max(total_liquidity, lf_liquidity) >= reduce_amount { - return Ok(()); - } - - if !lf_enable && total_liquidity >= lf_liquidity + reduce_amount { + if total_liquidity >= lf_liquidity + reduce_amount { return Ok(()); } Err(Error::::InsufficientLiquidity.into()) diff --git a/crates/loans/src/mock.rs b/crates/loans/src/mock.rs index 95d9a3f207..69cd1278ce 100644 --- a/crates/loans/src/mock.rs +++ b/crates/loans/src/mock.rs @@ -242,9 +242,6 @@ parameter_types! { parameter_types! { pub const LoansPalletId: PalletId = PalletId(*b"par/loan"); pub const RewardAssetId: CurrencyId = Token(KINT); - - // Until this is removed, set to a value that's not in use. - pub const LiquidationFreeAssetId: CurrencyId = ForeignAsset(100000); } impl Config for Test { @@ -257,7 +254,6 @@ impl Config for Test { type UnixTime = TimestampPallet; type Assets = Tokens; type RewardAssetId = RewardAssetId; - type LiquidationFreeAssetId = LiquidationFreeAssetId; } pub(crate) fn new_test_ext() -> sp_io::TestExternalities { diff --git a/crates/loans/src/tests.rs b/crates/loans/src/tests.rs index 8be07196b1..b11756cc68 100644 --- a/crates/loans/src/tests.rs +++ b/crates/loans/src/tests.rs @@ -223,7 +223,6 @@ fn redeem_allowed_works() { fn lf_redeem_allowed_works() { new_test_ext().execute_with(|| { // Set CDOT as lf collateral - Loans::update_liquidation_free_collateral(Origin::root(), vec![CDOT_6_13]).unwrap(); Loans::mint(Origin::signed(ALICE), CDOT_6_13, unit(200)).unwrap(); Loans::mint(Origin::signed(DAVE), USDT, unit(200)).unwrap(); @@ -248,8 +247,6 @@ fn lf_redeem_allowed_works() { // But it'll success when redeem cdot assert_ok!(Loans::redeem_allowed(CDOT_6_13, &ALICE, unit(100))); - // Remove CDOT from lf collateral - Loans::update_liquidation_free_collateral(Origin::root(), vec![]).unwrap(); // Then it can be redeemed assert_ok!(Loans::redeem_allowed(KSM, &ALICE, unit(100))); }) @@ -394,17 +391,6 @@ fn borrow_allowed_works() { }) } -#[test] -fn update_liquidation_free_collateral_works() { - new_test_ext().execute_with(|| { - assert_ok!(Loans::update_liquidation_free_collateral( - Origin::root(), - vec![CDOT_6_13] - )); - assert_eq!(Loans::liquidation_free_collaterals(), vec![CDOT_6_13]); - }) -} - #[test] fn get_account_liquidity_works() { new_test_ext().execute_with(|| { diff --git a/crates/loans/src/tests/liquidate_borrow.rs b/crates/loans/src/tests/liquidate_borrow.rs index 2ba058ed81..84437fafec 100644 --- a/crates/loans/src/tests/liquidate_borrow.rs +++ b/crates/loans/src/tests/liquidate_borrow.rs @@ -47,30 +47,12 @@ fn liquidate_borrow_allowed_works() { }) } -// ignore: tests liquidation-free collateral -#[ignore] -#[test] -fn lf_liquidate_borrow_fails_due_to_lf_collateral() { - new_test_ext().execute_with(|| { - Loans::update_liquidation_free_collateral(Origin::root(), vec![CDOT_6_13]).unwrap(); - - assert_err!( - Loans::liquidate_borrow(Origin::signed(ALICE), BOB, DOT, unit(100), CDOT_6_13), - Error::::CollateralReserved - ); - assert_err!( - Loans::liquidate_borrow(Origin::signed(ALICE), BOB, DOT, unit(100), DOT_U), - Error::::CollateralReserved - ); - }) -} - // ignore: tests liquidation-free collateral #[ignore] #[test] fn lf_liquidate_borrow_allowed_works() { new_test_ext().execute_with(|| { - Loans::update_liquidation_free_collateral(Origin::root(), vec![CDOT_6_13]).unwrap(); + // Loans::update_liquidation_free_collateral(Origin::root(), vec![CDOT_6_13]).unwrap(); // Bob deposits $200 DOT Loans::mint(Origin::signed(BOB), DOT, unit(200)).unwrap(); Loans::mint(Origin::signed(ALICE), USDT, unit(200)).unwrap(); @@ -107,7 +89,7 @@ fn lf_liquidate_borrow_allowed_works() { )); // Remove CDOT from lf collateral - Loans::update_liquidation_free_collateral(Origin::root(), vec![]).unwrap(); + // Loans::update_liquidation_free_collateral(Origin::root(), vec![]).unwrap(); // The max repay amount = 400 * 50 = $200 assert_ok!(Loans::liquidate_borrow_allowed( &ALICE, @@ -277,14 +259,4 @@ fn initial_setup() { // Alice deposits 200 DOT as collateral assert_ok!(Loans::mint(Origin::signed(ALICE), USDT, unit(200))); assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), USDT, true)); - assert_ok!(Loans::mint(Origin::signed(ALICE), CDOT_6_13, unit(200))); - assert_ok!(Loans::collateral_asset( - Origin::signed(ALICE), - CDOT_6_13, - true - )); - assert_ok!(Loans::update_liquidation_free_collateral( - Origin::root(), - vec![CDOT_6_13] - )); } diff --git a/crates/loans/src/weights.rs b/crates/loans/src/weights.rs index 30831de0dd..c641ce871f 100644 --- a/crates/loans/src/weights.rs +++ b/crates/loans/src/weights.rs @@ -65,7 +65,6 @@ pub trait WeightInfo { fn liquidate_borrow() -> Weight; fn add_reserves() -> Weight; fn reduce_reserves() -> Weight; - fn update_liquidation_free_collateral() -> Weight; } /// Weights for pallet_loans using the Substrate node and recommended hardware. @@ -352,13 +351,6 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) - // Storage: Loans LiquidationFreeCollaterals (r:1 w:1) - fn update_liquidation_free_collateral() -> Weight { - (37_654_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - } } // For backwards compatibility and tests @@ -644,11 +636,4 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) - // Storage: Loans LiquidationFreeCollaterals (r:1 w:1) - fn update_liquidation_free_collateral() -> Weight { - (37_654_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) - } } diff --git a/standalone/runtime/src/lib.rs b/standalone/runtime/src/lib.rs index a75631f96f..937b66409f 100644 --- a/standalone/runtime/src/lib.rs +++ b/standalone/runtime/src/lib.rs @@ -989,7 +989,6 @@ impl pallet_loans::Config for Runtime { type UnixTime = Timestamp; type Assets = Tokens; type RewardAssetId = GetNativeCurrencyId; - type LiquidationFreeAssetId = GetRelayChainCurrencyId; } construct_runtime! { From 590a405b0d65ab321d9b5af1df4c4dd3ee4c781f Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Thu, 22 Sep 2022 18:52:34 +0200 Subject: [PATCH 10/58] fix(lend): btc oracle integration, notes on integrating pTokens with orml-tokens --- crates/currency/src/amount.rs | 8 ++ crates/loans/src/lib.rs | 13 +++ standalone/runtime/src/lib.rs | 16 +++- standalone/runtime/tests/mock/mod.rs | 4 + standalone/runtime/tests/test_loans.rs | 128 +++++++++++++++++++++++++ 5 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 standalone/runtime/tests/test_loans.rs diff --git a/crates/currency/src/amount.rs b/crates/currency/src/amount.rs index 63a542c40c..5f0ffeee35 100644 --- a/crates/currency/src/amount.rs +++ b/crates/currency/src/amount.rs @@ -245,13 +245,17 @@ mod actions { destination, self.amount, ) + // if ptoken, must also call `Loans::transfer(...)` besides the orml-transfer } pub fn lock_on(&self, account_id: &T::AccountId) -> Result<(), DispatchError> { + // Once locked, pToken should not be withdrawable from lending pool + // TODO: Update loans pallet logic >::reserve(self.currency_id, account_id, self.amount) } pub fn unlock_on(&self, account_id: &T::AccountId) -> Result<(), DispatchError> { + // Should make pToken withdrawable from lending pool ensure!( >::unreserve(self.currency_id, account_id, self.amount).is_zero(), orml_tokens::Error::::BalanceTooLow @@ -260,6 +264,8 @@ mod actions { } pub fn burn_from(&self, account_id: &T::AccountId) -> DispatchResult { + // Called from Loans pallet + // burn ptokens when calling `Loans::redeem(...)` ensure!( >::slash_reserved(self.currency_id, account_id, self.amount).is_zero(), orml_tokens::Error::::BalanceTooLow @@ -268,6 +274,8 @@ mod actions { } pub fn mint_to(&self, account_id: &T::AccountId) -> DispatchResult { + // Called from Loans pallet + // mint ptokens when calling `Loans::mint(...)` >::deposit(self.currency_id, account_id, self.amount) } diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 89c2140b9f..a50762de7f 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -856,6 +856,8 @@ pub mod pallet { Self::accrue_interest(asset_id)?; let exchange_rate = Self::exchange_rate_stored(asset_id)?; Self::update_earned_stored(&who, asset_id, exchange_rate)?; + // let deposits = orml_tokens::Pallet::::accounts(who, asset_id); + let deposits = AccountDeposits::::get(asset_id, &who); let redeem_amount = Self::do_redeem_voucher(&who, asset_id, deposits.voucher_balance)?; Self::deposit_event(Event::::Redeemed(who, asset_id, redeem_amount)); @@ -930,6 +932,8 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; Self::ensure_active_market(asset_id)?; + // let account_data = orml_tokens::Pallet::::accounts(who, asset_id); + // ensure!(!account_data.free.is_zero()); ensure!( AccountDeposits::::contains_key(asset_id, &who), Error::::NoDeposit @@ -1221,6 +1225,8 @@ impl Pallet { supplier: &T::AccountId, asset_id: AssetIdOf, ) -> Result, DispatchError> { + // let account_data = orml_tokens::Pallet::::accounts(who, asset_id); + // if account_data.free.is_zero() { return Ok(BalanceOf::::zero()); } if !AccountDeposits::::contains_key(asset_id, supplier) { return Ok(BalanceOf::::zero()); } @@ -1253,6 +1259,9 @@ impl Pallet { borrower: &T::AccountId, asset_id: AssetIdOf, ) -> Result { + // let account_data = orml_tokens::Pallet::::accounts(who, asset_id); + // if account_data.free.is_zero() { return Ok(BalanceOf::::zero()); } + if !AccountDeposits::::contains_key(asset_id, borrower) { return Ok(FixedU128::zero()); } @@ -1355,6 +1364,7 @@ impl Pallet { let exchange_rate = Self::exchange_rate_stored(asset_id)?; let redeem_amount = Self::calc_underlying_amount(voucher_amount, exchange_rate)?; + // TODO: Amount::new(voucher_amount, asset_id).burn_from(who) AccountDeposits::::try_mutate_exists(asset_id, who, |deposits| -> DispatchResult { let mut d = deposits.unwrap_or_default(); d.voucher_balance = d @@ -1462,6 +1472,7 @@ impl Pallet { asset_id: AssetIdOf, exchange_rate: Rate, ) -> DispatchResult { + // let account_data = orml_tokens::Pallet::::accounts(who, asset_id); let deposits = AccountDeposits::::get(asset_id, who); let account_earned = AccountEarned::::get(asset_id, who); let total_earned_prior_new = exchange_rate @@ -1949,6 +1960,8 @@ impl LoansTrait, AccountIdOf, BalanceOf> for Palle ensure!(!voucher_amount.is_zero(), Error::::InvalidExchangeRate); T::Assets::transfer(asset_id, supplier, &Self::account_id(), amount, false)?; + + // TODO: Mint `voucher_amount` tokens to `supplier` AccountDeposits::::try_mutate(asset_id, supplier, |deposits| -> DispatchResult { deposits.voucher_balance = deposits .voucher_balance diff --git a/standalone/runtime/src/lib.rs b/standalone/runtime/src/lib.rs index 937b66409f..d9ffeed2d3 100644 --- a/standalone/runtime/src/lib.rs +++ b/standalone/runtime/src/lib.rs @@ -811,9 +811,21 @@ impl currency::CurrencyConversion, CurrencyId> for Cur pub struct PriceFeed; impl pallet_traits::PriceFeeder for PriceFeed { fn get_price(asset_id: &CurrencyId) -> Option { - Oracle::get_price(oracle::OracleKey::ExchangeRate(*asset_id)) + let one = match asset_id { + Token(t) => t.one(), + ForeignAsset(f) => { + // TODO: Either add `one` to the AssetRegistry or require this as an associated type in the config trait + if let Some(metadata) = AssetRegistry::metadata(f) { + 10u128.pow(metadata.decimals) + } else { + return None; + } + } + }; + let amount = Amount::::new(one, asset_id.clone()); + Oracle::convert(&amount, WRAPPED_CURRENCY_ID) .ok() - .map(|price| (price, Timestamp::now())) + .map(|price| (price.amount().into(), Timestamp::now())) } } diff --git a/standalone/runtime/tests/mock/mod.rs b/standalone/runtime/tests/mock/mod.rs index 5aa11ab67d..87da39375c 100644 --- a/standalone/runtime/tests/mock/mod.rs +++ b/standalone/runtime/tests/mock/mod.rs @@ -178,6 +178,10 @@ pub type SchedulerPallet = pallet_scheduler::Pallet; pub type ServicesCall = clients_info::Call; pub type ServicesPallet = clients_info::Pallet; +pub type LoansCall = pallet_loans::Call; +pub type LoansError = pallet_loans::Error; +pub type LoansPallet = pallet_loans::Pallet; + pub const DEFAULT_COLLATERAL_CURRENCY: ::CurrencyId = Token(DOT); pub const DEFAULT_WRAPPED_CURRENCY: ::CurrencyId = Token(IBTC); pub const DEFAULT_NATIVE_CURRENCY: ::CurrencyId = Token(INTR); diff --git a/standalone/runtime/tests/test_loans.rs b/standalone/runtime/tests/test_loans.rs new file mode 100644 index 0000000000..a335b7d322 --- /dev/null +++ b/standalone/runtime/tests/test_loans.rs @@ -0,0 +1,128 @@ +use interbtc_runtime_standalone::{CurrencyId::Token, KINT}; +mod mock; +use mock::{assert_eq, *}; +use oracle::types::UnsignedFixedPoint; +use pallet_loans::{MarketState, InterestRateModel, JumpModel, Market}; +use primitives::{CKINT, Ratio, Rate, CKSM}; +use sp_runtime::traits::CheckedMul; + +pub const USER: [u8; 32] = ALICE; +pub const LP: [u8; 32] = BOB; + + +pub const fn market_mock(ptoken_id: CurrencyId) -> Market { + Market { + close_factor: Ratio::from_percent(50), + collateral_factor: Ratio::from_percent(50), + liquidation_threshold: Ratio::from_percent(55), + liquidate_incentive: Rate::from_inner(Rate::DIV / 100 * 110), + liquidate_incentive_reserved_factor: Ratio::from_percent(3), + state: MarketState::Pending, + rate_model: InterestRateModel::Jump(JumpModel { + base_rate: Rate::from_inner(Rate::DIV / 100 * 2), + jump_rate: Rate::from_inner(Rate::DIV / 100 * 10), + full_rate: Rate::from_inner(Rate::DIV / 100 * 32), + jump_utilization: Ratio::from_percent(80), + }), + reserve_factor: Ratio::from_percent(15), + supply_cap: 1_000_000_000_000_000_000_000u128, // set to 1B + borrow_cap: 1_000_000_000_000_000_000_000u128, // set to 1B + ptoken_id, + } +} + +fn set_up_market(currency_id: CurrencyId, exchange_rate: FixedU128, ctoken_id: CurrencyId) { + assert_ok!(OraclePallet::_set_exchange_rate(currency_id, exchange_rate)); + assert_ok!(Call::Sudo(SudoCall::sudo { + call: Box::new(Call::Loans(LoansCall::add_market { + asset_id: currency_id, + market: market_mock(ctoken_id), + })), + }) + .dispatch(origin_of(account_of(ALICE)))); + + assert_ok!(Call::Sudo(SudoCall::sudo { + call: Box::new(Call::Loans(LoansCall::activate_market { + asset_id: currency_id, + })), + }) + .dispatch(origin_of(account_of(ALICE)))); +} + +fn test_real_market(execute: impl Fn() -> R) { + ExtBuilder::build().execute_with(|| { + // Use real market data for the exchange rates + set_up_market(Token(KINT), FixedU128::from_inner(115_942_028_985_507_246_376_810_000), Token(CKINT)); + set_up_market(Token(KSM), FixedU128::from_inner(4_573_498_406_135_805_461_670_000), Token(CKSM)); + execute() + }); +} + +#[test] +fn integration_test_issue_expiry_only_parachain_blocks_expired() { + test_real_market(|| { + let kint = Token(KINT); + let ksm = Token(KSM); + + assert_ok!( + Call::Loans(LoansCall::mint { + asset_id: kint, + mint_amount: 1000, + }).dispatch(origin_of(account_of(USER))) + ); + + assert_ok!( + Call::Loans(LoansCall::mint { + asset_id: ksm, + mint_amount: 50, + }).dispatch(origin_of(account_of(LP))) + ); + + assert_ok!( + Call::Loans(LoansCall::collateral_asset { + asset_id: kint, + enable: true, + }).dispatch(origin_of(account_of(USER))) + ); + + assert_err!( + Call::Loans(LoansCall::borrow { + asset_id: ksm, + borrow_amount: 20, + }).dispatch(origin_of(account_of(USER))), + LoansError::InsufficientLiquidity + ); + + assert_ok!( + Call::Loans(LoansCall::borrow { + asset_id: ksm, + borrow_amount: 15, + }).dispatch(origin_of(account_of(USER))) + ); + + assert_err!( + Call::Loans(LoansCall::liquidate_borrow { + borrower: account_of(USER), + liquidation_asset_id: ksm, + repay_amount: 15, + collateral_asset_id: kint + }).dispatch(origin_of(account_of(LP))), + LoansError::InsufficientShortfall + ); + + // KINT price drops to half + let kint_rate = OraclePallet::get_price(OracleKey::ExchangeRate(kint)).unwrap(); + assert_ok!(OraclePallet::_set_exchange_rate(kint, kint_rate.checked_mul(&2.into()).unwrap())); + + assert_ok!( + Call::Loans(LoansCall::liquidate_borrow { + borrower: account_of(USER), + liquidation_asset_id: ksm, + repay_amount: 7, + collateral_asset_id: kint + }).dispatch(origin_of(account_of(LP))) + ); + + }); + +} \ No newline at end of file From cf8a1b0cb1e6fadbcd5e0e1aec310d5fe1af3b53 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Fri, 7 Oct 2022 15:25:38 +0200 Subject: [PATCH 11/58] refactor(lend): cleanup --- crates/currency/src/amount.rs | 8 -------- crates/loans/src/lib.rs | 9 --------- 2 files changed, 17 deletions(-) diff --git a/crates/currency/src/amount.rs b/crates/currency/src/amount.rs index 5f0ffeee35..63a542c40c 100644 --- a/crates/currency/src/amount.rs +++ b/crates/currency/src/amount.rs @@ -245,17 +245,13 @@ mod actions { destination, self.amount, ) - // if ptoken, must also call `Loans::transfer(...)` besides the orml-transfer } pub fn lock_on(&self, account_id: &T::AccountId) -> Result<(), DispatchError> { - // Once locked, pToken should not be withdrawable from lending pool - // TODO: Update loans pallet logic >::reserve(self.currency_id, account_id, self.amount) } pub fn unlock_on(&self, account_id: &T::AccountId) -> Result<(), DispatchError> { - // Should make pToken withdrawable from lending pool ensure!( >::unreserve(self.currency_id, account_id, self.amount).is_zero(), orml_tokens::Error::::BalanceTooLow @@ -264,8 +260,6 @@ mod actions { } pub fn burn_from(&self, account_id: &T::AccountId) -> DispatchResult { - // Called from Loans pallet - // burn ptokens when calling `Loans::redeem(...)` ensure!( >::slash_reserved(self.currency_id, account_id, self.amount).is_zero(), orml_tokens::Error::::BalanceTooLow @@ -274,8 +268,6 @@ mod actions { } pub fn mint_to(&self, account_id: &T::AccountId) -> DispatchResult { - // Called from Loans pallet - // mint ptokens when calling `Loans::mint(...)` >::deposit(self.currency_id, account_id, self.amount) } diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index a50762de7f..563c73f2b4 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -856,8 +856,6 @@ pub mod pallet { Self::accrue_interest(asset_id)?; let exchange_rate = Self::exchange_rate_stored(asset_id)?; Self::update_earned_stored(&who, asset_id, exchange_rate)?; - // let deposits = orml_tokens::Pallet::::accounts(who, asset_id); - let deposits = AccountDeposits::::get(asset_id, &who); let redeem_amount = Self::do_redeem_voucher(&who, asset_id, deposits.voucher_balance)?; Self::deposit_event(Event::::Redeemed(who, asset_id, redeem_amount)); @@ -932,8 +930,6 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; Self::ensure_active_market(asset_id)?; - // let account_data = orml_tokens::Pallet::::accounts(who, asset_id); - // ensure!(!account_data.free.is_zero()); ensure!( AccountDeposits::::contains_key(asset_id, &who), Error::::NoDeposit @@ -1225,7 +1221,6 @@ impl Pallet { supplier: &T::AccountId, asset_id: AssetIdOf, ) -> Result, DispatchError> { - // let account_data = orml_tokens::Pallet::::accounts(who, asset_id); // if account_data.free.is_zero() { return Ok(BalanceOf::::zero()); } if !AccountDeposits::::contains_key(asset_id, supplier) { return Ok(BalanceOf::::zero()); @@ -1259,9 +1254,6 @@ impl Pallet { borrower: &T::AccountId, asset_id: AssetIdOf, ) -> Result { - // let account_data = orml_tokens::Pallet::::accounts(who, asset_id); - // if account_data.free.is_zero() { return Ok(BalanceOf::::zero()); } - if !AccountDeposits::::contains_key(asset_id, borrower) { return Ok(FixedU128::zero()); } @@ -1472,7 +1464,6 @@ impl Pallet { asset_id: AssetIdOf, exchange_rate: Rate, ) -> DispatchResult { - // let account_data = orml_tokens::Pallet::::accounts(who, asset_id); let deposits = AccountDeposits::::get(asset_id, who); let account_earned = AccountEarned::::get(asset_id, who); let total_earned_prior_new = exchange_rate From 7c41e20c20d6213661c16a7481cedd17b0141d73 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Fri, 7 Oct 2022 17:52:46 +0200 Subject: [PATCH 12/58] feat(lend): update benchmarks and copyrights --- crates/loans/Cargo.toml | 2 +- crates/loans/rpc/Cargo.toml | 2 +- crates/loans/rpc/runtime-api/Cargo.toml | 2 +- crates/loans/rpc/runtime-api/src/lib.rs | 3 + crates/loans/rpc/src/lib.rs | 3 + crates/loans/src/benchmarking.rs | 134 ++++----------------- crates/loans/src/farming.rs | 3 + crates/loans/src/interest.rs | 3 + crates/loans/src/lib.rs | 7 +- crates/loans/src/mock.rs | 12 +- crates/loans/src/ptoken.rs | 3 + crates/loans/src/rate_model.rs | 3 + crates/loans/src/tests.rs | 5 + crates/loans/src/tests/edge_cases.rs | 4 +- crates/loans/src/tests/liquidate_borrow.rs | 7 +- crates/loans/src/tests/market.rs | 5 +- crates/loans/src/weights.rs | 3 + standalone/runtime/tests/test_issue.rs | 1 - standalone/runtime/tests/test_loans.rs | 5 +- 19 files changed, 77 insertions(+), 130 deletions(-) diff --git a/crates/loans/Cargo.toml b/crates/loans/Cargo.toml index 96f4f4b51a..ce61bca382 100644 --- a/crates/loans/Cargo.toml +++ b/crates/loans/Cargo.toml @@ -1,5 +1,5 @@ [package] -authors = ['Parallel Team'] +authors = ['Interlay Ltd'] edition = '2021' name = 'pallet-loans' version = '1.9.3' diff --git a/crates/loans/rpc/Cargo.toml b/crates/loans/rpc/Cargo.toml index 3d50d19294..3b03ae2c45 100644 --- a/crates/loans/rpc/Cargo.toml +++ b/crates/loans/rpc/Cargo.toml @@ -1,5 +1,5 @@ [package] -authors = ['Parallel Team'] +authors = ['Interlay Ltd'] edition = '2021' name = 'pallet-loans-rpc' version = '1.9.3' diff --git a/crates/loans/rpc/runtime-api/Cargo.toml b/crates/loans/rpc/runtime-api/Cargo.toml index f3fccc5836..d9ff669a1d 100644 --- a/crates/loans/rpc/runtime-api/Cargo.toml +++ b/crates/loans/rpc/runtime-api/Cargo.toml @@ -1,5 +1,5 @@ [package] -authors = ['Parallel Team'] +authors = ['Interlay Ltd'] edition = '2021' name = 'pallet-loans-rpc-runtime-api' version = '1.9.3' diff --git a/crates/loans/rpc/runtime-api/src/lib.rs b/crates/loans/rpc/runtime-api/src/lib.rs index 4530b907e3..e55af63788 100644 --- a/crates/loans/rpc/runtime-api/src/lib.rs +++ b/crates/loans/rpc/runtime-api/src/lib.rs @@ -1,3 +1,6 @@ +// Copyright 2022 Interlay. +// This file is part of Interlay. + // Copyright 2021 Parallel Finance Developer. // This file is part of Parallel Finance. diff --git a/crates/loans/rpc/src/lib.rs b/crates/loans/rpc/src/lib.rs index fc7fa1bfc7..c5c787ffe4 100644 --- a/crates/loans/rpc/src/lib.rs +++ b/crates/loans/rpc/src/lib.rs @@ -1,3 +1,6 @@ +// Copyright 2022 Interlay. +// This file is part of Interlay. + // Copyright 2021 Parallel Finance Developer. // This file is part of Parallel Finance. diff --git a/crates/loans/src/benchmarking.rs b/crates/loans/src/benchmarking.rs index e0fcceaf26..8946066553 100644 --- a/crates/loans/src/benchmarking.rs +++ b/crates/loans/src/benchmarking.rs @@ -8,14 +8,23 @@ use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whiteli use frame_support::assert_ok; use frame_system::{self, RawOrigin as SystemOrigin}; use primitives::{ - tokens::{CDOT_6_13, DOT, KSM, PKSM, PSKSM, PUSDT, SKSM, USDT}, - Balance, CurrencyId, + Balance, + CurrencyId::{self, Token}, + CDOT as SKSM_CURRENCY, CKINT, CKSM as PSKSM_CURRENCY, INTR as PUSDT_CURRENCY, KBTC as USDT_CURRENCY, + KINT as PKSM_CURRENCY, KSM as KSM_CURRENCY, }; use rate_model::{InterestRateModel, JumpModel}; use sp_std::prelude::*; const SEED: u32 = 0; +const KSM: CurrencyId = Token(KSM_CURRENCY); +const USDT: CurrencyId = Token(USDT_CURRENCY); +const PKSM: CurrencyId = Token(PKSM_CURRENCY); +const PUSDT: CurrencyId = Token(PUSDT_CURRENCY); +const SKSM: CurrencyId = Token(SKSM_CURRENCY); +const PSKSM: CurrencyId = Token(PSKSM_CURRENCY); + const RATE_MODEL_MOCK: InterestRateModel = InterestRateModel::Jump(JumpModel { base_rate: Rate::from_inner(Rate::DIV / 100 * 2), jump_rate: Rate::from_inner(Rate::DIV / 100 * 10), @@ -40,7 +49,7 @@ fn market_mock() -> Market> { liquidate_incentive_reserved_factor: Ratio::from_percent(3), supply_cap: 1_000_000_000_000_000_000_000u128, // set to 1B borrow_cap: 1_000_000_000_000_000_000_000u128, // set to 1B - ptoken_id: 1200, + ptoken_id: CurrencyId::Token(CKINT), } } @@ -51,119 +60,28 @@ fn pending_market_mock(ptoken_id: CurrencyId) -> Market> market } -const INITIAL_AMOUNT: u32 = 500_000_000; - -fn transfer_initial_balance< - T: Config - + pallet_assets::Config - + pallet_prices::Config - + pallet_balances::Config, ->( +fn transfer_initial_balance>( caller: T::AccountId, ) { let account_id = T::Lookup::unlookup(caller.clone()); - pallet_assets::Pallet::::force_create( - SystemOrigin::Root.into(), - KSM, - account_id.clone(), - true, - 1, - ) - .ok(); - pallet_assets::Pallet::::force_create( - SystemOrigin::Root.into(), - SKSM, - account_id.clone(), - true, - 1, - ) - .ok(); - pallet_assets::Pallet::::force_create( - SystemOrigin::Root.into(), - DOT, - account_id.clone(), - true, - 1, - ) - .ok(); - pallet_assets::Pallet::::force_create( - SystemOrigin::Root.into(), - CDOT_6_13, - account_id.clone(), - true, - 1, - ) - .ok(); - pallet_assets::Pallet::::force_create( - SystemOrigin::Root.into(), - USDT, - account_id.clone(), - true, - 1, - ) - .ok(); - pallet_assets::Pallet::::force_set_metadata( - SystemOrigin::Root.into(), - KSM, - b"kusama".to_vec(), - b"KSM".to_vec(), - 12, - true, - ) - .ok(); - pallet_assets::Pallet::::force_set_metadata( - SystemOrigin::Root.into(), - SKSM, - b"xkusama".to_vec(), - b"sKSM".to_vec(), - 12, - true, - ) - .ok(); - pallet_assets::Pallet::::force_set_metadata( - SystemOrigin::Root.into(), - DOT, - b"polkadot".to_vec(), - b"DOT".to_vec(), - 12, - true, - ) - .ok(); - pallet_assets::Pallet::::force_set_metadata( - SystemOrigin::Root.into(), - CDOT_6_13, - b"cDot_6_13".to_vec(), - b"cDot_6_13".to_vec(), - 12, - true, - ) - .ok(); - pallet_assets::Pallet::::force_set_metadata( - SystemOrigin::Root.into(), - USDT, - b"tether".to_vec(), - b"USDT".to_vec(), - 6, - true, - ) - .ok(); - pallet_balances::Pallet::::set_balance( + orml_tokens::Pallet::::set_balance( SystemOrigin::Root.into(), account_id, + USDT, 10_000_000_000_000_u128, 0_u128, ) .unwrap(); - ::Assets::mint_into(USDT, &caller, INITIAL_AMOUNT.into()).unwrap(); - ::Assets::mint_into(KSM, &caller, INITIAL_AMOUNT.into()).unwrap(); - ::Assets::mint_into(SKSM, &caller, INITIAL_AMOUNT.into()).unwrap(); - ::Assets::mint_into(DOT, &caller, INITIAL_AMOUNT.into()).unwrap(); - ::Assets::mint_into(CDOT_6_13, &caller, INITIAL_AMOUNT.into()).unwrap(); - pallet_prices::Pallet::::set_price(SystemOrigin::Root.into(), USDT, 1.into()).unwrap(); - pallet_prices::Pallet::::set_price(SystemOrigin::Root.into(), KSM, 1.into()).unwrap(); - pallet_prices::Pallet::::set_price(SystemOrigin::Root.into(), SKSM, 1.into()).unwrap(); - pallet_prices::Pallet::::set_price(SystemOrigin::Root.into(), DOT, 1.into()).unwrap(); - pallet_prices::Pallet::::set_price(SystemOrigin::Root.into(), CDOT_6_13, 1.into()).unwrap(); + // ::Assets::mint_into(USDT, &caller, INITIAL_AMOUNT.into()).unwrap(); + // ::Assets::mint_into(KSM, &caller, INITIAL_AMOUNT.into()).unwrap(); + // ::Assets::mint_into(SKSM, &caller, INITIAL_AMOUNT.into()).unwrap(); + // ::Assets::mint_into(DOT, &caller, INITIAL_AMOUNT.into()).unwrap(); + // ::Assets::mint_into(CDOT_6_13, &caller, INITIAL_AMOUNT.into()).unwrap(); + // orml_tokens::Pallet::::set_price(SystemOrigin::Root.into(), USDT, 1.into()).unwrap(); + // orml_tokens::Pallet::::set_price(SystemOrigin::Root.into(), KSM, 1.into()).unwrap(); + // orml_tokens::Pallet::::set_price(SystemOrigin::Root.into(), SKSM, 1.into()).unwrap(); + // orml_tokens::Pallet::::set_price(SystemOrigin::Root.into(), DOT, 1.into()).unwrap(); + // orml_tokens::Pallet::::set_price(SystemOrigin::Root.into(), CDOT_6_13, 1.into()).unwrap(); } fn set_account_borrows( @@ -190,7 +108,7 @@ fn assert_last_event(generic_event: ::Event) { benchmarks! { where_clause { where - T: pallet_assets::Config + pallet_prices::Config + pallet_balances::Config + T: orml_tokens::Config } add_market { diff --git a/crates/loans/src/farming.rs b/crates/loans/src/farming.rs index b63af86725..2be948c15d 100644 --- a/crates/loans/src/farming.rs +++ b/crates/loans/src/farming.rs @@ -1,3 +1,6 @@ +// Copyright 2022 Interlay. +// This file is part of Interlay. + // Copyright 2021 Parallel Finance Developer. // This file is part of Parallel Finance. diff --git a/crates/loans/src/interest.rs b/crates/loans/src/interest.rs index 7176c2033c..65c4362db6 100644 --- a/crates/loans/src/interest.rs +++ b/crates/loans/src/interest.rs @@ -1,3 +1,6 @@ +// Copyright 2022 Interlay. +// This file is part of Interlay. + // Copyright 2021 Parallel Finance Developer. // This file is part of Parallel Finance. diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 563c73f2b4..b75926e38b 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -1,3 +1,6 @@ +// Copyright 2022 Interlay. +// This file is part of Interlay. + // Copyright 2021 Parallel Finance Developer. // This file is part of Parallel Finance. @@ -22,8 +25,6 @@ #![cfg_attr(not(feature = "std"), no_std)] -use core::cmp::max; - pub use crate::rate_model::*; use frame_support::{ @@ -53,7 +54,7 @@ use sp_runtime::{ }, ArithmeticError, FixedPointNumber, FixedU128, }; -use sp_std::{result::Result, vec::Vec}; +use sp_std::result::Result; use sp_io::hashing::blake2_256; pub use types::{BorrowSnapshot, Deposits, EarnedSnapshot, Market, MarketState, RewardMarketState}; diff --git a/crates/loans/src/mock.rs b/crates/loans/src/mock.rs index 69cd1278ce..96f983ccd3 100644 --- a/crates/loans/src/mock.rs +++ b/crates/loans/src/mock.rs @@ -1,3 +1,6 @@ +// Copyright 2022 Interlay. +// This file is part of Interlay. + // Copyright 2021 Parallel Finance Developer. // This file is part of Parallel Finance. @@ -17,12 +20,9 @@ pub use super::*; use frame_support::{ construct_runtime, parameter_types, traits::Everything, traits::SortedMembers, PalletId, }; -use frame_system::{EnsureRoot, EnsureSignedBy}; -use orml_traits::{DataFeeder, DataProvider, DataProviderExtended, parameter_type_with_key}; -use pallet_traits::{ - DecimalProvider, ExchangeRateProvider, LiquidStakingCurrenciesProvider, - VaultTokenCurrenciesFilter, VaultTokenExchangeRateProvider, -}; +use frame_system::EnsureRoot; +use orml_traits::{parameter_type_with_key, DataFeeder, DataProvider, DataProviderExtended}; +use pallet_traits::{VaultTokenCurrenciesFilter, VaultTokenExchangeRateProvider}; use primitives::{ CurrencyId::{Token, ForeignAsset}, Moment, PriceDetail, KSM, CKINT, CKSM, CDOT, CKBTC, KINT, DOT, KBTC, INTR, IBTC, CIBTC, diff --git a/crates/loans/src/ptoken.rs b/crates/loans/src/ptoken.rs index ac92c8d24c..4fd0f052a5 100644 --- a/crates/loans/src/ptoken.rs +++ b/crates/loans/src/ptoken.rs @@ -1,3 +1,6 @@ +// Copyright 2022 Interlay. +// This file is part of Interlay. + // Copyright 2021 Parallel Finance Developer. // This file is part of Parallel Finance. diff --git a/crates/loans/src/rate_model.rs b/crates/loans/src/rate_model.rs index befe77b16e..fd46b2712f 100644 --- a/crates/loans/src/rate_model.rs +++ b/crates/loans/src/rate_model.rs @@ -1,3 +1,6 @@ +// Copyright 2022 Interlay. +// This file is part of Interlay. + // Copyright 2021 Parallel Finance Developer. // This file is part of Parallel Finance. diff --git a/crates/loans/src/tests.rs b/crates/loans/src/tests.rs index b11756cc68..c073b912b5 100644 --- a/crates/loans/src/tests.rs +++ b/crates/loans/src/tests.rs @@ -1,3 +1,6 @@ +// Copyright 2022 Interlay. +// This file is part of Interlay. + // Copyright 2021 Parallel Finance Developer. // This file is part of Parallel Finance. @@ -29,6 +32,8 @@ use primitives::{CurrencyId::Token, DOT as DOT_CURRENCY, KSM as KSM_CURRENCY, KB use crate::mock::*; +// For the time being, do a quick reassignment here to avoid changing all the tests +// TODO: update all tests const DOT: CurrencyId = Token(DOT_CURRENCY); const KSM: CurrencyId = Token(KSM_CURRENCY); const USDT: CurrencyId = Token(KBTC); diff --git a/crates/loans/src/tests/edge_cases.rs b/crates/loans/src/tests/edge_cases.rs index 6d4f915d82..71f3350c29 100644 --- a/crates/loans/src/tests/edge_cases.rs +++ b/crates/loans/src/tests/edge_cases.rs @@ -4,8 +4,8 @@ use crate::{mock::*, Error}; use frame_support::{assert_err, assert_ok}; use primitives::{KSM, IBTC}; use primitives::{ - CurrencyId::{Token, ForeignAsset}, - DOT + CurrencyId::{ForeignAsset, Token}, + DOT, KSM, }; use sp_runtime::FixedPointNumber; diff --git a/crates/loans/src/tests/liquidate_borrow.rs b/crates/loans/src/tests/liquidate_borrow.rs index 84437fafec..be127e2267 100644 --- a/crates/loans/src/tests/liquidate_borrow.rs +++ b/crates/loans/src/tests/liquidate_borrow.rs @@ -6,15 +6,16 @@ use crate::{ Error, MarketState, }; use frame_support::{assert_err, assert_noop, assert_ok, traits::fungibles::Inspect}; -use primitives::{CurrencyId::{Token, self}, Rate, DOT as DOT_CURRENCY, KSM as KSM_CURRENCY, -KBTC as KBTC_CURRENCY, IBTC as IBTC_CURRENCY, KINT as KINT_CURRENCY}; +use primitives::{ + CurrencyId::{self, Token}, + Rate, DOT as DOT_CURRENCY, IBTC as IBTC_CURRENCY, KBTC as KBTC_CURRENCY, KSM as KSM_CURRENCY, +}; use sp_runtime::FixedPointNumber; const DOT: CurrencyId = Token(DOT_CURRENCY); const KSM: CurrencyId = Token(KSM_CURRENCY); const USDT: CurrencyId = Token(KBTC_CURRENCY); const CDOT_6_13: CurrencyId = Token(IBTC_CURRENCY); -const DOT_U: CurrencyId = Token(KINT_CURRENCY); #[test] fn liquidate_borrow_allowed_works() { diff --git a/crates/loans/src/tests/market.rs b/crates/loans/src/tests/market.rs index 2995227307..1dbb2d6f3b 100644 --- a/crates/loans/src/tests/market.rs +++ b/crates/loans/src/tests/market.rs @@ -6,7 +6,10 @@ use crate::{ Error, InterestRateModel, MarketState, }; use frame_support::{assert_noop, assert_ok, error::BadOrigin}; -use primitives::{Rate, Ratio, CDOT, CKBTC, IBTC, CurrencyId::{self, Token, ForeignAsset}, DOT as DOT_CURRENCY, CKSM,}; +use primitives::{ + CurrencyId::{self, ForeignAsset, Token}, + Rate, Ratio, CDOT, CKBTC, DOT as DOT_CURRENCY, +}; use sp_runtime::{traits::Zero, FixedPointNumber}; const DOT: CurrencyId = Token(DOT_CURRENCY); diff --git a/crates/loans/src/weights.rs b/crates/loans/src/weights.rs index c641ce871f..3a79f0a6ff 100644 --- a/crates/loans/src/weights.rs +++ b/crates/loans/src/weights.rs @@ -1,3 +1,6 @@ +// Copyright 2022 Interlay. +// This file is part of Interlay. + // This file is part of Parallel Finance. // Copyright (C) 2022 Parallel Finance Developer. diff --git a/standalone/runtime/tests/test_issue.rs b/standalone/runtime/tests/test_issue.rs index 8d7ea72039..1de6eb3d5d 100644 --- a/standalone/runtime/tests/test_issue.rs +++ b/standalone/runtime/tests/test_issue.rs @@ -1,7 +1,6 @@ mod mock; use currency::Amount; -use frame_support::assert_err; use mock::{assert_eq, issue_testing_utils::*, *}; fn test_with(execute: impl Fn(VaultId) -> R) { diff --git a/standalone/runtime/tests/test_loans.rs b/standalone/runtime/tests/test_loans.rs index a335b7d322..063e706719 100644 --- a/standalone/runtime/tests/test_loans.rs +++ b/standalone/runtime/tests/test_loans.rs @@ -1,9 +1,8 @@ use interbtc_runtime_standalone::{CurrencyId::Token, KINT}; mod mock; use mock::{assert_eq, *}; -use oracle::types::UnsignedFixedPoint; -use pallet_loans::{MarketState, InterestRateModel, JumpModel, Market}; -use primitives::{CKINT, Ratio, Rate, CKSM}; +use pallet_loans::{InterestRateModel, JumpModel, Market, MarketState}; +use primitives::{Rate, Ratio, CKINT, CKSM}; use sp_runtime::traits::CheckedMul; pub const USER: [u8; 32] = ALICE; From a70aa8e019d70d96531284d6d03c5aefad16c601 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Mon, 10 Oct 2022 15:19:06 +0200 Subject: [PATCH 13/58] fix(lend): attempt to fix benchmarks --- crates/loans/src/benchmarking.rs | 218 ++++++++++++++++--------------- crates/loans/src/mock.rs | 6 + 2 files changed, 122 insertions(+), 102 deletions(-) diff --git a/crates/loans/src/benchmarking.rs b/crates/loans/src/benchmarking.rs index 8946066553..663336c8e9 100644 --- a/crates/loans/src/benchmarking.rs +++ b/crates/loans/src/benchmarking.rs @@ -10,8 +10,8 @@ use frame_system::{self, RawOrigin as SystemOrigin}; use primitives::{ Balance, CurrencyId::{self, Token}, - CDOT as SKSM_CURRENCY, CKINT, CKSM as PSKSM_CURRENCY, INTR as PUSDT_CURRENCY, KBTC as USDT_CURRENCY, - KINT as PKSM_CURRENCY, KSM as KSM_CURRENCY, + CDOT as CDOT_CURRENCY, CKBTC as CKBTC_CURRENCY, CKSM as CKSM_CURRENCY, DOT as DOT_CURRENCY, KBTC as KBTC_CURRENCY, + KINT as KINT_CURRENCY, KSM as KSM_CURRENCY, }; use rate_model::{InterestRateModel, JumpModel}; use sp_std::prelude::*; @@ -19,11 +19,12 @@ use sp_std::prelude::*; const SEED: u32 = 0; const KSM: CurrencyId = Token(KSM_CURRENCY); -const USDT: CurrencyId = Token(USDT_CURRENCY); -const PKSM: CurrencyId = Token(PKSM_CURRENCY); -const PUSDT: CurrencyId = Token(PUSDT_CURRENCY); -const SKSM: CurrencyId = Token(SKSM_CURRENCY); -const PSKSM: CurrencyId = Token(PSKSM_CURRENCY); +const KBTC: CurrencyId = Token(KBTC_CURRENCY); +const CKSM: CurrencyId = Token(CKSM_CURRENCY); +const CKBTC: CurrencyId = Token(CKBTC_CURRENCY); +const DOT: CurrencyId = Token(DOT_CURRENCY); +const CDOT: CurrencyId = Token(CDOT_CURRENCY); +const KINT: CurrencyId = Token(KINT_CURRENCY); const RATE_MODEL_MOCK: InterestRateModel = InterestRateModel::Jump(JumpModel { base_rate: Rate::from_inner(Rate::DIV / 100 * 2), @@ -49,7 +50,7 @@ fn market_mock() -> Market> { liquidate_incentive_reserved_factor: Ratio::from_percent(3), supply_cap: 1_000_000_000_000_000_000_000u128, // set to 1B borrow_cap: 1_000_000_000_000_000_000_000u128, // set to 1B - ptoken_id: CurrencyId::Token(CKINT), + ptoken_id: CurrencyId::Token(CKBTC_CURRENCY), } } @@ -64,24 +65,40 @@ fn transfer_initial_balance::set_balance( + SystemOrigin::Root.into(), + account_id.clone(), + CKSM, + 10_000_000_000_000_u128, + 0_u128, + ) + .unwrap(); + orml_tokens::Pallet::::set_balance( + SystemOrigin::Root.into(), + account_id.clone(), + KBTC, + 10_000_000_000_000_u128, + 0_u128, + ) + .unwrap(); + + orml_tokens::Pallet::::set_balance( + SystemOrigin::Root.into(), + account_id.clone(), + KSM, + 10_000_000_000_000_u128, + 0_u128, + ) + .unwrap(); + orml_tokens::Pallet::::set_balance( SystemOrigin::Root.into(), account_id, - USDT, + CDOT, 10_000_000_000_000_u128, 0_u128, ) .unwrap(); - // ::Assets::mint_into(USDT, &caller, INITIAL_AMOUNT.into()).unwrap(); - // ::Assets::mint_into(KSM, &caller, INITIAL_AMOUNT.into()).unwrap(); - // ::Assets::mint_into(SKSM, &caller, INITIAL_AMOUNT.into()).unwrap(); - // ::Assets::mint_into(DOT, &caller, INITIAL_AMOUNT.into()).unwrap(); - // ::Assets::mint_into(CDOT_6_13, &caller, INITIAL_AMOUNT.into()).unwrap(); - // orml_tokens::Pallet::::set_price(SystemOrigin::Root.into(), USDT, 1.into()).unwrap(); - // orml_tokens::Pallet::::set_price(SystemOrigin::Root.into(), KSM, 1.into()).unwrap(); - // orml_tokens::Pallet::::set_price(SystemOrigin::Root.into(), SKSM, 1.into()).unwrap(); - // orml_tokens::Pallet::::set_price(SystemOrigin::Root.into(), DOT, 1.into()).unwrap(); - // orml_tokens::Pallet::::set_price(SystemOrigin::Root.into(), CDOT_6_13, 1.into()).unwrap(); } fn set_account_borrows( @@ -112,29 +129,26 @@ benchmarks! { } add_market { - }: _(SystemOrigin::Root, SKSM, pending_market_mock::(PSKSM)) + }: _(SystemOrigin::Root, DOT, pending_market_mock::(CDOT)) verify { - assert_last_event::(Event::::NewMarket(SKSM, pending_market_mock::(PSKSM)).into()); + assert_last_event::(Event::::NewMarket(DOT, pending_market_mock::(CDOT)).into()); } activate_market { - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), SKSM, pending_market_mock::(PSKSM))); - }: _(SystemOrigin::Root, SKSM) + }: _(SystemOrigin::Root, DOT) verify { - assert_last_event::(Event::::ActivatedMarket(SKSM).into()); + assert_last_event::(Event::::ActivatedMarket(DOT).into()); } update_rate_model { - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(PUSDT))); - }: _(SystemOrigin::Root, USDT, RATE_MODEL_MOCK) + }: _(SystemOrigin::Root, KBTC, RATE_MODEL_MOCK) verify { - let mut market = pending_market_mock::(PUSDT); + let mut market = pending_market_mock::(CKBTC); market.rate_model = RATE_MODEL_MOCK; - assert_last_event::(Event::::UpdatedMarket(USDT, market).into()); + assert_last_event::(Event::::UpdatedMarket(KBTC, market).into()); } update_market { - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KSM, pending_market_mock::(PKSM))); }: _( SystemOrigin::Root, KSM, @@ -148,17 +162,16 @@ benchmarks! { Some(1_000_000_000_000_000_000_000u128) ) verify { - let mut market = pending_market_mock::(PKSM); + let mut market = pending_market_mock::(CKSM); market.reserve_factor = Ratio::from_percent(50); market.close_factor = Ratio::from_percent(15); assert_last_event::(Event::::UpdatedMarket(KSM, market).into()); } force_update_market { - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(PUSDT))); - }: _(SystemOrigin::Root,USDT, pending_market_mock::(PUSDT)) + }: _(SystemOrigin::Root,KBTC, pending_market_mock::(CKBTC)) verify { - assert_last_event::(Event::::UpdatedMarket(USDT, pending_market_mock::(PUSDT)).into()); + assert_last_event::(Event::::UpdatedMarket(KBTC, pending_market_mock::(CKBTC)).into()); } add_reward { @@ -180,21 +193,21 @@ benchmarks! { } update_market_reward_speed { - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(USDT))); - assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); - }: _(SystemOrigin::Root, USDT, Some(1_000_000), Some(1_000_000)) + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); + }: _(SystemOrigin::Root, KBTC, Some(1_000_000), Some(1_000_000)) verify { - assert_last_event::(Event::::MarketRewardSpeedUpdated(USDT, 1_000_000, 1_000_000).into()); + assert_last_event::(Event::::MarketRewardSpeedUpdated(KBTC, 1_000_000, 1_000_000).into()); } claim_reward { let caller: T::AccountId = whitelisted_caller(); transfer_initial_balance::(caller.clone()); - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(USDT))); - assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); - assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), USDT, 100_000_000)); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); + assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, 100_000_000)); assert_ok!(Loans::::add_reward(SystemOrigin::Signed(caller.clone()).into(), 1_000_000_000_000_u128)); - assert_ok!(Loans::::update_market_reward_speed(SystemOrigin::Root.into(), USDT, Some(1_000_000), Some(1_000_000))); + assert_ok!(Loans::::update_market_reward_speed(SystemOrigin::Root.into(), KBTC, Some(1_000_000), Some(1_000_000))); let target_height = frame_system::Pallet::::block_number().saturating_add(One::one()); frame_system::Pallet::::set_block_number(target_height); }: _(SystemOrigin::Signed(caller.clone())) @@ -205,14 +218,14 @@ benchmarks! { claim_reward_for_market { let caller: T::AccountId = whitelisted_caller(); transfer_initial_balance::(caller.clone()); - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(USDT))); - assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); - assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), USDT, 100_000_000)); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); + assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, 100_000_000)); assert_ok!(Loans::::add_reward(SystemOrigin::Signed(caller.clone()).into(), 1_000_000_000_000_u128)); - assert_ok!(Loans::::update_market_reward_speed(SystemOrigin::Root.into(), USDT, Some(1_000_000), Some(1_000_000))); + assert_ok!(Loans::::update_market_reward_speed(SystemOrigin::Root.into(), KBTC, Some(1_000_000), Some(1_000_000))); let target_height = frame_system::Pallet::::block_number().saturating_add(One::one()); frame_system::Pallet::::set_block_number(target_height); - }: _(SystemOrigin::Signed(caller.clone()), USDT) + }: _(SystemOrigin::Signed(caller.clone()), KBTC) verify { assert_last_event::(Event::::RewardPaid(caller, 1_000_000).into()); } @@ -221,12 +234,12 @@ benchmarks! { mint { let caller: T::AccountId = whitelisted_caller(); transfer_initial_balance::(caller.clone()); - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(USDT))); - assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); let amount: u32 = 100_000; - }: _(SystemOrigin::Signed(caller.clone()), USDT, amount.into()) + }: _(SystemOrigin::Signed(caller.clone()), KBTC, amount.into()) verify { - assert_last_event::(Event::::Deposited(caller, USDT, amount.into()).into()); + assert_last_event::(Event::::Deposited(caller, KBTC, amount.into()).into()); } borrow { @@ -234,13 +247,13 @@ benchmarks! { transfer_initial_balance::(caller.clone()); let deposit_amount: u32 = 200_000_000; let borrowed_amount: u32 = 100_000_000; - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(PUSDT))); - assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); - assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), USDT, deposit_amount.into())); - assert_ok!(Loans::::collateral_asset(SystemOrigin::Signed(caller.clone()).into(), USDT, true)); - }: _(SystemOrigin::Signed(caller.clone()), USDT, borrowed_amount.into()) + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); + assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); + assert_ok!(Loans::::collateral_asset(SystemOrigin::Signed(caller.clone()).into(), KBTC, true)); + }: _(SystemOrigin::Signed(caller.clone()), KBTC, borrowed_amount.into()) verify { - assert_last_event::(Event::::Borrowed(caller, USDT, borrowed_amount.into()).into()); + assert_last_event::(Event::::Borrowed(caller, KBTC, borrowed_amount.into()).into()); } redeem { @@ -248,24 +261,24 @@ benchmarks! { transfer_initial_balance::(caller.clone()); let deposit_amount: u32 = 100_000_000; let redeem_amount: u32 = 100_000; - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(PUSDT))); - assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); - assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), USDT, deposit_amount.into())); - }: _(SystemOrigin::Signed(caller.clone()), USDT, redeem_amount.into()) + // assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); + assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); + }: _(SystemOrigin::Signed(caller.clone()), KBTC, redeem_amount.into()) verify { - assert_last_event::(Event::::Redeemed(caller, USDT, redeem_amount.into()).into()); + assert_last_event::(Event::::Redeemed(caller, KBTC, redeem_amount.into()).into()); } redeem_all { let caller: T::AccountId = whitelisted_caller(); transfer_initial_balance::(caller.clone()); let deposit_amount: u32 = 100_000_000; - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(PUSDT))); - assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); - assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), USDT, deposit_amount.into())); - }: _(SystemOrigin::Signed(caller.clone()), USDT) + // assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); + assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); + }: _(SystemOrigin::Signed(caller.clone()), KBTC) verify { - assert_last_event::(Event::::Redeemed(caller, USDT, deposit_amount.into()).into()); + assert_last_event::(Event::::Redeemed(caller, KBTC, deposit_amount.into()).into()); } repay_borrow { @@ -274,14 +287,14 @@ benchmarks! { let deposit_amount: u32 = 200_000_000; let borrowed_amount: u32 = 100_000_000; let repay_amount: u32 = 100; - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(PUSDT))); - assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); - assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), USDT, deposit_amount.into())); - assert_ok!(Loans::::collateral_asset(SystemOrigin::Signed(caller.clone()).into(), USDT, true)); - assert_ok!(Loans::::borrow(SystemOrigin::Signed(caller.clone()).into(), USDT, borrowed_amount.into())); - }: _(SystemOrigin::Signed(caller.clone()), USDT, repay_amount.into()) + // assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); + assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); + assert_ok!(Loans::::collateral_asset(SystemOrigin::Signed(caller.clone()).into(), KBTC, true)); + assert_ok!(Loans::::borrow(SystemOrigin::Signed(caller.clone()).into(), KBTC, borrowed_amount.into())); + }: _(SystemOrigin::Signed(caller.clone()), KBTC, repay_amount.into()) verify { - assert_last_event::(Event::::RepaidBorrow(caller, USDT, repay_amount.into()).into()); + assert_last_event::(Event::::RepaidBorrow(caller, KBTC, repay_amount.into()).into()); } repay_borrow_all { @@ -289,26 +302,27 @@ benchmarks! { transfer_initial_balance::(caller.clone()); let deposit_amount: u32 = 200_000_000; let borrowed_amount: u32 = 100_000_000; - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(PUSDT))); - assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); - assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), USDT, deposit_amount.into())); - assert_ok!(Loans::::collateral_asset(SystemOrigin::Signed(caller.clone()).into(), USDT, true)); - assert_ok!(Loans::::borrow(SystemOrigin::Signed(caller.clone()).into(), USDT, borrowed_amount.into())); - }: _(SystemOrigin::Signed(caller.clone()), USDT) + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); + + assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); + assert_ok!(Loans::::collateral_asset(SystemOrigin::Signed(caller.clone()).into(), KBTC, true)); + assert_ok!(Loans::::borrow(SystemOrigin::Signed(caller.clone()).into(), KBTC, borrowed_amount.into())); + }: _(SystemOrigin::Signed(caller.clone()), KBTC) verify { - assert_last_event::(Event::::RepaidBorrow(caller, USDT, borrowed_amount.into()).into()); + assert_last_event::(Event::::RepaidBorrow(caller, KBTC, borrowed_amount.into()).into()); } collateral_asset { let caller: T::AccountId = whitelisted_caller(); transfer_initial_balance::(caller.clone()); let deposit_amount: u32 = 200_000_000; - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(PUSDT))); - assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); - assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), USDT, deposit_amount.into())); - }: _(SystemOrigin::Signed(caller.clone()), USDT, true) + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); + assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); + }: _(SystemOrigin::Signed(caller.clone()), KBTC, true) verify { - assert_last_event::(Event::::CollateralAssetAdded(caller, USDT).into()); + assert_last_event::(Event::::CollateralAssetAdded(caller, KBTC).into()); } liquidate_borrow { @@ -320,17 +334,17 @@ benchmarks! { let borrowed_amount: u32 = 200_000_000; let liquidate_amount: u32 = 100_000_000; let incentive_amount: u32 = 110_000_000; - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), SKSM, pending_market_mock::(PSKSM))); - assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), SKSM)); - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KSM, pending_market_mock::(PKSM))); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), CDOT, pending_market_mock::(KINT))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), CDOT)); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KSM, pending_market_mock::(CKSM))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KSM)); assert_ok!(Loans::::mint(SystemOrigin::Signed(bob.clone()).into(), KSM, deposit_amount.into())); - assert_ok!(Loans::::mint(SystemOrigin::Signed(alice.clone()).into(), SKSM, deposit_amount.into())); - assert_ok!(Loans::::collateral_asset(SystemOrigin::Signed(alice.clone()).into(), SKSM, true)); + assert_ok!(Loans::::mint(SystemOrigin::Signed(alice.clone()).into(), CDOT, deposit_amount.into())); + assert_ok!(Loans::::collateral_asset(SystemOrigin::Signed(alice.clone()).into(), CDOT, true)); set_account_borrows::(alice.clone(), KSM, borrowed_amount.into()); - }: _(SystemOrigin::Signed(bob.clone()), alice.clone(), KSM, liquidate_amount.into(), SKSM) + }: _(SystemOrigin::Signed(bob.clone()), alice.clone(), KSM, liquidate_amount.into(), CDOT) verify { - assert_last_event::(Event::::LiquidatedBorrow(bob.clone(), alice.clone(), KSM, SKSM, liquidate_amount.into(), incentive_amount.into()).into()); + assert_last_event::(Event::::LiquidatedBorrow(bob.clone(), alice.clone(), KSM, CDOT, liquidate_amount.into(), incentive_amount.into()).into()); } add_reserves { @@ -338,11 +352,11 @@ benchmarks! { let payer = T::Lookup::unlookup(caller.clone()); transfer_initial_balance::(caller.clone()); let amount: u32 = 2000; - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(PUSDT))); - assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); - }: _(SystemOrigin::Root, payer, USDT, amount.into()) + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); + }: _(SystemOrigin::Root, payer, KBTC, amount.into()) verify { - assert_last_event::(Event::::ReservesAdded(caller, USDT, amount.into(), amount.into()).into()); + assert_last_event::(Event::::ReservesAdded(caller, KBTC, amount.into(), amount.into()).into()); } reduce_reserves { @@ -351,13 +365,13 @@ benchmarks! { transfer_initial_balance::(caller.clone()); let add_amount: u32 = 2000; let reduce_amount: u32 = 1000; - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), USDT, pending_market_mock::(PUSDT))); - assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), USDT)); - assert_ok!(Loans::::add_reserves(SystemOrigin::Root.into(), payer.clone(), USDT, add_amount.into())); - }: _(SystemOrigin::Root, payer, USDT, reduce_amount.into()) + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); + assert_ok!(Loans::::add_reserves(SystemOrigin::Root.into(), payer.clone(), KBTC, add_amount.into())); + }: _(SystemOrigin::Root, payer, KBTC, reduce_amount.into()) verify { - assert_last_event::(Event::::ReservesReduced(caller, USDT, reduce_amount.into(), (add_amount-reduce_amount).into()).into()); + assert_last_event::(Event::::ReservesReduced(caller, KBTC, reduce_amount.into(), (add_amount-reduce_amount).into()).into()); } } -impl_benchmark_test_suite!(Loans, crate::mock::new_test_ext(), crate::mock::Test); +// impl_benchmark_test_suite!(Loans, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/crates/loans/src/mock.rs b/crates/loans/src/mock.rs index 96f983ccd3..0ef5a9ccf7 100644 --- a/crates/loans/src/mock.rs +++ b/crates/loans/src/mock.rs @@ -17,6 +17,7 @@ pub use super::*; +use frame_benchmarking::whitelisted_caller; use frame_support::{ construct_runtime, parameter_types, traits::Everything, traits::SortedMembers, PalletId, }; @@ -274,7 +275,12 @@ pub(crate) fn new_test_ext() -> sp_io::TestExternalities { Tokens::set_balance(Origin::root(), DAVE, Token(DOT), 1000_000000000000, 0).unwrap(); Tokens::set_balance(Origin::root(), DAVE, Token(KBTC), 1000_000000000000, 0).unwrap(); Tokens::set_balance(Origin::root(), DAVE, Token(KINT), 1000_000000000000, 0).unwrap(); + Tokens::set_balance(Origin::root(), whitelisted_caller(), Token(KINT), 1000_000000000000, 0).unwrap(); + MockPriceFeeder::set_price(Token(KBTC), 1.into()); + MockPriceFeeder::set_price(Token(DOT), 1.into()); + MockPriceFeeder::set_price(Token(KSM), 1.into()); + MockPriceFeeder::set_price(Token(CDOT), 1.into()); // Init Markets Loans::add_market(Origin::root(), Token(KINT), market_mock(Token(CKINT))).unwrap(); Loans::activate_market(Origin::root(), Token(KINT)).unwrap(); From 81d925a847057a73c70f8c2711b3c6368dacfe67 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Mon, 10 Oct 2022 15:55:06 +0200 Subject: [PATCH 14/58] fix(lend): fmt --- crates/loans/src/benchmarking.rs | 6 +- crates/loans/src/farming.rs | 141 +++----- crates/loans/src/interest.rs | 52 +-- crates/loans/src/lib.rs | 402 ++++++--------------- crates/loans/src/mock.rs | 20 +- crates/loans/src/ptoken.rs | 56 +-- crates/loans/src/rate_model.rs | 31 +- crates/loans/src/tests.rs | 213 +++-------- crates/loans/src/tests/edge_cases.rs | 21 +- crates/loans/src/tests/interest_rate.rs | 117 ++---- crates/loans/src/tests/liquidate_borrow.rs | 61 +--- crates/loans/src/tests/market.rs | 39 +- crates/loans/src/tests/ptokens.rs | 51 +-- crates/traits/src/lib.rs | 65 +--- crates/traits/src/loans.rs | 40 +- primitives/src/lib.rs | 5 +- standalone/runtime/src/lib.rs | 6 +- standalone/runtime/tests/test_loans.rs | 93 ++--- 18 files changed, 393 insertions(+), 1026 deletions(-) diff --git a/crates/loans/src/benchmarking.rs b/crates/loans/src/benchmarking.rs index 663336c8e9..bd040659da 100644 --- a/crates/loans/src/benchmarking.rs +++ b/crates/loans/src/benchmarking.rs @@ -101,11 +101,7 @@ fn transfer_initial_balance( - who: T::AccountId, - asset_id: AssetIdOf, - borrow_balance: BalanceOf, -) { +fn set_account_borrows(who: T::AccountId, asset_id: AssetIdOf, borrow_balance: BalanceOf) { AccountBorrows::::insert( asset_id, &who, diff --git a/crates/loans/src/farming.rs b/crates/loans/src/farming.rs index 2be948c15d..c65af7cfc9 100644 --- a/crates/loans/src/farming.rs +++ b/crates/loans/src/farming.rs @@ -73,8 +73,7 @@ impl Pallet { let supply_speed = RewardSupplySpeed::::get(asset_id); if !supply_speed.is_zero() { let total_supply = TotalSupply::::get(asset_id); - let delta_index = - Self::calculate_reward_delta_index(delta_block, supply_speed, total_supply)?; + let delta_index = Self::calculate_reward_delta_index(delta_block, supply_speed, total_supply)?; supply_state.index = supply_state .index .checked_add(delta_index) @@ -101,11 +100,7 @@ impl Pallet { .reciprocal() .and_then(|r| r.checked_mul_int(current_borrow_amount)) .ok_or(ArithmeticError::Overflow)?; - let delta_index = Self::calculate_reward_delta_index( - delta_block, - borrow_speed, - base_borrow_amount, - )?; + let delta_index = Self::calculate_reward_delta_index(delta_block, borrow_speed, base_borrow_amount)?; borrow_state.index = borrow_state .index .checked_add(delta_index) @@ -117,85 +112,67 @@ impl Pallet { }) } - pub(crate) fn distribute_supplier_reward( - asset_id: AssetIdOf, - supplier: &T::AccountId, - ) -> DispatchResult { - RewardSupplierIndex::::try_mutate( - asset_id, - supplier, - |supplier_index| -> DispatchResult { - let supply_state = RewardSupplyState::::get(asset_id); - let delta_index = supply_state - .index - .checked_sub(*supplier_index) - .ok_or(ArithmeticError::Underflow)?; - *supplier_index = supply_state.index; - - RewardAccrued::::try_mutate(supplier, |total_reward| -> DispatchResult { - let supplier_account = AccountDeposits::::get(asset_id, supplier); - let supplier_amount = supplier_account.voucher_balance; - let reward_delta = Self::calculate_reward_delta(supplier_amount, delta_index)?; - *total_reward = total_reward - .checked_add(reward_delta) - .ok_or(ArithmeticError::Overflow)?; - Self::deposit_event(Event::::DistributedSupplierReward( - asset_id, - supplier.clone(), - reward_delta, - supply_state.index, - )); - - Ok(()) - }) - }, - ) + pub(crate) fn distribute_supplier_reward(asset_id: AssetIdOf, supplier: &T::AccountId) -> DispatchResult { + RewardSupplierIndex::::try_mutate(asset_id, supplier, |supplier_index| -> DispatchResult { + let supply_state = RewardSupplyState::::get(asset_id); + let delta_index = supply_state + .index + .checked_sub(*supplier_index) + .ok_or(ArithmeticError::Underflow)?; + *supplier_index = supply_state.index; + + RewardAccrued::::try_mutate(supplier, |total_reward| -> DispatchResult { + let supplier_account = AccountDeposits::::get(asset_id, supplier); + let supplier_amount = supplier_account.voucher_balance; + let reward_delta = Self::calculate_reward_delta(supplier_amount, delta_index)?; + *total_reward = total_reward + .checked_add(reward_delta) + .ok_or(ArithmeticError::Overflow)?; + Self::deposit_event(Event::::DistributedSupplierReward( + asset_id, + supplier.clone(), + reward_delta, + supply_state.index, + )); + + Ok(()) + }) + }) } - pub(crate) fn distribute_borrower_reward( - asset_id: AssetIdOf, - borrower: &T::AccountId, - ) -> DispatchResult { - RewardBorrowerIndex::::try_mutate( - asset_id, - borrower, - |borrower_index| -> DispatchResult { - let borrow_state = RewardBorrowState::::get(asset_id); - let delta_index = borrow_state - .index - .checked_sub(*borrower_index) - .ok_or(ArithmeticError::Underflow)?; - *borrower_index = borrow_state.index; - - RewardAccrued::::try_mutate(borrower, |total_reward| -> DispatchResult { - let current_borrow_amount = Self::current_borrow_balance(borrower, asset_id)?; - let current_borrow_index = BorrowIndex::::get(asset_id); - let base_borrow_amount = current_borrow_index - .reciprocal() - .and_then(|r| r.checked_mul_int(current_borrow_amount)) - .ok_or(ArithmeticError::Overflow)?; - let reward_delta = - Self::calculate_reward_delta(base_borrow_amount, delta_index)?; - *total_reward = total_reward - .checked_add(reward_delta) - .ok_or(ArithmeticError::Overflow)?; - Self::deposit_event(Event::::DistributedBorrowerReward( - asset_id, - borrower.clone(), - reward_delta, - borrow_state.index, - )); - - Ok(()) - }) - }, - ) + pub(crate) fn distribute_borrower_reward(asset_id: AssetIdOf, borrower: &T::AccountId) -> DispatchResult { + RewardBorrowerIndex::::try_mutate(asset_id, borrower, |borrower_index| -> DispatchResult { + let borrow_state = RewardBorrowState::::get(asset_id); + let delta_index = borrow_state + .index + .checked_sub(*borrower_index) + .ok_or(ArithmeticError::Underflow)?; + *borrower_index = borrow_state.index; + + RewardAccrued::::try_mutate(borrower, |total_reward| -> DispatchResult { + let current_borrow_amount = Self::current_borrow_balance(borrower, asset_id)?; + let current_borrow_index = BorrowIndex::::get(asset_id); + let base_borrow_amount = current_borrow_index + .reciprocal() + .and_then(|r| r.checked_mul_int(current_borrow_amount)) + .ok_or(ArithmeticError::Overflow)?; + let reward_delta = Self::calculate_reward_delta(base_borrow_amount, delta_index)?; + *total_reward = total_reward + .checked_add(reward_delta) + .ok_or(ArithmeticError::Overflow)?; + Self::deposit_event(Event::::DistributedBorrowerReward( + asset_id, + borrower.clone(), + reward_delta, + borrow_state.index, + )); + + Ok(()) + }) + }) } - pub(crate) fn collect_market_reward( - asset_id: AssetIdOf, - user: &T::AccountId, - ) -> DispatchResult { + pub(crate) fn collect_market_reward(asset_id: AssetIdOf, user: &T::AccountId) -> DispatchResult { Self::update_reward_supply_index(asset_id)?; Self::distribute_supplier_reward(asset_id, user)?; diff --git a/crates/loans/src/interest.rs b/crates/loans/src/interest.rs index 65c4362db6..bbd0073352 100644 --- a/crates/loans/src/interest.rs +++ b/crates/loans/src/interest.rs @@ -34,15 +34,8 @@ impl Pallet { return Ok(()); } - let ( - borrow_rate, - supply_rate, - exchange_rate, - util, - total_borrows_new, - total_reserves_new, - borrow_index_new, - ) = Self::get_market_status(asset_id)?; + let (borrow_rate, supply_rate, exchange_rate, util, total_borrows_new, total_reserves_new, borrow_index_new) = + Self::get_market_status(asset_id)?; Self::update_last_accrued_interest_time(asset_id, now)?; TotalBorrows::::insert(asset_id, total_borrows_new); @@ -60,18 +53,7 @@ impl Pallet { pub fn get_market_status( asset_id: AssetIdOf, - ) -> Result< - ( - Rate, - Rate, - Rate, - Ratio, - BalanceOf, - BalanceOf, - FixedU128, - ), - DispatchError, - > { + ) -> Result<(Rate, Rate, Rate, Ratio, BalanceOf, BalanceOf, FixedU128), DispatchError> { let market = Self::market(asset_id)?; let total_supply = Self::total_supply(asset_id); let total_cash = Self::get_total_cash(asset_id); @@ -84,16 +66,14 @@ impl Pallet { .rate_model .get_borrow_rate(util) .ok_or(ArithmeticError::Overflow)?; - let supply_rate = - InterestRateModel::get_supply_rate(borrow_rate, util, market.reserve_factor); + let supply_rate = InterestRateModel::get_supply_rate(borrow_rate, util, market.reserve_factor); let now = T::UnixTime::now().as_secs(); let last_accrued_interest_time = Self::last_accrued_interest_time(asset_id); if now > last_accrued_interest_time { let delta_time = now - last_accrued_interest_time; let interest_accumulated = - Self::accrued_interest(borrow_rate, total_borrows, delta_time) - .ok_or(ArithmeticError::Overflow)?; + Self::accrued_interest(borrow_rate, total_borrows, delta_time).ok_or(ArithmeticError::Overflow)?; total_borrows = interest_accumulated .checked_add(total_borrows) .ok_or(ArithmeticError::Overflow)?; @@ -108,8 +88,7 @@ impl Pallet { .ok_or(ArithmeticError::Overflow)?; } - let exchange_rate = - Self::calculate_exchange_rate(total_supply, total_cash, total_borrows, total_reserves)?; + let exchange_rate = Self::calculate_exchange_rate(total_supply, total_cash, total_borrows, total_reserves)?; Ok(( borrow_rate, @@ -157,29 +136,21 @@ impl Pallet { /// The exchange rate should be greater than 0.02 and less than 1 pub(crate) fn ensure_valid_exchange_rate(exchange_rate: Rate) -> DispatchResult { ensure!( - exchange_rate >= Rate::from_inner(MIN_EXCHANGE_RATE) - && exchange_rate < Rate::from_inner(MAX_EXCHANGE_RATE), + exchange_rate >= Rate::from_inner(MIN_EXCHANGE_RATE) && exchange_rate < Rate::from_inner(MAX_EXCHANGE_RATE), Error::::InvalidExchangeRate ); Ok(()) } - pub(crate) fn update_last_accrued_interest_time( - asset_id: AssetIdOf, - time: Timestamp, - ) -> DispatchResult { + pub(crate) fn update_last_accrued_interest_time(asset_id: AssetIdOf, time: Timestamp) -> DispatchResult { LastAccruedInterestTime::::try_mutate(asset_id, |last_time| -> DispatchResult { *last_time = time; Ok(()) }) } - fn accrued_interest( - borrow_rate: Rate, - amount: BalanceOf, - delta_time: Timestamp, - ) -> Option> { + fn accrued_interest(borrow_rate: Rate, amount: BalanceOf, delta_time: Timestamp) -> Option> { borrow_rate .checked_mul_int(amount)? .checked_mul(delta_time.into())? @@ -207,9 +178,8 @@ impl Pallet { .checked_add(total_borrows) .and_then(|r| r.checked_sub(total_reserves)) .ok_or(ArithmeticError::Overflow)?; - let exchange_rate = - Rate::checked_from_rational(cash_plus_borrows_minus_reserves, total_supply) - .ok_or(ArithmeticError::Underflow)?; + let exchange_rate = Rate::checked_from_rational(cash_plus_borrows_minus_reserves, total_supply) + .ok_or(ArithmeticError::Underflow)?; Self::ensure_valid_exchange_rate(exchange_rate)?; Ok(exchange_rate) diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index b75926e38b..5d961e1011 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -41,16 +41,14 @@ use frame_system::pallet_prelude::*; use num_traits::cast::ToPrimitive; pub use pallet::*; use pallet_traits::{ - ConvertToBigUint, Loans as LoansTrait, LoansMarketDataProvider, LoansPositionDataProvider, - MarketInfo, MarketStatus, PriceFeeder, -}; -use primitives::{ - Balance, CurrencyId, Liquidity, Price, Rate, Ratio, Shortfall, Timestamp, + ConvertToBigUint, Loans as LoansTrait, LoansMarketDataProvider, LoansPositionDataProvider, MarketInfo, + MarketStatus, PriceFeeder, }; +use primitives::{Balance, CurrencyId, Liquidity, Price, Rate, Ratio, Shortfall, Timestamp}; use sp_runtime::{ traits::{ - AccountIdConversion, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, One, - SaturatedConversion, Saturating, StaticLookup, Zero, + AccountIdConversion, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, One, SaturatedConversion, Saturating, + StaticLookup, Zero, }, ArithmeticError, FixedPointNumber, FixedU128, }; @@ -82,10 +80,8 @@ pub const MAX_EXCHANGE_RATE: u128 = 1_000_000_000_000_000_000; // 1 pub const MIN_EXCHANGE_RATE: u128 = 20_000_000_000_000_000; // 0.02 type AccountIdOf = ::AccountId; -type AssetIdOf = - <::Assets as Inspect<::AccountId>>::AssetId; -type BalanceOf = - <::Assets as Inspect<::AccountId>>::Balance; +type AssetIdOf = <::Assets as Inspect<::AccountId>>::AssetId; +type BalanceOf = <::Assets as Inspect<::AccountId>>::Balance; /// Utility type for managing upgrades/migrations. #[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)] @@ -265,29 +261,25 @@ pub mod pallet { /// The timestamp of the last calculation of accrued interest #[pallet::storage] #[pallet::getter(fn last_accrued_interest_time)] - pub type LastAccruedInterestTime = - StorageMap<_, Blake2_128Concat, AssetIdOf, Timestamp, ValueQuery>; + pub type LastAccruedInterestTime = StorageMap<_, Blake2_128Concat, AssetIdOf, Timestamp, ValueQuery>; /// Total number of collateral tokens in circulation /// CollateralType -> Balance #[pallet::storage] #[pallet::getter(fn total_supply)] - pub type TotalSupply = - StorageMap<_, Blake2_128Concat, AssetIdOf, BalanceOf, ValueQuery>; + pub type TotalSupply = StorageMap<_, Blake2_128Concat, AssetIdOf, BalanceOf, ValueQuery>; /// Total amount of outstanding borrows of the underlying in this market /// CurrencyId -> Balance #[pallet::storage] #[pallet::getter(fn total_borrows)] - pub type TotalBorrows = - StorageMap<_, Blake2_128Concat, AssetIdOf, BalanceOf, ValueQuery>; + pub type TotalBorrows = StorageMap<_, Blake2_128Concat, AssetIdOf, BalanceOf, ValueQuery>; /// Total amount of reserves of the underlying held in this market /// CurrencyId -> Balance #[pallet::storage] #[pallet::getter(fn total_reserves)] - pub type TotalReserves = - StorageMap<_, Blake2_128Concat, AssetIdOf, BalanceOf, ValueQuery>; + pub type TotalReserves = StorageMap<_, Blake2_128Concat, AssetIdOf, BalanceOf, ValueQuery>; /// Mapping of account addresses to outstanding borrow balances /// CurrencyId -> Owner -> BorrowSnapshot @@ -335,111 +327,77 @@ pub mod pallet { /// CurrencyId -> u128 #[pallet::storage] #[pallet::getter(fn borrow_index)] - pub type BorrowIndex = - StorageMap<_, Blake2_128Concat, AssetIdOf, Rate, ValueQuery>; + pub type BorrowIndex = StorageMap<_, Blake2_128Concat, AssetIdOf, Rate, ValueQuery>; /// The exchange rate from the underlying to the internal collateral #[pallet::storage] #[pallet::getter(fn exchange_rate)] - pub type ExchangeRate = - StorageMap<_, Blake2_128Concat, AssetIdOf, Rate, ValueQuery>; + pub type ExchangeRate = StorageMap<_, Blake2_128Concat, AssetIdOf, Rate, ValueQuery>; /// Mapping of borrow rate to currency type #[pallet::storage] #[pallet::getter(fn borrow_rate)] - pub type BorrowRate = - StorageMap<_, Blake2_128Concat, AssetIdOf, Rate, ValueQuery>; + pub type BorrowRate = StorageMap<_, Blake2_128Concat, AssetIdOf, Rate, ValueQuery>; /// Mapping of supply rate to currency type #[pallet::storage] #[pallet::getter(fn supply_rate)] - pub type SupplyRate = - StorageMap<_, Blake2_128Concat, AssetIdOf, Rate, ValueQuery>; + pub type SupplyRate = StorageMap<_, Blake2_128Concat, AssetIdOf, Rate, ValueQuery>; /// Borrow utilization ratio #[pallet::storage] #[pallet::getter(fn utilization_ratio)] - pub type UtilizationRatio = - StorageMap<_, Blake2_128Concat, AssetIdOf, Ratio, ValueQuery>; + pub type UtilizationRatio = StorageMap<_, Blake2_128Concat, AssetIdOf, Ratio, ValueQuery>; /// Mapping of asset id to its market #[pallet::storage] - pub type Markets = - StorageMap<_, Blake2_128Concat, AssetIdOf, Market>>; + pub type Markets = StorageMap<_, Blake2_128Concat, AssetIdOf, Market>>; /// Mapping of ptoken id to asset id /// `ptoken id`: voucher token id /// `asset id`: underlying token id #[pallet::storage] - pub type UnderlyingAssetId = - StorageMap<_, Blake2_128Concat, AssetIdOf, AssetIdOf>; + pub type UnderlyingAssetId = StorageMap<_, Blake2_128Concat, AssetIdOf, AssetIdOf>; /// Mapping of token id to supply reward speed #[pallet::storage] #[pallet::getter(fn reward_supply_speed)] - pub type RewardSupplySpeed = - StorageMap<_, Blake2_128Concat, AssetIdOf, BalanceOf, ValueQuery>; + pub type RewardSupplySpeed = StorageMap<_, Blake2_128Concat, AssetIdOf, BalanceOf, ValueQuery>; /// Mapping of token id to borrow reward speed #[pallet::storage] #[pallet::getter(fn reward_borrow_speed)] - pub type RewardBorrowSpeed = - StorageMap<_, Blake2_128Concat, AssetIdOf, BalanceOf, ValueQuery>; + pub type RewardBorrowSpeed = StorageMap<_, Blake2_128Concat, AssetIdOf, BalanceOf, ValueQuery>; /// The Reward market supply state for each market #[pallet::storage] #[pallet::getter(fn reward_supply_state)] - pub type RewardSupplyState = StorageMap< - _, - Blake2_128Concat, - AssetIdOf, - RewardMarketState>, - ValueQuery, - >; + pub type RewardSupplyState = + StorageMap<_, Blake2_128Concat, AssetIdOf, RewardMarketState>, ValueQuery>; /// The Reward market borrow state for each market #[pallet::storage] #[pallet::getter(fn reward_borrow_state)] - pub type RewardBorrowState = StorageMap< - _, - Blake2_128Concat, - AssetIdOf, - RewardMarketState>, - ValueQuery, - >; + pub type RewardBorrowState = + StorageMap<_, Blake2_128Concat, AssetIdOf, RewardMarketState>, ValueQuery>; /// The Reward index for each market for each supplier as of the last time they accrued Reward #[pallet::storage] #[pallet::getter(fn reward_supplier_index)] - pub type RewardSupplierIndex = StorageDoubleMap< - _, - Blake2_128Concat, - AssetIdOf, - Blake2_128Concat, - T::AccountId, - BalanceOf, - ValueQuery, - >; + pub type RewardSupplierIndex = + StorageDoubleMap<_, Blake2_128Concat, AssetIdOf, Blake2_128Concat, T::AccountId, BalanceOf, ValueQuery>; /// The Reward index for each market for each borrower as of the last time they accrued Reward #[pallet::storage] #[pallet::getter(fn reward_borrower_index)] - pub type RewardBorrowerIndex = StorageDoubleMap< - _, - Blake2_128Concat, - AssetIdOf, - Blake2_128Concat, - T::AccountId, - BalanceOf, - ValueQuery, - >; + pub type RewardBorrowerIndex = + StorageDoubleMap<_, Blake2_128Concat, AssetIdOf, Blake2_128Concat, T::AccountId, BalanceOf, ValueQuery>; /// The reward accrued but not yet transferred to each user. #[pallet::storage] #[pallet::storage_prefix = "RewardAccured"] #[pallet::getter(fn reward_accrued)] - pub type RewardAccrued = - StorageMap<_, Blake2_128Concat, T::AccountId, BalanceOf, ValueQuery>; + pub type RewardAccrued = StorageMap<_, Blake2_128Concat, T::AccountId, BalanceOf, ValueQuery>; /// DefaultVersion is using for initialize the StorageVersion #[pallet::type_value] @@ -449,8 +407,7 @@ pub mod pallet { /// Storage version of the pallet. #[pallet::storage] - pub(crate) type StorageVersion = - StorageValue<_, Versions, ValueQuery, DefaultVersion>; + pub(crate) type StorageVersion = StorageValue<_, Versions, ValueQuery, DefaultVersion>; #[pallet::pallet] #[pallet::without_storage_info] @@ -479,26 +436,18 @@ pub mod pallet { market: Market>, ) -> DispatchResultWithPostInfo { T::UpdateOrigin::ensure_origin(origin)?; - ensure!( - !Markets::::contains_key(asset_id), - Error::::MarketAlreadyExists - ); + ensure!(!Markets::::contains_key(asset_id), Error::::MarketAlreadyExists); ensure!( market.state == MarketState::Pending, Error::::NewMarketMustHavePendingState ); + ensure!(market.rate_model.check_model(), Error::::InvalidRateModelParam); ensure!( - market.rate_model.check_model(), - Error::::InvalidRateModelParam - ); - ensure!( - market.collateral_factor >= Ratio::zero() - && market.collateral_factor < Ratio::one(), + market.collateral_factor >= Ratio::zero() && market.collateral_factor < Ratio::one(), Error::::InvalidFactor, ); ensure!( - market.liquidation_threshold < Ratio::one() - && market.liquidation_threshold >= market.collateral_factor, + market.liquidation_threshold < Ratio::one() && market.liquidation_threshold >= market.collateral_factor, Error::::InvalidFactor ); ensure!( @@ -510,10 +459,7 @@ pub mod pallet { && market.liquidate_incentive_reserved_factor < Ratio::one(), Error::::InvalidFactor, ); - ensure!( - market.supply_cap > Zero::zero(), - Error::::InvalidSupplyCap, - ); + ensure!(market.supply_cap > Zero::zero(), Error::::InvalidSupplyCap,); // Ensures a given `ptoken_id` not exists on the `Market` and `UnderlyingAssetId`. Self::ensure_ptoken(market.ptoken_id)?; @@ -536,10 +482,7 @@ pub mod pallet { /// - `asset_id`: Market related currency #[pallet::weight(T::WeightInfo::activate_market())] #[transactional] - pub fn activate_market( - origin: OriginFor, - asset_id: AssetIdOf, - ) -> DispatchResultWithPostInfo { + pub fn activate_market(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResultWithPostInfo { T::UpdateOrigin::ensure_origin(origin)?; Self::mutate_market(asset_id, |stored_market| { if let MarketState::Active = stored_market.state { @@ -602,12 +545,11 @@ pub mod pallet { let market = Self::market(asset_id)?; let collateral_factor = collateral_factor.unwrap_or(market.collateral_factor); - let liquidation_threshold = - liquidation_threshold.unwrap_or(market.liquidation_threshold); + let liquidation_threshold = liquidation_threshold.unwrap_or(market.liquidation_threshold); let reserve_factor = reserve_factor.unwrap_or(market.reserve_factor); let close_factor = close_factor.unwrap_or(market.close_factor); - let liquidate_incentive_reserved_factor = liquidate_incentive_reserved_factor - .unwrap_or(market.liquidate_incentive_reserved_factor); + let liquidate_incentive_reserved_factor = + liquidate_incentive_reserved_factor.unwrap_or(market.liquidate_incentive_reserved_factor); let liquidate_incentive = liquidate_incentive.unwrap_or(market.liquidate_incentive); let supply_cap = supply_cap.unwrap_or(market.supply_cap); let borrow_cap = borrow_cap.unwrap_or(market.borrow_cap); @@ -660,10 +602,7 @@ pub mod pallet { market: Market>, ) -> DispatchResultWithPostInfo { T::UpdateOrigin::ensure_origin(origin)?; - ensure!( - market.rate_model.check_model(), - Error::::InvalidRateModelParam - ); + ensure!(market.rate_model.check_model(), Error::::InvalidRateModelParam); if UnderlyingAssetId::::contains_key(market.ptoken_id) { ensure!( Self::underlying_id(market.ptoken_id)? == asset_id, @@ -685,10 +624,7 @@ pub mod pallet { /// - `amount`: Reward amount added #[pallet::weight(T::WeightInfo::add_reward())] #[transactional] - pub fn add_reward( - origin: OriginFor, - amount: BalanceOf, - ) -> DispatchResultWithPostInfo { + pub fn add_reward(origin: OriginFor, amount: BalanceOf) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; ensure!(!amount.is_zero(), Error::::InvalidAmount); @@ -795,10 +731,7 @@ pub mod pallet { /// - `asset_id`: Market related currency #[pallet::weight(T::WeightInfo::claim_reward_for_market())] #[transactional] - pub fn claim_reward_for_market( - origin: OriginFor, - asset_id: AssetIdOf, - ) -> DispatchResultWithPostInfo { + pub fn claim_reward_for_market(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; Self::collect_market_reward(asset_id, &who)?; @@ -848,10 +781,7 @@ pub mod pallet { /// - `asset_id`: the asset to be redeemed. #[pallet::weight(T::WeightInfo::redeem_all())] #[transactional] - pub fn redeem_all( - origin: OriginFor, - asset_id: AssetIdOf, - ) -> DispatchResultWithPostInfo { + pub fn redeem_all(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; Self::ensure_active_market(asset_id)?; Self::accrue_interest(asset_id)?; @@ -905,10 +835,7 @@ pub mod pallet { /// - `asset_id`: the asset to be repaid. #[pallet::weight(T::WeightInfo::repay_borrow_all())] #[transactional] - pub fn repay_borrow_all( - origin: OriginFor, - asset_id: AssetIdOf, - ) -> DispatchResultWithPostInfo { + pub fn repay_borrow_all(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; Self::ensure_active_market(asset_id)?; Self::accrue_interest(asset_id)?; @@ -963,13 +890,7 @@ pub mod pallet { let who = ensure_signed(origin)?; Self::accrue_interest(liquidation_asset_id)?; Self::accrue_interest(collateral_asset_id)?; - Self::do_liquidate_borrow( - who, - borrower, - liquidation_asset_id, - repay_amount, - collateral_asset_id, - )?; + Self::do_liquidate_borrow(who, borrower, liquidation_asset_id, repay_amount, collateral_asset_id)?; Ok(().into()) } @@ -1036,13 +957,7 @@ pub mod pallet { .checked_sub(reduce_amount) .ok_or(ArithmeticError::Underflow)?; TotalReserves::::insert(asset_id, total_reserves_new); - T::Assets::transfer( - asset_id, - &Self::account_id(), - &receiver, - reduce_amount, - false, - )?; + T::Assets::transfer(asset_id, &Self::account_id(), &receiver, reduce_amount, false)?; Self::deposit_event(Event::::ReservesReduced( receiver, @@ -1075,14 +990,9 @@ pub mod pallet { let voucher_amount = Self::calc_collateral_amount(redeem_amount, exchange_rate)?; let redeem_amount = Self::do_redeem_voucher(&from, asset_id, voucher_amount)?; T::Assets::transfer(asset_id, &from, &receiver, redeem_amount, false)?; - Self::deposit_event(Event::::IncentiveReservesReduced( - receiver, - asset_id, - redeem_amount, - )); + Self::deposit_event(Event::::IncentiveReservesReduced(receiver, asset_id, redeem_amount)); Ok(().into()) } - } } @@ -1099,9 +1009,7 @@ impl Pallet { Ok(FixedU128::zero()) } - fn get_lf_liquidation_base_position( - _account: &T::AccountId, - ) -> Result { + fn get_lf_liquidation_base_position(_account: &T::AccountId) -> Result { Ok(FixedU128::zero()) } @@ -1234,18 +1142,14 @@ impl Pallet { return Ok(BalanceOf::::zero()); } let exchange_rate = Self::exchange_rate_stored(asset_id)?; - let underlying_amount = - Self::calc_underlying_amount(deposits.voucher_balance, exchange_rate)?; + let underlying_amount = Self::calc_underlying_amount(deposits.voucher_balance, exchange_rate)?; let market = Self::market(asset_id)?; let effects_amount = market.collateral_factor.mul_ceil(underlying_amount); Ok(BalanceOf::::saturated_from(effects_amount)) } - fn collateral_asset_value( - supplier: &T::AccountId, - asset_id: AssetIdOf, - ) -> Result { + fn collateral_asset_value(supplier: &T::AccountId, asset_id: AssetIdOf) -> Result { let effects_amount = Self::current_collateral_balance(supplier, asset_id)?; Self::get_asset_value(asset_id, effects_amount) @@ -1266,8 +1170,7 @@ impl Pallet { return Ok(FixedU128::zero()); } let exchange_rate = Self::exchange_rate_stored(asset_id)?; - let underlying_amount = - Self::calc_underlying_amount(deposits.voucher_balance, exchange_rate)?; + let underlying_amount = Self::calc_underlying_amount(deposits.voucher_balance, exchange_rate)?; let market = Self::market(asset_id)?; let effects_amount = market.liquidation_threshold.mul_ceil(underlying_amount); @@ -1285,15 +1188,11 @@ impl Pallet { Ok(total_asset_value) } - fn total_liquidation_threshold_value( - borrower: &T::AccountId, - ) -> Result { + fn total_liquidation_threshold_value(borrower: &T::AccountId) -> Result { let mut total_asset_value: FixedU128 = FixedU128::zero(); for (asset_id, _market) in Self::active_markets() { total_asset_value = total_asset_value - .checked_add(&Self::liquidation_threshold_asset_value( - borrower, asset_id, - )?) + .checked_add(&Self::liquidation_threshold_asset_value(borrower, asset_id)?) .ok_or(ArithmeticError::Overflow)?; } @@ -1301,11 +1200,7 @@ impl Pallet { } /// Checks if the redeemer should be allowed to redeem tokens in given market - fn redeem_allowed( - asset_id: AssetIdOf, - redeemer: &T::AccountId, - voucher_amount: BalanceOf, - ) -> DispatchResult { + fn redeem_allowed(asset_id: AssetIdOf, redeemer: &T::AccountId, voucher_amount: BalanceOf) -> DispatchResult { log::trace!( target: "loans::redeem_allowed", "asset_id: {:?}, redeemer: {:?}, voucher_amount: {:?}", @@ -1336,10 +1231,7 @@ impl Pallet { redeem_effects_value.into_inner(), ); - Self::ensure_liquidity( - redeemer, - redeem_effects_value, - )?; + Self::ensure_liquidity(redeemer, redeem_effects_value)?; Ok(()) } @@ -1386,18 +1278,11 @@ impl Pallet { } /// Borrower shouldn't borrow more than his total collateral value - fn borrow_allowed( - asset_id: AssetIdOf, - borrower: &T::AccountId, - borrow_amount: BalanceOf, - ) -> DispatchResult { + fn borrow_allowed(asset_id: AssetIdOf, borrower: &T::AccountId, borrow_amount: BalanceOf) -> DispatchResult { Self::ensure_under_borrow_cap(asset_id, borrow_amount)?; Self::ensure_enough_cash(asset_id, borrow_amount)?; let borrow_value = Self::get_asset_value(asset_id, borrow_amount)?; - Self::ensure_liquidity( - borrower, - borrow_value, - )?; + Self::ensure_liquidity(borrower, borrow_value)?; Ok(()) } @@ -1441,10 +1326,7 @@ impl Pallet { // Calculates and returns the most recent amount of borrowed balance of `currency_id` // for `who`. - pub fn current_borrow_balance( - who: &T::AccountId, - asset_id: AssetIdOf, - ) -> Result, DispatchError> { + pub fn current_borrow_balance(who: &T::AccountId, asset_id: AssetIdOf) -> Result, DispatchError> { let snapshot: BorrowSnapshot> = Self::account_borrows(asset_id, who); if snapshot.principal.is_zero() || snapshot.borrow_index.is_zero() { return Ok(Zero::zero()); @@ -1460,11 +1342,7 @@ impl Pallet { } #[require_transactional] - fn update_earned_stored( - who: &T::AccountId, - asset_id: AssetIdOf, - exchange_rate: Rate, - ) -> DispatchResult { + fn update_earned_stored(who: &T::AccountId, asset_id: AssetIdOf, exchange_rate: Rate) -> DispatchResult { let deposits = AccountDeposits::::get(asset_id, who); let account_earned = AccountEarned::::get(asset_id, who); let total_earned_prior_new = exchange_rate @@ -1500,8 +1378,7 @@ impl Pallet { repay_amount, market ); - let (liquidity, shortfall, lf_liquidity, _) = - Self::get_account_liquidation_threshold_liquidity(borrower)?; + let (liquidity, shortfall, lf_liquidity, _) = Self::get_account_liquidation_threshold_liquidity(borrower)?; // C_other >= B_other + B_dot_over // C_other >= B_other + max(B_dot - C_lf, 0) @@ -1519,11 +1396,7 @@ impl Pallet { let repay_value = Self::get_asset_value(liquidation_asset_id, repay_amount)?; let effects_borrows_value = account_borrows_value; - if market - .close_factor - .mul_ceil(effects_borrows_value.into_inner()) - < repay_value.into_inner() - { + if market.close_factor.mul_ceil(effects_borrows_value.into_inner()) < repay_value.into_inner() { return Err(Error::::TooMuchRepay.into()); } @@ -1664,26 +1537,18 @@ impl Pallet { Self::update_reward_supply_index(collateral_asset_id)?; Self::distribute_supplier_reward(collateral_asset_id, liquidator)?; Self::distribute_supplier_reward(collateral_asset_id, borrower)?; - Self::distribute_supplier_reward( - collateral_asset_id, - &Self::incentive_reward_account_id()?, - )?; + Self::distribute_supplier_reward(collateral_asset_id, &Self::incentive_reward_account_id()?)?; // 3.the liquidator will receive voucher token from borrower let exchange_rate = Self::exchange_rate_stored(collateral_asset_id)?; - let collateral_amount = - Self::calc_collateral_amount(collateral_underlying_amount, exchange_rate)?; - AccountDeposits::::try_mutate( - collateral_asset_id, - borrower, - |deposits| -> DispatchResult { - deposits.voucher_balance = deposits - .voucher_balance - .checked_sub(collateral_amount) - .ok_or(ArithmeticError::Underflow)?; - Ok(()) - }, - )?; + let collateral_amount = Self::calc_collateral_amount(collateral_underlying_amount, exchange_rate)?; + AccountDeposits::::try_mutate(collateral_asset_id, borrower, |deposits| -> DispatchResult { + deposits.voucher_balance = deposits + .voucher_balance + .checked_sub(collateral_amount) + .ok_or(ArithmeticError::Underflow)?; + Ok(()) + })?; let incentive_reserved_amount = market.liquidate_incentive_reserved_factor.mul_floor( FixedU128::from_inner(collateral_amount) .checked_div(&market.liquidate_incentive) @@ -1691,17 +1556,13 @@ impl Pallet { .ok_or(ArithmeticError::Underflow)?, ); // increase liquidator's voucher_balance - AccountDeposits::::try_mutate( - collateral_asset_id, - liquidator, - |deposits| -> DispatchResult { - deposits.voucher_balance = deposits - .voucher_balance - .checked_add(collateral_amount - incentive_reserved_amount) - .ok_or(ArithmeticError::Overflow)?; - Ok(()) - }, - )?; + AccountDeposits::::try_mutate(collateral_asset_id, liquidator, |deposits| -> DispatchResult { + deposits.voucher_balance = deposits + .voucher_balance + .checked_add(collateral_amount - incentive_reserved_amount) + .ok_or(ArithmeticError::Overflow)?; + Ok(()) + })?; // increase reserve's voucher_balance AccountDeposits::::try_mutate( collateral_asset_id, @@ -1740,13 +1601,8 @@ impl Pallet { let market = Self::market(asset_id)?; // Assets holded by market currently. let current_cash = T::Assets::balance(asset_id, &Self::account_id()); - let total_cash = current_cash - .checked_add(amount) - .ok_or(ArithmeticError::Overflow)?; - ensure!( - total_cash <= market.supply_cap, - Error::::SupplyCapacityExceeded - ); + let total_cash = current_cash.checked_add(amount).ok_or(ArithmeticError::Overflow)?; + ensure!(total_cash <= market.supply_cap, Error::::SupplyCapacityExceeded); Ok(()) } @@ -1755,9 +1611,7 @@ impl Pallet { fn ensure_under_borrow_cap(asset_id: AssetIdOf, amount: BalanceOf) -> DispatchResult { let market = Self::market(asset_id)?; let total_borrows = Self::total_borrows(asset_id); - let new_total_borrows = total_borrows - .checked_add(amount) - .ok_or(ArithmeticError::Overflow)?; + let new_total_borrows = total_borrows.checked_add(amount).ok_or(ArithmeticError::Overflow)?; ensure!( new_total_borrows <= market.borrow_cap, Error::::BorrowCapacityExceeded @@ -1787,10 +1641,7 @@ impl Pallet { ); // The ptoken id should not be the same as the id of any asset in markets - ensure!( - !Markets::::contains_key(ptoken_id), - Error::::InvalidPtokenId - ); + ensure!(!Markets::::contains_key(ptoken_id), Error::::InvalidPtokenId); Ok(()) } @@ -1799,10 +1650,7 @@ impl Pallet { // Returns `Err` If InsufficientLiquidity // `account`: account that need a liquidity check // `reduce_amount`: values that will have an impact on liquidity - fn ensure_liquidity( - account: &T::AccountId, - reduce_amount: FixedU128, - ) -> DispatchResult { + fn ensure_liquidity(account: &T::AccountId, reduce_amount: FixedU128) -> DispatchResult { let (total_liquidity, _, lf_liquidity, _) = Self::get_account_liquidity(account)?; if total_liquidity >= lf_liquidity + reduce_amount { return Ok(()); @@ -1840,8 +1688,7 @@ impl Pallet { // // Returns `Err` if the oracle price not ready pub fn get_price(asset_id: AssetIdOf) -> Result { - let (price, _) = - T::PriceFeeder::get_price(&asset_id).ok_or(Error::::PriceOracleNotReady)?; + let (price, _) = T::PriceFeeder::get_price(&asset_id).ok_or(Error::::PriceOracleNotReady)?; if price.is_zero() { return Err(Error::::PriceIsZero.into()); } @@ -1859,10 +1706,7 @@ impl Pallet { // We use FixedU128::from_inner(balance) instead of `balance / 1e18`. // // Returns `Err` if oracle price not ready or arithmetic error. - pub fn get_asset_value( - asset_id: AssetIdOf, - amount: BalanceOf, - ) -> Result { + pub fn get_asset_value(asset_id: AssetIdOf, amount: BalanceOf) -> Result { let value = Self::get_price(asset_id)? .checked_mul(&FixedU128::from_inner(amount)) .ok_or(ArithmeticError::Overflow)?; @@ -1880,22 +1724,16 @@ impl Pallet { // Mutates a stored Market. // // Returns `Err` if market does not exist. - pub(crate) fn mutate_market( - asset_id: AssetIdOf, - cb: F, - ) -> Result>, DispatchError> + pub(crate) fn mutate_market(asset_id: AssetIdOf, cb: F) -> Result>, DispatchError> where F: FnOnce(&mut Market>) -> Market>, { - Markets::::try_mutate( - asset_id, - |opt| -> Result>, DispatchError> { - if let Some(market) = opt { - return Ok(cb(market)); - } - Err(Error::::MarketDoesNotExist.into()) - }, - ) + Markets::::try_mutate(asset_id, |opt| -> Result>, DispatchError> { + if let Some(market) = opt { + return Ok(cb(market)); + } + Err(Error::::MarketDoesNotExist.into()) + }) } // All markets that are `MarketStatus::Active`. @@ -1907,8 +1745,7 @@ impl Pallet { // // Returns `Err` if asset_id does not exist, it also means that ptoken_id is invalid. pub fn underlying_id(ptoken_id: AssetIdOf) -> Result, DispatchError> { - UnderlyingAssetId::::try_get(ptoken_id) - .map_err(|_err| Error::::InvalidPtokenId.into()) + UnderlyingAssetId::::try_get(ptoken_id).map_err(|_err| Error::::InvalidPtokenId.into()) } // Returns the ptoken_id of the related asset @@ -1931,11 +1768,7 @@ impl Pallet { } impl LoansTrait, AccountIdOf, BalanceOf> for Pallet { - fn do_mint( - supplier: &AccountIdOf, - asset_id: AssetIdOf, - amount: BalanceOf, - ) -> Result<(), DispatchError> { + fn do_mint(supplier: &AccountIdOf, asset_id: AssetIdOf, amount: BalanceOf) -> Result<(), DispatchError> { ensure!(!amount.is_zero(), Error::::InvalidAmount); Self::ensure_active_market(asset_id)?; Self::ensure_under_supply_cap(asset_id, amount)?; @@ -1972,11 +1805,7 @@ impl LoansTrait, AccountIdOf, BalanceOf> for Palle Ok(()) } - fn do_borrow( - borrower: &AccountIdOf, - asset_id: AssetIdOf, - amount: BalanceOf, - ) -> Result<(), DispatchError> { + fn do_borrow(borrower: &AccountIdOf, asset_id: AssetIdOf, amount: BalanceOf) -> Result<(), DispatchError> { Self::ensure_active_market(asset_id)?; Self::accrue_interest(asset_id)?; @@ -1987,13 +1816,9 @@ impl LoansTrait, AccountIdOf, BalanceOf> for Palle Self::distribute_borrower_reward(asset_id, borrower)?; let account_borrows = Self::current_borrow_balance(borrower, asset_id)?; - let account_borrows_new = account_borrows - .checked_add(amount) - .ok_or(ArithmeticError::Overflow)?; + let account_borrows_new = account_borrows.checked_add(amount).ok_or(ArithmeticError::Overflow)?; let total_borrows = Self::total_borrows(asset_id); - let total_borrows_new = total_borrows - .checked_add(amount) - .ok_or(ArithmeticError::Overflow)?; + let total_borrows_new = total_borrows.checked_add(amount).ok_or(ArithmeticError::Overflow)?; AccountBorrows::::insert( asset_id, borrower, @@ -2047,10 +1872,7 @@ impl LoansTrait, AccountIdOf, BalanceOf> for Palle deposits.is_collateral = false; AccountDeposits::::insert(asset_id, supplier, deposits); - Self::deposit_event(Event::::CollateralAssetRemoved( - supplier.clone(), - asset_id, - )); + Self::deposit_event(Event::::CollateralAssetRemoved(supplier.clone(), asset_id)); Ok(()) } @@ -2068,22 +1890,14 @@ impl LoansTrait, AccountIdOf, BalanceOf> for Palle Ok(()) } - fn do_redeem( - supplier: &AccountIdOf, - asset_id: AssetIdOf, - amount: BalanceOf, - ) -> Result<(), DispatchError> { + fn do_redeem(supplier: &AccountIdOf, asset_id: AssetIdOf, amount: BalanceOf) -> Result<(), DispatchError> { Self::ensure_active_market(asset_id)?; Self::accrue_interest(asset_id)?; let exchange_rate = Self::exchange_rate_stored(asset_id)?; Self::update_earned_stored(supplier, asset_id, exchange_rate)?; let voucher_amount = Self::calc_collateral_amount(amount, exchange_rate)?; let redeem_amount = Self::do_redeem_voucher(supplier, asset_id, voucher_amount)?; - Self::deposit_event(Event::::Redeemed( - supplier.clone(), - asset_id, - redeem_amount, - )); + Self::deposit_event(Event::::Redeemed(supplier.clone(), asset_id, redeem_amount)); Ok(()) } } @@ -2091,8 +1905,7 @@ impl LoansTrait, AccountIdOf, BalanceOf> for Palle impl LoansMarketDataProvider, BalanceOf> for Pallet { fn get_market_info(asset_id: AssetIdOf) -> Result { let market = Self::market(asset_id)?; - let full_rate = - Self::get_full_interest_rate(asset_id).ok_or(Error::::InvalidRateModelParam)?; + let full_rate = Self::get_full_interest_rate(asset_id).ok_or(Error::::InvalidRateModelParam)?; Ok(MarketInfo { collateral_factor: market.collateral_factor, liquidation_threshold: market.liquidation_threshold, @@ -2103,15 +1916,8 @@ impl LoansMarketDataProvider, BalanceOf> for Pallet) -> Result, DispatchError> { - let ( - borrow_rate, - supply_rate, - exchange_rate, - utilization, - total_borrows, - total_reserves, - borrow_index, - ) = Self::get_market_status(asset_id)?; + let (borrow_rate, supply_rate, exchange_rate, utilization, total_borrows, total_reserves, borrow_index) = + Self::get_market_status(asset_id)?; Ok(MarketStatus { borrow_rate, supply_rate, @@ -2135,9 +1941,7 @@ impl LoansMarketDataProvider, BalanceOf> for Pallet LoansPositionDataProvider, AccountIdOf, BalanceOf> - for Pallet -{ +impl LoansPositionDataProvider, AccountIdOf, BalanceOf> for Pallet { fn get_current_borrow_balance( borrower: &AccountIdOf, asset_id: AssetIdOf, diff --git a/crates/loans/src/mock.rs b/crates/loans/src/mock.rs index 0ef5a9ccf7..625572c6e0 100644 --- a/crates/loans/src/mock.rs +++ b/crates/loans/src/mock.rs @@ -19,14 +19,16 @@ pub use super::*; use frame_benchmarking::whitelisted_caller; use frame_support::{ - construct_runtime, parameter_types, traits::Everything, traits::SortedMembers, PalletId, + construct_runtime, parameter_types, + traits::{Everything, SortedMembers}, + PalletId, }; use frame_system::EnsureRoot; use orml_traits::{parameter_type_with_key, DataFeeder, DataProvider, DataProviderExtended}; use pallet_traits::{VaultTokenCurrenciesFilter, VaultTokenExchangeRateProvider}; use primitives::{ - CurrencyId::{Token, ForeignAsset}, - Moment, PriceDetail, KSM, CKINT, CKSM, CDOT, CKBTC, KINT, DOT, KBTC, INTR, IBTC, CIBTC, + CurrencyId::{ForeignAsset, Token}, + Moment, PriceDetail, CDOT, CIBTC, CKBTC, CKINT, CKSM, DOT, IBTC, INTR, KBTC, KINT, KSM, }; use sp_core::H256; use sp_runtime::{testing::Header, traits::IdentityLookup, AccountId32}; @@ -177,9 +179,7 @@ impl LoansMarketDataProvider for VaultLoansRateProvider { Ok(Default::default()) } - fn get_market_status( - _: CurrencyId, - ) -> Result, sp_runtime::DispatchError> { + fn get_market_status(_: CurrencyId) -> Result, sp_runtime::DispatchError> { Ok(Default::default()) } } @@ -201,7 +201,7 @@ impl MockPriceFeeder { thread_local! { pub static PRICES: RefCell>> = { RefCell::new( - // Include a foreign assets to act as a liquidation-free collateral for now. + // Include a foreign assets to act as a liquidation-free collateral for now. // TODO: Remove liquidation-free collateral vec![Token(KINT), Token(DOT), Token(KSM), Token(KBTC), Token(INTR), Token(IBTC), ForeignAsset(100000)] .iter() @@ -258,14 +258,12 @@ impl Config for Test { } pub(crate) fn new_test_ext() -> sp_io::TestExternalities { - let t = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap(); + let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); let mut ext = sp_io::TestExternalities::new(t); ext.execute_with(|| { // Init assets - + Tokens::set_balance(Origin::root(), ALICE, Token(KSM), 1000_000000000000, 0).unwrap(); Tokens::set_balance(Origin::root(), ALICE, Token(DOT), 1000_000000000000, 0).unwrap(); Tokens::set_balance(Origin::root(), ALICE, Token(KBTC), 1000_000000000000, 0).unwrap(); diff --git a/crates/loans/src/ptoken.rs b/crates/loans/src/ptoken.rs index 4fd0f052a5..fca3da435e 100644 --- a/crates/loans/src/ptoken.rs +++ b/crates/loans/src/ptoken.rs @@ -53,11 +53,7 @@ impl Inspect for Pallet { /// Get the maximum amount that `who` can withdraw/transfer successfully. /// For ptoken, We don't care if keep_alive is enabled - fn reducible_balance( - ptoken_id: Self::AssetId, - who: &T::AccountId, - _keep_alive: bool, - ) -> Self::Balance { + fn reducible_balance(ptoken_id: Self::AssetId, who: &T::AccountId, _keep_alive: bool) -> Self::Balance { Self::reducible_asset(ptoken_id, who).unwrap_or_default() } @@ -73,16 +69,11 @@ impl Inspect for Pallet { Err(_) => return DepositConsequence::UnknownAsset, }; - if let Err(res) = - Self::ensure_active_market(underlying_id).map_err(|_| DepositConsequence::UnknownAsset) - { + if let Err(res) = Self::ensure_active_market(underlying_id).map_err(|_| DepositConsequence::UnknownAsset) { return res; } - if Self::total_supply(underlying_id) - .checked_add(amount) - .is_none() - { + if Self::total_supply(underlying_id).checked_add(amount).is_none() { return DepositConsequence::Overflow; } @@ -105,9 +96,7 @@ impl Inspect for Pallet { Err(_) => return WithdrawConsequence::UnknownAsset, }; - if let Err(res) = - Self::ensure_active_market(underlying_id).map_err(|_| WithdrawConsequence::UnknownAsset) - { + if let Err(res) = Self::ensure_active_market(underlying_id).map_err(|_| WithdrawConsequence::UnknownAsset) { return res; } @@ -161,24 +150,20 @@ impl Pallet { Self::distribute_supplier_reward(ptoken_id, dest)?; let underlying_id = Self::underlying_id(ptoken_id)?; - AccountDeposits::::try_mutate_exists( - underlying_id, - source, - |deposits| -> DispatchResult { - let mut d = deposits.unwrap_or_default(); - d.voucher_balance = d - .voucher_balance - .checked_sub(amount) - .ok_or(ArithmeticError::Underflow)?; - if d.voucher_balance.is_zero() { - // remove deposits storage if zero balance - *deposits = None; - } else { - *deposits = Some(d); - } - Ok(()) - }, - )?; + AccountDeposits::::try_mutate_exists(underlying_id, source, |deposits| -> DispatchResult { + let mut d = deposits.unwrap_or_default(); + d.voucher_balance = d + .voucher_balance + .checked_sub(amount) + .ok_or(ArithmeticError::Underflow)?; + if d.voucher_balance.is_zero() { + // remove deposits storage if zero balance + *deposits = None; + } else { + *deposits = Some(d); + } + Ok(()) + })?; AccountDeposits::::try_mutate(underlying_id, &dest, |deposits| -> DispatchResult { deposits.voucher_balance = deposits @@ -191,10 +176,7 @@ impl Pallet { Ok(()) } - fn reducible_asset( - ptoken_id: AssetIdOf, - who: &T::AccountId, - ) -> Result, DispatchError> { + fn reducible_asset(ptoken_id: AssetIdOf, who: &T::AccountId) -> Result, DispatchError> { let underlying_id = Self::underlying_id(ptoken_id)?; let Deposits { is_collateral, diff --git a/crates/loans/src/rate_model.rs b/crates/loans/src/rate_model.rs index fd46b2712f..87d20a78f5 100644 --- a/crates/loans/src/rate_model.rs +++ b/crates/loans/src/rate_model.rs @@ -41,18 +41,8 @@ impl Default for InterestRateModel { } impl InterestRateModel { - pub fn new_jump_model( - base_rate: Rate, - jump_rate: Rate, - full_rate: Rate, - jump_utilization: Ratio, - ) -> Self { - Self::Jump(JumpModel::new_model( - base_rate, - jump_rate, - full_rate, - jump_utilization, - )) + pub fn new_jump_model(base_rate: Rate, jump_rate: Rate, full_rate: Rate, jump_utilization: Ratio) -> Self { + Self::Jump(JumpModel::new_model(base_rate, jump_rate, full_rate, jump_utilization)) } pub fn new_curve_model(base_rate: Rate) -> Self { @@ -104,12 +94,7 @@ impl JumpModel { pub const MAX_FULL_RATE: Rate = Rate::from_inner(500_000_000_000_000_000); // 50% /// Create a new rate model - pub fn new_model( - base_rate: Rate, - jump_rate: Rate, - full_rate: Rate, - jump_utilization: Ratio, - ) -> JumpModel { + pub fn new_model(base_rate: Rate, jump_rate: Rate, full_rate: Rate, jump_utilization: Ratio) -> JumpModel { Self { base_rate, jump_rate, @@ -184,9 +169,7 @@ impl CurveModel { pub fn get_borrow_rate(&self, utilization: Ratio) -> Option { const NINE: usize = 9; let utilization_rate: Rate = utilization.into(); - utilization_rate - .saturating_pow(NINE) - .checked_add(&self.base_rate) + utilization_rate.saturating_pow(NINE).checked_add(&self.base_rate) } } @@ -238,8 +221,7 @@ mod tests { cash = 100; let util = Ratio::from_rational(borrows, cash + borrows); let borrow_rate = jump_model.get_borrow_rate(util).unwrap(); - let normal_rate = - jump_model.jump_rate.saturating_mul(jump_utilization.into()) + jump_model.base_rate; + let normal_rate = jump_model.jump_rate.saturating_mul(jump_utilization.into()) + jump_model.base_rate; let excess_util = util.saturating_sub(jump_utilization); assert_eq!( borrow_rate, @@ -260,8 +242,7 @@ mod tests { let supply_rate = InterestRateModel::get_supply_rate(borrow_rate, util, reserve_factor); assert_eq!( supply_rate, - borrow_rate - .saturating_mul(((Ratio::one().saturating_sub(reserve_factor)) * util).into()), + borrow_rate.saturating_mul(((Ratio::one().saturating_sub(reserve_factor)) * util).into()), ); } diff --git a/crates/loans/src/tests.rs b/crates/loans/src/tests.rs index c073b912b5..0419a8c870 100644 --- a/crates/loans/src/tests.rs +++ b/crates/loans/src/tests.rs @@ -28,7 +28,7 @@ use sp_runtime::{ FixedU128, Permill, }; -use primitives::{CurrencyId::Token, DOT as DOT_CURRENCY, KSM as KSM_CURRENCY, KBTC, IBTC, KINT}; +use primitives::{CurrencyId::Token, DOT as DOT_CURRENCY, IBTC, KBTC, KINT, KSM as KSM_CURRENCY}; use crate::mock::*; @@ -40,7 +40,6 @@ const USDT: CurrencyId = Token(KBTC); const CDOT_6_13: CurrencyId = Token(IBTC); const HKO: CurrencyId = Token(KINT); - #[test] fn init_minting_ok() { new_test_ext().execute_with(|| { @@ -63,18 +62,9 @@ fn init_markets_ok() { assert_eq!(BorrowIndex::::get(DOT), Rate::one()); assert_eq!(BorrowIndex::::get(USDT), Rate::one()); - assert_eq!( - ExchangeRate::::get(KSM), - Rate::saturating_from_rational(2, 100) - ); - assert_eq!( - ExchangeRate::::get(DOT), - Rate::saturating_from_rational(2, 100) - ); - assert_eq!( - ExchangeRate::::get(USDT), - Rate::saturating_from_rational(2, 100) - ); + assert_eq!(ExchangeRate::::get(KSM), Rate::saturating_from_rational(2, 100)); + assert_eq!(ExchangeRate::::get(DOT), Rate::saturating_from_rational(2, 100)); + assert_eq!(ExchangeRate::::get(USDT), Rate::saturating_from_rational(2, 100)); }); } @@ -84,10 +74,7 @@ fn loans_native_token_works() { assert_eq!(Tokens::balance(HKO, &DAVE), unit(1000)); assert_eq!(Loans::market(HKO).unwrap().state, MarketState::Active); assert_eq!(BorrowIndex::::get(HKO), Rate::one()); - assert_eq!( - ExchangeRate::::get(HKO), - Rate::saturating_from_rational(2, 100) - ); + assert_eq!(ExchangeRate::::get(HKO), Rate::saturating_from_rational(2, 100)); assert_ok!(Loans::mint(Origin::signed(DAVE), HKO, unit(1000))); // Redeem 1001 HKO should cause InsufficientDeposit @@ -109,8 +96,7 @@ fn loans_native_token_works() { // HKO borrow balance: borrow - repay = 500 - 400 = 100 // HKO: cash - deposit + borrow - repay = 1000 - 1000 + 500 - 400 = 100 assert_eq!( - Loans::exchange_rate(HKO) - .saturating_mul_int(Loans::account_deposits(HKO, DAVE).voucher_balance), + Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(HKO, DAVE).voucher_balance), unit(1000) ); let borrow_snapshot = Loans::account_borrows(HKO, DAVE); @@ -129,15 +115,11 @@ fn mint_works() { // DOT collateral: deposit = 100 // DOT: cash - deposit = 1000 - 100 = 900 assert_eq!( - Loans::exchange_rate(DOT) - .saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), + Loans::exchange_rate(DOT).saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), unit(100) ); assert_eq!(Tokens::balance(DOT, &ALICE), unit(900),); - assert_eq!( - Tokens::balance(DOT, &Loans::account_id()), - unit(100), - ); + assert_eq!(Tokens::balance(DOT, &Loans::account_id()), unit(100),); }) } @@ -163,13 +145,7 @@ fn mint_must_return_err_when_overflows_occur() { ); // Deposit OVERFLOW_DEPOSIT DOT for CHARLIE - assert_ok!(Tokens::set_balance( - Origin::root(), - CHARLIE, - DOT, - OVERFLOW_DEPOSIT, - 0 - )); + assert_ok!(Tokens::set_balance(Origin::root(), CHARLIE, DOT, OVERFLOW_DEPOSIT, 0)); // Amount is too large, OVERFLOW_DEPOSIT / 0.0X == Overflow // Underflow is used here redeem could also be 0 @@ -221,7 +197,6 @@ fn redeem_allowed_works() { }) } - // ignore: tests liquidation-free collateral #[ignore] #[test] @@ -266,8 +241,7 @@ fn redeem_works() { // DOT collateral: deposit - redeem = 100 - 20 = 80 // DOT: cash - deposit + redeem = 1000 - 100 + 20 = 920 assert_eq!( - Loans::exchange_rate(DOT) - .saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), + Loans::exchange_rate(DOT).saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), unit(80) ); assert_eq!(Tokens::balance(DOT, &ALICE), unit(920),); @@ -353,8 +327,7 @@ fn redeem_all_works() { // DOT: cash - deposit + redeem = 1000 - 100 + 100 = 1000 // DOT collateral: deposit - redeem = 100 - 100 = 0 assert_eq!( - Loans::exchange_rate(DOT) - .saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), + Loans::exchange_rate(DOT).saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), 0, ); assert_eq!(Tokens::balance(DOT, &ALICE), unit(1000),); @@ -424,8 +397,7 @@ fn get_account_liquidation_threshold_liquidity_works() { Loans::borrow(Origin::signed(ALICE), KSM, unit(100)).unwrap(); Loans::borrow(Origin::signed(ALICE), DOT, unit(100)).unwrap(); - let (liquidity, _, lf_liquidity, _) = - Loans::get_account_liquidation_threshold_liquidity(&ALICE).unwrap(); + let (liquidity, _, lf_liquidity, _) = Loans::get_account_liquidation_threshold_liquidity(&ALICE).unwrap(); assert_eq!(liquidity, FixedU128::from_inner(unit(20))); assert_eq!(lf_liquidity, FixedU128::from_inner(unit(0))); @@ -477,8 +449,7 @@ fn borrow_works() { // DOT borrow balance: borrow = 100 // DOT: cash - deposit + borrow = 1000 - 200 + 100 = 900 assert_eq!( - Loans::exchange_rate(DOT) - .saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), + Loans::exchange_rate(DOT).saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), unit(200) ); let borrow_snapshot = Loans::account_borrows(DOT, ALICE); @@ -529,8 +500,7 @@ fn repay_borrow_works() { // DOT borrow balance: borrow - repay = 100 - 30 = 70 // DOT: cash - deposit + borrow - repay = 1000 - 200 + 100 - 30 = 870 assert_eq!( - Loans::exchange_rate(DOT) - .saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), + Loans::exchange_rate(DOT).saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), unit(200) ); let borrow_snapshot = Loans::account_borrows(DOT, ALICE); @@ -560,8 +530,7 @@ fn repay_borrow_all_works() { // KSM borrow balance: borrow - repay = 50 - 50 = 0 assert_eq!(Tokens::balance(DOT, &ALICE), unit(800),); assert_eq!( - Loans::exchange_rate(DOT) - .saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), + Loans::exchange_rate(DOT).saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), unit(200) ); let borrow_snapshot = Loans::account_borrows(KSM, ALICE); @@ -627,10 +596,7 @@ fn add_reserves_works() { assert_ok!(Loans::add_reserves(Origin::root(), ALICE, DOT, unit(100))); assert_eq!(Loans::total_reserves(DOT), unit(100)); - assert_eq!( - Tokens::balance(DOT, &Loans::account_id()), - unit(100), - ); + assert_eq!(Tokens::balance(DOT, &Loans::account_id()), unit(100),); assert_eq!(Tokens::balance(DOT, &ALICE), unit(900),); }) } @@ -645,10 +611,7 @@ fn reduce_reserves_works() { assert_ok!(Loans::reduce_reserves(Origin::root(), ALICE, DOT, unit(20))); assert_eq!(Loans::total_reserves(DOT), unit(80)); - assert_eq!( - Tokens::balance(DOT, &Loans::account_id()), - unit(80), - ); + assert_eq!(Tokens::balance(DOT, &Loans::account_id()), unit(80),); assert_eq!(Tokens::balance(DOT, &ALICE), unit(920),); }) } @@ -695,10 +658,7 @@ fn ratio_and_rate_works() { let value1 = FixedU128::saturating_from_rational(9, 10); let value2 = 10_u128; let value3 = FixedU128::saturating_from_integer(10_u128); - assert_eq!( - value1.reciprocal(), - Some(FixedU128::saturating_from_rational(10, 9)) - ); + assert_eq!(value1.reciprocal(), Some(FixedU128::saturating_from_rational(10, 9))); // u128 div FixedU128 assert_eq!( FixedU128::saturating_from_integer(value2).checked_div(&value1), @@ -706,10 +666,7 @@ fn ratio_and_rate_works() { ); // FixedU128 div u128 - assert_eq!( - value1.reciprocal().and_then(|r| r.checked_mul_int(value2)), - Some(11) - ); + assert_eq!(value1.reciprocal().and_then(|r| r.checked_mul_int(value2)), Some(11)); assert_eq!( FixedU128::from_inner(17_777_777_777_777_777_777).checked_div_int(value2), Some(1) @@ -775,10 +732,7 @@ fn ratio_and_rate_works() { fn update_exchange_rate_works() { new_test_ext().execute_with(|| { // Initialize value of exchange rate is 0.02 - assert_eq!( - Loans::exchange_rate(DOT), - Rate::saturating_from_rational(2, 100) - ); + assert_eq!(Loans::exchange_rate(DOT), Rate::saturating_from_rational(2, 100)); // total_supply = 0 TotalSupply::::insert(DOT, 0); @@ -844,10 +798,7 @@ fn current_borrow_balance_works() { #[test] fn calc_collateral_amount_works() { let exchange_rate = Rate::saturating_from_rational(3, 10); - assert_eq!( - Loans::calc_collateral_amount(1000, exchange_rate).unwrap(), - 3333 - ); + assert_eq!(Loans::calc_collateral_amount(1000, exchange_rate).unwrap(), 3333); assert_eq!( Loans::calc_collateral_amount(u128::MAX, exchange_rate), Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) @@ -855,10 +806,7 @@ fn calc_collateral_amount_works() { // relative test: prevent_the_exchange_rate_attack let exchange_rate = Rate::saturating_from_rational(30000, 1); - assert_eq!( - Loans::calc_collateral_amount(10000, exchange_rate).unwrap(), - 0 - ); + assert_eq!(Loans::calc_collateral_amount(10000, exchange_rate).unwrap(), 0); } #[test] @@ -868,10 +816,7 @@ fn get_price_works() { assert_noop!(Loans::get_price(DOT), Error::::PriceIsZero); MockPriceFeeder::set_price(DOT, 2.into()); - assert_eq!( - Loans::get_price(DOT).unwrap(), - Price::saturating_from_integer(2) - ); + assert_eq!(Loans::get_price(DOT).unwrap(), Price::saturating_from_integer(2)); }) } @@ -902,15 +847,15 @@ fn ensure_valid_exchange_rate_works() { Loans::ensure_valid_exchange_rate(FixedU128::saturating_from_rational(1, 100)), Error::::InvalidExchangeRate ); - assert_ok!(Loans::ensure_valid_exchange_rate( - FixedU128::saturating_from_rational(2, 100) - )); - assert_ok!(Loans::ensure_valid_exchange_rate( - FixedU128::saturating_from_rational(3, 100) - )); - assert_ok!(Loans::ensure_valid_exchange_rate( - FixedU128::saturating_from_rational(99, 100) - )); + assert_ok!(Loans::ensure_valid_exchange_rate(FixedU128::saturating_from_rational( + 2, 100 + ))); + assert_ok!(Loans::ensure_valid_exchange_rate(FixedU128::saturating_from_rational( + 3, 100 + ))); + assert_ok!(Loans::ensure_valid_exchange_rate(FixedU128::saturating_from_rational( + 99, 100 + ))); assert_noop!( Loans::ensure_valid_exchange_rate(Rate::one()), Error::::InvalidExchangeRate, @@ -929,20 +874,13 @@ fn withdraw_missing_reward_works() { assert_ok!(Loans::add_reward(Origin::signed(DAVE), unit(100))); - assert_ok!(Loans::withdraw_missing_reward( - Origin::root(), - ALICE, - unit(40), - )); + assert_ok!(Loans::withdraw_missing_reward(Origin::root(), ALICE, unit(40),)); assert_eq!(Tokens::balance(HKO, &DAVE), unit(900)); assert_eq!(Tokens::balance(HKO, &ALICE), unit(40)); - assert_eq!( - Tokens::balance(HKO, &Loans::reward_account_id().unwrap()), - unit(60) - ); + assert_eq!(Tokens::balance(HKO, &Loans::reward_account_id().unwrap()), unit(60)); }) } @@ -970,12 +908,7 @@ fn update_market_reward_speed_works() { assert_eq!(Loans::reward_supply_speed(DOT), unit(2)); assert_eq!(Loans::reward_borrow_speed(DOT), unit(0)); - assert_ok!(Loans::update_market_reward_speed( - Origin::root(), - DOT, - Some(0), - Some(0) - )); + assert_ok!(Loans::update_market_reward_speed(Origin::root(), DOT, Some(0), Some(0))); assert_eq!(Loans::reward_supply_speed(DOT), unit(0)); assert_eq!(Loans::reward_borrow_speed(DOT), unit(0)); }) @@ -1034,12 +967,7 @@ fn reward_calculation_one_palyer_in_multi_markets_works() { assert_eq!(Loans::reward_accrued(ALICE), unit(10)); _run_to_block(30); - assert_ok!(Loans::update_market_reward_speed( - Origin::root(), - DOT, - Some(0), - Some(0) - )); + assert_ok!(Loans::update_market_reward_speed(Origin::root(), DOT, Some(0), Some(0))); assert_ok!(Loans::redeem(Origin::signed(ALICE), DOT, unit(100))); assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(10))); assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, unit(100))); @@ -1056,12 +984,7 @@ fn reward_calculation_one_palyer_in_multi_markets_works() { assert_eq!(almost_equal(Loans::reward_accrued(ALICE), unit(80)), true); _run_to_block(40); - assert_ok!(Loans::update_market_reward_speed( - Origin::root(), - KSM, - Some(0), - Some(0) - )); + assert_ok!(Loans::update_market_reward_speed(Origin::root(), KSM, Some(0), Some(0))); assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(100))); assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(10))); assert_ok!(Loans::redeem(Origin::signed(ALICE), KSM, unit(100))); @@ -1121,18 +1044,8 @@ fn reward_calculation_one_palyer_in_multi_markets_works() { assert_eq!(almost_equal(Loans::reward_accrued(ALICE), unit(110)), true,); _run_to_block(70); - assert_ok!(Loans::update_market_reward_speed( - Origin::root(), - DOT, - Some(0), - Some(0) - )); - assert_ok!(Loans::update_market_reward_speed( - Origin::root(), - KSM, - Some(0), - Some(0) - )); + assert_ok!(Loans::update_market_reward_speed(Origin::root(), DOT, Some(0), Some(0))); + assert_ok!(Loans::update_market_reward_speed(Origin::root(), KSM, Some(0), Some(0))); assert_ok!(Loans::redeem(Origin::signed(ALICE), DOT, unit(100))); assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, unit(100))); @@ -1150,15 +1063,9 @@ fn reward_calculation_one_palyer_in_multi_markets_works() { assert_ok!(Loans::add_reward(Origin::signed(DAVE), unit(200))); assert_ok!(Loans::claim_reward(Origin::signed(ALICE))); assert_eq!(Tokens::balance(HKO, &DAVE), unit(800)); + assert_eq!(almost_equal(Tokens::balance(HKO, &ALICE), unit(130)), true); assert_eq!( - almost_equal(Tokens::balance(HKO, &ALICE), unit(130)), - true - ); - assert_eq!( - almost_equal( - Tokens::balance(HKO, &Loans::reward_account_id().unwrap()), - unit(70) - ), + almost_equal(Tokens::balance(HKO, &Loans::reward_account_id().unwrap()), unit(70)), true ); assert_ok!(Loans::update_market_reward_speed( @@ -1174,10 +1081,7 @@ fn reward_calculation_one_palyer_in_multi_markets_works() { // KSM borrow:0 KSM borrow reward: 20 _run_to_block(90); assert_ok!(Loans::claim_reward(Origin::signed(ALICE))); - assert_eq!( - almost_equal(Tokens::balance(HKO, &ALICE), unit(140)), - true - ); + assert_eq!(almost_equal(Tokens::balance(HKO, &ALICE), unit(140)), true); }) } @@ -1266,19 +1170,10 @@ fn reward_calculation_multi_player_in_one_market_works() { assert_ok!(Loans::claim_reward_for_market(Origin::signed(ALICE), DOT)); assert_ok!(Loans::claim_reward_for_market(Origin::signed(BOB), DOT)); assert_eq!(Tokens::balance(HKO, &DAVE), unit(800)); + assert_eq!(almost_equal(Tokens::balance(HKO, &ALICE), unit(58)), true); + assert_eq!(almost_equal(Tokens::balance(HKO, &BOB), unit(22)), true); assert_eq!( - almost_equal(Tokens::balance(HKO, &ALICE), unit(58)), - true - ); - assert_eq!( - almost_equal(Tokens::balance(HKO, &BOB), unit(22)), - true - ); - assert_eq!( - almost_equal( - Tokens::balance(HKO, &Loans::reward_account_id().unwrap()), - unit(120) - ), + almost_equal(Tokens::balance(HKO, &Loans::reward_account_id().unwrap()), unit(120)), true ); }) @@ -1342,13 +1237,7 @@ fn reward_calculation_after_liquidate_borrow_works() { // Bob KSM Borrow: 75 // incentive_reward_account DOT Deposit: 75*0.03 = 2.25 MockPriceFeeder::set_price(KSM, 3.into()); - assert_ok!(Loans::liquidate_borrow( - Origin::signed(BOB), - ALICE, - KSM, - unit(25), - DOT - )); + assert_ok!(Loans::liquidate_borrow(Origin::signed(BOB), ALICE, KSM, unit(25), DOT)); _run_to_block(30); assert_ok!(Loans::update_reward_supply_index(DOT)); @@ -1369,14 +1258,8 @@ fn reward_calculation_after_liquidate_borrow_works() { &Loans::incentive_reward_account_id().unwrap(), )); - assert_eq!( - almost_equal(Loans::reward_accrued(ALICE), milli_unit(22375)), - true - ); - assert_eq!( - almost_equal(Loans::reward_accrued(BOB), micro_unit(37512500)), - true - ); + assert_eq!(almost_equal(Loans::reward_accrued(ALICE), milli_unit(22375)), true); + assert_eq!(almost_equal(Loans::reward_accrued(BOB), micro_unit(37512500)), true); assert_eq!( almost_equal( Loans::reward_accrued(Loans::incentive_reward_account_id().unwrap()), diff --git a/crates/loans/src/tests/edge_cases.rs b/crates/loans/src/tests/edge_cases.rs index 71f3350c29..d467ec6b02 100644 --- a/crates/loans/src/tests/edge_cases.rs +++ b/crates/loans/src/tests/edge_cases.rs @@ -1,11 +1,9 @@ use super::*; -use crate::tests::Loans; -use crate::{mock::*, Error}; +use crate::{mock::*, tests::Loans, Error}; use frame_support::{assert_err, assert_ok}; -use primitives::{KSM, IBTC}; use primitives::{ CurrencyId::{ForeignAsset, Token}, - DOT, KSM, + DOT, IBTC, KSM, }; use sp_runtime::FixedPointNumber; @@ -81,10 +79,7 @@ fn redeem_all_should_be_accurate() { // let exchange_rate greater than 0.02 accrue_interest_per_block(Token(KSM), 6, 2); - assert_eq!( - Loans::exchange_rate(Token(KSM)), - Rate::from_inner(20000000036387000) - ); + assert_eq!(Loans::exchange_rate(Token(KSM)), Rate::from_inner(20000000036387000)); assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), Token(KSM))); // It failed with InsufficientLiquidity before #839 @@ -114,10 +109,7 @@ fn prevent_the_exchange_rate_attack() { false )); assert_eq!(Tokens::balance(Token(DOT), &EVE), 99999999999999); - assert_eq!( - Tokens::balance(Token(DOT), &Loans::account_id()), - 100000000000001 - ); + assert_eq!(Tokens::balance(Token(DOT), &Loans::account_id()), 100000000000001); assert_eq!( Loans::total_supply(Token(DOT)), 1 * 50, // 1 / 0.02 @@ -127,10 +119,7 @@ fn prevent_the_exchange_rate_attack() { assert!(Loans::accrue_interest(Token(DOT)).is_err()); // Mock a BIG exchange_rate: 100000000000.02 - ExchangeRate::::insert( - Token(DOT), - Rate::saturating_from_rational(100000000000020u128, 20 * 50), - ); + ExchangeRate::::insert(Token(DOT), Rate::saturating_from_rational(100000000000020u128, 20 * 50)); // Bob can not deposit 0.1 DOT because the voucher_balance can not be 0. assert_noop!( Loans::mint(Origin::signed(BOB), Token(DOT), 100000000000), diff --git a/crates/loans/src/tests/interest_rate.rs b/crates/loans/src/tests/interest_rate.rs index a1008e494f..0eaab88f98 100644 --- a/crates/loans/src/tests/interest_rate.rs +++ b/crates/loans/src/tests/interest_rate.rs @@ -1,7 +1,6 @@ -use crate::tests::Loans; -use crate::{mock::*, Markets}; +use crate::{mock::*, tests::Loans, Markets}; use frame_support::assert_ok; -use primitives::{Rate, Ratio, SECONDS_PER_YEAR, DOT, KSM, CurrencyId::Token}; +use primitives::{CurrencyId::Token, Rate, Ratio, DOT, KSM, SECONDS_PER_YEAR}; use sp_runtime::{ traits::{CheckedDiv, One, Saturating}, FixedPointNumber, @@ -10,19 +9,13 @@ use sp_runtime::{ #[test] fn utilization_rate_works() { // 50% borrow - assert_eq!( - Loans::calc_utilization_ratio(1, 1, 0).unwrap(), - Ratio::from_percent(50) - ); + assert_eq!(Loans::calc_utilization_ratio(1, 1, 0).unwrap(), Ratio::from_percent(50)); assert_eq!( Loans::calc_utilization_ratio(100, 100, 0).unwrap(), Ratio::from_percent(50) ); // no borrow - assert_eq!( - Loans::calc_utilization_ratio(1, 0, 0).unwrap(), - Ratio::zero() - ); + assert_eq!(Loans::calc_utilization_ratio(1, 0, 0).unwrap(), Ratio::zero()); // full borrow assert_eq!( Loans::calc_utilization_ratio(0, 1, 0).unwrap(), @@ -34,22 +27,14 @@ fn utilization_rate_works() { fn interest_rate_model_works() { new_test_ext().execute_with(|| { let rate_decimal: u128 = 1_000_000_000_000_000_000; - Tokens::set_balance( - Origin::root(), - ALICE, - Token(DOT), - million_unit(1000) - unit(1000), - 0 - ) - .unwrap(); + Tokens::set_balance(Origin::root(), ALICE, Token(DOT), million_unit(1000) - unit(1000), 0).unwrap(); // Deposit 200 DOT and borrow 100 DOT assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), million_unit(200))); assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), million_unit(100))); let total_cash = million_unit(200) - million_unit(100); - let total_supply = - Loans::calc_collateral_amount(million_unit(200), Loans::exchange_rate(Token(DOT))).unwrap(); + let total_supply = Loans::calc_collateral_amount(million_unit(200), Loans::exchange_rate(Token(DOT))).unwrap(); assert_eq!(Loans::total_supply(Token(DOT)), total_supply); let borrow_snapshot = Loans::account_borrows(Token(DOT), ALICE); @@ -74,8 +59,7 @@ fn interest_rate_model_works() { let util_ratio = Ratio::from_rational(total_borrows, total_cash + total_borrows); assert_eq!(Loans::utilization_ratio(Token(DOT)), util_ratio); - let borrow_rate = - (jump_rate - base_rate) * util_ratio.into() / jump_utilization.into() + base_rate; + let borrow_rate = (jump_rate - base_rate) * util_ratio.into() / jump_utilization.into() + base_rate; let interest_accumulated: u128 = borrow_rate .saturating_mul_int(total_borrows) .saturating_mul(delta_time.into()) @@ -106,16 +90,12 @@ fn interest_rate_model_works() { assert_eq!(total_borrows, 100000063926960646826); assert_eq!(total_reserves, 9589044097001); assert_eq!(borrow_index, Rate::from_inner(1000000639269606444)); - assert_eq!( - Loans::exchange_rate(Token(DOT)), - Rate::from_inner(20000005433791654) - ); + assert_eq!(Loans::exchange_rate(Token(DOT)), Rate::from_inner(20000005433791654)); // Calculate borrow accrued interest - let borrow_principal = (borrow_index / borrow_snapshot.borrow_index) - .saturating_mul_int(borrow_snapshot.principal); - let supply_interest = - Loans::exchange_rate(Token(DOT)).saturating_mul_int(total_supply) - million_unit(200); + let borrow_principal = + (borrow_index / borrow_snapshot.borrow_index).saturating_mul_int(borrow_snapshot.principal); + let supply_interest = Loans::exchange_rate(Token(DOT)).saturating_mul_int(total_supply) - million_unit(200); assert_eq!(supply_interest, 54337916540000); assert_eq!(borrow_principal, 100000063926960644400); assert_eq!(total_borrows / 10000, borrow_principal / 10000); @@ -138,10 +118,7 @@ fn last_accrued_interest_time_should_be_update_correctly() { assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); TimestampPallet::set_timestamp(12000); assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(100))); - assert_eq!( - Loans::borrow_index(Token(DOT)), - Rate::from_inner(1000000013318112633), - ); + assert_eq!(Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000013318112633),); }) } @@ -154,10 +131,7 @@ fn accrue_interest_works_after_mint() { assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); TimestampPallet::set_timestamp(12000); assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(100))); - assert_eq!( - Loans::borrow_index(Token(DOT)), - Rate::from_inner(1000000013318112633), - ); + assert_eq!(Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000013318112633),); }) } @@ -169,10 +143,7 @@ fn accrue_interest_works_after_borrow() { assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); TimestampPallet::set_timestamp(12000); assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), unit(100))); - assert_eq!( - Loans::borrow_index(Token(DOT)), - Rate::from_inner(1000000003805175038), - ); + assert_eq!(Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000003805175038),); }) } @@ -185,19 +156,13 @@ fn accrue_interest_works_after_redeem() { assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); TimestampPallet::set_timestamp(12000); assert_ok!(Loans::redeem(Origin::signed(ALICE), Token(DOT), unit(10))); - assert_eq!( - Loans::borrow_index(Token(DOT)), - Rate::from_inner(1000000004756468797), - ); + assert_eq!(Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000004756468797),); assert_eq!( Loans::exchange_rate(Token(DOT)) .saturating_mul_int(Loans::account_deposits(Token(DOT), BOB).voucher_balance), 0, ); - assert_eq!( - Tokens::balance(Token(DOT), &ALICE), - 819999999999999 - ); + assert_eq!(Tokens::balance(Token(DOT), &ALICE), 819999999999999); }) } @@ -211,19 +176,13 @@ fn accrue_interest_works_after_redeem_all() { assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); TimestampPallet::set_timestamp(12000); assert_ok!(Loans::redeem_all(Origin::signed(BOB), Token(DOT))); - assert_eq!( - Loans::borrow_index(Token(DOT)), - Rate::from_inner(1000000004669977168), - ); + assert_eq!(Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000004669977168),); assert_eq!( Loans::exchange_rate(Token(DOT)) .saturating_mul_int(Loans::account_deposits(Token(DOT), BOB).voucher_balance), 0, ); - assert_eq!( - Tokens::balance(Token(DOT), &BOB), - 1000000000003608 - ); + assert_eq!(Tokens::balance(Token(DOT), &BOB), 1000000000003608); assert!(!AccountDeposits::::contains_key(Token(DOT), &BOB)) }) } @@ -237,10 +196,7 @@ fn accrue_interest_works_after_repay() { assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); TimestampPallet::set_timestamp(12000); assert_ok!(Loans::repay_borrow(Origin::signed(ALICE), Token(DOT), unit(10))); - assert_eq!( - Loans::borrow_index(Token(DOT)), - Rate::from_inner(1000000005707762557), - ); + assert_eq!(Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000005707762557),); }) } @@ -254,14 +210,8 @@ fn accrue_interest_works_after_repay_all() { assert_eq!(Loans::borrow_index(Token(KSM)), Rate::one()); TimestampPallet::set_timestamp(12000); assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), Token(KSM))); - assert_eq!( - Loans::borrow_index(Token(KSM)), - Rate::from_inner(1000000008561643835), - ); - assert_eq!( - Tokens::balance(Token(KSM), &ALICE), - 999999999571918 - ); + assert_eq!(Loans::borrow_index(Token(KSM)), Rate::from_inner(1000000008561643835),); + assert_eq!(Tokens::balance(Token(KSM), &ALICE), 999999999571918); let borrow_snapshot = Loans::account_borrows(Token(KSM), ALICE); assert_eq!(borrow_snapshot.principal, 0); assert_eq!(borrow_snapshot.borrow_index, Loans::borrow_index(Token(KSM))); @@ -292,14 +242,8 @@ fn accrue_interest_works_after_liquidate_borrow() { unit(50), Token(DOT) )); - assert_eq!( - Loans::borrow_index(Token(KSM)), - Rate::from_inner(1000000013318112633), - ); - assert_eq!( - Loans::borrow_index(Token(DOT)), - Rate::from_inner(1000000006976141552), - ); + assert_eq!(Loans::borrow_index(Token(KSM)), Rate::from_inner(1000000013318112633),); + assert_eq!(Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000006976141552),); }) } @@ -315,14 +259,8 @@ fn different_markets_can_accrue_interest_in_one_block() { TimestampPallet::set_timestamp(12000); assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), unit(100))); assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(KSM), unit(100))); - assert_eq!( - Loans::borrow_index(Token(DOT)), - Rate::from_inner(1000000003805175038), - ); - assert_eq!( - Loans::borrow_index(Token(KSM)), - Rate::from_inner(1000000003805175038), - ); + assert_eq!(Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000003805175038),); + assert_eq!(Loans::borrow_index(Token(KSM)), Rate::from_inner(1000000003805175038),); }) } @@ -337,9 +275,6 @@ fn a_market_can_only_accrue_interest_once_in_a_block() { TimestampPallet::set_timestamp(12000); assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), unit(100))); assert_ok!(Loans::borrow(Origin::signed(BOB), Token(DOT), unit(100))); - assert_eq!( - Loans::borrow_index(Token(DOT)), - Rate::from_inner(1000000003805175038), - ); + assert_eq!(Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000003805175038),); }) } diff --git a/crates/loans/src/tests/liquidate_borrow.rs b/crates/loans/src/tests/liquidate_borrow.rs index be127e2267..515fe8cdd2 100644 --- a/crates/loans/src/tests/liquidate_borrow.rs +++ b/crates/loans/src/tests/liquidate_borrow.rs @@ -1,7 +1,5 @@ use crate::{ - mock::{ - new_test_ext, Tokens, Loans, MockPriceFeeder, Origin, Test, ALICE, BOB, - }, + mock::{new_test_ext, Loans, MockPriceFeeder, Origin, Test, Tokens, ALICE, BOB}, tests::unit, Error, MarketState, }; @@ -39,12 +37,7 @@ fn liquidate_borrow_allowed_works() { Loans::liquidate_borrow_allowed(&ALICE, KSM, unit(51), &ksm_market), Error::::TooMuchRepay ); - assert_ok!(Loans::liquidate_borrow_allowed( - &ALICE, - KSM, - unit(50), - &ksm_market - )); + assert_ok!(Loans::liquidate_borrow_allowed(&ALICE, KSM, unit(50), &ksm_market)); }) } @@ -82,22 +75,12 @@ fn lf_liquidate_borrow_allowed_works() { Loans::liquidate_borrow_allowed(&ALICE, DOT, unit(51), &dot_market), Error::::TooMuchRepay ); - assert_ok!(Loans::liquidate_borrow_allowed( - &ALICE, - DOT, - unit(50), - &dot_market - )); + assert_ok!(Loans::liquidate_borrow_allowed(&ALICE, DOT, unit(50), &dot_market)); // Remove CDOT from lf collateral // Loans::update_liquidation_free_collateral(Origin::root(), vec![]).unwrap(); // The max repay amount = 400 * 50 = $200 - assert_ok!(Loans::liquidate_borrow_allowed( - &ALICE, - DOT, - unit(100), - &dot_market - )); + assert_ok!(Loans::liquidate_borrow_allowed(&ALICE, DOT, unit(100), &dot_market)); }) } @@ -146,13 +129,7 @@ fn full_workflow_works_as_expected() { // adjust KSM price to make ALICE generate shortfall MockPriceFeeder::set_price(KSM, 2.into()); // BOB repay the KSM borrow balance and get DOT from ALICE - assert_ok!(Loans::liquidate_borrow( - Origin::signed(BOB), - ALICE, - KSM, - unit(50), - USDT - )); + assert_ok!(Loans::liquidate_borrow(Origin::signed(BOB), ALICE, KSM, unit(50), USDT)); // KSM price = 2 // incentive = repay KSM value * 1.1 = (50 * 2) * 1.1 = 110 @@ -164,43 +141,31 @@ fn full_workflow_works_as_expected() { // Bob DOT collateral: incentive = 110-(110/1.1*0.03)=107 assert_eq!(Tokens::balance(USDT, &ALICE), unit(800),); assert_eq!( - Loans::exchange_rate(USDT) - .saturating_mul_int(Loans::account_deposits(USDT, ALICE).voucher_balance), + Loans::exchange_rate(USDT).saturating_mul_int(Loans::account_deposits(USDT, ALICE).voucher_balance), unit(90), ); assert_eq!(Tokens::balance(KSM, &ALICE), unit(1100),); assert_eq!(Loans::account_borrows(KSM, ALICE).principal, unit(50)); assert_eq!(Tokens::balance(KSM, &BOB), unit(750)); assert_eq!( - Loans::exchange_rate(USDT) - .saturating_mul_int(Loans::account_deposits(USDT, BOB).voucher_balance), + Loans::exchange_rate(USDT).saturating_mul_int(Loans::account_deposits(USDT, BOB).voucher_balance), unit(107), ); // 3 dollar reserved in our incentive reward account let incentive_reward_account = Loans::incentive_reward_account_id().unwrap(); - println!( - "incentive reserve account:{:?}", - incentive_reward_account.clone() - ); + println!("incentive reserve account:{:?}", incentive_reward_account.clone()); assert_eq!( - Loans::exchange_rate(USDT).saturating_mul_int( - Loans::account_deposits(USDT, incentive_reward_account.clone()).voucher_balance - ), + Loans::exchange_rate(USDT) + .saturating_mul_int(Loans::account_deposits(USDT, incentive_reward_account.clone()).voucher_balance), unit(3), ); assert_eq!(Tokens::balance(USDT, &ALICE), unit(800),); // reduce 2 dollar from incentive reserve to alice account - assert_ok!(Loans::reduce_incentive_reserves( - Origin::root(), - ALICE, - USDT, - unit(2), - )); + assert_ok!(Loans::reduce_incentive_reserves(Origin::root(), ALICE, USDT, unit(2),)); // still 1 dollar left in reserve account assert_eq!( - Loans::exchange_rate(USDT).saturating_mul_int( - Loans::account_deposits(USDT, incentive_reward_account).voucher_balance - ), + Loans::exchange_rate(USDT) + .saturating_mul_int(Loans::account_deposits(USDT, incentive_reward_account).voucher_balance), unit(1), ); // 2 dollar transfer to alice diff --git a/crates/loans/src/tests/market.rs b/crates/loans/src/tests/market.rs index 1dbb2d6f3b..df6f68ac1c 100644 --- a/crates/loans/src/tests/market.rs +++ b/crates/loans/src/tests/market.rs @@ -1,8 +1,5 @@ use crate::{ - mock::{ - market_mock, new_test_ext, Loans, Origin, Test, ACTIVE_MARKET_MOCK, ALICE, - MARKET_MOCK, - }, + mock::{market_mock, new_test_ext, Loans, Origin, Test, ACTIVE_MARKET_MOCK, ALICE, MARKET_MOCK}, Error, InterestRateModel, MarketState, }; use frame_support::{assert_noop, assert_ok, error::BadOrigin}; @@ -117,10 +114,7 @@ fn active_market_does_not_modify_unknown_market_currencies() { #[test] fn add_market_can_only_be_used_by_root() { new_test_ext().execute_with(|| { - assert_noop!( - Loans::add_market(Origin::signed(ALICE), DOT, MARKET_MOCK), - BadOrigin - ); + assert_noop!(Loans::add_market(Origin::signed(ALICE), DOT, MARKET_MOCK), BadOrigin); }) } @@ -210,18 +204,7 @@ fn update_market_has_sanity_checks_for_rate_models() { fn update_market_ensures_that_it_is_not_possible_to_modify_unknown_market_currencies() { new_test_ext().execute_with(|| { assert_noop!( - Loans::update_market( - Origin::root(), - SDOT, - None, - None, - None, - None, - None, - None, - None, - None, - ), + Loans::update_market(Origin::root(), SDOT, None, None, None, None, None, None, None, None,), Error::::MarketDoesNotExist ); }) @@ -230,10 +213,7 @@ fn update_market_ensures_that_it_is_not_possible_to_modify_unknown_market_curren #[test] fn update_market_works() { new_test_ext().execute_with(|| { - assert_eq!( - Loans::market(DOT).unwrap().close_factor, - Ratio::from_percent(50) - ); + assert_eq!(Loans::market(DOT).unwrap().close_factor, Ratio::from_percent(50)); let market = MARKET_MOCK; assert_ok!(Loans::update_market( @@ -257,10 +237,7 @@ fn update_market_works() { #[test] fn update_market_should_not_work_if_with_invalid_params() { new_test_ext().execute_with(|| { - assert_eq!( - Loans::market(DOT).unwrap().close_factor, - Ratio::from_percent(50) - ); + assert_eq!(Loans::market(DOT).unwrap().close_factor, Ratio::from_percent(50)); // check error code while collateral_factor is [0%, 100%) assert_ok!(Loans::update_market( @@ -349,11 +326,7 @@ fn update_rate_model_works() { Rate::saturating_from_rational(35, 100), Ratio::from_percent(80), ); - assert_ok!(Loans::update_rate_model( - Origin::root(), - DOT, - new_rate_model, - )); + assert_ok!(Loans::update_rate_model(Origin::root(), DOT, new_rate_model,)); assert_eq!(Loans::market(DOT).unwrap().rate_model, new_rate_model); // Invalid base_rate diff --git a/crates/loans/src/tests/ptokens.rs b/crates/loans/src/tests/ptokens.rs index 3260f6ae5c..49911ecd4c 100644 --- a/crates/loans/src/tests/ptokens.rs +++ b/crates/loans/src/tests/ptokens.rs @@ -1,7 +1,5 @@ use crate::{ - mock::{ - market_mock, new_test_ext, Loans, Origin, Test, ALICE, DAVE, - }, + mock::{market_mock, new_test_ext, Loans, Origin, Test, ALICE, DAVE}, tests::unit, Error, }; @@ -9,7 +7,10 @@ use frame_support::{ assert_err, assert_noop, assert_ok, traits::tokens::fungibles::{Inspect, Transfer}, }; -use primitives::{KINT, CKBTC, CKSM, CKINT, KSM as KSM_CURRENCY, CurrencyId::{self, Token, ForeignAsset}, KBTC}; +use primitives::{ + CurrencyId::{self, ForeignAsset, Token}, + CKBTC, CKINT, CKSM, KBTC, KINT, KSM as KSM_CURRENCY, +}; use sp_runtime::{FixedPointNumber, TokenError}; const HKO: CurrencyId = Token(KINT); @@ -19,15 +20,11 @@ const PKSM: CurrencyId = Token(CKSM); const PUSDT: CurrencyId = Token(CKBTC); const USDT: CurrencyId = Token(KBTC); - #[test] fn trait_inspect_methods_works() { new_test_ext().execute_with(|| { // No Deposits can't not withdraw - assert_err!( - Loans::can_withdraw(PHKO, &DAVE, 100).into_result(), - TokenError::NoFunds - ); + assert_err!(Loans::can_withdraw(PHKO, &DAVE, 100).into_result(), TokenError::NoFunds); assert_eq!(Loans::total_issuance(PHKO), 0); assert_eq!(Loans::total_issuance(PKSM), 0); @@ -46,18 +43,14 @@ fn trait_inspect_methods_works() { assert_ok!(Loans::borrow(Origin::signed(DAVE), HKO, unit(25))); assert_eq!( - Loans::exchange_rate(HKO) - .saturating_mul_int(Loans::account_deposits(HKO, DAVE).voucher_balance), + Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(HKO, DAVE).voucher_balance), unit(100) ); // DAVE Deposit 100 HKO, Borrow 25 HKO // Liquidity HKO 25 // Formula: ptokens = liquidity / price(1) / collateral(0.5) / exchange_rate(0.02) - assert_eq!( - Loans::reducible_balance(PHKO, &DAVE, true), - unit(25) * 2 * 50 - ); + assert_eq!(Loans::reducible_balance(PHKO, &DAVE, true), unit(25) * 2 * 50); // Multi-asset case, additional deposit USDT // DAVE Deposit 100 HKO, 50 USDT, Borrow 25 HKO @@ -65,16 +58,10 @@ fn trait_inspect_methods_works() { // ptokens = dollar(25 + 25) / 1 / 0.5 / 0.02 = dollar(50) * 100 assert_ok!(Loans::mint(Origin::signed(DAVE), USDT, unit(50))); assert_eq!(Loans::balance(PUSDT, &DAVE), unit(50) * 50); - assert_eq!( - Loans::reducible_balance(PUSDT, &DAVE, true), - unit(25) * 2 * 50 - ); + assert_eq!(Loans::reducible_balance(PUSDT, &DAVE, true), unit(25) * 2 * 50); // enable USDT collateral assert_ok!(Loans::collateral_asset(Origin::signed(DAVE), USDT, true)); - assert_eq!( - Loans::reducible_balance(PHKO, &DAVE, true), - unit(25 + 25) * 2 * 50 - ); + assert_eq!(Loans::reducible_balance(PHKO, &DAVE, true), unit(25 + 25) * 2 * 50); assert_ok!(Loans::borrow(Origin::signed(DAVE), HKO, unit(50))); assert_eq!(Loans::reducible_balance(PHKO, &DAVE, true), 0); @@ -111,15 +98,13 @@ fn transfer_ptoken_works() { // DAVE HKO collateral: deposit = 100 // HKO: cash - deposit = 1000 - 100 = 900 assert_eq!( - Loans::exchange_rate(HKO) - .saturating_mul_int(Loans::account_deposits(HKO, DAVE).voucher_balance), + Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(HKO, DAVE).voucher_balance), unit(100) ); // ALICE HKO collateral: deposit = 0 assert_eq!( - Loans::exchange_rate(HKO) - .saturating_mul_int(Loans::account_deposits(HKO, ALICE).voucher_balance), + Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(HKO, ALICE).voucher_balance), unit(0) ); @@ -129,8 +114,7 @@ fn transfer_ptoken_works() { // DAVE HKO collateral: deposit = 50 assert_eq!( - Loans::exchange_rate(HKO) - .saturating_mul_int(Loans::account_deposits(HKO, DAVE).voucher_balance), + Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(HKO, DAVE).voucher_balance), unit(50) ); // DAVE Redeem 51 HKO should cause InsufficientDeposit @@ -141,8 +125,7 @@ fn transfer_ptoken_works() { // ALICE HKO collateral: deposit = 50 assert_eq!( - Loans::exchange_rate(HKO) - .saturating_mul_int(Loans::account_deposits(HKO, ALICE).voucher_balance), + Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(HKO, ALICE).voucher_balance), unit(50) ); // ALICE Redeem 50 HKO should be succeeded @@ -169,8 +152,7 @@ fn transfer_ptokens_under_collateral_works() { // DAVE Borrow HKO = 0 + 50 - 40 = 10 // DAVE liquidity HKO = 80 * 0.5 - 10 = 30 assert_eq!( - Loans::exchange_rate(HKO) - .saturating_mul_int(Loans::account_deposits(HKO, DAVE).voucher_balance), + Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(HKO, DAVE).voucher_balance), unit(80) ); // DAVE Borrow 31 HKO should cause InsufficientLiquidity @@ -182,8 +164,7 @@ fn transfer_ptokens_under_collateral_works() { // Assert ALICE Supply HKO 20 assert_eq!( - Loans::exchange_rate(HKO) - .saturating_mul_int(Loans::account_deposits(HKO, ALICE).voucher_balance), + Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(HKO, ALICE).voucher_balance), unit(20) ); // ALICE Redeem 20 HKO should be succeeded diff --git a/crates/traits/src/lib.rs b/crates/traits/src/lib.rs index b3ed9828a2..007c0c6e59 100644 --- a/crates/traits/src/lib.rs +++ b/crates/traits/src/lib.rs @@ -7,9 +7,7 @@ use scale_info::TypeInfo; use sp_runtime::{traits::Zero, RuntimeDebug}; use sp_std::prelude::*; -use primitives::{ - CurrencyId, PriceDetail, Rate, Timestamp, -}; +use primitives::{CurrencyId, PriceDetail, Rate, Timestamp}; pub mod loans; pub use loans::*; @@ -61,19 +59,7 @@ pub trait LPVaultTokenCurrenciesFilter { fn contains(lp_asset_id: &CurrencyId) -> bool; } -#[derive( - Encode, - Decode, - Eq, - PartialEq, - Copy, - Clone, - RuntimeDebug, - PartialOrd, - Ord, - TypeInfo, - MaxEncodedLen, -)] +#[derive(Encode, Decode, Eq, PartialEq, Copy, Clone, RuntimeDebug, PartialOrd, Ord, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub struct Pool { pub base_amount: Balance, @@ -111,28 +97,18 @@ pub trait AMM { /// Based on the path specified and the available pool balances /// this will return the amounts outs when trading the specified /// amount in - fn get_amounts_out( - amount_in: Balance, - path: Vec, - ) -> Result, DispatchError>; + fn get_amounts_out(amount_in: Balance, path: Vec) -> Result, DispatchError>; /// Based on the path specified and the available pool balances /// this will return the amounts in needed to produce the specified /// amount out - fn get_amounts_in( - amount_out: Balance, - path: Vec, - ) -> Result, DispatchError>; + fn get_amounts_in(amount_out: Balance, path: Vec) -> Result, DispatchError>; /// Handles a "swap" on the AMM side for "who". /// This will move the `amount_in` funds to the AMM PalletId, /// trade `pair.0` to `pair.1` and return a result with the amount /// of currency that was sent back to the user. - fn swap( - who: &AccountId, - pair: (CurrencyId, CurrencyId), - amount_in: Balance, - ) -> Result<(), DispatchError>; + fn swap(who: &AccountId, pair: (CurrencyId, CurrencyId), amount_in: Balance) -> Result<(), DispatchError>; /// Iterate keys of asset pair in AMM Pools fn get_pools() -> Result, DispatchError>; @@ -140,16 +116,10 @@ pub trait AMM { /// Returns pool by lp_asset fn get_pool_by_lp_asset( asset_id: CurrencyId, - ) -> Option<( - CurrencyId, - CurrencyId, - Pool, - )>; + ) -> Option<(CurrencyId, CurrencyId, Pool)>; /// Returns pool by asset pair - fn get_pool_by_asset_pair( - pair: (CurrencyId, CurrencyId), - ) -> Option>; + fn get_pool_by_asset_pair(pair: (CurrencyId, CurrencyId)) -> Option>; } /// Exported traits from StableSwap pallet. These functions are to be used @@ -158,35 +128,22 @@ pub trait StableSwap { /// Based on the path specified and the available pool balances /// this will return the amounts outs when trading the specified /// amount in - fn get_amounts_out( - amount_in: Balance, - path: Vec, - ) -> Result, DispatchError>; + fn get_amounts_out(amount_in: Balance, path: Vec) -> Result, DispatchError>; /// Based on the path specified and the available pool balances /// this will return the amounts in needed to produce the specified /// amount out - fn get_amounts_in( - amount_out: Balance, - path: Vec, - ) -> Result, DispatchError>; + fn get_amounts_in(amount_out: Balance, path: Vec) -> Result, DispatchError>; /// Handles a "swap" on the AMM side for "who". /// This will move the `amount_in` funds to the AMM PalletId, /// trade `pair.0` to `pair.1` and return a result with the amount /// of currency that was sent back to the user. - fn swap( - who: &AccountId, - pair: (CurrencyId, CurrencyId), - amount_in: Balance, - ) -> Result<(), DispatchError>; + fn swap(who: &AccountId, pair: (CurrencyId, CurrencyId), amount_in: Balance) -> Result<(), DispatchError>; fn get_pools() -> Result, DispatchError>; - fn get_reserves( - asset_in: CurrencyId, - asset_out: CurrencyId, - ) -> Result<(Balance, Balance), DispatchError>; + fn get_reserves(asset_in: CurrencyId, asset_out: CurrencyId) -> Result<(Balance, Balance), DispatchError>; } pub trait ConvertToBigUint { diff --git a/crates/traits/src/loans.rs b/crates/traits/src/loans.rs index 5002009740..9a6d7c5653 100644 --- a/crates/traits/src/loans.rs +++ b/crates/traits/src/loans.rs @@ -20,43 +20,17 @@ use sp_runtime::{FixedU128, RuntimeDebug}; use sp_std::prelude::*; pub trait Loans { - fn do_mint( - supplier: &AccountId, - asset_id: CurrencyId, - amount: Balance, - ) -> Result<(), DispatchError>; - fn do_borrow( - borrower: &AccountId, - asset_id: CurrencyId, - amount: Balance, - ) -> Result<(), DispatchError>; - fn do_collateral_asset( - supplier: &AccountId, - asset_id: CurrencyId, - enable: bool, - ) -> Result<(), DispatchError>; - fn do_repay_borrow( - borrower: &AccountId, - asset_id: CurrencyId, - amount: Balance, - ) -> Result<(), DispatchError>; - fn do_redeem( - supplier: &AccountId, - asset_id: CurrencyId, - amount: Balance, - ) -> Result<(), DispatchError>; + fn do_mint(supplier: &AccountId, asset_id: CurrencyId, amount: Balance) -> Result<(), DispatchError>; + fn do_borrow(borrower: &AccountId, asset_id: CurrencyId, amount: Balance) -> Result<(), DispatchError>; + fn do_collateral_asset(supplier: &AccountId, asset_id: CurrencyId, enable: bool) -> Result<(), DispatchError>; + fn do_repay_borrow(borrower: &AccountId, asset_id: CurrencyId, amount: Balance) -> Result<(), DispatchError>; + fn do_redeem(supplier: &AccountId, asset_id: CurrencyId, amount: Balance) -> Result<(), DispatchError>; } pub trait LoansPositionDataProvider { - fn get_current_borrow_balance( - borrower: &AccountId, - asset_id: CurrencyId, - ) -> Result; + fn get_current_borrow_balance(borrower: &AccountId, asset_id: CurrencyId) -> Result; - fn get_current_collateral_balance( - supplier: &AccountId, - asset_id: CurrencyId, - ) -> Result; + fn get_current_collateral_balance(supplier: &AccountId, asset_id: CurrencyId) -> Result; } pub trait LoansMarketDataProvider { diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index f6f51dcef8..07b74c7bed 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -11,7 +11,7 @@ pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; use sp_runtime::{ generic, traits::{BlakeTwo256, IdentifyAccount, Verify}, - FixedI128, FixedPointNumber, FixedU128, MultiSignature, RuntimeDebug, Permill, + FixedI128, FixedPointNumber, FixedU128, MultiSignature, Permill, RuntimeDebug, }; use sp_std::{ convert::{TryFrom, TryInto}, @@ -358,7 +358,6 @@ pub type UnsignedFixedPoint = FixedU128; /// The `Inner` type of the `UnsignedFixedPoint`. pub type UnsignedInner = u128; - /// Loans pallet types pub type Price = FixedU128; @@ -370,8 +369,6 @@ pub type Shortfall = FixedU128; pub type Liquidity = FixedU128; pub const SECONDS_PER_YEAR: Timestamp = 365 * 24 * 60 * 60; - - pub trait CurrencyInfo { fn name(&self) -> &str; fn symbol(&self) -> &str; diff --git a/standalone/runtime/src/lib.rs b/standalone/runtime/src/lib.rs index d9ffeed2d3..09ecf380c3 100644 --- a/standalone/runtime/src/lib.rs +++ b/standalone/runtime/src/lib.rs @@ -64,8 +64,10 @@ pub use module_oracle_rpc_runtime_api::BalanceWrapper; pub use security::StatusCode; pub use primitives::{ - self, AccountId, Balance, BlockNumber, CurrencyId, CurrencyId::{Token, ForeignAsset}, CurrencyInfo, Hash, Moment, Nonce, Signature, - SignedFixedPoint, SignedInner, TokenSymbol, UnsignedFixedPoint, UnsignedInner, DOT, IBTC, INTR, KBTC, KINT, KSM, PriceDetail + self, AccountId, Balance, BlockNumber, CurrencyId, + CurrencyId::{ForeignAsset, Token}, + CurrencyInfo, Hash, Moment, Nonce, PriceDetail, Signature, SignedFixedPoint, SignedInner, TokenSymbol, + UnsignedFixedPoint, UnsignedInner, DOT, IBTC, INTR, KBTC, KINT, KSM, }; type VaultId = primitives::VaultId; diff --git a/standalone/runtime/tests/test_loans.rs b/standalone/runtime/tests/test_loans.rs index 063e706719..c261b8accf 100644 --- a/standalone/runtime/tests/test_loans.rs +++ b/standalone/runtime/tests/test_loans.rs @@ -8,7 +8,6 @@ use sp_runtime::traits::CheckedMul; pub const USER: [u8; 32] = ALICE; pub const LP: [u8; 32] = BOB; - pub const fn market_mock(ptoken_id: CurrencyId) -> Market { Market { close_factor: Ratio::from_percent(50), @@ -41,9 +40,7 @@ fn set_up_market(currency_id: CurrencyId, exchange_rate: FixedU128, ctoken_id: C .dispatch(origin_of(account_of(ALICE)))); assert_ok!(Call::Sudo(SudoCall::sudo { - call: Box::new(Call::Loans(LoansCall::activate_market { - asset_id: currency_id, - })), + call: Box::new(Call::Loans(LoansCall::activate_market { asset_id: currency_id })), }) .dispatch(origin_of(account_of(ALICE)))); } @@ -51,8 +48,16 @@ fn set_up_market(currency_id: CurrencyId, exchange_rate: FixedU128, ctoken_id: C fn test_real_market(execute: impl Fn() -> R) { ExtBuilder::build().execute_with(|| { // Use real market data for the exchange rates - set_up_market(Token(KINT), FixedU128::from_inner(115_942_028_985_507_246_376_810_000), Token(CKINT)); - set_up_market(Token(KSM), FixedU128::from_inner(4_573_498_406_135_805_461_670_000), Token(CKSM)); + set_up_market( + Token(KINT), + FixedU128::from_inner(115_942_028_985_507_246_376_810_000), + Token(CKINT), + ); + set_up_market( + Token(KSM), + FixedU128::from_inner(4_573_498_406_135_805_461_670_000), + Token(CKSM), + ); execute() }); } @@ -63,41 +68,38 @@ fn integration_test_issue_expiry_only_parachain_blocks_expired() { let kint = Token(KINT); let ksm = Token(KSM); - assert_ok!( - Call::Loans(LoansCall::mint { - asset_id: kint, - mint_amount: 1000, - }).dispatch(origin_of(account_of(USER))) - ); + assert_ok!(Call::Loans(LoansCall::mint { + asset_id: kint, + mint_amount: 1000, + }) + .dispatch(origin_of(account_of(USER)))); - assert_ok!( - Call::Loans(LoansCall::mint { - asset_id: ksm, - mint_amount: 50, - }).dispatch(origin_of(account_of(LP))) - ); + assert_ok!(Call::Loans(LoansCall::mint { + asset_id: ksm, + mint_amount: 50, + }) + .dispatch(origin_of(account_of(LP)))); - assert_ok!( - Call::Loans(LoansCall::collateral_asset { - asset_id: kint, - enable: true, - }).dispatch(origin_of(account_of(USER))) - ); + assert_ok!(Call::Loans(LoansCall::collateral_asset { + asset_id: kint, + enable: true, + }) + .dispatch(origin_of(account_of(USER)))); assert_err!( Call::Loans(LoansCall::borrow { asset_id: ksm, borrow_amount: 20, - }).dispatch(origin_of(account_of(USER))), + }) + .dispatch(origin_of(account_of(USER))), LoansError::InsufficientLiquidity ); - assert_ok!( - Call::Loans(LoansCall::borrow { - asset_id: ksm, - borrow_amount: 15, - }).dispatch(origin_of(account_of(USER))) - ); + assert_ok!(Call::Loans(LoansCall::borrow { + asset_id: ksm, + borrow_amount: 15, + }) + .dispatch(origin_of(account_of(USER)))); assert_err!( Call::Loans(LoansCall::liquidate_borrow { @@ -105,23 +107,24 @@ fn integration_test_issue_expiry_only_parachain_blocks_expired() { liquidation_asset_id: ksm, repay_amount: 15, collateral_asset_id: kint - }).dispatch(origin_of(account_of(LP))), + }) + .dispatch(origin_of(account_of(LP))), LoansError::InsufficientShortfall ); // KINT price drops to half let kint_rate = OraclePallet::get_price(OracleKey::ExchangeRate(kint)).unwrap(); - assert_ok!(OraclePallet::_set_exchange_rate(kint, kint_rate.checked_mul(&2.into()).unwrap())); - - assert_ok!( - Call::Loans(LoansCall::liquidate_borrow { - borrower: account_of(USER), - liquidation_asset_id: ksm, - repay_amount: 7, - collateral_asset_id: kint - }).dispatch(origin_of(account_of(LP))) - ); - + assert_ok!(OraclePallet::_set_exchange_rate( + kint, + kint_rate.checked_mul(&2.into()).unwrap() + )); + + assert_ok!(Call::Loans(LoansCall::liquidate_borrow { + borrower: account_of(USER), + liquidation_asset_id: ksm, + repay_amount: 7, + collateral_asset_id: kint + }) + .dispatch(origin_of(account_of(LP)))); }); - -} \ No newline at end of file +} From 50fd3a7921dea6e7b071afbe9dc6828511f009ba Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Mon, 10 Oct 2022 20:09:00 +0200 Subject: [PATCH 15/58] fix(lend): cleanup --- crates/loans/src/lib.rs | 4 +- crates/loans/src/tests.rs | 69 +--------------------- crates/loans/src/tests/edge_cases.rs | 2 +- crates/loans/src/tests/liquidate_borrow.rs | 46 +-------------- standalone/runtime/tests/test_loans.rs | 2 +- 5 files changed, 7 insertions(+), 116 deletions(-) diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 5d961e1011..41171210ea 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -1130,7 +1130,6 @@ impl Pallet { supplier: &T::AccountId, asset_id: AssetIdOf, ) -> Result, DispatchError> { - // if account_data.free.is_zero() { return Ok(BalanceOf::::zero()); } if !AccountDeposits::::contains_key(asset_id, supplier) { return Ok(BalanceOf::::zero()); } @@ -1394,9 +1393,8 @@ impl Pallet { let account_borrows = Self::current_borrow_balance(borrower, liquidation_asset_id)?; let account_borrows_value = Self::get_asset_value(liquidation_asset_id, account_borrows)?; let repay_value = Self::get_asset_value(liquidation_asset_id, repay_amount)?; - let effects_borrows_value = account_borrows_value; - if market.close_factor.mul_ceil(effects_borrows_value.into_inner()) < repay_value.into_inner() { + if market.close_factor.mul_ceil(account_borrows_value.into_inner()) < repay_value.into_inner() { return Err(Error::::TooMuchRepay.into()); } diff --git a/crates/loans/src/tests.rs b/crates/loans/src/tests.rs index 0419a8c870..adaac3dace 100644 --- a/crates/loans/src/tests.rs +++ b/crates/loans/src/tests.rs @@ -197,41 +197,6 @@ fn redeem_allowed_works() { }) } -// ignore: tests liquidation-free collateral -#[ignore] -#[test] -fn lf_redeem_allowed_works() { - new_test_ext().execute_with(|| { - // Set CDOT as lf collateral - Loans::mint(Origin::signed(ALICE), CDOT_6_13, unit(200)).unwrap(); - - Loans::mint(Origin::signed(DAVE), USDT, unit(200)).unwrap(); - Loans::mint(Origin::signed(DAVE), DOT, unit(200)).unwrap(); - // Lend $200 CDOT - Loans::collateral_asset(Origin::signed(ALICE), CDOT_6_13, true).unwrap(); - - Loans::borrow(Origin::signed(ALICE), DOT, unit(50)).unwrap(); - - // (200 - 100) * 50% >= 50 - assert_ok!(Loans::redeem_allowed(CDOT_6_13, &ALICE, unit(100))); - - // Set KSM as collateral, and borrow USDT - Loans::mint(Origin::signed(ALICE), KSM, unit(200)).unwrap(); - Loans::collateral_asset(Origin::signed(ALICE), KSM, true).unwrap(); - Loans::borrow(Origin::signed(ALICE), USDT, unit(100)).unwrap(); - - assert_err!( - Loans::redeem_allowed(KSM, &ALICE, unit(100)), - Error::::InsufficientLiquidity - ); - // But it'll success when redeem cdot - assert_ok!(Loans::redeem_allowed(CDOT_6_13, &ALICE, unit(100))); - - // Then it can be redeemed - assert_ok!(Loans::redeem_allowed(KSM, &ALICE, unit(100))); - }) -} - #[test] fn redeem_works() { new_test_ext().execute_with(|| { @@ -375,10 +340,9 @@ fn get_account_liquidity_works() { Loans::mint(Origin::signed(ALICE), CDOT_6_13, unit(200)).unwrap(); Loans::collateral_asset(Origin::signed(ALICE), CDOT_6_13, true).unwrap(); - let (liquidity, _, lf_liquidity, _) = Loans::get_account_liquidity(&ALICE).unwrap(); + let (liquidity, _, _, _) = Loans::get_account_liquidity(&ALICE).unwrap(); assert_eq!(liquidity, FixedU128::from_inner(unit(100))); - assert_eq!(lf_liquidity, FixedU128::from_inner(unit(0))); }) } @@ -397,42 +361,15 @@ fn get_account_liquidation_threshold_liquidity_works() { Loans::borrow(Origin::signed(ALICE), KSM, unit(100)).unwrap(); Loans::borrow(Origin::signed(ALICE), DOT, unit(100)).unwrap(); - let (liquidity, _, lf_liquidity, _) = Loans::get_account_liquidation_threshold_liquidity(&ALICE).unwrap(); + let (liquidity, _, _, _) = Loans::get_account_liquidation_threshold_liquidity(&ALICE).unwrap(); assert_eq!(liquidity, FixedU128::from_inner(unit(20))); - assert_eq!(lf_liquidity, FixedU128::from_inner(unit(0))); MockPriceFeeder::set_price(KSM, 2.into()); - let (liquidity, shortfall, lf_liquidity, _) = - Loans::get_account_liquidation_threshold_liquidity(&ALICE).unwrap(); + let (liquidity, shortfall, _, _) = Loans::get_account_liquidation_threshold_liquidity(&ALICE).unwrap(); assert_eq!(liquidity, FixedU128::from_inner(unit(0))); assert_eq!(shortfall, FixedU128::from_inner(unit(80))); - assert_eq!(lf_liquidity, FixedU128::from_inner(unit(0))); - }) -} - -// ignore: tests liquidation-free collateral -#[ignore] -#[test] -fn lf_borrow_allowed_works() { - new_test_ext().execute_with(|| { - Loans::mint(Origin::signed(ALICE), CDOT_6_13, unit(200)).unwrap(); - Loans::mint(Origin::signed(DAVE), USDT, unit(200)).unwrap(); - Loans::mint(Origin::signed(DAVE), DOT, unit(200)).unwrap(); - // Lend $200 CDOT - Loans::collateral_asset(Origin::signed(ALICE), CDOT_6_13, true).unwrap(); - - assert_eq!( - Loans::get_asset_value(DOT, unit(100)).unwrap(), - Loans::get_asset_value(USDT, unit(100)).unwrap() - ); - - assert_noop!( - Loans::borrow_allowed(USDT, &ALICE, unit(100)), - Error::::InsufficientLiquidity - ); - assert_ok!(Loans::borrow_allowed(DOT, &ALICE, unit(100))); }) } diff --git a/crates/loans/src/tests/edge_cases.rs b/crates/loans/src/tests/edge_cases.rs index d467ec6b02..df410e229b 100644 --- a/crates/loans/src/tests/edge_cases.rs +++ b/crates/loans/src/tests/edge_cases.rs @@ -3,7 +3,7 @@ use crate::{mock::*, tests::Loans, Error}; use frame_support::{assert_err, assert_ok}; use primitives::{ CurrencyId::{ForeignAsset, Token}, - DOT, IBTC, KSM, + DOT, KSM, }; use sp_runtime::FixedPointNumber; diff --git a/crates/loans/src/tests/liquidate_borrow.rs b/crates/loans/src/tests/liquidate_borrow.rs index 515fe8cdd2..6abe1157a2 100644 --- a/crates/loans/src/tests/liquidate_borrow.rs +++ b/crates/loans/src/tests/liquidate_borrow.rs @@ -6,14 +6,13 @@ use crate::{ use frame_support::{assert_err, assert_noop, assert_ok, traits::fungibles::Inspect}; use primitives::{ CurrencyId::{self, Token}, - Rate, DOT as DOT_CURRENCY, IBTC as IBTC_CURRENCY, KBTC as KBTC_CURRENCY, KSM as KSM_CURRENCY, + Rate, DOT as DOT_CURRENCY, KBTC as KBTC_CURRENCY, KSM as KSM_CURRENCY, }; use sp_runtime::FixedPointNumber; const DOT: CurrencyId = Token(DOT_CURRENCY); const KSM: CurrencyId = Token(KSM_CURRENCY); const USDT: CurrencyId = Token(KBTC_CURRENCY); -const CDOT_6_13: CurrencyId = Token(IBTC_CURRENCY); #[test] fn liquidate_borrow_allowed_works() { @@ -41,49 +40,6 @@ fn liquidate_borrow_allowed_works() { }) } -// ignore: tests liquidation-free collateral -#[ignore] -#[test] -fn lf_liquidate_borrow_allowed_works() { - new_test_ext().execute_with(|| { - // Loans::update_liquidation_free_collateral(Origin::root(), vec![CDOT_6_13]).unwrap(); - // Bob deposits $200 DOT - Loans::mint(Origin::signed(BOB), DOT, unit(200)).unwrap(); - Loans::mint(Origin::signed(ALICE), USDT, unit(200)).unwrap(); - Loans::mint(Origin::signed(ALICE), CDOT_6_13, unit(200)).unwrap(); - Loans::collateral_asset(Origin::signed(ALICE), USDT, true).unwrap(); - Loans::collateral_asset(Origin::signed(ALICE), CDOT_6_13, true).unwrap(); - - // ALICE - // Collateral Borrowed - // USDT $100 DOT $200 - // CDOT $100 - Loans::borrow(Origin::signed(ALICE), DOT, unit(200)).unwrap(); - - // CDOT's price is highly relative to DOT's price in real runtime. Thus we must update them - // at the same time. - MockPriceFeeder::set_price(DOT, 2.into()); - MockPriceFeeder::set_price(CDOT_6_13, 2.into()); - // ALICE - // Collateral Borrowed - // USDT $100 DOT $400 - // CDOT $200 - - let dot_market = Loans::market(DOT).unwrap(); - // The max repay amount = (400 - 200) * 50% = $100 - assert_err!( - Loans::liquidate_borrow_allowed(&ALICE, DOT, unit(51), &dot_market), - Error::::TooMuchRepay - ); - assert_ok!(Loans::liquidate_borrow_allowed(&ALICE, DOT, unit(50), &dot_market)); - - // Remove CDOT from lf collateral - // Loans::update_liquidation_free_collateral(Origin::root(), vec![]).unwrap(); - // The max repay amount = 400 * 50 = $200 - assert_ok!(Loans::liquidate_borrow_allowed(&ALICE, DOT, unit(100), &dot_market)); - }) -} - #[test] fn deposit_of_borrower_must_be_collateral() { new_test_ext().execute_with(|| { diff --git a/standalone/runtime/tests/test_loans.rs b/standalone/runtime/tests/test_loans.rs index c261b8accf..0fcf95edf3 100644 --- a/standalone/runtime/tests/test_loans.rs +++ b/standalone/runtime/tests/test_loans.rs @@ -63,7 +63,7 @@ fn test_real_market(execute: impl Fn() -> R) { } #[test] -fn integration_test_issue_expiry_only_parachain_blocks_expired() { +fn integration_test_liquidation() { test_real_market(|| { let kint = Token(KINT); let ksm = Token(KSM); From bca36ff99d8cf44f66f9255e2ab9ab138a8191c4 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Tue, 11 Oct 2022 15:43:57 +0200 Subject: [PATCH 16/58] feat(loans): import orml pallet with hooks feature --- Cargo.lock | 9 ---- crates/currency/Cargo.toml | 4 +- crates/fee/Cargo.toml | 4 +- crates/issue/Cargo.toml | 8 ++-- crates/loans/Cargo.toml | 6 +-- crates/loans/src/lib.rs | 44 ++++++++++++++++++- crates/loans/src/mock.rs | 3 ++ crates/nomination/Cargo.toml | 8 ++-- crates/oracle/Cargo.toml | 4 +- crates/redeem/Cargo.toml | 8 ++-- crates/replace/Cargo.toml | 8 ++-- crates/staking/Cargo.toml | 4 +- crates/vault-registry/Cargo.toml | 4 +- parachain/runtime/interlay/Cargo.toml | 16 +++---- parachain/runtime/interlay/src/lib.rs | 3 ++ parachain/runtime/kintsugi/Cargo.toml | 16 +++---- parachain/runtime/kintsugi/src/lib.rs | 3 ++ parachain/runtime/runtime-tests/Cargo.toml | 12 ++--- parachain/runtime/testnet-interlay/Cargo.toml | 16 +++---- parachain/runtime/testnet-interlay/src/lib.rs | 3 ++ parachain/runtime/testnet-kintsugi/Cargo.toml | 16 +++---- parachain/runtime/testnet-kintsugi/src/lib.rs | 3 ++ primitives/src/lib.rs | 12 +++++ standalone/runtime/Cargo.toml | 8 ++-- standalone/runtime/src/lib.rs | 3 ++ 25 files changed, 143 insertions(+), 82 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 57a35fe0fd..d57cd2be1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5922,7 +5922,6 @@ dependencies = [ [[package]] name = "orml-asset-registry" version = "0.4.1-dev" -source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=8c625a5ab43c1c56cdeed5f8d814a891566d4cf8#8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" dependencies = [ "frame-support", "frame-system", @@ -5941,7 +5940,6 @@ dependencies = [ [[package]] name = "orml-oracle" version = "0.4.1-dev" -source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=8c625a5ab43c1c56cdeed5f8d814a891566d4cf8#8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" dependencies = [ "frame-support", "frame-system", @@ -5959,7 +5957,6 @@ dependencies = [ [[package]] name = "orml-tokens" version = "0.4.1-dev" -source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=8c625a5ab43c1c56cdeed5f8d814a891566d4cf8#8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" dependencies = [ "frame-support", "frame-system", @@ -5974,7 +5971,6 @@ dependencies = [ [[package]] name = "orml-traits" version = "0.4.1-dev" -source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=8c625a5ab43c1c56cdeed5f8d814a891566d4cf8#8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" dependencies = [ "frame-support", "impl-trait-for-tuples", @@ -5992,7 +5988,6 @@ dependencies = [ [[package]] name = "orml-unknown-tokens" version = "0.4.1-dev" -source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=8c625a5ab43c1c56cdeed5f8d814a891566d4cf8#8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" dependencies = [ "frame-support", "frame-system", @@ -6007,7 +6002,6 @@ dependencies = [ [[package]] name = "orml-utilities" version = "0.4.1-dev" -source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=8c625a5ab43c1c56cdeed5f8d814a891566d4cf8#8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" dependencies = [ "frame-support", "parity-scale-codec", @@ -6021,7 +6015,6 @@ dependencies = [ [[package]] name = "orml-vesting" version = "0.4.1-dev" -source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=8c625a5ab43c1c56cdeed5f8d814a891566d4cf8#8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" dependencies = [ "frame-support", "frame-system", @@ -6050,7 +6043,6 @@ dependencies = [ [[package]] name = "orml-xcm-support" version = "0.4.1-dev" -source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=8c625a5ab43c1c56cdeed5f8d814a891566d4cf8#8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" dependencies = [ "frame-support", "orml-traits", @@ -6064,7 +6056,6 @@ dependencies = [ [[package]] name = "orml-xtokens" version = "0.4.1-dev" -source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=8c625a5ab43c1c56cdeed5f8d814a891566d4cf8#8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" dependencies = [ "cumulus-primitives-core", "frame-support", diff --git a/crates/currency/Cargo.toml b/crates/currency/Cargo.toml index 4bcf2f2a05..f53a1c09d2 100644 --- a/crates/currency/Cargo.toml +++ b/crates/currency/Cargo.toml @@ -21,8 +21,8 @@ pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } +orml-tokens = { path = "../../../open-runtime-module-library/tokens",default-features = false } +orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false } # for other pallets wanting to mock functions mocktopus = {version = "0.7.0", optional = true } diff --git a/crates/fee/Cargo.toml b/crates/fee/Cargo.toml index 7f98483355..306249b23f 100644 --- a/crates/fee/Cargo.toml +++ b/crates/fee/Cargo.toml @@ -35,8 +35,8 @@ pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = " currency = { path = "../currency", features = ["testing-utils"] } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } +orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false } +orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false } # Parachain dependencies primitives = { package = "interbtc-primitives", path = "../../primitives"} diff --git a/crates/issue/Cargo.toml b/crates/issue/Cargo.toml index 80952a513f..e092e9b893 100644 --- a/crates/issue/Cargo.toml +++ b/crates/issue/Cargo.toml @@ -35,8 +35,8 @@ vault-registry = { path = "../vault-registry", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false, optional = true } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false, optional = true } +orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false, optional = true } +orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false, optional = true } [dev-dependencies] mocktopus = "0.7.0" @@ -47,8 +47,8 @@ reward = { path = "../reward" } staking = { path = "../staking" } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" } +orml-tokens = { path = "../../../open-runtime-module-library/tokens" } +orml-traits = { path = "../../../open-runtime-module-library/traits" } [features] default = ["std"] diff --git a/crates/loans/Cargo.toml b/crates/loans/Cargo.toml index ce61bca382..c4cc59f8c5 100644 --- a/crates/loans/Cargo.toml +++ b/crates/loans/Cargo.toml @@ -13,9 +13,9 @@ frame-benchmarking = { git = 'https://github.com/paritytech/substrate.git', bran frame-support = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } frame-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } num-traits = { default-features = false, version = '0.2' } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-oracle = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } +orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false } +orml-oracle = { path = "../../../open-runtime-module-library/oracle", default-features = false } +orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false } pallet-timestamp = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } pallet-traits = { path = '../traits', default-features = false } primitives = { package = 'interbtc-primitives', path = '../../primitives', default-features = false } diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 41171210ea..7450d9702a 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -44,7 +44,7 @@ use pallet_traits::{ ConvertToBigUint, Loans as LoansTrait, LoansMarketDataProvider, LoansPositionDataProvider, MarketInfo, MarketStatus, PriceFeeder, }; -use primitives::{Balance, CurrencyId, Liquidity, Price, Rate, Ratio, Shortfall, Timestamp}; +use primitives::{is_ctoken, Balance, CurrencyId, Liquidity, Price, Rate, Ratio, Shortfall, Timestamp}; use sp_runtime::{ traits::{ AccountIdConversion, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, One, SaturatedConversion, Saturating, @@ -52,8 +52,9 @@ use sp_runtime::{ }, ArithmeticError, FixedPointNumber, FixedU128, }; -use sp_std::result::Result; +use sp_std::{marker, result::Result}; +pub use orml_traits::currency::{OnDeposit, OnSlash, OnTransfer}; use sp_io::hashing::blake2_256; pub use types::{BorrowSnapshot, Deposits, EarnedSnapshot, Market, MarketState, RewardMarketState}; pub use weights::WeightInfo; @@ -83,6 +84,45 @@ type AccountIdOf = ::AccountId; type AssetIdOf = <::Assets as Inspect<::AccountId>>::AssetId; type BalanceOf = <::Assets as Inspect<::AccountId>>::Balance; +pub struct OnSlashHook(marker::PhantomData); +impl OnSlash, BalanceOf> for OnSlashHook { + fn on_slash(currency_id: AssetIdOf, account_id: &T::AccountId, _: BalanceOf) -> DispatchResult { + if is_ctoken(currency_id) { + Pallet::::update_reward_supply_index(currency_id)?; + Pallet::::distribute_supplier_reward(currency_id, account_id)?; + } + Ok(()) + } +} + +pub struct OnDepositHook(marker::PhantomData); +impl OnDeposit, BalanceOf> for OnDepositHook { + fn on_deposit(currency_id: AssetIdOf, account_id: &T::AccountId, _: BalanceOf) -> DispatchResult { + if is_ctoken(currency_id) { + Pallet::::update_reward_supply_index(currency_id)?; + Pallet::::distribute_supplier_reward(currency_id, account_id)?; + } + Ok(()) + } +} + +pub struct OnTransferHook(marker::PhantomData); +impl OnTransfer, BalanceOf> for OnTransferHook { + fn on_transfer( + currency_id: AssetIdOf, + from: &T::AccountId, + to: &T::AccountId, + _: BalanceOf, + ) -> DispatchResult { + if is_ctoken(currency_id) { + Pallet::::update_reward_supply_index(currency_id)?; + Pallet::::distribute_supplier_reward(currency_id, from)?; + Pallet::::distribute_supplier_reward(currency_id, to)?; + } + Ok(()) + } +} + /// Utility type for managing upgrades/migrations. #[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)] pub enum Versions { diff --git a/crates/loans/src/mock.rs b/crates/loans/src/mock.rs index 625572c6e0..9288225f60 100644 --- a/crates/loans/src/mock.rs +++ b/crates/loans/src/mock.rs @@ -119,6 +119,9 @@ impl orml_tokens::Config for Test { type WeightInfo = (); type ExistentialDeposits = ExistentialDeposits; type OnDust = (); + type OnSlash = OnSlashHook; + type OnDeposit = OnDepositHook; + type OnTransfer = OnTransferHook; type MaxLocks = MaxLocks; type DustRemovalWhitelist = Everything; type MaxReserves = ConstU32<0>; // we don't use named reserves diff --git a/crates/nomination/Cargo.toml b/crates/nomination/Cargo.toml index 9bb71e20e5..77a50f8beb 100644 --- a/crates/nomination/Cargo.toml +++ b/crates/nomination/Cargo.toml @@ -33,16 +33,16 @@ staking = { path = "../staking", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false, optional = true } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false, optional = true } +orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false, optional = true } +orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false, optional = true } [dev-dependencies] mocktopus = "0.7.0" frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.26", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } +orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false } +orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false } [features] default = ["std"] diff --git a/crates/oracle/Cargo.toml b/crates/oracle/Cargo.toml index ef6b1c0e16..2550f3806e 100644 --- a/crates/oracle/Cargo.toml +++ b/crates/oracle/Cargo.toml @@ -31,8 +31,8 @@ mocktopus = "0.7.0" frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.26", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } +orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false } +orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false } [features] default = ["std"] diff --git a/crates/redeem/Cargo.toml b/crates/redeem/Cargo.toml index e82b472a8e..47baf58899 100644 --- a/crates/redeem/Cargo.toml +++ b/crates/redeem/Cargo.toml @@ -33,8 +33,8 @@ vault-registry = { path = "../vault-registry", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false, optional = true } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false, optional = true } +orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false, optional = true } +orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false, optional = true } [dev-dependencies] mocktopus = "0.7.0" @@ -46,8 +46,8 @@ staking = { path = "../staking" } currency = { path = "../currency", features = ["testing-utils"] } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" } +orml-tokens = { path = "../../../open-runtime-module-library/tokens" } +orml-traits = { path = "../../../open-runtime-module-library/traits" } [features] default = ["std"] diff --git a/crates/replace/Cargo.toml b/crates/replace/Cargo.toml index 19a0fcdca3..5a233c0245 100644 --- a/crates/replace/Cargo.toml +++ b/crates/replace/Cargo.toml @@ -34,8 +34,8 @@ nomination = { path = "../nomination", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false, optional = true } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false, optional = true } +orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false, optional = true } +orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false, optional = true } [dev-dependencies] mocktopus = "0.7.0" @@ -47,8 +47,8 @@ staking = { path = "../staking" } currency = { path = "../currency", features = ["testing-utils"] } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8" } +orml-tokens = { path = "../../../open-runtime-module-library/tokens" } +orml-traits = { path = "../../../open-runtime-module-library/traits" } [features] default = ["std"] diff --git a/crates/staking/Cargo.toml b/crates/staking/Cargo.toml index a5ea462d61..cb8c54aa6c 100644 --- a/crates/staking/Cargo.toml +++ b/crates/staking/Cargo.toml @@ -25,8 +25,8 @@ frame-system = { git = "https://github.com/paritytech/substrate", branch = "polk frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.26", default-features = false, optional = true } # note: can be remove after removal of migration -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } +orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false } +orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false } [dev-dependencies] mocktopus = "0.7.0" diff --git a/crates/vault-registry/Cargo.toml b/crates/vault-registry/Cargo.toml index b54ef5b191..f72637104e 100644 --- a/crates/vault-registry/Cargo.toml +++ b/crates/vault-registry/Cargo.toml @@ -37,8 +37,8 @@ staking = { path = "../staking", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } +orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false } +orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false } [dev-dependencies] mocktopus = "0.7.0" diff --git a/parachain/runtime/interlay/Cargo.toml b/parachain/runtime/interlay/Cargo.toml index a03685c16c..ac8b7a04b8 100644 --- a/parachain/runtime/interlay/Cargo.toml +++ b/parachain/runtime/interlay/Cargo.toml @@ -106,14 +106,14 @@ module-redeem-rpc-runtime-api = { path = "../../../crates/redeem/rpc/runtime-api module-replace-rpc-runtime-api = { path = "../../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-vesting = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } - -orml-xtokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-xcm-support = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-unknown-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-asset-registry= { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } +orml-tokens = { path = "../../../../open-runtime-module-library/tokens", default-features = false } +orml-traits = { path = "../../../../open-runtime-module-library/traits", default-features = false } +orml-vesting = { path = "../../../../open-runtime-module-library/vesting", default-features = false } + +orml-xtokens = { path = "../../../../open-runtime-module-library/xtokens", default-features = false } +orml-xcm-support = { path = "../../../../open-runtime-module-library/xcm-support", default-features = false } +orml-unknown-tokens = { path = "../../../../open-runtime-module-library/unknown-tokens", default-features = false } +orml-asset-registry = { path = "../../../../open-runtime-module-library/asset-registry", default-features = false } [dev-dependencies] hex = '0.4.2' diff --git a/parachain/runtime/interlay/src/lib.rs b/parachain/runtime/interlay/src/lib.rs index c2dc391d69..091eb75a2b 100644 --- a/parachain/runtime/interlay/src/lib.rs +++ b/parachain/runtime/interlay/src/lib.rs @@ -696,6 +696,9 @@ impl orml_tokens::Config for Runtime { type WeightInfo = (); type ExistentialDeposits = ExistentialDeposits; type OnDust = orml_tokens::TransferDust; + type OnSlash = (); + type OnDeposit = (); + type OnTransfer = (); type MaxLocks = MaxLocks; type DustRemovalWhitelist = DustRemovalWhitelist; type MaxReserves = ConstU32<0>; // we don't use named reserves diff --git a/parachain/runtime/kintsugi/Cargo.toml b/parachain/runtime/kintsugi/Cargo.toml index 9df0b1ee15..6caebef8d3 100644 --- a/parachain/runtime/kintsugi/Cargo.toml +++ b/parachain/runtime/kintsugi/Cargo.toml @@ -106,14 +106,14 @@ module-redeem-rpc-runtime-api = { path = "../../../crates/redeem/rpc/runtime-api module-replace-rpc-runtime-api = { path = "../../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-vesting = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } - -orml-xtokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-xcm-support = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-unknown-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-asset-registry= { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } +orml-tokens = { path = "../../../../open-runtime-module-library/tokens", default-features = false } +orml-traits = { path = "../../../../open-runtime-module-library/traits", default-features = false } +orml-vesting = { path = "../../../../open-runtime-module-library/vesting", default-features = false } + +orml-xtokens = { path = "../../../../open-runtime-module-library/xtokens", default-features = false } +orml-xcm-support = { path = "../../../../open-runtime-module-library/xcm-support", default-features = false } +orml-unknown-tokens = { path = "../../../../open-runtime-module-library/unknown-tokens", default-features = false } +orml-asset-registry = { path = "../../../../open-runtime-module-library/asset-registry", default-features = false } [dev-dependencies] hex = '0.4.2' diff --git a/parachain/runtime/kintsugi/src/lib.rs b/parachain/runtime/kintsugi/src/lib.rs index 4389e91b13..ac698b3520 100644 --- a/parachain/runtime/kintsugi/src/lib.rs +++ b/parachain/runtime/kintsugi/src/lib.rs @@ -698,6 +698,9 @@ impl orml_tokens::Config for Runtime { type WeightInfo = (); type ExistentialDeposits = ExistentialDeposits; type OnDust = orml_tokens::TransferDust; + type OnSlash = (); + type OnDeposit = (); + type OnTransfer = (); type MaxLocks = MaxLocks; type DustRemovalWhitelist = DustRemovalWhitelist; type MaxReserves = ConstU32<0>; // we don't use named reserves diff --git a/parachain/runtime/runtime-tests/Cargo.toml b/parachain/runtime/runtime-tests/Cargo.toml index 81b043e6dd..f0f3f1c483 100644 --- a/parachain/runtime/runtime-tests/Cargo.toml +++ b/parachain/runtime/runtime-tests/Cargo.toml @@ -112,14 +112,14 @@ module-redeem-rpc-runtime-api = { path = "../../../crates/redeem/rpc/runtime-api module-replace-rpc-runtime-api = { path = "../../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-vesting = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } +orml-tokens = { path = "../../../../open-runtime-module-library/tokens", default-features = false } +orml-traits = { path = "../../../../open-runtime-module-library/traits", default-features = false } +orml-vesting = { path = "../../../../open-runtime-module-library/vesting", default-features = false } -orml-xtokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } +orml-xtokens = { path = "../../../../open-runtime-module-library/xtokens", default-features = false } orml-xcm = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-xcm-support = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-unknown-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } +orml-xcm-support = { path = "../../../../open-runtime-module-library/xcm-support", default-features = false } +orml-unknown-tokens = { path = "../../../../open-runtime-module-library/unknown-tokens", default-features = false } xcm-emulator = { git = "https://github.com/shaunxw/xcm-simulator", rev = "ab5cd6c5fabe6ddda52ed6803ee1bf54c258fefe" } diff --git a/parachain/runtime/testnet-interlay/Cargo.toml b/parachain/runtime/testnet-interlay/Cargo.toml index 285cb297f8..b57442ea19 100644 --- a/parachain/runtime/testnet-interlay/Cargo.toml +++ b/parachain/runtime/testnet-interlay/Cargo.toml @@ -107,14 +107,14 @@ module-redeem-rpc-runtime-api = { path = "../../../crates/redeem/rpc/runtime-api module-replace-rpc-runtime-api = { path = "../../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-vesting = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } - -orml-xtokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-xcm-support = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-unknown-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-asset-registry= { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } +orml-tokens = { path = "../../../../open-runtime-module-library/tokens", default-features = false } +orml-traits = { path = "../../../../open-runtime-module-library/traits", default-features = false } +orml-vesting = { path = "../../../../open-runtime-module-library/vesting", default-features = false } + +orml-xtokens = { path = "../../../../open-runtime-module-library/xtokens", default-features = false } +orml-xcm-support = { path = "../../../../open-runtime-module-library/xcm-support", default-features = false } +orml-unknown-tokens = { path = "../../../../open-runtime-module-library/unknown-tokens", default-features = false } +orml-asset-registry = { path = "../../../../open-runtime-module-library/asset-registry", default-features = false } [dev-dependencies] hex = '0.4.2' diff --git a/parachain/runtime/testnet-interlay/src/lib.rs b/parachain/runtime/testnet-interlay/src/lib.rs index 583550c0ed..279130ff1d 100644 --- a/parachain/runtime/testnet-interlay/src/lib.rs +++ b/parachain/runtime/testnet-interlay/src/lib.rs @@ -668,6 +668,9 @@ impl orml_tokens::Config for Runtime { type WeightInfo = (); type ExistentialDeposits = ExistentialDeposits; type OnDust = orml_tokens::TransferDust; + type OnSlash = (); + type OnDeposit = (); + type OnTransfer = (); type MaxLocks = MaxLocks; type DustRemovalWhitelist = DustRemovalWhitelist; type MaxReserves = ConstU32<0>; // we don't use named reserves diff --git a/parachain/runtime/testnet-kintsugi/Cargo.toml b/parachain/runtime/testnet-kintsugi/Cargo.toml index 44e5f1840f..13c3ef1f21 100644 --- a/parachain/runtime/testnet-kintsugi/Cargo.toml +++ b/parachain/runtime/testnet-kintsugi/Cargo.toml @@ -107,14 +107,14 @@ module-redeem-rpc-runtime-api = { path = "../../../crates/redeem/rpc/runtime-api module-replace-rpc-runtime-api = { path = "../../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-vesting = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } - -orml-xtokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-xcm-support = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-unknown-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-asset-registry= { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } +orml-tokens = { path = "../../../../open-runtime-module-library/tokens", default-features = false } +orml-traits = { path = "../../../../open-runtime-module-library/traits", default-features = false } +orml-vesting = { path = "../../../../open-runtime-module-library/vesting", default-features = false } + +orml-xtokens = { path = "../../../../open-runtime-module-library/xtokens", default-features = false } +orml-xcm-support = { path = "../../../../open-runtime-module-library/xcm-support", default-features = false } +orml-unknown-tokens = { path = "../../../../open-runtime-module-library/unknown-tokens", default-features = false } +orml-asset-registry = { path = "../../../../open-runtime-module-library/asset-registry", default-features = false } [dev-dependencies] hex = '0.4.2' diff --git a/parachain/runtime/testnet-kintsugi/src/lib.rs b/parachain/runtime/testnet-kintsugi/src/lib.rs index 94bff4d55b..09305ae759 100644 --- a/parachain/runtime/testnet-kintsugi/src/lib.rs +++ b/parachain/runtime/testnet-kintsugi/src/lib.rs @@ -668,6 +668,9 @@ impl orml_tokens::Config for Runtime { type WeightInfo = (); type ExistentialDeposits = ExistentialDeposits; type OnDust = orml_tokens::TransferDust; + type OnSlash = (); + type OnDeposit = (); + type OnTransfer = (); type MaxLocks = MaxLocks; type DustRemovalWhitelist = DustRemovalWhitelist; type MaxReserves = ConstU32<0>; // we don't use named reserves diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 07b74c7bed..63b3b39854 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -491,3 +491,15 @@ pub struct CustomMetadata { pub fee_per_second: u128, pub coingecko_id: Vec, } + +pub fn is_ctoken(currency_id: CurrencyId) -> bool { + match currency_id { + CurrencyId::Token(CDOT) + | CurrencyId::Token(CIBTC) + | CurrencyId::Token(CINTR) + | CurrencyId::Token(CKSM) + | CurrencyId::Token(CKBTC) + | CurrencyId::Token(CKINT) => true, + _ => false, + } +} diff --git a/standalone/runtime/Cargo.toml b/standalone/runtime/Cargo.toml index 55759b42d4..83329ddc57 100644 --- a/standalone/runtime/Cargo.toml +++ b/standalone/runtime/Cargo.toml @@ -89,10 +89,10 @@ module-redeem-rpc-runtime-api = { path = "../../crates/redeem/rpc/runtime-api", module-replace-rpc-runtime-api = { path = "../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-vesting = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-asset-registry = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } +orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false } +orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false } +orml-vesting = { path = "../../../open-runtime-module-library/vesting", default-features = false } +orml-asset-registry = { path = "../../../open-runtime-module-library/asset-registry", default-features = false } xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.26", default-features = false } diff --git a/standalone/runtime/src/lib.rs b/standalone/runtime/src/lib.rs index 09ecf380c3..cfa9a14f9a 100644 --- a/standalone/runtime/src/lib.rs +++ b/standalone/runtime/src/lib.rs @@ -629,6 +629,9 @@ impl orml_tokens::Config for Runtime { type WeightInfo = (); type ExistentialDeposits = ExistentialDeposits; type OnDust = orml_tokens::TransferDust; + type OnSlash = (); + type OnDeposit = (); + type OnTransfer = (); type MaxLocks = MaxLocks; type DustRemovalWhitelist = DustRemovalWhitelist; type MaxReserves = ConstU32<0>; // we don't use named reserves From 32c204e836a024c8007acf2f347648074aef28c9 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Tue, 11 Oct 2022 16:54:31 +0200 Subject: [PATCH 17/58] feat(loans): add currency pallet --- Cargo.lock | 2 ++ crates/loans/Cargo.toml | 2 ++ crates/loans/src/lib.rs | 45 ++++++++++++++++++++-------------------- crates/loans/src/mock.rs | 45 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 71 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d57cd2be1c..1db2232948 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6461,10 +6461,12 @@ dependencies = [ name = "pallet-loans" version = "1.9.3" dependencies = [ + "currency", "frame-benchmarking", "frame-support", "frame-system", "interbtc-primitives", + "mocktopus", "num-traits", "orml-oracle", "orml-tokens", diff --git a/crates/loans/Cargo.toml b/crates/loans/Cargo.toml index c4cc59f8c5..f0ac611d6e 100644 --- a/crates/loans/Cargo.toml +++ b/crates/loans/Cargo.toml @@ -25,8 +25,10 @@ sp-io = { git = 'https://github.com/paritytech/substrate.git', bran sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } sp-std = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } +currency = { path = "../currency", default-features = false } [dev-dependencies] +mocktopus = "0.7.0" [features] default = ['std'] diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 7450d9702a..5bdef45d26 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -27,6 +27,7 @@ pub use crate::rate_model::*; +use currency::Amount; use frame_support::{ log, pallet_prelude::*, @@ -140,7 +141,7 @@ pub mod pallet { use super::*; #[pallet::config] - pub trait Config: frame_system::Config { + pub trait Config: frame_system::Config + currency::Config> { type Event: From> + IsType<::Event>; /// The oracle price feeder @@ -468,7 +469,7 @@ pub mod pallet { /// /// - `asset_id`: Market related currency /// - `market`: The market that is going to be stored - #[pallet::weight(T::WeightInfo::add_market())] + #[pallet::weight(::WeightInfo::add_market())] #[transactional] pub fn add_market( origin: OriginFor, @@ -520,7 +521,7 @@ pub mod pallet { /// If the market is already activated, does nothing. /// /// - `asset_id`: Market related currency - #[pallet::weight(T::WeightInfo::activate_market())] + #[pallet::weight(::WeightInfo::activate_market())] #[transactional] pub fn activate_market(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResultWithPostInfo { T::UpdateOrigin::ensure_origin(origin)?; @@ -540,7 +541,7 @@ pub mod pallet { /// /// - `asset_id`: Market related currency /// - `rate_model`: The new rate model to be updated - #[pallet::weight(T::WeightInfo::update_rate_model())] + #[pallet::weight(::WeightInfo::update_rate_model())] #[transactional] pub fn update_rate_model( origin: OriginFor, @@ -566,7 +567,7 @@ pub mod pallet { /// - `close_factor`: maximum liquidation ratio at one time /// - `liquidate_incentive`: liquidation incentive ratio /// - `cap`: market capacity - #[pallet::weight(T::WeightInfo::update_market())] + #[pallet::weight(::WeightInfo::update_market())] #[transactional] pub fn update_market( origin: OriginFor, @@ -634,7 +635,7 @@ pub mod pallet { /// /// - `asset_id`: market related currency /// - `market`: the new market parameters - #[pallet::weight(T::WeightInfo::force_update_market())] + #[pallet::weight(::WeightInfo::force_update_market())] #[transactional] pub fn force_update_market( origin: OriginFor, @@ -662,7 +663,7 @@ pub mod pallet { /// Add reward for the pallet account. /// /// - `amount`: Reward amount added - #[pallet::weight(T::WeightInfo::add_reward())] + #[pallet::weight(::WeightInfo::add_reward())] #[transactional] pub fn add_reward(origin: OriginFor, amount: BalanceOf) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; @@ -684,7 +685,7 @@ pub mod pallet { /// /// - `target_account`: account receive reward token. /// - `amount`: Withdraw amount - #[pallet::weight(T::WeightInfo::withdraw_missing_reward())] + #[pallet::weight(::WeightInfo::withdraw_missing_reward())] #[transactional] pub fn withdraw_missing_reward( origin: OriginFor, @@ -710,7 +711,7 @@ pub mod pallet { /// /// - `asset_id`: Market related currency /// - `reward_per_block`: reward amount per block. - #[pallet::weight(T::WeightInfo::update_market_reward_speed())] + #[pallet::weight(::WeightInfo::update_market_reward_speed())] #[transactional] pub fn update_market_reward_speed( origin: OriginFor, @@ -752,7 +753,7 @@ pub mod pallet { } /// Claim reward from all market. - #[pallet::weight(T::WeightInfo::claim_reward())] + #[pallet::weight(::WeightInfo::claim_reward())] #[transactional] pub fn claim_reward(origin: OriginFor) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; @@ -769,7 +770,7 @@ pub mod pallet { /// Claim reward from the specified market. /// /// - `asset_id`: Market related currency - #[pallet::weight(T::WeightInfo::claim_reward_for_market())] + #[pallet::weight(::WeightInfo::claim_reward_for_market())] #[transactional] pub fn claim_reward_for_market(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; @@ -785,7 +786,7 @@ pub mod pallet { /// /// - `asset_id`: the asset to be deposited. /// - `mint_amount`: the amount to be deposited. - #[pallet::weight(T::WeightInfo::mint())] + #[pallet::weight(::WeightInfo::mint())] #[transactional] pub fn mint( origin: OriginFor, @@ -802,7 +803,7 @@ pub mod pallet { /// /// - `asset_id`: the asset to be redeemed. /// - `redeem_amount`: the amount to be redeemed. - #[pallet::weight(T::WeightInfo::redeem())] + #[pallet::weight(::WeightInfo::redeem())] #[transactional] pub fn redeem( origin: OriginFor, @@ -819,7 +820,7 @@ pub mod pallet { /// Sender redeems all of internal supplies in exchange for the underlying asset. /// /// - `asset_id`: the asset to be redeemed. - #[pallet::weight(T::WeightInfo::redeem_all())] + #[pallet::weight(::WeightInfo::redeem_all())] #[transactional] pub fn redeem_all(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; @@ -838,7 +839,7 @@ pub mod pallet { /// /// - `asset_id`: the asset to be borrowed. /// - `borrow_amount`: the amount to be borrowed. - #[pallet::weight(T::WeightInfo::borrow())] + #[pallet::weight(::WeightInfo::borrow())] #[transactional] pub fn borrow( origin: OriginFor, @@ -856,7 +857,7 @@ pub mod pallet { /// /// - `asset_id`: the asset to be repaid. /// - `repay_amount`: the amount to be repaid. - #[pallet::weight(T::WeightInfo::repay_borrow())] + #[pallet::weight(::WeightInfo::repay_borrow())] #[transactional] pub fn repay_borrow( origin: OriginFor, @@ -873,7 +874,7 @@ pub mod pallet { /// Sender repays all of their debts. /// /// - `asset_id`: the asset to be repaid. - #[pallet::weight(T::WeightInfo::repay_borrow_all())] + #[pallet::weight(::WeightInfo::repay_borrow_all())] #[transactional] pub fn repay_borrow_all(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; @@ -889,7 +890,7 @@ pub mod pallet { /// /// - `asset_id`: the asset to be set. /// - `enable`: turn on/off the collateral option. - #[pallet::weight(T::WeightInfo::collateral_asset())] + #[pallet::weight(::WeightInfo::collateral_asset())] #[transactional] pub fn collateral_asset( origin: OriginFor, @@ -918,7 +919,7 @@ pub mod pallet { /// - `liquidation_asset_id`: the assert to be liquidated. /// - `repay_amount`: the amount to be repaid borrow. /// - `collateral_asset_id`: The collateral to seize from the borrower. - #[pallet::weight(T::WeightInfo::liquidate_borrow())] + #[pallet::weight(::WeightInfo::liquidate_borrow())] #[transactional] pub fn liquidate_borrow( origin: OriginFor, @@ -941,7 +942,7 @@ pub mod pallet { /// - `payer`: the payer account. /// - `asset_id`: the assets to be added. /// - `add_amount`: the amount to be added. - #[pallet::weight(T::WeightInfo::add_reserves())] + #[pallet::weight(::WeightInfo::add_reserves())] #[transactional] pub fn add_reserves( origin: OriginFor, @@ -977,7 +978,7 @@ pub mod pallet { /// - `receiver`: the receiver account. /// - `asset_id`: the assets to be reduced. /// - `reduce_amount`: the amount to be reduced. - #[pallet::weight(T::WeightInfo::reduce_reserves())] + #[pallet::weight(::WeightInfo::reduce_reserves())] #[transactional] pub fn reduce_reserves( origin: OriginFor, @@ -1013,7 +1014,7 @@ pub mod pallet { /// /// - `asset_id`: the asset to be redeemed. /// - `redeem_amount`: the amount to be redeemed. - #[pallet::weight(T::WeightInfo::redeem()+T::WeightInfo::reduce_reserves())] + #[pallet::weight(::WeightInfo::redeem()+::WeightInfo::reduce_reserves())] #[transactional] pub fn reduce_incentive_reserves( origin: OriginFor, diff --git a/crates/loans/src/mock.rs b/crates/loans/src/mock.rs index 9288225f60..06fd7412b0 100644 --- a/crates/loans/src/mock.rs +++ b/crates/loans/src/mock.rs @@ -17,6 +17,7 @@ pub use super::*; +use currency::Amount; use frame_benchmarking::whitelisted_caller; use frame_support::{ construct_runtime, parameter_types, @@ -24,6 +25,7 @@ use frame_support::{ PalletId, }; use frame_system::EnsureRoot; +use mocktopus::{macros::mockable, mocking::*}; use orml_traits::{parameter_type_with_key, DataFeeder, DataProvider, DataProviderExtended}; use pallet_traits::{VaultTokenCurrenciesFilter, VaultTokenExchangeRateProvider}; use primitives::{ @@ -31,7 +33,7 @@ use primitives::{ Moment, PriceDetail, CDOT, CIBTC, CKBTC, CKINT, CKSM, DOT, IBTC, INTR, KBTC, KINT, KSM, }; use sp_core::H256; -use sp_runtime::{testing::Header, traits::IdentityLookup, AccountId32}; +use sp_runtime::{testing::Header, traits::IdentityLookup, AccountId32, FixedI128}; use sp_std::vec::Vec; use std::{cell::RefCell, collections::HashMap}; @@ -48,6 +50,7 @@ construct_runtime!( Loans: crate::{Pallet, Storage, Call, Event}, TimestampPallet: pallet_timestamp::{Pallet, Call, Storage, Inherent}, Tokens: orml_tokens::{Pallet, Call, Storage, Config, Event}, + Currency: currency::{Pallet}, } ); @@ -130,6 +133,46 @@ impl orml_tokens::Config for Test { type OnKilledTokenAccount = (); } +pub type SignedFixedPoint = FixedI128; +pub type SignedInner = i128; +pub type UnsignedFixedPoint = FixedU128; +pub struct CurrencyConvert; +impl currency::CurrencyConversion, CurrencyId> for CurrencyConvert { + fn convert( + amount: ¤cy::Amount, + to: CurrencyId, + ) -> Result, sp_runtime::DispatchError> { + let amount = convert_to(to, amount.amount())?; + Ok(Amount::new(amount, to)) + } +} + +#[cfg_attr(test, mockable)] +pub fn convert_to(to: CurrencyId, amount: Balance) -> Result { + Ok(amount) // default conversion 1:1 - overwritable with mocktopus +} + +pub const DEFAULT_COLLATERAL_CURRENCY: CurrencyId = Token(DOT); +pub const DEFAULT_NATIVE_CURRENCY: CurrencyId = Token(INTR); +pub const DEFAULT_WRAPPED_CURRENCY: CurrencyId = Token(IBTC); + +parameter_types! { + pub const GetCollateralCurrencyId: CurrencyId = DEFAULT_COLLATERAL_CURRENCY; + pub const GetNativeCurrencyId: CurrencyId = DEFAULT_NATIVE_CURRENCY; + pub const GetWrappedCurrencyId: CurrencyId = DEFAULT_WRAPPED_CURRENCY; +} + +impl currency::Config for Test { + type SignedInner = SignedInner; + type SignedFixedPoint = SignedFixedPoint; + type UnsignedFixedPoint = UnsignedFixedPoint; + type Balance = Balance; + type GetNativeCurrencyId = GetNativeCurrencyId; + type GetRelayChainCurrencyId = GetCollateralCurrencyId; + type GetWrappedCurrencyId = GetWrappedCurrencyId; + type CurrencyConversion = CurrencyConvert; +} + // pallet-price is using for benchmark compilation pub type TimeStampedPrice = orml_oracle::TimestampedValue; pub struct MockDataProvider; From 409bb8b3f3e9382190d9f141ac02c1a122167ec9 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Tue, 11 Oct 2022 22:29:35 +0200 Subject: [PATCH 18/58] feat(loans): split do_collateral_asset and also distributes rewards based on pToken holdings instead of voucher balance --- crates/loans/src/farming.rs | 8 ++- crates/loans/src/lib.rs | 135 +++++++++++++++++++++--------------- 2 files changed, 83 insertions(+), 60 deletions(-) diff --git a/crates/loans/src/farming.rs b/crates/loans/src/farming.rs index c65af7cfc9..9b55a98d5f 100644 --- a/crates/loans/src/farming.rs +++ b/crates/loans/src/farming.rs @@ -15,6 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use orml_traits::MultiCurrency; use sp_io::hashing::blake2_256; use sp_runtime::{traits::Zero, DispatchResult}; @@ -122,9 +123,10 @@ impl Pallet { *supplier_index = supply_state.index; RewardAccrued::::try_mutate(supplier, |total_reward| -> DispatchResult { - let supplier_account = AccountDeposits::::get(asset_id, supplier); - let supplier_amount = supplier_account.voucher_balance; - let reward_delta = Self::calculate_reward_delta(supplier_amount, delta_index)?; + // Frozen balance is not counted towards the total + let total_balance = + as MultiCurrency>::total_balance(asset_id, supplier); + let reward_delta = Self::calculate_reward_delta(total_balance, delta_index)?; *total_reward = total_reward .checked_add(reward_delta) .ok_or(ArithmeticError::Overflow)?; diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 5bdef45d26..5ca134cb7c 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -141,7 +141,9 @@ pub mod pallet { use super::*; #[pallet::config] - pub trait Config: frame_system::Config + currency::Config> { + pub trait Config: + frame_system::Config + currency::Config, CurrencyId = CurrencyId> + { type Event: From> + IsType<::Event>; /// The oracle price feeder @@ -241,10 +243,10 @@ pub mod pallet { pub enum Event { /// Enable collateral for certain asset /// [sender, asset_id] - CollateralAssetAdded(T::AccountId, AssetIdOf), + DepositCollateral(T::AccountId, AssetIdOf, BalanceOf), /// Disable collateral for certain asset /// [sender, asset_id] - CollateralAssetRemoved(T::AccountId, AssetIdOf), + WithdrawCollateral(T::AccountId, AssetIdOf, BalanceOf), /// Event emitted when assets are deposited /// [sender, asset_id, amount] Deposited(T::AccountId, AssetIdOf, BalanceOf), @@ -340,15 +342,8 @@ pub mod pallet { /// CollateralType -> Owner -> Deposits #[pallet::storage] #[pallet::getter(fn account_deposits)] - pub type AccountDeposits = StorageDoubleMap< - _, - Blake2_128Concat, - AssetIdOf, - Blake2_128Concat, - T::AccountId, - Deposits>, - ValueQuery, - >; + pub type AccountDeposits = + StorageDoubleMap<_, Blake2_128Concat, AssetIdOf, Blake2_128Concat, T::AccountId, BalanceOf, ValueQuery>; /// Mapping of account addresses to total deposit interest accrual /// CurrencyId -> Owner -> EarnedSnapshot @@ -913,6 +908,22 @@ pub mod pallet { Ok(().into()) } + #[pallet::weight(::WeightInfo::collateral_asset())] + #[transactional] + pub fn deposit_collateral(origin: OriginFor, ptoken_amount: Amount) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + Self::do_deposit_collateral(&who, ptoken_amount)?; + Ok(().into()) + } + + #[pallet::weight(::WeightInfo::collateral_asset())] + #[transactional] + pub fn withdraw_collateral(origin: OriginFor, ptoken_amount: Amount) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + Self::do_withdraw_collateral(&who, ptoken_amount)?; + Ok(().into()) + } + /// The sender liquidates the borrower's collateral. /// /// - `borrower`: the borrower to be liquidated. @@ -1825,21 +1836,10 @@ impl LoansTrait, AccountIdOf, BalanceOf> for Palle T::Assets::transfer(asset_id, supplier, &Self::account_id(), amount, false)?; - // TODO: Mint `voucher_amount` tokens to `supplier` - AccountDeposits::::try_mutate(asset_id, supplier, |deposits| -> DispatchResult { - deposits.voucher_balance = deposits - .voucher_balance - .checked_add(voucher_amount) - .ok_or(ArithmeticError::Overflow)?; - Ok(()) - })?; - TotalSupply::::try_mutate(asset_id, |total_balance| -> DispatchResult { - let new_balance = total_balance - .checked_add(voucher_amount) - .ok_or(ArithmeticError::Overflow)?; - *total_balance = new_balance; - Ok(()) - })?; + let ptoken_id = Self::ptoken_id(asset_id)?; + let ptokens_to_mint: Amount = Amount::new(voucher_amount, ptoken_id); + ptokens_to_mint.mint_to(supplier)?; + Self::deposit_event(Event::::Deposited(supplier.clone(), asset_id, amount)); Ok(()) } @@ -1872,35 +1872,38 @@ impl LoansTrait, AccountIdOf, BalanceOf> for Palle Ok(()) } - fn do_collateral_asset( - supplier: &AccountIdOf, - asset_id: AssetIdOf, - enable: bool, - ) -> Result<(), DispatchError> { - Self::ensure_active_market(asset_id)?; - ensure!( - AccountDeposits::::contains_key(asset_id, supplier), - Error::::NoDeposit - ); - let mut deposits = Self::account_deposits(asset_id, supplier); - // turn on the collateral button - if enable { - deposits.is_collateral = true; - AccountDeposits::::insert(asset_id, supplier, deposits); - Self::deposit_event(Event::::CollateralAssetAdded(supplier.clone(), asset_id)); - return Ok(()); - } - // turn off the collateral button after checking the liquidity + fn do_deposit_collateral(supplier: &AccountIdOf, ptoken_amount: Amount) -> Result<(), DispatchError> { + let underlying_id = Self::underlying_id(ptoken_amount.currency())?; + Self::ensure_active_market(underlying_id)?; + + // Will fail if supplier has insufficient free tokens + ptoken_amount.lock_on(supplier)?; + + // Increase the amount of collateral deposited + AccountDeposits::::try_mutate_exists(ptoken_amount.currency(), supplier, |deposits| -> DispatchResult { + deposits = deposits + .unwrap_or_default() + .checked_add(ptoken_amount.amount()) + .ok_or(ArithmeticError::Overflow)?; + Ok(()) + })?; + + Self::deposit_event(Event::::DepositCollateral( + supplier.clone(), + ptoken_amount.currency(), + ptoken_amount.amount(), + )); + Ok(()) + } + + fn do_withdraw_collateral(supplier: &AccountIdOf, ptoken_amount: Amount) -> Result<(), DispatchError> { + let underlying_id = Self::underlying_id(ptoken_amount.currency())?; + Self::ensure_active_market(underlying_id)?; + let total_collateral_value = Self::total_collateral_value(supplier)?; - let collateral_asset_value = Self::collateral_asset_value(supplier, asset_id)?; + let collateral_asset_value = Self::collateral_asset_value(supplier, underlying_id)?; let total_borrowed_value = Self::total_borrowed_value(supplier)?; - log::trace!( - target: "loans::collateral_asset", - "total_collateral_value: {:?}, collateral_asset_value: {:?}, total_borrowed_value: {:?}", - total_collateral_value.into_inner(), - collateral_asset_value.into_inner(), - total_borrowed_value.into_inner(), - ); + if total_collateral_value < total_borrowed_value .checked_add(&collateral_asset_value) @@ -1908,11 +1911,29 @@ impl LoansTrait, AccountIdOf, BalanceOf> for Palle { return Err(Error::::InsufficientLiquidity.into()); } - deposits.is_collateral = false; - AccountDeposits::::insert(asset_id, supplier, deposits); - Self::deposit_event(Event::::CollateralAssetRemoved(supplier.clone(), asset_id)); + ptoken_amount.unlock_on(supplier)?; + + // Decrease the amount of collateral deposited + AccountDeposits::::try_mutate_exists(asset_id, who, |deposits| -> DispatchResult { + let mut d = deposits + .unwrap_or_default() + .checked_sub(ptoken_amount.amount()) + .ok_or(ArithmeticError::Underflow)?; + if d.is_zero() { + // remove deposits storage if zero balance + *deposits = None; + } else { + *deposits = Some(d); + } + Ok(()) + })?; + Self::deposit_event(Event::::WithdrawCollateral( + supplier.clone(), + ptoken_amount.currency(), + ptoken_amount.amount(), + )); Ok(()) } From 139a3148f4c707fde7bda6f007babe7835f7c296 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Thu, 13 Oct 2022 16:24:10 +0200 Subject: [PATCH 19/58] feat(loans): fully tokenize ptokens --- crates/loans/src/farming.rs | 5 +- crates/loans/src/interest.rs | 4 +- crates/loans/src/lib.rs | 291 ++++++++++----------- crates/loans/src/ptoken.rs | 84 +++--- crates/loans/src/tests.rs | 95 +++---- crates/loans/src/tests/edge_cases.rs | 8 +- crates/loans/src/tests/interest_rate.rs | 46 ++-- crates/loans/src/tests/liquidate_borrow.rs | 28 +- crates/loans/src/tests/ptokens.rs | 46 ++-- crates/traits/src/loans.rs | 4 +- 10 files changed, 312 insertions(+), 299 deletions(-) diff --git a/crates/loans/src/farming.rs b/crates/loans/src/farming.rs index 9b55a98d5f..996bbd001b 100644 --- a/crates/loans/src/farming.rs +++ b/crates/loans/src/farming.rs @@ -73,7 +73,7 @@ impl Pallet { } let supply_speed = RewardSupplySpeed::::get(asset_id); if !supply_speed.is_zero() { - let total_supply = TotalSupply::::get(asset_id); + let total_supply = Self::total_supply(asset_id)?; let delta_index = Self::calculate_reward_delta_index(delta_block, supply_speed, total_supply)?; supply_state.index = supply_state .index @@ -122,10 +122,11 @@ impl Pallet { .ok_or(ArithmeticError::Underflow)?; *supplier_index = supply_state.index; + let ptoken_id = Self::ptoken_id(asset_id)?; RewardAccrued::::try_mutate(supplier, |total_reward| -> DispatchResult { // Frozen balance is not counted towards the total let total_balance = - as MultiCurrency>::total_balance(asset_id, supplier); + as MultiCurrency>::total_balance(ptoken_id, supplier); let reward_delta = Self::calculate_reward_delta(total_balance, delta_index)?; *total_reward = total_reward .checked_add(reward_delta) diff --git a/crates/loans/src/interest.rs b/crates/loans/src/interest.rs index bbd0073352..37b38c57a6 100644 --- a/crates/loans/src/interest.rs +++ b/crates/loans/src/interest.rs @@ -55,7 +55,7 @@ impl Pallet { asset_id: AssetIdOf, ) -> Result<(Rate, Rate, Rate, Ratio, BalanceOf, BalanceOf, FixedU128), DispatchError> { let market = Self::market(asset_id)?; - let total_supply = Self::total_supply(asset_id); + let total_supply = Self::total_supply(asset_id)?; let total_cash = Self::get_total_cash(asset_id); let mut total_borrows = Self::total_borrows(asset_id); let mut total_reserves = Self::total_reserves(asset_id); @@ -105,7 +105,7 @@ impl Pallet { /// This function does not accrue interest before calculating the exchange rate. /// exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply pub fn exchange_rate_stored(asset_id: AssetIdOf) -> Result { - let total_supply = Self::total_supply(asset_id); + let total_supply = Self::total_supply(asset_id)?; let total_cash = Self::get_total_cash(asset_id); let total_borrows = Self::total_borrows(asset_id); let total_reserves = Self::total_reserves(asset_id); diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 5ca134cb7c..33fe5dd9fc 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -40,10 +40,10 @@ use frame_support::{ }; use frame_system::pallet_prelude::*; use num_traits::cast::ToPrimitive; +use orml_traits::MultiCurrency; pub use pallet::*; use pallet_traits::{ - ConvertToBigUint, Loans as LoansTrait, LoansMarketDataProvider, LoansPositionDataProvider, MarketInfo, - MarketStatus, PriceFeeder, + ConvertToBigUint, Loans as LoansTrait, LoansMarketDataProvider, MarketInfo, MarketStatus, PriceFeeder, }; use primitives::{is_ctoken, Balance, CurrencyId, Liquidity, Price, Rate, Ratio, Shortfall, Timestamp}; use sp_runtime::{ @@ -89,8 +89,9 @@ pub struct OnSlashHook(marker::PhantomData); impl OnSlash, BalanceOf> for OnSlashHook { fn on_slash(currency_id: AssetIdOf, account_id: &T::AccountId, _: BalanceOf) -> DispatchResult { if is_ctoken(currency_id) { - Pallet::::update_reward_supply_index(currency_id)?; - Pallet::::distribute_supplier_reward(currency_id, account_id)?; + let underlying_id = Pallet::::underlying_id(currency_id)?; + Pallet::::update_reward_supply_index(underlying_id)?; + Pallet::::distribute_supplier_reward(underlying_id, account_id)?; } Ok(()) } @@ -100,8 +101,9 @@ pub struct OnDepositHook(marker::PhantomData); impl OnDeposit, BalanceOf> for OnDepositHook { fn on_deposit(currency_id: AssetIdOf, account_id: &T::AccountId, _: BalanceOf) -> DispatchResult { if is_ctoken(currency_id) { - Pallet::::update_reward_supply_index(currency_id)?; - Pallet::::distribute_supplier_reward(currency_id, account_id)?; + let underlying_id = Pallet::::underlying_id(currency_id)?; + Pallet::::update_reward_supply_index(underlying_id)?; + Pallet::::distribute_supplier_reward(underlying_id, account_id)?; } Ok(()) } @@ -116,9 +118,10 @@ impl OnTransfer, BalanceOf> for OnTrans _: BalanceOf, ) -> DispatchResult { if is_ctoken(currency_id) { - Pallet::::update_reward_supply_index(currency_id)?; - Pallet::::distribute_supplier_reward(currency_id, from)?; - Pallet::::distribute_supplier_reward(currency_id, to)?; + let underlying_id = Pallet::::underlying_id(currency_id)?; + Pallet::::update_reward_supply_index(underlying_id)?; + Pallet::::distribute_supplier_reward(underlying_id, from)?; + Pallet::::distribute_supplier_reward(underlying_id, to)?; } Ok(()) } @@ -306,12 +309,6 @@ pub mod pallet { #[pallet::getter(fn last_accrued_interest_time)] pub type LastAccruedInterestTime = StorageMap<_, Blake2_128Concat, AssetIdOf, Timestamp, ValueQuery>; - /// Total number of collateral tokens in circulation - /// CollateralType -> Balance - #[pallet::storage] - #[pallet::getter(fn total_supply)] - pub type TotalSupply = StorageMap<_, Blake2_128Concat, AssetIdOf, BalanceOf, ValueQuery>; - /// Total amount of outstanding borrows of the underlying in this market /// CurrencyId -> Balance #[pallet::storage] @@ -823,8 +820,7 @@ pub mod pallet { Self::accrue_interest(asset_id)?; let exchange_rate = Self::exchange_rate_stored(asset_id)?; Self::update_earned_stored(&who, asset_id, exchange_rate)?; - let deposits = AccountDeposits::::get(asset_id, &who); - let redeem_amount = Self::do_redeem_voucher(&who, asset_id, deposits.voucher_balance)?; + let redeem_amount = Self::do_redeem_voucher(&who, asset_id, Self::free_ptoken_balance(asset_id, &who)?)?; Self::deposit_event(Event::::Redeemed(who, asset_id, redeem_amount)); Ok(().into()) @@ -881,46 +877,49 @@ pub mod pallet { Ok(().into()) } - /// Set the collateral asset. - /// - /// - `asset_id`: the asset to be set. - /// - `enable`: turn on/off the collateral option. #[pallet::weight(::WeightInfo::collateral_asset())] #[transactional] - pub fn collateral_asset( + pub fn deposit_all_collateral(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + + let ptoken_id = Self::ptoken_id(asset_id)?; + let ptokens = Self::free_ptoken_balance(asset_id, &who)?; + Self::do_deposit_collateral(&who, ptoken_id, ptokens)?; + Ok(().into()) + } + + #[pallet::weight(::WeightInfo::collateral_asset())] + #[transactional] + pub fn deposit_collateral( origin: OriginFor, asset_id: AssetIdOf, - enable: bool, + #[pallet::compact] amount: BalanceOf, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - Self::ensure_active_market(asset_id)?; - ensure!( - AccountDeposits::::contains_key(asset_id, &who), - Error::::NoDeposit - ); - let deposits = Self::account_deposits(asset_id, &who); - if deposits.is_collateral == enable { - return Err(Error::::DuplicateOperation.into()); - } - - Self::do_collateral_asset(&who, asset_id, enable)?; - + Self::do_deposit_collateral(&who, asset_id, amount)?; Ok(().into()) } #[pallet::weight(::WeightInfo::collateral_asset())] #[transactional] - pub fn deposit_collateral(origin: OriginFor, ptoken_amount: Amount) -> DispatchResultWithPostInfo { + pub fn withdraw_all_collateral(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - Self::do_deposit_collateral(&who, ptoken_amount)?; + + let ptoken_id = Self::ptoken_id(asset_id)?; + let collateral = Self::account_deposits(ptoken_id, who.clone()); + Self::do_withdraw_collateral(&who, ptoken_id, collateral)?; Ok(().into()) } #[pallet::weight(::WeightInfo::collateral_asset())] #[transactional] - pub fn withdraw_collateral(origin: OriginFor, ptoken_amount: Amount) -> DispatchResultWithPostInfo { + pub fn withdraw_collateral( + origin: OriginFor, + asset_id: AssetIdOf, + #[pallet::compact] amount: BalanceOf, + ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - Self::do_withdraw_collateral(&who, ptoken_amount)?; + Self::do_withdraw_collateral(&who, asset_id, amount)?; Ok(().into()) } @@ -1178,50 +1177,54 @@ impl Pallet { Ok(total_borrow_value) } - fn current_collateral_balance( + fn collateral_balance( supplier: &T::AccountId, asset_id: AssetIdOf, + ptoken_amount: BalanceOf, ) -> Result, DispatchError> { - if !AccountDeposits::::contains_key(asset_id, supplier) { - return Ok(BalanceOf::::zero()); - } - let deposits = Self::account_deposits(asset_id, supplier); - if !deposits.is_collateral { - return Ok(BalanceOf::::zero()); - } - if deposits.voucher_balance.is_zero() { - return Ok(BalanceOf::::zero()); - } let exchange_rate = Self::exchange_rate_stored(asset_id)?; - let underlying_amount = Self::calc_underlying_amount(deposits.voucher_balance, exchange_rate)?; + let underlying_amount = Self::calc_underlying_amount(ptoken_amount, exchange_rate)?; let market = Self::market(asset_id)?; let effects_amount = market.collateral_factor.mul_ceil(underlying_amount); Ok(BalanceOf::::saturated_from(effects_amount)) } - fn collateral_asset_value(supplier: &T::AccountId, asset_id: AssetIdOf) -> Result { - let effects_amount = Self::current_collateral_balance(supplier, asset_id)?; - + fn collateral_amount_value( + supplier: &T::AccountId, + asset_id: AssetIdOf, + ptoken_amount: BalanceOf, + ) -> Result { + let effects_amount = Self::collateral_balance(supplier, asset_id, ptoken_amount)?; Self::get_asset_value(asset_id, effects_amount) } + fn collateral_asset_value(supplier: &T::AccountId, asset_id: AssetIdOf) -> Result { + let ptoken_id = Self::ptoken_id(asset_id)?; + if !AccountDeposits::::contains_key(ptoken_id, supplier) { + return Ok(0.into()); + } + let deposits = Self::account_deposits(ptoken_id, supplier); + if deposits.is_zero() { + return Ok(0.into()); + } + Self::collateral_amount_value(supplier, asset_id, deposits) + } + fn liquidation_threshold_asset_value( borrower: &T::AccountId, asset_id: AssetIdOf, ) -> Result { - if !AccountDeposits::::contains_key(asset_id, borrower) { - return Ok(FixedU128::zero()); - } - let deposits = Self::account_deposits(asset_id, borrower); - if !deposits.is_collateral { + let ptoken_id = Self::ptoken_id(asset_id)?; + if !AccountDeposits::::contains_key(ptoken_id, borrower) { return Ok(FixedU128::zero()); } - if deposits.voucher_balance.is_zero() { + let deposits = Self::account_deposits(ptoken_id, borrower); + if deposits.is_zero() { return Ok(FixedU128::zero()); } let exchange_rate = Self::exchange_rate_stored(asset_id)?; - let underlying_amount = Self::calc_underlying_amount(deposits.voucher_balance, exchange_rate)?; + let underlying_amount = Self::calc_underlying_amount(deposits, exchange_rate)?; let market = Self::market(asset_id)?; let effects_amount = market.liquidation_threshold.mul_ceil(underlying_amount); @@ -1250,7 +1253,8 @@ impl Pallet { Ok(total_asset_value) } - /// Checks if the redeemer should be allowed to redeem tokens in given market + /// Checks if the redeemer should be allowed to redeem tokens in given market. + /// Takes into account both `free` and `locked` (deposited as collateral) ptokens. fn redeem_allowed(asset_id: AssetIdOf, redeemer: &T::AccountId, voucher_amount: BalanceOf) -> DispatchResult { log::trace!( target: "loans::redeem_allowed", @@ -1259,21 +1263,21 @@ impl Pallet { redeemer, voucher_amount, ); - let deposit = Self::account_deposits(asset_id, redeemer); - if deposit.voucher_balance < voucher_amount { + let ptoken_id = Self::ptoken_id(asset_id)?; + if Self::balance(ptoken_id, redeemer) < voucher_amount { return Err(Error::::InsufficientDeposit.into()); } + // Ensure there is enough cash in the market let exchange_rate = Self::exchange_rate_stored(asset_id)?; let redeem_amount = Self::calc_underlying_amount(voucher_amount, exchange_rate)?; Self::ensure_enough_cash(asset_id, redeem_amount)?; - if !deposit.is_collateral { - return Ok(()); - } - + // Ensure that withdrawing depoisted collateral doesn't leave the user undercollateralized. + let collateral_amount = voucher_amount.saturating_sub(Self::free_ptoken_balance(asset_id, redeemer)?); + let collateral_underlying_amount = Self::calc_underlying_amount(collateral_amount, exchange_rate)?; let market = Self::market(asset_id)?; - let effects_amount = market.collateral_factor.mul_ceil(redeem_amount); + let effects_amount = market.collateral_factor.mul_ceil(collateral_underlying_amount); let redeem_effects_value = Self::get_asset_value(asset_id, effects_amount)?; log::trace!( target: "loans::redeem_allowed", @@ -1300,28 +1304,14 @@ impl Pallet { let exchange_rate = Self::exchange_rate_stored(asset_id)?; let redeem_amount = Self::calc_underlying_amount(voucher_amount, exchange_rate)?; - // TODO: Amount::new(voucher_amount, asset_id).burn_from(who) - AccountDeposits::::try_mutate_exists(asset_id, who, |deposits| -> DispatchResult { - let mut d = deposits.unwrap_or_default(); - d.voucher_balance = d - .voucher_balance - .checked_sub(voucher_amount) - .ok_or(ArithmeticError::Underflow)?; - if d.voucher_balance.is_zero() { - // remove deposits storage if zero balance - *deposits = None; - } else { - *deposits = Some(d); - } - Ok(()) - })?; - TotalSupply::::try_mutate(asset_id, |total_balance| -> DispatchResult { - let new_balance = total_balance - .checked_sub(voucher_amount) - .ok_or(ArithmeticError::Underflow)?; - *total_balance = new_balance; - Ok(()) - })?; + let ptoken_id = Self::ptoken_id(asset_id)?; + let ptoken_amount: Amount = Amount::new(voucher_amount, ptoken_id); + + // Need to first `lock_on` in order to `burn_from` because: + // 1) only the `free` ptokens are redeemable + // 2) `burn_from` can only be called on locked tokens. + ptoken_amount.lock_on(who)?; + ptoken_amount.burn_from(who)?; T::Assets::transfer(asset_id, &Self::account_id(), who, redeem_amount, false) .map_err(|_| Error::::InsufficientCash)?; @@ -1398,7 +1388,7 @@ impl Pallet { let account_earned = AccountEarned::::get(asset_id, who); let total_earned_prior_new = exchange_rate .checked_sub(&account_earned.exchange_rate_prior) - .and_then(|r| r.checked_mul_int(deposits.voucher_balance)) + .and_then(|r| r.checked_mul_int(deposits)) .and_then(|r| r.checked_add(account_earned.total_earned_prior)) .ok_or(ArithmeticError::Overflow)?; @@ -1480,13 +1470,11 @@ impl Pallet { } Self::liquidate_borrow_allowed(&borrower, liquidation_asset_id, repay_amount, &market)?; - let deposits = AccountDeposits::::get(collateral_asset_id, &borrower); - if !deposits.is_collateral { - return Err(Error::::DepositsAreNotCollateral.into()); - } + let ptoken_id = Self::ptoken_id(collateral_asset_id)?; + let deposits = AccountDeposits::::get(ptoken_id, &borrower); let exchange_rate = Self::exchange_rate_stored(collateral_asset_id)?; let borrower_deposit_amount = exchange_rate - .checked_mul_int(deposits.voucher_balance) + .checked_mul_int(deposits) .ok_or(ArithmeticError::Overflow)?; let collateral_value = Self::get_asset_value(collateral_asset_id, borrower_deposit_amount)?; @@ -1592,39 +1580,28 @@ impl Pallet { // 3.the liquidator will receive voucher token from borrower let exchange_rate = Self::exchange_rate_stored(collateral_asset_id)?; let collateral_amount = Self::calc_collateral_amount(collateral_underlying_amount, exchange_rate)?; - AccountDeposits::::try_mutate(collateral_asset_id, borrower, |deposits| -> DispatchResult { - deposits.voucher_balance = deposits - .voucher_balance - .checked_sub(collateral_amount) - .ok_or(ArithmeticError::Underflow)?; - Ok(()) - })?; - let incentive_reserved_amount = market.liquidate_incentive_reserved_factor.mul_floor( + let ptoken_id = Self::ptoken_id(collateral_asset_id)?; + let incentive_reserved = market.liquidate_incentive_reserved_factor.mul_floor( FixedU128::from_inner(collateral_amount) .checked_div(&market.liquidate_incentive) .map(|r| r.into_inner()) .ok_or(ArithmeticError::Underflow)?, ); + + let amount_to_liquidate: Amount = Amount::new(collateral_amount, ptoken_id); + // Unlock this balance to make it transferrable + amount_to_liquidate.unlock_on(borrower)?; + // increase liquidator's voucher_balance - AccountDeposits::::try_mutate(collateral_asset_id, liquidator, |deposits| -> DispatchResult { - deposits.voucher_balance = deposits - .voucher_balance - .checked_add(collateral_amount - incentive_reserved_amount) - .ok_or(ArithmeticError::Overflow)?; - Ok(()) - })?; + let liquidator_amount_u128 = collateral_amount + .checked_sub(incentive_reserved) + .ok_or(ArithmeticError::Underflow)?; + let liquidator_amount: Amount = Amount::new(liquidator_amount_u128, ptoken_id); + liquidator_amount.transfer(borrower, liquidator)?; + // increase reserve's voucher_balance - AccountDeposits::::try_mutate( - collateral_asset_id, - Self::incentive_reward_account_id()?, - |deposits| -> DispatchResult { - deposits.voucher_balance = deposits - .voucher_balance - .checked_add(incentive_reserved_amount) - .ok_or(ArithmeticError::Overflow)?; - Ok(()) - }, - )?; + let incentive_reserved_amount: Amount = Amount::new(incentive_reserved, ptoken_id); + incentive_reserved_amount.transfer(borrower, &Self::incentive_reward_account_id()?)?; Self::deposit_event(Event::::LiquidatedBorrow( liquidator.clone(), @@ -1731,6 +1708,21 @@ impl Pallet { T::Assets::reducible_balance(asset_id, &Self::account_id(), false) } + /// Total suply of lending tokens (ptokens), given the underlying + pub fn total_supply(asset_id: AssetIdOf) -> Result, DispatchError> { + let ptoken_id = Self::ptoken_id(asset_id)?; + Ok(orml_tokens::Pallet::::total_issuance(ptoken_id)) + } + + /// Total suply of lending tokens (ptokens), given the underlying + pub fn free_ptoken_balance( + asset_id: AssetIdOf, + account_id: &T::AccountId, + ) -> Result, DispatchError> { + let ptoken_id = Self::ptoken_id(asset_id)?; + Ok(orml_tokens::Pallet::::free_balance(ptoken_id, account_id)) + } + // Returns the uniform format price. // Formula: `price = oracle_price * 10.pow(18 - asset_decimal)` // This particular price makes it easy to calculate the value , @@ -1872,7 +1864,13 @@ impl LoansTrait, AccountIdOf, BalanceOf> for Palle Ok(()) } - fn do_deposit_collateral(supplier: &AccountIdOf, ptoken_amount: Amount) -> Result<(), DispatchError> { + fn do_deposit_collateral( + supplier: &AccountIdOf, + asset_id: AssetIdOf, + amount: BalanceOf, + ) -> Result<(), DispatchError> { + let ptoken_amount: Amount = Amount::new(amount, asset_id); + // If the given asset_id is not a valid ptoken, fetching the underlying will fail let underlying_id = Self::underlying_id(ptoken_amount.currency())?; Self::ensure_active_market(underlying_id)?; @@ -1880,13 +1878,11 @@ impl LoansTrait, AccountIdOf, BalanceOf> for Palle ptoken_amount.lock_on(supplier)?; // Increase the amount of collateral deposited - AccountDeposits::::try_mutate_exists(ptoken_amount.currency(), supplier, |deposits| -> DispatchResult { - deposits = deposits - .unwrap_or_default() - .checked_add(ptoken_amount.amount()) - .ok_or(ArithmeticError::Overflow)?; - Ok(()) - })?; + let deposit = Self::account_deposits(ptoken_amount.currency(), supplier); + let new_deposit = deposit + .checked_add(ptoken_amount.amount()) + .ok_or(ArithmeticError::Overflow)?; + AccountDeposits::::insert(ptoken_amount.currency(), supplier, new_deposit); Self::deposit_event(Event::::DepositCollateral( supplier.clone(), @@ -1896,17 +1892,23 @@ impl LoansTrait, AccountIdOf, BalanceOf> for Palle Ok(()) } - fn do_withdraw_collateral(supplier: &AccountIdOf, ptoken_amount: Amount) -> Result<(), DispatchError> { + fn do_withdraw_collateral( + supplier: &AccountIdOf, + asset_id: AssetIdOf, + amount: BalanceOf, + ) -> Result<(), DispatchError> { + let ptoken_amount: Amount = Amount::new(amount, asset_id); + // If the given asset_id is not a valid ptoken, fetching the underlying will fail let underlying_id = Self::underlying_id(ptoken_amount.currency())?; Self::ensure_active_market(underlying_id)?; let total_collateral_value = Self::total_collateral_value(supplier)?; - let collateral_asset_value = Self::collateral_asset_value(supplier, underlying_id)?; + let collateral_amount_value = Self::collateral_amount_value(supplier, underlying_id, ptoken_amount.amount())?; let total_borrowed_value = Self::total_borrowed_value(supplier)?; if total_collateral_value < total_borrowed_value - .checked_add(&collateral_asset_value) + .checked_add(&collateral_amount_value) .ok_or(ArithmeticError::Overflow)? { return Err(Error::::InsufficientLiquidity.into()); @@ -1915,8 +1917,8 @@ impl LoansTrait, AccountIdOf, BalanceOf> for Palle ptoken_amount.unlock_on(supplier)?; // Decrease the amount of collateral deposited - AccountDeposits::::try_mutate_exists(asset_id, who, |deposits| -> DispatchResult { - let mut d = deposits + AccountDeposits::::try_mutate_exists(asset_id, supplier, |deposits| -> DispatchResult { + let d = deposits .unwrap_or_default() .checked_sub(ptoken_amount.amount()) .ok_or(ArithmeticError::Underflow)?; @@ -2000,20 +2002,3 @@ impl LoansMarketDataProvider, BalanceOf> for Pallet LoansPositionDataProvider, AccountIdOf, BalanceOf> for Pallet { - fn get_current_borrow_balance( - borrower: &AccountIdOf, - asset_id: AssetIdOf, - ) -> Result, DispatchError> { - Self::accrue_interest(asset_id)?; - Self::current_borrow_balance(borrower, asset_id) - } - - fn get_current_collateral_balance( - supplier: &AccountIdOf, - asset_id: AssetIdOf, - ) -> Result, DispatchError> { - Self::current_collateral_balance(supplier, asset_id) - } -} diff --git a/crates/loans/src/ptoken.rs b/crates/loans/src/ptoken.rs index fca3da435e..1f3a9cc522 100644 --- a/crates/loans/src/ptoken.rs +++ b/crates/loans/src/ptoken.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{types::Deposits, AssetIdOf, BalanceOf, *}; +use crate::{AssetIdOf, BalanceOf, *}; use frame_support::{ require_transactional, traits::tokens::{ @@ -31,10 +31,11 @@ impl Inspect for Pallet { /// The total amount of issuance in the system. fn total_issuance(ptoken_id: Self::AssetId) -> Self::Balance { if let Ok(underlying_id) = Self::underlying_id(ptoken_id) { - Self::total_supply(underlying_id) - } else { - Balance::default() + if let Ok(supply) = Self::total_supply(underlying_id) { + return supply; + } } + Balance::default() } /// The minimum balance any single account may have. @@ -44,11 +45,7 @@ impl Inspect for Pallet { /// Get the ptoken balance of `who`. fn balance(ptoken_id: Self::AssetId, who: &T::AccountId) -> Self::Balance { - if let Ok(underlying_id) = Self::underlying_id(ptoken_id) { - Self::account_deposits(underlying_id, who).voucher_balance - } else { - Balance::default() - } + as MultiCurrency>::total_balance(ptoken_id, who) } /// Get the maximum amount that `who` can withdraw/transfer successfully. @@ -73,8 +70,12 @@ impl Inspect for Pallet { return res; } - if Self::total_supply(underlying_id).checked_add(amount).is_none() { - return DepositConsequence::Overflow; + if let Ok(total_supply) = Self::total_supply(underlying_id) { + if total_supply.checked_add(amount).is_none() { + return DepositConsequence::Overflow; + } + } else { + return DepositConsequence::UnknownAsset; } if Self::balance(ptoken_id, who) + amount < Self::minimum_balance(ptoken_id) { @@ -126,12 +127,8 @@ impl Transfer for Pallet { amount: Self::Balance, _keep_alive: bool, ) -> Result, DispatchError> { - ensure!( - amount <= Self::reducible_balance(ptoken_id, source, false), - Error::::InsufficientCollateral - ); - - Self::do_transfer_ptokens(ptoken_id, source, dest, amount)?; + as MultiCurrency>::transfer(ptoken_id, source, dest, amount) + .map_err(|_| Error::::InsufficientCollateral)?; Ok(amount) } } @@ -150,43 +147,34 @@ impl Pallet { Self::distribute_supplier_reward(ptoken_id, dest)?; let underlying_id = Self::underlying_id(ptoken_id)?; - AccountDeposits::::try_mutate_exists(underlying_id, source, |deposits| -> DispatchResult { - let mut d = deposits.unwrap_or_default(); - d.voucher_balance = d - .voucher_balance - .checked_sub(amount) - .ok_or(ArithmeticError::Underflow)?; - if d.voucher_balance.is_zero() { - // remove deposits storage if zero balance - *deposits = None; - } else { - *deposits = Some(d); - } - Ok(()) - })?; - - AccountDeposits::::try_mutate(underlying_id, &dest, |deposits| -> DispatchResult { - deposits.voucher_balance = deposits - .voucher_balance - .checked_add(amount) - .ok_or(ArithmeticError::Overflow)?; - Ok(()) - })?; + // AccountDeposits::::try_mutate_exists(underlying_id, source, |deposits| -> DispatchResult { + // let mut d = deposits.unwrap_or_default(); + // d = d + // .checked_sub(amount) + // .ok_or(ArithmeticError::Underflow)?; + // if d.is_zero() { + // // remove deposits storage if zero balance + // *deposits = None; + // } else { + // *deposits = Some(d); + // } + // Ok(()) + // })?; + + // AccountDeposits::::try_mutate(underlying_id, &dest, |deposits| -> DispatchResult { + // deposits = &mut deposits + // .checked_add(amount) + // .ok_or(ArithmeticError::Overflow)?; + // Ok(()) + // })?; Ok(()) } fn reducible_asset(ptoken_id: AssetIdOf, who: &T::AccountId) -> Result, DispatchError> { - let underlying_id = Self::underlying_id(ptoken_id)?; - let Deposits { - is_collateral, - voucher_balance, - } = Self::account_deposits(underlying_id, &who); - - if !is_collateral { - return Ok(voucher_balance); - } + let voucher_balance = Self::account_deposits(ptoken_id, &who); + let underlying_id = Self::underlying_id(ptoken_id)?; let market = Self::ensure_active_market(underlying_id)?; let collateral_value = Self::collateral_asset_value(who, underlying_id)?; diff --git a/crates/loans/src/tests.rs b/crates/loans/src/tests.rs index adaac3dace..9a65993c07 100644 --- a/crates/loans/src/tests.rs +++ b/crates/loans/src/tests.rs @@ -85,7 +85,7 @@ fn loans_native_token_works() { // Redeem 1000 HKO is ok assert_ok!(Loans::redeem_allowed(HKO, &DAVE, unit(50000),)); - assert_ok!(Loans::collateral_asset(Origin::signed(DAVE), HKO, true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(DAVE), HKO)); // Borrow 500 HKO will reduce 500 HKO liquidity for collateral_factor is 50% assert_ok!(Loans::borrow(Origin::signed(DAVE), HKO, unit(500))); @@ -96,7 +96,7 @@ fn loans_native_token_works() { // HKO borrow balance: borrow - repay = 500 - 400 = 100 // HKO: cash - deposit + borrow - repay = 1000 - 1000 + 500 - 400 = 100 assert_eq!( - Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(HKO, DAVE).voucher_balance), + Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(HKO).unwrap(), DAVE)), unit(1000) ); let borrow_snapshot = Loans::account_borrows(HKO, DAVE); @@ -115,7 +115,7 @@ fn mint_works() { // DOT collateral: deposit = 100 // DOT: cash - deposit = 1000 - 100 = 900 assert_eq!( - Loans::exchange_rate(DOT).saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), + Loans::exchange_rate(DOT).saturating_mul_int(Loans::free_ptoken_balance(DOT, &ALICE).unwrap()), unit(100) ); assert_eq!(Tokens::balance(DOT, &ALICE), unit(900),); @@ -184,7 +184,7 @@ fn redeem_allowed_works() { // Redeem 200 KSM is ok assert_ok!(Loans::redeem_allowed(KSM, &ALICE, 10000)); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), KSM, true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), KSM)); // Borrow 50 DOT will reduce 100 KSM liquidity for collateral_factor is 50% assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, 50)); // Redeem 101 KSM should cause InsufficientLiquidity @@ -206,7 +206,7 @@ fn redeem_works() { // DOT collateral: deposit - redeem = 100 - 20 = 80 // DOT: cash - deposit + redeem = 1000 - 100 + 20 = 920 assert_eq!( - Loans::exchange_rate(DOT).saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), + Loans::exchange_rate(DOT).saturating_mul_int(Tokens::balance(Loans::ptoken_id(DOT).unwrap(), &ALICE)), unit(80) ); assert_eq!(Tokens::balance(DOT, &ALICE), unit(920),); @@ -232,7 +232,7 @@ fn redeem_fails_when_insufficient_liquidity() { // Deposit 200 KSM as collateral assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, 200)); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), KSM, true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), KSM)); // Borrow 50 DOT will reduce 100 KSM liquidity for collateral_factor is 50% assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, 50)); @@ -252,7 +252,7 @@ fn redeem_fails_when_would_use_reserved_balanace() { // Deposit 200 KSM as collateral assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, 200)); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), KSM, true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), KSM)); // Borrow 50 DOT will reduce 100 KSM liquidity for collateral_factor is 50% assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, 50)); assert_ok!(Loans::add_reserves(Origin::root(), ALICE, DOT, 50)); @@ -292,7 +292,8 @@ fn redeem_all_works() { // DOT: cash - deposit + redeem = 1000 - 100 + 100 = 1000 // DOT collateral: deposit - redeem = 100 - 100 = 0 assert_eq!( - Loans::exchange_rate(DOT).saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), + Loans::exchange_rate(DOT) + .saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(DOT).unwrap(), ALICE)), 0, ); assert_eq!(Tokens::balance(DOT, &ALICE), unit(1000),); @@ -306,7 +307,7 @@ fn borrow_allowed_works() { // Deposit 200 DOT as collateral assert_ok!(Loans::mint(Origin::signed(BOB), DOT, 200)); assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, 200)); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), KSM, true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), KSM)); // Borrow 101 DOT should cause InsufficientLiquidity assert_noop!( Loans::borrow_allowed(DOT, &ALICE, 101), @@ -338,7 +339,7 @@ fn borrow_allowed_works() { fn get_account_liquidity_works() { new_test_ext().execute_with(|| { Loans::mint(Origin::signed(ALICE), CDOT_6_13, unit(200)).unwrap(); - Loans::collateral_asset(Origin::signed(ALICE), CDOT_6_13, true).unwrap(); + Loans::deposit_all_collateral(Origin::signed(ALICE), CDOT_6_13).unwrap(); let (liquidity, _, _, _) = Loans::get_account_liquidity(&ALICE).unwrap(); @@ -353,10 +354,10 @@ fn get_account_liquidation_threshold_liquidity_works() { Loans::mint(Origin::signed(BOB), KSM, unit(200)).unwrap(); Loans::mint(Origin::signed(ALICE), CDOT_6_13, unit(200)).unwrap(); - Loans::collateral_asset(Origin::signed(ALICE), CDOT_6_13, true).unwrap(); + Loans::deposit_all_collateral(Origin::signed(ALICE), CDOT_6_13).unwrap(); Loans::mint(Origin::signed(ALICE), USDT, unit(200)).unwrap(); - Loans::collateral_asset(Origin::signed(ALICE), USDT, true).unwrap(); + Loans::deposit_all_collateral(Origin::signed(ALICE), USDT).unwrap(); Loans::borrow(Origin::signed(ALICE), KSM, unit(100)).unwrap(); Loans::borrow(Origin::signed(ALICE), DOT, unit(100)).unwrap(); @@ -378,7 +379,7 @@ fn borrow_works() { new_test_ext().execute_with(|| { // Deposit 200 DOT as collateral assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), DOT)); // Borrow 100 DOT assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(100))); @@ -386,7 +387,8 @@ fn borrow_works() { // DOT borrow balance: borrow = 100 // DOT: cash - deposit + borrow = 1000 - 200 + 100 = 900 assert_eq!( - Loans::exchange_rate(DOT).saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), + Loans::exchange_rate(DOT) + .saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(DOT).unwrap(), ALICE)), unit(200) ); let borrow_snapshot = Loans::account_borrows(DOT, ALICE); @@ -402,7 +404,7 @@ fn lf_borrow_works() { // Deposit 200 DOT as collateral Loans::mint(Origin::signed(ALICE), CDOT_6_13, unit(200)).unwrap(); Loans::mint(Origin::signed(DAVE), DOT, unit(200)).unwrap(); - Loans::collateral_asset(Origin::signed(ALICE), CDOT_6_13, true).unwrap(); + Loans::deposit_all_collateral(Origin::signed(ALICE), CDOT_6_13).unwrap(); // Borrow 100 DOT assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(100))); @@ -412,7 +414,7 @@ fn lf_borrow_works() { // DOT: cash - deposit + borrow = 1000 + 100 = 1100 assert_eq!( Loans::exchange_rate(CDOT_6_13) - .saturating_mul_int(Loans::account_deposits(CDOT_6_13, ALICE).voucher_balance), + .saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(CDOT_6_13).unwrap(), ALICE)), unit(200) ); let borrow_snapshot = Loans::account_borrows(DOT, ALICE); @@ -427,7 +429,7 @@ fn repay_borrow_works() { new_test_ext().execute_with(|| { // Deposit 200 DOT as collateral assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), DOT)); // Borrow 100 DOT assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(100))); // Repay 30 DOT @@ -437,7 +439,8 @@ fn repay_borrow_works() { // DOT borrow balance: borrow - repay = 100 - 30 = 70 // DOT: cash - deposit + borrow - repay = 1000 - 200 + 100 - 30 = 870 assert_eq!( - Loans::exchange_rate(DOT).saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), + Loans::exchange_rate(DOT) + .saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(DOT).unwrap(), ALICE)), unit(200) ); let borrow_snapshot = Loans::account_borrows(DOT, ALICE); @@ -454,7 +457,7 @@ fn repay_borrow_all_works() { assert_ok!(Loans::mint(Origin::signed(BOB), KSM, unit(200))); // Alice deposit 200 DOT as collateral assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), DOT)); // Alice borrow 50 KSM assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(50))); @@ -467,7 +470,8 @@ fn repay_borrow_all_works() { // KSM borrow balance: borrow - repay = 50 - 50 = 0 assert_eq!(Tokens::balance(DOT, &ALICE), unit(800),); assert_eq!( - Loans::exchange_rate(DOT).saturating_mul_int(Loans::account_deposits(DOT, ALICE).voucher_balance), + Loans::exchange_rate(DOT) + .saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(DOT).unwrap(), ALICE)), unit(200) ); let borrow_snapshot = Loans::account_borrows(KSM, ALICE); @@ -480,32 +484,29 @@ fn repay_borrow_all_works() { fn collateral_asset_works() { new_test_ext().execute_with(|| { // No collateral assets - assert_noop!( - Loans::collateral_asset(Origin::signed(ALICE), DOT, true), - Error::::NoDeposit - ); // Deposit 200 DOT as collateral assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, 200)); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); - assert_eq!(Loans::account_deposits(DOT, ALICE).is_collateral, true); - assert_noop!( - Loans::collateral_asset(Origin::signed(ALICE), DOT, true), - Error::::DuplicateOperation + // No ptokens deposited as collateral + assert_eq!( + Loans::account_deposits(Loans::ptoken_id(DOT).unwrap(), ALICE).eq(&0), + true + ); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), DOT)); + // Non-zero ptokens deposited as collateral + assert_eq!( + Loans::account_deposits(Loans::ptoken_id(DOT).unwrap(), ALICE).gt(&0), + true ); // Borrow 100 DOT base on the collateral of 200 DOT assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, 100)); assert_noop!( - Loans::collateral_asset(Origin::signed(ALICE), DOT, false), + Loans::withdraw_all_collateral(Origin::signed(ALICE), DOT), Error::::InsufficientLiquidity ); // Repay all the borrows assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), DOT)); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, false)); - assert_eq!(Loans::account_deposits(DOT, ALICE).is_collateral, false); - assert_noop!( - Loans::collateral_asset(Origin::signed(ALICE), DOT, false), - Error::::DuplicateOperation - ); + assert_ok!(Loans::withdraw_all_collateral(Origin::signed(ALICE), DOT)); + assert_eq!(Loans::account_deposits(Loans::ptoken_id(DOT).unwrap(), ALICE), 0); }) } @@ -517,8 +518,8 @@ fn total_collateral_value_works() { assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(100))); assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, unit(200))); assert_ok!(Loans::mint(Origin::signed(ALICE), USDT, unit(300))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), KSM, true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), DOT)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), KSM)); assert_eq!( Loans::total_collateral_value(&ALICE).unwrap(), (collateral_factor.saturating_mul(FixedU128::from_inner(unit(100) + unit(200)))) @@ -671,8 +672,6 @@ fn update_exchange_rate_works() { // Initialize value of exchange rate is 0.02 assert_eq!(Loans::exchange_rate(DOT), Rate::saturating_from_rational(2, 100)); - // total_supply = 0 - TotalSupply::::insert(DOT, 0); // assert_ok!(Loans::update_exchange_rate(DOT)); assert_eq!( Loans::exchange_rate_stored(DOT).unwrap(), @@ -856,8 +855,8 @@ fn reward_calculation_one_palyer_in_multi_markets_works() { new_test_ext().execute_with(|| { assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(100))); assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, unit(100))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), KSM, true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), DOT)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), KSM)); assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(10))); assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(10))); @@ -1027,8 +1026,8 @@ fn reward_calculation_multi_player_in_one_market_works() { new_test_ext().execute_with(|| { assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(10))); assert_ok!(Loans::mint(Origin::signed(BOB), DOT, unit(10))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); - assert_ok!(Loans::collateral_asset(Origin::signed(BOB), DOT, true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), DOT)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(BOB), DOT)); _run_to_block(10); assert_ok!(Loans::update_market_reward_speed( @@ -1080,6 +1079,10 @@ fn reward_calculation_multi_player_in_one_market_works() { _run_to_block(50); assert_ok!(Loans::redeem(Origin::signed(ALICE), DOT, unit(10))); + // Withdraw all collateral first, so `redeem_all()` redeems collateral as well. + // This is a change from Parallel's original implementation, where `redeem_all` + // would implicitly withdraw all collateral. + assert_ok!(Loans::withdraw_all_collateral(Origin::signed(BOB), DOT)); assert_ok!(Loans::redeem_all(Origin::signed(BOB), DOT)); assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), DOT)); assert_ok!(Loans::repay_borrow_all(Origin::signed(BOB), DOT)); @@ -1120,9 +1123,9 @@ fn reward_calculation_multi_player_in_one_market_works() { fn reward_calculation_after_liquidate_borrow_works() { new_test_ext().execute_with(|| { assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), DOT, true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), DOT)); assert_ok!(Loans::mint(Origin::signed(BOB), KSM, unit(500))); - assert_ok!(Loans::collateral_asset(Origin::signed(BOB), KSM, true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(BOB), KSM)); assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(50))); assert_ok!(Loans::borrow(Origin::signed(BOB), KSM, unit(75))); diff --git a/crates/loans/src/tests/edge_cases.rs b/crates/loans/src/tests/edge_cases.rs index df410e229b..153861105a 100644 --- a/crates/loans/src/tests/edge_cases.rs +++ b/crates/loans/src/tests/edge_cases.rs @@ -30,7 +30,7 @@ fn repay_borrow_all_no_underflow() { new_test_ext().execute_with(|| { // Alice deposits 200 KSM as collateral assert_ok!(Loans::mint(Origin::signed(ALICE), Token(KSM), unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(KSM), true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), Token(KSM))); // Alice borrow only 1/1e5 KSM which is hard to accrue total borrows interest in 100 seconds assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(KSM), 10_u128.pow(7))); @@ -50,7 +50,7 @@ fn repay_borrow_all_no_underflow() { assert_eq!( Loans::exchange_rate(Token(DOT)) - .saturating_mul_int(Loans::account_deposits(Token(KSM), ALICE).voucher_balance), + .saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(Token(KSM)).unwrap(), ALICE)), unit(200) ); @@ -74,7 +74,7 @@ fn ensure_capacity_fails_when_market_not_existed() { fn redeem_all_should_be_accurate() { new_test_ext().execute_with(|| { assert_ok!(Loans::mint(Origin::signed(ALICE), Token(KSM), unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(KSM), true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), Token(KSM))); assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(KSM), unit(50))); // let exchange_rate greater than 0.02 @@ -111,7 +111,7 @@ fn prevent_the_exchange_rate_attack() { assert_eq!(Tokens::balance(Token(DOT), &EVE), 99999999999999); assert_eq!(Tokens::balance(Token(DOT), &Loans::account_id()), 100000000000001); assert_eq!( - Loans::total_supply(Token(DOT)), + Loans::total_supply(Token(DOT)).unwrap(), 1 * 50, // 1 / 0.02 ); TimestampPallet::set_timestamp(12000); diff --git a/crates/loans/src/tests/interest_rate.rs b/crates/loans/src/tests/interest_rate.rs index 0eaab88f98..6f5e75cfef 100644 --- a/crates/loans/src/tests/interest_rate.rs +++ b/crates/loans/src/tests/interest_rate.rs @@ -30,12 +30,12 @@ fn interest_rate_model_works() { Tokens::set_balance(Origin::root(), ALICE, Token(DOT), million_unit(1000) - unit(1000), 0).unwrap(); // Deposit 200 DOT and borrow 100 DOT assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), million_unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), Token(DOT))); assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), million_unit(100))); let total_cash = million_unit(200) - million_unit(100); let total_supply = Loans::calc_collateral_amount(million_unit(200), Loans::exchange_rate(Token(DOT))).unwrap(); - assert_eq!(Loans::total_supply(Token(DOT)), total_supply); + assert_eq!(Loans::total_supply(Token(DOT)).unwrap(), total_supply); let borrow_snapshot = Loans::account_borrows(Token(DOT), ALICE); assert_eq!(borrow_snapshot.principal, million_unit(100)); @@ -113,7 +113,7 @@ fn last_accrued_interest_time_should_be_update_correctly() { assert_eq!(Loans::last_accrued_interest_time(Token(DOT)), 0); assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); assert_eq!(Loans::last_accrued_interest_time(Token(DOT)), 6); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), Token(DOT))); assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), unit(100))); assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); TimestampPallet::set_timestamp(12000); @@ -126,7 +126,7 @@ fn last_accrued_interest_time_should_be_update_correctly() { fn accrue_interest_works_after_mint() { new_test_ext().execute_with(|| { assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), Token(DOT))); assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), unit(100))); assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); TimestampPallet::set_timestamp(12000); @@ -139,7 +139,7 @@ fn accrue_interest_works_after_mint() { fn accrue_interest_works_after_borrow() { new_test_ext().execute_with(|| { assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), Token(DOT))); assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); TimestampPallet::set_timestamp(12000); assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), unit(100))); @@ -151,15 +151,26 @@ fn accrue_interest_works_after_borrow() { fn accrue_interest_works_after_redeem() { new_test_ext().execute_with(|| { assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), Token(DOT))); assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), unit(10))); assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); TimestampPallet::set_timestamp(12000); - assert_ok!(Loans::redeem(Origin::signed(ALICE), Token(DOT), unit(10))); + + let amount_to_redeem = unit(10); + // First, withdraw the amount to redeem from the deposited collateral + let exchange_rate = Loans::exchange_rate_stored(Token(DOT)).unwrap(); + let ptoken_amount = Loans::calc_collateral_amount(amount_to_redeem, exchange_rate).unwrap(); + assert_ok!(Loans::withdraw_collateral( + Origin::signed(ALICE), + Loans::ptoken_id(Token(DOT)).unwrap(), + ptoken_amount + )); + // Then the amount can be redeemed + assert_ok!(Loans::redeem(Origin::signed(ALICE), Token(DOT), amount_to_redeem)); assert_eq!(Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000004756468797),); assert_eq!( Loans::exchange_rate(Token(DOT)) - .saturating_mul_int(Loans::account_deposits(Token(DOT), BOB).voucher_balance), + .saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(Token(DOT)).unwrap(), BOB)), 0, ); assert_eq!(Tokens::balance(Token(DOT), &ALICE), 819999999999999); @@ -169,9 +180,10 @@ fn accrue_interest_works_after_redeem() { #[test] fn accrue_interest_works_after_redeem_all() { new_test_ext().execute_with(|| { + assert_eq!(Tokens::balance(Token(DOT), &BOB), 1000000000000000); assert_ok!(Loans::mint(Origin::signed(BOB), Token(DOT), unit(20))); assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), Token(DOT))); assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), unit(10))); assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); TimestampPallet::set_timestamp(12000); @@ -179,7 +191,7 @@ fn accrue_interest_works_after_redeem_all() { assert_eq!(Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000004669977168),); assert_eq!( Loans::exchange_rate(Token(DOT)) - .saturating_mul_int(Loans::account_deposits(Token(DOT), BOB).voucher_balance), + .saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(Token(DOT)).unwrap(), BOB)), 0, ); assert_eq!(Tokens::balance(Token(DOT), &BOB), 1000000000003608); @@ -191,7 +203,7 @@ fn accrue_interest_works_after_redeem_all() { fn accrue_interest_works_after_repay() { new_test_ext().execute_with(|| { assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), Token(DOT))); assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), unit(20))); assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); TimestampPallet::set_timestamp(12000); @@ -205,7 +217,7 @@ fn accrue_interest_works_after_repay_all() { new_test_ext().execute_with(|| { assert_ok!(Loans::mint(Origin::signed(BOB), Token(KSM), unit(200))); assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), Token(DOT))); assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(KSM), unit(50))); assert_eq!(Loans::borrow_index(Token(KSM)), Rate::one()); TimestampPallet::set_timestamp(12000); @@ -225,7 +237,7 @@ fn accrue_interest_works_after_liquidate_borrow() { assert_ok!(Loans::mint(Origin::signed(BOB), Token(KSM), unit(200))); // Alice deposits 300 DOT as collateral assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(300))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), Token(DOT))); // Alice borrows 100 KSM and 50 DOT assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(KSM), unit(100))); assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), unit(50))); @@ -251,9 +263,9 @@ fn accrue_interest_works_after_liquidate_borrow() { fn different_markets_can_accrue_interest_in_one_block() { new_test_ext().execute_with(|| { assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), Token(DOT))); assert_ok!(Loans::mint(Origin::signed(ALICE), Token(KSM), unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(KSM), true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), Token(KSM))); assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); assert_eq!(Loans::borrow_index(Token(KSM)), Rate::one()); TimestampPallet::set_timestamp(12000); @@ -268,9 +280,9 @@ fn different_markets_can_accrue_interest_in_one_block() { fn a_market_can_only_accrue_interest_once_in_a_block() { new_test_ext().execute_with(|| { assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), Token(DOT), true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), Token(DOT))); assert_ok!(Loans::mint(Origin::signed(BOB), Token(DOT), unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(BOB), Token(DOT), true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(BOB), Token(DOT))); assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); TimestampPallet::set_timestamp(12000); assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), unit(100))); diff --git a/crates/loans/src/tests/liquidate_borrow.rs b/crates/loans/src/tests/liquidate_borrow.rs index 6abe1157a2..c357065643 100644 --- a/crates/loans/src/tests/liquidate_borrow.rs +++ b/crates/loans/src/tests/liquidate_borrow.rs @@ -52,9 +52,17 @@ fn deposit_of_borrower_must_be_collateral() { Loans::liquidate_borrow_allowed(&ALICE, KSM, unit(51), &market), Error::::TooMuchRepay ); + + // Previously (in Parallel's original implementation), this extrinsic call used to + // return a `DepositsAreNotCollateral` error. + // However, because the collateral "toggle" has been removed, the extrinsic looks + // directly inside the `AccountDeposits` map, which no longer represents ptoken holdings + // but rather ptokens that have been locked as collateral. + // Since no KSM ptokens have been locked as collateral in this test, there will be zero + // collateral available for paying the liquidator, thus producing the error below. assert_noop!( Loans::liquidate_borrow(Origin::signed(BOB), ALICE, KSM, 10, DOT), - Error::::DepositsAreNotCollateral + Error::::InsufficientCollateral ); }) } @@ -97,22 +105,24 @@ fn full_workflow_works_as_expected() { // Bob DOT collateral: incentive = 110-(110/1.1*0.03)=107 assert_eq!(Tokens::balance(USDT, &ALICE), unit(800),); assert_eq!( - Loans::exchange_rate(USDT).saturating_mul_int(Loans::account_deposits(USDT, ALICE).voucher_balance), + Loans::exchange_rate(USDT).saturating_mul_int(Tokens::balance(Loans::ptoken_id(USDT).unwrap(), &ALICE)), unit(90), ); assert_eq!(Tokens::balance(KSM, &ALICE), unit(1100),); assert_eq!(Loans::account_borrows(KSM, ALICE).principal, unit(50)); assert_eq!(Tokens::balance(KSM, &BOB), unit(750)); assert_eq!( - Loans::exchange_rate(USDT).saturating_mul_int(Loans::account_deposits(USDT, BOB).voucher_balance), + Loans::exchange_rate(USDT).saturating_mul_int(Tokens::balance(Loans::ptoken_id(USDT).unwrap(), &BOB)), unit(107), ); // 3 dollar reserved in our incentive reward account let incentive_reward_account = Loans::incentive_reward_account_id().unwrap(); println!("incentive reserve account:{:?}", incentive_reward_account.clone()); assert_eq!( - Loans::exchange_rate(USDT) - .saturating_mul_int(Loans::account_deposits(USDT, incentive_reward_account.clone()).voucher_balance), + Loans::exchange_rate(USDT).saturating_mul_int(Tokens::balance( + Loans::ptoken_id(USDT).unwrap(), + &incentive_reward_account.clone() + )), unit(3), ); assert_eq!(Tokens::balance(USDT, &ALICE), unit(800),); @@ -120,8 +130,10 @@ fn full_workflow_works_as_expected() { assert_ok!(Loans::reduce_incentive_reserves(Origin::root(), ALICE, USDT, unit(2),)); // still 1 dollar left in reserve account assert_eq!( - Loans::exchange_rate(USDT) - .saturating_mul_int(Loans::account_deposits(USDT, incentive_reward_account).voucher_balance), + Loans::exchange_rate(USDT).saturating_mul_int(Tokens::balance( + Loans::ptoken_id(USDT).unwrap(), + &incentive_reward_account + )), unit(1), ); // 2 dollar transfer to alice @@ -180,5 +192,5 @@ fn initial_setup() { assert_ok!(Loans::mint(Origin::signed(BOB), KSM, unit(200))); // Alice deposits 200 DOT as collateral assert_ok!(Loans::mint(Origin::signed(ALICE), USDT, unit(200))); - assert_ok!(Loans::collateral_asset(Origin::signed(ALICE), USDT, true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), USDT)); } diff --git a/crates/loans/src/tests/ptokens.rs b/crates/loans/src/tests/ptokens.rs index 49911ecd4c..4198b21414 100644 --- a/crates/loans/src/tests/ptokens.rs +++ b/crates/loans/src/tests/ptokens.rs @@ -1,5 +1,5 @@ use crate::{ - mock::{market_mock, new_test_ext, Loans, Origin, Test, ALICE, DAVE}, + mock::{market_mock, new_test_ext, Loans, Origin, Test, Tokens, ALICE, DAVE}, tests::unit, Error, }; @@ -35,15 +35,16 @@ fn trait_inspect_methods_works() { // DAVE Deposit 100 HKO assert_ok!(Loans::mint(Origin::signed(DAVE), HKO, unit(100))); - assert_eq!(Loans::balance(PHKO, &DAVE), unit(100) * 50); + assert_eq!(Tokens::balance(PHKO, &DAVE), unit(100) * 50); - assert_eq!(Loans::reducible_balance(PHKO, &DAVE, true), unit(100) * 50); - assert_ok!(Loans::collateral_asset(Origin::signed(DAVE), HKO, true)); + // No collateral deposited yet, therefore no reducible balance + assert_eq!(Loans::reducible_balance(PHKO, &DAVE, true), 0); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(DAVE), HKO)); // Borrow 25 HKO will reduce 25 HKO liquidity for collateral_factor is 50% assert_ok!(Loans::borrow(Origin::signed(DAVE), HKO, unit(25))); assert_eq!( - Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(HKO, DAVE).voucher_balance), + Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(HKO).unwrap(), DAVE)), unit(100) ); @@ -57,10 +58,10 @@ fn trait_inspect_methods_works() { // Liquidity HKO = 25, USDT = 25 // ptokens = dollar(25 + 25) / 1 / 0.5 / 0.02 = dollar(50) * 100 assert_ok!(Loans::mint(Origin::signed(DAVE), USDT, unit(50))); - assert_eq!(Loans::balance(PUSDT, &DAVE), unit(50) * 50); - assert_eq!(Loans::reducible_balance(PUSDT, &DAVE, true), unit(25) * 2 * 50); + assert_eq!(Tokens::balance(PUSDT, &DAVE), unit(50) * 50); + assert_eq!(Loans::reducible_balance(PUSDT, &DAVE, true), 0); // enable USDT collateral - assert_ok!(Loans::collateral_asset(Origin::signed(DAVE), USDT, true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(DAVE), USDT)); assert_eq!(Loans::reducible_balance(PHKO, &DAVE, true), unit(25 + 25) * 2 * 50); assert_ok!(Loans::borrow(Origin::signed(DAVE), HKO, unit(50))); @@ -98,13 +99,13 @@ fn transfer_ptoken_works() { // DAVE HKO collateral: deposit = 100 // HKO: cash - deposit = 1000 - 100 = 900 assert_eq!( - Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(HKO, DAVE).voucher_balance), + Loans::exchange_rate(HKO).saturating_mul_int(Tokens::balance(Loans::ptoken_id(HKO).unwrap(), &DAVE)), unit(100) ); // ALICE HKO collateral: deposit = 0 assert_eq!( - Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(HKO, ALICE).voucher_balance), + Loans::exchange_rate(HKO).saturating_mul_int(Tokens::balance(Loans::ptoken_id(HKO).unwrap(), &ALICE)), unit(0) ); @@ -114,7 +115,7 @@ fn transfer_ptoken_works() { // DAVE HKO collateral: deposit = 50 assert_eq!( - Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(HKO, DAVE).voucher_balance), + Loans::exchange_rate(HKO).saturating_mul_int(Tokens::balance(Loans::ptoken_id(HKO).unwrap(), &DAVE)), unit(50) ); // DAVE Redeem 51 HKO should cause InsufficientDeposit @@ -125,7 +126,7 @@ fn transfer_ptoken_works() { // ALICE HKO collateral: deposit = 50 assert_eq!( - Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(HKO, ALICE).voucher_balance), + Loans::exchange_rate(HKO).saturating_mul_int(Tokens::balance(Loans::ptoken_id(HKO).unwrap(), &ALICE)), unit(50) ); // ALICE Redeem 50 HKO should be succeeded @@ -134,25 +135,34 @@ fn transfer_ptoken_works() { } #[test] -fn transfer_ptokens_under_collateral_works() { +fn transfer_ptokens_under_collateral_does_not_work() { new_test_ext().execute_with(|| { // DAVE Deposit 100 HKO assert_ok!(Loans::mint(Origin::signed(DAVE), HKO, unit(100))); - assert_ok!(Loans::collateral_asset(Origin::signed(DAVE), HKO, true)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(DAVE), HKO)); // Borrow 50 HKO will reduce 50 HKO liquidity for collateral_factor is 50% assert_ok!(Loans::borrow(Origin::signed(DAVE), HKO, unit(50))); // Repay 40 HKO assert_ok!(Loans::repay_borrow(Origin::signed(DAVE), HKO, unit(40))); - // Transfer 20 ptokens from DAVE to ALICE - Loans::transfer(PHKO, &DAVE, &ALICE, unit(20) * 50, true).unwrap(); + // Allowed to redeem 20 ptokens + assert_ok!(Loans::redeem_allowed(HKO, &DAVE, unit(20) * 50,)); + // Not allowed to transfer the same 20 ptokens because they are locked + assert_noop!( + Loans::transfer(PHKO, &DAVE, &ALICE, unit(20) * 50, true), + Error::::InsufficientCollateral + ); + // First, withdraw the tokens + assert_ok!(Loans::withdraw_collateral(Origin::signed(DAVE), PHKO, unit(20) * 50)); + // Then transfer them + assert_ok!(Loans::transfer(PHKO, &DAVE, &ALICE, unit(20) * 50, true),); // DAVE Deposit HKO = 100 - 20 = 80 // DAVE Borrow HKO = 0 + 50 - 40 = 10 // DAVE liquidity HKO = 80 * 0.5 - 10 = 30 assert_eq!( - Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(HKO, DAVE).voucher_balance), + Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(HKO).unwrap(), DAVE)), unit(80) ); // DAVE Borrow 31 HKO should cause InsufficientLiquidity @@ -164,7 +174,7 @@ fn transfer_ptokens_under_collateral_works() { // Assert ALICE Supply HKO 20 assert_eq!( - Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(HKO, ALICE).voucher_balance), + Loans::exchange_rate(HKO).saturating_mul_int(Tokens::balance(Loans::ptoken_id(HKO).unwrap(), &ALICE)), unit(20) ); // ALICE Redeem 20 HKO should be succeeded diff --git a/crates/traits/src/loans.rs b/crates/traits/src/loans.rs index 9a6d7c5653..d2a6e803d0 100644 --- a/crates/traits/src/loans.rs +++ b/crates/traits/src/loans.rs @@ -22,7 +22,9 @@ use sp_std::prelude::*; pub trait Loans { fn do_mint(supplier: &AccountId, asset_id: CurrencyId, amount: Balance) -> Result<(), DispatchError>; fn do_borrow(borrower: &AccountId, asset_id: CurrencyId, amount: Balance) -> Result<(), DispatchError>; - fn do_collateral_asset(supplier: &AccountId, asset_id: CurrencyId, enable: bool) -> Result<(), DispatchError>; + fn do_deposit_collateral(supplier: &AccountId, asset_id: CurrencyId, amount: Balance) -> Result<(), DispatchError>; + fn do_withdraw_collateral(supplier: &AccountId, asset_id: CurrencyId, amount: Balance) + -> Result<(), DispatchError>; fn do_repay_borrow(borrower: &AccountId, asset_id: CurrencyId, amount: Balance) -> Result<(), DispatchError>; fn do_redeem(supplier: &AccountId, asset_id: CurrencyId, amount: Balance) -> Result<(), DispatchError>; } From 9ec2ed0bfcc20857815c95eadd730350279a339a Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Thu, 13 Oct 2022 21:24:08 +0200 Subject: [PATCH 20/58] feat(loans): Replace T::Asset actions with Currency pallet --- crates/currency/src/mock.rs | 3 ++ crates/fee/src/mock.rs | 3 ++ crates/issue/src/mock.rs | 3 ++ crates/loans/src/benchmarking.rs | 3 +- crates/loans/src/farming.rs | 3 +- crates/loans/src/lib.rs | 53 +++++++++++++++++--------- crates/nomination/src/mock.rs | 3 ++ crates/oracle/src/mock.rs | 3 ++ crates/redeem/src/mock.rs | 3 ++ crates/replace/src/mock.rs | 3 ++ crates/staking/src/mock.rs | 3 ++ crates/vault-registry/src/mock.rs | 3 ++ standalone/runtime/tests/test_loans.rs | 8 ++-- 13 files changed, 69 insertions(+), 25 deletions(-) diff --git a/crates/currency/src/mock.rs b/crates/currency/src/mock.rs index 623fd761c2..69cac3794d 100644 --- a/crates/currency/src/mock.rs +++ b/crates/currency/src/mock.rs @@ -93,6 +93,9 @@ impl orml_tokens::Config for Test { type WeightInfo = (); type ExistentialDeposits = ExistentialDeposits; type OnDust = (); + type OnSlash = (); + type OnDeposit = (); + type OnTransfer = (); type MaxLocks = MaxLocks; type DustRemovalWhitelist = Everything; type MaxReserves = ConstU32<0>; // we don't use named reserves diff --git a/crates/fee/src/mock.rs b/crates/fee/src/mock.rs index af96839faf..1e5f70984e 100644 --- a/crates/fee/src/mock.rs +++ b/crates/fee/src/mock.rs @@ -106,6 +106,9 @@ impl orml_tokens::Config for Test { type WeightInfo = (); type ExistentialDeposits = ExistentialDeposits; type OnDust = (); + type OnSlash = (); + type OnDeposit = (); + type OnTransfer = (); type MaxLocks = MaxLocks; type DustRemovalWhitelist = Everything; type MaxReserves = ConstU32<0>; // we don't use named reserves diff --git a/crates/issue/src/mock.rs b/crates/issue/src/mock.rs index bd19d61552..c1041f3e47 100644 --- a/crates/issue/src/mock.rs +++ b/crates/issue/src/mock.rs @@ -116,6 +116,9 @@ impl orml_tokens::Config for Test { type WeightInfo = (); type ExistentialDeposits = ExistentialDeposits; type OnDust = (); + type OnSlash = (); + type OnDeposit = (); + type OnTransfer = (); type MaxLocks = MaxLocks; type DustRemovalWhitelist = Everything; type MaxReserves = ConstU32<0>; // we don't use named reserves diff --git a/crates/loans/src/benchmarking.rs b/crates/loans/src/benchmarking.rs index bd040659da..e36fbe54a7 100644 --- a/crates/loans/src/benchmarking.rs +++ b/crates/loans/src/benchmarking.rs @@ -111,7 +111,8 @@ fn set_account_borrows(who: T::AccountId, asset_id: AssetIdOf, bor }, ); TotalBorrows::::insert(asset_id, borrow_balance); - T::Assets::burn_from(asset_id, &who, borrow_balance).unwrap(); + let amount: Amount = Amount::new(borrow_balance, asset_id); + amount.burn_from(who)?; } fn assert_last_event(generic_event: ::Event) { diff --git a/crates/loans/src/farming.rs b/crates/loans/src/farming.rs index 996bbd001b..20a21ba530 100644 --- a/crates/loans/src/farming.rs +++ b/crates/loans/src/farming.rs @@ -190,7 +190,8 @@ impl Pallet { let reward_asset = T::RewardAssetId::get(); let total_reward = RewardAccrued::::get(user); if total_reward > 0 { - T::Assets::transfer(reward_asset, &pool_account, user, total_reward, true)?; + let amount: Amount = Amount::new(total_reward, reward_asset); + amount.transfer(&pool_account, user)?; RewardAccrued::::remove(user); } Self::deposit_event(Event::::RewardPaid(user.clone(), total_reward)); diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 33fe5dd9fc..cc3ff9e462 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -664,7 +664,8 @@ pub mod pallet { let reward_asset = T::RewardAssetId::get(); let pool_account = Self::reward_account_id()?; - T::Assets::transfer(reward_asset, &who, &pool_account, amount, true)?; + let amount_to_transfer: Amount = Amount::new(amount, reward_asset); + amount_to_transfer.transfer(&who, &pool_account)?; Self::deposit_event(Event::::RewardAdded(who, amount)); @@ -691,7 +692,9 @@ pub mod pallet { let pool_account = Self::reward_account_id()?; let target_account = T::Lookup::lookup(target_account)?; - T::Assets::transfer(reward_asset, &pool_account, &target_account, amount, true)?; + let amount_to_transfer: Amount = Amount::new(amount, reward_asset); + amount_to_transfer.transfer(&pool_account, &target_account)?; + Self::deposit_event(Event::::RewardWithdrawn(target_account, amount)); Ok(().into()) @@ -964,7 +967,8 @@ pub mod pallet { let payer = T::Lookup::lookup(payer)?; Self::ensure_active_market(asset_id)?; - T::Assets::transfer(asset_id, &payer, &Self::account_id(), add_amount, false)?; + let amount_to_transfer: Amount = Amount::new(add_amount, asset_id); + amount_to_transfer.transfer(&payer, &Self::account_id())?; let total_reserves = Self::total_reserves(asset_id); let total_reserves_new = total_reserves .checked_add(add_amount) @@ -1008,7 +1012,9 @@ pub mod pallet { .checked_sub(reduce_amount) .ok_or(ArithmeticError::Underflow)?; TotalReserves::::insert(asset_id, total_reserves_new); - T::Assets::transfer(asset_id, &Self::account_id(), &receiver, reduce_amount, false)?; + + let amount_to_transfer: Amount = Amount::new(reduce_amount, asset_id); + amount_to_transfer.transfer(&Self::account_id(), &receiver)?; Self::deposit_event(Event::::ReservesReduced( receiver, @@ -1040,7 +1046,10 @@ pub mod pallet { let exchange_rate = Self::exchange_rate_stored(asset_id)?; let voucher_amount = Self::calc_collateral_amount(redeem_amount, exchange_rate)?; let redeem_amount = Self::do_redeem_voucher(&from, asset_id, voucher_amount)?; - T::Assets::transfer(asset_id, &from, &receiver, redeem_amount, false)?; + + let amount_to_transfer: Amount = Amount::new(redeem_amount, asset_id); + amount_to_transfer.transfer(&from, &receiver)?; + Self::deposit_event(Event::::IncentiveReservesReduced(receiver, asset_id, redeem_amount)); Ok(().into()) } @@ -1313,8 +1322,11 @@ impl Pallet { ptoken_amount.lock_on(who)?; ptoken_amount.burn_from(who)?; - T::Assets::transfer(asset_id, &Self::account_id(), who, redeem_amount, false) + let amount_to_transfer: Amount = Amount::new(redeem_amount, asset_id); + amount_to_transfer + .transfer(&Self::account_id(), who) .map_err(|_| Error::::InsufficientCash)?; + Ok(redeem_amount) } @@ -1341,7 +1353,9 @@ impl Pallet { Self::update_reward_borrow_index(asset_id)?; Self::distribute_borrower_reward(asset_id, borrower)?; - T::Assets::transfer(asset_id, borrower, &Self::account_id(), repay_amount, false)?; + let amount_to_transfer: Amount = Amount::new(repay_amount, asset_id); + amount_to_transfer.transfer(borrower, &Self::account_id())?; + let account_borrows_new = account_borrows .checked_sub(repay_amount) .ok_or(ArithmeticError::Underflow)?; @@ -1544,13 +1558,8 @@ impl Pallet { // 1.liquidator repay borrower's debt, // transfer from liquidator to module account - T::Assets::transfer( - liquidation_asset_id, - liquidator, - &Self::account_id(), - repay_amount, - false, - )?; + let amount_to_transfer: Amount = Amount::new(repay_amount, liquidation_asset_id); + amount_to_transfer.transfer(liquidator, &Self::account_id())?; // 2.the system reduce borrower's debt let account_borrows = Self::current_borrow_balance(borrower, liquidation_asset_id)?; @@ -1627,7 +1636,7 @@ impl Pallet { fn ensure_under_supply_cap(asset_id: AssetIdOf, amount: BalanceOf) -> DispatchResult { let market = Self::market(asset_id)?; // Assets holded by market currently. - let current_cash = T::Assets::balance(asset_id, &Self::account_id()); + let current_cash = Self::balance(asset_id, &Self::account_id()); let total_cash = current_cash.checked_add(amount).ok_or(ArithmeticError::Overflow)?; ensure!(total_cash <= market.supply_cap, Error::::SupplyCapacityExceeded); @@ -1705,7 +1714,12 @@ impl Pallet { } fn get_total_cash(asset_id: AssetIdOf) -> BalanceOf { - T::Assets::reducible_balance(asset_id, &Self::account_id(), false) + orml_tokens::Pallet::::free_balance(asset_id, &Self::account_id()) + } + + /// Get the total balance of `who`. + fn balance(asset_id: AssetIdOf, who: &T::AccountId) -> BalanceOf { + as MultiCurrency>::total_balance(asset_id, who) } /// Total suply of lending tokens (ptokens), given the underlying @@ -1826,7 +1840,8 @@ impl LoansTrait, AccountIdOf, BalanceOf> for Palle let voucher_amount = Self::calc_collateral_amount(amount, exchange_rate)?; ensure!(!voucher_amount.is_zero(), Error::::InvalidExchangeRate); - T::Assets::transfer(asset_id, supplier, &Self::account_id(), amount, false)?; + let amount_to_transfer: Amount = Amount::new(amount, asset_id); + amount_to_transfer.transfer(supplier, &Self::account_id())?; let ptoken_id = Self::ptoken_id(asset_id)?; let ptokens_to_mint: Amount = Amount::new(voucher_amount, ptoken_id); @@ -1859,7 +1874,9 @@ impl LoansTrait, AccountIdOf, BalanceOf> for Palle }, ); TotalBorrows::::insert(asset_id, total_borrows_new); - T::Assets::transfer(asset_id, &Self::account_id(), borrower, amount, false)?; + let amount_to_transfer: Amount = Amount::new(amount, asset_id); + amount_to_transfer.transfer(&Self::account_id(), borrower)?; + Self::deposit_event(Event::::Borrowed(borrower.clone(), asset_id, amount)); Ok(()) } diff --git a/crates/nomination/src/mock.rs b/crates/nomination/src/mock.rs index f8183fa5f0..ff728e68e3 100644 --- a/crates/nomination/src/mock.rs +++ b/crates/nomination/src/mock.rs @@ -121,6 +121,9 @@ impl orml_tokens::Config for Test { type WeightInfo = (); type ExistentialDeposits = ExistentialDeposits; type OnDust = (); + type OnSlash = (); + type OnDeposit = (); + type OnTransfer = (); type MaxLocks = MaxLocks; type DustRemovalWhitelist = Everything; type MaxReserves = ConstU32<0>; // we don't use named reserves diff --git a/crates/oracle/src/mock.rs b/crates/oracle/src/mock.rs index a4ab06c0a2..b794fa02b4 100644 --- a/crates/oracle/src/mock.rs +++ b/crates/oracle/src/mock.rs @@ -104,6 +104,9 @@ impl orml_tokens::Config for Test { type WeightInfo = (); type ExistentialDeposits = ExistentialDeposits; type OnDust = (); + type OnSlash = (); + type OnDeposit = (); + type OnTransfer = (); type MaxLocks = MaxLocks; type DustRemovalWhitelist = Everything; type MaxReserves = ConstU32<0>; // we don't use named reserves diff --git a/crates/redeem/src/mock.rs b/crates/redeem/src/mock.rs index f954cd6d45..532daaf978 100644 --- a/crates/redeem/src/mock.rs +++ b/crates/redeem/src/mock.rs @@ -122,6 +122,9 @@ impl orml_tokens::Config for Test { type WeightInfo = (); type ExistentialDeposits = ExistentialDeposits; type OnDust = (); + type OnSlash = (); + type OnDeposit = (); + type OnTransfer = (); type MaxLocks = MaxLocks; type DustRemovalWhitelist = Everything; type MaxReserves = ConstU32<0>; // we don't use named reserves diff --git a/crates/replace/src/mock.rs b/crates/replace/src/mock.rs index 5beb227494..8bc9c0f52a 100644 --- a/crates/replace/src/mock.rs +++ b/crates/replace/src/mock.rs @@ -117,6 +117,9 @@ impl orml_tokens::Config for Test { type WeightInfo = (); type ExistentialDeposits = ExistentialDeposits; type OnDust = (); + type OnSlash = (); + type OnDeposit = (); + type OnTransfer = (); type MaxLocks = MaxLocks; type DustRemovalWhitelist = Everything; type MaxReserves = ConstU32<0>; // we don't use named reserves diff --git a/crates/staking/src/mock.rs b/crates/staking/src/mock.rs index ad630e61bd..7e2b9b22b9 100644 --- a/crates/staking/src/mock.rs +++ b/crates/staking/src/mock.rs @@ -98,6 +98,9 @@ impl orml_tokens::Config for Test { type WeightInfo = (); type ExistentialDeposits = ExistentialDeposits; type OnDust = (); + type OnSlash = (); + type OnDeposit = (); + type OnTransfer = (); type MaxLocks = MaxLocks; type DustRemovalWhitelist = Everything; type MaxReserves = ConstU32<0>; // we don't use named reserves diff --git a/crates/vault-registry/src/mock.rs b/crates/vault-registry/src/mock.rs index 40e95c759e..2d286d4bb7 100644 --- a/crates/vault-registry/src/mock.rs +++ b/crates/vault-registry/src/mock.rs @@ -117,6 +117,9 @@ impl orml_tokens::Config for Test { type WeightInfo = (); type ExistentialDeposits = ExistentialDeposits; type OnDust = (); + type OnSlash = (); + type OnDeposit = (); + type OnTransfer = (); type MaxLocks = MaxLocks; type DustRemovalWhitelist = Everything; type MaxReserves = ConstU32<0>; // we don't use named reserves diff --git a/standalone/runtime/tests/test_loans.rs b/standalone/runtime/tests/test_loans.rs index 0fcf95edf3..bbc737cc21 100644 --- a/standalone/runtime/tests/test_loans.rs +++ b/standalone/runtime/tests/test_loans.rs @@ -80,11 +80,9 @@ fn integration_test_liquidation() { }) .dispatch(origin_of(account_of(LP)))); - assert_ok!(Call::Loans(LoansCall::collateral_asset { - asset_id: kint, - enable: true, - }) - .dispatch(origin_of(account_of(USER)))); + assert_ok!( + Call::Loans(LoansCall::deposit_all_collateral { asset_id: kint }).dispatch(origin_of(account_of(USER))) + ); assert_err!( Call::Loans(LoansCall::borrow { From 7fd05bb72df53b92a5e112a259ff90f758e27eec Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Thu, 13 Oct 2022 21:38:14 +0200 Subject: [PATCH 21/58] feat(loans): clean up ptoken module --- crates/loans/src/lib.rs | 15 ++--- crates/loans/src/ptoken.rs | 78 +++++----------------- crates/loans/src/tests.rs | 2 +- crates/loans/src/tests/liquidate_borrow.rs | 2 +- 4 files changed, 22 insertions(+), 75 deletions(-) diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index cc3ff9e462..78d98ec876 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -1186,11 +1186,7 @@ impl Pallet { Ok(total_borrow_value) } - fn collateral_balance( - supplier: &T::AccountId, - asset_id: AssetIdOf, - ptoken_amount: BalanceOf, - ) -> Result, DispatchError> { + fn collateral_balance(asset_id: AssetIdOf, ptoken_amount: BalanceOf) -> Result, DispatchError> { let exchange_rate = Self::exchange_rate_stored(asset_id)?; let underlying_amount = Self::calc_underlying_amount(ptoken_amount, exchange_rate)?; let market = Self::market(asset_id)?; @@ -1200,11 +1196,10 @@ impl Pallet { } fn collateral_amount_value( - supplier: &T::AccountId, asset_id: AssetIdOf, ptoken_amount: BalanceOf, ) -> Result { - let effects_amount = Self::collateral_balance(supplier, asset_id, ptoken_amount)?; + let effects_amount = Self::collateral_balance(asset_id, ptoken_amount)?; Self::get_asset_value(asset_id, effects_amount) } @@ -1217,7 +1212,7 @@ impl Pallet { if deposits.is_zero() { return Ok(0.into()); } - Self::collateral_amount_value(supplier, asset_id, deposits) + Self::collateral_amount_value(asset_id, deposits) } fn liquidation_threshold_asset_value( @@ -1714,7 +1709,7 @@ impl Pallet { } fn get_total_cash(asset_id: AssetIdOf) -> BalanceOf { - orml_tokens::Pallet::::free_balance(asset_id, &Self::account_id()) + orml_tokens::Pallet::::reducible_balance(asset_id, &Self::account_id(), true) } /// Get the total balance of `who`. @@ -1920,7 +1915,7 @@ impl LoansTrait, AccountIdOf, BalanceOf> for Palle Self::ensure_active_market(underlying_id)?; let total_collateral_value = Self::total_collateral_value(supplier)?; - let collateral_amount_value = Self::collateral_amount_value(supplier, underlying_id, ptoken_amount.amount())?; + let collateral_amount_value = Self::collateral_amount_value(underlying_id, ptoken_amount.amount())?; let total_borrowed_value = Self::total_borrowed_value(supplier)?; if total_collateral_value diff --git a/crates/loans/src/ptoken.rs b/crates/loans/src/ptoken.rs index 1f3a9cc522..cbcde28e31 100644 --- a/crates/loans/src/ptoken.rs +++ b/crates/loans/src/ptoken.rs @@ -24,12 +24,10 @@ use frame_support::{ }, }; -impl Inspect for Pallet { - type AssetId = AssetIdOf; - type Balance = BalanceOf; - +// Utilities used for testing +impl Pallet { /// The total amount of issuance in the system. - fn total_issuance(ptoken_id: Self::AssetId) -> Self::Balance { + pub fn total_issuance(ptoken_id: AssetIdOf) -> BalanceOf { if let Ok(underlying_id) = Self::underlying_id(ptoken_id) { if let Ok(supply) = Self::total_supply(underlying_id) { return supply; @@ -39,26 +37,21 @@ impl Inspect for Pallet { } /// The minimum balance any single account may have. - fn minimum_balance(_ptoken_id: Self::AssetId) -> Self::Balance { + pub fn minimum_balance(_ptoken_id: AssetIdOf) -> BalanceOf { Zero::zero() } - /// Get the ptoken balance of `who`. - fn balance(ptoken_id: Self::AssetId, who: &T::AccountId) -> Self::Balance { - as MultiCurrency>::total_balance(ptoken_id, who) - } - /// Get the maximum amount that `who` can withdraw/transfer successfully. /// For ptoken, We don't care if keep_alive is enabled - fn reducible_balance(ptoken_id: Self::AssetId, who: &T::AccountId, _keep_alive: bool) -> Self::Balance { + pub fn reducible_balance(ptoken_id: AssetIdOf, who: &T::AccountId, _keep_alive: bool) -> BalanceOf { Self::reducible_asset(ptoken_id, who).unwrap_or_default() } /// Returns `true` if the balance of `who` may be increased by `amount`. - fn can_deposit( - ptoken_id: Self::AssetId, + pub fn can_deposit( + ptoken_id: AssetIdOf, who: &T::AccountId, - amount: Self::Balance, + amount: BalanceOf, _mint: bool, ) -> DepositConsequence { let underlying_id = match Self::underlying_id(ptoken_id) { @@ -87,11 +80,11 @@ impl Inspect for Pallet { /// Returns `Failed` if the balance of `who` may not be decreased by `amount`, otherwise /// the consequence. - fn can_withdraw( - ptoken_id: Self::AssetId, + pub fn can_withdraw( + ptoken_id: AssetIdOf, who: &T::AccountId, - amount: Self::Balance, - ) -> WithdrawConsequence { + amount: BalanceOf, + ) -> WithdrawConsequence> { let underlying_id = match Self::underlying_id(ptoken_id) { Ok(asset_id) => asset_id, Err(_) => return WithdrawConsequence::UnknownAsset, @@ -113,63 +106,22 @@ impl Inspect for Pallet { WithdrawConsequence::Success } -} -impl Transfer for Pallet { /// Returns `Err` if the reducible ptoken of `who` is insufficient /// /// For ptoken, We don't care if keep_alive is enabled #[transactional] - fn transfer( - ptoken_id: Self::AssetId, + pub fn transfer( + ptoken_id: AssetIdOf, source: &T::AccountId, dest: &T::AccountId, - amount: Self::Balance, + amount: BalanceOf, _keep_alive: bool, ) -> Result, DispatchError> { as MultiCurrency>::transfer(ptoken_id, source, dest, amount) .map_err(|_| Error::::InsufficientCollateral)?; Ok(amount) } -} - -impl Pallet { - #[require_transactional] - fn do_transfer_ptokens( - ptoken_id: AssetIdOf, - source: &T::AccountId, - dest: &T::AccountId, - amount: BalanceOf, - ) -> Result<(), DispatchError> { - // update supply index before modify supply balance. - Self::update_reward_supply_index(ptoken_id)?; - Self::distribute_supplier_reward(ptoken_id, source)?; - Self::distribute_supplier_reward(ptoken_id, dest)?; - - let underlying_id = Self::underlying_id(ptoken_id)?; - // AccountDeposits::::try_mutate_exists(underlying_id, source, |deposits| -> DispatchResult { - // let mut d = deposits.unwrap_or_default(); - // d = d - // .checked_sub(amount) - // .ok_or(ArithmeticError::Underflow)?; - // if d.is_zero() { - // // remove deposits storage if zero balance - // *deposits = None; - // } else { - // *deposits = Some(d); - // } - // Ok(()) - // })?; - - // AccountDeposits::::try_mutate(underlying_id, &dest, |deposits| -> DispatchResult { - // deposits = &mut deposits - // .checked_add(amount) - // .ok_or(ArithmeticError::Overflow)?; - // Ok(()) - // })?; - - Ok(()) - } fn reducible_asset(ptoken_id: AssetIdOf, who: &T::AccountId) -> Result, DispatchError> { let voucher_balance = Self::account_deposits(ptoken_id, &who); diff --git a/crates/loans/src/tests.rs b/crates/loans/src/tests.rs index 9a65993c07..d2ca112de3 100644 --- a/crates/loans/src/tests.rs +++ b/crates/loans/src/tests.rs @@ -21,7 +21,7 @@ mod liquidate_borrow; mod market; mod ptokens; -use frame_support::{assert_err, assert_noop, assert_ok}; +use frame_support::{assert_noop, assert_ok}; use sp_runtime::{ traits::{CheckedDiv, One, Saturating}, diff --git a/crates/loans/src/tests/liquidate_borrow.rs b/crates/loans/src/tests/liquidate_borrow.rs index c357065643..d04fe4301b 100644 --- a/crates/loans/src/tests/liquidate_borrow.rs +++ b/crates/loans/src/tests/liquidate_borrow.rs @@ -3,7 +3,7 @@ use crate::{ tests::unit, Error, MarketState, }; -use frame_support::{assert_err, assert_noop, assert_ok, traits::fungibles::Inspect}; +use frame_support::{assert_noop, assert_ok, traits::fungibles::Inspect}; use primitives::{ CurrencyId::{self, Token}, Rate, DOT as DOT_CURRENCY, KBTC as KBTC_CURRENCY, KSM as KSM_CURRENCY, From 25bec4e8794b12a2682dd6c07732b12dfac17f7c Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Thu, 13 Oct 2022 21:43:24 +0200 Subject: [PATCH 22/58] feat(loans): replace local orml-tokens fork with interlay repo --- Cargo.lock | 125 +++++++++++++++++++++---------- crates/currency/Cargo.toml | 4 +- crates/fee/Cargo.toml | 4 +- crates/issue/Cargo.toml | 8 +- crates/loans/Cargo.toml | 4 +- crates/nomination/Cargo.toml | 8 +- crates/oracle/Cargo.toml | 4 +- crates/redeem/Cargo.toml | 8 +- crates/replace/Cargo.toml | 8 +- crates/staking/Cargo.toml | 4 +- crates/vault-registry/Cargo.toml | 4 +- standalone/runtime/Cargo.toml | 4 +- 12 files changed, 116 insertions(+), 69 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1db2232948..73d89b03fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1907,8 +1907,8 @@ dependencies = [ "frame-system", "interbtc-primitives", "mocktopus", - "orml-tokens", - "orml-traits", + "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", "pallet-transaction-payment", "parity-scale-codec", "scale-info", @@ -2431,8 +2431,8 @@ dependencies = [ "frame-system", "interbtc-primitives", "mocktopus", - "orml-tokens", - "orml-traits", + "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", "pallet-timestamp", "parity-scale-codec", "reward", @@ -3610,8 +3610,8 @@ dependencies = [ "nomination", "oracle", "orml-asset-registry", - "orml-tokens", - "orml-traits", + "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", "orml-vesting", "pallet-aura", "pallet-authorship", @@ -3748,8 +3748,8 @@ dependencies = [ "nomination", "oracle", "orml-asset-registry", - "orml-tokens", - "orml-traits", + "orml-tokens 0.4.1-dev", + "orml-traits 0.4.1-dev", "orml-unknown-tokens", "orml-vesting", "orml-xcm-support", @@ -3855,8 +3855,8 @@ dependencies = [ "log", "mocktopus", "oracle", - "orml-tokens", - "orml-traits", + "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", "pallet-timestamp", "parity-scale-codec", "reward", @@ -4110,8 +4110,8 @@ dependencies = [ "nomination", "oracle", "orml-asset-registry", - "orml-tokens", - "orml-traits", + "orml-tokens 0.4.1-dev", + "orml-traits 0.4.1-dev", "orml-unknown-tokens", "orml-vesting", "orml-xcm-support", @@ -5700,8 +5700,8 @@ dependencies = [ "interbtc-primitives", "mocktopus", "oracle", - "orml-tokens", - "orml-traits", + "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", "pallet-timestamp", "parity-scale-codec", "reward", @@ -5866,8 +5866,8 @@ dependencies = [ "frame-system", "interbtc-primitives", "mocktopus", - "orml-tokens", - "orml-traits", + "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", "pallet-timestamp", "parity-scale-codec", "scale-info", @@ -5925,7 +5925,7 @@ version = "0.4.1-dev" dependencies = [ "frame-support", "frame-system", - "orml-traits", + "orml-traits 0.4.1-dev", "pallet-xcm", "parity-scale-codec", "scale-info", @@ -5943,8 +5943,8 @@ version = "0.4.1-dev" dependencies = [ "frame-support", "frame-system", - "orml-traits", - "orml-utilities", + "orml-traits 0.4.1-dev", + "orml-utilities 0.4.1-dev", "parity-scale-codec", "scale-info", "serde", @@ -5960,7 +5960,7 @@ version = "0.4.1-dev" dependencies = [ "frame-support", "frame-system", - "orml-traits", + "orml-traits 0.4.1-dev", "parity-scale-codec", "scale-info", "serde", @@ -5968,14 +5968,47 @@ dependencies = [ "sp-std", ] +[[package]] +name = "orml-tokens" +version = "0.4.1-dev" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#250c3bf31aec734e6add7d8a0a325c7dcd06f55b" +dependencies = [ + "frame-support", + "frame-system", + "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "parity-scale-codec", + "scale-info", + "serde", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "orml-traits" +version = "0.4.1-dev" +dependencies = [ + "frame-support", + "impl-trait-for-tuples", + "num-traits", + "orml-utilities 0.4.1-dev", + "parity-scale-codec", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std", + "xcm", +] + [[package]] name = "orml-traits" version = "0.4.1-dev" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#250c3bf31aec734e6add7d8a0a325c7dcd06f55b" dependencies = [ "frame-support", "impl-trait-for-tuples", "num-traits", - "orml-utilities", + "orml-utilities 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", "parity-scale-codec", "scale-info", "serde", @@ -6012,6 +6045,20 @@ dependencies = [ "sp-std", ] +[[package]] +name = "orml-utilities" +version = "0.4.1-dev" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#250c3bf31aec734e6add7d8a0a325c7dcd06f55b" +dependencies = [ + "frame-support", + "parity-scale-codec", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "orml-vesting" version = "0.4.1-dev" @@ -6045,7 +6092,7 @@ name = "orml-xcm-support" version = "0.4.1-dev" dependencies = [ "frame-support", - "orml-traits", + "orml-traits 0.4.1-dev", "parity-scale-codec", "sp-runtime", "sp-std", @@ -6060,7 +6107,7 @@ dependencies = [ "cumulus-primitives-core", "frame-support", "frame-system", - "orml-traits", + "orml-traits 0.4.1-dev", "orml-xcm-support", "pallet-xcm", "parity-scale-codec", @@ -6469,8 +6516,8 @@ dependencies = [ "mocktopus", "num-traits", "orml-oracle", - "orml-tokens", - "orml-traits", + "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", "pallet-timestamp", "pallet-traits", "parity-scale-codec", @@ -7034,8 +7081,8 @@ dependencies = [ "module-vault-registry-rpc-runtime-api", "nomination", "oracle", - "orml-tokens", - "orml-traits", + "orml-tokens 0.4.1-dev", + "orml-traits 0.4.1-dev", "orml-unknown-tokens", "orml-vesting", "orml-xcm", @@ -9031,8 +9078,8 @@ dependencies = [ "interbtc-primitives", "mocktopus", "oracle", - "orml-tokens", - "orml-traits", + "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", "pallet-timestamp", "parity-scale-codec", "reward", @@ -9192,8 +9239,8 @@ dependencies = [ "mocktopus", "nomination", "oracle", - "orml-tokens", - "orml-traits", + "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", "pallet-timestamp", "parity-scale-codec", "reward", @@ -11799,8 +11846,8 @@ dependencies = [ "frame-system", "interbtc-primitives", "mocktopus", - "orml-tokens", - "orml-traits", + "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", "pallet-timestamp", "parity-scale-codec", "rand 0.8.5", @@ -12149,8 +12196,8 @@ dependencies = [ "nomination", "oracle", "orml-asset-registry", - "orml-tokens", - "orml-traits", + "orml-tokens 0.4.1-dev", + "orml-traits 0.4.1-dev", "orml-unknown-tokens", "orml-vesting", "orml-xcm-support", @@ -12248,8 +12295,8 @@ dependencies = [ "nomination", "oracle", "orml-asset-registry", - "orml-tokens", - "orml-traits", + "orml-tokens 0.4.1-dev", + "orml-traits 0.4.1-dev", "orml-unknown-tokens", "orml-vesting", "orml-xcm-support", @@ -12876,8 +12923,8 @@ dependencies = [ "log", "mocktopus", "oracle", - "orml-tokens", - "orml-traits", + "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", "pallet-timestamp", "parity-scale-codec", "pretty_assertions", diff --git a/crates/currency/Cargo.toml b/crates/currency/Cargo.toml index f53a1c09d2..8321e60e61 100644 --- a/crates/currency/Cargo.toml +++ b/crates/currency/Cargo.toml @@ -21,8 +21,8 @@ pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { path = "../../../open-runtime-module-library/tokens",default-features = false } -orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks",default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } # for other pallets wanting to mock functions mocktopus = {version = "0.7.0", optional = true } diff --git a/crates/fee/Cargo.toml b/crates/fee/Cargo.toml index 306249b23f..381cf12c8d 100644 --- a/crates/fee/Cargo.toml +++ b/crates/fee/Cargo.toml @@ -35,8 +35,8 @@ pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = " currency = { path = "../currency", features = ["testing-utils"] } # Orml dependencies -orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false } -orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } # Parachain dependencies primitives = { package = "interbtc-primitives", path = "../../primitives"} diff --git a/crates/issue/Cargo.toml b/crates/issue/Cargo.toml index e092e9b893..08fbd3f483 100644 --- a/crates/issue/Cargo.toml +++ b/crates/issue/Cargo.toml @@ -35,8 +35,8 @@ vault-registry = { path = "../vault-registry", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false, optional = true } -orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false, optional = true } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false, optional = true } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false, optional = true } [dev-dependencies] mocktopus = "0.7.0" @@ -47,8 +47,8 @@ reward = { path = "../reward" } staking = { path = "../staking" } # Orml dependencies -orml-tokens = { path = "../../../open-runtime-module-library/tokens" } -orml-traits = { path = "../../../open-runtime-module-library/traits" } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks" } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks" } [features] default = ["std"] diff --git a/crates/loans/Cargo.toml b/crates/loans/Cargo.toml index f0ac611d6e..abc7a37032 100644 --- a/crates/loans/Cargo.toml +++ b/crates/loans/Cargo.toml @@ -13,9 +13,9 @@ frame-benchmarking = { git = 'https://github.com/paritytech/substrate.git', bran frame-support = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } frame-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } num-traits = { default-features = false, version = '0.2' } -orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } orml-oracle = { path = "../../../open-runtime-module-library/oracle", default-features = false } -orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } pallet-timestamp = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } pallet-traits = { path = '../traits', default-features = false } primitives = { package = 'interbtc-primitives', path = '../../primitives', default-features = false } diff --git a/crates/nomination/Cargo.toml b/crates/nomination/Cargo.toml index 77a50f8beb..c06aa8de25 100644 --- a/crates/nomination/Cargo.toml +++ b/crates/nomination/Cargo.toml @@ -33,16 +33,16 @@ staking = { path = "../staking", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false, optional = true } -orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false, optional = true } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false, optional = true } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false, optional = true } [dev-dependencies] mocktopus = "0.7.0" frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.26", default-features = false } # Orml dependencies -orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false } -orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } [features] default = ["std"] diff --git a/crates/oracle/Cargo.toml b/crates/oracle/Cargo.toml index 2550f3806e..bd4314c4d2 100644 --- a/crates/oracle/Cargo.toml +++ b/crates/oracle/Cargo.toml @@ -31,8 +31,8 @@ mocktopus = "0.7.0" frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.26", default-features = false } # Orml dependencies -orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false } -orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } [features] default = ["std"] diff --git a/crates/redeem/Cargo.toml b/crates/redeem/Cargo.toml index 47baf58899..72931dd152 100644 --- a/crates/redeem/Cargo.toml +++ b/crates/redeem/Cargo.toml @@ -33,8 +33,8 @@ vault-registry = { path = "../vault-registry", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false, optional = true } -orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false, optional = true } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false, optional = true } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false, optional = true } [dev-dependencies] mocktopus = "0.7.0" @@ -46,8 +46,8 @@ staking = { path = "../staking" } currency = { path = "../currency", features = ["testing-utils"] } # Orml dependencies -orml-tokens = { path = "../../../open-runtime-module-library/tokens" } -orml-traits = { path = "../../../open-runtime-module-library/traits" } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks" } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks" } [features] default = ["std"] diff --git a/crates/replace/Cargo.toml b/crates/replace/Cargo.toml index 5a233c0245..80f26379d1 100644 --- a/crates/replace/Cargo.toml +++ b/crates/replace/Cargo.toml @@ -34,8 +34,8 @@ nomination = { path = "../nomination", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false, optional = true } -orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false, optional = true } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false, optional = true } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false, optional = true } [dev-dependencies] mocktopus = "0.7.0" @@ -47,8 +47,8 @@ staking = { path = "../staking" } currency = { path = "../currency", features = ["testing-utils"] } # Orml dependencies -orml-tokens = { path = "../../../open-runtime-module-library/tokens" } -orml-traits = { path = "../../../open-runtime-module-library/traits" } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks" } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks" } [features] default = ["std"] diff --git a/crates/staking/Cargo.toml b/crates/staking/Cargo.toml index cb8c54aa6c..ecd62166c1 100644 --- a/crates/staking/Cargo.toml +++ b/crates/staking/Cargo.toml @@ -25,8 +25,8 @@ frame-system = { git = "https://github.com/paritytech/substrate", branch = "polk frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.26", default-features = false, optional = true } # note: can be remove after removal of migration -orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false } -orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } [dev-dependencies] mocktopus = "0.7.0" diff --git a/crates/vault-registry/Cargo.toml b/crates/vault-registry/Cargo.toml index f72637104e..e251d91730 100644 --- a/crates/vault-registry/Cargo.toml +++ b/crates/vault-registry/Cargo.toml @@ -37,8 +37,8 @@ staking = { path = "../staking", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false } -orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } [dev-dependencies] mocktopus = "0.7.0" diff --git a/standalone/runtime/Cargo.toml b/standalone/runtime/Cargo.toml index 83329ddc57..e0dfadce17 100644 --- a/standalone/runtime/Cargo.toml +++ b/standalone/runtime/Cargo.toml @@ -89,8 +89,8 @@ module-redeem-rpc-runtime-api = { path = "../../crates/redeem/rpc/runtime-api", module-replace-rpc-runtime-api = { path = "../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { path = "../../../open-runtime-module-library/tokens", default-features = false } -orml-traits = { path = "../../../open-runtime-module-library/traits", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } orml-vesting = { path = "../../../open-runtime-module-library/vesting", default-features = false } orml-asset-registry = { path = "../../../open-runtime-module-library/asset-registry", default-features = false } From 1b6d0b2f7ec38f0a28cce76bb0c602ef836fa71c Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Thu, 13 Oct 2022 22:02:38 +0200 Subject: [PATCH 23/58] fix(loans): fix all local orml imports --- Cargo.lock | 128 ++++++------------ crates/currency/Cargo.toml | 2 +- crates/loans/Cargo.toml | 2 +- crates/loans/src/lib.rs | 1 + parachain/runtime/interlay/Cargo.toml | 16 +-- parachain/runtime/kintsugi/Cargo.toml | 16 +-- parachain/runtime/runtime-tests/Cargo.toml | 12 +- parachain/runtime/testnet-interlay/Cargo.toml | 16 +-- parachain/runtime/testnet-kintsugi/Cargo.toml | 16 +-- standalone/runtime/Cargo.toml | 4 +- 10 files changed, 88 insertions(+), 125 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 73d89b03fb..e2f0302d0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1907,8 +1907,8 @@ dependencies = [ "frame-system", "interbtc-primitives", "mocktopus", - "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", - "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-tokens", + "orml-traits", "pallet-transaction-payment", "parity-scale-codec", "scale-info", @@ -2431,8 +2431,8 @@ dependencies = [ "frame-system", "interbtc-primitives", "mocktopus", - "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", - "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-tokens", + "orml-traits", "pallet-timestamp", "parity-scale-codec", "reward", @@ -3610,8 +3610,8 @@ dependencies = [ "nomination", "oracle", "orml-asset-registry", - "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", - "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-tokens", + "orml-traits", "orml-vesting", "pallet-aura", "pallet-authorship", @@ -3748,8 +3748,8 @@ dependencies = [ "nomination", "oracle", "orml-asset-registry", - "orml-tokens 0.4.1-dev", - "orml-traits 0.4.1-dev", + "orml-tokens", + "orml-traits", "orml-unknown-tokens", "orml-vesting", "orml-xcm-support", @@ -3855,8 +3855,8 @@ dependencies = [ "log", "mocktopus", "oracle", - "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", - "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-tokens", + "orml-traits", "pallet-timestamp", "parity-scale-codec", "reward", @@ -4110,8 +4110,8 @@ dependencies = [ "nomination", "oracle", "orml-asset-registry", - "orml-tokens 0.4.1-dev", - "orml-traits 0.4.1-dev", + "orml-tokens", + "orml-traits", "orml-unknown-tokens", "orml-vesting", "orml-xcm-support", @@ -5700,8 +5700,8 @@ dependencies = [ "interbtc-primitives", "mocktopus", "oracle", - "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", - "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-tokens", + "orml-traits", "pallet-timestamp", "parity-scale-codec", "reward", @@ -5866,8 +5866,8 @@ dependencies = [ "frame-system", "interbtc-primitives", "mocktopus", - "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", - "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-tokens", + "orml-traits", "pallet-timestamp", "parity-scale-codec", "scale-info", @@ -5922,10 +5922,11 @@ dependencies = [ [[package]] name = "orml-asset-registry" version = "0.4.1-dev" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#250c3bf31aec734e6add7d8a0a325c7dcd06f55b" dependencies = [ "frame-support", "frame-system", - "orml-traits 0.4.1-dev", + "orml-traits", "pallet-xcm", "parity-scale-codec", "scale-info", @@ -5940,11 +5941,12 @@ dependencies = [ [[package]] name = "orml-oracle" version = "0.4.1-dev" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#250c3bf31aec734e6add7d8a0a325c7dcd06f55b" dependencies = [ "frame-support", "frame-system", - "orml-traits 0.4.1-dev", - "orml-utilities 0.4.1-dev", + "orml-traits", + "orml-utilities", "parity-scale-codec", "scale-info", "serde", @@ -5954,20 +5956,6 @@ dependencies = [ "sp-std", ] -[[package]] -name = "orml-tokens" -version = "0.4.1-dev" -dependencies = [ - "frame-support", - "frame-system", - "orml-traits 0.4.1-dev", - "parity-scale-codec", - "scale-info", - "serde", - "sp-runtime", - "sp-std", -] - [[package]] name = "orml-tokens" version = "0.4.1-dev" @@ -5975,29 +5963,12 @@ source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan dependencies = [ "frame-support", "frame-system", - "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", - "parity-scale-codec", - "scale-info", - "serde", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "orml-traits" -version = "0.4.1-dev" -dependencies = [ - "frame-support", - "impl-trait-for-tuples", - "num-traits", - "orml-utilities 0.4.1-dev", + "orml-traits", "parity-scale-codec", "scale-info", "serde", - "sp-io", "sp-runtime", "sp-std", - "xcm", ] [[package]] @@ -6008,7 +5979,7 @@ dependencies = [ "frame-support", "impl-trait-for-tuples", "num-traits", - "orml-utilities 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-utilities", "parity-scale-codec", "scale-info", "serde", @@ -6021,6 +5992,7 @@ dependencies = [ [[package]] name = "orml-unknown-tokens" version = "0.4.1-dev" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#250c3bf31aec734e6add7d8a0a325c7dcd06f55b" dependencies = [ "frame-support", "frame-system", @@ -6032,19 +6004,6 @@ dependencies = [ "xcm", ] -[[package]] -name = "orml-utilities" -version = "0.4.1-dev" -dependencies = [ - "frame-support", - "parity-scale-codec", - "scale-info", - "serde", - "sp-io", - "sp-runtime", - "sp-std", -] - [[package]] name = "orml-utilities" version = "0.4.1-dev" @@ -6062,6 +6021,7 @@ dependencies = [ [[package]] name = "orml-vesting" version = "0.4.1-dev" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#250c3bf31aec734e6add7d8a0a325c7dcd06f55b" dependencies = [ "frame-support", "frame-system", @@ -6090,9 +6050,10 @@ dependencies = [ [[package]] name = "orml-xcm-support" version = "0.4.1-dev" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#250c3bf31aec734e6add7d8a0a325c7dcd06f55b" dependencies = [ "frame-support", - "orml-traits 0.4.1-dev", + "orml-traits", "parity-scale-codec", "sp-runtime", "sp-std", @@ -6103,11 +6064,12 @@ dependencies = [ [[package]] name = "orml-xtokens" version = "0.4.1-dev" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#250c3bf31aec734e6add7d8a0a325c7dcd06f55b" dependencies = [ "cumulus-primitives-core", "frame-support", "frame-system", - "orml-traits 0.4.1-dev", + "orml-traits", "orml-xcm-support", "pallet-xcm", "parity-scale-codec", @@ -6516,8 +6478,8 @@ dependencies = [ "mocktopus", "num-traits", "orml-oracle", - "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", - "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-tokens", + "orml-traits", "pallet-timestamp", "pallet-traits", "parity-scale-codec", @@ -7081,8 +7043,8 @@ dependencies = [ "module-vault-registry-rpc-runtime-api", "nomination", "oracle", - "orml-tokens 0.4.1-dev", - "orml-traits 0.4.1-dev", + "orml-tokens", + "orml-traits", "orml-unknown-tokens", "orml-vesting", "orml-xcm", @@ -9078,8 +9040,8 @@ dependencies = [ "interbtc-primitives", "mocktopus", "oracle", - "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", - "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-tokens", + "orml-traits", "pallet-timestamp", "parity-scale-codec", "reward", @@ -9239,8 +9201,8 @@ dependencies = [ "mocktopus", "nomination", "oracle", - "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", - "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-tokens", + "orml-traits", "pallet-timestamp", "parity-scale-codec", "reward", @@ -11846,8 +11808,8 @@ dependencies = [ "frame-system", "interbtc-primitives", "mocktopus", - "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", - "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-tokens", + "orml-traits", "pallet-timestamp", "parity-scale-codec", "rand 0.8.5", @@ -12196,8 +12158,8 @@ dependencies = [ "nomination", "oracle", "orml-asset-registry", - "orml-tokens 0.4.1-dev", - "orml-traits 0.4.1-dev", + "orml-tokens", + "orml-traits", "orml-unknown-tokens", "orml-vesting", "orml-xcm-support", @@ -12295,8 +12257,8 @@ dependencies = [ "nomination", "oracle", "orml-asset-registry", - "orml-tokens 0.4.1-dev", - "orml-traits 0.4.1-dev", + "orml-tokens", + "orml-traits", "orml-unknown-tokens", "orml-vesting", "orml-xcm-support", @@ -12923,8 +12885,8 @@ dependencies = [ "log", "mocktopus", "oracle", - "orml-tokens 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", - "orml-traits 0.4.1-dev (git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks)", + "orml-tokens", + "orml-traits", "pallet-timestamp", "parity-scale-codec", "pretty_assertions", diff --git a/crates/currency/Cargo.toml b/crates/currency/Cargo.toml index 8321e60e61..1ac0439bec 100644 --- a/crates/currency/Cargo.toml +++ b/crates/currency/Cargo.toml @@ -21,7 +21,7 @@ pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks",default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } # for other pallets wanting to mock functions diff --git a/crates/loans/Cargo.toml b/crates/loans/Cargo.toml index abc7a37032..d366b456aa 100644 --- a/crates/loans/Cargo.toml +++ b/crates/loans/Cargo.toml @@ -14,7 +14,7 @@ frame-support = { git = 'https://github.com/paritytech/substrate.git', bran frame-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } num-traits = { default-features = false, version = '0.2' } orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-oracle = { path = "../../../open-runtime-module-library/oracle", default-features = false } +orml-oracle = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } pallet-timestamp = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } pallet-traits = { path = '../traits', default-features = false } diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 78d98ec876..4374c4ecf9 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -1094,6 +1094,7 @@ impl Pallet { total_collateral_value > total_borrow_value, lf_base_position > lf_borrowed_value, ) { + // TODO: simplify this function and use checked math operations (true, true) => Ok(( total_collateral_value - total_borrow_value, FixedU128::zero(), diff --git a/parachain/runtime/interlay/Cargo.toml b/parachain/runtime/interlay/Cargo.toml index ac8b7a04b8..2f848044e8 100644 --- a/parachain/runtime/interlay/Cargo.toml +++ b/parachain/runtime/interlay/Cargo.toml @@ -106,14 +106,14 @@ module-redeem-rpc-runtime-api = { path = "../../../crates/redeem/rpc/runtime-api module-replace-rpc-runtime-api = { path = "../../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { path = "../../../../open-runtime-module-library/tokens", default-features = false } -orml-traits = { path = "../../../../open-runtime-module-library/traits", default-features = false } -orml-vesting = { path = "../../../../open-runtime-module-library/vesting", default-features = false } - -orml-xtokens = { path = "../../../../open-runtime-module-library/xtokens", default-features = false } -orml-xcm-support = { path = "../../../../open-runtime-module-library/xcm-support", default-features = false } -orml-unknown-tokens = { path = "../../../../open-runtime-module-library/unknown-tokens", default-features = false } -orml-asset-registry = { path = "../../../../open-runtime-module-library/asset-registry", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-vesting = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } + +orml-xtokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-xcm-support = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-unknown-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-asset-registry = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } [dev-dependencies] hex = '0.4.2' diff --git a/parachain/runtime/kintsugi/Cargo.toml b/parachain/runtime/kintsugi/Cargo.toml index 6caebef8d3..988528c635 100644 --- a/parachain/runtime/kintsugi/Cargo.toml +++ b/parachain/runtime/kintsugi/Cargo.toml @@ -106,14 +106,14 @@ module-redeem-rpc-runtime-api = { path = "../../../crates/redeem/rpc/runtime-api module-replace-rpc-runtime-api = { path = "../../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { path = "../../../../open-runtime-module-library/tokens", default-features = false } -orml-traits = { path = "../../../../open-runtime-module-library/traits", default-features = false } -orml-vesting = { path = "../../../../open-runtime-module-library/vesting", default-features = false } - -orml-xtokens = { path = "../../../../open-runtime-module-library/xtokens", default-features = false } -orml-xcm-support = { path = "../../../../open-runtime-module-library/xcm-support", default-features = false } -orml-unknown-tokens = { path = "../../../../open-runtime-module-library/unknown-tokens", default-features = false } -orml-asset-registry = { path = "../../../../open-runtime-module-library/asset-registry", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-vesting = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } + +orml-xtokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-xcm-support = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-unknown-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-asset-registry = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } [dev-dependencies] hex = '0.4.2' diff --git a/parachain/runtime/runtime-tests/Cargo.toml b/parachain/runtime/runtime-tests/Cargo.toml index f0f3f1c483..2c594818ce 100644 --- a/parachain/runtime/runtime-tests/Cargo.toml +++ b/parachain/runtime/runtime-tests/Cargo.toml @@ -112,14 +112,14 @@ module-redeem-rpc-runtime-api = { path = "../../../crates/redeem/rpc/runtime-api module-replace-rpc-runtime-api = { path = "../../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { path = "../../../../open-runtime-module-library/tokens", default-features = false } -orml-traits = { path = "../../../../open-runtime-module-library/traits", default-features = false } -orml-vesting = { path = "../../../../open-runtime-module-library/vesting", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-vesting = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-xtokens = { path = "../../../../open-runtime-module-library/xtokens", default-features = false } +orml-xtokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } orml-xcm = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-xcm-support = { path = "../../../../open-runtime-module-library/xcm-support", default-features = false } -orml-unknown-tokens = { path = "../../../../open-runtime-module-library/unknown-tokens", default-features = false } +orml-xcm-support = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-unknown-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } xcm-emulator = { git = "https://github.com/shaunxw/xcm-simulator", rev = "ab5cd6c5fabe6ddda52ed6803ee1bf54c258fefe" } diff --git a/parachain/runtime/testnet-interlay/Cargo.toml b/parachain/runtime/testnet-interlay/Cargo.toml index b57442ea19..cd9aef400f 100644 --- a/parachain/runtime/testnet-interlay/Cargo.toml +++ b/parachain/runtime/testnet-interlay/Cargo.toml @@ -107,14 +107,14 @@ module-redeem-rpc-runtime-api = { path = "../../../crates/redeem/rpc/runtime-api module-replace-rpc-runtime-api = { path = "../../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { path = "../../../../open-runtime-module-library/tokens", default-features = false } -orml-traits = { path = "../../../../open-runtime-module-library/traits", default-features = false } -orml-vesting = { path = "../../../../open-runtime-module-library/vesting", default-features = false } - -orml-xtokens = { path = "../../../../open-runtime-module-library/xtokens", default-features = false } -orml-xcm-support = { path = "../../../../open-runtime-module-library/xcm-support", default-features = false } -orml-unknown-tokens = { path = "../../../../open-runtime-module-library/unknown-tokens", default-features = false } -orml-asset-registry = { path = "../../../../open-runtime-module-library/asset-registry", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-vesting = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } + +orml-xtokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-xcm-support = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-unknown-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-asset-registry = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } [dev-dependencies] hex = '0.4.2' diff --git a/parachain/runtime/testnet-kintsugi/Cargo.toml b/parachain/runtime/testnet-kintsugi/Cargo.toml index 13c3ef1f21..bbf94c3301 100644 --- a/parachain/runtime/testnet-kintsugi/Cargo.toml +++ b/parachain/runtime/testnet-kintsugi/Cargo.toml @@ -107,14 +107,14 @@ module-redeem-rpc-runtime-api = { path = "../../../crates/redeem/rpc/runtime-api module-replace-rpc-runtime-api = { path = "../../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { path = "../../../../open-runtime-module-library/tokens", default-features = false } -orml-traits = { path = "../../../../open-runtime-module-library/traits", default-features = false } -orml-vesting = { path = "../../../../open-runtime-module-library/vesting", default-features = false } - -orml-xtokens = { path = "../../../../open-runtime-module-library/xtokens", default-features = false } -orml-xcm-support = { path = "../../../../open-runtime-module-library/xcm-support", default-features = false } -orml-unknown-tokens = { path = "../../../../open-runtime-module-library/unknown-tokens", default-features = false } -orml-asset-registry = { path = "../../../../open-runtime-module-library/asset-registry", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-vesting = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } + +orml-xtokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-xcm-support = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-unknown-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-asset-registry = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } [dev-dependencies] hex = '0.4.2' diff --git a/standalone/runtime/Cargo.toml b/standalone/runtime/Cargo.toml index e0dfadce17..60d0d8543e 100644 --- a/standalone/runtime/Cargo.toml +++ b/standalone/runtime/Cargo.toml @@ -91,8 +91,8 @@ module-replace-rpc-runtime-api = { path = "../../crates/replace/rpc/runtime-api" # Orml dependencies orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-vesting = { path = "../../../open-runtime-module-library/vesting", default-features = false } -orml-asset-registry = { path = "../../../open-runtime-module-library/asset-registry", default-features = false } +orml-vesting = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-asset-registry = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.26", default-features = false } From a4331b2a6a3ee9eddb5d2443a80413aba31b0482 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Thu, 13 Oct 2022 22:38:23 +0200 Subject: [PATCH 24/58] fix(loans): benchmark --- crates/loans/src/benchmarking.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/loans/src/benchmarking.rs b/crates/loans/src/benchmarking.rs index e36fbe54a7..b99ae41457 100644 --- a/crates/loans/src/benchmarking.rs +++ b/crates/loans/src/benchmarking.rs @@ -112,7 +112,7 @@ fn set_account_borrows(who: T::AccountId, asset_id: AssetIdOf, bor ); TotalBorrows::::insert(asset_id, borrow_balance); let amount: Amount = Amount::new(borrow_balance, asset_id); - amount.burn_from(who)?; + amount.burn_from(&who).unwrap(); } fn assert_last_event(generic_event: ::Event) { @@ -247,7 +247,7 @@ benchmarks! { assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); - assert_ok!(Loans::::collateral_asset(SystemOrigin::Signed(caller.clone()).into(), KBTC, true)); + assert_ok!(Loans::::deposit_all_collateral(SystemOrigin::Signed(caller.clone()).into(), KBTC)); }: _(SystemOrigin::Signed(caller.clone()), KBTC, borrowed_amount.into()) verify { assert_last_event::(Event::::Borrowed(caller, KBTC, borrowed_amount.into()).into()); @@ -287,7 +287,7 @@ benchmarks! { // assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); - assert_ok!(Loans::::collateral_asset(SystemOrigin::Signed(caller.clone()).into(), KBTC, true)); + assert_ok!(Loans::::deposit_all_collateral(SystemOrigin::Signed(caller.clone()).into(), KBTC)); assert_ok!(Loans::::borrow(SystemOrigin::Signed(caller.clone()).into(), KBTC, borrowed_amount.into())); }: _(SystemOrigin::Signed(caller.clone()), KBTC, repay_amount.into()) verify { @@ -303,23 +303,23 @@ benchmarks! { assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); - assert_ok!(Loans::::collateral_asset(SystemOrigin::Signed(caller.clone()).into(), KBTC, true)); + assert_ok!(Loans::::deposit_all_collateral(SystemOrigin::Signed(caller.clone()).into(), KBTC)); assert_ok!(Loans::::borrow(SystemOrigin::Signed(caller.clone()).into(), KBTC, borrowed_amount.into())); }: _(SystemOrigin::Signed(caller.clone()), KBTC) verify { assert_last_event::(Event::::RepaidBorrow(caller, KBTC, borrowed_amount.into()).into()); } - collateral_asset { + deposit_all_collateral { let caller: T::AccountId = whitelisted_caller(); transfer_initial_balance::(caller.clone()); let deposit_amount: u32 = 200_000_000; assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); - }: _(SystemOrigin::Signed(caller.clone()), KBTC, true) + }: _(SystemOrigin::Signed(caller.clone()), KBTC) verify { - assert_last_event::(Event::::CollateralAssetAdded(caller, KBTC).into()); + assert_last_event::(Event::::DepositCollateral(caller, KBTC, deposit_amount.into()).into()); } liquidate_borrow { @@ -337,7 +337,7 @@ benchmarks! { assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KSM)); assert_ok!(Loans::::mint(SystemOrigin::Signed(bob.clone()).into(), KSM, deposit_amount.into())); assert_ok!(Loans::::mint(SystemOrigin::Signed(alice.clone()).into(), CDOT, deposit_amount.into())); - assert_ok!(Loans::::collateral_asset(SystemOrigin::Signed(alice.clone()).into(), CDOT, true)); + assert_ok!(Loans::::deposit_all_collateral(SystemOrigin::Signed(alice.clone()).into(), CDOT)); set_account_borrows::(alice.clone(), KSM, borrowed_amount.into()); }: _(SystemOrigin::Signed(bob.clone()), alice.clone(), KSM, liquidate_amount.into(), CDOT) verify { From 815c53f3f2be2407792241366f6d898b0724f412 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Fri, 14 Oct 2022 14:57:11 +0200 Subject: [PATCH 25/58] chore(loans): cleanup and added comments --- crates/loans/src/farming.rs | 4 +--- crates/loans/src/lib.rs | 19 +++++++++++++------ crates/loans/src/tests/ptokens.rs | 3 +++ 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/crates/loans/src/farming.rs b/crates/loans/src/farming.rs index 20a21ba530..a6f0d64639 100644 --- a/crates/loans/src/farming.rs +++ b/crates/loans/src/farming.rs @@ -15,7 +15,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use orml_traits::MultiCurrency; use sp_io::hashing::blake2_256; use sp_runtime::{traits::Zero, DispatchResult}; @@ -125,8 +124,7 @@ impl Pallet { let ptoken_id = Self::ptoken_id(asset_id)?; RewardAccrued::::try_mutate(supplier, |total_reward| -> DispatchResult { // Frozen balance is not counted towards the total - let total_balance = - as MultiCurrency>::total_balance(ptoken_id, supplier); + let total_balance = Self::balance(ptoken_id, supplier); let reward_delta = Self::calculate_reward_delta(total_balance, delta_index)?; *total_reward = total_reward .checked_add(reward_delta) diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 4374c4ecf9..8f2e46950d 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -1207,11 +1207,11 @@ impl Pallet { fn collateral_asset_value(supplier: &T::AccountId, asset_id: AssetIdOf) -> Result { let ptoken_id = Self::ptoken_id(asset_id)?; if !AccountDeposits::::contains_key(ptoken_id, supplier) { - return Ok(0.into()); + return Ok(FixedU128::zero()); } let deposits = Self::account_deposits(ptoken_id, supplier); if deposits.is_zero() { - return Ok(0.into()); + return Ok(FixedU128::zero()); } Self::collateral_amount_value(asset_id, deposits) } @@ -1259,7 +1259,7 @@ impl Pallet { } /// Checks if the redeemer should be allowed to redeem tokens in given market. - /// Takes into account both `free` and `locked` (deposited as collateral) ptokens. + /// Takes into account both `free` and `locked` (i.e. deposited as collateral) ptokens. fn redeem_allowed(asset_id: AssetIdOf, redeemer: &T::AccountId, voucher_amount: BalanceOf) -> DispatchResult { log::trace!( target: "loans::redeem_allowed", @@ -1593,8 +1593,8 @@ impl Pallet { .ok_or(ArithmeticError::Underflow)?, ); - let amount_to_liquidate: Amount = Amount::new(collateral_amount, ptoken_id); // Unlock this balance to make it transferrable + let amount_to_liquidate: Amount = Amount::new(collateral_amount, ptoken_id); amount_to_liquidate.unlock_on(borrower)?; // increase liquidator's voucher_balance @@ -1718,13 +1718,13 @@ impl Pallet { as MultiCurrency>::total_balance(asset_id, who) } - /// Total suply of lending tokens (ptokens), given the underlying + /// Total supply of lending tokens (ptokens), given the underlying pub fn total_supply(asset_id: AssetIdOf) -> Result, DispatchError> { let ptoken_id = Self::ptoken_id(asset_id)?; Ok(orml_tokens::Pallet::::total_issuance(ptoken_id)) } - /// Total suply of lending tokens (ptokens), given the underlying + /// Free lending tokens (ptokens) of an account, given the underlying pub fn free_ptoken_balance( asset_id: AssetIdOf, account_id: &T::AccountId, @@ -1918,6 +1918,13 @@ impl LoansTrait, AccountIdOf, BalanceOf> for Palle let total_collateral_value = Self::total_collateral_value(supplier)?; let collateral_amount_value = Self::collateral_amount_value(underlying_id, ptoken_amount.amount())?; let total_borrowed_value = Self::total_borrowed_value(supplier)?; + log::trace!( + target: "loans::collateral_asset", + "total_collateral_value: {:?}, collateral_asset_value: {:?}, total_borrowed_value: {:?}", + total_collateral_value.into_inner(), + collateral_amount_value.into_inner(), + total_borrowed_value.into_inner(), + ); if total_collateral_value < total_borrowed_value diff --git a/crates/loans/src/tests/ptokens.rs b/crates/loans/src/tests/ptokens.rs index 4198b21414..ac0fb21dad 100644 --- a/crates/loans/src/tests/ptokens.rs +++ b/crates/loans/src/tests/ptokens.rs @@ -59,6 +59,9 @@ fn trait_inspect_methods_works() { // ptokens = dollar(25 + 25) / 1 / 0.5 / 0.02 = dollar(50) * 100 assert_ok!(Loans::mint(Origin::signed(DAVE), USDT, unit(50))); assert_eq!(Tokens::balance(PUSDT, &DAVE), unit(50) * 50); + + // `reducible_balance()` check how much collateral can be withdrawn from the amount deposited. + // Since no collateral has been deposited yet, this value is zero. assert_eq!(Loans::reducible_balance(PUSDT, &DAVE, true), 0); // enable USDT collateral assert_ok!(Loans::deposit_all_collateral(Origin::signed(DAVE), USDT)); From 4b94319b4f3e4933fe0d38e52242652ebf8b1999 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Fri, 14 Oct 2022 17:40:35 +0200 Subject: [PATCH 26/58] fix(loans): don't propagate on_slash errors; feature-gate test utils --- Cargo.lock | 22 +++++++++++----------- crates/loans/src/lib.rs | 22 +++++++++++++++++----- crates/loans/src/ptoken.rs | 2 +- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e2f0302d0e..527a1b4009 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5922,7 +5922,7 @@ dependencies = [ [[package]] name = "orml-asset-registry" version = "0.4.1-dev" -source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#250c3bf31aec734e6add7d8a0a325c7dcd06f55b" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#87306f17f34fe8003776c230cc6a5fd0e3c2724c" dependencies = [ "frame-support", "frame-system", @@ -5941,7 +5941,7 @@ dependencies = [ [[package]] name = "orml-oracle" version = "0.4.1-dev" -source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#250c3bf31aec734e6add7d8a0a325c7dcd06f55b" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#87306f17f34fe8003776c230cc6a5fd0e3c2724c" dependencies = [ "frame-support", "frame-system", @@ -5959,7 +5959,7 @@ dependencies = [ [[package]] name = "orml-tokens" version = "0.4.1-dev" -source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#250c3bf31aec734e6add7d8a0a325c7dcd06f55b" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#87306f17f34fe8003776c230cc6a5fd0e3c2724c" dependencies = [ "frame-support", "frame-system", @@ -5974,7 +5974,7 @@ dependencies = [ [[package]] name = "orml-traits" version = "0.4.1-dev" -source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#250c3bf31aec734e6add7d8a0a325c7dcd06f55b" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#87306f17f34fe8003776c230cc6a5fd0e3c2724c" dependencies = [ "frame-support", "impl-trait-for-tuples", @@ -5992,7 +5992,7 @@ dependencies = [ [[package]] name = "orml-unknown-tokens" version = "0.4.1-dev" -source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#250c3bf31aec734e6add7d8a0a325c7dcd06f55b" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#87306f17f34fe8003776c230cc6a5fd0e3c2724c" dependencies = [ "frame-support", "frame-system", @@ -6007,7 +6007,7 @@ dependencies = [ [[package]] name = "orml-utilities" version = "0.4.1-dev" -source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#250c3bf31aec734e6add7d8a0a325c7dcd06f55b" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#87306f17f34fe8003776c230cc6a5fd0e3c2724c" dependencies = [ "frame-support", "parity-scale-codec", @@ -6021,7 +6021,7 @@ dependencies = [ [[package]] name = "orml-vesting" version = "0.4.1-dev" -source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#250c3bf31aec734e6add7d8a0a325c7dcd06f55b" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#87306f17f34fe8003776c230cc6a5fd0e3c2724c" dependencies = [ "frame-support", "frame-system", @@ -6050,7 +6050,7 @@ dependencies = [ [[package]] name = "orml-xcm-support" version = "0.4.1-dev" -source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#250c3bf31aec734e6add7d8a0a325c7dcd06f55b" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#87306f17f34fe8003776c230cc6a5fd0e3c2724c" dependencies = [ "frame-support", "orml-traits", @@ -6064,7 +6064,7 @@ dependencies = [ [[package]] name = "orml-xtokens" version = "0.4.1-dev" -source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#250c3bf31aec734e6add7d8a0a325c7dcd06f55b" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#87306f17f34fe8003776c230cc6a5fd0e3c2724c" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -12736,9 +12736,9 @@ version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 0.1.10", "digest 0.10.3", - "rand 0.8.5", + "rand 0.6.5", "static_assertions", ] diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 8f2e46950d..10390026bf 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -87,13 +87,25 @@ type BalanceOf = <::Assets as Inspect<(marker::PhantomData); impl OnSlash, BalanceOf> for OnSlashHook { - fn on_slash(currency_id: AssetIdOf, account_id: &T::AccountId, _: BalanceOf) -> DispatchResult { + fn on_slash(currency_id: AssetIdOf, account_id: &T::AccountId, amount: BalanceOf) { if is_ctoken(currency_id) { - let underlying_id = Pallet::::underlying_id(currency_id)?; - Pallet::::update_reward_supply_index(underlying_id)?; - Pallet::::distribute_supplier_reward(underlying_id, account_id)?; + let f = || -> DispatchResult { + let underlying_id = Pallet::::underlying_id(currency_id)?; + Pallet::::update_reward_supply_index(underlying_id)?; + Pallet::::distribute_supplier_reward(underlying_id, account_id)?; + Ok(()) + }; + if let Err(e) = f() { + log::trace!( + target: "loans::on_slash", + "error: {:?}, currency_id: {:?}, account_id: {:?}, amount: {:?}", + e, + currency_id, + account_id, + amount, + ); + } } - Ok(()) } } diff --git a/crates/loans/src/ptoken.rs b/crates/loans/src/ptoken.rs index cbcde28e31..bae1857734 100644 --- a/crates/loans/src/ptoken.rs +++ b/crates/loans/src/ptoken.rs @@ -24,7 +24,7 @@ use frame_support::{ }, }; -// Utilities used for testing +#[cfg(test)] impl Pallet { /// The total amount of issuance in the system. pub fn total_issuance(ptoken_id: AssetIdOf) -> BalanceOf { From e3215ef97ba15634b5d6f887af724268f32b9a0a Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Fri, 14 Oct 2022 18:29:32 +0200 Subject: [PATCH 27/58] fix(loans): use a weghts-v1 compatible orml dependency --- Cargo.lock | 991 ++++++++++-------- crates/currency/Cargo.toml | 4 +- crates/fee/Cargo.toml | 4 +- crates/issue/Cargo.toml | 8 +- crates/loans/Cargo.toml | 6 +- crates/nomination/Cargo.toml | 8 +- crates/oracle/Cargo.toml | 4 +- crates/redeem/Cargo.toml | 8 +- crates/replace/Cargo.toml | 8 +- crates/staking/Cargo.toml | 4 +- crates/vault-registry/Cargo.toml | 4 +- parachain/runtime/interlay/Cargo.toml | 16 +- parachain/runtime/kintsugi/Cargo.toml | 16 +- parachain/runtime/runtime-tests/Cargo.toml | 12 +- parachain/runtime/testnet-interlay/Cargo.toml | 16 +- parachain/runtime/testnet-kintsugi/Cargo.toml | 16 +- standalone/runtime/Cargo.toml | 8 +- 17 files changed, 601 insertions(+), 532 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 527a1b4009..bd2d5642f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ "cfg-if 1.0.0", - "cipher", + "cipher 0.3.0", "cpufeatures", "opaque-debug 0.3.0", ] @@ -56,7 +56,7 @@ checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" dependencies = [ "aead", "aes", - "cipher", + "cipher 0.3.0", "ctr", "ghash", "subtle", @@ -75,9 +75,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" dependencies = [ "memchr", ] @@ -129,9 +129,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.63" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26fa4d7e3f2eebadf743988fc8aec9fa9a9e82611acafd77c1462ed6262440a" +checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" [[package]] name = "approx" @@ -233,9 +233,9 @@ dependencies = [ [[package]] name = "async-io" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab006897723d9352f63e2b13047177c3982d8d79709d713ce7747a8f19fd1b0" +checksum = "83e21f3a490c72b3b0cf44962180e60045de2925d8dff97918f7ee43c8f637c7" dependencies = [ "autocfg 1.1.0", "concurrent-queue", @@ -454,7 +454,7 @@ dependencies = [ [[package]] name = "beefy-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "beefy-primitives", "fnv", @@ -488,7 +488,7 @@ dependencies = [ [[package]] name = "beefy-gadget-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "beefy-gadget", "beefy-primitives", @@ -508,7 +508,7 @@ dependencies = [ [[package]] name = "beefy-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "beefy-primitives", "sp-api", @@ -517,7 +517,7 @@ dependencies = [ [[package]] name = "beefy-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "parity-scale-codec", "scale-info", @@ -611,7 +611,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9cf849ee05b2ee5fba5e36f97ff8ec2533916700fc0758d40d92136a42f3388" dependencies = [ - "digest 0.10.3", + "digest 0.10.5", ] [[package]] @@ -657,7 +657,7 @@ dependencies = [ "cc", "cfg-if 1.0.0", "constant_time_eq", - "digest 0.10.3", + "digest 0.10.5", ] [[package]] @@ -666,7 +666,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" dependencies = [ - "block-padding 0.1.5", + "block-padding", "byte-tools", "byteorder", "generic-array 0.12.4", @@ -678,15 +678,14 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "block-padding 0.2.1", "generic-array 0.14.6", ] [[package]] name = "block-buffer" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" dependencies = [ "generic-array 0.14.6", ] @@ -700,12 +699,6 @@ dependencies = [ "byte-tools", ] -[[package]] -name = "block-padding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" - [[package]] name = "blocking" version = "1.2.0" @@ -854,7 +847,7 @@ checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" dependencies = [ "camino", "cargo-platform", - "semver 1.0.13", + "semver 1.0.14", "serde", "serde_json", ] @@ -902,7 +895,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" dependencies = [ "cfg-if 1.0.0", - "cipher", + "cipher 0.3.0", "cpufeatures", "zeroize", ] @@ -915,7 +908,7 @@ checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" dependencies = [ "aead", "chacha20", - "cipher", + "cipher 0.3.0", "poly1305", "zeroize", ] @@ -957,6 +950,16 @@ dependencies = [ "generic-array 0.14.6", ] +[[package]] +name = "cipher" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "ckb-merkle-mountain-range" version = "0.3.2" @@ -968,9 +971,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.3.3" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a050e2153c5be08febd6734e29298e844fdb0fa21aeddd63b4eb7baa106c69b" +checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" dependencies = [ "glob", "libc", @@ -979,9 +982,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.19" +version = "3.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68d43934757334b5c0519ff882e1ab9647ac0258b47c24c4f490d78e42697fd5" +checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" dependencies = [ "atty", "bitflags", @@ -1067,6 +1070,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + [[package]] name = "collator-selection" version = "3.0.0" @@ -1167,9 +1180,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc948ebb96241bb40ab73effeb80d9f93afaad49359d159a5e61be51619fe813" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" dependencies = [ "libc", ] @@ -1302,15 +1315,14 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" +checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348" dependencies = [ "autocfg 1.1.0", "cfg-if 1.0.0", "crossbeam-utils", "memoffset", - "once_cell", "scopeguard", ] @@ -1326,12 +1338,11 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" +checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac" dependencies = [ "cfg-if 1.0.0", - "once_cell", ] [[package]] @@ -1347,7 +1358,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" dependencies = [ "generic-array 0.14.6", - "rand_core 0.6.3", + "rand_core 0.6.4", "subtle", "zeroize", ] @@ -1398,7 +1409,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" dependencies = [ - "cipher", + "cipher 0.3.0", ] [[package]] @@ -1415,7 +1426,7 @@ dependencies = [ [[package]] name = "cumulus-client-cli" version = "0.1.0" -source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "clap", "parity-scale-codec", @@ -1430,7 +1441,7 @@ dependencies = [ [[package]] name = "cumulus-client-collator" version = "0.1.0" -source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "cumulus-client-consensus-common", "cumulus-client-network", @@ -1454,7 +1465,7 @@ dependencies = [ [[package]] name = "cumulus-client-collator" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "cumulus-client-consensus-common", "cumulus-client-network", @@ -1478,7 +1489,7 @@ dependencies = [ [[package]] name = "cumulus-client-consensus-aura" version = "0.1.0" -source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "async-trait", "cumulus-client-consensus-common", @@ -1507,7 +1518,7 @@ dependencies = [ [[package]] name = "cumulus-client-consensus-common" version = "0.1.0" -source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "async-trait", "cumulus-relay-chain-interface", @@ -1528,7 +1539,7 @@ dependencies = [ [[package]] name = "cumulus-client-consensus-relay-chain" version = "0.1.0" -source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "async-trait", "cumulus-client-consensus-common", @@ -1552,7 +1563,7 @@ dependencies = [ [[package]] name = "cumulus-client-network" version = "0.1.0" -source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "async-trait", "cumulus-relay-chain-interface", @@ -1577,7 +1588,7 @@ dependencies = [ [[package]] name = "cumulus-client-pov-recovery" version = "0.1.0" -source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "cumulus-primitives-core", "cumulus-relay-chain-interface", @@ -1601,7 +1612,7 @@ dependencies = [ [[package]] name = "cumulus-client-service" version = "0.1.0" -source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "cumulus-client-cli", "cumulus-client-collator 0.1.0 (git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26)", @@ -1629,7 +1640,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-aura-ext" version = "0.1.0" -source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "frame-executive", "frame-support", @@ -1647,7 +1658,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-dmp-queue" version = "0.1.0" -source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -1665,7 +1676,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-parachain-system" version = "0.1.0" -source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "cumulus-pallet-parachain-system-proc-macro", "cumulus-primitives-core", @@ -1695,7 +1706,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-parachain-system-proc-macro" version = "0.1.0" -source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1706,7 +1717,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-xcm" version = "0.1.0" -source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -1723,7 +1734,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-xcmp-queue" version = "0.1.0" -source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -1741,7 +1752,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-core" version = "0.1.0" -source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "frame-support", "parity-scale-codec", @@ -1757,7 +1768,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-parachain-inherent" version = "0.1.0" -source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -1780,7 +1791,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-timestamp" version = "0.1.0" -source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "cumulus-primitives-core", "futures", @@ -1793,7 +1804,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-utility" version = "0.1.0" -source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -1810,7 +1821,7 @@ dependencies = [ [[package]] name = "cumulus-relay-chain-inprocess-interface" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -1840,7 +1851,7 @@ dependencies = [ [[package]] name = "cumulus-relay-chain-interface" version = "0.1.0" -source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -1863,7 +1874,7 @@ dependencies = [ [[package]] name = "cumulus-relay-chain-rpc-interface" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "async-trait", "backoff", @@ -1889,7 +1900,7 @@ dependencies = [ [[package]] name = "cumulus-test-relay-sproof-builder" version = "0.1.0" -source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "cumulus-primitives-core", "parity-scale-codec", @@ -1954,11 +1965,55 @@ checksum = "4033478fbf70d6acf2655ac70da91ee65852d69daf7a67bf7a2f518fb47aafcf" dependencies = [ "byteorder", "digest 0.9.0", - "rand_core 0.6.3", + "rand_core 0.6.4", "subtle", "zeroize", ] +[[package]] +name = "cxx" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f39818dcfc97d45b03953c1292efc4e80954e1583c4aa770bac1383e2310a4" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e580d70777c116df50c390d1211993f62d40302881e54d4b79727acb83d0199" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56a46460b88d1cec95112c8c363f0e2c39afdb237f60583b0b36343bf627ea9c" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747b608fecf06b0d72d440f27acc99288207324b793be2c17991839f3d4995ea" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "data-encoding" version = "2.3.2" @@ -2063,11 +2118,11 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" dependencies = [ - "block-buffer 0.10.2", + "block-buffer 0.10.3", "crypto-common", "subtle", ] @@ -2131,9 +2186,9 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "dtoa" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6053ff46b5639ceb91756a85a4c8914668393a03170efd79c8884a529d80656" +checksum = "f8a6eee2d5d0d113f015688310da018bd1d864d86bd567c8fca9c266889e1bfa" [[package]] name = "dyn-clonable" @@ -2215,7 +2270,7 @@ dependencies = [ "ff", "generic-array 0.14.6", "group", - "rand_core 0.6.3", + "rand_core 0.6.4", "sec1", "subtle", "zeroize", @@ -2266,9 +2321,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +checksum = "c90bf5f19754d10198ccb95b70664fc925bd1fc090a0fd9a6ebc54acc8cd6272" dependencies = [ "atty", "humantime", @@ -2453,7 +2508,7 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" dependencies = [ - "rand_core 0.6.3", + "rand_core 0.6.4", "subtle", ] @@ -2533,25 +2588,24 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "parity-scale-codec", ] [[package]] name = "form_urlencoded" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" dependencies = [ - "matches", "percent-encoding", ] [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-support", "frame-system", @@ -2573,7 +2627,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "Inflector", "chrono", @@ -2624,7 +2678,7 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2635,7 +2689,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -2651,7 +2705,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-support", "frame-system", @@ -2679,7 +2733,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "bitflags", "frame-metadata", @@ -2709,7 +2763,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "Inflector", "frame-support-procedural-tools", @@ -2721,7 +2775,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -2733,7 +2787,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "proc-macro2", "quote", @@ -2743,7 +2797,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-support", "log", @@ -2760,7 +2814,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -2775,7 +2829,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "parity-scale-codec", "sp-api", @@ -2784,7 +2838,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-support", "sp-api", @@ -3081,7 +3135,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" dependencies = [ "ff", - "rand_core 0.6.3", + "rand_core 0.6.4", "subtle", ] @@ -3106,9 +3160,9 @@ dependencies = [ [[package]] name = "handlebars" -version = "4.3.3" +version = "4.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360d9740069b2f6cbb63ce2dbaa71a20d3185350cbb990d7bebeb9318415eb17" +checksum = "433e4ab33f1213cdc25b5fa45c76881240cfe79284cf2b395e8b9e312a30a2fd" dependencies = [ "log", "pest", @@ -3262,7 +3316,7 @@ checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ "bytes", "fnv", - "itoa 1.0.3", + "itoa", ] [[package]] @@ -3309,7 +3363,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa 1.0.3", + "itoa", "pin-project-lite 0.2.9", "socket2", "tokio", @@ -3335,18 +3389,28 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.47" +version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c495f162af0bf17656d0014a0eded5f3cd2f365fdd204548c2869db89359dc7" +checksum = "f5a6ef98976b22b3b7f2f3a806f858cb862044cfa66805aa3ad84cb3d3b785ed" dependencies = [ "android_system_properties", "core-foundation-sys", + "iana-time-zone-haiku", "js-sys", - "once_cell", "wasm-bindgen", "winapi", ] +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fde6edd6cef363e9359ed3c98ba64590ba9eecba2293eb5a723ab32aee8926aa" +dependencies = [ + "cxx", + "cxx-build", +] + [[package]] name = "idna" version = "0.2.3" @@ -3358,6 +3422,16 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "if-addrs" version = "0.7.0" @@ -3426,6 +3500,15 @@ dependencies = [ "serde", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array 0.14.6", +] + [[package]] name = "instant" version = "0.1.12" @@ -3874,39 +3957,33 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" [[package]] name = "jobserver" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.59" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" dependencies = [ "wasm-bindgen", ] @@ -4331,9 +4408,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.132" +version = "0.2.135" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" +checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" [[package]] name = "libloading" @@ -4451,7 +4528,7 @@ dependencies = [ "rand 0.8.5", "ring", "rw-stream-sink", - "sha2 0.10.3", + "sha2 0.10.6", "smallvec", "thiserror", "unsigned-varint", @@ -4525,7 +4602,7 @@ dependencies = [ "prost-build", "rand 0.7.3", "regex", - "sha2 0.10.3", + "sha2 0.10.6", "smallvec", "unsigned-varint", "wasm-timer", @@ -4572,7 +4649,7 @@ dependencies = [ "prost", "prost-build", "rand 0.7.3", - "sha2 0.10.3", + "sha2 0.10.6", "smallvec", "thiserror", "uint", @@ -4650,7 +4727,7 @@ dependencies = [ "prost", "prost-build", "rand 0.8.5", - "sha2 0.10.3", + "sha2 0.10.6", "snow", "static_assertions", "x25519-dalek", @@ -4692,16 +4769,16 @@ dependencies = [ [[package]] name = "libp2p-pnet" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f1a458bbda880107b5b36fcb9b5a1ef0c329685da0e203ed692a8ebe64cc92c" +checksum = "1a5a702574223aa55d8878bdc8bf55c84a6086f87ddaddc28ce730b4caa81538" dependencies = [ "futures", "log", "pin-project", - "rand 0.7.3", + "rand 0.8.5", "salsa20", - "sha3 0.9.1", + "sha3", ] [[package]] @@ -4747,7 +4824,7 @@ dependencies = [ "prost", "prost-build", "rand 0.8.5", - "sha2 0.10.3", + "sha2 0.10.6", "thiserror", "unsigned-varint", "void", @@ -4998,6 +5075,15 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "link-cplusplus" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +dependencies = [ + "cc", +] + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -5037,9 +5123,9 @@ checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d" [[package]] name = "lock_api" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ "autocfg 1.1.0", "scopeguard", @@ -5057,18 +5143,18 @@ dependencies = [ [[package]] name = "lru" -version = "0.6.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ea2d928b485416e8908cff2d97d621db22b27f7b3b6729e438bcf42c671ba91" +checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" dependencies = [ - "hashbrown 0.11.2", + "hashbrown 0.12.3", ] [[package]] name = "lru" -version = "0.7.8" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" +checksum = "b6e8aaa3f231bb4bd57b84b2d5dc3ae7f350265df8aa96492e0bc394a1571909" dependencies = [ "hashbrown 0.12.3", ] @@ -5156,15 +5242,6 @@ dependencies = [ "libc", ] -[[package]] -name = "memmap2" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723e3ebdcdc5c023db1df315364573789f8857c11b631a2fdfad7c00f5c046b4" -dependencies = [ - "libc", -] - [[package]] name = "memmap2" version = "0.5.7" @@ -5196,11 +5273,11 @@ dependencies = [ [[package]] name = "memory-lru" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beeb98b3d1ed2c0054bd81b5ba949a0243c3ccad751d45ea898fa8059fa2860a" +checksum = "ce95ae042940bad7e312857b929ee3d11b8f799a80cb7b9c7ec5125516906395" dependencies = [ - "lru 0.6.6", + "lru 0.8.1", ] [[package]] @@ -5240,9 +5317,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" dependencies = [ "adler", ] @@ -5504,10 +5581,10 @@ dependencies = [ "blake2s_simd", "blake3", "core2", - "digest 0.10.3", + "digest 0.10.5", "multihash-derive", - "sha2 0.10.3", - "sha3 0.10.2", + "sha2 0.10.6", + "sha3", "unsigned-varint", ] @@ -5750,12 +5827,12 @@ dependencies = [ [[package]] name = "num-format" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bafe4179722c2894288ee77a9f044f02811c86af699344c498b0840c698a2465" +checksum = "54b862ff8df690cf089058c98b183676a7ed0f974cc08b426800093227cbff3b" dependencies = [ - "arrayvec 0.4.12", - "itoa 0.4.8", + "arrayvec 0.7.2", + "itoa", ] [[package]] @@ -5834,9 +5911,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.13.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e" +checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" [[package]] name = "opaque-debug" @@ -5922,7 +5999,7 @@ dependencies = [ [[package]] name = "orml-asset-registry" version = "0.4.1-dev" -source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#87306f17f34fe8003776c230cc6a5fd0e3c2724c" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/hooks-weights-v1#208dfa5adf718095e62a88c92954f453a6a4b1fb" dependencies = [ "frame-support", "frame-system", @@ -5941,7 +6018,7 @@ dependencies = [ [[package]] name = "orml-oracle" version = "0.4.1-dev" -source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#87306f17f34fe8003776c230cc6a5fd0e3c2724c" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/hooks-weights-v1#208dfa5adf718095e62a88c92954f453a6a4b1fb" dependencies = [ "frame-support", "frame-system", @@ -5959,7 +6036,7 @@ dependencies = [ [[package]] name = "orml-tokens" version = "0.4.1-dev" -source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#87306f17f34fe8003776c230cc6a5fd0e3c2724c" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/hooks-weights-v1#208dfa5adf718095e62a88c92954f453a6a4b1fb" dependencies = [ "frame-support", "frame-system", @@ -5974,7 +6051,7 @@ dependencies = [ [[package]] name = "orml-traits" version = "0.4.1-dev" -source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#87306f17f34fe8003776c230cc6a5fd0e3c2724c" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/hooks-weights-v1#208dfa5adf718095e62a88c92954f453a6a4b1fb" dependencies = [ "frame-support", "impl-trait-for-tuples", @@ -5992,7 +6069,7 @@ dependencies = [ [[package]] name = "orml-unknown-tokens" version = "0.4.1-dev" -source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#87306f17f34fe8003776c230cc6a5fd0e3c2724c" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/hooks-weights-v1#208dfa5adf718095e62a88c92954f453a6a4b1fb" dependencies = [ "frame-support", "frame-system", @@ -6007,7 +6084,7 @@ dependencies = [ [[package]] name = "orml-utilities" version = "0.4.1-dev" -source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#87306f17f34fe8003776c230cc6a5fd0e3c2724c" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/hooks-weights-v1#208dfa5adf718095e62a88c92954f453a6a4b1fb" dependencies = [ "frame-support", "parity-scale-codec", @@ -6021,7 +6098,7 @@ dependencies = [ [[package]] name = "orml-vesting" version = "0.4.1-dev" -source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#87306f17f34fe8003776c230cc6a5fd0e3c2724c" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/hooks-weights-v1#208dfa5adf718095e62a88c92954f453a6a4b1fb" dependencies = [ "frame-support", "frame-system", @@ -6050,7 +6127,7 @@ dependencies = [ [[package]] name = "orml-xcm-support" version = "0.4.1-dev" -source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#87306f17f34fe8003776c230cc6a5fd0e3c2724c" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/hooks-weights-v1#208dfa5adf718095e62a88c92954f453a6a4b1fb" dependencies = [ "frame-support", "orml-traits", @@ -6064,7 +6141,7 @@ dependencies = [ [[package]] name = "orml-xtokens" version = "0.4.1-dev" -source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/mutation-hooks#87306f17f34fe8003776c230cc6a5fd0e3c2724c" +source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/hooks-weights-v1#208dfa5adf718095e62a88c92954f453a6a4b1fb" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -6109,7 +6186,7 @@ dependencies = [ [[package]] name = "pallet-aura" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-support", "frame-system", @@ -6125,7 +6202,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-support", "frame-system", @@ -6141,7 +6218,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-support", "frame-system", @@ -6156,7 +6233,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6180,7 +6257,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6200,7 +6277,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6215,7 +6292,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "beefy-primitives", "frame-support", @@ -6231,7 +6308,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "beefy-merkle-tree", "beefy-primitives", @@ -6254,7 +6331,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6272,7 +6349,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6291,7 +6368,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6308,7 +6385,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6324,7 +6401,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6347,7 +6424,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6360,7 +6437,7 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6378,7 +6455,7 @@ dependencies = [ [[package]] name = "pallet-gilt" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6393,7 +6470,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6416,7 +6493,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6432,7 +6509,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6452,7 +6529,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6494,7 +6571,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6511,7 +6588,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "ckb-merkle-mountain-range", "frame-benchmarking", @@ -6529,7 +6606,7 @@ dependencies = [ [[package]] name = "pallet-mmr-rpc" version = "3.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -6544,7 +6621,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6559,7 +6636,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-support", "frame-system", @@ -6576,7 +6653,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6595,7 +6672,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-support", "frame-system", @@ -6612,7 +6689,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6635,7 +6712,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6651,7 +6728,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6666,7 +6743,7 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6681,7 +6758,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6697,7 +6774,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-support", "frame-system", @@ -6718,7 +6795,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6734,7 +6811,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-support", "frame-system", @@ -6748,7 +6825,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6771,7 +6848,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -6782,7 +6859,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "log", "sp-arithmetic", @@ -6791,7 +6868,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-support", "frame-system", @@ -6805,7 +6882,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6823,7 +6900,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6864,7 +6941,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-support", "frame-system", @@ -6880,7 +6957,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -6895,7 +6972,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -6906,7 +6983,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6923,7 +7000,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6939,7 +7016,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6989,7 +7066,7 @@ dependencies = [ [[package]] name = "parachain-info" version = "0.1.0" -source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#e43b8b878a6fd0ca8b5e88d19822c4d777d3c677" +source = "git+https://github.com/paritytech//cumulus?branch=polkadot-v0.9.26#be9e23c377555cabb867326ace51e0ab72bee1b9" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -7104,9 +7181,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb474d0ed0836e185cb998a6b140ed1073d1fbf27d690ecf9ede8030289382c" +checksum = "2c8fdb726a43661fa54b43e7114e6b88b2289cae388eb3ad766d9d1754d83fce" dependencies = [ "blake2-rfc", "crc32fast", @@ -7115,17 +7192,17 @@ dependencies = [ "libc", "log", "lz4", - "memmap2 0.2.3", - "parking_lot 0.11.2", + "memmap2", + "parking_lot 0.12.1", "rand 0.8.5", "snap", ] [[package]] name = "parity-scale-codec" -version = "3.1.5" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9182e4a71cae089267ab03e67c99368db7cd877baf50f931e5d6d4b71e195ac0" +checksum = "366e44391a8af4cfd6002ef6ba072bae071a96aafca98d7d448a34c5dca38b6a" dependencies = [ "arrayvec 0.7.2", "bitvec", @@ -7281,15 +7358,15 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "percent-encoding" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0560d531d1febc25a3c9398a62a71256c0178f2e3443baedd9ad4bb8c9deb4" +checksum = "dbc7bc69c062e492337d74d59b120c274fd3d261b6bf6d3207d499b4b379c41a" dependencies = [ "thiserror", "ucd-trie", @@ -7297,9 +7374,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "905708f7f674518498c1f8d644481440f476d39ca6ecae83319bba7c6c12da91" +checksum = "60b75706b9642ebcb34dab3bc7750f811609a0eb1dd8b88c2d15bf628c1c65b2" dependencies = [ "pest", "pest_generator", @@ -7307,9 +7384,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5803d8284a629cc999094ecd630f55e91b561a1d1ba75e233b00ae13b91a69ad" +checksum = "f4f9272122f5979a6511a749af9db9bfc810393f63119970d7085fed1c4ea0db" dependencies = [ "pest", "pest_meta", @@ -7320,13 +7397,13 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1538eb784f07615c6d9a8ab061089c6c54a344c5b4301db51990ca1c241e8c04" +checksum = "4c8717927f9b79515e565a64fe46c38b8cd0427e64c40680b14a7365ab09ac8d" dependencies = [ "once_cell", "pest", - "sha-1 0.10.0", + "sha1", ] [[package]] @@ -8628,18 +8705,18 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.43" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" dependencies = [ "unicode-ident", ] [[package]] name = "prometheus" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cface98dfa6d645ea4c789839f176e4b072265d085bfcc48eaa8d137f58d3c39" +checksum = "45c8babc29389186697fe5a2a4859d697825496b83db5d0b65271cdc0488e88c" dependencies = [ "cfg-if 1.0.0", "fnv", @@ -8656,7 +8733,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac1abe0255c04d15f571427a2d1e00099016506cf3297b53853acd2b7eb87825" dependencies = [ "dtoa", - "itoa 1.0.3", + "itoa", "owning_ref", "prometheus-client-derive-text-encode", ] @@ -8742,9 +8819,9 @@ dependencies = [ [[package]] name = "psm" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f446d0a6efba22928558c4fb4ce0b3fd6c89b0061343e390bf01a703742b8125" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" dependencies = [ "cc", ] @@ -8822,7 +8899,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha 0.3.1", - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -8852,7 +8929,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -8881,9 +8958,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom 0.2.7", ] @@ -8975,7 +9052,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e" dependencies = [ - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -9092,18 +9169,18 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed13bcd201494ab44900a96490291651d200730904221832b9547d24a87d332b" +checksum = "12a733f1746c929b4913fe48f8697fcf9c55e3304ba251a79ffb41adfeaf49c2" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5234cd6063258a5e32903b53b1b6ac043a0541c8adc1f610f67b0326c7a578fa" +checksum = "5887de4a01acafd221861463be6113e6e87275e79804e56779f4cdc131c60368" dependencies = [ "proc-macro2", "quote", @@ -9163,7 +9240,7 @@ dependencies = [ [[package]] name = "remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "env_logger", "jsonrpsee", @@ -9421,7 +9498,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.13", + "semver 1.0.14", ] [[package]] @@ -9440,9 +9517,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.35.9" +version = "0.35.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c825b8aa8010eb9ee99b75f05e10180b9278d161583034d7574c9d617aeada" +checksum = "fbb2fda4666def1433b1b05431ab402e42a1084285477222b72d6c564c417cef" dependencies = [ "bitflags", "errno", @@ -9510,11 +9587,11 @@ checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" [[package]] name = "salsa20" -version = "0.9.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0fbb5f676da676c260ba276a8f43a8dc67cf02d1438423aeb1c677a7212686" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" dependencies = [ - "cipher", + "cipher 0.4.3", ] [[package]] @@ -9529,7 +9606,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "log", "sp-core", @@ -9540,7 +9617,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "async-trait", "futures", @@ -9567,7 +9644,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "futures", "futures-timer", @@ -9590,7 +9667,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -9606,10 +9683,10 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "impl-trait-for-tuples", - "memmap2 0.5.7", + "memmap2", "parity-scale-codec", "sc-chain-spec-derive", "sc-network", @@ -9623,7 +9700,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -9634,7 +9711,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "chrono", "clap", @@ -9673,7 +9750,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "fnv", "futures", @@ -9701,7 +9778,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "hash-db", "kvdb", @@ -9726,7 +9803,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "async-trait", "futures", @@ -9750,7 +9827,7 @@ dependencies = [ [[package]] name = "sc-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "async-trait", "futures", @@ -9779,7 +9856,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "async-trait", "fork-tree", @@ -9822,7 +9899,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "futures", "jsonrpsee", @@ -9844,7 +9921,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "fork-tree", "parity-scale-codec", @@ -9857,7 +9934,7 @@ dependencies = [ [[package]] name = "sc-consensus-manual-seal" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "assert_matches", "async-trait", @@ -9891,7 +9968,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "async-trait", "futures", @@ -9916,7 +9993,7 @@ dependencies = [ [[package]] name = "sc-consensus-uncles" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "sc-client-api", "sp-authorship", @@ -9927,7 +10004,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "lazy_static", "lru 0.7.8", @@ -9954,7 +10031,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "environmental", "parity-scale-codec", @@ -9971,7 +10048,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmi" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "log", "parity-scale-codec", @@ -9986,7 +10063,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "cfg-if 1.0.0", "libc", @@ -9994,7 +10071,7 @@ dependencies = [ "once_cell", "parity-scale-codec", "parity-wasm 0.42.2", - "rustix 0.35.9", + "rustix 0.35.11", "sc-allocator", "sc-executor-common", "sp-runtime-interface", @@ -10006,7 +10083,7 @@ dependencies = [ [[package]] name = "sc-finality-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "ahash", "async-trait", @@ -10046,7 +10123,7 @@ dependencies = [ [[package]] name = "sc-finality-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "finality-grandpa", "futures", @@ -10067,7 +10144,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "ansi_term", "futures", @@ -10084,7 +10161,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "async-trait", "hex", @@ -10099,7 +10176,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "async-trait", "asynchronous-codec", @@ -10151,7 +10228,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "futures", "libp2p", @@ -10164,7 +10241,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "ahash", "futures", @@ -10181,7 +10258,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "futures", "libp2p", @@ -10201,7 +10278,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "bitflags", "either", @@ -10230,7 +10307,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "bytes", "fnv", @@ -10258,7 +10335,7 @@ dependencies = [ [[package]] name = "sc-peerset" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "futures", "libp2p", @@ -10271,7 +10348,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -10280,7 +10357,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "futures", "hash-db", @@ -10310,7 +10387,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "futures", "jsonrpsee", @@ -10333,7 +10410,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "futures", "jsonrpsee", @@ -10346,7 +10423,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "async-trait", "directories", @@ -10411,7 +10488,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "log", "parity-scale-codec", @@ -10425,7 +10502,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -10444,7 +10521,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "futures", "libc", @@ -10463,7 +10540,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "futures", "libc", @@ -10482,7 +10559,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "chrono", "futures", @@ -10500,7 +10577,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "ansi_term", "atty", @@ -10531,7 +10608,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10542,7 +10619,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "futures", "futures-timer", @@ -10569,7 +10646,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "futures", "log", @@ -10582,7 +10659,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "futures", "futures-timer", @@ -10594,9 +10671,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c46be926081c9f4dd5dd9b6f1d3e3229f2360bc6502dd8836f84a93b7c75e99a" +checksum = "333af15b02563b8182cd863f925bd31ef8fa86a0e095d30c091956057d436153" dependencies = [ "bitvec", "cfg-if 1.0.0", @@ -10608,9 +10685,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e334bb10a245e28e5fd755cabcafd96cfcd167c99ae63a46924ca8d8703a3c" +checksum = "53f56acbd0743d29ffa08f911ab5397def774ad01bab3786804cf6ee057fb5e1" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10652,6 +10729,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scratch" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" + [[package]] name = "sct" version = "0.7.0" @@ -10769,9 +10852,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f6841e709003d68bb2deee8c343572bf446003ec20a583e76f7b15cebf3711" +checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" dependencies = [ "serde", ] @@ -10784,18 +10867,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.144" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" +checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.144" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" +checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" dependencies = [ "proc-macro2", "quote", @@ -10804,11 +10887,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" +checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074" dependencies = [ - "itoa 1.0.3", + "itoa", "ryu", "serde", ] @@ -10836,14 +10919,14 @@ dependencies = [ ] [[package]] -name = "sha-1" -version = "0.10.0" +name = "sha1" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.3", + "digest 0.10.5", ] [[package]] @@ -10873,34 +10956,22 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.3" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899bf02746a2c92bf1053d9327dadb252b01af1f81f90cdb902411f518bc7215" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.3", -] - -[[package]] -name = "sha3" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" -dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "keccak", - "opaque-debug 0.3.0", + "digest 0.10.5", ] [[package]] name = "sha3" -version = "0.10.2" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a31480366ec990f395a61b7c08122d99bd40544fdb5abcfc1b06bb29994312c" +checksum = "e2904bea16a1ae962b483322a1c7b81d976029203aea1f461e51cd7705db7ba9" dependencies = [ - "digest 0.10.3", + "digest 0.10.5", "keccak", ] @@ -10945,7 +11016,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" dependencies = [ "digest 0.9.0", - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -10998,9 +11069,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "snap" @@ -11018,10 +11089,10 @@ dependencies = [ "blake2", "chacha20poly1305", "curve25519-dalek 4.0.0-pre.1", - "rand_core 0.6.3", + "rand_core 0.6.4", "ring", "rustc_version", - "sha2 0.10.3", + "sha2 0.10.6", "subtle", ] @@ -11048,13 +11119,13 @@ dependencies = [ "httparse", "log", "rand 0.8.5", - "sha-1 0.9.8", + "sha-1", ] [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "hash-db", "log", @@ -11071,7 +11142,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "blake2", "proc-macro-crate", @@ -11083,7 +11154,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "6.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "parity-scale-codec", "scale-info", @@ -11096,7 +11167,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "5.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "integer-sqrt", "num-traits", @@ -11111,7 +11182,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "parity-scale-codec", "scale-info", @@ -11124,7 +11195,7 @@ dependencies = [ [[package]] name = "sp-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "async-trait", "parity-scale-codec", @@ -11136,7 +11207,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "parity-scale-codec", "sp-api", @@ -11148,7 +11219,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "futures", "log", @@ -11166,7 +11237,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "async-trait", "futures", @@ -11185,7 +11256,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "async-trait", "parity-scale-codec", @@ -11203,7 +11274,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "async-trait", "merlin", @@ -11226,7 +11297,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "parity-scale-codec", "scale-info", @@ -11240,7 +11311,7 @@ dependencies = [ [[package]] name = "sp-consensus-vrf" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "parity-scale-codec", "scale-info", @@ -11253,7 +11324,7 @@ dependencies = [ [[package]] name = "sp-core" version = "6.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "base58", "bitflags", @@ -11299,13 +11370,13 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "4.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "blake2", "byteorder", - "digest 0.10.3", - "sha2 0.10.3", - "sha3 0.10.2", + "digest 0.10.5", + "sha2 0.10.6", + "sha3", "sp-std", "twox-hash", ] @@ -11313,7 +11384,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "5.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "proc-macro2", "quote", @@ -11324,7 +11395,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -11333,7 +11404,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "4.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "proc-macro2", "quote", @@ -11343,7 +11414,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.12.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "environmental", "parity-scale-codec", @@ -11354,7 +11425,7 @@ dependencies = [ [[package]] name = "sp-finality-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "finality-grandpa", "log", @@ -11372,7 +11443,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -11386,7 +11457,7 @@ dependencies = [ [[package]] name = "sp-io" version = "6.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "futures", "hash-db", @@ -11411,7 +11482,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "6.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "lazy_static", "sp-core", @@ -11422,7 +11493,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.12.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "async-trait", "futures", @@ -11439,7 +11510,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "thiserror", "zstd", @@ -11448,7 +11519,7 @@ dependencies = [ [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "log", "parity-scale-codec", @@ -11463,7 +11534,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "parity-scale-codec", "scale-info", @@ -11477,7 +11548,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "sp-api", "sp-core", @@ -11487,7 +11558,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "4.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "backtrace", "lazy_static", @@ -11497,7 +11568,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "rustc-hash", "serde", @@ -11507,7 +11578,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "6.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "either", "hash256-std-hasher", @@ -11529,7 +11600,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "6.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", @@ -11546,7 +11617,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "5.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "Inflector", "proc-macro-crate", @@ -11558,7 +11629,7 @@ dependencies = [ [[package]] name = "sp-sandbox" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "log", "parity-scale-codec", @@ -11572,7 +11643,7 @@ dependencies = [ [[package]] name = "sp-serializer" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "serde", "serde_json", @@ -11581,7 +11652,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "parity-scale-codec", "scale-info", @@ -11595,7 +11666,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "parity-scale-codec", "scale-info", @@ -11606,7 +11677,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.12.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "hash-db", "log", @@ -11628,12 +11699,12 @@ dependencies = [ [[package]] name = "sp-std" version = "4.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" [[package]] name = "sp-storage" version = "6.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "impl-serde", "parity-scale-codec", @@ -11646,7 +11717,7 @@ dependencies = [ [[package]] name = "sp-tasks" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "log", "sp-core", @@ -11659,7 +11730,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "async-trait", "futures-timer", @@ -11675,7 +11746,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "5.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "parity-scale-codec", "sp-std", @@ -11687,7 +11758,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "sp-api", "sp-runtime", @@ -11696,7 +11767,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "async-trait", "log", @@ -11712,7 +11783,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "6.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "hash-db", "memory-db", @@ -11728,7 +11799,7 @@ dependencies = [ [[package]] name = "sp-version" version = "5.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "impl-serde", "parity-scale-codec", @@ -11745,7 +11816,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -11756,7 +11827,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "6.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "impl-trait-for-tuples", "log", @@ -11780,9 +11851,9 @@ checksum = "13287b4da9d1207a4f4929ac390916d64eacfe236a487e9a9f5b3be392be5162" [[package]] name = "ss58-registry" -version = "1.28.0" +version = "1.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c8a1e645fa0bd3e81a90e592a677f7ada3182ac338c4a71cd9ec0ba911f6abb" +checksum = "3ab7554f8a8b6f8d71cd5a8e6536ef116e2ce0504cf97ebf16311d58065dc8a6" dependencies = [ "Inflector", "num-format", @@ -11932,7 +12003,7 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "platforms", ] @@ -11940,7 +12011,7 @@ dependencies = [ [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "frame-system-rpc-runtime-api", "futures", @@ -11961,7 +12032,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "futures-util", "hyper", @@ -11974,7 +12045,7 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "jsonrpsee", "log", @@ -11995,7 +12066,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "ansi_term", "build-helper", @@ -12038,9 +12109,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.99" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" dependencies = [ "proc-macro2", "quote", @@ -12315,24 +12386,24 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16" [[package]] name = "thiserror" -version = "1.0.33" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0a539a918745651435ac7db7a18761589a94cd7e94cd56999f828bf73c8a57" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.33" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c251e90f708e16c49a16f4917dc2131e75222b72edfa9cb7f7c58ae56aae0c09" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" dependencies = [ "proc-macro2", "quote", @@ -12434,9 +12505,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.20.1" +version = "1.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a8325f63a7d4774dd041e363b2409ed1c5cbbd0f867795e661df066b2b0a581" +checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" dependencies = [ "autocfg 1.1.0", "bytes", @@ -12444,7 +12515,6 @@ dependencies = [ "memchr", "mio", "num_cpus", - "once_cell", "parking_lot 0.12.1", "pin-project-lite 0.2.9", "signal-hook-registry", @@ -12477,9 +12547,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9" +checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" dependencies = [ "futures-core", "pin-project-lite 0.2.9", @@ -12488,9 +12558,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" dependencies = [ "bytes", "futures-core", @@ -12518,9 +12588,9 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.36" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if 1.0.0", "pin-project-lite 0.2.9", @@ -12530,9 +12600,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", @@ -12541,9 +12611,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.29" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" dependencies = [ "once_cell", "valuable", @@ -12663,7 +12733,7 @@ dependencies = [ "futures-channel", "futures-io", "futures-util", - "idna", + "idna 0.2.3", "ipnet", "lazy_static", "log", @@ -12702,7 +12772,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" dependencies = [ "clap", "jsonrpsee", @@ -12736,9 +12806,9 @@ version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ - "cfg-if 0.1.10", - "digest 0.10.3", - "rand 0.6.5", + "cfg-if 1.0.0", + "digest 0.10.5", + "rand 0.8.5", "static_assertions", ] @@ -12750,15 +12820,15 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "ucd-trie" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89570599c4fe5585de2b388aab47e99f7fa4e9238a1399f707a02e356058141c" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" [[package]] name = "uint" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f03af7ccf01dd611cc450a0d10dbc9b745770d096473e2faf0ca6e2d66d1e0" +checksum = "a45526d29728d135c2900b0d30573fe3ee79fceb12ef534c7bb30e810a91b601" dependencies = [ "byteorder", "crunchy", @@ -12783,36 +12853,36 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" [[package]] name = "unicode-normalization" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" [[package]] name = "unicode-width" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "unicode-xid" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "universal-hash" @@ -12844,13 +12914,12 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.2.2" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" dependencies = [ "form_urlencoded", - "idna", - "matches", + "idna 0.3.0", "percent-encoding", ] @@ -12979,9 +13048,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -12989,9 +13058,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" dependencies = [ "bumpalo", "log", @@ -13004,9 +13073,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.32" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa76fb221a1f8acddf5b54ace85912606980ad661ac7a503b4570ffd3a624dad" +checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -13016,9 +13085,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -13026,9 +13095,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ "proc-macro2", "quote", @@ -13039,9 +13108,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" [[package]] name = "wasm-gc-api" @@ -13282,9 +13351,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.59" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" dependencies = [ "js-sys", "wasm-bindgen", @@ -13302,9 +13371,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.22.4" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1c760f0d366a6c24a02ed7816e23e691f5d92291f94d15e836006fd11b04daf" +checksum = "368bfe657969fb01238bb756d351dcade285e0f6fcbd36dcb23359a5169975be" dependencies = [ "webpki", ] @@ -13736,4 +13805,4 @@ dependencies = [ [[patch.unused]] name = "pallet-nicks" version = "4.0.0-dev" -source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#e8a7d161f39db70cb27fdad6c6e215cf493ebc3b" +source = "git+https://github.com/paritytech//substrate?branch=polkadot-v0.9.26#1cca061ede75a4c693a3b71bd1b61d7275fe29e4" diff --git a/crates/currency/Cargo.toml b/crates/currency/Cargo.toml index 1ac0439bec..f084a49b04 100644 --- a/crates/currency/Cargo.toml +++ b/crates/currency/Cargo.toml @@ -21,8 +21,8 @@ pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } # for other pallets wanting to mock functions mocktopus = {version = "0.7.0", optional = true } diff --git a/crates/fee/Cargo.toml b/crates/fee/Cargo.toml index 381cf12c8d..797d7108a1 100644 --- a/crates/fee/Cargo.toml +++ b/crates/fee/Cargo.toml @@ -35,8 +35,8 @@ pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = " currency = { path = "../currency", features = ["testing-utils"] } # Orml dependencies -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } # Parachain dependencies primitives = { package = "interbtc-primitives", path = "../../primitives"} diff --git a/crates/issue/Cargo.toml b/crates/issue/Cargo.toml index 08fbd3f483..4915cacede 100644 --- a/crates/issue/Cargo.toml +++ b/crates/issue/Cargo.toml @@ -35,8 +35,8 @@ vault-registry = { path = "../vault-registry", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false, optional = true } -orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false, optional = true } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false, optional = true } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false, optional = true } [dev-dependencies] mocktopus = "0.7.0" @@ -47,8 +47,8 @@ reward = { path = "../reward" } staking = { path = "../staking" } # Orml dependencies -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks" } -orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks" } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1" } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1" } [features] default = ["std"] diff --git a/crates/loans/Cargo.toml b/crates/loans/Cargo.toml index d366b456aa..0d856ef810 100644 --- a/crates/loans/Cargo.toml +++ b/crates/loans/Cargo.toml @@ -13,9 +13,9 @@ frame-benchmarking = { git = 'https://github.com/paritytech/substrate.git', bran frame-support = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } frame-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } num-traits = { default-features = false, version = '0.2' } -orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-oracle = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-oracle = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } pallet-timestamp = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } pallet-traits = { path = '../traits', default-features = false } primitives = { package = 'interbtc-primitives', path = '../../primitives', default-features = false } diff --git a/crates/nomination/Cargo.toml b/crates/nomination/Cargo.toml index c06aa8de25..e0167868d9 100644 --- a/crates/nomination/Cargo.toml +++ b/crates/nomination/Cargo.toml @@ -33,16 +33,16 @@ staking = { path = "../staking", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false, optional = true } -orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false, optional = true } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false, optional = true } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false, optional = true } [dev-dependencies] mocktopus = "0.7.0" frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.26", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } [features] default = ["std"] diff --git a/crates/oracle/Cargo.toml b/crates/oracle/Cargo.toml index bd4314c4d2..7e72df66e8 100644 --- a/crates/oracle/Cargo.toml +++ b/crates/oracle/Cargo.toml @@ -31,8 +31,8 @@ mocktopus = "0.7.0" frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.26", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } [features] default = ["std"] diff --git a/crates/redeem/Cargo.toml b/crates/redeem/Cargo.toml index 72931dd152..e3a796f3a0 100644 --- a/crates/redeem/Cargo.toml +++ b/crates/redeem/Cargo.toml @@ -33,8 +33,8 @@ vault-registry = { path = "../vault-registry", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false, optional = true } -orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false, optional = true } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false, optional = true } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false, optional = true } [dev-dependencies] mocktopus = "0.7.0" @@ -46,8 +46,8 @@ staking = { path = "../staking" } currency = { path = "../currency", features = ["testing-utils"] } # Orml dependencies -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks" } -orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks" } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1" } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1" } [features] default = ["std"] diff --git a/crates/replace/Cargo.toml b/crates/replace/Cargo.toml index 80f26379d1..cb28c27e2c 100644 --- a/crates/replace/Cargo.toml +++ b/crates/replace/Cargo.toml @@ -34,8 +34,8 @@ nomination = { path = "../nomination", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false, optional = true } -orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false, optional = true } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false, optional = true } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false, optional = true } [dev-dependencies] mocktopus = "0.7.0" @@ -47,8 +47,8 @@ staking = { path = "../staking" } currency = { path = "../currency", features = ["testing-utils"] } # Orml dependencies -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks" } -orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks" } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1" } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1" } [features] default = ["std"] diff --git a/crates/staking/Cargo.toml b/crates/staking/Cargo.toml index ecd62166c1..4b8872a020 100644 --- a/crates/staking/Cargo.toml +++ b/crates/staking/Cargo.toml @@ -25,8 +25,8 @@ frame-system = { git = "https://github.com/paritytech/substrate", branch = "polk frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.26", default-features = false, optional = true } # note: can be remove after removal of migration -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } [dev-dependencies] mocktopus = "0.7.0" diff --git a/crates/vault-registry/Cargo.toml b/crates/vault-registry/Cargo.toml index e251d91730..b7dd007e8c 100644 --- a/crates/vault-registry/Cargo.toml +++ b/crates/vault-registry/Cargo.toml @@ -37,8 +37,8 @@ staking = { path = "../staking", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } [dev-dependencies] mocktopus = "0.7.0" diff --git a/parachain/runtime/interlay/Cargo.toml b/parachain/runtime/interlay/Cargo.toml index 2f848044e8..e2b679c2ae 100644 --- a/parachain/runtime/interlay/Cargo.toml +++ b/parachain/runtime/interlay/Cargo.toml @@ -106,14 +106,14 @@ module-redeem-rpc-runtime-api = { path = "../../../crates/redeem/rpc/runtime-api module-replace-rpc-runtime-api = { path = "../../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-vesting = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } - -orml-xtokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-xcm-support = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-unknown-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-asset-registry = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-vesting = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } + +orml-xtokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-xcm-support = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-unknown-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-asset-registry = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } [dev-dependencies] hex = '0.4.2' diff --git a/parachain/runtime/kintsugi/Cargo.toml b/parachain/runtime/kintsugi/Cargo.toml index 988528c635..0998fbbfe9 100644 --- a/parachain/runtime/kintsugi/Cargo.toml +++ b/parachain/runtime/kintsugi/Cargo.toml @@ -106,14 +106,14 @@ module-redeem-rpc-runtime-api = { path = "../../../crates/redeem/rpc/runtime-api module-replace-rpc-runtime-api = { path = "../../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-vesting = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } - -orml-xtokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-xcm-support = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-unknown-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-asset-registry = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-vesting = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } + +orml-xtokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-xcm-support = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-unknown-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-asset-registry = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } [dev-dependencies] hex = '0.4.2' diff --git a/parachain/runtime/runtime-tests/Cargo.toml b/parachain/runtime/runtime-tests/Cargo.toml index 2c594818ce..d8a6123f62 100644 --- a/parachain/runtime/runtime-tests/Cargo.toml +++ b/parachain/runtime/runtime-tests/Cargo.toml @@ -112,14 +112,14 @@ module-redeem-rpc-runtime-api = { path = "../../../crates/redeem/rpc/runtime-api module-replace-rpc-runtime-api = { path = "../../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-vesting = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-vesting = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } -orml-xtokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-xtokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } orml-xcm = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "8c625a5ab43c1c56cdeed5f8d814a891566d4cf8", default-features = false } -orml-xcm-support = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-unknown-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-xcm-support = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-unknown-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } xcm-emulator = { git = "https://github.com/shaunxw/xcm-simulator", rev = "ab5cd6c5fabe6ddda52ed6803ee1bf54c258fefe" } diff --git a/parachain/runtime/testnet-interlay/Cargo.toml b/parachain/runtime/testnet-interlay/Cargo.toml index cd9aef400f..a320113c92 100644 --- a/parachain/runtime/testnet-interlay/Cargo.toml +++ b/parachain/runtime/testnet-interlay/Cargo.toml @@ -107,14 +107,14 @@ module-redeem-rpc-runtime-api = { path = "../../../crates/redeem/rpc/runtime-api module-replace-rpc-runtime-api = { path = "../../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-vesting = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } - -orml-xtokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-xcm-support = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-unknown-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-asset-registry = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-vesting = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } + +orml-xtokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-xcm-support = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-unknown-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-asset-registry = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } [dev-dependencies] hex = '0.4.2' diff --git a/parachain/runtime/testnet-kintsugi/Cargo.toml b/parachain/runtime/testnet-kintsugi/Cargo.toml index bbf94c3301..1b048af197 100644 --- a/parachain/runtime/testnet-kintsugi/Cargo.toml +++ b/parachain/runtime/testnet-kintsugi/Cargo.toml @@ -107,14 +107,14 @@ module-redeem-rpc-runtime-api = { path = "../../../crates/redeem/rpc/runtime-api module-replace-rpc-runtime-api = { path = "../../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-vesting = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } - -orml-xtokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-xcm-support = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-unknown-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-asset-registry = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-vesting = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } + +orml-xtokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-xcm-support = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-unknown-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-asset-registry = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } [dev-dependencies] hex = '0.4.2' diff --git a/standalone/runtime/Cargo.toml b/standalone/runtime/Cargo.toml index 60d0d8543e..f9fbf82b38 100644 --- a/standalone/runtime/Cargo.toml +++ b/standalone/runtime/Cargo.toml @@ -89,10 +89,10 @@ module-redeem-rpc-runtime-api = { path = "../../crates/redeem/rpc/runtime-api", module-replace-rpc-runtime-api = { path = "../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-vesting = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } -orml-asset-registry = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/mutation-hooks", default-features = false } +orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-vesting = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } +orml-asset-registry = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.26", default-features = false } From e18c703b788e96e92f70796ee9e990eec8d439c6 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Mon, 17 Oct 2022 21:24:13 +0200 Subject: [PATCH 28/58] feat(loans): ptokens as currency id --- crates/loans/src/benchmarking.rs | 13 ++++++------- crates/loans/src/lib.rs | 8 ++++---- crates/loans/src/mock.rs | 24 +++++++++++++++--------- crates/loans/src/tests/market.rs | 10 +++++----- crates/loans/src/tests/ptokens.rs | 12 ++++++------ primitives/src/lib.rs | 20 ++++---------------- standalone/runtime/src/lib.rs | 3 ++- standalone/runtime/tests/mock/mod.rs | 7 +++++++ standalone/runtime/tests/test_loans.rs | 10 +++++----- 9 files changed, 54 insertions(+), 53 deletions(-) diff --git a/crates/loans/src/benchmarking.rs b/crates/loans/src/benchmarking.rs index b99ae41457..47b36d7d34 100644 --- a/crates/loans/src/benchmarking.rs +++ b/crates/loans/src/benchmarking.rs @@ -9,9 +9,8 @@ use frame_support::assert_ok; use frame_system::{self, RawOrigin as SystemOrigin}; use primitives::{ Balance, - CurrencyId::{self, Token}, - CDOT as CDOT_CURRENCY, CKBTC as CKBTC_CURRENCY, CKSM as CKSM_CURRENCY, DOT as DOT_CURRENCY, KBTC as KBTC_CURRENCY, - KINT as KINT_CURRENCY, KSM as KSM_CURRENCY, + CurrencyId::{self, PToken, Token}, + DOT as DOT_CURRENCY, KBTC as KBTC_CURRENCY, KINT as KINT_CURRENCY, KSM as KSM_CURRENCY, }; use rate_model::{InterestRateModel, JumpModel}; use sp_std::prelude::*; @@ -20,10 +19,10 @@ const SEED: u32 = 0; const KSM: CurrencyId = Token(KSM_CURRENCY); const KBTC: CurrencyId = Token(KBTC_CURRENCY); -const CKSM: CurrencyId = Token(CKSM_CURRENCY); -const CKBTC: CurrencyId = Token(CKBTC_CURRENCY); +const CKSM: CurrencyId = PToken(3); +const CKBTC: CurrencyId = PToken(4); const DOT: CurrencyId = Token(DOT_CURRENCY); -const CDOT: CurrencyId = Token(CDOT_CURRENCY); +const CDOT: CurrencyId = PToken(1); const KINT: CurrencyId = Token(KINT_CURRENCY); const RATE_MODEL_MOCK: InterestRateModel = InterestRateModel::Jump(JumpModel { @@ -50,7 +49,7 @@ fn market_mock() -> Market> { liquidate_incentive_reserved_factor: Ratio::from_percent(3), supply_cap: 1_000_000_000_000_000_000_000u128, // set to 1B borrow_cap: 1_000_000_000_000_000_000_000u128, // set to 1B - ptoken_id: CurrencyId::Token(CKBTC_CURRENCY), + ptoken_id: CurrencyId::PToken(4), } } diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 10390026bf..3f4d1db95c 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -45,7 +45,7 @@ pub use pallet::*; use pallet_traits::{ ConvertToBigUint, Loans as LoansTrait, LoansMarketDataProvider, MarketInfo, MarketStatus, PriceFeeder, }; -use primitives::{is_ctoken, Balance, CurrencyId, Liquidity, Price, Rate, Ratio, Shortfall, Timestamp}; +use primitives::{is_ptoken, Balance, CurrencyId, Liquidity, Price, Rate, Ratio, Shortfall, Timestamp}; use sp_runtime::{ traits::{ AccountIdConversion, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, One, SaturatedConversion, Saturating, @@ -88,7 +88,7 @@ type BalanceOf = <::Assets as Inspect<(marker::PhantomData); impl OnSlash, BalanceOf> for OnSlashHook { fn on_slash(currency_id: AssetIdOf, account_id: &T::AccountId, amount: BalanceOf) { - if is_ctoken(currency_id) { + if is_ptoken(currency_id) { let f = || -> DispatchResult { let underlying_id = Pallet::::underlying_id(currency_id)?; Pallet::::update_reward_supply_index(underlying_id)?; @@ -112,7 +112,7 @@ impl OnSlash, BalanceOf> for OnSlashHoo pub struct OnDepositHook(marker::PhantomData); impl OnDeposit, BalanceOf> for OnDepositHook { fn on_deposit(currency_id: AssetIdOf, account_id: &T::AccountId, _: BalanceOf) -> DispatchResult { - if is_ctoken(currency_id) { + if is_ptoken(currency_id) { let underlying_id = Pallet::::underlying_id(currency_id)?; Pallet::::update_reward_supply_index(underlying_id)?; Pallet::::distribute_supplier_reward(underlying_id, account_id)?; @@ -129,7 +129,7 @@ impl OnTransfer, BalanceOf> for OnTrans to: &T::AccountId, _: BalanceOf, ) -> DispatchResult { - if is_ctoken(currency_id) { + if is_ptoken(currency_id) { let underlying_id = Pallet::::underlying_id(currency_id)?; Pallet::::update_reward_supply_index(underlying_id)?; Pallet::::distribute_supplier_reward(underlying_id, from)?; diff --git a/crates/loans/src/mock.rs b/crates/loans/src/mock.rs index 06fd7412b0..6a25a5a633 100644 --- a/crates/loans/src/mock.rs +++ b/crates/loans/src/mock.rs @@ -29,8 +29,8 @@ use mocktopus::{macros::mockable, mocking::*}; use orml_traits::{parameter_type_with_key, DataFeeder, DataProvider, DataProviderExtended}; use pallet_traits::{VaultTokenCurrenciesFilter, VaultTokenExchangeRateProvider}; use primitives::{ - CurrencyId::{ForeignAsset, Token}, - Moment, PriceDetail, CDOT, CIBTC, CKBTC, CKINT, CKSM, DOT, IBTC, INTR, KBTC, KINT, KSM, + CurrencyId::{ForeignAsset, PToken, Token}, + Moment, PriceDetail, DOT, IBTC, INTR, KBTC, KINT, KSM, }; use sp_core::H256; use sp_runtime::{testing::Header, traits::IdentityLookup, AccountId32, FixedI128}; @@ -303,6 +303,12 @@ impl Config for Test { type RewardAssetId = RewardAssetId; } +pub const CDOT: CurrencyId = PToken(1); +pub const CKINT: CurrencyId = PToken(2); +pub const CKSM: CurrencyId = PToken(3); +pub const CKBTC: CurrencyId = PToken(4); +pub const CIBTC: CurrencyId = PToken(5); + pub(crate) fn new_test_ext() -> sp_io::TestExternalities { let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); @@ -324,17 +330,17 @@ pub(crate) fn new_test_ext() -> sp_io::TestExternalities { MockPriceFeeder::set_price(Token(KBTC), 1.into()); MockPriceFeeder::set_price(Token(DOT), 1.into()); MockPriceFeeder::set_price(Token(KSM), 1.into()); - MockPriceFeeder::set_price(Token(CDOT), 1.into()); + MockPriceFeeder::set_price(CDOT, 1.into()); // Init Markets - Loans::add_market(Origin::root(), Token(KINT), market_mock(Token(CKINT))).unwrap(); + Loans::add_market(Origin::root(), Token(DOT), market_mock(CDOT)).unwrap(); + Loans::activate_market(Origin::root(), Token(DOT)).unwrap(); + Loans::add_market(Origin::root(), Token(KINT), market_mock(CKINT)).unwrap(); Loans::activate_market(Origin::root(), Token(KINT)).unwrap(); - Loans::add_market(Origin::root(), Token(KSM), market_mock(Token(CKSM))).unwrap(); + Loans::add_market(Origin::root(), Token(KSM), market_mock(CKSM)).unwrap(); Loans::activate_market(Origin::root(), Token(KSM)).unwrap(); - Loans::add_market(Origin::root(), Token(DOT), market_mock(Token(CDOT))).unwrap(); - Loans::activate_market(Origin::root(), Token(DOT)).unwrap(); - Loans::add_market(Origin::root(), Token(KBTC), market_mock(Token(CKBTC))).unwrap(); + Loans::add_market(Origin::root(), Token(KBTC), market_mock(CKBTC)).unwrap(); Loans::activate_market(Origin::root(), Token(KBTC)).unwrap(); - Loans::add_market(Origin::root(), Token(IBTC), market_mock(Token(CIBTC))).unwrap(); + Loans::add_market(Origin::root(), Token(IBTC), market_mock(CIBTC)).unwrap(); Loans::activate_market(Origin::root(), Token(IBTC)).unwrap(); System::set_block_number(0); diff --git a/crates/loans/src/tests/market.rs b/crates/loans/src/tests/market.rs index df6f68ac1c..63d9feb288 100644 --- a/crates/loans/src/tests/market.rs +++ b/crates/loans/src/tests/market.rs @@ -1,17 +1,17 @@ use crate::{ - mock::{market_mock, new_test_ext, Loans, Origin, Test, ACTIVE_MARKET_MOCK, ALICE, MARKET_MOCK}, + mock::{market_mock, new_test_ext, Loans, Origin, Test, ACTIVE_MARKET_MOCK, ALICE, CDOT, MARKET_MOCK}, Error, InterestRateModel, MarketState, }; use frame_support::{assert_noop, assert_ok, error::BadOrigin}; use primitives::{ - CurrencyId::{self, ForeignAsset, Token}, - Rate, Ratio, CDOT, CKBTC, DOT as DOT_CURRENCY, + CurrencyId::{self, ForeignAsset, PToken, Token}, + Rate, Ratio, DOT as DOT_CURRENCY, }; use sp_runtime::{traits::Zero, FixedPointNumber}; const DOT: CurrencyId = Token(DOT_CURRENCY); -const PDOT: CurrencyId = Token(CDOT); -const PUSDT: CurrencyId = Token(CKBTC); +const PDOT: CurrencyId = CDOT; +const PUSDT: CurrencyId = PToken(4); const SDOT: CurrencyId = ForeignAsset(987997280); macro_rules! rate_model_sanity_check { diff --git a/crates/loans/src/tests/ptokens.rs b/crates/loans/src/tests/ptokens.rs index ac0fb21dad..907bc64eac 100644 --- a/crates/loans/src/tests/ptokens.rs +++ b/crates/loans/src/tests/ptokens.rs @@ -1,5 +1,5 @@ use crate::{ - mock::{market_mock, new_test_ext, Loans, Origin, Test, Tokens, ALICE, DAVE}, + mock::{market_mock, new_test_ext, Loans, Origin, Test, Tokens, ALICE, CKBTC, CKINT, CKSM, DAVE}, tests::unit, Error, }; @@ -8,16 +8,16 @@ use frame_support::{ traits::tokens::fungibles::{Inspect, Transfer}, }; use primitives::{ - CurrencyId::{self, ForeignAsset, Token}, - CKBTC, CKINT, CKSM, KBTC, KINT, KSM as KSM_CURRENCY, + CurrencyId::{self, ForeignAsset, PToken, Token}, + KBTC, KINT, KSM as KSM_CURRENCY, }; use sp_runtime::{FixedPointNumber, TokenError}; const HKO: CurrencyId = Token(KINT); const KSM: CurrencyId = Token(KSM_CURRENCY); -const PHKO: CurrencyId = Token(CKINT); -const PKSM: CurrencyId = Token(CKSM); -const PUSDT: CurrencyId = Token(CKBTC); +const PHKO: CurrencyId = CKINT; +const PKSM: CurrencyId = CKSM; +const PUSDT: CurrencyId = CKBTC; const USDT: CurrencyId = Token(KBTC); #[test] diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 63b3b39854..0837e63961 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -464,15 +464,6 @@ create_currency_id! { KSM("Kusama", 12) = 10, KBTC("kBTC", 8) = 11, KINT("Kintsugi", 12) = 12, - - // cTokens - CDOT("cPolkadot", 10) = 20, - CIBTC("cinterBTC", 8) = 21, - CINTR("cInterlay", 10) = 22, - - CKSM("cKusama", 12) = 30, - CKBTC("ckBTC", 8) = 31, - CKINT("cKintsugi", 12) = 32, } } @@ -482,9 +473,11 @@ create_currency_id! { pub enum CurrencyId { Token(TokenSymbol), ForeignAsset(ForeignAssetId), + PToken(PTokenId), } pub type ForeignAssetId = u32; +pub type PTokenId = u32; #[derive(scale_info::TypeInfo, Encode, Decode, Clone, Eq, PartialEq, Debug)] pub struct CustomMetadata { @@ -492,14 +485,9 @@ pub struct CustomMetadata { pub coingecko_id: Vec, } -pub fn is_ctoken(currency_id: CurrencyId) -> bool { +pub fn is_ptoken(currency_id: CurrencyId) -> bool { match currency_id { - CurrencyId::Token(CDOT) - | CurrencyId::Token(CIBTC) - | CurrencyId::Token(CINTR) - | CurrencyId::Token(CKSM) - | CurrencyId::Token(CKBTC) - | CurrencyId::Token(CKINT) => true, + CurrencyId::PToken(_) => true, _ => false, } } diff --git a/standalone/runtime/src/lib.rs b/standalone/runtime/src/lib.rs index cfa9a14f9a..fa89f3c33f 100644 --- a/standalone/runtime/src/lib.rs +++ b/standalone/runtime/src/lib.rs @@ -65,7 +65,7 @@ pub use security::StatusCode; pub use primitives::{ self, AccountId, Balance, BlockNumber, CurrencyId, - CurrencyId::{ForeignAsset, Token}, + CurrencyId::{ForeignAsset, PToken, Token}, CurrencyInfo, Hash, Moment, Nonce, PriceDetail, Signature, SignedFixedPoint, SignedInner, TokenSymbol, UnsignedFixedPoint, UnsignedInner, DOT, IBTC, INTR, KBTC, KINT, KSM, }; @@ -826,6 +826,7 @@ impl pallet_traits::PriceFeeder for PriceFeed { return None; } } + PToken(_) => return None, }; let amount = Amount::::new(one, asset_id.clone()); Oracle::convert(&amount, WRAPPED_CURRENCY_ID) diff --git a/standalone/runtime/tests/mock/mod.rs b/standalone/runtime/tests/mock/mod.rs index 87da39375c..64c0247d5e 100644 --- a/standalone/runtime/tests/mock/mod.rs +++ b/standalone/runtime/tests/mock/mod.rs @@ -28,6 +28,7 @@ pub use primitives::{ use redeem::RedeemRequestStatus; use staking::DefaultVaultCurrencyPair; use vault_registry::types::UpdatableVault; +use CurrencyId::PToken; pub use issue::{types::IssueRequestExt, IssueRequest, IssueRequestStatus}; pub use oracle::OracleKey; @@ -187,6 +188,12 @@ pub const DEFAULT_WRAPPED_CURRENCY: ::CurrencyId pub const DEFAULT_NATIVE_CURRENCY: ::CurrencyId = Token(INTR); pub const DEFAULT_GRIEFING_CURRENCY: ::CurrencyId = DEFAULT_NATIVE_CURRENCY; +pub const CDOT: CurrencyId = PToken(1); +pub const CKINT: CurrencyId = PToken(2); +pub const CKSM: CurrencyId = PToken(3); +pub const CKBTC: CurrencyId = PToken(4); +pub const CIBTC: CurrencyId = PToken(5); + pub fn default_vault_id_of(hash: [u8; 32]) -> VaultId { VaultId { account_id: account_of(hash), diff --git a/standalone/runtime/tests/test_loans.rs b/standalone/runtime/tests/test_loans.rs index bbc737cc21..97f8f19631 100644 --- a/standalone/runtime/tests/test_loans.rs +++ b/standalone/runtime/tests/test_loans.rs @@ -2,7 +2,7 @@ use interbtc_runtime_standalone::{CurrencyId::Token, KINT}; mod mock; use mock::{assert_eq, *}; use pallet_loans::{InterestRateModel, JumpModel, Market, MarketState}; -use primitives::{Rate, Ratio, CKINT, CKSM}; +use primitives::{Rate, Ratio}; use sp_runtime::traits::CheckedMul; pub const USER: [u8; 32] = ALICE; @@ -29,12 +29,12 @@ pub const fn market_mock(ptoken_id: CurrencyId) -> Market { } } -fn set_up_market(currency_id: CurrencyId, exchange_rate: FixedU128, ctoken_id: CurrencyId) { +fn set_up_market(currency_id: CurrencyId, exchange_rate: FixedU128, ptoken_id: CurrencyId) { assert_ok!(OraclePallet::_set_exchange_rate(currency_id, exchange_rate)); assert_ok!(Call::Sudo(SudoCall::sudo { call: Box::new(Call::Loans(LoansCall::add_market { asset_id: currency_id, - market: market_mock(ctoken_id), + market: market_mock(ptoken_id), })), }) .dispatch(origin_of(account_of(ALICE)))); @@ -51,12 +51,12 @@ fn test_real_market(execute: impl Fn() -> R) { set_up_market( Token(KINT), FixedU128::from_inner(115_942_028_985_507_246_376_810_000), - Token(CKINT), + CKINT, ); set_up_market( Token(KSM), FixedU128::from_inner(4_573_498_406_135_805_461_670_000), - Token(CKSM), + CKSM, ); execute() }); From a7028c24dca726e3b71b416a04ef05ffce6f2cbe Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Tue, 18 Oct 2022 19:04:39 +0200 Subject: [PATCH 29/58] feat(loans): ptoken oracle integration --- crates/loans/src/lib.rs | 26 ++++++++-- primitives/src/lib.rs | 2 +- standalone/runtime/src/lib.rs | 13 ++++- .../runtime/tests/mock/loans_testing_utils.rs | 48 +++++++++++++++++++ standalone/runtime/tests/mock/mod.rs | 43 +++++++++++++---- standalone/runtime/tests/test_issue.rs | 23 +++++++-- 6 files changed, 134 insertions(+), 21 deletions(-) create mode 100644 standalone/runtime/tests/mock/loans_testing_utils.rs diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 3f4d1db95c..9694ed1baa 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -78,8 +78,10 @@ pub mod weights; pub const MAX_INTEREST_CALCULATING_INTERVAL: u64 = 5 * 24 * 3600; // 5 days pub const MIN_INTEREST_CALCULATING_INTERVAL: u64 = 100; // 100 seconds -pub const MAX_EXCHANGE_RATE: u128 = 1_000_000_000_000_000_000; // 1 -pub const MIN_EXCHANGE_RATE: u128 = 20_000_000_000_000_000; // 0.02 +// TODO: If the exchange rate ever exceeds this, the corresponding market will become unusable. +// Refactor these constant to storage items. +pub const MAX_EXCHANGE_RATE: u128 = 1_000_000_000_000_000_000_00; // 1 +pub const MIN_EXCHANGE_RATE: u128 = 1_000_000_000_000_000_000; // 0.02 type AccountIdOf = ::AccountId; type AssetIdOf = <::Assets as Inspect<::AccountId>>::AssetId; @@ -88,7 +90,7 @@ type BalanceOf = <::Assets as Inspect<(marker::PhantomData); impl OnSlash, BalanceOf> for OnSlashHook { fn on_slash(currency_id: AssetIdOf, account_id: &T::AccountId, amount: BalanceOf) { - if is_ptoken(currency_id) { + if is_ptoken(¤cy_id) { let f = || -> DispatchResult { let underlying_id = Pallet::::underlying_id(currency_id)?; Pallet::::update_reward_supply_index(underlying_id)?; @@ -112,7 +114,7 @@ impl OnSlash, BalanceOf> for OnSlashHoo pub struct OnDepositHook(marker::PhantomData); impl OnDeposit, BalanceOf> for OnDepositHook { fn on_deposit(currency_id: AssetIdOf, account_id: &T::AccountId, _: BalanceOf) -> DispatchResult { - if is_ptoken(currency_id) { + if is_ptoken(¤cy_id) { let underlying_id = Pallet::::underlying_id(currency_id)?; Pallet::::update_reward_supply_index(underlying_id)?; Pallet::::distribute_supplier_reward(underlying_id, account_id)?; @@ -129,7 +131,7 @@ impl OnTransfer, BalanceOf> for OnTrans to: &T::AccountId, _: BalanceOf, ) -> DispatchResult { - if is_ptoken(currency_id) { + if is_ptoken(¤cy_id) { let underlying_id = Pallet::::underlying_id(currency_id)?; Pallet::::update_reward_supply_index(underlying_id)?; Pallet::::distribute_supplier_reward(underlying_id, from)?; @@ -1702,6 +1704,13 @@ impl Pallet { Err(Error::::InsufficientLiquidity.into()) } + pub fn get_underlying_amount(ptokens: &Amount) -> Result, DispatchError> { + let underlying_id = Self::underlying_id(ptokens.currency())?; + let exchange_rate = Self::exchange_rate_stored(underlying_id)?; + let underlying_amount = Self::calc_underlying_amount(ptokens.amount(), exchange_rate)?; + Ok(Amount::new(underlying_amount, underlying_id)) + } + pub fn calc_underlying_amount( voucher_amount: BalanceOf, exchange_rate: Rate, @@ -1711,6 +1720,13 @@ impl Pallet { .ok_or(ArithmeticError::Overflow)?) } + pub fn get_collateral_amount(underlying: &Amount) -> Result, DispatchError> { + let exchange_rate = Self::exchange_rate_stored(underlying.currency())?; + let underlying_amount = Self::calc_collateral_amount(underlying.amount(), exchange_rate)?; + let ptoken_id = Self::ptoken_id(underlying.currency())?; + Ok(Amount::new(underlying_amount, ptoken_id)) + } + pub fn calc_collateral_amount( underlying_amount: BalanceOf, exchange_rate: Rate, diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 0837e63961..5727cd8a80 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -485,7 +485,7 @@ pub struct CustomMetadata { pub coingecko_id: Vec, } -pub fn is_ptoken(currency_id: CurrencyId) -> bool { +pub fn is_ptoken(currency_id: &CurrencyId) -> bool { match currency_id { CurrencyId::PToken(_) => true, _ => false, diff --git a/standalone/runtime/src/lib.rs b/standalone/runtime/src/lib.rs index fa89f3c33f..e2d47cd6ab 100644 --- a/standalone/runtime/src/lib.rs +++ b/standalone/runtime/src/lib.rs @@ -26,6 +26,7 @@ use frame_system::{ use orml_asset_registry::SequentialId; use orml_traits::parameter_type_with_key; use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment}; +use primitives::is_ptoken; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H256}; use sp_runtime::{ @@ -809,7 +810,17 @@ impl security::Config for Runtime { pub struct CurrencyConvert; impl currency::CurrencyConversion, CurrencyId> for CurrencyConvert { fn convert(amount: ¤cy::Amount, to: CurrencyId) -> Result, DispatchError> { - Oracle::convert(amount, to) + if is_ptoken(&amount.currency()) { + Oracle::convert(&Loans::get_underlying_amount(amount)?, to) + } else if is_ptoken(&to) { + let underlying_id = Loans::underlying_id(to)?; + // get the converted value expressed in the underlying asset + let underlying_amount = Oracle::convert(amount, underlying_id)?; + // get the equivalent ptoken amount using the internal exchange rate + Loans::get_collateral_amount(&underlying_amount) + } else { + Oracle::convert(amount, to) + } } } diff --git a/standalone/runtime/tests/mock/loans_testing_utils.rs b/standalone/runtime/tests/mock/loans_testing_utils.rs new file mode 100644 index 0000000000..36f6e52f80 --- /dev/null +++ b/standalone/runtime/tests/mock/loans_testing_utils.rs @@ -0,0 +1,48 @@ +use pallet_loans::JumpModel; + +use crate::{assert_eq, *}; + +pub const fn market_mock(ptoken_id: CurrencyId) -> Market { + Market { + close_factor: Ratio::from_percent(50), + collateral_factor: Ratio::from_percent(50), + liquidation_threshold: Ratio::from_percent(55), + liquidate_incentive: Rate::from_inner(Rate::DIV / 100 * 110), + liquidate_incentive_reserved_factor: Ratio::from_percent(3), + state: MarketState::Pending, + rate_model: InterestRateModel::Jump(JumpModel { + base_rate: Rate::from_inner(Rate::DIV / 100 * 2), + jump_rate: Rate::from_inner(Rate::DIV / 100 * 10), + full_rate: Rate::from_inner(Rate::DIV / 100 * 32), + jump_utilization: Ratio::from_percent(80), + }), + reserve_factor: Ratio::from_percent(15), + supply_cap: 1_000_000_000_000_000_000_000u128, // set to 1B + borrow_cap: 1_000_000_000_000_000_000_000u128, // set to 1B + ptoken_id, + } +} + +pub fn activate_market(underlying_id: CurrencyId, ptoken_id: CurrencyId) { + assert_ok!(Call::Loans(LoansCall::add_market { + asset_id: underlying_id, + market: market_mock(ptoken_id) + }) + .dispatch(root())); + assert_ok!(Call::Loans(LoansCall::activate_market { + asset_id: underlying_id + }) + .dispatch(root())); +} + +pub fn mint_ptokens(account_id: AccountId, underlying_id: CurrencyId) { + let balance_to_mint = FUND_LIMIT_CEILING; + let amount: Amount = Amount::new(balance_to_mint, underlying_id); + assert_ok!(amount.mint_to(&account_id)); + + assert_ok!(Call::Loans(LoansCall::mint { + asset_id: Token(DOT), + mint_amount: balance_to_mint + }) + .dispatch(origin_of(account_id))); +} diff --git a/standalone/runtime/tests/mock/mod.rs b/standalone/runtime/tests/mock/mod.rs index 64c0247d5e..ab0d27ecb5 100644 --- a/standalone/runtime/tests/mock/mod.rs +++ b/standalone/runtime/tests/mock/mod.rs @@ -21,17 +21,18 @@ pub use interbtc_runtime_standalone::{ }; pub use mocktopus::mocking::*; pub use orml_tokens::CurrencyAdapter; +use primitives::is_ptoken; pub use primitives::{ - CurrencyId::{ForeignAsset, Token}, - VaultCurrencyPair, VaultId as PrimitiveVaultId, DOT, IBTC, INTR, KBTC, KINT, KSM, + CurrencyId::{ForeignAsset, PToken, Token}, + Rate, Ratio, VaultCurrencyPair, VaultId as PrimitiveVaultId, DOT, IBTC, INTR, KBTC, KINT, KSM, }; use redeem::RedeemRequestStatus; use staking::DefaultVaultCurrencyPair; use vault_registry::types::UpdatableVault; -use CurrencyId::PToken; pub use issue::{types::IssueRequestExt, IssueRequest, IssueRequestStatus}; pub use oracle::OracleKey; +pub use pallet_loans::{InterestRateModel, Market, MarketState}; pub use redeem::{types::RedeemRequestExt, RedeemRequest}; pub use replace::{types::ReplaceRequestExt, ReplaceRequest}; pub use reward::Rewards; @@ -50,6 +51,7 @@ pub use vault_registry::{CurrencySource, DefaultVaultId, Vault, VaultStatus}; use self::redeem_testing_utils::USER_BTC_ADDRESS; pub mod issue_testing_utils; +pub mod loans_testing_utils; pub mod nomination_testing_utils; pub mod redeem_testing_utils; pub mod replace_testing_utils; @@ -360,10 +362,25 @@ pub fn iter_currency_pairs() -> impl Iterator impl Iterator> { + iter_collateral_currencies_and_ptokens().flat_map(|collateral_id| { + iter_wrapped_currencies().map(move |wrapped_id| VaultCurrencyPair { + collateral: collateral_id, + wrapped: wrapped_id, + }) + }) +} + pub fn iter_collateral_currencies() -> impl Iterator { vec![Token(DOT), Token(KSM), Token(INTR), ForeignAsset(1)].into_iter() } +// ptokens should not be minted to the endowed accounts. Use this function +// to include them in the iterators for configuring the bridge. +pub fn iter_collateral_currencies_and_ptokens() -> impl Iterator { + iter_collateral_currencies().chain(vec![PToken(1)].into_iter()) +} + pub fn iter_native_currencies() -> impl Iterator { vec![Token(INTR), Token(KINT)].into_iter() } @@ -977,7 +994,7 @@ pub fn set_default_thresholds() { let premium = FixedU128::checked_from_rational(135, 100).unwrap(); let liquidation = FixedU128::checked_from_rational(110, 100).unwrap(); - for collateral_id in iter_collateral_currencies() { + for collateral_id in iter_collateral_currencies_and_ptokens() { for wrapped_id in iter_wrapped_currencies() { let currency_pair = VaultCurrencyPair { collateral: collateral_id, @@ -1388,16 +1405,24 @@ impl ExtBuilder { .unwrap(); vault_registry::GenesisConfig:: { - minimum_collateral_vault: vec![(Token(DOT), 0), (Token(KSM), 0), (ForeignAsset(1), 0), (Token(INTR), 0)], + minimum_collateral_vault: vec![ + (Token(DOT), 0), + (Token(KSM), 0), + (ForeignAsset(1), 0), + (Token(INTR), 0), + (PToken(1), 0), + ], punishment_delay: 8, - system_collateral_ceiling: iter_currency_pairs().map(|pair| (pair, FUND_LIMIT_CEILING)).collect(), - secure_collateral_threshold: iter_currency_pairs() + system_collateral_ceiling: iter_currency_pairs_with_ptokens() + .map(|pair| (pair, FUND_LIMIT_CEILING)) + .collect(), + secure_collateral_threshold: iter_currency_pairs_with_ptokens() .map(|pair| (pair, FixedU128::checked_from_rational(150, 100).unwrap())) .collect(), - premium_redeem_threshold: iter_currency_pairs() + premium_redeem_threshold: iter_currency_pairs_with_ptokens() .map(|pair| (pair, FixedU128::checked_from_rational(150, 100).unwrap())) .collect(), - liquidation_collateral_threshold: iter_currency_pairs() + liquidation_collateral_threshold: iter_currency_pairs_with_ptokens() .map(|pair| (pair, FixedU128::checked_from_rational(110, 100).unwrap())) .collect(), } diff --git a/standalone/runtime/tests/test_issue.rs b/standalone/runtime/tests/test_issue.rs index 1de6eb3d5d..bd915e5233 100644 --- a/standalone/runtime/tests/test_issue.rs +++ b/standalone/runtime/tests/test_issue.rs @@ -1,7 +1,13 @@ mod mock; use currency::Amount; -use mock::{assert_eq, issue_testing_utils::*, *}; +use mock::{ + assert_eq, + issue_testing_utils::*, + loans_testing_utils::{activate_market, market_mock, mint_ptokens}, + *, +}; +use CurrencyId::PToken; fn test_with(execute: impl Fn(VaultId) -> R) { let test_with = |currency_id, wrapped_id| { @@ -17,13 +23,20 @@ fn test_with(execute: impl Fn(VaultId) -> R) { let vault_id = PrimitiveVaultId::new(account_of(VAULT), currency_id, wrapped_id); LiquidationVaultData::force_to(default_liquidation_vault_state(&vault_id.currencies)); + activate_market(Token(DOT), PToken(1)); + mint_ptokens(account_of(VAULT), Token(DOT)); + mint_ptokens(account_of(BOB), Token(DOT)); + mint_ptokens(account_of(CAROL), Token(DOT)); + mint_ptokens(account_of(FAUCET), Token(DOT)); + execute(vault_id) }); }; - test_with(Token(DOT), Token(KBTC)); - test_with(Token(KSM), Token(IBTC)); - test_with(Token(DOT), Token(IBTC)); - test_with(ForeignAsset(1), Token(IBTC)); + // test_with(Token(DOT), Token(KBTC)); + // test_with(Token(KSM), Token(IBTC)); + // test_with(Token(DOT), Token(IBTC)); + // test_with(ForeignAsset(1), Token(IBTC)); + test_with(PToken(1), Token(IBTC)); } fn test_with_initialized_vault(execute: impl Fn(VaultId) -> R) { From 156a472eb4194a42e962e4477897f30d6e61b6c2 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Wed, 19 Oct 2022 16:18:42 +0200 Subject: [PATCH 30/58] feat(primitives): is_ctoken associated method --- crates/loans/src/lib.rs | 8 ++++---- primitives/src/lib.rs | 20 +++++++++++--------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 10390026bf..5e1c385d82 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -45,7 +45,7 @@ pub use pallet::*; use pallet_traits::{ ConvertToBigUint, Loans as LoansTrait, LoansMarketDataProvider, MarketInfo, MarketStatus, PriceFeeder, }; -use primitives::{is_ctoken, Balance, CurrencyId, Liquidity, Price, Rate, Ratio, Shortfall, Timestamp}; +use primitives::{Balance, CurrencyId, Liquidity, Price, Rate, Ratio, Shortfall, Timestamp}; use sp_runtime::{ traits::{ AccountIdConversion, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, One, SaturatedConversion, Saturating, @@ -88,7 +88,7 @@ type BalanceOf = <::Assets as Inspect<(marker::PhantomData); impl OnSlash, BalanceOf> for OnSlashHook { fn on_slash(currency_id: AssetIdOf, account_id: &T::AccountId, amount: BalanceOf) { - if is_ctoken(currency_id) { + if currency_id.is_ctoken() { let f = || -> DispatchResult { let underlying_id = Pallet::::underlying_id(currency_id)?; Pallet::::update_reward_supply_index(underlying_id)?; @@ -112,7 +112,7 @@ impl OnSlash, BalanceOf> for OnSlashHoo pub struct OnDepositHook(marker::PhantomData); impl OnDeposit, BalanceOf> for OnDepositHook { fn on_deposit(currency_id: AssetIdOf, account_id: &T::AccountId, _: BalanceOf) -> DispatchResult { - if is_ctoken(currency_id) { + if currency_id.is_ctoken() { let underlying_id = Pallet::::underlying_id(currency_id)?; Pallet::::update_reward_supply_index(underlying_id)?; Pallet::::distribute_supplier_reward(underlying_id, account_id)?; @@ -129,7 +129,7 @@ impl OnTransfer, BalanceOf> for OnTrans to: &T::AccountId, _: BalanceOf, ) -> DispatchResult { - if is_ctoken(currency_id) { + if currency_id.is_ctoken() { let underlying_id = Pallet::::underlying_id(currency_id)?; Pallet::::update_reward_supply_index(underlying_id)?; Pallet::::distribute_supplier_reward(underlying_id, from)?; diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 63b3b39854..7940df8673 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -492,14 +492,16 @@ pub struct CustomMetadata { pub coingecko_id: Vec, } -pub fn is_ctoken(currency_id: CurrencyId) -> bool { - match currency_id { - CurrencyId::Token(CDOT) - | CurrencyId::Token(CIBTC) - | CurrencyId::Token(CINTR) - | CurrencyId::Token(CKSM) - | CurrencyId::Token(CKBTC) - | CurrencyId::Token(CKINT) => true, - _ => false, +impl CurrencyId { + pub fn is_ctoken(&self) -> bool { + match self { + CurrencyId::Token(CDOT) + | CurrencyId::Token(CIBTC) + | CurrencyId::Token(CINTR) + | CurrencyId::Token(CKSM) + | CurrencyId::Token(CKBTC) + | CurrencyId::Token(CKINT) => true, + _ => false, + } } } From 6283dabc095b12942446898157402b295d81fec8 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Wed, 19 Oct 2022 20:05:27 +0200 Subject: [PATCH 31/58] feat(loans): min and max exchange rates as storage items --- crates/loans/src/interest.rs | 4 +-- crates/loans/src/lib.rs | 46 ++++++++++++++++++++++------ crates/loans/src/mock.rs | 18 +++++++++-- standalone/runtime/src/lib.rs | 2 +- standalone/runtime/tests/mock/mod.rs | 12 ++++++++ standalone/src/chain_spec.rs | 10 ++++-- 6 files changed, 75 insertions(+), 17 deletions(-) diff --git a/crates/loans/src/interest.rs b/crates/loans/src/interest.rs index 37b38c57a6..6ceb64b593 100644 --- a/crates/loans/src/interest.rs +++ b/crates/loans/src/interest.rs @@ -136,7 +136,7 @@ impl Pallet { /// The exchange rate should be greater than 0.02 and less than 1 pub(crate) fn ensure_valid_exchange_rate(exchange_rate: Rate) -> DispatchResult { ensure!( - exchange_rate >= Rate::from_inner(MIN_EXCHANGE_RATE) && exchange_rate < Rate::from_inner(MAX_EXCHANGE_RATE), + exchange_rate >= Self::min_exchange_rate() && exchange_rate < Self::max_exchange_rate(), Error::::InvalidExchangeRate ); @@ -171,7 +171,7 @@ impl Pallet { total_reserves: BalanceOf, ) -> Result { if total_supply.is_zero() { - return Ok(Rate::from_inner(MIN_EXCHANGE_RATE)); + return Ok(Self::min_exchange_rate()); } let cash_plus_borrows_minus_reserves = total_cash diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index f2016c408f..629eed127c 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -75,14 +75,6 @@ mod types; pub mod weights; -pub const MAX_INTEREST_CALCULATING_INTERVAL: u64 = 5 * 24 * 3600; // 5 days -pub const MIN_INTEREST_CALCULATING_INTERVAL: u64 = 100; // 100 seconds - -// TODO: If the exchange rate ever exceeds this, the corresponding market will become unusable. -// Refactor these constants to storage items. -pub const MAX_EXCHANGE_RATE: u128 = 1_000_000_000_000_000_000_00; // 1 -pub const MIN_EXCHANGE_RATE: u128 = 1_000_000_000_000_000_000; // 0.02 - type AccountIdOf = ::AccountId; type AssetIdOf = <::Assets as Inspect<::AccountId>>::AssetId; type BalanceOf = <::Assets as Inspect<::AccountId>>::Balance; @@ -446,6 +438,18 @@ pub mod pallet { #[pallet::getter(fn reward_accrued)] pub type RewardAccrued = StorageMap<_, Blake2_128Concat, T::AccountId, BalanceOf, ValueQuery>; + /// The maximum allowed exchange rate for a market. + #[pallet::storage] + #[pallet::storage_prefix = "MaxExchangeRate"] + #[pallet::getter(fn max_exchange_rate)] + pub type MaxExchangeRate = StorageValue<_, Rate, ValueQuery>; + + /// The minimum allowed exchange rate for a market. + #[pallet::storage] + #[pallet::storage_prefix = "MinExchangeRate"] + #[pallet::getter(fn min_exchange_rate)] + pub type MinExchangeRate = StorageValue<_, Rate, ValueQuery>; + /// DefaultVersion is using for initialize the StorageVersion #[pallet::type_value] pub(super) fn DefaultVersion() -> Versions { @@ -456,6 +460,30 @@ pub mod pallet { #[pallet::storage] pub(crate) type StorageVersion = StorageValue<_, Versions, ValueQuery, DefaultVersion>; + #[pallet::genesis_config] + pub struct GenesisConfig { + pub max_exchange_rate: Rate, + pub min_exchange_rate: Rate, + } + + #[cfg(feature = "std")] + impl Default for GenesisConfig { + fn default() -> Self { + Self { + max_exchange_rate: Default::default(), + min_exchange_rate: Default::default(), + } + } + } + + #[pallet::genesis_build] + impl GenesisBuild for GenesisConfig { + fn build(&self) { + MaxExchangeRate::::put(&self.max_exchange_rate); + MinExchangeRate::::put(&self.min_exchange_rate); + } + } + #[pallet::pallet] #[pallet::without_storage_info] pub struct Pallet(PhantomData); @@ -515,7 +543,7 @@ pub mod pallet { UnderlyingAssetId::::insert(market.ptoken_id, asset_id); // Init the ExchangeRate and BorrowIndex for asset - ExchangeRate::::insert(asset_id, Rate::from_inner(MIN_EXCHANGE_RATE)); + ExchangeRate::::insert(asset_id, Self::min_exchange_rate()); BorrowIndex::::insert(asset_id, Rate::one()); Self::deposit_event(Event::::NewMarket(asset_id, market)); diff --git a/crates/loans/src/mock.rs b/crates/loans/src/mock.rs index 6a25a5a633..1ba83006b3 100644 --- a/crates/loans/src/mock.rs +++ b/crates/loans/src/mock.rs @@ -17,6 +17,8 @@ pub use super::*; +use crate as pallet_loans; + use currency::Amount; use frame_benchmarking::whitelisted_caller; use frame_support::{ @@ -47,7 +49,7 @@ construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system::{Pallet, Call, Storage, Config, Event}, - Loans: crate::{Pallet, Storage, Call, Event}, + Loans: pallet_loans::{Pallet, Storage, Call, Event, Config}, TimestampPallet: pallet_timestamp::{Pallet, Call, Storage, Inherent}, Tokens: orml_tokens::{Pallet, Call, Storage, Config, Event}, Currency: currency::{Pallet}, @@ -309,8 +311,20 @@ pub const CKSM: CurrencyId = PToken(3); pub const CKBTC: CurrencyId = PToken(4); pub const CIBTC: CurrencyId = PToken(5); +pub const DEFAULT_MAX_EXCHANGE_RATE: u128 = 1_000_000_000_000_000_000; // 1 +pub const DEFAULT_MIN_EXCHANGE_RATE: u128 = 20_000_000_000_000_000; // 0.02 + pub(crate) fn new_test_ext() -> sp_io::TestExternalities { - let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + + GenesisBuild::::assimilate_storage( + &pallet_loans::GenesisConfig { + max_exchange_rate: Rate::from_inner(DEFAULT_MAX_EXCHANGE_RATE), + min_exchange_rate: Rate::from_inner(DEFAULT_MIN_EXCHANGE_RATE), + }, + &mut t, + ) + .unwrap(); let mut ext = sp_io::TestExternalities::new(t); ext.execute_with(|| { diff --git a/standalone/runtime/src/lib.rs b/standalone/runtime/src/lib.rs index 4fb66e3292..260dac3948 100644 --- a/standalone/runtime/src/lib.rs +++ b/standalone/runtime/src/lib.rs @@ -1065,7 +1065,7 @@ construct_runtime! { // Refund: 27 Nomination: nomination::{Pallet, Call, Config, Storage, Event} = 28, - Loans: pallet_loans::{Pallet, Call, Storage, Event} = 39, + Loans: pallet_loans::{Pallet, Call, Storage, Event, Config} = 39, Identity: pallet_identity::{Pallet, Call, Storage, Event} = 36, ClientsInfo: clients_info::{Pallet, Call, Storage, Event} = 38, diff --git a/standalone/runtime/tests/mock/mod.rs b/standalone/runtime/tests/mock/mod.rs index 10011b963a..08bb2af0ff 100644 --- a/standalone/runtime/tests/mock/mod.rs +++ b/standalone/runtime/tests/mock/mod.rs @@ -90,6 +90,9 @@ pub const DEFAULT_VAULT_REPLACE_COLLATERAL: Amount = griefing(20_000); pub const DEFAULT_GRIEFING_COLLATERAL: Amount = griefing(5_000); +pub const DEFAULT_MAX_EXCHANGE_RATE: u128 = 100_000_000_000_000_000_000; // 100, normally 1 +pub const DEFAULT_MIN_EXCHANGE_RATE: u128 = 1_000_000_000_000_000_000; // 1, normally 0.02 + pub fn default_user_free_balance(currency_id: CurrencyId) -> Amount { Amount::new(1_000_000, currency_id) } @@ -1476,6 +1479,15 @@ impl ExtBuilder { .assimilate_storage(&mut storage) .unwrap(); + GenesisBuild::::assimilate_storage( + &pallet_loans::GenesisConfig { + max_exchange_rate: Rate::from_inner(DEFAULT_MAX_EXCHANGE_RATE), + min_exchange_rate: Rate::from_inner(DEFAULT_MIN_EXCHANGE_RATE), + }, + &mut storage, + ) + .unwrap(); + Self { test_externalities: sp_io::TestExternalities::from(storage), } diff --git a/standalone/src/chain_spec.rs b/standalone/src/chain_spec.rs index e70d96f936..f8bf473fc2 100644 --- a/standalone/src/chain_spec.rs +++ b/standalone/src/chain_spec.rs @@ -2,12 +2,12 @@ use bitcoin::utils::{virtual_transaction_size, InputType, TransactionInputMetada use hex_literal::hex; use interbtc_runtime::{ token_distribution, AccountId, AuraConfig, BTCRelayConfig, CurrencyId, CurrencyId::Token, CurrencyInfo, FeeConfig, - GenesisConfig, GetWrappedCurrencyId, GrandpaConfig, IssueConfig, NominationConfig, OracleConfig, RedeemConfig, - ReplaceConfig, SecurityConfig, Signature, StatusCode, SudoConfig, SupplyConfig, SystemConfig, + GenesisConfig, GetWrappedCurrencyId, GrandpaConfig, IssueConfig, LoansConfig, NominationConfig, OracleConfig, + RedeemConfig, ReplaceConfig, SecurityConfig, Signature, StatusCode, SudoConfig, SupplyConfig, SystemConfig, TechnicalCommitteeConfig, TokensConfig, VaultRegistryConfig, BITCOIN_BLOCK_SPACING, DAYS, DOT, IBTC, INTR, KBTC, KINT, KSM, WASM_BINARY, YEARS, }; -use primitives::{VaultCurrencyPair, BITCOIN_REGTEST}; +use primitives::{Rate, VaultCurrencyPair, BITCOIN_REGTEST}; use sc_service::ChainType; use serde_json::{map::Map, Value}; use sp_arithmetic::{FixedPointNumber, FixedU128}; @@ -365,5 +365,9 @@ fn testnet_genesis( inflation: FixedU128::checked_from_rational(2, 100).unwrap(), // 2% }, asset_registry: Default::default(), + loans: LoansConfig { + max_exchange_rate: Rate::from_inner(100_000_000_000_000_000_000), // 100, normally 1 + min_exchange_rate: Rate::from_inner(1_000_000_000_000_000_000), // 1, normally 0.02 + }, } } From 85c1bf5de452ffd330a3890a388c63bab34c27e7 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Wed, 19 Oct 2022 23:08:05 +0200 Subject: [PATCH 32/58] feat(loans): pToken integration tests for issue and redeem --- standalone/runtime/tests/mock/mod.rs | 53 ++++++++++++--------- standalone/runtime/tests/test_issue.rs | 19 ++++---- standalone/runtime/tests/test_nomination.rs | 6 +++ standalone/runtime/tests/test_redeem.rs | 8 +++- 4 files changed, 53 insertions(+), 33 deletions(-) diff --git a/standalone/runtime/tests/mock/mod.rs b/standalone/runtime/tests/mock/mod.rs index 08bb2af0ff..c2ab4d348f 100644 --- a/standalone/runtime/tests/mock/mod.rs +++ b/standalone/runtime/tests/mock/mod.rs @@ -21,6 +21,7 @@ pub use interbtc_runtime_standalone::{ }; pub use mocktopus::mocking::*; pub use orml_tokens::CurrencyAdapter; +use pallet_traits::Loans; pub use primitives::{ CurrencyId::{ForeignAsset, PToken, Token}, Rate, Ratio, VaultCurrencyPair, VaultId as PrimitiveVaultId, DOT, IBTC, INTR, KBTC, KINT, KSM, @@ -47,7 +48,7 @@ use std::collections::BTreeMap; pub use std::convert::TryFrom; pub use vault_registry::{CurrencySource, DefaultVaultId, Vault, VaultStatus}; -use self::redeem_testing_utils::USER_BTC_ADDRESS; +use self::{issue_testing_utils::VAULT, redeem_testing_utils::USER_BTC_ADDRESS}; pub mod issue_testing_utils; pub mod loans_testing_utils; @@ -217,7 +218,7 @@ pub fn vault_id_of(id: [u8; 32], collateral_currency: CurrencyId) -> VaultId { pub fn default_user_state() -> UserData { let mut balances = BTreeMap::new(); - for currency_id in iter_collateral_currencies() { + for currency_id in iter_collateral_currencies_and_ptokens() { balances.insert( currency_id, AccountData { @@ -355,15 +356,6 @@ impl Wrapped for VaultId { } } -pub fn iter_currency_pairs() -> impl Iterator> { - iter_collateral_currencies().flat_map(|collateral_id| { - iter_wrapped_currencies().map(move |wrapped_id| VaultCurrencyPair { - collateral: collateral_id, - wrapped: wrapped_id, - }) - }) -} - pub fn iter_currency_pairs_with_ptokens() -> impl Iterator> { iter_collateral_currencies_and_ptokens().flat_map(|collateral_id| { iter_wrapped_currencies().map(move |wrapped_id| VaultCurrencyPair { @@ -373,6 +365,20 @@ pub fn iter_currency_pairs_with_ptokens() -> impl Iterator impl Iterator { + vec![ + account_of(ALICE), + account_of(BOB), + account_of(CAROL), + account_of(DAVE), + account_of(EVE), + account_of(FRANK), + account_of(GRACE), + account_of(FAUCET), + ] + .into_iter() +} + pub fn iter_collateral_currencies() -> impl Iterator { vec![Token(DOT), Token(KSM), Token(INTR), ForeignAsset(1)].into_iter() } @@ -392,7 +398,7 @@ pub fn iter_wrapped_currencies() -> impl Iterator { } pub fn iter_all_currencies() -> impl Iterator { - iter_collateral_currencies() + iter_collateral_currencies_and_ptokens() .chain(iter_native_currencies()) .chain(iter_wrapped_currencies()) } @@ -799,7 +805,7 @@ pub struct LiquidationVaultData { impl LiquidationVaultData { pub fn get() -> Self { - let liquidation_vaults = iter_currency_pairs() + let liquidation_vaults = iter_currency_pairs_with_ptokens() .map(|currency_pair| { let vault = VaultRegistryPallet::get_liquidation_vault(¤cy_pair); let data = SingleLiquidationVault { @@ -824,7 +830,7 @@ impl LiquidationVaultData { let mut ret = Self { liquidation_vaults: BTreeMap::new(), }; - for pair in iter_currency_pairs() { + for pair in iter_currency_pairs_with_ptokens() { if &pair == currency_pair { ret.liquidation_vaults .insert(pair.clone(), SingleLiquidationVault::zero(&pair)); @@ -969,18 +975,21 @@ impl ParachainTwoVaultState { } } +pub fn set_collateral_price(vault_id: &VaultId, price: FixedU128) { + let currency_to_set = if vault_id.currencies.collateral.is_ptoken() { + LoansPallet::underlying_id(vault_id.currencies.collateral).unwrap() + } else { + vault_id.currencies.collateral + }; + assert_ok!(OraclePallet::_set_exchange_rate(currency_to_set, price)); +} + pub fn liquidate_vault(vault_id: &VaultId) { VaultRegistryPallet::collateral_integrity_check(); - assert_ok!(OraclePallet::_set_exchange_rate( - vault_id.currencies.collateral, - FixedU128::checked_from_integer(10_000_000_000u128).unwrap() - )); + set_collateral_price(vault_id, FixedU128::checked_from_integer(10_000_000_000u128).unwrap()); assert_ok!(VaultRegistryPallet::liquidate_vault(&vault_id)); - assert_ok!(OraclePallet::_set_exchange_rate( - vault_id.currencies.collateral, - FixedU128::checked_from_integer(1u128).unwrap() - )); + set_collateral_price(vault_id, FixedU128::checked_from_integer(1u128).unwrap()); assert_eq!( CurrencySource::::AvailableReplaceCollateral(vault_id.clone()) diff --git a/standalone/runtime/tests/test_issue.rs b/standalone/runtime/tests/test_issue.rs index bd915e5233..8c586ba035 100644 --- a/standalone/runtime/tests/test_issue.rs +++ b/standalone/runtime/tests/test_issue.rs @@ -19,23 +19,22 @@ fn test_with(execute: impl Fn(VaultId) -> R) { if wrapped_id != Token(IBTC) { assert_ok!(OraclePallet::_set_exchange_rate(wrapped_id, FixedU128::one())); } + activate_market(Token(DOT), PToken(1)); + for account in iter_endowed_with_ptoken() { + mint_ptokens(account, Token(DOT)); + } + UserData::force_to(USER, default_user_state()); let vault_id = PrimitiveVaultId::new(account_of(VAULT), currency_id, wrapped_id); LiquidationVaultData::force_to(default_liquidation_vault_state(&vault_id.currencies)); - activate_market(Token(DOT), PToken(1)); - mint_ptokens(account_of(VAULT), Token(DOT)); - mint_ptokens(account_of(BOB), Token(DOT)); - mint_ptokens(account_of(CAROL), Token(DOT)); - mint_ptokens(account_of(FAUCET), Token(DOT)); - execute(vault_id) }); }; - // test_with(Token(DOT), Token(KBTC)); - // test_with(Token(KSM), Token(IBTC)); - // test_with(Token(DOT), Token(IBTC)); - // test_with(ForeignAsset(1), Token(IBTC)); + test_with(Token(DOT), Token(KBTC)); + test_with(Token(KSM), Token(IBTC)); + test_with(Token(DOT), Token(IBTC)); + test_with(ForeignAsset(1), Token(IBTC)); test_with(PToken(1), Token(IBTC)); } diff --git a/standalone/runtime/tests/test_nomination.rs b/standalone/runtime/tests/test_nomination.rs index 19cea0dfc7..b4e335a35b 100644 --- a/standalone/runtime/tests/test_nomination.rs +++ b/standalone/runtime/tests/test_nomination.rs @@ -1,5 +1,6 @@ mod mock; +use crate::loans_testing_utils::{activate_market, mint_ptokens}; use currency::Amount; use mock::{assert_eq, nomination_testing_utils::*, *}; use sp_runtime::traits::{CheckedDiv, CheckedSub}; @@ -14,6 +15,10 @@ fn test_with(execute: impl Fn(VaultId) -> R) { if wrapped_id != Token(IBTC) { assert_ok!(OraclePallet::_set_exchange_rate(wrapped_id, FixedU128::one())); } + activate_market(Token(DOT), PToken(1)); + for account in iter_endowed_with_ptoken() { + mint_ptokens(account, Token(DOT)); + } UserData::force_to(USER, default_user_state()); let vault_id = PrimitiveVaultId::new(account_of(VAULT), currency_id, wrapped_id); LiquidationVaultData::force_to(default_liquidation_vault_state(&vault_id.currencies)); @@ -26,6 +31,7 @@ fn test_with(execute: impl Fn(VaultId) -> R) { test_with(Token(KSM), Token(IBTC)); test_with(Token(DOT), Token(IBTC)); test_with(ForeignAsset(1), Token(IBTC)); + // test_with(PToken(1), Token(IBTC)); } fn test_with_nomination_enabled(execute: impl Fn(VaultId) -> R) { diff --git a/standalone/runtime/tests/test_redeem.rs b/standalone/runtime/tests/test_redeem.rs index a2cf6c6ea9..2868b4c115 100644 --- a/standalone/runtime/tests/test_redeem.rs +++ b/standalone/runtime/tests/test_redeem.rs @@ -2,6 +2,7 @@ mod mock; use std::str::FromStr; +use crate::loans_testing_utils::{activate_market, mint_ptokens}; use currency::Amount; use mock::{assert_eq, redeem_testing_utils::*, *}; @@ -14,6 +15,10 @@ fn test_with(execute: impl Fn(VaultId) -> R) { if wrapped_id != Token(IBTC) { assert_ok!(OraclePallet::_set_exchange_rate(wrapped_id, FixedU128::one())); } + activate_market(Token(DOT), PToken(1)); + for account in iter_endowed_with_ptoken() { + mint_ptokens(account, Token(DOT)); + } set_default_thresholds(); LiquidationVaultData::force_to(default_liquidation_vault_state(&vault_id.currencies)); UserData::force_to(USER, default_user_state()); @@ -38,6 +43,7 @@ fn test_with(execute: impl Fn(VaultId) -> R) { test_with(Token(DOT), Token(IBTC), Some(Token(KSM))); test_with(Token(KSM), Token(IBTC), None); test_with(ForeignAsset(1), Token(IBTC), None); + test_with(PToken(1), Token(IBTC), None); } /// to-be-replaced & replace_collateral are decreased in request_redeem @@ -1354,7 +1360,7 @@ fn integration_test_premium_redeem_wrapped_execute() { // make vault undercollateralized. Note that we place it under the liquidation threshold // as well, but as long as we don't call liquidate that's ok - assert_ok!(OraclePallet::_set_exchange_rate(currency_id, FixedU128::from(100))); + set_collateral_price(&vault_id, FixedU128::from(100)); // alice requests to redeem issued_tokens from Bob assert_ok!(Call::Redeem(RedeemCall::request_redeem { From 551692c88938ced8c969605a9964ff0325450de9 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Wed, 19 Oct 2022 23:21:22 +0200 Subject: [PATCH 33/58] feat(loans): nomination integration tests with ptokens collateral --- standalone/runtime/tests/test_nomination.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/standalone/runtime/tests/test_nomination.rs b/standalone/runtime/tests/test_nomination.rs index b4e335a35b..281b837b6f 100644 --- a/standalone/runtime/tests/test_nomination.rs +++ b/standalone/runtime/tests/test_nomination.rs @@ -31,7 +31,7 @@ fn test_with(execute: impl Fn(VaultId) -> R) { test_with(Token(KSM), Token(IBTC)); test_with(Token(DOT), Token(IBTC)); test_with(ForeignAsset(1), Token(IBTC)); - // test_with(PToken(1), Token(IBTC)); + test_with(PToken(1), Token(IBTC)); } fn test_with_nomination_enabled(execute: impl Fn(VaultId) -> R) { @@ -353,10 +353,8 @@ mod spec_based_tests { .dispatch(origin_of(account_of(VAULT)))); assert_nomination_opt_in(&vault_id); assert_nominate_collateral(&vault_id, account_of(USER), default_nomination(&vault_id)); - assert_ok!(OraclePallet::_set_exchange_rate( - vault_id.collateral_currency(), - FixedU128::checked_from_integer(3u128).unwrap() - )); + set_collateral_price(&vault_id, FixedU128::checked_from_integer(3u128).unwrap()); + assert_noop!( withdraw_nominator_collateral(account_of(USER), &vault_id, default_nomination(&vault_id)), NominationError::CannotWithdrawCollateral @@ -550,10 +548,7 @@ fn integration_test_nominator_withdrawal_below_collateralization_threshold_fails .dispatch(origin_of(account_of(VAULT)))); assert_nomination_opt_in(&vault_id); assert_nominate_collateral(&vault_id, account_of(USER), default_nomination(&vault_id)); - assert_ok!(OraclePallet::_set_exchange_rate( - vault_id.collateral_currency(), - FixedU128::checked_from_integer(3u128).unwrap() - )); + set_collateral_price(&vault_id, FixedU128::checked_from_integer(3u128).unwrap()); assert_noop!( withdraw_nominator_collateral(account_of(USER), &vault_id, default_nomination(&vault_id)), NominationError::CannotWithdrawCollateral From 0b4eef5e3f59e814a2dd14274473bd06b5adac52 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Thu, 20 Oct 2022 13:44:06 +0200 Subject: [PATCH 34/58] chore(loans): improve comments, remove test duplication --- crates/loans/src/interest.rs | 3 ++- crates/loans/src/lib.rs | 3 --- primitives/src/lib.rs | 5 +--- standalone/runtime/src/lib.rs | 10 +++++++- .../runtime/tests/mock/loans_testing_utils.rs | 9 +++++++- standalone/runtime/tests/mock/mod.rs | 23 ++++++++----------- standalone/runtime/tests/test_issue.rs | 15 +++--------- standalone/runtime/tests/test_nomination.rs | 13 ++++------- standalone/runtime/tests/test_redeem.rs | 9 +++----- standalone/runtime/tests/test_replace.rs | 2 +- .../runtime/tests/test_vault_registry.rs | 2 +- 11 files changed, 42 insertions(+), 52 deletions(-) diff --git a/crates/loans/src/interest.rs b/crates/loans/src/interest.rs index 6ceb64b593..74c7eb344d 100644 --- a/crates/loans/src/interest.rs +++ b/crates/loans/src/interest.rs @@ -133,7 +133,8 @@ impl Pallet { Ok(Ratio::from_rational(borrows, total)) } - /// The exchange rate should be greater than 0.02 and less than 1 + /// The exchange rate should be greater than the `MinExchangeRate` storage value and less than + /// the `MaxExchangeRate` storage value. pub(crate) fn ensure_valid_exchange_rate(exchange_rate: Rate) -> DispatchResult { ensure!( exchange_rate >= Self::min_exchange_rate() && exchange_rate < Self::max_exchange_rate(), diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 629eed127c..8c5edd0fb8 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -434,19 +434,16 @@ pub mod pallet { /// The reward accrued but not yet transferred to each user. #[pallet::storage] - #[pallet::storage_prefix = "RewardAccured"] #[pallet::getter(fn reward_accrued)] pub type RewardAccrued = StorageMap<_, Blake2_128Concat, T::AccountId, BalanceOf, ValueQuery>; /// The maximum allowed exchange rate for a market. #[pallet::storage] - #[pallet::storage_prefix = "MaxExchangeRate"] #[pallet::getter(fn max_exchange_rate)] pub type MaxExchangeRate = StorageValue<_, Rate, ValueQuery>; /// The minimum allowed exchange rate for a market. #[pallet::storage] - #[pallet::storage_prefix = "MinExchangeRate"] #[pallet::getter(fn min_exchange_rate)] pub type MinExchangeRate = StorageValue<_, Rate, ValueQuery>; diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index b607dad3b1..9c8a6a1091 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -487,9 +487,6 @@ pub struct CustomMetadata { impl CurrencyId { pub fn is_ptoken(&self) -> bool { - match self { - CurrencyId::PToken(_) => true, - _ => false, - } + matches!(self, CurrencyId::PToken(_)) } } diff --git a/standalone/runtime/src/lib.rs b/standalone/runtime/src/lib.rs index 260dac3948..101d4a3e30 100644 --- a/standalone/runtime/src/lib.rs +++ b/standalone/runtime/src/lib.rs @@ -809,7 +809,12 @@ impl security::Config for Runtime { pub struct CurrencyConvert; impl currency::CurrencyConversion, CurrencyId> for CurrencyConvert { fn convert(amount: ¤cy::Amount, to: CurrencyId) -> Result, DispatchError> { - if amount.currency().is_ptoken() { + if amount.currency().is_ptoken() && to.is_ptoken() { + let to_underlying_id = Loans::underlying_id(to)?; + let from_underlying_amount = Loans::get_underlying_amount(amount)?; + let to_underlying_amount = Oracle::convert(&from_underlying_amount, to_underlying_id)?; + Loans::get_collateral_amount(&to_underlying_amount) + } else if amount.currency().is_ptoken() { Oracle::convert(&Loans::get_underlying_amount(amount)?, to) } else if to.is_ptoken() { let underlying_id = Loans::underlying_id(to)?; @@ -836,6 +841,9 @@ impl pallet_traits::PriceFeeder for PriceFeed { return None; } } + // Returning `None` here means there is no price for this asset. + // This is fine since PTokens may not be used as underlying currency + // in the loans pallet. PToken(_) => return None, }; let amount = Amount::::new(one, asset_id.clone()); diff --git a/standalone/runtime/tests/mock/loans_testing_utils.rs b/standalone/runtime/tests/mock/loans_testing_utils.rs index cd8bb145e0..cb48248aed 100644 --- a/standalone/runtime/tests/mock/loans_testing_utils.rs +++ b/standalone/runtime/tests/mock/loans_testing_utils.rs @@ -42,8 +42,15 @@ pub fn mint_ptokens(account_id: AccountId, underlying_id: CurrencyId) { assert_ok!(amount.mint_to(&account_id)); assert_ok!(Call::Loans(LoansCall::mint { - asset_id: Token(DOT), + asset_id: underlying_id, mint_amount: balance_to_mint }) .dispatch(origin_of(account_id))); } + +pub fn activate_lending_and_mint(underlying_id: CurrencyId, ptoken_id: CurrencyId) { + activate_market(underlying_id, ptoken_id); + for account in iter_endowed_with_ptoken() { + mint_ptokens(account, underlying_id); + } +} diff --git a/standalone/runtime/tests/mock/mod.rs b/standalone/runtime/tests/mock/mod.rs index c2ab4d348f..f427c13bf7 100644 --- a/standalone/runtime/tests/mock/mod.rs +++ b/standalone/runtime/tests/mock/mod.rs @@ -218,7 +218,7 @@ pub fn vault_id_of(id: [u8; 32], collateral_currency: CurrencyId) -> VaultId { pub fn default_user_state() -> UserData { let mut balances = BTreeMap::new(); - for currency_id in iter_collateral_currencies_and_ptokens() { + for currency_id in iter_collateral_currencies() { balances.insert( currency_id, AccountData { @@ -357,7 +357,7 @@ impl Wrapped for VaultId { } pub fn iter_currency_pairs_with_ptokens() -> impl Iterator> { - iter_collateral_currencies_and_ptokens().flat_map(|collateral_id| { + iter_collateral_currencies().flat_map(|collateral_id| { iter_wrapped_currencies().map(move |wrapped_id| VaultCurrencyPair { collateral: collateral_id, wrapped: wrapped_id, @@ -380,13 +380,7 @@ pub fn iter_endowed_with_ptoken() -> impl Iterator { } pub fn iter_collateral_currencies() -> impl Iterator { - vec![Token(DOT), Token(KSM), Token(INTR), ForeignAsset(1)].into_iter() -} - -// ptokens should not be minted to the endowed accounts. Use this function -// to include them in the iterators for configuring the bridge. -pub fn iter_collateral_currencies_and_ptokens() -> impl Iterator { - iter_collateral_currencies().chain(vec![PToken(1)].into_iter()) + vec![Token(DOT), Token(KSM), Token(INTR), ForeignAsset(1), PToken(1)].into_iter() } pub fn iter_native_currencies() -> impl Iterator { @@ -398,7 +392,7 @@ pub fn iter_wrapped_currencies() -> impl Iterator { } pub fn iter_all_currencies() -> impl Iterator { - iter_collateral_currencies_and_ptokens() + iter_collateral_currencies() .chain(iter_native_currencies()) .chain(iter_wrapped_currencies()) } @@ -975,7 +969,7 @@ impl ParachainTwoVaultState { } } -pub fn set_collateral_price(vault_id: &VaultId, price: FixedU128) { +pub fn set_collateral_exchange_rate(vault_id: &VaultId, price: FixedU128) { let currency_to_set = if vault_id.currencies.collateral.is_ptoken() { LoansPallet::underlying_id(vault_id.currencies.collateral).unwrap() } else { @@ -987,9 +981,9 @@ pub fn set_collateral_price(vault_id: &VaultId, price: FixedU128) { pub fn liquidate_vault(vault_id: &VaultId) { VaultRegistryPallet::collateral_integrity_check(); - set_collateral_price(vault_id, FixedU128::checked_from_integer(10_000_000_000u128).unwrap()); + set_collateral_exchange_rate(vault_id, FixedU128::checked_from_integer(10_000_000_000u128).unwrap()); assert_ok!(VaultRegistryPallet::liquidate_vault(&vault_id)); - set_collateral_price(vault_id, FixedU128::checked_from_integer(1u128).unwrap()); + set_collateral_exchange_rate(vault_id, FixedU128::checked_from_integer(1u128).unwrap()); assert_eq!( CurrencySource::::AvailableReplaceCollateral(vault_id.clone()) @@ -1005,7 +999,7 @@ pub fn set_default_thresholds() { let premium = FixedU128::checked_from_rational(135, 100).unwrap(); let liquidation = FixedU128::checked_from_rational(110, 100).unwrap(); - for collateral_id in iter_collateral_currencies_and_ptokens() { + for collateral_id in iter_collateral_currencies() { for wrapped_id in iter_wrapped_currencies() { let currency_pair = VaultCurrencyPair { collateral: collateral_id, @@ -1382,6 +1376,7 @@ impl ExtBuilder { .into_iter() .flat_map(|(account, balance)| { iter_collateral_currencies() + .filter(|c| !c.is_ptoken()) .chain(iter_native_currencies()) .unique() .map(move |currency| (account.clone(), currency, balance)) diff --git a/standalone/runtime/tests/test_issue.rs b/standalone/runtime/tests/test_issue.rs index 8c586ba035..d212631358 100644 --- a/standalone/runtime/tests/test_issue.rs +++ b/standalone/runtime/tests/test_issue.rs @@ -1,29 +1,20 @@ mod mock; use currency::Amount; -use mock::{ - assert_eq, - issue_testing_utils::*, - loans_testing_utils::{activate_market, market_mock, mint_ptokens}, - *, -}; +use mock::{assert_eq, issue_testing_utils::*, loans_testing_utils::activate_lending_and_mint, *}; use CurrencyId::PToken; fn test_with(execute: impl Fn(VaultId) -> R) { let test_with = |currency_id, wrapped_id| { ExtBuilder::build().execute_with(|| { SecurityPallet::set_active_block_number(1); - for currency_id in iter_collateral_currencies() { + for currency_id in iter_collateral_currencies().filter(|c| !c.is_ptoken()) { assert_ok!(OraclePallet::_set_exchange_rate(currency_id, FixedU128::one())); } if wrapped_id != Token(IBTC) { assert_ok!(OraclePallet::_set_exchange_rate(wrapped_id, FixedU128::one())); } - activate_market(Token(DOT), PToken(1)); - for account in iter_endowed_with_ptoken() { - mint_ptokens(account, Token(DOT)); - } - + activate_lending_and_mint(Token(DOT), PToken(1)); UserData::force_to(USER, default_user_state()); let vault_id = PrimitiveVaultId::new(account_of(VAULT), currency_id, wrapped_id); LiquidationVaultData::force_to(default_liquidation_vault_state(&vault_id.currencies)); diff --git a/standalone/runtime/tests/test_nomination.rs b/standalone/runtime/tests/test_nomination.rs index 281b837b6f..5774ce4349 100644 --- a/standalone/runtime/tests/test_nomination.rs +++ b/standalone/runtime/tests/test_nomination.rs @@ -1,6 +1,6 @@ mod mock; -use crate::loans_testing_utils::{activate_market, mint_ptokens}; +use crate::loans_testing_utils::activate_lending_and_mint; use currency::Amount; use mock::{assert_eq, nomination_testing_utils::*, *}; use sp_runtime::traits::{CheckedDiv, CheckedSub}; @@ -9,16 +9,13 @@ fn test_with(execute: impl Fn(VaultId) -> R) { let test_with = |currency_id, wrapped_id| { ExtBuilder::build().execute_with(|| { SecurityPallet::set_active_block_number(1); - for currency_id in iter_collateral_currencies() { + for currency_id in iter_collateral_currencies().filter(|c| !c.is_ptoken()) { assert_ok!(OraclePallet::_set_exchange_rate(currency_id, FixedU128::one())); } if wrapped_id != Token(IBTC) { assert_ok!(OraclePallet::_set_exchange_rate(wrapped_id, FixedU128::one())); } - activate_market(Token(DOT), PToken(1)); - for account in iter_endowed_with_ptoken() { - mint_ptokens(account, Token(DOT)); - } + activate_lending_and_mint(Token(DOT), PToken(1)); UserData::force_to(USER, default_user_state()); let vault_id = PrimitiveVaultId::new(account_of(VAULT), currency_id, wrapped_id); LiquidationVaultData::force_to(default_liquidation_vault_state(&vault_id.currencies)); @@ -353,7 +350,7 @@ mod spec_based_tests { .dispatch(origin_of(account_of(VAULT)))); assert_nomination_opt_in(&vault_id); assert_nominate_collateral(&vault_id, account_of(USER), default_nomination(&vault_id)); - set_collateral_price(&vault_id, FixedU128::checked_from_integer(3u128).unwrap()); + set_collateral_exchange_rate(&vault_id, FixedU128::checked_from_integer(3u128).unwrap()); assert_noop!( withdraw_nominator_collateral(account_of(USER), &vault_id, default_nomination(&vault_id)), @@ -548,7 +545,7 @@ fn integration_test_nominator_withdrawal_below_collateralization_threshold_fails .dispatch(origin_of(account_of(VAULT)))); assert_nomination_opt_in(&vault_id); assert_nominate_collateral(&vault_id, account_of(USER), default_nomination(&vault_id)); - set_collateral_price(&vault_id, FixedU128::checked_from_integer(3u128).unwrap()); + set_collateral_exchange_rate(&vault_id, FixedU128::checked_from_integer(3u128).unwrap()); assert_noop!( withdraw_nominator_collateral(account_of(USER), &vault_id, default_nomination(&vault_id)), NominationError::CannotWithdrawCollateral diff --git a/standalone/runtime/tests/test_redeem.rs b/standalone/runtime/tests/test_redeem.rs index 2868b4c115..7af0a0e632 100644 --- a/standalone/runtime/tests/test_redeem.rs +++ b/standalone/runtime/tests/test_redeem.rs @@ -2,7 +2,7 @@ mod mock; use std::str::FromStr; -use crate::loans_testing_utils::{activate_market, mint_ptokens}; +use crate::loans_testing_utils::activate_lending_and_mint; use currency::Amount; use mock::{assert_eq, redeem_testing_utils::*, *}; @@ -15,10 +15,7 @@ fn test_with(execute: impl Fn(VaultId) -> R) { if wrapped_id != Token(IBTC) { assert_ok!(OraclePallet::_set_exchange_rate(wrapped_id, FixedU128::one())); } - activate_market(Token(DOT), PToken(1)); - for account in iter_endowed_with_ptoken() { - mint_ptokens(account, Token(DOT)); - } + activate_lending_and_mint(Token(DOT), PToken(1)); set_default_thresholds(); LiquidationVaultData::force_to(default_liquidation_vault_state(&vault_id.currencies)); UserData::force_to(USER, default_user_state()); @@ -1360,7 +1357,7 @@ fn integration_test_premium_redeem_wrapped_execute() { // make vault undercollateralized. Note that we place it under the liquidation threshold // as well, but as long as we don't call liquidate that's ok - set_collateral_price(&vault_id, FixedU128::from(100)); + set_collateral_exchange_rate(&vault_id, FixedU128::from(100)); // alice requests to redeem issued_tokens from Bob assert_ok!(Call::Redeem(RedeemCall::request_redeem { diff --git a/standalone/runtime/tests/test_replace.rs b/standalone/runtime/tests/test_replace.rs index ffe07c6524..fe8a46df4f 100644 --- a/standalone/runtime/tests/test_replace.rs +++ b/standalone/runtime/tests/test_replace.rs @@ -1125,7 +1125,7 @@ fn integration_test_replace_cancel_replace_both_vaults_liquidated() { #[test] fn integration_test_replace_vault_with_different_currency_succeeds() { test_without_initialization(|currency_id| { - for currency_id in iter_collateral_currencies() { + for currency_id in iter_collateral_currencies().filter(|c| !c.is_ptoken()) { assert_ok!(OraclePallet::_set_exchange_rate(currency_id, FixedU128::one())); } set_default_thresholds(); diff --git a/standalone/runtime/tests/test_vault_registry.rs b/standalone/runtime/tests/test_vault_registry.rs index 092ab19b19..1b94826aa8 100644 --- a/standalone/runtime/tests/test_vault_registry.rs +++ b/standalone/runtime/tests/test_vault_registry.rs @@ -12,7 +12,7 @@ fn test_with(execute: impl Fn(VaultId) -> R) { let test_with = |currency_id, wrapped_id| { ExtBuilder::build().execute_with(|| { SecurityPallet::set_active_block_number(1); - for currency_id in iter_collateral_currencies() { + for currency_id in iter_collateral_currencies().filter(|c| !c.is_ptoken()) { assert_ok!(OraclePallet::_set_exchange_rate(currency_id, FixedU128::one())); } if wrapped_id != Token(IBTC) { From 84adbd347ef10f4df7a42a46f788e2c3cc66c25e Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Thu, 20 Oct 2022 18:51:35 +0200 Subject: [PATCH 35/58] refactor(loans): default CurrencyConversion implementation; remove unused traits --- Cargo.lock | 6 + crates/currency/Cargo.toml | 1 + crates/currency/src/lib.rs | 36 +++- crates/loans/src/lib.rs | 46 ++--- crates/loans/src/mock.rs | 30 ---- crates/oracle/Cargo.toml | 1 + crates/oracle/src/lib.rs | 43 ++--- crates/traits/src/lib.rs | 163 +----------------- crates/traits/src/loans.rs | 5 +- parachain/runtime/interlay/Cargo.toml | 1 + parachain/runtime/interlay/src/lib.rs | 1 + parachain/runtime/kintsugi/Cargo.toml | 1 + parachain/runtime/kintsugi/src/lib.rs | 1 + parachain/runtime/testnet-interlay/Cargo.toml | 1 + parachain/runtime/testnet-interlay/src/lib.rs | 1 + parachain/runtime/testnet-kintsugi/Cargo.toml | 1 + parachain/runtime/testnet-kintsugi/src/lib.rs | 1 + standalone/runtime/src/lib.rs | 25 +-- standalone/runtime/tests/mock/mod.rs | 4 +- 19 files changed, 107 insertions(+), 261 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bd2d5642f6..0b42735307 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1920,6 +1920,7 @@ dependencies = [ "mocktopus", "orml-tokens", "orml-traits", + "pallet-traits", "pallet-transaction-payment", "parity-scale-codec", "scale-info", @@ -3850,6 +3851,7 @@ dependencies = [ "pallet-society", "pallet-sudo", "pallet-timestamp", + "pallet-traits", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-treasury", @@ -4205,6 +4207,7 @@ dependencies = [ "pallet-session", "pallet-society", "pallet-timestamp", + "pallet-traits", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-treasury", @@ -5946,6 +5949,7 @@ dependencies = [ "orml-tokens", "orml-traits", "pallet-timestamp", + "pallet-traits", "parity-scale-codec", "scale-info", "security", @@ -12248,6 +12252,7 @@ dependencies = [ "pallet-society", "pallet-sudo", "pallet-timestamp", + "pallet-traits", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-treasury", @@ -12347,6 +12352,7 @@ dependencies = [ "pallet-society", "pallet-sudo", "pallet-timestamp", + "pallet-traits", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-treasury", diff --git a/crates/currency/Cargo.toml b/crates/currency/Cargo.toml index f084a49b04..17e203ef18 100644 --- a/crates/currency/Cargo.toml +++ b/crates/currency/Cargo.toml @@ -16,6 +16,7 @@ sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkad frame-support = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.26", default-features = false } frame-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.26", default-features = false } pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.26", default-features = false } +pallet-traits = { path = '../traits', default-features = false } # Parachain dependencies primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } diff --git a/crates/currency/src/lib.rs b/crates/currency/src/lib.rs index 2eb546c431..461e62ed4e 100644 --- a/crates/currency/src/lib.rs +++ b/crates/currency/src/lib.rs @@ -15,11 +15,12 @@ pub mod amount; use codec::{EncodeLike, FullCodec}; use frame_support::{dispatch::DispatchResult, traits::Get}; use orml_traits::{MultiCurrency, MultiReservableCurrency}; -use primitives::TruncateFixedPointToInt; +use pallet_traits::{LoansApi, OracleApi}; +use primitives::{CurrencyId as PrimitivesCurrencyId, TruncateFixedPointToInt}; use scale_info::TypeInfo; use sp_runtime::{ traits::{AtLeast32BitUnsigned, CheckedDiv, MaybeSerializeDeserialize}, - FixedPointNumber, FixedPointOperand, + DispatchError, FixedPointNumber, FixedPointOperand, }; use sp_std::{ convert::{TryFrom, TryInto}, @@ -34,6 +35,33 @@ mod types; use types::*; pub use types::{CurrencyConversion, CurrencyId}; +pub struct CurrencyConvert(PhantomData<(T, Oracle, Loans)>); +impl CurrencyConversion, CurrencyId> for CurrencyConvert +where + T: Config, + Oracle: OracleApi, CurrencyId>, + Loans: LoansApi, T::AccountId, ::Balance, Amount>, +{ + fn convert(amount: &Amount, to: CurrencyId) -> Result, DispatchError> { + if amount.currency().is_ptoken() && to.is_ptoken() { + let to_underlying_id = Loans::underlying_id(to)?; + let from_underlying_amount = Loans::get_underlying_amount(amount)?; + let to_underlying_amount = Oracle::convert(&from_underlying_amount, to_underlying_id)?; + Loans::get_collateral_amount(&to_underlying_amount) + } else if amount.currency().is_ptoken() { + Oracle::convert(&Loans::get_underlying_amount(amount)?, to) + } else if to.is_ptoken() { + let underlying_id = Loans::underlying_id(to)?; + // get the converted value expressed in the underlying asset + let underlying_amount = Oracle::convert(amount, underlying_id)?; + // get the equivalent ptoken amount using the internal exchange rate + Loans::get_collateral_amount(&underlying_amount) + } else { + Oracle::convert(amount, to) + } + } +} + #[frame_support::pallet] pub mod pallet { use super::*; @@ -42,7 +70,9 @@ pub mod pallet { /// ## Configuration /// The pallet's configuration trait. #[pallet::config] - pub trait Config: frame_system::Config + orml_tokens::Config> { + pub trait Config: + frame_system::Config + orml_tokens::Config, CurrencyId = PrimitivesCurrencyId> + { type UnsignedFixedPoint: FixedPointNumber> + TruncateFixedPointToInt + Encode diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 8c5edd0fb8..384f3ebd10 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -43,7 +43,7 @@ use num_traits::cast::ToPrimitive; use orml_traits::MultiCurrency; pub use pallet::*; use pallet_traits::{ - ConvertToBigUint, Loans as LoansTrait, LoansMarketDataProvider, MarketInfo, MarketStatus, PriceFeeder, + ConvertToBigUint, LoansApi as LoansTrait, LoansMarketDataProvider, MarketInfo, MarketStatus, PriceFeeder, }; use primitives::{Balance, CurrencyId, Liquidity, Price, Rate, Ratio, Shortfall, Timestamp}; use sp_runtime::{ @@ -1729,13 +1729,6 @@ impl Pallet { Err(Error::::InsufficientLiquidity.into()) } - pub fn get_underlying_amount(ptokens: &Amount) -> Result, DispatchError> { - let underlying_id = Self::underlying_id(ptokens.currency())?; - let exchange_rate = Self::exchange_rate_stored(underlying_id)?; - let underlying_amount = Self::calc_underlying_amount(ptokens.amount(), exchange_rate)?; - Ok(Amount::new(underlying_amount, underlying_id)) - } - pub fn calc_underlying_amount( voucher_amount: BalanceOf, exchange_rate: Rate, @@ -1745,13 +1738,6 @@ impl Pallet { .ok_or(ArithmeticError::Overflow)?) } - pub fn get_collateral_amount(underlying: &Amount) -> Result, DispatchError> { - let exchange_rate = Self::exchange_rate_stored(underlying.currency())?; - let underlying_amount = Self::calc_collateral_amount(underlying.amount(), exchange_rate)?; - let ptoken_id = Self::ptoken_id(underlying.currency())?; - Ok(Amount::new(underlying_amount, ptoken_id)) - } - pub fn calc_collateral_amount( underlying_amount: BalanceOf, exchange_rate: Rate, @@ -1846,13 +1832,6 @@ impl Pallet { Markets::::iter().filter(|(_, market)| market.state == MarketState::Active) } - // Returns a stored asset_id - // - // Returns `Err` if asset_id does not exist, it also means that ptoken_id is invalid. - pub fn underlying_id(ptoken_id: AssetIdOf) -> Result, DispatchError> { - UnderlyingAssetId::::try_get(ptoken_id).map_err(|_err| Error::::InvalidPtokenId.into()) - } - // Returns the ptoken_id of the related asset // // Returns `Err` if market does not exist. @@ -1872,7 +1851,7 @@ impl Pallet { } } -impl LoansTrait, AccountIdOf, BalanceOf> for Pallet { +impl LoansTrait, AccountIdOf, BalanceOf, Amount> for Pallet { fn do_mint(supplier: &AccountIdOf, asset_id: AssetIdOf, amount: BalanceOf) -> Result<(), DispatchError> { ensure!(!amount.is_zero(), Error::::InvalidAmount); Self::ensure_active_market(asset_id)?; @@ -2035,6 +2014,27 @@ impl LoansTrait, AccountIdOf, BalanceOf> for Palle Self::deposit_event(Event::::Redeemed(supplier.clone(), asset_id, redeem_amount)); Ok(()) } + + fn get_underlying_amount(ptokens: &Amount) -> Result, DispatchError> { + let underlying_id = Self::underlying_id(ptokens.currency())?; + let exchange_rate = Self::exchange_rate_stored(underlying_id)?; + let underlying_amount = Self::calc_underlying_amount(ptokens.amount(), exchange_rate)?; + Ok(Amount::new(underlying_amount, underlying_id)) + } + + // Returns a stored asset_id + // + // Returns `Err` if asset_id does not exist, it also means that ptoken_id is invalid. + fn underlying_id(ptoken_id: AssetIdOf) -> Result, DispatchError> { + UnderlyingAssetId::::try_get(ptoken_id).map_err(|_err| Error::::InvalidPtokenId.into()) + } + + fn get_collateral_amount(underlying: &Amount) -> Result, DispatchError> { + let exchange_rate = Self::exchange_rate_stored(underlying.currency())?; + let underlying_amount = Self::calc_collateral_amount(underlying.amount(), exchange_rate)?; + let ptoken_id = Self::ptoken_id(underlying.currency())?; + Ok(Amount::new(underlying_amount, ptoken_id)) + } } impl LoansMarketDataProvider, BalanceOf> for Pallet { diff --git a/crates/loans/src/mock.rs b/crates/loans/src/mock.rs index 1ba83006b3..3697ab6232 100644 --- a/crates/loans/src/mock.rs +++ b/crates/loans/src/mock.rs @@ -29,7 +29,6 @@ use frame_support::{ use frame_system::EnsureRoot; use mocktopus::{macros::mockable, mocking::*}; use orml_traits::{parameter_type_with_key, DataFeeder, DataProvider, DataProviderExtended}; -use pallet_traits::{VaultTokenCurrenciesFilter, VaultTokenExchangeRateProvider}; use primitives::{ CurrencyId::{ForeignAsset, PToken, Token}, Moment, PriceDetail, DOT, IBTC, INTR, KBTC, KINT, KSM, @@ -203,35 +202,6 @@ impl DataFeeder for MockDataProvider { } } -pub struct TokenExchangeRateProvider; -impl VaultTokenExchangeRateProvider for TokenExchangeRateProvider { - fn get_exchange_rate(_: &CurrencyId, _: Rate) -> Option { - Some(Rate::saturating_from_rational(100, 150)) - } -} - -pub struct TokenCurrenciesFilter; -impl VaultTokenCurrenciesFilter for TokenCurrenciesFilter { - fn contains(_asset_id: &CurrencyId) -> bool { - return false; - } -} - -pub struct VaultLoansRateProvider; -impl LoansMarketDataProvider for VaultLoansRateProvider { - fn get_full_interest_rate(_asset_id: CurrencyId) -> Option { - Some(Rate::from_inner(450_000_000_000_000_000)) - } - - fn get_market_info(_: CurrencyId) -> Result { - Ok(Default::default()) - } - - fn get_market_status(_: CurrencyId) -> Result, sp_runtime::DispatchError> { - Ok(Default::default()) - } -} - parameter_types! { pub const RelayCurrency: CurrencyId = Token(KSM); } diff --git a/crates/oracle/Cargo.toml b/crates/oracle/Cargo.toml index 7e72df66e8..0459b6ca9e 100644 --- a/crates/oracle/Cargo.toml +++ b/crates/oracle/Cargo.toml @@ -25,6 +25,7 @@ security = { path = "../security", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } staking = { path = "../staking", default-features = false } currency = { path = "../currency", default-features = false } +pallet-traits = { path = '../traits', default-features = false } [dev-dependencies] mocktopus = "0.7.0" diff --git a/crates/oracle/src/lib.rs b/crates/oracle/src/lib.rs index 8aef835552..47d3fbce76 100644 --- a/crates/oracle/src/lib.rs +++ b/crates/oracle/src/lib.rs @@ -38,6 +38,7 @@ use frame_support::{ weights::Weight, }; use frame_system::{ensure_root, ensure_signed}; +use pallet_traits::OracleApi; use scale_info::TypeInfo; use security::{ErrorCode, StatusCode}; use sp_runtime::{ @@ -308,26 +309,6 @@ impl Pallet { Aggregate::::get(key).ok_or(Error::::MissingExchangeRate.into()) } - pub fn convert(amount: &Amount, currency_id: T::CurrencyId) -> Result, DispatchError> { - let converted = match (amount.currency(), currency_id) { - (x, y) if x == y => amount.amount(), - (x, _) if x == T::GetWrappedCurrencyId::get() => { - // convert interbtc to collateral - Self::wrapped_to_collateral(amount.amount(), currency_id)? - } - (from_currency, x) if x == T::GetWrappedCurrencyId::get() => { - // convert collateral to interbtc - Self::collateral_to_wrapped(amount.amount(), from_currency)? - } - (_, _) => { - // first convert to btc, then convert the btc to the desired currency - let base = Self::collateral_to_wrapped(amount.amount(), amount.currency())?; - Self::wrapped_to_collateral(base, currency_id)? - } - }; - Ok(Amount::new(converted, currency_id)) - } - pub fn wrapped_to_collateral(amount: BalanceOf, currency_id: CurrencyId) -> Result, DispatchError> { let rate = Self::get_price(OracleKey::ExchangeRate(currency_id))?; let converted = rate.checked_mul_int(amount).ok_or(ArithmeticError::Overflow)?; @@ -428,3 +409,25 @@ impl Pallet { >::contains_key(oracle) } } + +impl OracleApi, T::CurrencyId> for Pallet { + fn convert(amount: &Amount, currency_id: T::CurrencyId) -> Result, DispatchError> { + let converted = match (amount.currency(), currency_id) { + (x, y) if x == y => amount.amount(), + (x, _) if x == T::GetWrappedCurrencyId::get() => { + // convert interbtc to collateral + Self::wrapped_to_collateral(amount.amount(), currency_id)? + } + (from_currency, x) if x == T::GetWrappedCurrencyId::get() => { + // convert collateral to interbtc + Self::collateral_to_wrapped(amount.amount(), from_currency)? + } + (_, _) => { + // first convert to btc, then convert the btc to the desired currency + let base = Self::collateral_to_wrapped(amount.amount(), amount.currency())?; + Self::wrapped_to_collateral(base, currency_id)? + } + }; + Ok(Amount::new(converted, currency_id)) + } +} diff --git a/crates/traits/src/lib.rs b/crates/traits/src/lib.rs index 007c0c6e59..67c63bc141 100644 --- a/crates/traits/src/lib.rs +++ b/crates/traits/src/lib.rs @@ -1,151 +1,18 @@ #![cfg_attr(not(feature = "std"), no_std)] -use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::{dispatch::DispatchError, traits::tokens::Balance as BalanceT}; +use frame_support::dispatch::DispatchError; use num_bigint::{BigUint, ToBigUint}; -use scale_info::TypeInfo; -use sp_runtime::{traits::Zero, RuntimeDebug}; use sp_std::prelude::*; -use primitives::{CurrencyId, PriceDetail, Rate, Timestamp}; +use primitives::{CurrencyId, PriceDetail}; pub mod loans; pub use loans::*; -pub trait EmergencyCallFilter { - fn contains(call: &Call) -> bool; -} - pub trait PriceFeeder { fn get_price(asset_id: &CurrencyId) -> Option; } -pub trait DecimalProvider { - fn get_decimal(asset_id: &CurrencyId) -> Option; -} - -pub trait EmergencyPriceFeeder { - fn set_emergency_price(asset_id: CurrencyId, price: Price); - fn reset_emergency_price(asset_id: CurrencyId); -} - -pub trait ExchangeRateProvider { - fn get_exchange_rate(asset_id: &CurrencyId) -> Option; -} - -pub trait LiquidStakingConvert { - fn staking_to_liquid(amount: Balance) -> Option; - fn liquid_to_staking(liquid_amount: Balance) -> Option; -} - -pub trait LiquidStakingCurrenciesProvider { - fn get_staking_currency() -> Option; - fn get_liquid_currency() -> Option; -} - -pub trait VaultTokenExchangeRateProvider { - fn get_exchange_rate(asset_id: &CurrencyId, init_rate: Rate) -> Option; -} - -pub trait LPVaultTokenExchangeRateProvider { - fn get_exchange_rate(lp_asset_id: &CurrencyId) -> Option; -} - -pub trait VaultTokenCurrenciesFilter { - fn contains(asset_id: &CurrencyId) -> bool; -} - -pub trait LPVaultTokenCurrenciesFilter { - fn contains(lp_asset_id: &CurrencyId) -> bool; -} - -#[derive(Encode, Decode, Eq, PartialEq, Copy, Clone, RuntimeDebug, PartialOrd, Ord, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -pub struct Pool { - pub base_amount: Balance, - pub quote_amount: Balance, - pub base_amount_last: Balance, - pub quote_amount_last: Balance, - pub lp_token_id: CurrencyId, - pub block_timestamp_last: BlockNumber, - pub price_0_cumulative_last: Balance, - pub price_1_cumulative_last: Balance, -} - -impl Pool { - pub fn new(lp_token_id: CurrencyId) -> Self { - Self { - base_amount: Zero::zero(), - quote_amount: Zero::zero(), - base_amount_last: Zero::zero(), - quote_amount_last: Zero::zero(), - lp_token_id, - block_timestamp_last: Zero::zero(), - price_0_cumulative_last: Zero::zero(), - price_1_cumulative_last: Zero::zero(), - } - } - - pub fn is_empty(&self) -> bool { - self.base_amount.is_zero() && self.quote_amount.is_zero() - } -} - -/// Exported traits from our AMM pallet. These functions are to be used -/// by the router to enable multi route token swaps -pub trait AMM { - /// Based on the path specified and the available pool balances - /// this will return the amounts outs when trading the specified - /// amount in - fn get_amounts_out(amount_in: Balance, path: Vec) -> Result, DispatchError>; - - /// Based on the path specified and the available pool balances - /// this will return the amounts in needed to produce the specified - /// amount out - fn get_amounts_in(amount_out: Balance, path: Vec) -> Result, DispatchError>; - - /// Handles a "swap" on the AMM side for "who". - /// This will move the `amount_in` funds to the AMM PalletId, - /// trade `pair.0` to `pair.1` and return a result with the amount - /// of currency that was sent back to the user. - fn swap(who: &AccountId, pair: (CurrencyId, CurrencyId), amount_in: Balance) -> Result<(), DispatchError>; - - /// Iterate keys of asset pair in AMM Pools - fn get_pools() -> Result, DispatchError>; - - /// Returns pool by lp_asset - fn get_pool_by_lp_asset( - asset_id: CurrencyId, - ) -> Option<(CurrencyId, CurrencyId, Pool)>; - - /// Returns pool by asset pair - fn get_pool_by_asset_pair(pair: (CurrencyId, CurrencyId)) -> Option>; -} - -/// Exported traits from StableSwap pallet. These functions are to be used -/// by the router. -pub trait StableSwap { - /// Based on the path specified and the available pool balances - /// this will return the amounts outs when trading the specified - /// amount in - fn get_amounts_out(amount_in: Balance, path: Vec) -> Result, DispatchError>; - - /// Based on the path specified and the available pool balances - /// this will return the amounts in needed to produce the specified - /// amount out - fn get_amounts_in(amount_out: Balance, path: Vec) -> Result, DispatchError>; - - /// Handles a "swap" on the AMM side for "who". - /// This will move the `amount_in` funds to the AMM PalletId, - /// trade `pair.0` to `pair.1` and return a result with the amount - /// of currency that was sent back to the user. - fn swap(who: &AccountId, pair: (CurrencyId, CurrencyId), amount_in: Balance) -> Result<(), DispatchError>; - - fn get_pools() -> Result, DispatchError>; - - fn get_reserves(asset_in: CurrencyId, asset_out: CurrencyId) -> Result<(Balance, Balance), DispatchError>; -} - pub trait ConvertToBigUint { fn get_big_uint(&self) -> BigUint; } @@ -156,28 +23,6 @@ impl ConvertToBigUint for u128 { } } -pub trait Streaming { - fn create( - sender: AccountId, - recipient: AccountId, - deposit: Balance, - asset_id: CurrencyId, - start_time: Timestamp, - end_time: Timestamp, - cancellable: bool, - ) -> Result<(), DispatchError>; -} - -impl Streaming for () { - fn create( - _sender: AccountId, - _recipient: AccountId, - _deposit: Balance, - _asset_id: CurrencyId, - _start_time: Timestamp, - _end_time: Timestamp, - _cancellable: bool, - ) -> Result<(), DispatchError> { - Ok(()) - } +pub trait OracleApi { + fn convert(amount: &Amount, to: CurrencyId) -> Result; } diff --git a/crates/traits/src/loans.rs b/crates/traits/src/loans.rs index d2a6e803d0..517a9d3ceb 100644 --- a/crates/traits/src/loans.rs +++ b/crates/traits/src/loans.rs @@ -19,7 +19,7 @@ use scale_info::TypeInfo; use sp_runtime::{FixedU128, RuntimeDebug}; use sp_std::prelude::*; -pub trait Loans { +pub trait LoansApi { fn do_mint(supplier: &AccountId, asset_id: CurrencyId, amount: Balance) -> Result<(), DispatchError>; fn do_borrow(borrower: &AccountId, asset_id: CurrencyId, amount: Balance) -> Result<(), DispatchError>; fn do_deposit_collateral(supplier: &AccountId, asset_id: CurrencyId, amount: Balance) -> Result<(), DispatchError>; @@ -27,6 +27,9 @@ pub trait Loans { -> Result<(), DispatchError>; fn do_repay_borrow(borrower: &AccountId, asset_id: CurrencyId, amount: Balance) -> Result<(), DispatchError>; fn do_redeem(supplier: &AccountId, asset_id: CurrencyId, amount: Balance) -> Result<(), DispatchError>; + fn get_underlying_amount(ptokens: &Amount) -> Result; + fn underlying_id(ptoken_id: CurrencyId) -> Result; + fn get_collateral_amount(underlying: &Amount) -> Result; } pub trait LoansPositionDataProvider { diff --git a/parachain/runtime/interlay/Cargo.toml b/parachain/runtime/interlay/Cargo.toml index e2b679c2ae..4c27438ffc 100644 --- a/parachain/runtime/interlay/Cargo.toml +++ b/parachain/runtime/interlay/Cargo.toml @@ -95,6 +95,7 @@ collator-selection = { path = "../../../crates/collator-selection", default-feat clients-info = { path = "../../../crates/clients-info", default-features = false } primitives = { package = "interbtc-primitives", path = "../../../primitives", default-features = false } +pallet-traits = { path = "../../../crates/traits", default-features = false } module-btc-relay-rpc-runtime-api = { path = "../../../crates/btc-relay/rpc/runtime-api", default-features = false } module-oracle-rpc-runtime-api = { path = "../../../crates/oracle/rpc/runtime-api", default-features = false } diff --git a/parachain/runtime/interlay/src/lib.rs b/parachain/runtime/interlay/src/lib.rs index 091eb75a2b..36ff0d1cc6 100644 --- a/parachain/runtime/interlay/src/lib.rs +++ b/parachain/runtime/interlay/src/lib.rs @@ -26,6 +26,7 @@ use frame_system::{ pub use orml_asset_registry::AssetMetadata; use orml_asset_registry::SequentialId; use orml_traits::parameter_type_with_key; +use pallet_traits::OracleApi; use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment}; use sp_api::impl_runtime_apis; use sp_core::{OpaqueMetadata, H256}; diff --git a/parachain/runtime/kintsugi/Cargo.toml b/parachain/runtime/kintsugi/Cargo.toml index 0998fbbfe9..db546a8547 100644 --- a/parachain/runtime/kintsugi/Cargo.toml +++ b/parachain/runtime/kintsugi/Cargo.toml @@ -95,6 +95,7 @@ collator-selection = { path = "../../../crates/collator-selection", default-feat clients-info = { path = "../../../crates/clients-info", default-features = false } primitives = { package = "interbtc-primitives", path = "../../../primitives", default-features = false } +pallet-traits = { path = "../../../crates/traits", default-features = false } module-btc-relay-rpc-runtime-api = { path = "../../../crates/btc-relay/rpc/runtime-api", default-features = false } module-oracle-rpc-runtime-api = { path = "../../../crates/oracle/rpc/runtime-api", default-features = false } diff --git a/parachain/runtime/kintsugi/src/lib.rs b/parachain/runtime/kintsugi/src/lib.rs index ac698b3520..f55acd9cfd 100644 --- a/parachain/runtime/kintsugi/src/lib.rs +++ b/parachain/runtime/kintsugi/src/lib.rs @@ -25,6 +25,7 @@ use frame_system::{ }; use orml_asset_registry::SequentialId; use orml_traits::parameter_type_with_key; +use pallet_traits::OracleApi; use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment}; use sp_api::impl_runtime_apis; use sp_core::{OpaqueMetadata, H256}; diff --git a/parachain/runtime/testnet-interlay/Cargo.toml b/parachain/runtime/testnet-interlay/Cargo.toml index a320113c92..c38dd5c5ae 100644 --- a/parachain/runtime/testnet-interlay/Cargo.toml +++ b/parachain/runtime/testnet-interlay/Cargo.toml @@ -96,6 +96,7 @@ collator-selection = { path = "../../../crates/collator-selection", default-feat clients-info = { path = "../../../crates/clients-info", default-features = false } primitives = { package = "interbtc-primitives", path = "../../../primitives", default-features = false } +pallet-traits = { path = "../../../crates/traits", default-features = false } module-btc-relay-rpc-runtime-api = { path = "../../../crates/btc-relay/rpc/runtime-api", default-features = false } module-oracle-rpc-runtime-api = { path = "../../../crates/oracle/rpc/runtime-api", default-features = false } diff --git a/parachain/runtime/testnet-interlay/src/lib.rs b/parachain/runtime/testnet-interlay/src/lib.rs index 279130ff1d..ef69a27a34 100644 --- a/parachain/runtime/testnet-interlay/src/lib.rs +++ b/parachain/runtime/testnet-interlay/src/lib.rs @@ -26,6 +26,7 @@ use frame_system::{ }; use orml_asset_registry::SequentialId; use orml_traits::{location::AbsoluteReserveProvider, parameter_type_with_key, MultiCurrency}; +use pallet_traits::OracleApi; use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment}; use sp_api::impl_runtime_apis; use sp_core::{OpaqueMetadata, H256}; diff --git a/parachain/runtime/testnet-kintsugi/Cargo.toml b/parachain/runtime/testnet-kintsugi/Cargo.toml index 1b048af197..eb6969d20f 100644 --- a/parachain/runtime/testnet-kintsugi/Cargo.toml +++ b/parachain/runtime/testnet-kintsugi/Cargo.toml @@ -96,6 +96,7 @@ collator-selection = { path = "../../../crates/collator-selection", default-feat clients-info = { path = "../../../crates/clients-info", default-features = false } primitives = { package = "interbtc-primitives", path = "../../../primitives", default-features = false } +pallet-traits = { path = "../../../crates/traits", default-features = false } module-btc-relay-rpc-runtime-api = { path = "../../../crates/btc-relay/rpc/runtime-api", default-features = false } module-oracle-rpc-runtime-api = { path = "../../../crates/oracle/rpc/runtime-api", default-features = false } diff --git a/parachain/runtime/testnet-kintsugi/src/lib.rs b/parachain/runtime/testnet-kintsugi/src/lib.rs index 09305ae759..0782f87d63 100644 --- a/parachain/runtime/testnet-kintsugi/src/lib.rs +++ b/parachain/runtime/testnet-kintsugi/src/lib.rs @@ -26,6 +26,7 @@ use frame_system::{ }; use orml_asset_registry::SequentialId; use orml_traits::{location::AbsoluteReserveProvider, parameter_type_with_key, MultiCurrency}; +use pallet_traits::OracleApi; use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment}; use sp_api::impl_runtime_apis; use sp_core::{OpaqueMetadata, H256}; diff --git a/standalone/runtime/src/lib.rs b/standalone/runtime/src/lib.rs index 101d4a3e30..a5a0ffa3c6 100644 --- a/standalone/runtime/src/lib.rs +++ b/standalone/runtime/src/lib.rs @@ -25,6 +25,7 @@ use frame_system::{ }; use orml_asset_registry::SequentialId; use orml_traits::parameter_type_with_key; +use pallet_traits::OracleApi; use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment}; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H256}; @@ -806,28 +807,6 @@ impl security::Config for Runtime { type Event = Event; } -pub struct CurrencyConvert; -impl currency::CurrencyConversion, CurrencyId> for CurrencyConvert { - fn convert(amount: ¤cy::Amount, to: CurrencyId) -> Result, DispatchError> { - if amount.currency().is_ptoken() && to.is_ptoken() { - let to_underlying_id = Loans::underlying_id(to)?; - let from_underlying_amount = Loans::get_underlying_amount(amount)?; - let to_underlying_amount = Oracle::convert(&from_underlying_amount, to_underlying_id)?; - Loans::get_collateral_amount(&to_underlying_amount) - } else if amount.currency().is_ptoken() { - Oracle::convert(&Loans::get_underlying_amount(amount)?, to) - } else if to.is_ptoken() { - let underlying_id = Loans::underlying_id(to)?; - // get the converted value expressed in the underlying asset - let underlying_amount = Oracle::convert(amount, underlying_id)?; - // get the equivalent ptoken amount using the internal exchange rate - Loans::get_collateral_amount(&underlying_amount) - } else { - Oracle::convert(amount, to) - } - } -} - pub struct PriceFeed; impl pallet_traits::PriceFeeder for PriceFeed { fn get_price(asset_id: &CurrencyId) -> Option { @@ -861,7 +840,7 @@ impl currency::Config for Runtime { type GetNativeCurrencyId = GetNativeCurrencyId; type GetRelayChainCurrencyId = GetRelayChainCurrencyId; type GetWrappedCurrencyId = GetWrappedCurrencyId; - type CurrencyConversion = CurrencyConvert; + type CurrencyConversion = currency::CurrencyConvert; } impl staking::Config for Runtime { diff --git a/standalone/runtime/tests/mock/mod.rs b/standalone/runtime/tests/mock/mod.rs index f427c13bf7..fe83802363 100644 --- a/standalone/runtime/tests/mock/mod.rs +++ b/standalone/runtime/tests/mock/mod.rs @@ -21,7 +21,7 @@ pub use interbtc_runtime_standalone::{ }; pub use mocktopus::mocking::*; pub use orml_tokens::CurrencyAdapter; -use pallet_traits::Loans; +use pallet_traits::LoansApi; pub use primitives::{ CurrencyId::{ForeignAsset, PToken, Token}, Rate, Ratio, VaultCurrencyPair, VaultId as PrimitiveVaultId, DOT, IBTC, INTR, KBTC, KINT, KSM, @@ -48,7 +48,7 @@ use std::collections::BTreeMap; pub use std::convert::TryFrom; pub use vault_registry::{CurrencySource, DefaultVaultId, Vault, VaultStatus}; -use self::{issue_testing_utils::VAULT, redeem_testing_utils::USER_BTC_ADDRESS}; +use self::redeem_testing_utils::USER_BTC_ADDRESS; pub mod issue_testing_utils; pub mod loans_testing_utils; From 2d18a240dfd6eee1cd1ce62ecaf4b466d33d4ade Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Thu, 20 Oct 2022 19:37:26 +0200 Subject: [PATCH 36/58] fix(loans): replace and vault registry integration tests --- Cargo.lock | 1 + crates/vault-registry/Cargo.toml | 1 + crates/vault-registry/src/mock.rs | 1 + standalone/runtime/tests/test_replace.rs | 5 +++++ standalone/runtime/tests/test_vault_registry.rs | 9 ++++++++- 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 0b42735307..7ac4c0ace1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12963,6 +12963,7 @@ dependencies = [ "orml-tokens", "orml-traits", "pallet-timestamp", + "pallet-traits", "parity-scale-codec", "pretty_assertions", "reward", diff --git a/crates/vault-registry/Cargo.toml b/crates/vault-registry/Cargo.toml index b7dd007e8c..f5b80765c5 100644 --- a/crates/vault-registry/Cargo.toml +++ b/crates/vault-registry/Cargo.toml @@ -44,6 +44,7 @@ orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", mocktopus = "0.7.0" frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.26", default-features = false } currency = { path = "../currency", default-features = false, features = ["testing-utils"] } +pallet-traits = { path = "../../crates/traits", default-features = false } pretty_assertions = "0.7.2" [features] diff --git a/crates/vault-registry/src/mock.rs b/crates/vault-registry/src/mock.rs index 2d286d4bb7..193531bc13 100644 --- a/crates/vault-registry/src/mock.rs +++ b/crates/vault-registry/src/mock.rs @@ -7,6 +7,7 @@ use frame_support::{ }; use mocktopus::{macros::mockable, mocking::clear_mocks}; use orml_traits::parameter_type_with_key; +use pallet_traits::OracleApi; pub use primitives::{CurrencyId, CurrencyId::Token, TokenSymbol::*}; use primitives::{VaultCurrencyPair, VaultId}; use sp_arithmetic::{FixedI128, FixedPointNumber, FixedU128}; diff --git a/standalone/runtime/tests/test_replace.rs b/standalone/runtime/tests/test_replace.rs index fe8a46df4f..4360d3f912 100644 --- a/standalone/runtime/tests/test_replace.rs +++ b/standalone/runtime/tests/test_replace.rs @@ -6,6 +6,8 @@ use mock::{assert_eq, replace_testing_utils::*, *}; use sp_core::H256; use vault_registry::DefaultVaultId; +use crate::loans_testing_utils::activate_lending_and_mint; + type IssueCall = issue::Call; pub type VaultRegistryError = vault_registry::Error; @@ -24,6 +26,7 @@ fn test_with(execute: impl Fn(VaultId, VaultId) -> R) { if wrapped_currency != Token(IBTC) { assert_ok!(OraclePallet::_set_exchange_rate(wrapped_currency, FixedU128::one())); } + activate_lending_and_mint(Token(DOT), PToken(1)); set_default_thresholds(); UserData::force_to(USER, default_user_state()); let old_vault_id = VaultId::new(account_of(OLD_VAULT), old_vault_currency, wrapped_currency); @@ -1140,6 +1143,8 @@ fn integration_test_replace_vault_with_different_currency_succeeds() { let old_vault_id = vault_id_of(OLD_VAULT, currency_id); let new_vault_id = vault_id_of(NEW_VAULT, other_currency); + // Mint pTokens so that force-setting vault state doesn't fail + activate_lending_and_mint(Token(DOT), PToken(1)); CoreVaultData::force_to(&old_vault_id, default_vault_state(&old_vault_id)); CoreVaultData::force_to(&new_vault_id, default_vault_state(&new_vault_id)); diff --git a/standalone/runtime/tests/test_vault_registry.rs b/standalone/runtime/tests/test_vault_registry.rs index 1b94826aa8..a7fce645f0 100644 --- a/standalone/runtime/tests/test_vault_registry.rs +++ b/standalone/runtime/tests/test_vault_registry.rs @@ -3,7 +3,10 @@ mod mock; use currency::Amount; use mock::{assert_eq, *}; -use crate::mock::issue_testing_utils::{execute_issue, request_issue}; +use crate::{ + loans_testing_utils::activate_lending_and_mint, + mock::issue_testing_utils::{execute_issue, request_issue}, +}; pub const USER: [u8; 32] = ALICE; pub const VAULT: [u8; 32] = BOB; @@ -18,6 +21,7 @@ fn test_with(execute: impl Fn(VaultId) -> R) { if wrapped_id != Token(IBTC) { assert_ok!(OraclePallet::_set_exchange_rate(wrapped_id, FixedU128::one())); } + activate_lending_and_mint(Token(DOT), PToken(1)); UserData::force_to(USER, default_user_state()); let vault_id = PrimitiveVaultId::new(account_of(VAULT), currency_id, wrapped_id); LiquidationVaultData::force_to(default_liquidation_vault_state(&vault_id.currencies)); @@ -30,6 +34,7 @@ fn test_with(execute: impl Fn(VaultId) -> R) { test_with(Token(KSM), Token(IBTC)); test_with(Token(DOT), Token(IBTC)); test_with(ForeignAsset(1), Token(IBTC)); + test_with(PToken(1), Token(IBTC)); } fn deposit_collateral_and_issue(vault_id: VaultId) { @@ -117,6 +122,8 @@ mod deposit_collateral_test { let amount_1 = 1000_000_000_000_000; + // Mint pTokens so that force-setting vault state doesn't fail + activate_lending_and_mint(Token(DOT), PToken(1)); let mut vault_data = default_vault_state(&vault_id); *vault_data.free_balance.get_mut(¤cy_id).unwrap() = Amount::new(amount_1, currency_id); CoreVaultData::force_to(&vault_id, vault_data); From 442cfa67539f9d1ddb4e0f3c110f4911537ab1d9 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Thu, 20 Oct 2022 19:49:12 +0200 Subject: [PATCH 37/58] test(loans): replace with pToken collateral --- standalone/runtime/tests/test_replace.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/standalone/runtime/tests/test_replace.rs b/standalone/runtime/tests/test_replace.rs index 4360d3f912..9a3e34a58a 100644 --- a/standalone/runtime/tests/test_replace.rs +++ b/standalone/runtime/tests/test_replace.rs @@ -63,6 +63,8 @@ fn test_with(execute: impl Fn(VaultId, VaultId) -> R) { test_with(Token(KSM), Token(DOT), Token(IBTC), None); test_with(ForeignAsset(1), Token(DOT), Token(IBTC), None); test_with(Token(KSM), ForeignAsset(1), Token(IBTC), None); + test_with(PToken(1), ForeignAsset(1), Token(IBTC), None); + test_with(Token(KSM), PToken(1), Token(IBTC), None); } fn test_without_initialization(execute: impl Fn(CurrencyId) -> R) { From c4f7aa34417af8b12a143934f7f72bb18f371860 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Fri, 21 Oct 2022 12:26:02 +0200 Subject: [PATCH 38/58] feat(loans): add lending to testnet runtimes --- Cargo.lock | 2 + parachain/runtime/testnet-interlay/Cargo.toml | 1 + parachain/runtime/testnet-interlay/src/lib.rs | 55 +++++++++++++++---- parachain/runtime/testnet-kintsugi/Cargo.toml | 1 + parachain/runtime/testnet-kintsugi/src/lib.rs | 55 +++++++++++++++---- parachain/src/chain_spec/mod.rs | 3 + parachain/src/chain_spec/testnet_interlay.rs | 7 +++ parachain/src/chain_spec/testnet_kintsugi.rs | 7 +++ standalone/runtime/src/lib.rs | 1 + 9 files changed, 112 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ac4c0ace1..824b3a078d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12244,6 +12244,7 @@ dependencies = [ "pallet-balances", "pallet-collective", "pallet-identity", + "pallet-loans", "pallet-membership", "pallet-multisig", "pallet-preimage", @@ -12344,6 +12345,7 @@ dependencies = [ "pallet-balances", "pallet-collective", "pallet-identity", + "pallet-loans", "pallet-membership", "pallet-multisig", "pallet-preimage", diff --git a/parachain/runtime/testnet-interlay/Cargo.toml b/parachain/runtime/testnet-interlay/Cargo.toml index c38dd5c5ae..442220cdae 100644 --- a/parachain/runtime/testnet-interlay/Cargo.toml +++ b/parachain/runtime/testnet-interlay/Cargo.toml @@ -94,6 +94,7 @@ annuity = { path = "../../../crates/annuity", default-features = false } supply = { path = "../../../crates/supply", default-features = false } collator-selection = { path = "../../../crates/collator-selection", default-features = false } clients-info = { path = "../../../crates/clients-info", default-features = false } +pallet-loans = { path = "../../../crates/loans", default-features = false } primitives = { package = "interbtc-primitives", path = "../../../primitives", default-features = false } pallet-traits = { path = "../../../crates/traits", default-features = false } diff --git a/parachain/runtime/testnet-interlay/src/lib.rs b/parachain/runtime/testnet-interlay/src/lib.rs index ef69a27a34..bec03edb0d 100644 --- a/parachain/runtime/testnet-interlay/src/lib.rs +++ b/parachain/runtime/testnet-interlay/src/lib.rs @@ -28,6 +28,7 @@ use orml_asset_registry::SequentialId; use orml_traits::{location::AbsoluteReserveProvider, parameter_type_with_key, MultiCurrency}; use pallet_traits::OracleApi; use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment}; +use primitives::PriceDetail; use sp_api::impl_runtime_apis; use sp_core::{OpaqueMetadata, H256}; use sp_runtime::{ @@ -65,8 +66,9 @@ pub use module_oracle_rpc_runtime_api::BalanceWrapper; pub use security::StatusCode; pub use primitives::{ - self, AccountId, BlockNumber, CurrencyInfo, Hash, Moment, Nonce, Signature, SignedFixedPoint, SignedInner, - UnsignedFixedPoint, UnsignedInner, + self, AccountId, BlockNumber, + CurrencyId::{ForeignAsset, PToken, Token}, + CurrencyInfo, Hash, Moment, Nonce, Signature, SignedFixedPoint, SignedInner, UnsignedFixedPoint, UnsignedInner, }; // XCM imports @@ -613,6 +615,7 @@ parameter_types! { pub const TreasuryPalletId: PalletId = PalletId(*b"mod/trsy"); pub const CollatorPotId: PalletId = PalletId(*b"col/slct"); pub const VaultRegistryPalletId: PalletId = PalletId(*b"mod/vreg"); + pub const LoansPalletId: PalletId = PalletId(*b"mod/loan"); } parameter_types! { @@ -870,13 +873,6 @@ impl security::Config for Runtime { type Event = Event; } -pub struct CurrencyConvert; -impl currency::CurrencyConversion, CurrencyId> for CurrencyConvert { - fn convert(amount: ¤cy::Amount, to: CurrencyId) -> Result, DispatchError> { - Oracle::convert(amount, to) - } -} - impl currency::Config for Runtime { type SignedInner = SignedInner; type SignedFixedPoint = SignedFixedPoint; @@ -885,7 +881,7 @@ impl currency::Config for Runtime { type GetNativeCurrencyId = GetNativeCurrencyId; type GetRelayChainCurrencyId = GetRelayChainCurrencyId; type GetWrappedCurrencyId = GetWrappedCurrencyId; - type CurrencyConversion = CurrencyConvert; + type CurrencyConversion = currency::CurrencyConvert; } impl staking::Config for Runtime { @@ -1017,6 +1013,44 @@ impl clients_info::Config for Runtime { type WeightInfo = (); } +// TODO: Remove this once `get_price()` is replaced with `amount.convert()` +pub struct PriceFeed; +impl pallet_traits::PriceFeeder for PriceFeed { + fn get_price(asset_id: &CurrencyId) -> Option { + let one = match asset_id { + Token(t) => t.one(), + ForeignAsset(f) => { + // TODO: Either add `one` to the AssetRegistry or require this as an associated type in the config trait + if let Some(metadata) = AssetRegistry::metadata(f) { + 10u128.pow(metadata.decimals) + } else { + return None; + } + } + // Returning `None` here means there is no price for this asset. + // This is fine since PTokens may not be used as underlying currency + // in the loans pallet. + PToken(_) => return None, + }; + let amount = Amount::::new(one, asset_id.clone()); + Oracle::convert(&amount, WRAPPED_CURRENCY_ID) + .ok() + .map(|price| (price.amount().into(), Timestamp::now())) + } +} + +impl pallet_loans::Config for Runtime { + type Event = Event; + type PalletId = LoansPalletId; + type PriceFeeder = PriceFeed; + type ReserveOrigin = EnsureRoot; + type UpdateOrigin = EnsureRoot; + type WeightInfo = (); + type UnixTime = Timestamp; + type Assets = Tokens; + type RewardAssetId = GetNativeCurrencyId; +} + construct_runtime! { pub enum Runtime where Block = Block, @@ -1063,6 +1097,7 @@ construct_runtime! { // Refund: 67 Nomination: nomination::{Pallet, Call, Config, Storage, Event} = 68, ClientsInfo: clients_info::{Pallet, Call, Storage, Event} = 96, + Loans: pallet_loans::{Pallet, Call, Storage, Event, Config} = 97, // # Governance Democracy: democracy::{Pallet, Call, Storage, Config, Event} = 70, diff --git a/parachain/runtime/testnet-kintsugi/Cargo.toml b/parachain/runtime/testnet-kintsugi/Cargo.toml index eb6969d20f..ebda4e9afb 100644 --- a/parachain/runtime/testnet-kintsugi/Cargo.toml +++ b/parachain/runtime/testnet-kintsugi/Cargo.toml @@ -94,6 +94,7 @@ annuity = { path = "../../../crates/annuity", default-features = false } supply = { path = "../../../crates/supply", default-features = false } collator-selection = { path = "../../../crates/collator-selection", default-features = false } clients-info = { path = "../../../crates/clients-info", default-features = false } +pallet-loans = { path = "../../../crates/loans", default-features = false } primitives = { package = "interbtc-primitives", path = "../../../primitives", default-features = false } pallet-traits = { path = "../../../crates/traits", default-features = false } diff --git a/parachain/runtime/testnet-kintsugi/src/lib.rs b/parachain/runtime/testnet-kintsugi/src/lib.rs index 0782f87d63..d6b47194bb 100644 --- a/parachain/runtime/testnet-kintsugi/src/lib.rs +++ b/parachain/runtime/testnet-kintsugi/src/lib.rs @@ -28,6 +28,7 @@ use orml_asset_registry::SequentialId; use orml_traits::{location::AbsoluteReserveProvider, parameter_type_with_key, MultiCurrency}; use pallet_traits::OracleApi; use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment}; +use primitives::PriceDetail; use sp_api::impl_runtime_apis; use sp_core::{OpaqueMetadata, H256}; use sp_runtime::{ @@ -65,8 +66,9 @@ pub use module_oracle_rpc_runtime_api::BalanceWrapper; pub use security::StatusCode; pub use primitives::{ - self, AccountId, BlockNumber, CurrencyInfo, Hash, Moment, Nonce, Signature, SignedFixedPoint, SignedInner, - UnsignedFixedPoint, UnsignedInner, + self, AccountId, BlockNumber, + CurrencyId::{ForeignAsset, PToken, Token}, + CurrencyInfo, Hash, Moment, Nonce, Signature, SignedFixedPoint, SignedInner, UnsignedFixedPoint, UnsignedInner, }; // XCM imports @@ -613,6 +615,7 @@ parameter_types! { pub const TreasuryPalletId: PalletId = PalletId(*b"mod/trsy"); pub const CollatorPotId: PalletId = PalletId(*b"col/slct"); pub const VaultRegistryPalletId: PalletId = PalletId(*b"mod/vreg"); + pub const LoansPalletId: PalletId = PalletId(*b"mod/loan"); } parameter_types! { @@ -870,13 +873,6 @@ impl security::Config for Runtime { type Event = Event; } -pub struct CurrencyConvert; -impl currency::CurrencyConversion, CurrencyId> for CurrencyConvert { - fn convert(amount: ¤cy::Amount, to: CurrencyId) -> Result, DispatchError> { - Oracle::convert(amount, to) - } -} - impl currency::Config for Runtime { type SignedInner = SignedInner; type SignedFixedPoint = SignedFixedPoint; @@ -885,7 +881,7 @@ impl currency::Config for Runtime { type GetNativeCurrencyId = GetNativeCurrencyId; type GetRelayChainCurrencyId = GetRelayChainCurrencyId; type GetWrappedCurrencyId = GetWrappedCurrencyId; - type CurrencyConversion = CurrencyConvert; + type CurrencyConversion = currency::CurrencyConvert; } impl staking::Config for Runtime { @@ -1017,6 +1013,44 @@ impl clients_info::Config for Runtime { type WeightInfo = (); } +// TODO: Remove this once `get_price()` is replaced with `amount.convert()` +pub struct PriceFeed; +impl pallet_traits::PriceFeeder for PriceFeed { + fn get_price(asset_id: &CurrencyId) -> Option { + let one = match asset_id { + Token(t) => t.one(), + ForeignAsset(f) => { + // TODO: Either add `one` to the AssetRegistry or require this as an associated type in the config trait + if let Some(metadata) = AssetRegistry::metadata(f) { + 10u128.pow(metadata.decimals) + } else { + return None; + } + } + // Returning `None` here means there is no price for this asset. + // This is fine since PTokens may not be used as underlying currency + // in the loans pallet. + PToken(_) => return None, + }; + let amount = Amount::::new(one, asset_id.clone()); + Oracle::convert(&amount, WRAPPED_CURRENCY_ID) + .ok() + .map(|price| (price.amount().into(), Timestamp::now())) + } +} + +impl pallet_loans::Config for Runtime { + type Event = Event; + type PalletId = LoansPalletId; + type PriceFeeder = PriceFeed; + type ReserveOrigin = EnsureRoot; + type UpdateOrigin = EnsureRoot; + type WeightInfo = (); + type UnixTime = Timestamp; + type Assets = Tokens; + type RewardAssetId = GetNativeCurrencyId; +} + construct_runtime! { pub enum Runtime where Block = Block, @@ -1063,6 +1097,7 @@ construct_runtime! { // Refund: 67 Nomination: nomination::{Pallet, Call, Config, Storage, Event} = 68, ClientsInfo: clients_info::{Pallet, Call, Storage, Event} = 96, + Loans: pallet_loans::{Pallet, Call, Storage, Event, Config} = 97, // # Governance Democracy: democracy::{Pallet, Call, Storage, Config, Event} = 70, diff --git a/parachain/src/chain_spec/mod.rs b/parachain/src/chain_spec/mod.rs index aa16cf8389..29f62cb9d6 100644 --- a/parachain/src/chain_spec/mod.rs +++ b/parachain/src/chain_spec/mod.rs @@ -95,6 +95,9 @@ const DEFAULT_DUST_VALUE: Balance = 1000; const DEFAULT_BITCOIN_CONFIRMATIONS: u32 = 1; const SECURE_BITCOIN_CONFIRMATIONS: u32 = 6; +pub const DEFAULT_MAX_EXCHANGE_RATE: u128 = 1_000_000_000_000_000_000; // 1 +pub const DEFAULT_MIN_EXCHANGE_RATE: u128 = 20_000_000_000_000_000; // 0.02 + fn expected_transaction_size() -> u32 { virtual_transaction_size( TransactionInputMetadata { diff --git a/parachain/src/chain_spec/testnet_interlay.rs b/parachain/src/chain_spec/testnet_interlay.rs index 4d3760b733..c627f9a82e 100644 --- a/parachain/src/chain_spec/testnet_interlay.rs +++ b/parachain/src/chain_spec/testnet_interlay.rs @@ -1,3 +1,6 @@ +use primitives::Rate; +use testnet_interlay_runtime::LoansConfig; + use super::*; fn testnet_properties(bitcoin_network: &str) -> Map { @@ -267,5 +270,9 @@ fn testnet_genesis( polkadot_xcm: testnet_interlay_runtime::PolkadotXcmConfig { safe_xcm_version: Some(2), }, + loans: LoansConfig { + max_exchange_rate: Rate::from_inner(DEFAULT_MAX_EXCHANGE_RATE), + min_exchange_rate: Rate::from_inner(DEFAULT_MIN_EXCHANGE_RATE), + }, } } diff --git a/parachain/src/chain_spec/testnet_kintsugi.rs b/parachain/src/chain_spec/testnet_kintsugi.rs index fffc23aaa6..965337402d 100644 --- a/parachain/src/chain_spec/testnet_kintsugi.rs +++ b/parachain/src/chain_spec/testnet_kintsugi.rs @@ -1,3 +1,6 @@ +use primitives::Rate; +use testnet_kintsugi_runtime::LoansConfig; + use super::*; fn testnet_properties(bitcoin_network: &str) -> Map { @@ -464,5 +467,9 @@ fn testnet_genesis( polkadot_xcm: testnet_kintsugi_runtime::PolkadotXcmConfig { safe_xcm_version: Some(2), }, + loans: LoansConfig { + max_exchange_rate: Rate::from_inner(DEFAULT_MAX_EXCHANGE_RATE), + min_exchange_rate: Rate::from_inner(DEFAULT_MIN_EXCHANGE_RATE), + }, } } diff --git a/standalone/runtime/src/lib.rs b/standalone/runtime/src/lib.rs index a5a0ffa3c6..ce2c14173f 100644 --- a/standalone/runtime/src/lib.rs +++ b/standalone/runtime/src/lib.rs @@ -807,6 +807,7 @@ impl security::Config for Runtime { type Event = Event; } +// TODO: Remove this once `get_price()` is replaced with `amount.convert()` pub struct PriceFeed; impl pallet_traits::PriceFeeder for PriceFeed { fn get_price(asset_id: &CurrencyId) -> Option { From 043d6bfc4b8cc0e2aef686bfa8df9df43d37fcf3 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Mon, 24 Oct 2022 20:24:50 +0200 Subject: [PATCH 39/58] test(loans): lockable ptokens, lending edge cases --- crates/loans/src/lib.rs | 60 +++++++++++--- crates/loans/src/tests.rs | 58 +++++++++++-- crates/loans/src/tests/edge_cases.rs | 28 ++++++- crates/loans/src/tests/interest_rate.rs | 2 + crates/loans/src/tests/liquidate_borrow.rs | 2 +- standalone/runtime/tests/mock/mod.rs | 16 ++-- standalone/runtime/tests/test_loans.rs | 94 ++++++++++++++++++++++ 7 files changed, 232 insertions(+), 28 deletions(-) diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 384f3ebd10..283da502fa 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -858,11 +858,31 @@ pub mod pallet { #[transactional] pub fn redeem_all(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; + // This function is an almost 1:1 duplicate of the logic in `do_redeem`. + // It could be refactored to compute the redeemable underlying + // with `Self::get_underlying_amount(&Self::free_ptokens(asset_id, &who)?)?` + // but that would cause the `accrue_interest_works_after_redeem_all` unit test to fail with + // left: `1000000000003607`, + // right: `1000000000003608`' + + // Chaining `calc_underlying_amount` and `calc_collateral_amount` continuously decreases + // an amount because of rounding down, and having the current function call `do_redeem` + // would perform three conversions: ptoken -> token -> ptoken -> token. + // Calling `do_redeem_voucher` directly only performs one conversion: ptoken -> token, + // avoiding this edge case. + // TODO: investigate whether it is possible to implement the conversion functions + // with guarantees that this always holds: + // `calc_underlying_amount(calc_collateral_amount(x)) = calc_collateral_amount(calc_underlying_amount(x))` + // Use the `converting_to_and_from_collateral_should_not_change_results` unit test to achieve this. + // If there are leftover ptokens after a `redeem_all` (because of rounding down), it would make it + // impossible to enforce "collateral toggle" state transitions. Self::ensure_active_market(asset_id)?; Self::accrue_interest(asset_id)?; let exchange_rate = Self::exchange_rate_stored(asset_id)?; Self::update_earned_stored(&who, asset_id, exchange_rate)?; - let redeem_amount = Self::do_redeem_voucher(&who, asset_id, Self::free_ptoken_balance(asset_id, &who)?)?; + let ptokens = Self::free_ptokens(asset_id, &who)?; + ensure!(!ptokens.is_zero(), Error::::InvalidAmount); + let redeem_amount = Self::do_redeem_voucher(&who, asset_id, ptokens.amount())?; Self::deposit_event(Event::::Redeemed(who, asset_id, redeem_amount)); Ok(().into()) @@ -881,6 +901,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; + ensure!(!borrow_amount.is_zero(), Error::::InvalidAmount); Self::do_borrow(&who, asset_id, borrow_amount)?; Ok(().into()) @@ -899,6 +920,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; + ensure!(!repay_amount.is_zero(), Error::::InvalidAmount); Self::do_repay_borrow(&who, asset_id, repay_amount)?; Ok(().into()) @@ -914,6 +936,7 @@ pub mod pallet { Self::ensure_active_market(asset_id)?; Self::accrue_interest(asset_id)?; let account_borrows = Self::current_borrow_balance(&who, asset_id)?; + ensure!(!account_borrows.is_zero(), Error::::InvalidAmount); Self::do_repay_borrow(&who, asset_id, account_borrows)?; Ok(().into()) @@ -923,10 +946,9 @@ pub mod pallet { #[transactional] pub fn deposit_all_collateral(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - - let ptoken_id = Self::ptoken_id(asset_id)?; - let ptokens = Self::free_ptoken_balance(asset_id, &who)?; - Self::do_deposit_collateral(&who, ptoken_id, ptokens)?; + let ptokens = Self::free_ptokens(asset_id, &who)?; + ensure!(!ptokens.is_zero(), Error::::InvalidAmount); + Self::do_deposit_collateral(&who, ptokens.currency(), ptokens.amount())?; Ok(().into()) } @@ -938,6 +960,7 @@ pub mod pallet { #[pallet::compact] amount: BalanceOf, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; + ensure!(!amount.is_zero(), Error::::InvalidAmount); Self::do_deposit_collateral(&who, asset_id, amount)?; Ok(().into()) } @@ -949,6 +972,7 @@ pub mod pallet { let ptoken_id = Self::ptoken_id(asset_id)?; let collateral = Self::account_deposits(ptoken_id, who.clone()); + ensure!(!collateral.is_zero(), Error::::InvalidAmount); Self::do_withdraw_collateral(&who, ptoken_id, collateral)?; Ok(().into()) } @@ -961,6 +985,7 @@ pub mod pallet { #[pallet::compact] amount: BalanceOf, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; + ensure!(!amount.is_zero(), Error::::InvalidAmount); Self::do_withdraw_collateral(&who, asset_id, amount)?; Ok(().into()) } @@ -983,6 +1008,7 @@ pub mod pallet { let who = ensure_signed(origin)?; Self::accrue_interest(liquidation_asset_id)?; Self::accrue_interest(collateral_asset_id)?; + ensure!(!repay_amount.is_zero(), Error::::InvalidAmount); Self::do_liquidate_borrow(who, borrower, liquidation_asset_id, repay_amount, collateral_asset_id)?; Ok(().into()) } @@ -1006,6 +1032,7 @@ pub mod pallet { let payer = T::Lookup::lookup(payer)?; Self::ensure_active_market(asset_id)?; + ensure!(!add_amount.is_zero(), Error::::InvalidAmount); let amount_to_transfer: Amount = Amount::new(add_amount, asset_id); amount_to_transfer.transfer(&payer, &Self::account_id())?; let total_reserves = Self::total_reserves(asset_id); @@ -1042,6 +1069,7 @@ pub mod pallet { T::ReserveOrigin::ensure_origin(origin)?; let receiver = T::Lookup::lookup(receiver)?; Self::ensure_active_market(asset_id)?; + ensure!(!reduce_amount.is_zero(), Error::::InvalidAmount); let total_reserves = Self::total_reserves(asset_id); if reduce_amount > total_reserves { @@ -1317,8 +1345,8 @@ impl Pallet { let redeem_amount = Self::calc_underlying_amount(voucher_amount, exchange_rate)?; Self::ensure_enough_cash(asset_id, redeem_amount)?; - // Ensure that withdrawing depoisted collateral doesn't leave the user undercollateralized. - let collateral_amount = voucher_amount.saturating_sub(Self::free_ptoken_balance(asset_id, redeemer)?); + // Ensure that withdrawing deposited collateral doesn't leave the user undercollateralized. + let collateral_amount = voucher_amount.saturating_sub(Self::free_ptokens(asset_id, redeemer)?.amount()); let collateral_underlying_amount = Self::calc_underlying_amount(collateral_amount, exchange_rate)?; let market = Self::market(asset_id)?; let effects_amount = market.collateral_factor.mul_ceil(collateral_underlying_amount); @@ -1764,12 +1792,10 @@ impl Pallet { } /// Free lending tokens (ptokens) of an account, given the underlying - pub fn free_ptoken_balance( - asset_id: AssetIdOf, - account_id: &T::AccountId, - ) -> Result, DispatchError> { + pub fn free_ptokens(asset_id: AssetIdOf, account_id: &T::AccountId) -> Result, DispatchError> { let ptoken_id = Self::ptoken_id(asset_id)?; - Ok(orml_tokens::Pallet::::free_balance(ptoken_id, account_id)) + let amount = Amount::new(orml_tokens::Pallet::::free_balance(ptoken_id, account_id), ptoken_id); + Ok(amount) } // Returns the uniform format price. @@ -2016,7 +2042,12 @@ impl LoansTrait, AccountIdOf, BalanceOf, Amount } fn get_underlying_amount(ptokens: &Amount) -> Result, DispatchError> { + // This function could be called externally to this pallet, with interest + // possibly not having accrued for a few blocks. This would result in using an + // outdated exchange rate. Call `accrue_interest` to avoid this. let underlying_id = Self::underlying_id(ptokens.currency())?; + Self::ensure_active_market(underlying_id)?; + Self::accrue_interest(underlying_id)?; let exchange_rate = Self::exchange_rate_stored(underlying_id)?; let underlying_amount = Self::calc_underlying_amount(ptokens.amount(), exchange_rate)?; Ok(Amount::new(underlying_amount, underlying_id)) @@ -2030,6 +2061,11 @@ impl LoansTrait, AccountIdOf, BalanceOf, Amount } fn get_collateral_amount(underlying: &Amount) -> Result, DispatchError> { + // This function could be called externally to this pallet, with interest + // possibly not having accrued for a few blocks. This would result in using an + // outdated exchange rate. Call `accrue_interest` to avoid this. + Self::ensure_active_market(underlying.currency())?; + Self::accrue_interest(underlying.currency())?; let exchange_rate = Self::exchange_rate_stored(underlying.currency())?; let underlying_amount = Self::calc_collateral_amount(underlying.amount(), exchange_rate)?; let ptoken_id = Self::ptoken_id(underlying.currency())?; diff --git a/crates/loans/src/tests.rs b/crates/loans/src/tests.rs index d2ca112de3..42202df8de 100644 --- a/crates/loans/src/tests.rs +++ b/crates/loans/src/tests.rs @@ -21,6 +21,7 @@ mod liquidate_borrow; mod market; mod ptokens; +use currency::Amount; use frame_support::{assert_noop, assert_ok}; use sp_runtime::{ @@ -115,7 +116,7 @@ fn mint_works() { // DOT collateral: deposit = 100 // DOT: cash - deposit = 1000 - 100 = 900 assert_eq!( - Loans::exchange_rate(DOT).saturating_mul_int(Loans::free_ptoken_balance(DOT, &ALICE).unwrap()), + Loans::exchange_rate(DOT).saturating_mul_int(Loans::free_ptokens(DOT, &ALICE).unwrap().amount()), unit(100) ); assert_eq!(Tokens::balance(DOT, &ALICE), unit(900),); @@ -1085,7 +1086,11 @@ fn reward_calculation_multi_player_in_one_market_works() { assert_ok!(Loans::withdraw_all_collateral(Origin::signed(BOB), DOT)); assert_ok!(Loans::redeem_all(Origin::signed(BOB), DOT)); assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), DOT)); - assert_ok!(Loans::repay_borrow_all(Origin::signed(BOB), DOT)); + // No loans to repay + assert_noop!( + Loans::repay_borrow_all(Origin::signed(BOB), DOT), + Error::::InvalidAmount + ); // Alice supply:10 supply reward: 23 // Alice borrow:0 borrow reward: 15 // BOB supply:0 supply reward: 17 @@ -1095,9 +1100,24 @@ fn reward_calculation_multi_player_in_one_market_works() { _run_to_block(60); assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(10))); - assert_ok!(Loans::redeem_all(Origin::signed(BOB), DOT)); - assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), DOT)); - assert_ok!(Loans::repay_borrow_all(Origin::signed(BOB), DOT)); + // There is no locked collateral left, so withdrawing will fail + assert_noop!( + Loans::withdraw_all_collateral(Origin::signed(BOB), DOT), + Error::::InvalidAmount + ); + // There is also no free collateral left, so redeeming will fail + assert_noop!( + Loans::redeem_all(Origin::signed(BOB), DOT), + Error::::InvalidAmount + ); + assert_noop!( + Loans::repay_borrow_all(Origin::signed(ALICE), DOT), + Error::::InvalidAmount + ); + assert_noop!( + Loans::repay_borrow_all(Origin::signed(BOB), DOT), + Error::::InvalidAmount + ); // Alice supply:10 supply reward: 33 // Alice borrow:0 borrow reward: 15 // BOB supply:0 supply reward: 17 @@ -1209,3 +1229,31 @@ fn reward_calculation_after_liquidate_borrow_works() { ); }) } + +#[test] +fn accrue_interest_works_after_get_collateral_amount() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::mint(Origin::signed(BOB), KSM, unit(200))); + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), DOT)); + assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(50))); + assert_eq!(Loans::borrow_index(KSM), Rate::one()); + TimestampPallet::set_timestamp(12000); + assert_ok!(Loans::get_collateral_amount(&Amount::::new(1234, KSM))); + assert_eq!(Loans::borrow_index(KSM), Rate::from_inner(1000000008561643835),); + }) +} + +#[test] +fn accrue_interest_works_after_get_underlying_amount() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::mint(Origin::signed(BOB), KSM, unit(200))); + assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), DOT)); + assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(50))); + assert_eq!(Loans::borrow_index(KSM), Rate::one()); + TimestampPallet::set_timestamp(12000); + assert_ok!(Loans::get_underlying_amount(&Loans::free_ptokens(KSM, &ALICE).unwrap())); + assert_eq!(Loans::borrow_index(KSM), Rate::from_inner(1000000008561643835),); + }) +} diff --git a/crates/loans/src/tests/edge_cases.rs b/crates/loans/src/tests/edge_cases.rs index 153861105a..36015b4baa 100644 --- a/crates/loans/src/tests/edge_cases.rs +++ b/crates/loans/src/tests/edge_cases.rs @@ -1,5 +1,6 @@ use super::*; use crate::{mock::*, tests::Loans, Error}; +use currency::Amount; use frame_support::{assert_err, assert_ok}; use primitives::{ CurrencyId::{ForeignAsset, Token}, @@ -83,10 +84,35 @@ fn redeem_all_should_be_accurate() { assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), Token(KSM))); // It failed with InsufficientLiquidity before #839 + // Interlay modification: Need to withraw collateral first in order to redeem + assert_ok!(Loans::withdraw_all_collateral(Origin::signed(ALICE), Token(KSM))); assert_ok!(Loans::redeem_all(Origin::signed(ALICE), Token(KSM))); }) } +// FIXME: this test fails because of rounding +#[ignore] +#[test] +fn converting_to_and_from_collateral_should_not_change_results() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::mint(Origin::signed(ALICE), Token(KSM), unit(201))); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), Token(KSM))); + assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(KSM), unit(50))); + + // let exchange_rate greater than 0.02 + accrue_interest_per_block(Token(KSM), 1, 131); + assert_eq!(Loans::exchange_rate(Token(KSM)), Rate::from_inner(20000000782289552)); + + let base_ksm_amount = 100007444213; + for offset in 0..=1000 { + let ksm_amount = Amount::new(base_ksm_amount + offset, Token(KSM)); + let conv_pksm_amount = Loans::get_collateral_amount(&ksm_amount).unwrap(); + let conv_ksm_amount = Loans::get_underlying_amount(&conv_pksm_amount).unwrap(); + assert_eq!(conv_ksm_amount.amount(), ksm_amount.amount()); + } + }) +} + #[test] fn prevent_the_exchange_rate_attack() { new_test_ext().execute_with(|| { @@ -116,7 +142,7 @@ fn prevent_the_exchange_rate_attack() { ); TimestampPallet::set_timestamp(12000); // Eve can not let the exchange rate greater than 1 - assert!(Loans::accrue_interest(Token(DOT)).is_err()); + assert_noop!(Loans::accrue_interest(Token(DOT)), Error::::InvalidExchangeRate); // Mock a BIG exchange_rate: 100000000000.02 ExchangeRate::::insert(Token(DOT), Rate::saturating_from_rational(100000000000020u128, 20 * 50)); diff --git a/crates/loans/src/tests/interest_rate.rs b/crates/loans/src/tests/interest_rate.rs index 6f5e75cfef..c68719bdb2 100644 --- a/crates/loans/src/tests/interest_rate.rs +++ b/crates/loans/src/tests/interest_rate.rs @@ -1,4 +1,5 @@ use crate::{mock::*, tests::Loans, Markets}; +use currency::Amount; use frame_support::assert_ok; use primitives::{CurrencyId::Token, Rate, Ratio, DOT, KSM, SECONDS_PER_YEAR}; use sp_runtime::{ @@ -186,6 +187,7 @@ fn accrue_interest_works_after_redeem_all() { assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), Token(DOT))); assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(DOT), unit(10))); assert_eq!(Loans::borrow_index(Token(DOT)), Rate::one()); + assert_eq!(Tokens::balance(Token(DOT), &BOB), 980000000000000); TimestampPallet::set_timestamp(12000); assert_ok!(Loans::redeem_all(Origin::signed(BOB), Token(DOT))); assert_eq!(Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000004669977168),); diff --git a/crates/loans/src/tests/liquidate_borrow.rs b/crates/loans/src/tests/liquidate_borrow.rs index d04fe4301b..464c00a6fb 100644 --- a/crates/loans/src/tests/liquidate_borrow.rs +++ b/crates/loans/src/tests/liquidate_borrow.rs @@ -177,7 +177,7 @@ fn liquidator_must_not_be_borrower() { new_test_ext().execute_with(|| { initial_setup(); assert_noop!( - Loans::liquidate_borrow(Origin::signed(ALICE), ALICE, KSM, 0, DOT), + Loans::liquidate_borrow(Origin::signed(ALICE), ALICE, KSM, 1, DOT), Error::::LiquidatorIsBorrower ); }) diff --git a/standalone/runtime/tests/mock/mod.rs b/standalone/runtime/tests/mock/mod.rs index fe83802363..8c970f4b19 100644 --- a/standalone/runtime/tests/mock/mod.rs +++ b/standalone/runtime/tests/mock/mod.rs @@ -356,7 +356,7 @@ impl Wrapped for VaultId { } } -pub fn iter_currency_pairs_with_ptokens() -> impl Iterator> { +pub fn iter_currency_pairs() -> impl Iterator> { iter_collateral_currencies().flat_map(|collateral_id| { iter_wrapped_currencies().map(move |wrapped_id| VaultCurrencyPair { collateral: collateral_id, @@ -799,7 +799,7 @@ pub struct LiquidationVaultData { impl LiquidationVaultData { pub fn get() -> Self { - let liquidation_vaults = iter_currency_pairs_with_ptokens() + let liquidation_vaults = iter_currency_pairs() .map(|currency_pair| { let vault = VaultRegistryPallet::get_liquidation_vault(¤cy_pair); let data = SingleLiquidationVault { @@ -824,7 +824,7 @@ impl LiquidationVaultData { let mut ret = Self { liquidation_vaults: BTreeMap::new(), }; - for pair in iter_currency_pairs_with_ptokens() { + for pair in iter_currency_pairs() { if &pair == currency_pair { ret.liquidation_vaults .insert(pair.clone(), SingleLiquidationVault::zero(&pair)); @@ -1419,16 +1419,14 @@ impl ExtBuilder { (PToken(1), 0), ], punishment_delay: 8, - system_collateral_ceiling: iter_currency_pairs_with_ptokens() - .map(|pair| (pair, FUND_LIMIT_CEILING)) - .collect(), - secure_collateral_threshold: iter_currency_pairs_with_ptokens() + system_collateral_ceiling: iter_currency_pairs().map(|pair| (pair, FUND_LIMIT_CEILING)).collect(), + secure_collateral_threshold: iter_currency_pairs() .map(|pair| (pair, FixedU128::checked_from_rational(150, 100).unwrap())) .collect(), - premium_redeem_threshold: iter_currency_pairs_with_ptokens() + premium_redeem_threshold: iter_currency_pairs() .map(|pair| (pair, FixedU128::checked_from_rational(150, 100).unwrap())) .collect(), - liquidation_collateral_threshold: iter_currency_pairs_with_ptokens() + liquidation_collateral_threshold: iter_currency_pairs() .map(|pair| (pair, FixedU128::checked_from_rational(110, 100).unwrap())) .collect(), } diff --git a/standalone/runtime/tests/test_loans.rs b/standalone/runtime/tests/test_loans.rs index 97f8f19631..125d24a510 100644 --- a/standalone/runtime/tests/test_loans.rs +++ b/standalone/runtime/tests/test_loans.rs @@ -1,7 +1,9 @@ +use currency::Amount; use interbtc_runtime_standalone::{CurrencyId::Token, KINT}; mod mock; use mock::{assert_eq, *}; use pallet_loans::{InterestRateModel, JumpModel, Market, MarketState}; +use pallet_traits::LoansApi; use primitives::{Rate, Ratio}; use sp_runtime::traits::CheckedMul; @@ -58,6 +60,7 @@ fn test_real_market(execute: impl Fn() -> R) { FixedU128::from_inner(4_573_498_406_135_805_461_670_000), CKSM, ); + set_up_market(Token(DOT), FixedU128::from_inner(324_433_053_239_464_036_596_000), CDOT); execute() }); } @@ -126,3 +129,94 @@ fn integration_test_liquidation() { .dispatch(origin_of(account_of(LP)))); }); } + +#[test] +fn integration_test_ptoken_vault_insufficient_balance() { + test_real_market(|| { + let dot = Token(DOT); + let vault_account_id = account_of(USER); + + assert_ok!(Call::Loans(LoansCall::mint { + asset_id: dot, + mint_amount: 1000, + }) + .dispatch(origin_of(account_of(USER)))); + + let ptokens = LoansPallet::free_ptokens(dot, &vault_account_id).unwrap(); + + // Depositing all the collateral should leave none free for registering as a vault + assert_ok!(Call::Loans(LoansCall::deposit_all_collateral { asset_id: dot }) + .dispatch(origin_of(vault_account_id.clone()))); + + let ptoken_vault_id = PrimitiveVaultId::new(vault_account_id.clone(), ptokens.currency(), Token(IBTC)); + assert_err!( + get_register_vault_result(&ptoken_vault_id, ptokens), + TokensError::BalanceTooLow + ); + + // Withdraw the ptokens to use them for another purpose + assert_ok!(Call::Loans(LoansCall::withdraw_all_collateral { asset_id: dot }) + .dispatch(origin_of(vault_account_id.clone()))); + + // This time, registering a vault works because the ptokens are unlocked + assert_ok!(get_register_vault_result(&ptoken_vault_id, ptokens)); + }); +} + +#[test] +fn integration_test_ptoken_deposit_insufficient_balance() { + test_real_market(|| { + let dot = Token(DOT); + let vault_account_id = account_of(USER); + + assert_ok!(Call::Loans(LoansCall::mint { + asset_id: dot, + mint_amount: 1000, + }) + .dispatch(origin_of(account_of(USER)))); + + let ptokens = LoansPallet::free_ptokens(dot, &vault_account_id).unwrap(); + + // Register a vault with all the available ptokens + let ptoken_vault_id = PrimitiveVaultId::new(vault_account_id.clone(), ptokens.currency(), Token(IBTC)); + assert_ok!(get_register_vault_result(&ptoken_vault_id, ptokens),); + + assert_err!( + LoansPallet::do_deposit_collateral(&vault_account_id, ptokens.currency(), ptokens.amount()), + TokensError::BalanceTooLow + ); + }); +} + +#[test] +fn integration_test_ptoken_transfer_reserved_fails() { + test_real_market(|| { + let dot = Token(DOT); + let vault_account_id = account_of(USER); + + assert_ok!(Call::Loans(LoansCall::mint { + asset_id: dot, + mint_amount: 1000, + }) + .dispatch(origin_of(vault_account_id.clone()))); + + let ptokens = LoansPallet::free_ptokens(dot, &vault_account_id).unwrap(); + + // Lock some ptokens into the lending market + assert_ok!(LoansPallet::do_deposit_collateral( + &vault_account_id, + ptokens.currency(), + ptokens.amount() / 2 + )); + + let half_ptokens = ptokens.checked_div(&FixedU128::from_u32(2)).unwrap(); + assert_eq!(half_ptokens, LoansPallet::free_ptokens(dot, &vault_account_id).unwrap()); + + // Transferring the full amount fails + assert_noop!( + ptokens.transfer(&vault_account_id, &account_of(LP)), + TokensError::BalanceTooLow + ); + assert_ok!(half_ptokens.transfer(&vault_account_id, &account_of(LP))); + }); +} From 2395d352e8e960bb04d3ec2f3efb55eee3caf5d7 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Tue, 25 Oct 2022 11:02:58 +0200 Subject: [PATCH 40/58] chore(loans): move tests to interest rate file --- crates/loans/src/tests.rs | 28 ----------------------- crates/loans/src/tests/interest_rate.rs | 30 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/crates/loans/src/tests.rs b/crates/loans/src/tests.rs index 42202df8de..8d7716cd67 100644 --- a/crates/loans/src/tests.rs +++ b/crates/loans/src/tests.rs @@ -1229,31 +1229,3 @@ fn reward_calculation_after_liquidate_borrow_works() { ); }) } - -#[test] -fn accrue_interest_works_after_get_collateral_amount() { - new_test_ext().execute_with(|| { - assert_ok!(Loans::mint(Origin::signed(BOB), KSM, unit(200))); - assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); - assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), DOT)); - assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(50))); - assert_eq!(Loans::borrow_index(KSM), Rate::one()); - TimestampPallet::set_timestamp(12000); - assert_ok!(Loans::get_collateral_amount(&Amount::::new(1234, KSM))); - assert_eq!(Loans::borrow_index(KSM), Rate::from_inner(1000000008561643835),); - }) -} - -#[test] -fn accrue_interest_works_after_get_underlying_amount() { - new_test_ext().execute_with(|| { - assert_ok!(Loans::mint(Origin::signed(BOB), KSM, unit(200))); - assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(200))); - assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), DOT)); - assert_ok!(Loans::borrow(Origin::signed(ALICE), KSM, unit(50))); - assert_eq!(Loans::borrow_index(KSM), Rate::one()); - TimestampPallet::set_timestamp(12000); - assert_ok!(Loans::get_underlying_amount(&Loans::free_ptokens(KSM, &ALICE).unwrap())); - assert_eq!(Loans::borrow_index(KSM), Rate::from_inner(1000000008561643835),); - }) -} diff --git a/crates/loans/src/tests/interest_rate.rs b/crates/loans/src/tests/interest_rate.rs index c68719bdb2..b585223b8e 100644 --- a/crates/loans/src/tests/interest_rate.rs +++ b/crates/loans/src/tests/interest_rate.rs @@ -261,6 +261,36 @@ fn accrue_interest_works_after_liquidate_borrow() { }) } +#[test] +fn accrue_interest_works_after_get_collateral_amount() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::mint(Origin::signed(BOB), Token(KSM), unit(200))); + assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), Token(DOT))); + assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(KSM), unit(50))); + assert_eq!(Loans::borrow_index(Token(KSM)), Rate::one()); + TimestampPallet::set_timestamp(12000); + assert_ok!(Loans::get_collateral_amount(&Amount::::new(1234, Token(KSM)))); + assert_eq!(Loans::borrow_index(Token(KSM)), Rate::from_inner(1000000008561643835),); + }) +} + +#[test] +fn accrue_interest_works_after_get_underlying_amount() { + new_test_ext().execute_with(|| { + assert_ok!(Loans::mint(Origin::signed(BOB), Token(KSM), unit(200))); + assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), Token(DOT))); + assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(KSM), unit(50))); + assert_eq!(Loans::borrow_index(Token(KSM)), Rate::one()); + TimestampPallet::set_timestamp(12000); + assert_ok!(Loans::get_underlying_amount( + &Loans::free_ptokens(Token(KSM), &ALICE).unwrap() + )); + assert_eq!(Loans::borrow_index(Token(KSM)), Rate::from_inner(1000000008561643835),); + }) +} + #[test] fn different_markets_can_accrue_interest_in_one_block() { new_test_ext().execute_with(|| { From 716f51daa985f090bc735834066df57eebbf9551 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Tue, 25 Oct 2022 18:33:51 +0200 Subject: [PATCH 41/58] test(loans): orml ptoken tests --- crates/loans/src/tests/interest_rate.rs | 5 +- crates/loans/src/tests/liquidate_borrow.rs | 4 +- crates/loans/src/tests/ptokens.rs | 53 ++++++++++++- crates/loans/src/types.rs | 2 + standalone/runtime/tests/test_loans.rs | 92 ++++++++++++++++++---- 5 files changed, 134 insertions(+), 22 deletions(-) diff --git a/crates/loans/src/tests/interest_rate.rs b/crates/loans/src/tests/interest_rate.rs index b585223b8e..ed44e0b468 100644 --- a/crates/loans/src/tests/interest_rate.rs +++ b/crates/loans/src/tests/interest_rate.rs @@ -56,8 +56,8 @@ fn interest_rate_model_works() { let delta_time = 6u128; TimestampPallet::set_timestamp(6000 * (i + 1)); assert_ok!(Loans::accrue_interest(Token(DOT))); - // utilizationRatio = totalBorrows / (totalCash + totalBorrows) - let util_ratio = Ratio::from_rational(total_borrows, total_cash + total_borrows); + // utilizationRatio = totalBorrows / (totalCash + totalBorrows - totalReserves) + let util_ratio = Ratio::from_rational(total_borrows, total_cash + total_borrows - total_reserves); assert_eq!(Loans::utilization_ratio(Token(DOT)), util_ratio); let borrow_rate = (jump_rate - base_rate) * util_ratio.into() / jump_utilization.into() + base_rate; @@ -96,6 +96,7 @@ fn interest_rate_model_works() { // Calculate borrow accrued interest let borrow_principal = (borrow_index / borrow_snapshot.borrow_index).saturating_mul_int(borrow_snapshot.principal); + // TODO: Why subtract `million_unit(200)` here? Accruing interest doesn't fix this. let supply_interest = Loans::exchange_rate(Token(DOT)).saturating_mul_int(total_supply) - million_unit(200); assert_eq!(supply_interest, 54337916540000); assert_eq!(borrow_principal, 100000063926960644400); diff --git a/crates/loans/src/tests/liquidate_borrow.rs b/crates/loans/src/tests/liquidate_borrow.rs index 464c00a6fb..5850a8ec3e 100644 --- a/crates/loans/src/tests/liquidate_borrow.rs +++ b/crates/loans/src/tests/liquidate_borrow.rs @@ -4,6 +4,7 @@ use crate::{ Error, MarketState, }; use frame_support::{assert_noop, assert_ok, traits::fungibles::Inspect}; +use pallet_traits::LoansApi; use primitives::{ CurrencyId::{self, Token}, Rate, DOT as DOT_CURRENCY, KBTC as KBTC_CURRENCY, KSM as KSM_CURRENCY, @@ -30,8 +31,7 @@ fn liquidate_borrow_allowed_works() { let ksm_market = Loans::market(KSM).unwrap(); // Here the balance sheet of Alice is: // Collateral Loans - // CDOT $200 KSM $400 - // USDT $200 + // USDT $110 KSM $200 assert_noop!( Loans::liquidate_borrow_allowed(&ALICE, KSM, unit(51), &ksm_market), Error::::TooMuchRepay diff --git a/crates/loans/src/tests/ptokens.rs b/crates/loans/src/tests/ptokens.rs index 907bc64eac..fc56e784df 100644 --- a/crates/loans/src/tests/ptokens.rs +++ b/crates/loans/src/tests/ptokens.rs @@ -1,13 +1,15 @@ use crate::{ - mock::{market_mock, new_test_ext, Loans, Origin, Test, Tokens, ALICE, CKBTC, CKINT, CKSM, DAVE}, + mock::{market_mock, new_test_ext, AccountId, Loans, Origin, Test, Tokens, ALICE, CKBTC, CKINT, CKSM, DAVE}, tests::unit, - Error, + Config, Error, }; use frame_support::{ assert_err, assert_noop, assert_ok, traits::tokens::fungibles::{Inspect, Transfer}, }; +use orml_traits::{MultiCurrency, MultiReservableCurrency}; use primitives::{ + Balance, CurrencyId::{self, ForeignAsset, PToken, Token}, KBTC, KINT, KSM as KSM_CURRENCY, }; @@ -20,6 +22,17 @@ const PKSM: CurrencyId = CKSM; const PUSDT: CurrencyId = CKBTC; const USDT: CurrencyId = Token(KBTC); +fn free_balance(currency_id: CurrencyId, account_id: &AccountId) -> Balance { + ::AccountId>>::free_balance(currency_id, account_id) +} + +fn reserved_balance(currency_id: CurrencyId, account_id: &AccountId) -> Balance { + ::AccountId>>::reserved_balance( + currency_id, + account_id, + ) +} + #[test] fn trait_inspect_methods_works() { new_test_ext().execute_with(|| { @@ -36,10 +49,20 @@ fn trait_inspect_methods_works() { // DAVE Deposit 100 HKO assert_ok!(Loans::mint(Origin::signed(DAVE), HKO, unit(100))); assert_eq!(Tokens::balance(PHKO, &DAVE), unit(100) * 50); + assert_eq!(Tokens::total_issuance(PHKO), unit(100) * 50); + // Check entries from orml-tokens directly + assert_eq!(free_balance(PHKO, &DAVE), unit(100) * 50); + assert_eq!(reserved_balance(PHKO, &DAVE), 0); // No collateral deposited yet, therefore no reducible balance assert_eq!(Loans::reducible_balance(PHKO, &DAVE, true), 0); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(DAVE), HKO)); + assert_eq!(Loans::reducible_balance(PHKO, &DAVE, true), unit(100) * 50); + // Check entries from orml-tokens directly + assert_eq!(free_balance(PHKO, &DAVE), 0); + assert_eq!(reserved_balance(PHKO, &DAVE), unit(100) * 50); + // Borrow 25 HKO will reduce 25 HKO liquidity for collateral_factor is 50% assert_ok!(Loans::borrow(Origin::signed(DAVE), HKO, unit(25))); @@ -59,16 +82,24 @@ fn trait_inspect_methods_works() { // ptokens = dollar(25 + 25) / 1 / 0.5 / 0.02 = dollar(50) * 100 assert_ok!(Loans::mint(Origin::signed(DAVE), USDT, unit(50))); assert_eq!(Tokens::balance(PUSDT, &DAVE), unit(50) * 50); + // Check entries from orml-tokens directly + assert_eq!(free_balance(PUSDT, &DAVE), unit(50) * 50); + assert_eq!(reserved_balance(PUSDT, &DAVE), 0); - // `reducible_balance()` check how much collateral can be withdrawn from the amount deposited. + // `reducible_balance()` checks how much collateral can be withdrawn from the amount deposited. // Since no collateral has been deposited yet, this value is zero. assert_eq!(Loans::reducible_balance(PUSDT, &DAVE, true), 0); // enable USDT collateral assert_ok!(Loans::deposit_all_collateral(Origin::signed(DAVE), USDT)); assert_eq!(Loans::reducible_balance(PHKO, &DAVE, true), unit(25 + 25) * 2 * 50); + assert_eq!(Loans::reducible_balance(PUSDT, &DAVE, true), unit(50) * 50); + // Check entries from orml-tokens directly + assert_eq!(free_balance(PUSDT, &DAVE), 0); + assert_eq!(reserved_balance(PUSDT, &DAVE), unit(50) * 50); assert_ok!(Loans::borrow(Origin::signed(DAVE), HKO, unit(50))); assert_eq!(Loans::reducible_balance(PHKO, &DAVE, true), 0); + assert_eq!(Loans::reducible_balance(PUSDT, &DAVE, true), 0); assert_eq!(Loans::total_issuance(PHKO), unit(100) * 50); assert_ok!(Loans::can_deposit(PHKO, &DAVE, 100, true).into_result()); @@ -142,7 +173,14 @@ fn transfer_ptokens_under_collateral_does_not_work() { new_test_ext().execute_with(|| { // DAVE Deposit 100 HKO assert_ok!(Loans::mint(Origin::signed(DAVE), HKO, unit(100))); + // Check entries from orml-tokens directly + assert_eq!(free_balance(PHKO, &DAVE), unit(100) * 50); + assert_eq!(reserved_balance(PHKO, &DAVE), 0); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(DAVE), HKO)); + // Check entries from orml-tokens directly + assert_eq!(free_balance(PHKO, &DAVE), 0); + assert_eq!(reserved_balance(PHKO, &DAVE), unit(100) * 50); // Borrow 50 HKO will reduce 50 HKO liquidity for collateral_factor is 50% assert_ok!(Loans::borrow(Origin::signed(DAVE), HKO, unit(50))); @@ -156,10 +194,17 @@ fn transfer_ptokens_under_collateral_does_not_work() { Loans::transfer(PHKO, &DAVE, &ALICE, unit(20) * 50, true), Error::::InsufficientCollateral ); - // First, withdraw the tokens + // First, withdraw some tokens assert_ok!(Loans::withdraw_collateral(Origin::signed(DAVE), PHKO, unit(20) * 50)); + // Check entries from orml-tokens directly + assert_eq!(free_balance(PHKO, &DAVE), unit(20) * 50); + assert_eq!(reserved_balance(PHKO, &DAVE), unit(80) * 50); // Then transfer them assert_ok!(Loans::transfer(PHKO, &DAVE, &ALICE, unit(20) * 50, true),); + // Check entries from orml-tokens directly + assert_eq!(free_balance(PHKO, &DAVE), 0); + assert_eq!(reserved_balance(PHKO, &DAVE), unit(80) * 50); + assert_eq!(free_balance(PHKO, &ALICE), unit(20) * 50); // DAVE Deposit HKO = 100 - 20 = 80 // DAVE Borrow HKO = 0 + 50 - 40 = 10 diff --git a/crates/loans/src/types.rs b/crates/loans/src/types.rs index a820e9ee3c..5914d8e0f0 100644 --- a/crates/loans/src/types.rs +++ b/crates/loans/src/types.rs @@ -36,6 +36,8 @@ pub struct Deposits { pub enum MarketState { Active, Pending, + // Unclear why the `Supervision` state is required at all, since it's not used anywhere. + // Could just reuse the `Pending` state to temporarily halt a market. Supervision, } diff --git a/standalone/runtime/tests/test_loans.rs b/standalone/runtime/tests/test_loans.rs index 125d24a510..27ffaec3b2 100644 --- a/standalone/runtime/tests/test_loans.rs +++ b/standalone/runtime/tests/test_loans.rs @@ -1,7 +1,8 @@ use currency::Amount; -use interbtc_runtime_standalone::{CurrencyId::Token, KINT}; +use interbtc_runtime_standalone::{CurrencyId::Token, Tokens, KINT}; mod mock; use mock::{assert_eq, *}; +use orml_traits::{MultiCurrency, MultiReservableCurrency}; use pallet_loans::{InterestRateModel, JumpModel, Market, MarketState}; use pallet_traits::LoansApi; use primitives::{Rate, Ratio}; @@ -31,6 +32,17 @@ pub const fn market_mock(ptoken_id: CurrencyId) -> Market { } } +fn free_balance(currency_id: CurrencyId, account_id: &AccountId) -> Balance { + ::AccountId>>::free_balance(currency_id, account_id) +} + +fn reserved_balance(currency_id: CurrencyId, account_id: &AccountId) -> Balance { + ::AccountId>>::reserved_balance( + currency_id, + account_id, + ) +} + fn set_up_market(currency_id: CurrencyId, exchange_rate: FixedU128, ptoken_id: CurrencyId) { assert_ok!(OraclePallet::_set_exchange_rate(currency_id, exchange_rate)); assert_ok!(Call::Sudo(SudoCall::sudo { @@ -70,46 +82,60 @@ fn integration_test_liquidation() { test_real_market(|| { let kint = Token(KINT); let ksm = Token(KSM); + let user = account_of(USER); + let lp = account_of(LP); assert_ok!(Call::Loans(LoansCall::mint { asset_id: kint, mint_amount: 1000, }) - .dispatch(origin_of(account_of(USER)))); + .dispatch(origin_of(user.clone()))); + + // Check entries from orml-tokens directly + assert_eq!(free_balance(CKINT, &user), 1000); + assert_eq!(reserved_balance(CKINT, &user), 0); assert_ok!(Call::Loans(LoansCall::mint { asset_id: ksm, mint_amount: 50, }) - .dispatch(origin_of(account_of(LP)))); + .dispatch(origin_of(lp.clone()))); - assert_ok!( - Call::Loans(LoansCall::deposit_all_collateral { asset_id: kint }).dispatch(origin_of(account_of(USER))) - ); + // Check entries from orml-tokens directly + assert_eq!(free_balance(CKSM, &lp), 50); + assert_eq!(reserved_balance(CKSM, &lp), 0); + + assert_ok!(Call::Loans(LoansCall::deposit_all_collateral { asset_id: kint }).dispatch(origin_of(user.clone()))); + + // Check entries from orml-tokens directly + assert_eq!(free_balance(CKINT, &user), 0); + assert_eq!(reserved_balance(CKINT, &user), 1000); assert_err!( Call::Loans(LoansCall::borrow { asset_id: ksm, borrow_amount: 20, }) - .dispatch(origin_of(account_of(USER))), + .dispatch(origin_of(user.clone())), LoansError::InsufficientLiquidity ); + assert_eq!(free_balance(ksm, &user), 1000000000000); assert_ok!(Call::Loans(LoansCall::borrow { asset_id: ksm, borrow_amount: 15, }) - .dispatch(origin_of(account_of(USER)))); + .dispatch(origin_of(user.clone()))); + assert_eq!(free_balance(ksm, &user), 1000000000015); assert_err!( Call::Loans(LoansCall::liquidate_borrow { - borrower: account_of(USER), + borrower: user.clone(), liquidation_asset_id: ksm, repay_amount: 15, collateral_asset_id: kint }) - .dispatch(origin_of(account_of(LP))), + .dispatch(origin_of(lp.clone())), LoansError::InsufficientShortfall ); @@ -121,12 +147,32 @@ fn integration_test_liquidation() { )); assert_ok!(Call::Loans(LoansCall::liquidate_borrow { - borrower: account_of(USER), + borrower: user.clone(), liquidation_asset_id: ksm, repay_amount: 7, collateral_asset_id: kint }) - .dispatch(origin_of(account_of(LP)))); + .dispatch(origin_of(lp.clone()))); + + assert_eq!(free_balance(CKINT, &user), 0); + // borrower's reserved collateral is slashed + assert_eq!(reserved_balance(CKINT, &user), 610); + // borrower's borrowed balance is unchanged + assert_eq!(free_balance(ksm, &user), 1000000000015); + + // the liquidator receives most of the slashed collateral + assert_eq!(reserved_balance(CKINT, &lp), 0); + assert_eq!(free_balance(CKINT, &lp), 380); + + // the rest of the slashed collateral routed to the incentive reward account's free balance + assert_eq!( + free_balance(CKINT, &LoansPallet::incentive_reward_account_id().unwrap()), + 10 + ); + assert_eq!( + reserved_balance(CKINT, &LoansPallet::incentive_reward_account_id().unwrap()), + 0 + ); }); } @@ -142,11 +188,17 @@ fn integration_test_ptoken_vault_insufficient_balance() { }) .dispatch(origin_of(account_of(USER)))); + // Check entries from orml-tokens directly + assert_eq!(free_balance(CDOT, &vault_account_id), 1000); + assert_eq!(reserved_balance(CDOT, &vault_account_id), 0); + let ptokens = LoansPallet::free_ptokens(dot, &vault_account_id).unwrap(); // Depositing all the collateral should leave none free for registering as a vault assert_ok!(Call::Loans(LoansCall::deposit_all_collateral { asset_id: dot }) .dispatch(origin_of(vault_account_id.clone()))); + assert_eq!(free_balance(CDOT, &vault_account_id), 0); + assert_eq!(reserved_balance(CDOT, &vault_account_id), 1000); let ptoken_vault_id = PrimitiveVaultId::new(vault_account_id.clone(), ptokens.currency(), Token(IBTC)); assert_err!( @@ -157,9 +209,13 @@ fn integration_test_ptoken_vault_insufficient_balance() { // Withdraw the ptokens to use them for another purpose assert_ok!(Call::Loans(LoansCall::withdraw_all_collateral { asset_id: dot }) .dispatch(origin_of(vault_account_id.clone()))); + assert_eq!(free_balance(CDOT, &vault_account_id), 1000); + assert_eq!(reserved_balance(CDOT, &vault_account_id), 0); // This time, registering a vault works because the ptokens are unlocked assert_ok!(get_register_vault_result(&ptoken_vault_id, ptokens)); + assert_eq!(free_balance(CDOT, &vault_account_id), 0); + assert_eq!(reserved_balance(CDOT, &vault_account_id), 1000); }); } @@ -193,6 +249,7 @@ fn integration_test_ptoken_transfer_reserved_fails() { test_real_market(|| { let dot = Token(DOT); let vault_account_id = account_of(USER); + let lp_account_id = account_of(LP); assert_ok!(Call::Loans(LoansCall::mint { asset_id: dot, @@ -200,6 +257,8 @@ fn integration_test_ptoken_transfer_reserved_fails() { }) .dispatch(origin_of(vault_account_id.clone()))); + assert_eq!(free_balance(CDOT, &vault_account_id), 1000); + assert_eq!(reserved_balance(CDOT, &vault_account_id), 0); let ptokens = LoansPallet::free_ptokens(dot, &vault_account_id).unwrap(); // Lock some ptokens into the lending market @@ -208,15 +267,20 @@ fn integration_test_ptoken_transfer_reserved_fails() { ptokens.currency(), ptokens.amount() / 2 )); + assert_eq!(free_balance(CDOT, &vault_account_id), 500); + assert_eq!(reserved_balance(CDOT, &vault_account_id), 500); let half_ptokens = ptokens.checked_div(&FixedU128::from_u32(2)).unwrap(); assert_eq!(half_ptokens, LoansPallet::free_ptokens(dot, &vault_account_id).unwrap()); // Transferring the full amount fails assert_noop!( - ptokens.transfer(&vault_account_id, &account_of(LP)), + ptokens.transfer(&vault_account_id, &lp_account_id), TokensError::BalanceTooLow ); - assert_ok!(half_ptokens.transfer(&vault_account_id, &account_of(LP))); + assert_ok!(half_ptokens.transfer(&vault_account_id, &lp_account_id)); + assert_eq!(free_balance(CDOT, &vault_account_id), 0); + assert_eq!(reserved_balance(CDOT, &vault_account_id), 500); + assert_eq!(free_balance(CDOT, &lp_account_id), 500); }); } From e13c0fa83143e6d09fecd9a8ad954147d95bc13f Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Thu, 27 Oct 2022 11:49:44 +0200 Subject: [PATCH 42/58] chore(loans): rename to `compute_collateral_amount`, add market cap, exchange rate, ptoken tests --- crates/currency/src/lib.rs | 8 +- crates/loans/src/lib.rs | 8 +- crates/loans/src/tests.rs | 174 ++++++++++++++++++------ crates/loans/src/tests/edge_cases.rs | 4 +- crates/loans/src/tests/interest_rate.rs | 11 +- crates/loans/src/tests/ptokens.rs | 4 +- crates/loans/src/types.rs | 9 -- crates/traits/src/loans.rs | 4 +- standalone/runtime/tests/test_loans.rs | 16 +++ 9 files changed, 168 insertions(+), 70 deletions(-) diff --git a/crates/currency/src/lib.rs b/crates/currency/src/lib.rs index 461e62ed4e..0b8a1a99ab 100644 --- a/crates/currency/src/lib.rs +++ b/crates/currency/src/lib.rs @@ -45,17 +45,17 @@ where fn convert(amount: &Amount, to: CurrencyId) -> Result, DispatchError> { if amount.currency().is_ptoken() && to.is_ptoken() { let to_underlying_id = Loans::underlying_id(to)?; - let from_underlying_amount = Loans::get_underlying_amount(amount)?; + let from_underlying_amount = Loans::recompute_underlying_amount(amount)?; let to_underlying_amount = Oracle::convert(&from_underlying_amount, to_underlying_id)?; - Loans::get_collateral_amount(&to_underlying_amount) + Loans::recompute_collateral_amount(&to_underlying_amount) } else if amount.currency().is_ptoken() { - Oracle::convert(&Loans::get_underlying_amount(amount)?, to) + Oracle::convert(&Loans::recompute_underlying_amount(amount)?, to) } else if to.is_ptoken() { let underlying_id = Loans::underlying_id(to)?; // get the converted value expressed in the underlying asset let underlying_amount = Oracle::convert(amount, underlying_id)?; // get the equivalent ptoken amount using the internal exchange rate - Loans::get_collateral_amount(&underlying_amount) + Loans::recompute_collateral_amount(&underlying_amount) } else { Oracle::convert(amount, to) } diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 283da502fa..77f7926431 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -57,7 +57,7 @@ use sp_std::{marker, result::Result}; pub use orml_traits::currency::{OnDeposit, OnSlash, OnTransfer}; use sp_io::hashing::blake2_256; -pub use types::{BorrowSnapshot, Deposits, EarnedSnapshot, Market, MarketState, RewardMarketState}; +pub use types::{BorrowSnapshot, EarnedSnapshot, Market, MarketState, RewardMarketState}; pub use weights::WeightInfo; mod benchmarking; @@ -860,7 +860,7 @@ pub mod pallet { let who = ensure_signed(origin)?; // This function is an almost 1:1 duplicate of the logic in `do_redeem`. // It could be refactored to compute the redeemable underlying - // with `Self::get_underlying_amount(&Self::free_ptokens(asset_id, &who)?)?` + // with `Self::recompute_underlying_amount(&Self::free_ptokens(asset_id, &who)?)?` // but that would cause the `accrue_interest_works_after_redeem_all` unit test to fail with // left: `1000000000003607`, // right: `1000000000003608`' @@ -2041,7 +2041,7 @@ impl LoansTrait, AccountIdOf, BalanceOf, Amount Ok(()) } - fn get_underlying_amount(ptokens: &Amount) -> Result, DispatchError> { + fn recompute_underlying_amount(ptokens: &Amount) -> Result, DispatchError> { // This function could be called externally to this pallet, with interest // possibly not having accrued for a few blocks. This would result in using an // outdated exchange rate. Call `accrue_interest` to avoid this. @@ -2060,7 +2060,7 @@ impl LoansTrait, AccountIdOf, BalanceOf, Amount UnderlyingAssetId::::try_get(ptoken_id).map_err(|_err| Error::::InvalidPtokenId.into()) } - fn get_collateral_amount(underlying: &Amount) -> Result, DispatchError> { + fn recompute_collateral_amount(underlying: &Amount) -> Result, DispatchError> { // This function could be called externally to this pallet, with interest // possibly not having accrued for a few blocks. This would result in using an // outdated exchange rate. Call `accrue_interest` to avoid this. diff --git a/crates/loans/src/tests.rs b/crates/loans/src/tests.rs index 8d7716cd67..9d739b4c06 100644 --- a/crates/loans/src/tests.rs +++ b/crates/loans/src/tests.rs @@ -31,7 +31,10 @@ use sp_runtime::{ use primitives::{CurrencyId::Token, DOT as DOT_CURRENCY, IBTC, KBTC, KINT, KSM as KSM_CURRENCY}; -use crate::mock::*; +use crate::{ + mock::*, + tests::ptokens::{free_balance, reserved_balance}, +}; // For the time being, do a quick reassignment here to avoid changing all the tests // TODO: update all tests @@ -63,6 +66,7 @@ fn init_markets_ok() { assert_eq!(BorrowIndex::::get(DOT), Rate::one()); assert_eq!(BorrowIndex::::get(USDT), Rate::one()); + assert_eq!(ExchangeRate::::get(HKO), Rate::saturating_from_rational(2, 100)); assert_eq!(ExchangeRate::::get(KSM), Rate::saturating_from_rational(2, 100)); assert_eq!(ExchangeRate::::get(DOT), Rate::saturating_from_rational(2, 100)); assert_eq!(ExchangeRate::::get(USDT), Rate::saturating_from_rational(2, 100)); @@ -155,12 +159,62 @@ fn mint_must_return_err_when_overflows_occur() { ArithmeticError::Underflow ); - // Exchange rate must ge greater than zero - // ExchangeRate::::insert(DOT, Rate::zero()); - // assert_noop!( - // Loans::mint(Origin::signed(CHARLIE), DOT, 100), - // ArithmeticError::Underflow - // ); + // Assume a misconfiguration occurs + MinExchangeRate::::put(Rate::zero()); + // There is no cash in the market. To compute how many ptokens this first deposit + // should mint, the `MinExchangeRate` is used, which has been misconfigured and + // set to zero (default value for the type). The extrinsic should fail. + assert_noop!( + Loans::mint(Origin::signed(CHARLIE), DOT, 100), + ArithmeticError::Underflow + ); + }) +} + +#[test] +fn supply_cap_below_current_volume() { + new_test_ext().execute_with(|| { + // Deposit 200 DOT as collateral + assert_ok!(Loans::mint(Origin::signed(BOB), DOT, 200)); + assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, 200)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), KSM)); + + let new_supply_cap = 10; + assert_ok!(Loans::force_update_market( + Origin::root(), + DOT, + Market { + supply_cap: new_supply_cap, + ..ACTIVE_MARKET_MOCK + }, + )); + // Minting anything would exceed the cap + assert_noop!( + Loans::mint(Origin::signed(ALICE), DOT, 10), + Error::::SupplyCapacityExceeded + ); + // Can redeem, even if the resulting deposit is still + // above the new cap + assert_ok!(Loans::withdraw_all_collateral(Origin::signed(ALICE), KSM)); + assert_ok!(Loans::redeem(Origin::signed(ALICE), KSM, 10)); + + // Cannot mint back the amount that has just been redeemed + assert_noop!( + Loans::mint(Origin::signed(ALICE), DOT, 10), + Error::::SupplyCapacityExceeded + ); + + let ptokens = Loans::free_ptokens(KSM, &ALICE).unwrap(); + + // Redeem enough to be below the cap + assert_ok!(Loans::redeem( + Origin::signed(ALICE), + KSM, + Loans::recompute_underlying_amount(&ptokens).unwrap().amount() - (new_supply_cap / 2) + )); + + // Can now supply + assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, new_supply_cap / 2)); }) } @@ -275,12 +329,12 @@ fn redeem_must_return_err_when_overflows_occur() { ArithmeticError::Underflow, ); - // Exchange rate must ge greater than zero - // ExchangeRate::::insert(DOT, Rate::zero()); - // assert_noop!( - // Loans::redeem(Origin::signed(ALICE), DOT, 100), - // ArithmeticError::Underflow - // ); + // Assume a misconfiguration occurs + MinExchangeRate::::put(Rate::zero()); + assert_noop!( + Loans::redeem(Origin::signed(ALICE), DOT, 100), + ArithmeticError::Underflow + ); }) } @@ -298,7 +352,8 @@ fn redeem_all_works() { 0, ); assert_eq!(Tokens::balance(DOT, &ALICE), unit(1000),); - assert!(!AccountDeposits::::contains_key(DOT, &ALICE)) + assert!(!AccountDeposits::::contains_key(DOT, &ALICE)); + assert_eq!(Tokens::balance(CDOT, &ALICE), 0); }) } @@ -336,6 +391,53 @@ fn borrow_allowed_works() { }) } +#[test] +fn borrow_cap_below_current_volume() { + new_test_ext().execute_with(|| { + // Deposit 200 DOT as collateral + assert_ok!(Loans::mint(Origin::signed(BOB), DOT, 200)); + assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, 200)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), KSM)); + assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, 50)); + + let new_borrow_cap = 10; + assert_ok!(Loans::force_update_market( + Origin::root(), + DOT, + Market { + borrow_cap: new_borrow_cap, + ..ACTIVE_MARKET_MOCK + }, + )); + // Borrowing anything would exceed the cap + assert_noop!( + Loans::borrow_allowed(DOT, &ALICE, 10), + Error::::BorrowCapacityExceeded + ); + // Can repay the borrow, even if the resulting loan is still + // above the new cap + assert_ok!(Loans::repay_borrow(Origin::signed(ALICE), DOT, 10)); + + // Cannot borrow back the amount that has just been repaid + assert_noop!( + Loans::borrow_allowed(DOT, &ALICE, 10), + Error::::BorrowCapacityExceeded + ); + + let outstanding = Loans::current_borrow_balance(&ALICE, DOT).unwrap(); + + // Repay enough to be below the cap + assert_ok!(Loans::repay_borrow( + Origin::signed(ALICE), + DOT, + outstanding - (new_borrow_cap / 2) + )); + + // Can now borrow + assert_ok!(Loans::borrow_allowed(DOT, &ALICE, new_borrow_cap / 2),); + }) +} + #[test] fn get_account_liquidity_works() { new_test_ext().execute_with(|| { @@ -399,32 +501,6 @@ fn borrow_works() { }) } -#[test] -fn lf_borrow_works() { - new_test_ext().execute_with(|| { - // Deposit 200 DOT as collateral - Loans::mint(Origin::signed(ALICE), CDOT_6_13, unit(200)).unwrap(); - Loans::mint(Origin::signed(DAVE), DOT, unit(200)).unwrap(); - Loans::deposit_all_collateral(Origin::signed(ALICE), CDOT_6_13).unwrap(); - - // Borrow 100 DOT - assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, unit(100))); - - // CDOT collateral: deposit = 200 - // DOT borrow balance: borrow = 100 - // DOT: cash - deposit + borrow = 1000 + 100 = 1100 - assert_eq!( - Loans::exchange_rate(CDOT_6_13) - .saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(CDOT_6_13).unwrap(), ALICE)), - unit(200) - ); - let borrow_snapshot = Loans::account_borrows(DOT, ALICE); - assert_eq!(borrow_snapshot.principal, unit(100)); - assert_eq!(borrow_snapshot.borrow_index, Loans::borrow_index(DOT)); - assert_eq!(Tokens::balance(DOT, &ALICE), unit(1100),); - }) -} - #[test] fn repay_borrow_works() { new_test_ext().execute_with(|| { @@ -487,17 +563,24 @@ fn collateral_asset_works() { // No collateral assets // Deposit 200 DOT as collateral assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, 200)); + let ptoken_id = Loans::ptoken_id(DOT).unwrap(); // No ptokens deposited as collateral assert_eq!( - Loans::account_deposits(Loans::ptoken_id(DOT).unwrap(), ALICE).eq(&0), + Loans::account_deposits(ptoken_id, ALICE).eq(&reserved_balance(ptoken_id, &ALICE)), true ); + assert_eq!(free_balance(ptoken_id, &ALICE), 200 * 50); + assert_eq!(reserved_balance(ptoken_id, &ALICE), 0); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), DOT)); // Non-zero ptokens deposited as collateral assert_eq!( - Loans::account_deposits(Loans::ptoken_id(DOT).unwrap(), ALICE).gt(&0), + Loans::account_deposits(ptoken_id, ALICE).eq(&reserved_balance(ptoken_id, &ALICE)), true ); + assert_eq!(free_balance(ptoken_id, &ALICE), 0); + assert_eq!(reserved_balance(ptoken_id, &ALICE), 200 * 50); + // Borrow 100 DOT base on the collateral of 200 DOT assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, 100)); assert_noop!( @@ -507,7 +590,12 @@ fn collateral_asset_works() { // Repay all the borrows assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), DOT)); assert_ok!(Loans::withdraw_all_collateral(Origin::signed(ALICE), DOT)); - assert_eq!(Loans::account_deposits(Loans::ptoken_id(DOT).unwrap(), ALICE), 0); + assert_eq!( + Loans::account_deposits(ptoken_id, ALICE), + reserved_balance(ptoken_id, &ALICE) + ); + assert_eq!(free_balance(ptoken_id, &ALICE), 200 * 50); + assert_eq!(reserved_balance(ptoken_id, &ALICE), 0); }) } diff --git a/crates/loans/src/tests/edge_cases.rs b/crates/loans/src/tests/edge_cases.rs index 36015b4baa..2cbf6a4807 100644 --- a/crates/loans/src/tests/edge_cases.rs +++ b/crates/loans/src/tests/edge_cases.rs @@ -106,8 +106,8 @@ fn converting_to_and_from_collateral_should_not_change_results() { let base_ksm_amount = 100007444213; for offset in 0..=1000 { let ksm_amount = Amount::new(base_ksm_amount + offset, Token(KSM)); - let conv_pksm_amount = Loans::get_collateral_amount(&ksm_amount).unwrap(); - let conv_ksm_amount = Loans::get_underlying_amount(&conv_pksm_amount).unwrap(); + let conv_pksm_amount = Loans::recompute_collateral_amount(&ksm_amount).unwrap(); + let conv_ksm_amount = Loans::recompute_underlying_amount(&conv_pksm_amount).unwrap(); assert_eq!(conv_ksm_amount.amount(), ksm_amount.amount()); } }) diff --git a/crates/loans/src/tests/interest_rate.rs b/crates/loans/src/tests/interest_rate.rs index ed44e0b468..6b2b7a82cb 100644 --- a/crates/loans/src/tests/interest_rate.rs +++ b/crates/loans/src/tests/interest_rate.rs @@ -263,7 +263,7 @@ fn accrue_interest_works_after_liquidate_borrow() { } #[test] -fn accrue_interest_works_after_get_collateral_amount() { +fn accrue_interest_works_after_recompute_collateral_amount() { new_test_ext().execute_with(|| { assert_ok!(Loans::mint(Origin::signed(BOB), Token(KSM), unit(200))); assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); @@ -271,13 +271,16 @@ fn accrue_interest_works_after_get_collateral_amount() { assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(KSM), unit(50))); assert_eq!(Loans::borrow_index(Token(KSM)), Rate::one()); TimestampPallet::set_timestamp(12000); - assert_ok!(Loans::get_collateral_amount(&Amount::::new(1234, Token(KSM)))); + assert_ok!(Loans::recompute_collateral_amount(&Amount::::new( + 1234, + Token(KSM) + ))); assert_eq!(Loans::borrow_index(Token(KSM)), Rate::from_inner(1000000008561643835),); }) } #[test] -fn accrue_interest_works_after_get_underlying_amount() { +fn accrue_interest_works_after_recompute_underlying_amount() { new_test_ext().execute_with(|| { assert_ok!(Loans::mint(Origin::signed(BOB), Token(KSM), unit(200))); assert_ok!(Loans::mint(Origin::signed(ALICE), Token(DOT), unit(200))); @@ -285,7 +288,7 @@ fn accrue_interest_works_after_get_underlying_amount() { assert_ok!(Loans::borrow(Origin::signed(ALICE), Token(KSM), unit(50))); assert_eq!(Loans::borrow_index(Token(KSM)), Rate::one()); TimestampPallet::set_timestamp(12000); - assert_ok!(Loans::get_underlying_amount( + assert_ok!(Loans::recompute_underlying_amount( &Loans::free_ptokens(Token(KSM), &ALICE).unwrap() )); assert_eq!(Loans::borrow_index(Token(KSM)), Rate::from_inner(1000000008561643835),); diff --git a/crates/loans/src/tests/ptokens.rs b/crates/loans/src/tests/ptokens.rs index fc56e784df..d2fcae2f47 100644 --- a/crates/loans/src/tests/ptokens.rs +++ b/crates/loans/src/tests/ptokens.rs @@ -22,11 +22,11 @@ const PKSM: CurrencyId = CKSM; const PUSDT: CurrencyId = CKBTC; const USDT: CurrencyId = Token(KBTC); -fn free_balance(currency_id: CurrencyId, account_id: &AccountId) -> Balance { +pub fn free_balance(currency_id: CurrencyId, account_id: &AccountId) -> Balance { ::AccountId>>::free_balance(currency_id, account_id) } -fn reserved_balance(currency_id: CurrencyId, account_id: &AccountId) -> Balance { +pub fn reserved_balance(currency_id: CurrencyId, account_id: &AccountId) -> Balance { ::AccountId>>::reserved_balance( currency_id, account_id, diff --git a/crates/loans/src/types.rs b/crates/loans/src/types.rs index 5914d8e0f0..05d1344009 100644 --- a/crates/loans/src/types.rs +++ b/crates/loans/src/types.rs @@ -21,15 +21,6 @@ pub struct EarnedSnapshot { pub exchange_rate_prior: Rate, } -/// Deposit information -#[derive(Encode, Decode, Eq, PartialEq, Copy, Clone, RuntimeDebug, Default, TypeInfo)] -pub struct Deposits { - /// The voucher amount of the deposit - pub voucher_balance: Balance, - /// Can this deposit be used as collateral - pub is_collateral: bool, -} - /// The current state of a market. For more information, see [Market]. #[cfg_attr(feature = "std", derive(serde::Deserialize, serde::Serialize))] #[derive(Clone, Copy, PartialEq, Eq, codec::Decode, codec::Encode, RuntimeDebug, TypeInfo)] diff --git a/crates/traits/src/loans.rs b/crates/traits/src/loans.rs index 517a9d3ceb..9e95d25f4b 100644 --- a/crates/traits/src/loans.rs +++ b/crates/traits/src/loans.rs @@ -27,9 +27,9 @@ pub trait LoansApi { -> Result<(), DispatchError>; fn do_repay_borrow(borrower: &AccountId, asset_id: CurrencyId, amount: Balance) -> Result<(), DispatchError>; fn do_redeem(supplier: &AccountId, asset_id: CurrencyId, amount: Balance) -> Result<(), DispatchError>; - fn get_underlying_amount(ptokens: &Amount) -> Result; + fn recompute_underlying_amount(ptokens: &Amount) -> Result; fn underlying_id(ptoken_id: CurrencyId) -> Result; - fn get_collateral_amount(underlying: &Amount) -> Result; + fn recompute_collateral_amount(underlying: &Amount) -> Result; } pub trait LoansPositionDataProvider { diff --git a/standalone/runtime/tests/test_loans.rs b/standalone/runtime/tests/test_loans.rs index 27ffaec3b2..432fb64522 100644 --- a/standalone/runtime/tests/test_loans.rs +++ b/standalone/runtime/tests/test_loans.rs @@ -191,6 +191,10 @@ fn integration_test_ptoken_vault_insufficient_balance() { // Check entries from orml-tokens directly assert_eq!(free_balance(CDOT, &vault_account_id), 1000); assert_eq!(reserved_balance(CDOT, &vault_account_id), 0); + assert_eq!( + LoansPallet::account_deposits(CDOT, vault_account_id.clone()), + reserved_balance(CDOT, &vault_account_id) + ); let ptokens = LoansPallet::free_ptokens(dot, &vault_account_id).unwrap(); @@ -199,6 +203,10 @@ fn integration_test_ptoken_vault_insufficient_balance() { .dispatch(origin_of(vault_account_id.clone()))); assert_eq!(free_balance(CDOT, &vault_account_id), 0); assert_eq!(reserved_balance(CDOT, &vault_account_id), 1000); + assert_eq!( + LoansPallet::account_deposits(ptokens.currency(), vault_account_id.clone()), + reserved_balance(CDOT, &vault_account_id) + ); let ptoken_vault_id = PrimitiveVaultId::new(vault_account_id.clone(), ptokens.currency(), Token(IBTC)); assert_err!( @@ -216,6 +224,10 @@ fn integration_test_ptoken_vault_insufficient_balance() { assert_ok!(get_register_vault_result(&ptoken_vault_id, ptokens)); assert_eq!(free_balance(CDOT, &vault_account_id), 0); assert_eq!(reserved_balance(CDOT, &vault_account_id), 1000); + assert_eq!( + LoansPallet::account_deposits(ptokens.currency(), vault_account_id.clone()), + 0 + ); }); } @@ -267,6 +279,10 @@ fn integration_test_ptoken_transfer_reserved_fails() { ptokens.currency(), ptokens.amount() / 2 )); + assert_eq!( + LoansPallet::account_deposits(ptokens.currency(), vault_account_id.clone()), + reserved_balance(ptokens.currency(), &vault_account_id) + ); assert_eq!(free_balance(CDOT, &vault_account_id), 500); assert_eq!(reserved_balance(CDOT, &vault_account_id), 500); From 17b5e3142f6a72daad79bdaba0723c2285abb4fd Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Thu, 27 Oct 2022 14:38:25 +0200 Subject: [PATCH 43/58] chore(loans): comments, Rate default impl --- crates/currency/src/lib.rs | 13 +++++++++++++ crates/loans/src/interest.rs | 3 +++ primitives/src/lib.rs | 6 ++++++ 3 files changed, 22 insertions(+) diff --git a/crates/currency/src/lib.rs b/crates/currency/src/lib.rs index 0b8a1a99ab..7773253fa6 100644 --- a/crates/currency/src/lib.rs +++ b/crates/currency/src/lib.rs @@ -44,19 +44,32 @@ where { fn convert(amount: &Amount, to: CurrencyId) -> Result, DispatchError> { if amount.currency().is_ptoken() && to.is_ptoken() { + // Exampe (lendDOT to lendINTR): carg + // collateral_amount(convert(underlying_amount(lendDOT_amount), underlying_id(lendINTR))) + // collateral_amount(convert(dot_amount, INTR)) + // collateral_amount(intr_amount) let to_underlying_id = Loans::underlying_id(to)?; let from_underlying_amount = Loans::recompute_underlying_amount(amount)?; let to_underlying_amount = Oracle::convert(&from_underlying_amount, to_underlying_id)?; Loans::recompute_collateral_amount(&to_underlying_amount) } else if amount.currency().is_ptoken() { + // Exampe: cDOT -> INTR = + // convert(underlying_amount(lendDOT_amount), INTR) + // convert(dot_amount, INTR) Oracle::convert(&Loans::recompute_underlying_amount(amount)?, to) } else if to.is_ptoken() { + // Exampe (DOT to lendINTR): + // collateral_amount(convert(dot_amount, underlying_id(lendINTR))) + // collateral_amount(convert(dot_amount, INTR)) + // collateral_amount(intr_amount) let underlying_id = Loans::underlying_id(to)?; // get the converted value expressed in the underlying asset let underlying_amount = Oracle::convert(amount, underlying_id)?; // get the equivalent ptoken amount using the internal exchange rate Loans::recompute_collateral_amount(&underlying_amount) } else { + // Exampe (DOT to INTR): + // convert(dot_amount, INTR) Oracle::convert(amount, to) } } diff --git a/crates/loans/src/interest.rs b/crates/loans/src/interest.rs index 74c7eb344d..9bfd22d0ee 100644 --- a/crates/loans/src/interest.rs +++ b/crates/loans/src/interest.rs @@ -135,6 +135,9 @@ impl Pallet { /// The exchange rate should be greater than the `MinExchangeRate` storage value and less than /// the `MaxExchangeRate` storage value. + /// This ensures the exchange rate cannot be attacked by a deposit so big that + /// subsequent deposits to receive zero lendTokens (because of rounding down). See this + /// PR for more details: https://github.com/parallel-finance/parallel/pull/1552/files pub(crate) fn ensure_valid_exchange_rate(exchange_rate: Rate) -> DispatchResult { ensure!( exchange_rate >= Self::min_exchange_rate() && exchange_rate < Self::max_exchange_rate(), diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 9c8a6a1091..4ddb9b37dd 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -369,6 +369,12 @@ pub type Shortfall = FixedU128; pub type Liquidity = FixedU128; pub const SECONDS_PER_YEAR: Timestamp = 365 * 24 * 60 * 60; +impl Default for Rate { + fn default() -> Self { + Self(Default::default()) + } +} + pub trait CurrencyInfo { fn name(&self) -> &str; fn symbol(&self) -> &str; From d32db005c56f1f358f7758e6b552c00b16da65b7 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Thu, 27 Oct 2022 14:55:23 +0200 Subject: [PATCH 44/58] refactor(loans): ptokens to lend_tokens --- crates/currency/src/lib.rs | 14 +- crates/loans/src/benchmarking.rs | 68 +++--- crates/loans/src/farming.rs | 4 +- crates/loans/src/{ptoken.rs => lend_token.rs} | 40 ++-- crates/loans/src/lib.rs | 211 +++++++++--------- crates/loans/src/mock.rs | 28 +-- crates/loans/src/tests.rs | 63 +++--- crates/loans/src/tests/edge_cases.rs | 6 +- crates/loans/src/tests/interest_rate.rs | 12 +- .../src/tests/{ptokens.rs => lend_tokens.rs} | 56 ++--- crates/loans/src/tests/liquidate_borrow.rs | 14 +- crates/loans/src/tests/market.rs | 16 +- crates/loans/src/types.rs | 4 +- crates/traits/src/loans.rs | 4 +- parachain/runtime/testnet-interlay/src/lib.rs | 6 +- parachain/runtime/testnet-kintsugi/src/lib.rs | 6 +- primitives/src/lib.rs | 14 +- standalone/runtime/src/lib.rs | 6 +- .../runtime/tests/mock/loans_testing_utils.rs | 18 +- standalone/runtime/tests/mock/mod.rs | 22 +- standalone/runtime/tests/test_issue.rs | 8 +- standalone/runtime/tests/test_loans.rs | 133 +++++------ standalone/runtime/tests/test_nomination.rs | 6 +- standalone/runtime/tests/test_redeem.rs | 4 +- standalone/runtime/tests/test_replace.rs | 12 +- .../runtime/tests/test_vault_registry.rs | 10 +- 26 files changed, 401 insertions(+), 384 deletions(-) rename crates/loans/src/{ptoken.rs => lend_token.rs} (75%) rename crates/loans/src/tests/{ptokens.rs => lend_tokens.rs} (82%) diff --git a/crates/currency/src/lib.rs b/crates/currency/src/lib.rs index 7773253fa6..1c41f80d1c 100644 --- a/crates/currency/src/lib.rs +++ b/crates/currency/src/lib.rs @@ -43,7 +43,7 @@ where Loans: LoansApi, T::AccountId, ::Balance, Amount>, { fn convert(amount: &Amount, to: CurrencyId) -> Result, DispatchError> { - if amount.currency().is_ptoken() && to.is_ptoken() { + if amount.currency().is_lend_token() && to.is_lend_token() { // Exampe (lendDOT to lendINTR): carg // collateral_amount(convert(underlying_amount(lendDOT_amount), underlying_id(lendINTR))) // collateral_amount(convert(dot_amount, INTR)) @@ -52,23 +52,23 @@ where let from_underlying_amount = Loans::recompute_underlying_amount(amount)?; let to_underlying_amount = Oracle::convert(&from_underlying_amount, to_underlying_id)?; Loans::recompute_collateral_amount(&to_underlying_amount) - } else if amount.currency().is_ptoken() { - // Exampe: cDOT -> INTR = + } else if amount.currency().is_lend_token() { + // Exampe: LendDOT -> INTR = // convert(underlying_amount(lendDOT_amount), INTR) // convert(dot_amount, INTR) Oracle::convert(&Loans::recompute_underlying_amount(amount)?, to) - } else if to.is_ptoken() { - // Exampe (DOT to lendINTR): + } else if to.is_lend_token() { + // Exampe (DOT to lendINTR): // collateral_amount(convert(dot_amount, underlying_id(lendINTR))) // collateral_amount(convert(dot_amount, INTR)) // collateral_amount(intr_amount) let underlying_id = Loans::underlying_id(to)?; // get the converted value expressed in the underlying asset let underlying_amount = Oracle::convert(amount, underlying_id)?; - // get the equivalent ptoken amount using the internal exchange rate + // get the equivalent lend_token amount using the internal exchange rate Loans::recompute_collateral_amount(&underlying_amount) } else { - // Exampe (DOT to INTR): + // Exampe (DOT to INTR): // convert(dot_amount, INTR) Oracle::convert(amount, to) } diff --git a/crates/loans/src/benchmarking.rs b/crates/loans/src/benchmarking.rs index 47b36d7d34..e4d50a69f8 100644 --- a/crates/loans/src/benchmarking.rs +++ b/crates/loans/src/benchmarking.rs @@ -9,7 +9,7 @@ use frame_support::assert_ok; use frame_system::{self, RawOrigin as SystemOrigin}; use primitives::{ Balance, - CurrencyId::{self, PToken, Token}, + CurrencyId::{self, LendToken, Token}, DOT as DOT_CURRENCY, KBTC as KBTC_CURRENCY, KINT as KINT_CURRENCY, KSM as KSM_CURRENCY, }; use rate_model::{InterestRateModel, JumpModel}; @@ -19,10 +19,10 @@ const SEED: u32 = 0; const KSM: CurrencyId = Token(KSM_CURRENCY); const KBTC: CurrencyId = Token(KBTC_CURRENCY); -const CKSM: CurrencyId = PToken(3); -const CKBTC: CurrencyId = PToken(4); +const LendKSM: CurrencyId = LendToken(3); +const LendKBTC: CurrencyId = LendToken(4); const DOT: CurrencyId = Token(DOT_CURRENCY); -const CDOT: CurrencyId = PToken(1); +const LendDOT: CurrencyId = LendToken(1); const KINT: CurrencyId = Token(KINT_CURRENCY); const RATE_MODEL_MOCK: InterestRateModel = InterestRateModel::Jump(JumpModel { @@ -49,14 +49,14 @@ fn market_mock() -> Market> { liquidate_incentive_reserved_factor: Ratio::from_percent(3), supply_cap: 1_000_000_000_000_000_000_000u128, // set to 1B borrow_cap: 1_000_000_000_000_000_000_000u128, // set to 1B - ptoken_id: CurrencyId::PToken(4), + lend_token_id: CurrencyId::LendToken(4), } } -fn pending_market_mock(ptoken_id: CurrencyId) -> Market> { +fn pending_market_mock(lend_token_id: CurrencyId) -> Market> { let mut market = market_mock::(); market.state = MarketState::Pending; - market.ptoken_id = ptoken_id; + market.lend_token_id = lend_token_id; market } @@ -67,7 +67,7 @@ fn transfer_initial_balance::set_balance( SystemOrigin::Root.into(), account_id.clone(), - CKSM, + LendKSM, 10_000_000_000_000_u128, 0_u128, ) @@ -93,7 +93,7 @@ fn transfer_initial_balance::set_balance( SystemOrigin::Root.into(), account_id, - CDOT, + LendDOT, 10_000_000_000_000_u128, 0_u128, ) @@ -125,9 +125,9 @@ benchmarks! { } add_market { - }: _(SystemOrigin::Root, DOT, pending_market_mock::(CDOT)) + }: _(SystemOrigin::Root, DOT, pending_market_mock::(LendDOT)) verify { - assert_last_event::(Event::::NewMarket(DOT, pending_market_mock::(CDOT)).into()); + assert_last_event::(Event::::NewMarket(DOT, pending_market_mock::(LendDOT)).into()); } activate_market { @@ -139,7 +139,7 @@ benchmarks! { update_rate_model { }: _(SystemOrigin::Root, KBTC, RATE_MODEL_MOCK) verify { - let mut market = pending_market_mock::(CKBTC); + let mut market = pending_market_mock::(LendKBTC); market.rate_model = RATE_MODEL_MOCK; assert_last_event::(Event::::UpdatedMarket(KBTC, market).into()); } @@ -158,16 +158,16 @@ benchmarks! { Some(1_000_000_000_000_000_000_000u128) ) verify { - let mut market = pending_market_mock::(CKSM); + let mut market = pending_market_mock::(LendKSM); market.reserve_factor = Ratio::from_percent(50); market.close_factor = Ratio::from_percent(15); assert_last_event::(Event::::UpdatedMarket(KSM, market).into()); } force_update_market { - }: _(SystemOrigin::Root,KBTC, pending_market_mock::(CKBTC)) + }: _(SystemOrigin::Root,KBTC, pending_market_mock::(LendKBTC)) verify { - assert_last_event::(Event::::UpdatedMarket(KBTC, pending_market_mock::(CKBTC)).into()); + assert_last_event::(Event::::UpdatedMarket(KBTC, pending_market_mock::(LendKBTC)).into()); } add_reward { @@ -189,7 +189,7 @@ benchmarks! { } update_market_reward_speed { - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); }: _(SystemOrigin::Root, KBTC, Some(1_000_000), Some(1_000_000)) verify { @@ -199,7 +199,7 @@ benchmarks! { claim_reward { let caller: T::AccountId = whitelisted_caller(); transfer_initial_balance::(caller.clone()); - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, 100_000_000)); assert_ok!(Loans::::add_reward(SystemOrigin::Signed(caller.clone()).into(), 1_000_000_000_000_u128)); @@ -214,7 +214,7 @@ benchmarks! { claim_reward_for_market { let caller: T::AccountId = whitelisted_caller(); transfer_initial_balance::(caller.clone()); - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, 100_000_000)); assert_ok!(Loans::::add_reward(SystemOrigin::Signed(caller.clone()).into(), 1_000_000_000_000_u128)); @@ -230,7 +230,7 @@ benchmarks! { mint { let caller: T::AccountId = whitelisted_caller(); transfer_initial_balance::(caller.clone()); - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); let amount: u32 = 100_000; }: _(SystemOrigin::Signed(caller.clone()), KBTC, amount.into()) @@ -243,7 +243,7 @@ benchmarks! { transfer_initial_balance::(caller.clone()); let deposit_amount: u32 = 200_000_000; let borrowed_amount: u32 = 100_000_000; - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); assert_ok!(Loans::::deposit_all_collateral(SystemOrigin::Signed(caller.clone()).into(), KBTC)); @@ -257,7 +257,7 @@ benchmarks! { transfer_initial_balance::(caller.clone()); let deposit_amount: u32 = 100_000_000; let redeem_amount: u32 = 100_000; - // assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + // assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); }: _(SystemOrigin::Signed(caller.clone()), KBTC, redeem_amount.into()) @@ -269,7 +269,7 @@ benchmarks! { let caller: T::AccountId = whitelisted_caller(); transfer_initial_balance::(caller.clone()); let deposit_amount: u32 = 100_000_000; - // assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + // assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); }: _(SystemOrigin::Signed(caller.clone()), KBTC) @@ -283,7 +283,7 @@ benchmarks! { let deposit_amount: u32 = 200_000_000; let borrowed_amount: u32 = 100_000_000; let repay_amount: u32 = 100; - // assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + // assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); assert_ok!(Loans::::deposit_all_collateral(SystemOrigin::Signed(caller.clone()).into(), KBTC)); @@ -298,7 +298,7 @@ benchmarks! { transfer_initial_balance::(caller.clone()); let deposit_amount: u32 = 200_000_000; let borrowed_amount: u32 = 100_000_000; - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); @@ -313,7 +313,7 @@ benchmarks! { let caller: T::AccountId = whitelisted_caller(); transfer_initial_balance::(caller.clone()); let deposit_amount: u32 = 200_000_000; - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); }: _(SystemOrigin::Signed(caller.clone()), KBTC) @@ -330,17 +330,17 @@ benchmarks! { let borrowed_amount: u32 = 200_000_000; let liquidate_amount: u32 = 100_000_000; let incentive_amount: u32 = 110_000_000; - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), CDOT, pending_market_mock::(KINT))); - assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), CDOT)); - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KSM, pending_market_mock::(CKSM))); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), LendDOT, pending_market_mock::(KINT))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), LendDOT)); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KSM, pending_market_mock::(LendKSM))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KSM)); assert_ok!(Loans::::mint(SystemOrigin::Signed(bob.clone()).into(), KSM, deposit_amount.into())); - assert_ok!(Loans::::mint(SystemOrigin::Signed(alice.clone()).into(), CDOT, deposit_amount.into())); - assert_ok!(Loans::::deposit_all_collateral(SystemOrigin::Signed(alice.clone()).into(), CDOT)); + assert_ok!(Loans::::mint(SystemOrigin::Signed(alice.clone()).into(), LendDOT, deposit_amount.into())); + assert_ok!(Loans::::deposit_all_collateral(SystemOrigin::Signed(alice.clone()).into(), LendDOT)); set_account_borrows::(alice.clone(), KSM, borrowed_amount.into()); - }: _(SystemOrigin::Signed(bob.clone()), alice.clone(), KSM, liquidate_amount.into(), CDOT) + }: _(SystemOrigin::Signed(bob.clone()), alice.clone(), KSM, liquidate_amount.into(), LendDOT) verify { - assert_last_event::(Event::::LiquidatedBorrow(bob.clone(), alice.clone(), KSM, CDOT, liquidate_amount.into(), incentive_amount.into()).into()); + assert_last_event::(Event::::LiquidatedBorrow(bob.clone(), alice.clone(), KSM, LendDOT, liquidate_amount.into(), incentive_amount.into()).into()); } add_reserves { @@ -348,7 +348,7 @@ benchmarks! { let payer = T::Lookup::unlookup(caller.clone()); transfer_initial_balance::(caller.clone()); let amount: u32 = 2000; - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); }: _(SystemOrigin::Root, payer, KBTC, amount.into()) verify { @@ -361,7 +361,7 @@ benchmarks! { transfer_initial_balance::(caller.clone()); let add_amount: u32 = 2000; let reduce_amount: u32 = 1000; - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(CKBTC))); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::add_reserves(SystemOrigin::Root.into(), payer.clone(), KBTC, add_amount.into())); }: _(SystemOrigin::Root, payer, KBTC, reduce_amount.into()) diff --git a/crates/loans/src/farming.rs b/crates/loans/src/farming.rs index a6f0d64639..a54c0606be 100644 --- a/crates/loans/src/farming.rs +++ b/crates/loans/src/farming.rs @@ -121,10 +121,10 @@ impl Pallet { .ok_or(ArithmeticError::Underflow)?; *supplier_index = supply_state.index; - let ptoken_id = Self::ptoken_id(asset_id)?; + let lend_token_id = Self::lend_token_id(asset_id)?; RewardAccrued::::try_mutate(supplier, |total_reward| -> DispatchResult { // Frozen balance is not counted towards the total - let total_balance = Self::balance(ptoken_id, supplier); + let total_balance = Self::balance(lend_token_id, supplier); let reward_delta = Self::calculate_reward_delta(total_balance, delta_index)?; *total_reward = total_reward .checked_add(reward_delta) diff --git a/crates/loans/src/ptoken.rs b/crates/loans/src/lend_token.rs similarity index 75% rename from crates/loans/src/ptoken.rs rename to crates/loans/src/lend_token.rs index bae1857734..3dead11c1c 100644 --- a/crates/loans/src/ptoken.rs +++ b/crates/loans/src/lend_token.rs @@ -27,8 +27,8 @@ use frame_support::{ #[cfg(test)] impl Pallet { /// The total amount of issuance in the system. - pub fn total_issuance(ptoken_id: AssetIdOf) -> BalanceOf { - if let Ok(underlying_id) = Self::underlying_id(ptoken_id) { + pub fn total_issuance(lend_token_id: AssetIdOf) -> BalanceOf { + if let Ok(underlying_id) = Self::underlying_id(lend_token_id) { if let Ok(supply) = Self::total_supply(underlying_id) { return supply; } @@ -37,24 +37,24 @@ impl Pallet { } /// The minimum balance any single account may have. - pub fn minimum_balance(_ptoken_id: AssetIdOf) -> BalanceOf { + pub fn minimum_balance(_lend_token_id: AssetIdOf) -> BalanceOf { Zero::zero() } /// Get the maximum amount that `who` can withdraw/transfer successfully. - /// For ptoken, We don't care if keep_alive is enabled - pub fn reducible_balance(ptoken_id: AssetIdOf, who: &T::AccountId, _keep_alive: bool) -> BalanceOf { - Self::reducible_asset(ptoken_id, who).unwrap_or_default() + /// For lend_token, We don't care if keep_alive is enabled + pub fn reducible_balance(lend_token_id: AssetIdOf, who: &T::AccountId, _keep_alive: bool) -> BalanceOf { + Self::reducible_asset(lend_token_id, who).unwrap_or_default() } /// Returns `true` if the balance of `who` may be increased by `amount`. pub fn can_deposit( - ptoken_id: AssetIdOf, + lend_token_id: AssetIdOf, who: &T::AccountId, amount: BalanceOf, _mint: bool, ) -> DepositConsequence { - let underlying_id = match Self::underlying_id(ptoken_id) { + let underlying_id = match Self::underlying_id(lend_token_id) { Ok(asset_id) => asset_id, Err(_) => return DepositConsequence::UnknownAsset, }; @@ -71,7 +71,7 @@ impl Pallet { return DepositConsequence::UnknownAsset; } - if Self::balance(ptoken_id, who) + amount < Self::minimum_balance(ptoken_id) { + if Self::balance(lend_token_id, who) + amount < Self::minimum_balance(lend_token_id) { return DepositConsequence::BelowMinimum; } @@ -81,11 +81,11 @@ impl Pallet { /// Returns `Failed` if the balance of `who` may not be decreased by `amount`, otherwise /// the consequence. pub fn can_withdraw( - ptoken_id: AssetIdOf, + lend_token_id: AssetIdOf, who: &T::AccountId, amount: BalanceOf, ) -> WithdrawConsequence> { - let underlying_id = match Self::underlying_id(ptoken_id) { + let underlying_id = match Self::underlying_id(lend_token_id) { Ok(asset_id) => asset_id, Err(_) => return WithdrawConsequence::UnknownAsset, }; @@ -94,39 +94,39 @@ impl Pallet { return res; } - let sub_result = Self::balance(ptoken_id, who).checked_sub(amount); + let sub_result = Self::balance(lend_token_id, who).checked_sub(amount); if sub_result.is_none() { return WithdrawConsequence::NoFunds; } let rest = sub_result.expect("Cannot be none; qed"); - if rest < Self::minimum_balance(ptoken_id) { + if rest < Self::minimum_balance(lend_token_id) { return WithdrawConsequence::ReducedToZero(rest); } WithdrawConsequence::Success } - /// Returns `Err` if the reducible ptoken of `who` is insufficient + /// Returns `Err` if the reducible lend_token of `who` is insufficient /// - /// For ptoken, We don't care if keep_alive is enabled + /// For lend_token, We don't care if keep_alive is enabled #[transactional] pub fn transfer( - ptoken_id: AssetIdOf, + lend_token_id: AssetIdOf, source: &T::AccountId, dest: &T::AccountId, amount: BalanceOf, _keep_alive: bool, ) -> Result, DispatchError> { - as MultiCurrency>::transfer(ptoken_id, source, dest, amount) + as MultiCurrency>::transfer(lend_token_id, source, dest, amount) .map_err(|_| Error::::InsufficientCollateral)?; Ok(amount) } - fn reducible_asset(ptoken_id: AssetIdOf, who: &T::AccountId) -> Result, DispatchError> { - let voucher_balance = Self::account_deposits(ptoken_id, &who); + fn reducible_asset(lend_token_id: AssetIdOf, who: &T::AccountId) -> Result, DispatchError> { + let voucher_balance = Self::account_deposits(lend_token_id, &who); - let underlying_id = Self::underlying_id(ptoken_id)?; + let underlying_id = Self::underlying_id(lend_token_id)?; let market = Self::ensure_active_market(underlying_id)?; let collateral_value = Self::collateral_asset_value(who, underlying_id)?; diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 77f7926431..a174981e0d 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -69,7 +69,7 @@ mod tests; mod farming; mod interest; -mod ptoken; +mod lend_token; mod rate_model; mod types; @@ -82,7 +82,7 @@ type BalanceOf = <::Assets as Inspect<(marker::PhantomData); impl OnSlash, BalanceOf> for OnSlashHook { fn on_slash(currency_id: AssetIdOf, account_id: &T::AccountId, amount: BalanceOf) { - if currency_id.is_ptoken() { + if currency_id.is_lend_token() { let f = || -> DispatchResult { let underlying_id = Pallet::::underlying_id(currency_id)?; Pallet::::update_reward_supply_index(underlying_id)?; @@ -106,7 +106,7 @@ impl OnSlash, BalanceOf> for OnSlashHoo pub struct OnDepositHook(marker::PhantomData); impl OnDeposit, BalanceOf> for OnDepositHook { fn on_deposit(currency_id: AssetIdOf, account_id: &T::AccountId, _: BalanceOf) -> DispatchResult { - if currency_id.is_ptoken() { + if currency_id.is_lend_token() { let underlying_id = Pallet::::underlying_id(currency_id)?; Pallet::::update_reward_supply_index(underlying_id)?; Pallet::::distribute_supplier_reward(underlying_id, account_id)?; @@ -123,7 +123,7 @@ impl OnTransfer, BalanceOf> for OnTrans to: &T::AccountId, _: BalanceOf, ) -> DispatchResult { - if currency_id.is_ptoken() { + if currency_id.is_lend_token() { let underlying_id = Pallet::::underlying_id(currency_id)?; Pallet::::update_reward_supply_index(underlying_id)?; Pallet::::distribute_supplier_reward(underlying_id, from)?; @@ -217,8 +217,8 @@ pub mod pallet { PriceIsZero, /// Invalid asset id InvalidCurrencyId, - /// Invalid ptoken id - InvalidPtokenId, + /// Invalid lend_token id + InvalidLendTokenId, /// Market does not exist MarketDoesNotExist, /// Market already exists @@ -392,8 +392,8 @@ pub mod pallet { #[pallet::storage] pub type Markets = StorageMap<_, Blake2_128Concat, AssetIdOf, Market>>; - /// Mapping of ptoken id to asset id - /// `ptoken id`: voucher token id + /// Mapping of lend_token id to asset id + /// `lend_token id`: voucher token id /// `asset id`: underlying token id #[pallet::storage] pub type UnderlyingAssetId = StorageMap<_, Blake2_128Concat, AssetIdOf, AssetIdOf>; @@ -495,8 +495,8 @@ pub mod pallet { /// If a currency is already attached to a market, then the market will be replaced /// by the new provided value. /// - /// The ptoken id and asset id are bound, the ptoken id of new provided market cannot - /// be duplicated with the existing one, otherwise it will return `InvalidPtokenId`. + /// The lend_token id and asset id are bound, the lend_token id of new provided market cannot + /// be duplicated with the existing one, otherwise it will return `InvalidLendTokenId`. /// /// - `asset_id`: Market related currency /// - `market`: The market that is going to be stored @@ -533,11 +533,11 @@ pub mod pallet { ); ensure!(market.supply_cap > Zero::zero(), Error::::InvalidSupplyCap,); - // Ensures a given `ptoken_id` not exists on the `Market` and `UnderlyingAssetId`. - Self::ensure_ptoken(market.ptoken_id)?; + // Ensures a given `lend_token_id` not exists on the `Market` and `UnderlyingAssetId`. + Self::ensure_lend_token(market.lend_token_id)?; // Update storage of `Market` and `UnderlyingAssetId` Markets::::insert(asset_id, market.clone()); - UnderlyingAssetId::::insert(market.ptoken_id, asset_id); + UnderlyingAssetId::::insert(market.lend_token_id, asset_id); // Init the ExchangeRate and BorrowIndex for asset ExchangeRate::::insert(asset_id, Self::min_exchange_rate()); @@ -643,7 +643,7 @@ pub mod pallet { let market = Self::mutate_market(asset_id, |stored_market| { *stored_market = Market { state: stored_market.state, - ptoken_id: stored_market.ptoken_id, + lend_token_id: stored_market.lend_token_id, rate_model: stored_market.rate_model, collateral_factor, liquidation_threshold, @@ -675,13 +675,13 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { T::UpdateOrigin::ensure_origin(origin)?; ensure!(market.rate_model.check_model(), Error::::InvalidRateModelParam); - if UnderlyingAssetId::::contains_key(market.ptoken_id) { + if UnderlyingAssetId::::contains_key(market.lend_token_id) { ensure!( - Self::underlying_id(market.ptoken_id)? == asset_id, - Error::::InvalidPtokenId + Self::underlying_id(market.lend_token_id)? == asset_id, + Error::::InvalidLendTokenId ); } - UnderlyingAssetId::::insert(market.ptoken_id, asset_id); + UnderlyingAssetId::::insert(market.lend_token_id, asset_id); let updated_market = Self::mutate_market(asset_id, |stored_market| { *stored_market = market; stored_market.clone() @@ -860,29 +860,29 @@ pub mod pallet { let who = ensure_signed(origin)?; // This function is an almost 1:1 duplicate of the logic in `do_redeem`. // It could be refactored to compute the redeemable underlying - // with `Self::recompute_underlying_amount(&Self::free_ptokens(asset_id, &who)?)?` + // with `Self::recompute_underlying_amount(&Self::free_lend_tokens(asset_id, &who)?)?` // but that would cause the `accrue_interest_works_after_redeem_all` unit test to fail with // left: `1000000000003607`, // right: `1000000000003608`' // Chaining `calc_underlying_amount` and `calc_collateral_amount` continuously decreases // an amount because of rounding down, and having the current function call `do_redeem` - // would perform three conversions: ptoken -> token -> ptoken -> token. - // Calling `do_redeem_voucher` directly only performs one conversion: ptoken -> token, + // would perform three conversions: lend_token -> token -> lend_token -> token. + // Calling `do_redeem_voucher` directly only performs one conversion: lend_token -> token, // avoiding this edge case. // TODO: investigate whether it is possible to implement the conversion functions // with guarantees that this always holds: // `calc_underlying_amount(calc_collateral_amount(x)) = calc_collateral_amount(calc_underlying_amount(x))` // Use the `converting_to_and_from_collateral_should_not_change_results` unit test to achieve this. - // If there are leftover ptokens after a `redeem_all` (because of rounding down), it would make it + // If there are leftover lend_tokens after a `redeem_all` (because of rounding down), it would make it // impossible to enforce "collateral toggle" state transitions. Self::ensure_active_market(asset_id)?; Self::accrue_interest(asset_id)?; let exchange_rate = Self::exchange_rate_stored(asset_id)?; Self::update_earned_stored(&who, asset_id, exchange_rate)?; - let ptokens = Self::free_ptokens(asset_id, &who)?; - ensure!(!ptokens.is_zero(), Error::::InvalidAmount); - let redeem_amount = Self::do_redeem_voucher(&who, asset_id, ptokens.amount())?; + let lend_tokens = Self::free_lend_tokens(asset_id, &who)?; + ensure!(!lend_tokens.is_zero(), Error::::InvalidAmount); + let redeem_amount = Self::do_redeem_voucher(&who, asset_id, lend_tokens.amount())?; Self::deposit_event(Event::::Redeemed(who, asset_id, redeem_amount)); Ok(().into()) @@ -946,9 +946,9 @@ pub mod pallet { #[transactional] pub fn deposit_all_collateral(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - let ptokens = Self::free_ptokens(asset_id, &who)?; - ensure!(!ptokens.is_zero(), Error::::InvalidAmount); - Self::do_deposit_collateral(&who, ptokens.currency(), ptokens.amount())?; + let lend_tokens = Self::free_lend_tokens(asset_id, &who)?; + ensure!(!lend_tokens.is_zero(), Error::::InvalidAmount); + Self::do_deposit_collateral(&who, lend_tokens.currency(), lend_tokens.amount())?; Ok(().into()) } @@ -970,10 +970,10 @@ pub mod pallet { pub fn withdraw_all_collateral(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - let ptoken_id = Self::ptoken_id(asset_id)?; - let collateral = Self::account_deposits(ptoken_id, who.clone()); + let lend_token_id = Self::lend_token_id(asset_id)?; + let collateral = Self::account_deposits(lend_token_id, who.clone()); ensure!(!collateral.is_zero(), Error::::InvalidAmount); - Self::do_withdraw_collateral(&who, ptoken_id, collateral)?; + Self::do_withdraw_collateral(&who, lend_token_id, collateral)?; Ok(().into()) } @@ -1254,9 +1254,12 @@ impl Pallet { Ok(total_borrow_value) } - fn collateral_balance(asset_id: AssetIdOf, ptoken_amount: BalanceOf) -> Result, DispatchError> { + fn collateral_balance( + asset_id: AssetIdOf, + lend_token_amount: BalanceOf, + ) -> Result, DispatchError> { let exchange_rate = Self::exchange_rate_stored(asset_id)?; - let underlying_amount = Self::calc_underlying_amount(ptoken_amount, exchange_rate)?; + let underlying_amount = Self::calc_underlying_amount(lend_token_amount, exchange_rate)?; let market = Self::market(asset_id)?; let effects_amount = market.collateral_factor.mul_ceil(underlying_amount); @@ -1265,18 +1268,18 @@ impl Pallet { fn collateral_amount_value( asset_id: AssetIdOf, - ptoken_amount: BalanceOf, + lend_token_amount: BalanceOf, ) -> Result { - let effects_amount = Self::collateral_balance(asset_id, ptoken_amount)?; + let effects_amount = Self::collateral_balance(asset_id, lend_token_amount)?; Self::get_asset_value(asset_id, effects_amount) } fn collateral_asset_value(supplier: &T::AccountId, asset_id: AssetIdOf) -> Result { - let ptoken_id = Self::ptoken_id(asset_id)?; - if !AccountDeposits::::contains_key(ptoken_id, supplier) { + let lend_token_id = Self::lend_token_id(asset_id)?; + if !AccountDeposits::::contains_key(lend_token_id, supplier) { return Ok(FixedU128::zero()); } - let deposits = Self::account_deposits(ptoken_id, supplier); + let deposits = Self::account_deposits(lend_token_id, supplier); if deposits.is_zero() { return Ok(FixedU128::zero()); } @@ -1287,11 +1290,11 @@ impl Pallet { borrower: &T::AccountId, asset_id: AssetIdOf, ) -> Result { - let ptoken_id = Self::ptoken_id(asset_id)?; - if !AccountDeposits::::contains_key(ptoken_id, borrower) { + let lend_token_id = Self::lend_token_id(asset_id)?; + if !AccountDeposits::::contains_key(lend_token_id, borrower) { return Ok(FixedU128::zero()); } - let deposits = Self::account_deposits(ptoken_id, borrower); + let deposits = Self::account_deposits(lend_token_id, borrower); if deposits.is_zero() { return Ok(FixedU128::zero()); } @@ -1326,7 +1329,7 @@ impl Pallet { } /// Checks if the redeemer should be allowed to redeem tokens in given market. - /// Takes into account both `free` and `locked` (i.e. deposited as collateral) ptokens. + /// Takes into account both `free` and `locked` (i.e. deposited as collateral) lend_tokens. fn redeem_allowed(asset_id: AssetIdOf, redeemer: &T::AccountId, voucher_amount: BalanceOf) -> DispatchResult { log::trace!( target: "loans::redeem_allowed", @@ -1335,8 +1338,8 @@ impl Pallet { redeemer, voucher_amount, ); - let ptoken_id = Self::ptoken_id(asset_id)?; - if Self::balance(ptoken_id, redeemer) < voucher_amount { + let lend_token_id = Self::lend_token_id(asset_id)?; + if Self::balance(lend_token_id, redeemer) < voucher_amount { return Err(Error::::InsufficientDeposit.into()); } @@ -1346,7 +1349,7 @@ impl Pallet { Self::ensure_enough_cash(asset_id, redeem_amount)?; // Ensure that withdrawing deposited collateral doesn't leave the user undercollateralized. - let collateral_amount = voucher_amount.saturating_sub(Self::free_ptokens(asset_id, redeemer)?.amount()); + let collateral_amount = voucher_amount.saturating_sub(Self::free_lend_tokens(asset_id, redeemer)?.amount()); let collateral_underlying_amount = Self::calc_underlying_amount(collateral_amount, exchange_rate)?; let market = Self::market(asset_id)?; let effects_amount = market.collateral_factor.mul_ceil(collateral_underlying_amount); @@ -1376,14 +1379,14 @@ impl Pallet { let exchange_rate = Self::exchange_rate_stored(asset_id)?; let redeem_amount = Self::calc_underlying_amount(voucher_amount, exchange_rate)?; - let ptoken_id = Self::ptoken_id(asset_id)?; - let ptoken_amount: Amount = Amount::new(voucher_amount, ptoken_id); + let lend_token_id = Self::lend_token_id(asset_id)?; + let lend_token_amount: Amount = Amount::new(voucher_amount, lend_token_id); // Need to first `lock_on` in order to `burn_from` because: - // 1) only the `free` ptokens are redeemable + // 1) only the `free` lend_tokens are redeemable // 2) `burn_from` can only be called on locked tokens. - ptoken_amount.lock_on(who)?; - ptoken_amount.burn_from(who)?; + lend_token_amount.lock_on(who)?; + lend_token_amount.burn_from(who)?; let amount_to_transfer: Amount = Amount::new(redeem_amount, asset_id); amount_to_transfer @@ -1547,8 +1550,8 @@ impl Pallet { } Self::liquidate_borrow_allowed(&borrower, liquidation_asset_id, repay_amount, &market)?; - let ptoken_id = Self::ptoken_id(collateral_asset_id)?; - let deposits = AccountDeposits::::get(ptoken_id, &borrower); + let lend_token_id = Self::lend_token_id(collateral_asset_id)?; + let deposits = AccountDeposits::::get(lend_token_id, &borrower); let exchange_rate = Self::exchange_rate_stored(collateral_asset_id)?; let borrower_deposit_amount = exchange_rate .checked_mul_int(deposits) @@ -1652,7 +1655,7 @@ impl Pallet { // 3.the liquidator will receive voucher token from borrower let exchange_rate = Self::exchange_rate_stored(collateral_asset_id)?; let collateral_amount = Self::calc_collateral_amount(collateral_underlying_amount, exchange_rate)?; - let ptoken_id = Self::ptoken_id(collateral_asset_id)?; + let lend_token_id = Self::lend_token_id(collateral_asset_id)?; let incentive_reserved = market.liquidate_incentive_reserved_factor.mul_floor( FixedU128::from_inner(collateral_amount) .checked_div(&market.liquidate_incentive) @@ -1661,18 +1664,18 @@ impl Pallet { ); // Unlock this balance to make it transferrable - let amount_to_liquidate: Amount = Amount::new(collateral_amount, ptoken_id); + let amount_to_liquidate: Amount = Amount::new(collateral_amount, lend_token_id); amount_to_liquidate.unlock_on(borrower)?; // increase liquidator's voucher_balance let liquidator_amount_u128 = collateral_amount .checked_sub(incentive_reserved) .ok_or(ArithmeticError::Underflow)?; - let liquidator_amount: Amount = Amount::new(liquidator_amount_u128, ptoken_id); + let liquidator_amount: Amount = Amount::new(liquidator_amount_u128, lend_token_id); liquidator_amount.transfer(borrower, liquidator)?; // increase reserve's voucher_balance - let incentive_reserved_amount: Amount = Amount::new(incentive_reserved, ptoken_id); + let incentive_reserved_amount: Amount = Amount::new(incentive_reserved, lend_token_id); incentive_reserved_amount.transfer(borrower, &Self::incentive_reward_account_id()?)?; Self::deposit_event(Event::::LiquidatedBorrow( @@ -1731,16 +1734,19 @@ impl Pallet { Ok(()) } - // Ensures a given `ptoken_id` is unique in `Markets` and `UnderlyingAssetId`. - fn ensure_ptoken(ptoken_id: CurrencyId) -> DispatchResult { - // The ptoken id is unique, cannot be repeated + // Ensures a given `lend_token_id` is unique in `Markets` and `UnderlyingAssetId`. + fn ensure_lend_token(lend_token_id: CurrencyId) -> DispatchResult { + // The lend_token id is unique, cannot be repeated ensure!( - !UnderlyingAssetId::::contains_key(ptoken_id), - Error::::InvalidPtokenId + !UnderlyingAssetId::::contains_key(lend_token_id), + Error::::InvalidLendTokenId ); - // The ptoken id should not be the same as the id of any asset in markets - ensure!(!Markets::::contains_key(ptoken_id), Error::::InvalidPtokenId); + // The lend_token id should not be the same as the id of any asset in markets + ensure!( + !Markets::::contains_key(lend_token_id), + Error::::InvalidLendTokenId + ); Ok(()) } @@ -1785,16 +1791,19 @@ impl Pallet { as MultiCurrency>::total_balance(asset_id, who) } - /// Total supply of lending tokens (ptokens), given the underlying + /// Total supply of lending tokens (lend_tokens), given the underlying pub fn total_supply(asset_id: AssetIdOf) -> Result, DispatchError> { - let ptoken_id = Self::ptoken_id(asset_id)?; - Ok(orml_tokens::Pallet::::total_issuance(ptoken_id)) + let lend_token_id = Self::lend_token_id(asset_id)?; + Ok(orml_tokens::Pallet::::total_issuance(lend_token_id)) } - /// Free lending tokens (ptokens) of an account, given the underlying - pub fn free_ptokens(asset_id: AssetIdOf, account_id: &T::AccountId) -> Result, DispatchError> { - let ptoken_id = Self::ptoken_id(asset_id)?; - let amount = Amount::new(orml_tokens::Pallet::::free_balance(ptoken_id, account_id), ptoken_id); + /// Free lending tokens (lend_tokens) of an account, given the underlying + pub fn free_lend_tokens(asset_id: AssetIdOf, account_id: &T::AccountId) -> Result, DispatchError> { + let lend_token_id = Self::lend_token_id(asset_id)?; + let amount = Amount::new( + orml_tokens::Pallet::::free_balance(lend_token_id, account_id), + lend_token_id, + ); Ok(amount) } @@ -1858,12 +1867,12 @@ impl Pallet { Markets::::iter().filter(|(_, market)| market.state == MarketState::Active) } - // Returns the ptoken_id of the related asset + // Returns the lend_token_id of the related asset // // Returns `Err` if market does not exist. - pub fn ptoken_id(asset_id: AssetIdOf) -> Result, DispatchError> { + pub fn lend_token_id(asset_id: AssetIdOf) -> Result, DispatchError> { if let Ok(market) = Self::market(asset_id) { - Ok(market.ptoken_id) + Ok(market.lend_token_id) } else { Err(Error::::MarketDoesNotExist.into()) } @@ -1897,9 +1906,9 @@ impl LoansTrait, AccountIdOf, BalanceOf, Amount let amount_to_transfer: Amount = Amount::new(amount, asset_id); amount_to_transfer.transfer(supplier, &Self::account_id())?; - let ptoken_id = Self::ptoken_id(asset_id)?; - let ptokens_to_mint: Amount = Amount::new(voucher_amount, ptoken_id); - ptokens_to_mint.mint_to(supplier)?; + let lend_token_id = Self::lend_token_id(asset_id)?; + let lend_tokens_to_mint: Amount = Amount::new(voucher_amount, lend_token_id); + lend_tokens_to_mint.mint_to(supplier)?; Self::deposit_event(Event::::Deposited(supplier.clone(), asset_id, amount)); Ok(()) @@ -1940,25 +1949,25 @@ impl LoansTrait, AccountIdOf, BalanceOf, Amount asset_id: AssetIdOf, amount: BalanceOf, ) -> Result<(), DispatchError> { - let ptoken_amount: Amount = Amount::new(amount, asset_id); - // If the given asset_id is not a valid ptoken, fetching the underlying will fail - let underlying_id = Self::underlying_id(ptoken_amount.currency())?; + let lend_token_amount: Amount = Amount::new(amount, asset_id); + // If the given asset_id is not a valid lend_token, fetching the underlying will fail + let underlying_id = Self::underlying_id(lend_token_amount.currency())?; Self::ensure_active_market(underlying_id)?; // Will fail if supplier has insufficient free tokens - ptoken_amount.lock_on(supplier)?; + lend_token_amount.lock_on(supplier)?; // Increase the amount of collateral deposited - let deposit = Self::account_deposits(ptoken_amount.currency(), supplier); + let deposit = Self::account_deposits(lend_token_amount.currency(), supplier); let new_deposit = deposit - .checked_add(ptoken_amount.amount()) + .checked_add(lend_token_amount.amount()) .ok_or(ArithmeticError::Overflow)?; - AccountDeposits::::insert(ptoken_amount.currency(), supplier, new_deposit); + AccountDeposits::::insert(lend_token_amount.currency(), supplier, new_deposit); Self::deposit_event(Event::::DepositCollateral( supplier.clone(), - ptoken_amount.currency(), - ptoken_amount.amount(), + lend_token_amount.currency(), + lend_token_amount.amount(), )); Ok(()) } @@ -1968,13 +1977,13 @@ impl LoansTrait, AccountIdOf, BalanceOf, Amount asset_id: AssetIdOf, amount: BalanceOf, ) -> Result<(), DispatchError> { - let ptoken_amount: Amount = Amount::new(amount, asset_id); - // If the given asset_id is not a valid ptoken, fetching the underlying will fail - let underlying_id = Self::underlying_id(ptoken_amount.currency())?; + let lend_token_amount: Amount = Amount::new(amount, asset_id); + // If the given asset_id is not a valid lend_token, fetching the underlying will fail + let underlying_id = Self::underlying_id(lend_token_amount.currency())?; Self::ensure_active_market(underlying_id)?; let total_collateral_value = Self::total_collateral_value(supplier)?; - let collateral_amount_value = Self::collateral_amount_value(underlying_id, ptoken_amount.amount())?; + let collateral_amount_value = Self::collateral_amount_value(underlying_id, lend_token_amount.amount())?; let total_borrowed_value = Self::total_borrowed_value(supplier)?; log::trace!( target: "loans::collateral_asset", @@ -1992,13 +2001,13 @@ impl LoansTrait, AccountIdOf, BalanceOf, Amount return Err(Error::::InsufficientLiquidity.into()); } - ptoken_amount.unlock_on(supplier)?; + lend_token_amount.unlock_on(supplier)?; // Decrease the amount of collateral deposited AccountDeposits::::try_mutate_exists(asset_id, supplier, |deposits| -> DispatchResult { let d = deposits .unwrap_or_default() - .checked_sub(ptoken_amount.amount()) + .checked_sub(lend_token_amount.amount()) .ok_or(ArithmeticError::Underflow)?; if d.is_zero() { // remove deposits storage if zero balance @@ -2011,8 +2020,8 @@ impl LoansTrait, AccountIdOf, BalanceOf, Amount Self::deposit_event(Event::::WithdrawCollateral( supplier.clone(), - ptoken_amount.currency(), - ptoken_amount.amount(), + lend_token_amount.currency(), + lend_token_amount.amount(), )); Ok(()) } @@ -2041,23 +2050,23 @@ impl LoansTrait, AccountIdOf, BalanceOf, Amount Ok(()) } - fn recompute_underlying_amount(ptokens: &Amount) -> Result, DispatchError> { + fn recompute_underlying_amount(lend_tokens: &Amount) -> Result, DispatchError> { // This function could be called externally to this pallet, with interest // possibly not having accrued for a few blocks. This would result in using an // outdated exchange rate. Call `accrue_interest` to avoid this. - let underlying_id = Self::underlying_id(ptokens.currency())?; + let underlying_id = Self::underlying_id(lend_tokens.currency())?; Self::ensure_active_market(underlying_id)?; Self::accrue_interest(underlying_id)?; let exchange_rate = Self::exchange_rate_stored(underlying_id)?; - let underlying_amount = Self::calc_underlying_amount(ptokens.amount(), exchange_rate)?; + let underlying_amount = Self::calc_underlying_amount(lend_tokens.amount(), exchange_rate)?; Ok(Amount::new(underlying_amount, underlying_id)) } // Returns a stored asset_id // - // Returns `Err` if asset_id does not exist, it also means that ptoken_id is invalid. - fn underlying_id(ptoken_id: AssetIdOf) -> Result, DispatchError> { - UnderlyingAssetId::::try_get(ptoken_id).map_err(|_err| Error::::InvalidPtokenId.into()) + // Returns `Err` if asset_id does not exist, it also means that lend_token_id is invalid. + fn underlying_id(lend_token_id: AssetIdOf) -> Result, DispatchError> { + UnderlyingAssetId::::try_get(lend_token_id).map_err(|_err| Error::::InvalidLendTokenId.into()) } fn recompute_collateral_amount(underlying: &Amount) -> Result, DispatchError> { @@ -2068,8 +2077,8 @@ impl LoansTrait, AccountIdOf, BalanceOf, Amount Self::accrue_interest(underlying.currency())?; let exchange_rate = Self::exchange_rate_stored(underlying.currency())?; let underlying_amount = Self::calc_collateral_amount(underlying.amount(), exchange_rate)?; - let ptoken_id = Self::ptoken_id(underlying.currency())?; - Ok(Amount::new(underlying_amount, ptoken_id)) + let lend_token_id = Self::lend_token_id(underlying.currency())?; + Ok(Amount::new(underlying_amount, lend_token_id)) } } diff --git a/crates/loans/src/mock.rs b/crates/loans/src/mock.rs index 3697ab6232..75ed1544e5 100644 --- a/crates/loans/src/mock.rs +++ b/crates/loans/src/mock.rs @@ -30,7 +30,7 @@ use frame_system::EnsureRoot; use mocktopus::{macros::mockable, mocking::*}; use orml_traits::{parameter_type_with_key, DataFeeder, DataProvider, DataProviderExtended}; use primitives::{ - CurrencyId::{ForeignAsset, PToken, Token}, + CurrencyId::{ForeignAsset, LendToken, Token}, Moment, PriceDetail, DOT, IBTC, INTR, KBTC, KINT, KSM, }; use sp_core::H256; @@ -275,11 +275,11 @@ impl Config for Test { type RewardAssetId = RewardAssetId; } -pub const CDOT: CurrencyId = PToken(1); -pub const CKINT: CurrencyId = PToken(2); -pub const CKSM: CurrencyId = PToken(3); -pub const CKBTC: CurrencyId = PToken(4); -pub const CIBTC: CurrencyId = PToken(5); +pub const LEND_DOT: CurrencyId = LendToken(1); +pub const LEND_KINT: CurrencyId = LendToken(2); +pub const LEND_KSM: CurrencyId = LendToken(3); +pub const LEND_KBTC: CurrencyId = LendToken(4); +pub const LEND_IBTC: CurrencyId = LendToken(5); pub const DEFAULT_MAX_EXCHANGE_RATE: u128 = 1_000_000_000_000_000_000; // 1 pub const DEFAULT_MIN_EXCHANGE_RATE: u128 = 20_000_000_000_000_000; // 0.02 @@ -314,17 +314,17 @@ pub(crate) fn new_test_ext() -> sp_io::TestExternalities { MockPriceFeeder::set_price(Token(KBTC), 1.into()); MockPriceFeeder::set_price(Token(DOT), 1.into()); MockPriceFeeder::set_price(Token(KSM), 1.into()); - MockPriceFeeder::set_price(CDOT, 1.into()); + MockPriceFeeder::set_price(LEND_DOT, 1.into()); // Init Markets - Loans::add_market(Origin::root(), Token(DOT), market_mock(CDOT)).unwrap(); + Loans::add_market(Origin::root(), Token(DOT), market_mock(LEND_DOT)).unwrap(); Loans::activate_market(Origin::root(), Token(DOT)).unwrap(); - Loans::add_market(Origin::root(), Token(KINT), market_mock(CKINT)).unwrap(); + Loans::add_market(Origin::root(), Token(KINT), market_mock(LEND_KINT)).unwrap(); Loans::activate_market(Origin::root(), Token(KINT)).unwrap(); - Loans::add_market(Origin::root(), Token(KSM), market_mock(CKSM)).unwrap(); + Loans::add_market(Origin::root(), Token(KSM), market_mock(LEND_KSM)).unwrap(); Loans::activate_market(Origin::root(), Token(KSM)).unwrap(); - Loans::add_market(Origin::root(), Token(KBTC), market_mock(CKBTC)).unwrap(); + Loans::add_market(Origin::root(), Token(KBTC), market_mock(LEND_KBTC)).unwrap(); Loans::activate_market(Origin::root(), Token(KBTC)).unwrap(); - Loans::add_market(Origin::root(), Token(IBTC), market_mock(CIBTC)).unwrap(); + Loans::add_market(Origin::root(), Token(IBTC), market_mock(LEND_IBTC)).unwrap(); Loans::activate_market(Origin::root(), Token(IBTC)).unwrap(); System::set_block_number(0); @@ -376,7 +376,7 @@ pub fn million_unit(d: u128) -> u128 { unit(d) * 10_u128.pow(6) } -pub const fn market_mock(ptoken_id: CurrencyId) -> Market { +pub const fn market_mock(lend_token_id: CurrencyId) -> Market { Market { close_factor: Ratio::from_percent(50), collateral_factor: Ratio::from_percent(50), @@ -393,7 +393,7 @@ pub const fn market_mock(ptoken_id: CurrencyId) -> Market { reserve_factor: Ratio::from_percent(15), supply_cap: 1_000_000_000_000_000_000_000u128, // set to 1B borrow_cap: 1_000_000_000_000_000_000_000u128, // set to 1B - ptoken_id, + lend_token_id, } } diff --git a/crates/loans/src/tests.rs b/crates/loans/src/tests.rs index 9d739b4c06..628bf45846 100644 --- a/crates/loans/src/tests.rs +++ b/crates/loans/src/tests.rs @@ -17,9 +17,9 @@ mod edge_cases; mod interest_rate; +mod lend_tokens; mod liquidate_borrow; mod market; -mod ptokens; use currency::Amount; use frame_support::{assert_noop, assert_ok}; @@ -33,7 +33,7 @@ use primitives::{CurrencyId::Token, DOT as DOT_CURRENCY, IBTC, KBTC, KINT, KSM a use crate::{ mock::*, - tests::ptokens::{free_balance, reserved_balance}, + tests::lend_tokens::{free_balance, reserved_balance}, }; // For the time being, do a quick reassignment here to avoid changing all the tests @@ -41,7 +41,7 @@ use crate::{ const DOT: CurrencyId = Token(DOT_CURRENCY); const KSM: CurrencyId = Token(KSM_CURRENCY); const USDT: CurrencyId = Token(KBTC); -const CDOT_6_13: CurrencyId = Token(IBTC); +const LEND_DOT_6_13: CurrencyId = Token(IBTC); const HKO: CurrencyId = Token(KINT); #[test] @@ -101,7 +101,8 @@ fn loans_native_token_works() { // HKO borrow balance: borrow - repay = 500 - 400 = 100 // HKO: cash - deposit + borrow - repay = 1000 - 1000 + 500 - 400 = 100 assert_eq!( - Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(HKO).unwrap(), DAVE)), + Loans::exchange_rate(HKO) + .saturating_mul_int(Loans::account_deposits(Loans::lend_token_id(HKO).unwrap(), DAVE)), unit(1000) ); let borrow_snapshot = Loans::account_borrows(HKO, DAVE); @@ -120,7 +121,7 @@ fn mint_works() { // DOT collateral: deposit = 100 // DOT: cash - deposit = 1000 - 100 = 900 assert_eq!( - Loans::exchange_rate(DOT).saturating_mul_int(Loans::free_ptokens(DOT, &ALICE).unwrap().amount()), + Loans::exchange_rate(DOT).saturating_mul_int(Loans::free_lend_tokens(DOT, &ALICE).unwrap().amount()), unit(100) ); assert_eq!(Tokens::balance(DOT, &ALICE), unit(900),); @@ -161,7 +162,7 @@ fn mint_must_return_err_when_overflows_occur() { // Assume a misconfiguration occurs MinExchangeRate::::put(Rate::zero()); - // There is no cash in the market. To compute how many ptokens this first deposit + // There is no cash in the market. To compute how many lend_tokens this first deposit // should mint, the `MinExchangeRate` is used, which has been misconfigured and // set to zero (default value for the type). The extrinsic should fail. assert_noop!( @@ -204,13 +205,13 @@ fn supply_cap_below_current_volume() { Error::::SupplyCapacityExceeded ); - let ptokens = Loans::free_ptokens(KSM, &ALICE).unwrap(); + let lend_tokens = Loans::free_lend_tokens(KSM, &ALICE).unwrap(); // Redeem enough to be below the cap assert_ok!(Loans::redeem( Origin::signed(ALICE), KSM, - Loans::recompute_underlying_amount(&ptokens).unwrap().amount() - (new_supply_cap / 2) + Loans::recompute_underlying_amount(&lend_tokens).unwrap().amount() - (new_supply_cap / 2) )); // Can now supply @@ -261,7 +262,7 @@ fn redeem_works() { // DOT collateral: deposit - redeem = 100 - 20 = 80 // DOT: cash - deposit + redeem = 1000 - 100 + 20 = 920 assert_eq!( - Loans::exchange_rate(DOT).saturating_mul_int(Tokens::balance(Loans::ptoken_id(DOT).unwrap(), &ALICE)), + Loans::exchange_rate(DOT).saturating_mul_int(Tokens::balance(Loans::lend_token_id(DOT).unwrap(), &ALICE)), unit(80) ); assert_eq!(Tokens::balance(DOT, &ALICE), unit(920),); @@ -348,12 +349,12 @@ fn redeem_all_works() { // DOT collateral: deposit - redeem = 100 - 100 = 0 assert_eq!( Loans::exchange_rate(DOT) - .saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(DOT).unwrap(), ALICE)), + .saturating_mul_int(Loans::account_deposits(Loans::lend_token_id(DOT).unwrap(), ALICE)), 0, ); assert_eq!(Tokens::balance(DOT, &ALICE), unit(1000),); assert!(!AccountDeposits::::contains_key(DOT, &ALICE)); - assert_eq!(Tokens::balance(CDOT, &ALICE), 0); + assert_eq!(Tokens::balance(LEND_DOT, &ALICE), 0); }) } @@ -441,8 +442,8 @@ fn borrow_cap_below_current_volume() { #[test] fn get_account_liquidity_works() { new_test_ext().execute_with(|| { - Loans::mint(Origin::signed(ALICE), CDOT_6_13, unit(200)).unwrap(); - Loans::deposit_all_collateral(Origin::signed(ALICE), CDOT_6_13).unwrap(); + Loans::mint(Origin::signed(ALICE), LEND_DOT_6_13, unit(200)).unwrap(); + Loans::deposit_all_collateral(Origin::signed(ALICE), LEND_DOT_6_13).unwrap(); let (liquidity, _, _, _) = Loans::get_account_liquidity(&ALICE).unwrap(); @@ -456,8 +457,8 @@ fn get_account_liquidation_threshold_liquidity_works() { Loans::mint(Origin::signed(BOB), DOT, unit(200)).unwrap(); Loans::mint(Origin::signed(BOB), KSM, unit(200)).unwrap(); - Loans::mint(Origin::signed(ALICE), CDOT_6_13, unit(200)).unwrap(); - Loans::deposit_all_collateral(Origin::signed(ALICE), CDOT_6_13).unwrap(); + Loans::mint(Origin::signed(ALICE), LEND_DOT_6_13, unit(200)).unwrap(); + Loans::deposit_all_collateral(Origin::signed(ALICE), LEND_DOT_6_13).unwrap(); Loans::mint(Origin::signed(ALICE), USDT, unit(200)).unwrap(); Loans::deposit_all_collateral(Origin::signed(ALICE), USDT).unwrap(); @@ -491,7 +492,7 @@ fn borrow_works() { // DOT: cash - deposit + borrow = 1000 - 200 + 100 = 900 assert_eq!( Loans::exchange_rate(DOT) - .saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(DOT).unwrap(), ALICE)), + .saturating_mul_int(Loans::account_deposits(Loans::lend_token_id(DOT).unwrap(), ALICE)), unit(200) ); let borrow_snapshot = Loans::account_borrows(DOT, ALICE); @@ -517,7 +518,7 @@ fn repay_borrow_works() { // DOT: cash - deposit + borrow - repay = 1000 - 200 + 100 - 30 = 870 assert_eq!( Loans::exchange_rate(DOT) - .saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(DOT).unwrap(), ALICE)), + .saturating_mul_int(Loans::account_deposits(Loans::lend_token_id(DOT).unwrap(), ALICE)), unit(200) ); let borrow_snapshot = Loans::account_borrows(DOT, ALICE); @@ -548,7 +549,7 @@ fn repay_borrow_all_works() { assert_eq!(Tokens::balance(DOT, &ALICE), unit(800),); assert_eq!( Loans::exchange_rate(DOT) - .saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(DOT).unwrap(), ALICE)), + .saturating_mul_int(Loans::account_deposits(Loans::lend_token_id(DOT).unwrap(), ALICE)), unit(200) ); let borrow_snapshot = Loans::account_borrows(KSM, ALICE); @@ -563,23 +564,23 @@ fn collateral_asset_works() { // No collateral assets // Deposit 200 DOT as collateral assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, 200)); - let ptoken_id = Loans::ptoken_id(DOT).unwrap(); - // No ptokens deposited as collateral + let lend_token_id = Loans::lend_token_id(DOT).unwrap(); + // No lend_tokens deposited as collateral assert_eq!( - Loans::account_deposits(ptoken_id, ALICE).eq(&reserved_balance(ptoken_id, &ALICE)), + Loans::account_deposits(lend_token_id, ALICE).eq(&reserved_balance(lend_token_id, &ALICE)), true ); - assert_eq!(free_balance(ptoken_id, &ALICE), 200 * 50); - assert_eq!(reserved_balance(ptoken_id, &ALICE), 0); + assert_eq!(free_balance(lend_token_id, &ALICE), 200 * 50); + assert_eq!(reserved_balance(lend_token_id, &ALICE), 0); assert_ok!(Loans::deposit_all_collateral(Origin::signed(ALICE), DOT)); - // Non-zero ptokens deposited as collateral + // Non-zero lend_tokens deposited as collateral assert_eq!( - Loans::account_deposits(ptoken_id, ALICE).eq(&reserved_balance(ptoken_id, &ALICE)), + Loans::account_deposits(lend_token_id, ALICE).eq(&reserved_balance(lend_token_id, &ALICE)), true ); - assert_eq!(free_balance(ptoken_id, &ALICE), 0); - assert_eq!(reserved_balance(ptoken_id, &ALICE), 200 * 50); + assert_eq!(free_balance(lend_token_id, &ALICE), 0); + assert_eq!(reserved_balance(lend_token_id, &ALICE), 200 * 50); // Borrow 100 DOT base on the collateral of 200 DOT assert_ok!(Loans::borrow(Origin::signed(ALICE), DOT, 100)); @@ -591,11 +592,11 @@ fn collateral_asset_works() { assert_ok!(Loans::repay_borrow_all(Origin::signed(ALICE), DOT)); assert_ok!(Loans::withdraw_all_collateral(Origin::signed(ALICE), DOT)); assert_eq!( - Loans::account_deposits(ptoken_id, ALICE), - reserved_balance(ptoken_id, &ALICE) + Loans::account_deposits(lend_token_id, ALICE), + reserved_balance(lend_token_id, &ALICE) ); - assert_eq!(free_balance(ptoken_id, &ALICE), 200 * 50); - assert_eq!(reserved_balance(ptoken_id, &ALICE), 0); + assert_eq!(free_balance(lend_token_id, &ALICE), 200 * 50); + assert_eq!(reserved_balance(lend_token_id, &ALICE), 0); }) } diff --git a/crates/loans/src/tests/edge_cases.rs b/crates/loans/src/tests/edge_cases.rs index 2cbf6a4807..30ec7dbc6d 100644 --- a/crates/loans/src/tests/edge_cases.rs +++ b/crates/loans/src/tests/edge_cases.rs @@ -50,8 +50,10 @@ fn repay_borrow_all_no_underflow() { assert_eq!(Tokens::balance(Token(KSM), &ALICE), unit(800) - 5); assert_eq!( - Loans::exchange_rate(Token(DOT)) - .saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(Token(KSM)).unwrap(), ALICE)), + Loans::exchange_rate(Token(DOT)).saturating_mul_int(Loans::account_deposits( + Loans::lend_token_id(Token(KSM)).unwrap(), + ALICE + )), unit(200) ); diff --git a/crates/loans/src/tests/interest_rate.rs b/crates/loans/src/tests/interest_rate.rs index 6b2b7a82cb..ea6d421096 100644 --- a/crates/loans/src/tests/interest_rate.rs +++ b/crates/loans/src/tests/interest_rate.rs @@ -161,18 +161,18 @@ fn accrue_interest_works_after_redeem() { let amount_to_redeem = unit(10); // First, withdraw the amount to redeem from the deposited collateral let exchange_rate = Loans::exchange_rate_stored(Token(DOT)).unwrap(); - let ptoken_amount = Loans::calc_collateral_amount(amount_to_redeem, exchange_rate).unwrap(); + let lend_token_amount = Loans::calc_collateral_amount(amount_to_redeem, exchange_rate).unwrap(); assert_ok!(Loans::withdraw_collateral( Origin::signed(ALICE), - Loans::ptoken_id(Token(DOT)).unwrap(), - ptoken_amount + Loans::lend_token_id(Token(DOT)).unwrap(), + lend_token_amount )); // Then the amount can be redeemed assert_ok!(Loans::redeem(Origin::signed(ALICE), Token(DOT), amount_to_redeem)); assert_eq!(Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000004756468797),); assert_eq!( Loans::exchange_rate(Token(DOT)) - .saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(Token(DOT)).unwrap(), BOB)), + .saturating_mul_int(Loans::account_deposits(Loans::lend_token_id(Token(DOT)).unwrap(), BOB)), 0, ); assert_eq!(Tokens::balance(Token(DOT), &ALICE), 819999999999999); @@ -194,7 +194,7 @@ fn accrue_interest_works_after_redeem_all() { assert_eq!(Loans::borrow_index(Token(DOT)), Rate::from_inner(1000000004669977168),); assert_eq!( Loans::exchange_rate(Token(DOT)) - .saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(Token(DOT)).unwrap(), BOB)), + .saturating_mul_int(Loans::account_deposits(Loans::lend_token_id(Token(DOT)).unwrap(), BOB)), 0, ); assert_eq!(Tokens::balance(Token(DOT), &BOB), 1000000000003608); @@ -289,7 +289,7 @@ fn accrue_interest_works_after_recompute_underlying_amount() { assert_eq!(Loans::borrow_index(Token(KSM)), Rate::one()); TimestampPallet::set_timestamp(12000); assert_ok!(Loans::recompute_underlying_amount( - &Loans::free_ptokens(Token(KSM), &ALICE).unwrap() + &Loans::free_lend_tokens(Token(KSM), &ALICE).unwrap() )); assert_eq!(Loans::borrow_index(Token(KSM)), Rate::from_inner(1000000008561643835),); }) diff --git a/crates/loans/src/tests/ptokens.rs b/crates/loans/src/tests/lend_tokens.rs similarity index 82% rename from crates/loans/src/tests/ptokens.rs rename to crates/loans/src/tests/lend_tokens.rs index d2fcae2f47..fcce4e900e 100644 --- a/crates/loans/src/tests/ptokens.rs +++ b/crates/loans/src/tests/lend_tokens.rs @@ -1,5 +1,7 @@ use crate::{ - mock::{market_mock, new_test_ext, AccountId, Loans, Origin, Test, Tokens, ALICE, CKBTC, CKINT, CKSM, DAVE}, + mock::{ + market_mock, new_test_ext, AccountId, Loans, Origin, Test, Tokens, ALICE, DAVE, LEND_KBTC, LEND_KINT, LEND_KSM, + }, tests::unit, Config, Error, }; @@ -10,16 +12,16 @@ use frame_support::{ use orml_traits::{MultiCurrency, MultiReservableCurrency}; use primitives::{ Balance, - CurrencyId::{self, ForeignAsset, PToken, Token}, + CurrencyId::{self, ForeignAsset, LendToken, Token}, KBTC, KINT, KSM as KSM_CURRENCY, }; use sp_runtime::{FixedPointNumber, TokenError}; const HKO: CurrencyId = Token(KINT); const KSM: CurrencyId = Token(KSM_CURRENCY); -const PHKO: CurrencyId = CKINT; -const PKSM: CurrencyId = CKSM; -const PUSDT: CurrencyId = CKBTC; +const PHKO: CurrencyId = LEND_KINT; +const PKSM: CurrencyId = LEND_KSM; +const PUSDT: CurrencyId = LEND_KBTC; const USDT: CurrencyId = Token(KBTC); pub fn free_balance(currency_id: CurrencyId, account_id: &AccountId) -> Balance { @@ -67,19 +69,20 @@ fn trait_inspect_methods_works() { assert_ok!(Loans::borrow(Origin::signed(DAVE), HKO, unit(25))); assert_eq!( - Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(HKO).unwrap(), DAVE)), + Loans::exchange_rate(HKO) + .saturating_mul_int(Loans::account_deposits(Loans::lend_token_id(HKO).unwrap(), DAVE)), unit(100) ); // DAVE Deposit 100 HKO, Borrow 25 HKO // Liquidity HKO 25 - // Formula: ptokens = liquidity / price(1) / collateral(0.5) / exchange_rate(0.02) + // Formula: lend_tokens = liquidity / price(1) / collateral(0.5) / exchange_rate(0.02) assert_eq!(Loans::reducible_balance(PHKO, &DAVE, true), unit(25) * 2 * 50); // Multi-asset case, additional deposit USDT // DAVE Deposit 100 HKO, 50 USDT, Borrow 25 HKO // Liquidity HKO = 25, USDT = 25 - // ptokens = dollar(25 + 25) / 1 / 0.5 / 0.02 = dollar(50) * 100 + // lend_tokens = dollar(25 + 25) / 1 / 0.5 / 0.02 = dollar(50) * 100 assert_ok!(Loans::mint(Origin::signed(DAVE), USDT, unit(50))); assert_eq!(Tokens::balance(PUSDT, &DAVE), unit(50) * 50); // Check entries from orml-tokens directly @@ -108,24 +111,24 @@ fn trait_inspect_methods_works() { } #[test] -fn ptoken_unique_works() { +fn lend_token_unique_works() { new_test_ext().execute_with(|| { - // ptoken_id already exists in `UnderlyingAssetId` + // lend_token_id already exists in `UnderlyingAssetId` assert_noop!( Loans::add_market(Origin::root(), ForeignAsset(1000000), market_mock(PHKO)), - Error::::InvalidPtokenId + Error::::InvalidLendTokenId ); - // ptoken_id cannot as the same as the asset id in `Markets` + // lend_token_id cannot as the same as the asset id in `Markets` assert_noop!( Loans::add_market(Origin::root(), ForeignAsset(1000000), market_mock(KSM)), - Error::::InvalidPtokenId + Error::::InvalidLendTokenId ); }) } #[test] -fn transfer_ptoken_works() { +fn transfer_lend_token_works() { new_test_ext().execute_with(|| { // DAVE Deposit 100 HKO assert_ok!(Loans::mint(Origin::signed(DAVE), HKO, unit(100))); @@ -133,23 +136,23 @@ fn transfer_ptoken_works() { // DAVE HKO collateral: deposit = 100 // HKO: cash - deposit = 1000 - 100 = 900 assert_eq!( - Loans::exchange_rate(HKO).saturating_mul_int(Tokens::balance(Loans::ptoken_id(HKO).unwrap(), &DAVE)), + Loans::exchange_rate(HKO).saturating_mul_int(Tokens::balance(Loans::lend_token_id(HKO).unwrap(), &DAVE)), unit(100) ); // ALICE HKO collateral: deposit = 0 assert_eq!( - Loans::exchange_rate(HKO).saturating_mul_int(Tokens::balance(Loans::ptoken_id(HKO).unwrap(), &ALICE)), + Loans::exchange_rate(HKO).saturating_mul_int(Tokens::balance(Loans::lend_token_id(HKO).unwrap(), &ALICE)), unit(0) ); - // Transfer ptokens from DAVE to ALICE + // Transfer lend_tokens from DAVE to ALICE Loans::transfer(PHKO, &DAVE, &ALICE, unit(50) * 50, true).unwrap(); - // Loans::transfer_ptokens(Origin::signed(DAVE), ALICE, HKO, dollar(50) * 50).unwrap(); + // Loans::transfer_lend_tokens(Origin::signed(DAVE), ALICE, HKO, dollar(50) * 50).unwrap(); // DAVE HKO collateral: deposit = 50 assert_eq!( - Loans::exchange_rate(HKO).saturating_mul_int(Tokens::balance(Loans::ptoken_id(HKO).unwrap(), &DAVE)), + Loans::exchange_rate(HKO).saturating_mul_int(Tokens::balance(Loans::lend_token_id(HKO).unwrap(), &DAVE)), unit(50) ); // DAVE Redeem 51 HKO should cause InsufficientDeposit @@ -160,7 +163,7 @@ fn transfer_ptoken_works() { // ALICE HKO collateral: deposit = 50 assert_eq!( - Loans::exchange_rate(HKO).saturating_mul_int(Tokens::balance(Loans::ptoken_id(HKO).unwrap(), &ALICE)), + Loans::exchange_rate(HKO).saturating_mul_int(Tokens::balance(Loans::lend_token_id(HKO).unwrap(), &ALICE)), unit(50) ); // ALICE Redeem 50 HKO should be succeeded @@ -169,7 +172,7 @@ fn transfer_ptoken_works() { } #[test] -fn transfer_ptokens_under_collateral_does_not_work() { +fn transfer_lend_tokens_under_collateral_does_not_work() { new_test_ext().execute_with(|| { // DAVE Deposit 100 HKO assert_ok!(Loans::mint(Origin::signed(DAVE), HKO, unit(100))); @@ -187,9 +190,9 @@ fn transfer_ptokens_under_collateral_does_not_work() { // Repay 40 HKO assert_ok!(Loans::repay_borrow(Origin::signed(DAVE), HKO, unit(40))); - // Allowed to redeem 20 ptokens + // Allowed to redeem 20 lend_tokens assert_ok!(Loans::redeem_allowed(HKO, &DAVE, unit(20) * 50,)); - // Not allowed to transfer the same 20 ptokens because they are locked + // Not allowed to transfer the same 20 lend_tokens because they are locked assert_noop!( Loans::transfer(PHKO, &DAVE, &ALICE, unit(20) * 50, true), Error::::InsufficientCollateral @@ -210,7 +213,8 @@ fn transfer_ptokens_under_collateral_does_not_work() { // DAVE Borrow HKO = 0 + 50 - 40 = 10 // DAVE liquidity HKO = 80 * 0.5 - 10 = 30 assert_eq!( - Loans::exchange_rate(HKO).saturating_mul_int(Loans::account_deposits(Loans::ptoken_id(HKO).unwrap(), DAVE)), + Loans::exchange_rate(HKO) + .saturating_mul_int(Loans::account_deposits(Loans::lend_token_id(HKO).unwrap(), DAVE)), unit(80) ); // DAVE Borrow 31 HKO should cause InsufficientLiquidity @@ -222,11 +226,11 @@ fn transfer_ptokens_under_collateral_does_not_work() { // Assert ALICE Supply HKO 20 assert_eq!( - Loans::exchange_rate(HKO).saturating_mul_int(Tokens::balance(Loans::ptoken_id(HKO).unwrap(), &ALICE)), + Loans::exchange_rate(HKO).saturating_mul_int(Tokens::balance(Loans::lend_token_id(HKO).unwrap(), &ALICE)), unit(20) ); // ALICE Redeem 20 HKO should be succeeded - // Also means that transfer ptoken succeed + // Also means that transfer lend_token succeed assert_ok!(Loans::redeem_allowed(HKO, &ALICE, unit(20) * 50,)); }) } diff --git a/crates/loans/src/tests/liquidate_borrow.rs b/crates/loans/src/tests/liquidate_borrow.rs index 5850a8ec3e..4f2a721a74 100644 --- a/crates/loans/src/tests/liquidate_borrow.rs +++ b/crates/loans/src/tests/liquidate_borrow.rs @@ -56,9 +56,9 @@ fn deposit_of_borrower_must_be_collateral() { // Previously (in Parallel's original implementation), this extrinsic call used to // return a `DepositsAreNotCollateral` error. // However, because the collateral "toggle" has been removed, the extrinsic looks - // directly inside the `AccountDeposits` map, which no longer represents ptoken holdings - // but rather ptokens that have been locked as collateral. - // Since no KSM ptokens have been locked as collateral in this test, there will be zero + // directly inside the `AccountDeposits` map, which no longer represents lend_token holdings + // but rather lend_tokens that have been locked as collateral. + // Since no KSM lend_tokens have been locked as collateral in this test, there will be zero // collateral available for paying the liquidator, thus producing the error below. assert_noop!( Loans::liquidate_borrow(Origin::signed(BOB), ALICE, KSM, 10, DOT), @@ -105,14 +105,14 @@ fn full_workflow_works_as_expected() { // Bob DOT collateral: incentive = 110-(110/1.1*0.03)=107 assert_eq!(Tokens::balance(USDT, &ALICE), unit(800),); assert_eq!( - Loans::exchange_rate(USDT).saturating_mul_int(Tokens::balance(Loans::ptoken_id(USDT).unwrap(), &ALICE)), + Loans::exchange_rate(USDT).saturating_mul_int(Tokens::balance(Loans::lend_token_id(USDT).unwrap(), &ALICE)), unit(90), ); assert_eq!(Tokens::balance(KSM, &ALICE), unit(1100),); assert_eq!(Loans::account_borrows(KSM, ALICE).principal, unit(50)); assert_eq!(Tokens::balance(KSM, &BOB), unit(750)); assert_eq!( - Loans::exchange_rate(USDT).saturating_mul_int(Tokens::balance(Loans::ptoken_id(USDT).unwrap(), &BOB)), + Loans::exchange_rate(USDT).saturating_mul_int(Tokens::balance(Loans::lend_token_id(USDT).unwrap(), &BOB)), unit(107), ); // 3 dollar reserved in our incentive reward account @@ -120,7 +120,7 @@ fn full_workflow_works_as_expected() { println!("incentive reserve account:{:?}", incentive_reward_account.clone()); assert_eq!( Loans::exchange_rate(USDT).saturating_mul_int(Tokens::balance( - Loans::ptoken_id(USDT).unwrap(), + Loans::lend_token_id(USDT).unwrap(), &incentive_reward_account.clone() )), unit(3), @@ -131,7 +131,7 @@ fn full_workflow_works_as_expected() { // still 1 dollar left in reserve account assert_eq!( Loans::exchange_rate(USDT).saturating_mul_int(Tokens::balance( - Loans::ptoken_id(USDT).unwrap(), + Loans::lend_token_id(USDT).unwrap(), &incentive_reward_account )), unit(1), diff --git a/crates/loans/src/tests/market.rs b/crates/loans/src/tests/market.rs index 63d9feb288..cb5a565c71 100644 --- a/crates/loans/src/tests/market.rs +++ b/crates/loans/src/tests/market.rs @@ -1,17 +1,17 @@ use crate::{ - mock::{market_mock, new_test_ext, Loans, Origin, Test, ACTIVE_MARKET_MOCK, ALICE, CDOT, MARKET_MOCK}, + mock::{market_mock, new_test_ext, Loans, Origin, Test, ACTIVE_MARKET_MOCK, ALICE, LEND_DOT, MARKET_MOCK}, Error, InterestRateModel, MarketState, }; use frame_support::{assert_noop, assert_ok, error::BadOrigin}; use primitives::{ - CurrencyId::{self, ForeignAsset, PToken, Token}, + CurrencyId::{self, ForeignAsset, LendToken, Token}, Rate, Ratio, DOT as DOT_CURRENCY, }; use sp_runtime::{traits::Zero, FixedPointNumber}; const DOT: CurrencyId = Token(DOT_CURRENCY); -const PDOT: CurrencyId = CDOT; -const PUSDT: CurrencyId = PToken(4); +const PDOT: CurrencyId = LEND_DOT; +const PUSDT: CurrencyId = LendToken(4); const SDOT: CurrencyId = ForeignAsset(987997280); macro_rules! rate_model_sanity_check { @@ -169,19 +169,19 @@ fn force_update_market_works() { new_market.state = MarketState::Active; Loans::force_update_market(Origin::root(), DOT, new_market).unwrap(); assert_eq!(Loans::market(DOT).unwrap().state, MarketState::Active); - assert_eq!(Loans::market(DOT).unwrap().ptoken_id, PDOT); + assert_eq!(Loans::market(DOT).unwrap().lend_token_id, PDOT); - // New ptoken_id must not be in use + // New lend_token_id must not be in use assert_noop!( Loans::force_update_market(Origin::root(), DOT, market_mock(PUSDT)), - Error::::InvalidPtokenId + Error::::InvalidLendTokenId ); assert_ok!(Loans::force_update_market( Origin::root(), DOT, market_mock(ForeignAsset(1234)) )); - assert_eq!(Loans::market(DOT).unwrap().ptoken_id, ForeignAsset(1234)); + assert_eq!(Loans::market(DOT).unwrap().lend_token_id, ForeignAsset(1234)); }) } diff --git a/crates/loans/src/types.rs b/crates/loans/src/types.rs index 05d1344009..1a5e6dc7d5 100644 --- a/crates/loans/src/types.rs +++ b/crates/loans/src/types.rs @@ -59,8 +59,8 @@ pub struct Market { pub supply_cap: Balance, /// Upper bound of borrowing pub borrow_cap: Balance, - /// Ptoken asset id - pub ptoken_id: CurrencyId, + /// LendToken asset id + pub lend_token_id: CurrencyId, } #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, Default)] diff --git a/crates/traits/src/loans.rs b/crates/traits/src/loans.rs index 9e95d25f4b..63d93d3a6c 100644 --- a/crates/traits/src/loans.rs +++ b/crates/traits/src/loans.rs @@ -27,8 +27,8 @@ pub trait LoansApi { -> Result<(), DispatchError>; fn do_repay_borrow(borrower: &AccountId, asset_id: CurrencyId, amount: Balance) -> Result<(), DispatchError>; fn do_redeem(supplier: &AccountId, asset_id: CurrencyId, amount: Balance) -> Result<(), DispatchError>; - fn recompute_underlying_amount(ptokens: &Amount) -> Result; - fn underlying_id(ptoken_id: CurrencyId) -> Result; + fn recompute_underlying_amount(lend_tokens: &Amount) -> Result; + fn underlying_id(lend_token_id: CurrencyId) -> Result; fn recompute_collateral_amount(underlying: &Amount) -> Result; } diff --git a/parachain/runtime/testnet-interlay/src/lib.rs b/parachain/runtime/testnet-interlay/src/lib.rs index bec03edb0d..5f1cc8e4f0 100644 --- a/parachain/runtime/testnet-interlay/src/lib.rs +++ b/parachain/runtime/testnet-interlay/src/lib.rs @@ -67,7 +67,7 @@ pub use security::StatusCode; pub use primitives::{ self, AccountId, BlockNumber, - CurrencyId::{ForeignAsset, PToken, Token}, + CurrencyId::{ForeignAsset, LendToken, Token}, CurrencyInfo, Hash, Moment, Nonce, Signature, SignedFixedPoint, SignedInner, UnsignedFixedPoint, UnsignedInner, }; @@ -1028,9 +1028,9 @@ impl pallet_traits::PriceFeeder for PriceFeed { } } // Returning `None` here means there is no price for this asset. - // This is fine since PTokens may not be used as underlying currency + // This is fine since LendTokens may not be used as underlying currency // in the loans pallet. - PToken(_) => return None, + LendToken(_) => return None, }; let amount = Amount::::new(one, asset_id.clone()); Oracle::convert(&amount, WRAPPED_CURRENCY_ID) diff --git a/parachain/runtime/testnet-kintsugi/src/lib.rs b/parachain/runtime/testnet-kintsugi/src/lib.rs index d6b47194bb..bd10983560 100644 --- a/parachain/runtime/testnet-kintsugi/src/lib.rs +++ b/parachain/runtime/testnet-kintsugi/src/lib.rs @@ -67,7 +67,7 @@ pub use security::StatusCode; pub use primitives::{ self, AccountId, BlockNumber, - CurrencyId::{ForeignAsset, PToken, Token}, + CurrencyId::{ForeignAsset, LendToken, Token}, CurrencyInfo, Hash, Moment, Nonce, Signature, SignedFixedPoint, SignedInner, UnsignedFixedPoint, UnsignedInner, }; @@ -1028,9 +1028,9 @@ impl pallet_traits::PriceFeeder for PriceFeed { } } // Returning `None` here means there is no price for this asset. - // This is fine since PTokens may not be used as underlying currency + // This is fine since LendTokens may not be used as underlying currency // in the loans pallet. - PToken(_) => return None, + LendToken(_) => return None, }; let amount = Amount::::new(one, asset_id.clone()); Oracle::convert(&amount, WRAPPED_CURRENCY_ID) diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 4ddb9b37dd..8713c6b262 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -369,12 +369,6 @@ pub type Shortfall = FixedU128; pub type Liquidity = FixedU128; pub const SECONDS_PER_YEAR: Timestamp = 365 * 24 * 60 * 60; -impl Default for Rate { - fn default() -> Self { - Self(Default::default()) - } -} - pub trait CurrencyInfo { fn name(&self) -> &str; fn symbol(&self) -> &str; @@ -479,11 +473,11 @@ create_currency_id! { pub enum CurrencyId { Token(TokenSymbol), ForeignAsset(ForeignAssetId), - PToken(PTokenId), + LendToken(LendTokenId), } pub type ForeignAssetId = u32; -pub type PTokenId = u32; +pub type LendTokenId = u32; #[derive(scale_info::TypeInfo, Encode, Decode, Clone, Eq, PartialEq, Debug)] pub struct CustomMetadata { @@ -492,7 +486,7 @@ pub struct CustomMetadata { } impl CurrencyId { - pub fn is_ptoken(&self) -> bool { - matches!(self, CurrencyId::PToken(_)) + pub fn is_lend_token(&self) -> bool { + matches!(self, CurrencyId::LendToken(_)) } } diff --git a/standalone/runtime/src/lib.rs b/standalone/runtime/src/lib.rs index ce2c14173f..4391755f21 100644 --- a/standalone/runtime/src/lib.rs +++ b/standalone/runtime/src/lib.rs @@ -66,7 +66,7 @@ pub use security::StatusCode; pub use primitives::{ self, AccountId, Balance, BlockNumber, CurrencyId, - CurrencyId::{ForeignAsset, PToken, Token}, + CurrencyId::{ForeignAsset, LendToken, Token}, CurrencyInfo, Hash, Moment, Nonce, PriceDetail, Signature, SignedFixedPoint, SignedInner, TokenSymbol, UnsignedFixedPoint, UnsignedInner, DOT, IBTC, INTR, KBTC, KINT, KSM, }; @@ -822,9 +822,9 @@ impl pallet_traits::PriceFeeder for PriceFeed { } } // Returning `None` here means there is no price for this asset. - // This is fine since PTokens may not be used as underlying currency + // This is fine since LendTokens may not be used as underlying currency // in the loans pallet. - PToken(_) => return None, + LendToken(_) => return None, }; let amount = Amount::::new(one, asset_id.clone()); Oracle::convert(&amount, WRAPPED_CURRENCY_ID) diff --git a/standalone/runtime/tests/mock/loans_testing_utils.rs b/standalone/runtime/tests/mock/loans_testing_utils.rs index cb48248aed..e3009f9790 100644 --- a/standalone/runtime/tests/mock/loans_testing_utils.rs +++ b/standalone/runtime/tests/mock/loans_testing_utils.rs @@ -3,7 +3,7 @@ use pallet_loans::JumpModel; use crate::{assert_eq, *}; -pub const fn market_mock(ptoken_id: CurrencyId) -> Market { +pub const fn market_mock(lend_token_id: CurrencyId) -> Market { Market { close_factor: Ratio::from_percent(50), collateral_factor: Ratio::from_percent(50), @@ -20,14 +20,14 @@ pub const fn market_mock(ptoken_id: CurrencyId) -> Market { reserve_factor: Ratio::from_percent(15), supply_cap: 1_000_000_000_000_000_000_000u128, // set to 1B borrow_cap: 1_000_000_000_000_000_000_000u128, // set to 1B - ptoken_id, + lend_token_id, } } -pub fn activate_market(underlying_id: CurrencyId, ptoken_id: CurrencyId) { +pub fn activate_market(underlying_id: CurrencyId, lend_token_id: CurrencyId) { assert_ok!(Call::Loans(LoansCall::add_market { asset_id: underlying_id, - market: market_mock(ptoken_id) + market: market_mock(lend_token_id) }) .dispatch(root())); assert_ok!(Call::Loans(LoansCall::activate_market { @@ -36,7 +36,7 @@ pub fn activate_market(underlying_id: CurrencyId, ptoken_id: CurrencyId) { .dispatch(root())); } -pub fn mint_ptokens(account_id: AccountId, underlying_id: CurrencyId) { +pub fn mint_lend_tokens(account_id: AccountId, underlying_id: CurrencyId) { let balance_to_mint = FUND_LIMIT_CEILING; let amount: Amount = Amount::new(balance_to_mint, underlying_id); assert_ok!(amount.mint_to(&account_id)); @@ -48,9 +48,9 @@ pub fn mint_ptokens(account_id: AccountId, underlying_id: CurrencyId) { .dispatch(origin_of(account_id))); } -pub fn activate_lending_and_mint(underlying_id: CurrencyId, ptoken_id: CurrencyId) { - activate_market(underlying_id, ptoken_id); - for account in iter_endowed_with_ptoken() { - mint_ptokens(account, underlying_id); +pub fn activate_lending_and_mint(underlying_id: CurrencyId, lend_token_id: CurrencyId) { + activate_market(underlying_id, lend_token_id); + for account in iter_endowed_with_lend_token() { + mint_lend_tokens(account, underlying_id); } } diff --git a/standalone/runtime/tests/mock/mod.rs b/standalone/runtime/tests/mock/mod.rs index 8c970f4b19..47e1fd24d4 100644 --- a/standalone/runtime/tests/mock/mod.rs +++ b/standalone/runtime/tests/mock/mod.rs @@ -23,7 +23,7 @@ pub use mocktopus::mocking::*; pub use orml_tokens::CurrencyAdapter; use pallet_traits::LoansApi; pub use primitives::{ - CurrencyId::{ForeignAsset, PToken, Token}, + CurrencyId::{ForeignAsset, LendToken, Token}, Rate, Ratio, VaultCurrencyPair, VaultId as PrimitiveVaultId, DOT, IBTC, INTR, KBTC, KINT, KSM, }; use redeem::RedeemRequestStatus; @@ -193,11 +193,11 @@ pub const DEFAULT_WRAPPED_CURRENCY: ::CurrencyId pub const DEFAULT_NATIVE_CURRENCY: ::CurrencyId = Token(INTR); pub const DEFAULT_GRIEFING_CURRENCY: ::CurrencyId = DEFAULT_NATIVE_CURRENCY; -pub const CDOT: CurrencyId = PToken(1); -pub const CKINT: CurrencyId = PToken(2); -pub const CKSM: CurrencyId = PToken(3); -pub const CKBTC: CurrencyId = PToken(4); -pub const CIBTC: CurrencyId = PToken(5); +pub const LendDOT: CurrencyId = LendToken(1); +pub const LendKINT: CurrencyId = LendToken(2); +pub const LendKSM: CurrencyId = LendToken(3); +pub const LendKBTC: CurrencyId = LendToken(4); +pub const LendIBTC: CurrencyId = LendToken(5); pub fn default_vault_id_of(hash: [u8; 32]) -> VaultId { VaultId { @@ -365,7 +365,7 @@ pub fn iter_currency_pairs() -> impl Iterator impl Iterator { +pub fn iter_endowed_with_lend_token() -> impl Iterator { vec![ account_of(ALICE), account_of(BOB), @@ -380,7 +380,7 @@ pub fn iter_endowed_with_ptoken() -> impl Iterator { } pub fn iter_collateral_currencies() -> impl Iterator { - vec![Token(DOT), Token(KSM), Token(INTR), ForeignAsset(1), PToken(1)].into_iter() + vec![Token(DOT), Token(KSM), Token(INTR), ForeignAsset(1), LendToken(1)].into_iter() } pub fn iter_native_currencies() -> impl Iterator { @@ -970,7 +970,7 @@ impl ParachainTwoVaultState { } pub fn set_collateral_exchange_rate(vault_id: &VaultId, price: FixedU128) { - let currency_to_set = if vault_id.currencies.collateral.is_ptoken() { + let currency_to_set = if vault_id.currencies.collateral.is_lend_token() { LoansPallet::underlying_id(vault_id.currencies.collateral).unwrap() } else { vault_id.currencies.collateral @@ -1376,7 +1376,7 @@ impl ExtBuilder { .into_iter() .flat_map(|(account, balance)| { iter_collateral_currencies() - .filter(|c| !c.is_ptoken()) + .filter(|c| !c.is_lend_token()) .chain(iter_native_currencies()) .unique() .map(move |currency| (account.clone(), currency, balance)) @@ -1416,7 +1416,7 @@ impl ExtBuilder { (Token(KSM), 0), (ForeignAsset(1), 0), (Token(INTR), 0), - (PToken(1), 0), + (LendToken(1), 0), ], punishment_delay: 8, system_collateral_ceiling: iter_currency_pairs().map(|pair| (pair, FUND_LIMIT_CEILING)).collect(), diff --git a/standalone/runtime/tests/test_issue.rs b/standalone/runtime/tests/test_issue.rs index d212631358..219d4048c0 100644 --- a/standalone/runtime/tests/test_issue.rs +++ b/standalone/runtime/tests/test_issue.rs @@ -2,19 +2,19 @@ mod mock; use currency::Amount; use mock::{assert_eq, issue_testing_utils::*, loans_testing_utils::activate_lending_and_mint, *}; -use CurrencyId::PToken; +use CurrencyId::LendToken; fn test_with(execute: impl Fn(VaultId) -> R) { let test_with = |currency_id, wrapped_id| { ExtBuilder::build().execute_with(|| { SecurityPallet::set_active_block_number(1); - for currency_id in iter_collateral_currencies().filter(|c| !c.is_ptoken()) { + for currency_id in iter_collateral_currencies().filter(|c| !c.is_lend_token()) { assert_ok!(OraclePallet::_set_exchange_rate(currency_id, FixedU128::one())); } if wrapped_id != Token(IBTC) { assert_ok!(OraclePallet::_set_exchange_rate(wrapped_id, FixedU128::one())); } - activate_lending_and_mint(Token(DOT), PToken(1)); + activate_lending_and_mint(Token(DOT), LendToken(1)); UserData::force_to(USER, default_user_state()); let vault_id = PrimitiveVaultId::new(account_of(VAULT), currency_id, wrapped_id); LiquidationVaultData::force_to(default_liquidation_vault_state(&vault_id.currencies)); @@ -26,7 +26,7 @@ fn test_with(execute: impl Fn(VaultId) -> R) { test_with(Token(KSM), Token(IBTC)); test_with(Token(DOT), Token(IBTC)); test_with(ForeignAsset(1), Token(IBTC)); - test_with(PToken(1), Token(IBTC)); + test_with(LendToken(1), Token(IBTC)); } fn test_with_initialized_vault(execute: impl Fn(VaultId) -> R) { diff --git a/standalone/runtime/tests/test_loans.rs b/standalone/runtime/tests/test_loans.rs index 432fb64522..4d78f14730 100644 --- a/standalone/runtime/tests/test_loans.rs +++ b/standalone/runtime/tests/test_loans.rs @@ -11,7 +11,7 @@ use sp_runtime::traits::CheckedMul; pub const USER: [u8; 32] = ALICE; pub const LP: [u8; 32] = BOB; -pub const fn market_mock(ptoken_id: CurrencyId) -> Market { +pub const fn market_mock(lend_token_id: CurrencyId) -> Market { Market { close_factor: Ratio::from_percent(50), collateral_factor: Ratio::from_percent(50), @@ -28,7 +28,7 @@ pub const fn market_mock(ptoken_id: CurrencyId) -> Market { reserve_factor: Ratio::from_percent(15), supply_cap: 1_000_000_000_000_000_000_000u128, // set to 1B borrow_cap: 1_000_000_000_000_000_000_000u128, // set to 1B - ptoken_id, + lend_token_id, } } @@ -43,12 +43,12 @@ fn reserved_balance(currency_id: CurrencyId, account_id: &AccountId) -> Balance ) } -fn set_up_market(currency_id: CurrencyId, exchange_rate: FixedU128, ptoken_id: CurrencyId) { +fn set_up_market(currency_id: CurrencyId, exchange_rate: FixedU128, lend_token_id: CurrencyId) { assert_ok!(OraclePallet::_set_exchange_rate(currency_id, exchange_rate)); assert_ok!(Call::Sudo(SudoCall::sudo { call: Box::new(Call::Loans(LoansCall::add_market { asset_id: currency_id, - market: market_mock(ptoken_id), + market: market_mock(lend_token_id), })), }) .dispatch(origin_of(account_of(ALICE)))); @@ -65,14 +65,18 @@ fn test_real_market(execute: impl Fn() -> R) { set_up_market( Token(KINT), FixedU128::from_inner(115_942_028_985_507_246_376_810_000), - CKINT, + LendKINT, ); set_up_market( Token(KSM), FixedU128::from_inner(4_573_498_406_135_805_461_670_000), - CKSM, + LendKSM, + ); + set_up_market( + Token(DOT), + FixedU128::from_inner(324_433_053_239_464_036_596_000), + LendDOT, ); - set_up_market(Token(DOT), FixedU128::from_inner(324_433_053_239_464_036_596_000), CDOT); execute() }); } @@ -92,8 +96,8 @@ fn integration_test_liquidation() { .dispatch(origin_of(user.clone()))); // Check entries from orml-tokens directly - assert_eq!(free_balance(CKINT, &user), 1000); - assert_eq!(reserved_balance(CKINT, &user), 0); + assert_eq!(free_balance(LendKINT, &user), 1000); + assert_eq!(reserved_balance(LendKINT, &user), 0); assert_ok!(Call::Loans(LoansCall::mint { asset_id: ksm, @@ -102,14 +106,14 @@ fn integration_test_liquidation() { .dispatch(origin_of(lp.clone()))); // Check entries from orml-tokens directly - assert_eq!(free_balance(CKSM, &lp), 50); - assert_eq!(reserved_balance(CKSM, &lp), 0); + assert_eq!(free_balance(LendKSM, &lp), 50); + assert_eq!(reserved_balance(LendKSM, &lp), 0); assert_ok!(Call::Loans(LoansCall::deposit_all_collateral { asset_id: kint }).dispatch(origin_of(user.clone()))); // Check entries from orml-tokens directly - assert_eq!(free_balance(CKINT, &user), 0); - assert_eq!(reserved_balance(CKINT, &user), 1000); + assert_eq!(free_balance(LendKINT, &user), 0); + assert_eq!(reserved_balance(LendKINT, &user), 1000); assert_err!( Call::Loans(LoansCall::borrow { @@ -154,30 +158,30 @@ fn integration_test_liquidation() { }) .dispatch(origin_of(lp.clone()))); - assert_eq!(free_balance(CKINT, &user), 0); + assert_eq!(free_balance(LendKINT, &user), 0); // borrower's reserved collateral is slashed - assert_eq!(reserved_balance(CKINT, &user), 610); + assert_eq!(reserved_balance(LendKINT, &user), 610); // borrower's borrowed balance is unchanged assert_eq!(free_balance(ksm, &user), 1000000000015); // the liquidator receives most of the slashed collateral - assert_eq!(reserved_balance(CKINT, &lp), 0); - assert_eq!(free_balance(CKINT, &lp), 380); + assert_eq!(reserved_balance(LendKINT, &lp), 0); + assert_eq!(free_balance(LendKINT, &lp), 380); // the rest of the slashed collateral routed to the incentive reward account's free balance assert_eq!( - free_balance(CKINT, &LoansPallet::incentive_reward_account_id().unwrap()), + free_balance(LendKINT, &LoansPallet::incentive_reward_account_id().unwrap()), 10 ); assert_eq!( - reserved_balance(CKINT, &LoansPallet::incentive_reward_account_id().unwrap()), + reserved_balance(LendKINT, &LoansPallet::incentive_reward_account_id().unwrap()), 0 ); }); } #[test] -fn integration_test_ptoken_vault_insufficient_balance() { +fn integration_test_lend_token_vault_insufficient_balance() { test_real_market(|| { let dot = Token(DOT); let vault_account_id = account_of(USER); @@ -189,50 +193,50 @@ fn integration_test_ptoken_vault_insufficient_balance() { .dispatch(origin_of(account_of(USER)))); // Check entries from orml-tokens directly - assert_eq!(free_balance(CDOT, &vault_account_id), 1000); - assert_eq!(reserved_balance(CDOT, &vault_account_id), 0); + assert_eq!(free_balance(LendDOT, &vault_account_id), 1000); + assert_eq!(reserved_balance(LendDOT, &vault_account_id), 0); assert_eq!( - LoansPallet::account_deposits(CDOT, vault_account_id.clone()), - reserved_balance(CDOT, &vault_account_id) + LoansPallet::account_deposits(LendDOT, vault_account_id.clone()), + reserved_balance(LendDOT, &vault_account_id) ); - let ptokens = LoansPallet::free_ptokens(dot, &vault_account_id).unwrap(); + let lend_tokens = LoansPallet::free_lend_tokens(dot, &vault_account_id).unwrap(); // Depositing all the collateral should leave none free for registering as a vault assert_ok!(Call::Loans(LoansCall::deposit_all_collateral { asset_id: dot }) .dispatch(origin_of(vault_account_id.clone()))); - assert_eq!(free_balance(CDOT, &vault_account_id), 0); - assert_eq!(reserved_balance(CDOT, &vault_account_id), 1000); + assert_eq!(free_balance(LendDOT, &vault_account_id), 0); + assert_eq!(reserved_balance(LendDOT, &vault_account_id), 1000); assert_eq!( - LoansPallet::account_deposits(ptokens.currency(), vault_account_id.clone()), - reserved_balance(CDOT, &vault_account_id) + LoansPallet::account_deposits(lend_tokens.currency(), vault_account_id.clone()), + reserved_balance(LendDOT, &vault_account_id) ); - let ptoken_vault_id = PrimitiveVaultId::new(vault_account_id.clone(), ptokens.currency(), Token(IBTC)); + let lend_token_vault_id = PrimitiveVaultId::new(vault_account_id.clone(), lend_tokens.currency(), Token(IBTC)); assert_err!( - get_register_vault_result(&ptoken_vault_id, ptokens), + get_register_vault_result(&lend_token_vault_id, lend_tokens), TokensError::BalanceTooLow ); - // Withdraw the ptokens to use them for another purpose + // Withdraw the lend_tokens to use them for another purpose assert_ok!(Call::Loans(LoansCall::withdraw_all_collateral { asset_id: dot }) .dispatch(origin_of(vault_account_id.clone()))); - assert_eq!(free_balance(CDOT, &vault_account_id), 1000); - assert_eq!(reserved_balance(CDOT, &vault_account_id), 0); + assert_eq!(free_balance(LendDOT, &vault_account_id), 1000); + assert_eq!(reserved_balance(LendDOT, &vault_account_id), 0); - // This time, registering a vault works because the ptokens are unlocked - assert_ok!(get_register_vault_result(&ptoken_vault_id, ptokens)); - assert_eq!(free_balance(CDOT, &vault_account_id), 0); - assert_eq!(reserved_balance(CDOT, &vault_account_id), 1000); + // This time, registering a vault works because the lend_tokens are unlocked + assert_ok!(get_register_vault_result(&lend_token_vault_id, lend_tokens)); + assert_eq!(free_balance(LendDOT, &vault_account_id), 0); + assert_eq!(reserved_balance(LendDOT, &vault_account_id), 1000); assert_eq!( - LoansPallet::account_deposits(ptokens.currency(), vault_account_id.clone()), + LoansPallet::account_deposits(lend_tokens.currency(), vault_account_id.clone()), 0 ); }); } #[test] -fn integration_test_ptoken_deposit_insufficient_balance() { +fn integration_test_lend_token_deposit_insufficient_balance() { test_real_market(|| { let dot = Token(DOT); let vault_account_id = account_of(USER); @@ -243,21 +247,21 @@ fn integration_test_ptoken_deposit_insufficient_balance() { }) .dispatch(origin_of(account_of(USER)))); - let ptokens = LoansPallet::free_ptokens(dot, &vault_account_id).unwrap(); + let lend_tokens = LoansPallet::free_lend_tokens(dot, &vault_account_id).unwrap(); - // Register a vault with all the available ptokens - let ptoken_vault_id = PrimitiveVaultId::new(vault_account_id.clone(), ptokens.currency(), Token(IBTC)); - assert_ok!(get_register_vault_result(&ptoken_vault_id, ptokens),); + // Register a vault with all the available lend_tokens + let lend_token_vault_id = PrimitiveVaultId::new(vault_account_id.clone(), lend_tokens.currency(), Token(IBTC)); + assert_ok!(get_register_vault_result(&lend_token_vault_id, lend_tokens),); assert_err!( - LoansPallet::do_deposit_collateral(&vault_account_id, ptokens.currency(), ptokens.amount()), + LoansPallet::do_deposit_collateral(&vault_account_id, lend_tokens.currency(), lend_tokens.amount()), TokensError::BalanceTooLow ); }); } #[test] -fn integration_test_ptoken_transfer_reserved_fails() { +fn integration_test_lend_token_transfer_reserved_fails() { test_real_market(|| { let dot = Token(DOT); let vault_account_id = account_of(USER); @@ -269,34 +273,37 @@ fn integration_test_ptoken_transfer_reserved_fails() { }) .dispatch(origin_of(vault_account_id.clone()))); - assert_eq!(free_balance(CDOT, &vault_account_id), 1000); - assert_eq!(reserved_balance(CDOT, &vault_account_id), 0); - let ptokens = LoansPallet::free_ptokens(dot, &vault_account_id).unwrap(); + assert_eq!(free_balance(LendDOT, &vault_account_id), 1000); + assert_eq!(reserved_balance(LendDOT, &vault_account_id), 0); + let lend_tokens = LoansPallet::free_lend_tokens(dot, &vault_account_id).unwrap(); - // Lock some ptokens into the lending market + // Lock some lend_tokens into the lending market assert_ok!(LoansPallet::do_deposit_collateral( &vault_account_id, - ptokens.currency(), - ptokens.amount() / 2 + lend_tokens.currency(), + lend_tokens.amount() / 2 )); assert_eq!( - LoansPallet::account_deposits(ptokens.currency(), vault_account_id.clone()), - reserved_balance(ptokens.currency(), &vault_account_id) + LoansPallet::account_deposits(lend_tokens.currency(), vault_account_id.clone()), + reserved_balance(lend_tokens.currency(), &vault_account_id) ); - assert_eq!(free_balance(CDOT, &vault_account_id), 500); - assert_eq!(reserved_balance(CDOT, &vault_account_id), 500); + assert_eq!(free_balance(LendDOT, &vault_account_id), 500); + assert_eq!(reserved_balance(LendDOT, &vault_account_id), 500); - let half_ptokens = ptokens.checked_div(&FixedU128::from_u32(2)).unwrap(); - assert_eq!(half_ptokens, LoansPallet::free_ptokens(dot, &vault_account_id).unwrap()); + let half_lend_tokens = lend_tokens.checked_div(&FixedU128::from_u32(2)).unwrap(); + assert_eq!( + half_lend_tokens, + LoansPallet::free_lend_tokens(dot, &vault_account_id).unwrap() + ); // Transferring the full amount fails assert_noop!( - ptokens.transfer(&vault_account_id, &lp_account_id), + lend_tokens.transfer(&vault_account_id, &lp_account_id), TokensError::BalanceTooLow ); - assert_ok!(half_ptokens.transfer(&vault_account_id, &lp_account_id)); - assert_eq!(free_balance(CDOT, &vault_account_id), 0); - assert_eq!(reserved_balance(CDOT, &vault_account_id), 500); - assert_eq!(free_balance(CDOT, &lp_account_id), 500); + assert_ok!(half_lend_tokens.transfer(&vault_account_id, &lp_account_id)); + assert_eq!(free_balance(LendDOT, &vault_account_id), 0); + assert_eq!(reserved_balance(LendDOT, &vault_account_id), 500); + assert_eq!(free_balance(LendDOT, &lp_account_id), 500); }); } diff --git a/standalone/runtime/tests/test_nomination.rs b/standalone/runtime/tests/test_nomination.rs index 5774ce4349..e631855939 100644 --- a/standalone/runtime/tests/test_nomination.rs +++ b/standalone/runtime/tests/test_nomination.rs @@ -9,13 +9,13 @@ fn test_with(execute: impl Fn(VaultId) -> R) { let test_with = |currency_id, wrapped_id| { ExtBuilder::build().execute_with(|| { SecurityPallet::set_active_block_number(1); - for currency_id in iter_collateral_currencies().filter(|c| !c.is_ptoken()) { + for currency_id in iter_collateral_currencies().filter(|c| !c.is_lend_token()) { assert_ok!(OraclePallet::_set_exchange_rate(currency_id, FixedU128::one())); } if wrapped_id != Token(IBTC) { assert_ok!(OraclePallet::_set_exchange_rate(wrapped_id, FixedU128::one())); } - activate_lending_and_mint(Token(DOT), PToken(1)); + activate_lending_and_mint(Token(DOT), LendToken(1)); UserData::force_to(USER, default_user_state()); let vault_id = PrimitiveVaultId::new(account_of(VAULT), currency_id, wrapped_id); LiquidationVaultData::force_to(default_liquidation_vault_state(&vault_id.currencies)); @@ -28,7 +28,7 @@ fn test_with(execute: impl Fn(VaultId) -> R) { test_with(Token(KSM), Token(IBTC)); test_with(Token(DOT), Token(IBTC)); test_with(ForeignAsset(1), Token(IBTC)); - test_with(PToken(1), Token(IBTC)); + test_with(LendToken(1), Token(IBTC)); } fn test_with_nomination_enabled(execute: impl Fn(VaultId) -> R) { diff --git a/standalone/runtime/tests/test_redeem.rs b/standalone/runtime/tests/test_redeem.rs index 7af0a0e632..68fd8de1e0 100644 --- a/standalone/runtime/tests/test_redeem.rs +++ b/standalone/runtime/tests/test_redeem.rs @@ -15,7 +15,7 @@ fn test_with(execute: impl Fn(VaultId) -> R) { if wrapped_id != Token(IBTC) { assert_ok!(OraclePallet::_set_exchange_rate(wrapped_id, FixedU128::one())); } - activate_lending_and_mint(Token(DOT), PToken(1)); + activate_lending_and_mint(Token(DOT), LendToken(1)); set_default_thresholds(); LiquidationVaultData::force_to(default_liquidation_vault_state(&vault_id.currencies)); UserData::force_to(USER, default_user_state()); @@ -40,7 +40,7 @@ fn test_with(execute: impl Fn(VaultId) -> R) { test_with(Token(DOT), Token(IBTC), Some(Token(KSM))); test_with(Token(KSM), Token(IBTC), None); test_with(ForeignAsset(1), Token(IBTC), None); - test_with(PToken(1), Token(IBTC), None); + test_with(LendToken(1), Token(IBTC), None); } /// to-be-replaced & replace_collateral are decreased in request_redeem diff --git a/standalone/runtime/tests/test_replace.rs b/standalone/runtime/tests/test_replace.rs index 9a3e34a58a..0030084cc7 100644 --- a/standalone/runtime/tests/test_replace.rs +++ b/standalone/runtime/tests/test_replace.rs @@ -26,7 +26,7 @@ fn test_with(execute: impl Fn(VaultId, VaultId) -> R) { if wrapped_currency != Token(IBTC) { assert_ok!(OraclePallet::_set_exchange_rate(wrapped_currency, FixedU128::one())); } - activate_lending_and_mint(Token(DOT), PToken(1)); + activate_lending_and_mint(Token(DOT), LendToken(1)); set_default_thresholds(); UserData::force_to(USER, default_user_state()); let old_vault_id = VaultId::new(account_of(OLD_VAULT), old_vault_currency, wrapped_currency); @@ -63,8 +63,8 @@ fn test_with(execute: impl Fn(VaultId, VaultId) -> R) { test_with(Token(KSM), Token(DOT), Token(IBTC), None); test_with(ForeignAsset(1), Token(DOT), Token(IBTC), None); test_with(Token(KSM), ForeignAsset(1), Token(IBTC), None); - test_with(PToken(1), ForeignAsset(1), Token(IBTC), None); - test_with(Token(KSM), PToken(1), Token(IBTC), None); + test_with(LendToken(1), ForeignAsset(1), Token(IBTC), None); + test_with(Token(KSM), LendToken(1), Token(IBTC), None); } fn test_without_initialization(execute: impl Fn(CurrencyId) -> R) { @@ -1130,7 +1130,7 @@ fn integration_test_replace_cancel_replace_both_vaults_liquidated() { #[test] fn integration_test_replace_vault_with_different_currency_succeeds() { test_without_initialization(|currency_id| { - for currency_id in iter_collateral_currencies().filter(|c| !c.is_ptoken()) { + for currency_id in iter_collateral_currencies().filter(|c| !c.is_lend_token()) { assert_ok!(OraclePallet::_set_exchange_rate(currency_id, FixedU128::one())); } set_default_thresholds(); @@ -1145,8 +1145,8 @@ fn integration_test_replace_vault_with_different_currency_succeeds() { let old_vault_id = vault_id_of(OLD_VAULT, currency_id); let new_vault_id = vault_id_of(NEW_VAULT, other_currency); - // Mint pTokens so that force-setting vault state doesn't fail - activate_lending_and_mint(Token(DOT), PToken(1)); + // Mint lendTokens so that force-setting vault state doesn't fail + activate_lending_and_mint(Token(DOT), LendToken(1)); CoreVaultData::force_to(&old_vault_id, default_vault_state(&old_vault_id)); CoreVaultData::force_to(&new_vault_id, default_vault_state(&new_vault_id)); diff --git a/standalone/runtime/tests/test_vault_registry.rs b/standalone/runtime/tests/test_vault_registry.rs index a7fce645f0..d5331ecdc9 100644 --- a/standalone/runtime/tests/test_vault_registry.rs +++ b/standalone/runtime/tests/test_vault_registry.rs @@ -15,13 +15,13 @@ fn test_with(execute: impl Fn(VaultId) -> R) { let test_with = |currency_id, wrapped_id| { ExtBuilder::build().execute_with(|| { SecurityPallet::set_active_block_number(1); - for currency_id in iter_collateral_currencies().filter(|c| !c.is_ptoken()) { + for currency_id in iter_collateral_currencies().filter(|c| !c.is_lend_token()) { assert_ok!(OraclePallet::_set_exchange_rate(currency_id, FixedU128::one())); } if wrapped_id != Token(IBTC) { assert_ok!(OraclePallet::_set_exchange_rate(wrapped_id, FixedU128::one())); } - activate_lending_and_mint(Token(DOT), PToken(1)); + activate_lending_and_mint(Token(DOT), LendToken(1)); UserData::force_to(USER, default_user_state()); let vault_id = PrimitiveVaultId::new(account_of(VAULT), currency_id, wrapped_id); LiquidationVaultData::force_to(default_liquidation_vault_state(&vault_id.currencies)); @@ -34,7 +34,7 @@ fn test_with(execute: impl Fn(VaultId) -> R) { test_with(Token(KSM), Token(IBTC)); test_with(Token(DOT), Token(IBTC)); test_with(ForeignAsset(1), Token(IBTC)); - test_with(PToken(1), Token(IBTC)); + test_with(LendToken(1), Token(IBTC)); } fn deposit_collateral_and_issue(vault_id: VaultId) { @@ -122,8 +122,8 @@ mod deposit_collateral_test { let amount_1 = 1000_000_000_000_000; - // Mint pTokens so that force-setting vault state doesn't fail - activate_lending_and_mint(Token(DOT), PToken(1)); + // Mint lendTokens so that force-setting vault state doesn't fail + activate_lending_and_mint(Token(DOT), LendToken(1)); let mut vault_data = default_vault_state(&vault_id); *vault_data.free_balance.get_mut(¤cy_id).unwrap() = Amount::new(amount_1, currency_id); CoreVaultData::force_to(&vault_id, vault_data); From 0b49fcda42a512188ee73a745379e37ed66a9e61 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Thu, 27 Oct 2022 15:53:15 +0200 Subject: [PATCH 45/58] refactor(loans): use interlay assets in tests --- crates/loans/src/tests.rs | 93 ++++++------ crates/loans/src/tests/lend_tokens.rs | 202 +++++++++++++------------- crates/loans/src/tests/market.rs | 69 +++++---- 3 files changed, 190 insertions(+), 174 deletions(-) diff --git a/crates/loans/src/tests.rs b/crates/loans/src/tests.rs index 628bf45846..387cd46a4c 100644 --- a/crates/loans/src/tests.rs +++ b/crates/loans/src/tests.rs @@ -29,20 +29,21 @@ use sp_runtime::{ FixedU128, Permill, }; -use primitives::{CurrencyId::Token, DOT as DOT_CURRENCY, IBTC, KBTC, KINT, KSM as KSM_CURRENCY}; +use primitives::{ + CurrencyId::Token, DOT as DOT_CURRENCY, IBTC as IBTC_CURRENCY, KBTC as KBTC_CURRENCY, KINT as KINT_CURRENCY, + KSM as KSM_CURRENCY, +}; use crate::{ mock::*, tests::lend_tokens::{free_balance, reserved_balance}, }; -// For the time being, do a quick reassignment here to avoid changing all the tests -// TODO: update all tests const DOT: CurrencyId = Token(DOT_CURRENCY); const KSM: CurrencyId = Token(KSM_CURRENCY); -const USDT: CurrencyId = Token(KBTC); -const LEND_DOT_6_13: CurrencyId = Token(IBTC); -const HKO: CurrencyId = Token(KINT); +const USDT: CurrencyId = Token(KBTC_CURRENCY); +const IBTC: CurrencyId = Token(IBTC_CURRENCY); +const KINT: CurrencyId = Token(KINT_CURRENCY); #[test] fn init_minting_ok() { @@ -61,12 +62,12 @@ fn init_markets_ok() { assert_eq!(Loans::market(KSM).unwrap().state, MarketState::Active); assert_eq!(Loans::market(DOT).unwrap().state, MarketState::Active); assert_eq!(Loans::market(USDT).unwrap().state, MarketState::Active); - assert_eq!(BorrowIndex::::get(HKO), Rate::one()); + assert_eq!(BorrowIndex::::get(KINT), Rate::one()); assert_eq!(BorrowIndex::::get(KSM), Rate::one()); assert_eq!(BorrowIndex::::get(DOT), Rate::one()); assert_eq!(BorrowIndex::::get(USDT), Rate::one()); - assert_eq!(ExchangeRate::::get(HKO), Rate::saturating_from_rational(2, 100)); + assert_eq!(ExchangeRate::::get(KINT), Rate::saturating_from_rational(2, 100)); assert_eq!(ExchangeRate::::get(KSM), Rate::saturating_from_rational(2, 100)); assert_eq!(ExchangeRate::::get(DOT), Rate::saturating_from_rational(2, 100)); assert_eq!(ExchangeRate::::get(USDT), Rate::saturating_from_rational(2, 100)); @@ -76,39 +77,39 @@ fn init_markets_ok() { #[test] fn loans_native_token_works() { new_test_ext().execute_with(|| { - assert_eq!(Tokens::balance(HKO, &DAVE), unit(1000)); - assert_eq!(Loans::market(HKO).unwrap().state, MarketState::Active); - assert_eq!(BorrowIndex::::get(HKO), Rate::one()); - assert_eq!(ExchangeRate::::get(HKO), Rate::saturating_from_rational(2, 100)); - assert_ok!(Loans::mint(Origin::signed(DAVE), HKO, unit(1000))); + assert_eq!(Tokens::balance(KINT, &DAVE), unit(1000)); + assert_eq!(Loans::market(KINT).unwrap().state, MarketState::Active); + assert_eq!(BorrowIndex::::get(KINT), Rate::one()); + assert_eq!(ExchangeRate::::get(KINT), Rate::saturating_from_rational(2, 100)); + assert_ok!(Loans::mint(Origin::signed(DAVE), KINT, unit(1000))); - // Redeem 1001 HKO should cause InsufficientDeposit + // Redeem 1001 KINT should cause InsufficientDeposit assert_noop!( - Loans::redeem_allowed(HKO, &DAVE, unit(50050)), + Loans::redeem_allowed(KINT, &DAVE, unit(50050)), Error::::InsufficientDeposit ); - // Redeem 1000 HKO is ok - assert_ok!(Loans::redeem_allowed(HKO, &DAVE, unit(50000),)); + // Redeem 1000 KINT is ok + assert_ok!(Loans::redeem_allowed(KINT, &DAVE, unit(50000),)); - assert_ok!(Loans::deposit_all_collateral(Origin::signed(DAVE), HKO)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(DAVE), KINT)); - // Borrow 500 HKO will reduce 500 HKO liquidity for collateral_factor is 50% - assert_ok!(Loans::borrow(Origin::signed(DAVE), HKO, unit(500))); - // Repay 400 HKO - assert_ok!(Loans::repay_borrow(Origin::signed(DAVE), HKO, unit(400))); + // Borrow 500 KINT will reduce 500 KINT liquidity for collateral_factor is 50% + assert_ok!(Loans::borrow(Origin::signed(DAVE), KINT, unit(500))); + // Repay 400 KINT + assert_ok!(Loans::repay_borrow(Origin::signed(DAVE), KINT, unit(400))); - // HKO collateral: deposit = 1000 - // HKO borrow balance: borrow - repay = 500 - 400 = 100 - // HKO: cash - deposit + borrow - repay = 1000 - 1000 + 500 - 400 = 100 + // KINT collateral: deposit = 1000 + // KINT borrow balance: borrow - repay = 500 - 400 = 100 + // KINT: cash - deposit + borrow - repay = 1000 - 1000 + 500 - 400 = 100 assert_eq!( - Loans::exchange_rate(HKO) - .saturating_mul_int(Loans::account_deposits(Loans::lend_token_id(HKO).unwrap(), DAVE)), + Loans::exchange_rate(KINT) + .saturating_mul_int(Loans::account_deposits(Loans::lend_token_id(KINT).unwrap(), DAVE)), unit(1000) ); - let borrow_snapshot = Loans::account_borrows(HKO, DAVE); + let borrow_snapshot = Loans::account_borrows(KINT, DAVE); assert_eq!(borrow_snapshot.principal, unit(100)); - assert_eq!(borrow_snapshot.borrow_index, Loans::borrow_index(HKO)); - assert_eq!(Tokens::balance(HKO, &DAVE), unit(100),); + assert_eq!(borrow_snapshot.borrow_index, Loans::borrow_index(KINT)); + assert_eq!(Tokens::balance(KINT, &DAVE), unit(100),); }) } @@ -442,8 +443,8 @@ fn borrow_cap_below_current_volume() { #[test] fn get_account_liquidity_works() { new_test_ext().execute_with(|| { - Loans::mint(Origin::signed(ALICE), LEND_DOT_6_13, unit(200)).unwrap(); - Loans::deposit_all_collateral(Origin::signed(ALICE), LEND_DOT_6_13).unwrap(); + Loans::mint(Origin::signed(ALICE), IBTC, unit(200)).unwrap(); + Loans::deposit_all_collateral(Origin::signed(ALICE), IBTC).unwrap(); let (liquidity, _, _, _) = Loans::get_account_liquidity(&ALICE).unwrap(); @@ -457,8 +458,8 @@ fn get_account_liquidation_threshold_liquidity_works() { Loans::mint(Origin::signed(BOB), DOT, unit(200)).unwrap(); Loans::mint(Origin::signed(BOB), KSM, unit(200)).unwrap(); - Loans::mint(Origin::signed(ALICE), LEND_DOT_6_13, unit(200)).unwrap(); - Loans::deposit_all_collateral(Origin::signed(ALICE), LEND_DOT_6_13).unwrap(); + Loans::mint(Origin::signed(ALICE), IBTC, unit(200)).unwrap(); + Loans::deposit_all_collateral(Origin::signed(ALICE), IBTC).unwrap(); Loans::mint(Origin::signed(ALICE), USDT, unit(200)).unwrap(); Loans::deposit_all_collateral(Origin::signed(ALICE), USDT).unwrap(); @@ -896,17 +897,17 @@ fn ensure_valid_exchange_rate_works() { #[test] fn withdraw_missing_reward_works() { new_test_ext().execute_with(|| { - assert_eq!(Tokens::balance(HKO, &DAVE), unit(1000)); + assert_eq!(Tokens::balance(KINT, &DAVE), unit(1000)); assert_ok!(Loans::add_reward(Origin::signed(DAVE), unit(100))); assert_ok!(Loans::withdraw_missing_reward(Origin::root(), ALICE, unit(40),)); - assert_eq!(Tokens::balance(HKO, &DAVE), unit(900)); + assert_eq!(Tokens::balance(KINT, &DAVE), unit(900)); - assert_eq!(Tokens::balance(HKO, &ALICE), unit(40)); + assert_eq!(Tokens::balance(KINT, &ALICE), unit(40)); - assert_eq!(Tokens::balance(HKO, &Loans::reward_account_id().unwrap()), unit(60)); + assert_eq!(Tokens::balance(KINT, &Loans::reward_account_id().unwrap()), unit(60)); }) } @@ -1088,10 +1089,10 @@ fn reward_calculation_one_palyer_in_multi_markets_works() { _run_to_block(80); assert_ok!(Loans::add_reward(Origin::signed(DAVE), unit(200))); assert_ok!(Loans::claim_reward(Origin::signed(ALICE))); - assert_eq!(Tokens::balance(HKO, &DAVE), unit(800)); - assert_eq!(almost_equal(Tokens::balance(HKO, &ALICE), unit(130)), true); + assert_eq!(Tokens::balance(KINT, &DAVE), unit(800)); + assert_eq!(almost_equal(Tokens::balance(KINT, &ALICE), unit(130)), true); assert_eq!( - almost_equal(Tokens::balance(HKO, &Loans::reward_account_id().unwrap()), unit(70)), + almost_equal(Tokens::balance(KINT, &Loans::reward_account_id().unwrap()), unit(70)), true ); assert_ok!(Loans::update_market_reward_speed( @@ -1107,7 +1108,7 @@ fn reward_calculation_one_palyer_in_multi_markets_works() { // KSM borrow:0 KSM borrow reward: 20 _run_to_block(90); assert_ok!(Loans::claim_reward(Origin::signed(ALICE))); - assert_eq!(almost_equal(Tokens::balance(HKO, &ALICE), unit(140)), true); + assert_eq!(almost_equal(Tokens::balance(KINT, &ALICE), unit(140)), true); }) } @@ -1218,11 +1219,11 @@ fn reward_calculation_multi_player_in_one_market_works() { assert_ok!(Loans::add_reward(Origin::signed(DAVE), unit(200))); assert_ok!(Loans::claim_reward_for_market(Origin::signed(ALICE), DOT)); assert_ok!(Loans::claim_reward_for_market(Origin::signed(BOB), DOT)); - assert_eq!(Tokens::balance(HKO, &DAVE), unit(800)); - assert_eq!(almost_equal(Tokens::balance(HKO, &ALICE), unit(58)), true); - assert_eq!(almost_equal(Tokens::balance(HKO, &BOB), unit(22)), true); + assert_eq!(Tokens::balance(KINT, &DAVE), unit(800)); + assert_eq!(almost_equal(Tokens::balance(KINT, &ALICE), unit(58)), true); + assert_eq!(almost_equal(Tokens::balance(KINT, &BOB), unit(22)), true); assert_eq!( - almost_equal(Tokens::balance(HKO, &Loans::reward_account_id().unwrap()), unit(120)), + almost_equal(Tokens::balance(KINT, &Loans::reward_account_id().unwrap()), unit(120)), true ); }) diff --git a/crates/loans/src/tests/lend_tokens.rs b/crates/loans/src/tests/lend_tokens.rs index fcce4e900e..a1febc4f93 100644 --- a/crates/loans/src/tests/lend_tokens.rs +++ b/crates/loans/src/tests/lend_tokens.rs @@ -13,16 +13,13 @@ use orml_traits::{MultiCurrency, MultiReservableCurrency}; use primitives::{ Balance, CurrencyId::{self, ForeignAsset, LendToken, Token}, - KBTC, KINT, KSM as KSM_CURRENCY, + KBTC as KBTC_CURRENCY, KINT as KINT_CURRENCY, KSM as KSM_CURRENCY, }; use sp_runtime::{FixedPointNumber, TokenError}; -const HKO: CurrencyId = Token(KINT); +const KINT: CurrencyId = Token(KINT_CURRENCY); const KSM: CurrencyId = Token(KSM_CURRENCY); -const PHKO: CurrencyId = LEND_KINT; -const PKSM: CurrencyId = LEND_KSM; -const PUSDT: CurrencyId = LEND_KBTC; -const USDT: CurrencyId = Token(KBTC); +const KBTC: CurrencyId = Token(KBTC_CURRENCY); pub fn free_balance(currency_id: CurrencyId, account_id: &AccountId) -> Balance { ::AccountId>>::free_balance(currency_id, account_id) @@ -39,74 +36,77 @@ pub fn reserved_balance(currency_id: CurrencyId, account_id: &AccountId) -> Bala fn trait_inspect_methods_works() { new_test_ext().execute_with(|| { // No Deposits can't not withdraw - assert_err!(Loans::can_withdraw(PHKO, &DAVE, 100).into_result(), TokenError::NoFunds); - assert_eq!(Loans::total_issuance(PHKO), 0); - assert_eq!(Loans::total_issuance(PKSM), 0); + assert_err!( + Loans::can_withdraw(LEND_KINT, &DAVE, 100).into_result(), + TokenError::NoFunds + ); + assert_eq!(Loans::total_issuance(LEND_KINT), 0); + assert_eq!(Loans::total_issuance(LEND_KSM), 0); - let minimum_balance = Loans::minimum_balance(PHKO); + let minimum_balance = Loans::minimum_balance(LEND_KINT); assert_eq!(minimum_balance, 0); - assert_eq!(Loans::balance(PHKO, &DAVE), 0); + assert_eq!(Loans::balance(LEND_KINT, &DAVE), 0); - // DAVE Deposit 100 HKO - assert_ok!(Loans::mint(Origin::signed(DAVE), HKO, unit(100))); - assert_eq!(Tokens::balance(PHKO, &DAVE), unit(100) * 50); - assert_eq!(Tokens::total_issuance(PHKO), unit(100) * 50); + // DAVE Deposit 100 KINT + assert_ok!(Loans::mint(Origin::signed(DAVE), KINT, unit(100))); + assert_eq!(Tokens::balance(LEND_KINT, &DAVE), unit(100) * 50); + assert_eq!(Tokens::total_issuance(LEND_KINT), unit(100) * 50); // Check entries from orml-tokens directly - assert_eq!(free_balance(PHKO, &DAVE), unit(100) * 50); - assert_eq!(reserved_balance(PHKO, &DAVE), 0); + assert_eq!(free_balance(LEND_KINT, &DAVE), unit(100) * 50); + assert_eq!(reserved_balance(LEND_KINT, &DAVE), 0); // No collateral deposited yet, therefore no reducible balance - assert_eq!(Loans::reducible_balance(PHKO, &DAVE, true), 0); + assert_eq!(Loans::reducible_balance(LEND_KINT, &DAVE, true), 0); - assert_ok!(Loans::deposit_all_collateral(Origin::signed(DAVE), HKO)); - assert_eq!(Loans::reducible_balance(PHKO, &DAVE, true), unit(100) * 50); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(DAVE), KINT)); + assert_eq!(Loans::reducible_balance(LEND_KINT, &DAVE, true), unit(100) * 50); // Check entries from orml-tokens directly - assert_eq!(free_balance(PHKO, &DAVE), 0); - assert_eq!(reserved_balance(PHKO, &DAVE), unit(100) * 50); + assert_eq!(free_balance(LEND_KINT, &DAVE), 0); + assert_eq!(reserved_balance(LEND_KINT, &DAVE), unit(100) * 50); - // Borrow 25 HKO will reduce 25 HKO liquidity for collateral_factor is 50% - assert_ok!(Loans::borrow(Origin::signed(DAVE), HKO, unit(25))); + // Borrow 25 KINT will reduce 25 KINT liquidity for collateral_factor is 50% + assert_ok!(Loans::borrow(Origin::signed(DAVE), KINT, unit(25))); assert_eq!( - Loans::exchange_rate(HKO) - .saturating_mul_int(Loans::account_deposits(Loans::lend_token_id(HKO).unwrap(), DAVE)), + Loans::exchange_rate(KINT) + .saturating_mul_int(Loans::account_deposits(Loans::lend_token_id(KINT).unwrap(), DAVE)), unit(100) ); - // DAVE Deposit 100 HKO, Borrow 25 HKO - // Liquidity HKO 25 + // DAVE Deposit 100 KINT, Borrow 25 KINT + // Liquidity KINT 25 // Formula: lend_tokens = liquidity / price(1) / collateral(0.5) / exchange_rate(0.02) - assert_eq!(Loans::reducible_balance(PHKO, &DAVE, true), unit(25) * 2 * 50); + assert_eq!(Loans::reducible_balance(LEND_KINT, &DAVE, true), unit(25) * 2 * 50); - // Multi-asset case, additional deposit USDT - // DAVE Deposit 100 HKO, 50 USDT, Borrow 25 HKO - // Liquidity HKO = 25, USDT = 25 + // Multi-asset case, additional deposit KBTC + // DAVE Deposit 100 KINT, 50 KBTC, Borrow 25 KINT + // Liquidity KINT = 25, KBTC = 25 // lend_tokens = dollar(25 + 25) / 1 / 0.5 / 0.02 = dollar(50) * 100 - assert_ok!(Loans::mint(Origin::signed(DAVE), USDT, unit(50))); - assert_eq!(Tokens::balance(PUSDT, &DAVE), unit(50) * 50); + assert_ok!(Loans::mint(Origin::signed(DAVE), KBTC, unit(50))); + assert_eq!(Tokens::balance(LEND_KBTC, &DAVE), unit(50) * 50); // Check entries from orml-tokens directly - assert_eq!(free_balance(PUSDT, &DAVE), unit(50) * 50); - assert_eq!(reserved_balance(PUSDT, &DAVE), 0); + assert_eq!(free_balance(LEND_KBTC, &DAVE), unit(50) * 50); + assert_eq!(reserved_balance(LEND_KBTC, &DAVE), 0); // `reducible_balance()` checks how much collateral can be withdrawn from the amount deposited. // Since no collateral has been deposited yet, this value is zero. - assert_eq!(Loans::reducible_balance(PUSDT, &DAVE, true), 0); - // enable USDT collateral - assert_ok!(Loans::deposit_all_collateral(Origin::signed(DAVE), USDT)); - assert_eq!(Loans::reducible_balance(PHKO, &DAVE, true), unit(25 + 25) * 2 * 50); - assert_eq!(Loans::reducible_balance(PUSDT, &DAVE, true), unit(50) * 50); + assert_eq!(Loans::reducible_balance(LEND_KBTC, &DAVE, true), 0); + // enable KBTC collateral + assert_ok!(Loans::deposit_all_collateral(Origin::signed(DAVE), KBTC)); + assert_eq!(Loans::reducible_balance(LEND_KINT, &DAVE, true), unit(25 + 25) * 2 * 50); + assert_eq!(Loans::reducible_balance(LEND_KBTC, &DAVE, true), unit(50) * 50); // Check entries from orml-tokens directly - assert_eq!(free_balance(PUSDT, &DAVE), 0); - assert_eq!(reserved_balance(PUSDT, &DAVE), unit(50) * 50); + assert_eq!(free_balance(LEND_KBTC, &DAVE), 0); + assert_eq!(reserved_balance(LEND_KBTC, &DAVE), unit(50) * 50); - assert_ok!(Loans::borrow(Origin::signed(DAVE), HKO, unit(50))); - assert_eq!(Loans::reducible_balance(PHKO, &DAVE, true), 0); - assert_eq!(Loans::reducible_balance(PUSDT, &DAVE, true), 0); + assert_ok!(Loans::borrow(Origin::signed(DAVE), KINT, unit(50))); + assert_eq!(Loans::reducible_balance(LEND_KINT, &DAVE, true), 0); + assert_eq!(Loans::reducible_balance(LEND_KBTC, &DAVE, true), 0); - assert_eq!(Loans::total_issuance(PHKO), unit(100) * 50); - assert_ok!(Loans::can_deposit(PHKO, &DAVE, 100, true).into_result()); - assert_ok!(Loans::can_withdraw(PHKO, &DAVE, 1000).into_result()); + assert_eq!(Loans::total_issuance(LEND_KINT), unit(100) * 50); + assert_ok!(Loans::can_deposit(LEND_KINT, &DAVE, 100, true).into_result()); + assert_ok!(Loans::can_withdraw(LEND_KINT, &DAVE, 1000).into_result()); }) } @@ -115,7 +115,7 @@ fn lend_token_unique_works() { new_test_ext().execute_with(|| { // lend_token_id already exists in `UnderlyingAssetId` assert_noop!( - Loans::add_market(Origin::root(), ForeignAsset(1000000), market_mock(PHKO)), + Loans::add_market(Origin::root(), ForeignAsset(1000000), market_mock(LEND_KINT)), Error::::InvalidLendTokenId ); @@ -130,107 +130,111 @@ fn lend_token_unique_works() { #[test] fn transfer_lend_token_works() { new_test_ext().execute_with(|| { - // DAVE Deposit 100 HKO - assert_ok!(Loans::mint(Origin::signed(DAVE), HKO, unit(100))); + // DAVE Deposit 100 KINT + assert_ok!(Loans::mint(Origin::signed(DAVE), KINT, unit(100))); - // DAVE HKO collateral: deposit = 100 - // HKO: cash - deposit = 1000 - 100 = 900 + // DAVE KINT collateral: deposit = 100 + // KINT: cash - deposit = 1000 - 100 = 900 assert_eq!( - Loans::exchange_rate(HKO).saturating_mul_int(Tokens::balance(Loans::lend_token_id(HKO).unwrap(), &DAVE)), + Loans::exchange_rate(KINT).saturating_mul_int(Tokens::balance(Loans::lend_token_id(KINT).unwrap(), &DAVE)), unit(100) ); - // ALICE HKO collateral: deposit = 0 + // ALICE KINT collateral: deposit = 0 assert_eq!( - Loans::exchange_rate(HKO).saturating_mul_int(Tokens::balance(Loans::lend_token_id(HKO).unwrap(), &ALICE)), + Loans::exchange_rate(KINT).saturating_mul_int(Tokens::balance(Loans::lend_token_id(KINT).unwrap(), &ALICE)), unit(0) ); // Transfer lend_tokens from DAVE to ALICE - Loans::transfer(PHKO, &DAVE, &ALICE, unit(50) * 50, true).unwrap(); - // Loans::transfer_lend_tokens(Origin::signed(DAVE), ALICE, HKO, dollar(50) * 50).unwrap(); + Loans::transfer(LEND_KINT, &DAVE, &ALICE, unit(50) * 50, true).unwrap(); + // Loans::transfer_lend_tokens(Origin::signed(DAVE), ALICE, KINT, dollar(50) * 50).unwrap(); - // DAVE HKO collateral: deposit = 50 + // DAVE KINT collateral: deposit = 50 assert_eq!( - Loans::exchange_rate(HKO).saturating_mul_int(Tokens::balance(Loans::lend_token_id(HKO).unwrap(), &DAVE)), + Loans::exchange_rate(KINT).saturating_mul_int(Tokens::balance(Loans::lend_token_id(KINT).unwrap(), &DAVE)), unit(50) ); - // DAVE Redeem 51 HKO should cause InsufficientDeposit + // DAVE Redeem 51 KINT should cause InsufficientDeposit assert_noop!( - Loans::redeem_allowed(HKO, &DAVE, unit(51) * 50), + Loans::redeem_allowed(KINT, &DAVE, unit(51) * 50), Error::::InsufficientDeposit ); - // ALICE HKO collateral: deposit = 50 + // ALICE KINT collateral: deposit = 50 assert_eq!( - Loans::exchange_rate(HKO).saturating_mul_int(Tokens::balance(Loans::lend_token_id(HKO).unwrap(), &ALICE)), + Loans::exchange_rate(KINT).saturating_mul_int(Tokens::balance(Loans::lend_token_id(KINT).unwrap(), &ALICE)), unit(50) ); - // ALICE Redeem 50 HKO should be succeeded - assert_ok!(Loans::redeem_allowed(HKO, &ALICE, unit(50) * 50)); + // ALICE Redeem 50 KINT should be succeeded + assert_ok!(Loans::redeem_allowed(KINT, &ALICE, unit(50) * 50)); }) } #[test] fn transfer_lend_tokens_under_collateral_does_not_work() { new_test_ext().execute_with(|| { - // DAVE Deposit 100 HKO - assert_ok!(Loans::mint(Origin::signed(DAVE), HKO, unit(100))); + // DAVE Deposit 100 KINT + assert_ok!(Loans::mint(Origin::signed(DAVE), KINT, unit(100))); // Check entries from orml-tokens directly - assert_eq!(free_balance(PHKO, &DAVE), unit(100) * 50); - assert_eq!(reserved_balance(PHKO, &DAVE), 0); + assert_eq!(free_balance(LEND_KINT, &DAVE), unit(100) * 50); + assert_eq!(reserved_balance(LEND_KINT, &DAVE), 0); - assert_ok!(Loans::deposit_all_collateral(Origin::signed(DAVE), HKO)); + assert_ok!(Loans::deposit_all_collateral(Origin::signed(DAVE), KINT)); // Check entries from orml-tokens directly - assert_eq!(free_balance(PHKO, &DAVE), 0); - assert_eq!(reserved_balance(PHKO, &DAVE), unit(100) * 50); + assert_eq!(free_balance(LEND_KINT, &DAVE), 0); + assert_eq!(reserved_balance(LEND_KINT, &DAVE), unit(100) * 50); - // Borrow 50 HKO will reduce 50 HKO liquidity for collateral_factor is 50% - assert_ok!(Loans::borrow(Origin::signed(DAVE), HKO, unit(50))); - // Repay 40 HKO - assert_ok!(Loans::repay_borrow(Origin::signed(DAVE), HKO, unit(40))); + // Borrow 50 KINT will reduce 50 KINT liquidity for collateral_factor is 50% + assert_ok!(Loans::borrow(Origin::signed(DAVE), KINT, unit(50))); + // Repay 40 KINT + assert_ok!(Loans::repay_borrow(Origin::signed(DAVE), KINT, unit(40))); // Allowed to redeem 20 lend_tokens - assert_ok!(Loans::redeem_allowed(HKO, &DAVE, unit(20) * 50,)); + assert_ok!(Loans::redeem_allowed(KINT, &DAVE, unit(20) * 50,)); // Not allowed to transfer the same 20 lend_tokens because they are locked assert_noop!( - Loans::transfer(PHKO, &DAVE, &ALICE, unit(20) * 50, true), + Loans::transfer(LEND_KINT, &DAVE, &ALICE, unit(20) * 50, true), Error::::InsufficientCollateral ); // First, withdraw some tokens - assert_ok!(Loans::withdraw_collateral(Origin::signed(DAVE), PHKO, unit(20) * 50)); + assert_ok!(Loans::withdraw_collateral( + Origin::signed(DAVE), + LEND_KINT, + unit(20) * 50 + )); // Check entries from orml-tokens directly - assert_eq!(free_balance(PHKO, &DAVE), unit(20) * 50); - assert_eq!(reserved_balance(PHKO, &DAVE), unit(80) * 50); + assert_eq!(free_balance(LEND_KINT, &DAVE), unit(20) * 50); + assert_eq!(reserved_balance(LEND_KINT, &DAVE), unit(80) * 50); // Then transfer them - assert_ok!(Loans::transfer(PHKO, &DAVE, &ALICE, unit(20) * 50, true),); + assert_ok!(Loans::transfer(LEND_KINT, &DAVE, &ALICE, unit(20) * 50, true),); // Check entries from orml-tokens directly - assert_eq!(free_balance(PHKO, &DAVE), 0); - assert_eq!(reserved_balance(PHKO, &DAVE), unit(80) * 50); - assert_eq!(free_balance(PHKO, &ALICE), unit(20) * 50); + assert_eq!(free_balance(LEND_KINT, &DAVE), 0); + assert_eq!(reserved_balance(LEND_KINT, &DAVE), unit(80) * 50); + assert_eq!(free_balance(LEND_KINT, &ALICE), unit(20) * 50); - // DAVE Deposit HKO = 100 - 20 = 80 - // DAVE Borrow HKO = 0 + 50 - 40 = 10 - // DAVE liquidity HKO = 80 * 0.5 - 10 = 30 + // DAVE Deposit KINT = 100 - 20 = 80 + // DAVE Borrow KINT = 0 + 50 - 40 = 10 + // DAVE liquidity KINT = 80 * 0.5 - 10 = 30 assert_eq!( - Loans::exchange_rate(HKO) - .saturating_mul_int(Loans::account_deposits(Loans::lend_token_id(HKO).unwrap(), DAVE)), + Loans::exchange_rate(KINT) + .saturating_mul_int(Loans::account_deposits(Loans::lend_token_id(KINT).unwrap(), DAVE)), unit(80) ); - // DAVE Borrow 31 HKO should cause InsufficientLiquidity + // DAVE Borrow 31 KINT should cause InsufficientLiquidity assert_noop!( - Loans::borrow(Origin::signed(DAVE), HKO, unit(31)), + Loans::borrow(Origin::signed(DAVE), KINT, unit(31)), Error::::InsufficientLiquidity ); - assert_ok!(Loans::borrow(Origin::signed(DAVE), HKO, unit(30))); + assert_ok!(Loans::borrow(Origin::signed(DAVE), KINT, unit(30))); - // Assert ALICE Supply HKO 20 + // Assert ALICE Supply KINT 20 assert_eq!( - Loans::exchange_rate(HKO).saturating_mul_int(Tokens::balance(Loans::lend_token_id(HKO).unwrap(), &ALICE)), + Loans::exchange_rate(KINT).saturating_mul_int(Tokens::balance(Loans::lend_token_id(KINT).unwrap(), &ALICE)), unit(20) ); - // ALICE Redeem 20 HKO should be succeeded + // ALICE Redeem 20 KINT should be succeeded // Also means that transfer lend_token succeed - assert_ok!(Loans::redeem_allowed(HKO, &ALICE, unit(20) * 50,)); + assert_ok!(Loans::redeem_allowed(KINT, &ALICE, unit(20) * 50,)); }) } diff --git a/crates/loans/src/tests/market.rs b/crates/loans/src/tests/market.rs index cb5a565c71..e1fb4abb5d 100644 --- a/crates/loans/src/tests/market.rs +++ b/crates/loans/src/tests/market.rs @@ -1,5 +1,7 @@ use crate::{ - mock::{market_mock, new_test_ext, Loans, Origin, Test, ACTIVE_MARKET_MOCK, ALICE, LEND_DOT, MARKET_MOCK}, + mock::{ + market_mock, new_test_ext, Loans, Origin, Test, ACTIVE_MARKET_MOCK, ALICE, LEND_DOT, LEND_KBTC, MARKET_MOCK, + }, Error, InterestRateModel, MarketState, }; use frame_support::{assert_noop, assert_ok, error::BadOrigin}; @@ -10,16 +12,14 @@ use primitives::{ use sp_runtime::{traits::Zero, FixedPointNumber}; const DOT: CurrencyId = Token(DOT_CURRENCY); -const PDOT: CurrencyId = LEND_DOT; -const PUSDT: CurrencyId = LendToken(4); -const SDOT: CurrencyId = ForeignAsset(987997280); +const FOREIGN_ASSET: CurrencyId = ForeignAsset(1200); macro_rules! rate_model_sanity_check { ($call:ident) => { new_test_ext().execute_with(|| { // Invalid base_rate assert_noop!( - Loans::$call(Origin::root(), SDOT, { + Loans::$call(Origin::root(), FOREIGN_ASSET, { let mut market = MARKET_MOCK; market.rate_model = InterestRateModel::new_jump_model( Rate::saturating_from_rational(36, 100), @@ -33,7 +33,7 @@ macro_rules! rate_model_sanity_check { ); // Invalid jump_rate assert_noop!( - Loans::$call(Origin::root(), SDOT, { + Loans::$call(Origin::root(), FOREIGN_ASSET, { let mut market = MARKET_MOCK; market.rate_model = InterestRateModel::new_jump_model( Rate::saturating_from_rational(5, 100), @@ -47,7 +47,7 @@ macro_rules! rate_model_sanity_check { ); // Invalid full_rate assert_noop!( - Loans::$call(Origin::root(), SDOT, { + Loans::$call(Origin::root(), FOREIGN_ASSET, { let mut market = MARKET_MOCK; market.rate_model = InterestRateModel::new_jump_model( Rate::saturating_from_rational(5, 100), @@ -61,7 +61,7 @@ macro_rules! rate_model_sanity_check { ); // base_rate greater than jump_rate assert_noop!( - Loans::$call(Origin::root(), SDOT, { + Loans::$call(Origin::root(), FOREIGN_ASSET, { let mut market = MARKET_MOCK; market.rate_model = InterestRateModel::new_jump_model( Rate::saturating_from_rational(10, 100), @@ -75,7 +75,7 @@ macro_rules! rate_model_sanity_check { ); // jump_rate greater than full_rate assert_noop!( - Loans::$call(Origin::root(), SDOT, { + Loans::$call(Origin::root(), FOREIGN_ASSET, { let mut market = MARKET_MOCK; market.rate_model = InterestRateModel::new_jump_model( Rate::saturating_from_rational(5, 100), @@ -94,10 +94,10 @@ macro_rules! rate_model_sanity_check { #[test] fn active_market_sets_state_to_active() { new_test_ext().execute_with(|| { - Loans::add_market(Origin::root(), SDOT, MARKET_MOCK).unwrap(); - assert_eq!(Loans::market(SDOT).unwrap().state, MarketState::Pending); - Loans::activate_market(Origin::root(), SDOT).unwrap(); - assert_eq!(Loans::market(SDOT).unwrap().state, MarketState::Active); + Loans::add_market(Origin::root(), FOREIGN_ASSET, MARKET_MOCK).unwrap(); + assert_eq!(Loans::market(FOREIGN_ASSET).unwrap().state, MarketState::Pending); + Loans::activate_market(Origin::root(), FOREIGN_ASSET).unwrap(); + assert_eq!(Loans::market(FOREIGN_ASSET).unwrap().state, MarketState::Active); }) } @@ -105,7 +105,7 @@ fn active_market_sets_state_to_active() { fn active_market_does_not_modify_unknown_market_currencies() { new_test_ext().execute_with(|| { assert_noop!( - Loans::activate_market(Origin::root(), SDOT), + Loans::activate_market(Origin::root(), FOREIGN_ASSET), Error::::MarketDoesNotExist ); }) @@ -122,7 +122,7 @@ fn add_market_can_only_be_used_by_root() { fn add_market_ensures_that_market_state_must_be_pending() { new_test_ext().execute_with(|| { assert_noop!( - Loans::add_market(Origin::root(), SDOT, ACTIVE_MARKET_MOCK), + Loans::add_market(Origin::root(), FOREIGN_ASSET, ACTIVE_MARKET_MOCK), Error::::NewMarketMustHavePendingState ); }) @@ -136,17 +136,17 @@ fn add_market_has_sanity_checks_for_rate_models() { #[test] fn add_market_successfully_stores_a_new_market() { new_test_ext().execute_with(|| { - Loans::add_market(Origin::root(), SDOT, MARKET_MOCK).unwrap(); - assert_eq!(Loans::market(SDOT).unwrap(), MARKET_MOCK); + Loans::add_market(Origin::root(), FOREIGN_ASSET, MARKET_MOCK).unwrap(); + assert_eq!(Loans::market(FOREIGN_ASSET).unwrap(), MARKET_MOCK); }) } #[test] fn add_market_ensures_that_market_does_not_exist() { new_test_ext().execute_with(|| { - assert_ok!(Loans::add_market(Origin::root(), SDOT, MARKET_MOCK)); + assert_ok!(Loans::add_market(Origin::root(), FOREIGN_ASSET, MARKET_MOCK)); assert_noop!( - Loans::add_market(Origin::root(), SDOT, MARKET_MOCK), + Loans::add_market(Origin::root(), FOREIGN_ASSET, MARKET_MOCK), Error::::MarketAlreadyExists ); }) @@ -165,15 +165,15 @@ fn force_update_market_can_only_be_used_by_root() { #[test] fn force_update_market_works() { new_test_ext().execute_with(|| { - let mut new_market = market_mock(PDOT); + let mut new_market = market_mock(LEND_DOT); new_market.state = MarketState::Active; Loans::force_update_market(Origin::root(), DOT, new_market).unwrap(); assert_eq!(Loans::market(DOT).unwrap().state, MarketState::Active); - assert_eq!(Loans::market(DOT).unwrap().lend_token_id, PDOT); + assert_eq!(Loans::market(DOT).unwrap().lend_token_id, LEND_DOT); // New lend_token_id must not be in use assert_noop!( - Loans::force_update_market(Origin::root(), DOT, market_mock(PUSDT)), + Loans::force_update_market(Origin::root(), DOT, market_mock(LEND_KBTC)), Error::::InvalidLendTokenId ); assert_ok!(Loans::force_update_market( @@ -189,7 +189,7 @@ fn force_update_market_works() { fn force_update_market_ensures_that_it_is_not_possible_to_modify_unknown_market_currencies() { new_test_ext().execute_with(|| { assert_noop!( - Loans::force_update_market(Origin::root(), SDOT, MARKET_MOCK), + Loans::force_update_market(Origin::root(), FOREIGN_ASSET, MARKET_MOCK), Error::::MarketDoesNotExist ); }) @@ -204,7 +204,18 @@ fn update_market_has_sanity_checks_for_rate_models() { fn update_market_ensures_that_it_is_not_possible_to_modify_unknown_market_currencies() { new_test_ext().execute_with(|| { assert_noop!( - Loans::update_market(Origin::root(), SDOT, None, None, None, None, None, None, None, None,), + Loans::update_market( + Origin::root(), + FOREIGN_ASSET, + None, + None, + None, + None, + None, + None, + None, + None, + ), Error::::MarketDoesNotExist ); }) @@ -333,7 +344,7 @@ fn update_rate_model_works() { assert_noop!( Loans::update_rate_model( Origin::root(), - SDOT, + FOREIGN_ASSET, InterestRateModel::new_jump_model( Rate::saturating_from_rational(36, 100), Rate::saturating_from_rational(15, 100), @@ -347,7 +358,7 @@ fn update_rate_model_works() { assert_noop!( Loans::update_rate_model( Origin::root(), - SDOT, + FOREIGN_ASSET, InterestRateModel::new_jump_model( Rate::saturating_from_rational(5, 100), Rate::saturating_from_rational(36, 100), @@ -361,7 +372,7 @@ fn update_rate_model_works() { assert_noop!( Loans::update_rate_model( Origin::root(), - SDOT, + FOREIGN_ASSET, InterestRateModel::new_jump_model( Rate::saturating_from_rational(5, 100), Rate::saturating_from_rational(15, 100), @@ -375,7 +386,7 @@ fn update_rate_model_works() { assert_noop!( Loans::update_rate_model( Origin::root(), - SDOT, + FOREIGN_ASSET, InterestRateModel::new_jump_model( Rate::saturating_from_rational(10, 100), Rate::saturating_from_rational(9, 100), @@ -389,7 +400,7 @@ fn update_rate_model_works() { assert_noop!( Loans::update_rate_model( Origin::root(), - SDOT, + FOREIGN_ASSET, InterestRateModel::new_jump_model( Rate::saturating_from_rational(5, 100), Rate::saturating_from_rational(15, 100), From 68e0ae7e7d3f87dae6414b04a5dfee5f0c0777fa Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Thu, 27 Oct 2022 16:12:55 +0200 Subject: [PATCH 46/58] chore(loans): remove leftover liquidation-free code --- crates/loans/src/lend_token.rs | 2 +- crates/loans/src/lib.rs | 114 ++++++--------------------------- crates/loans/src/mock.rs | 2 - crates/loans/src/tests.rs | 7 +- 4 files changed, 24 insertions(+), 101 deletions(-) diff --git a/crates/loans/src/lend_token.rs b/crates/loans/src/lend_token.rs index 3dead11c1c..037e6bcc5b 100644 --- a/crates/loans/src/lend_token.rs +++ b/crates/loans/src/lend_token.rs @@ -131,7 +131,7 @@ impl Pallet { let collateral_value = Self::collateral_asset_value(who, underlying_id)?; // liquidity of all assets - let (liquidity, _, _, _) = Self::get_account_liquidity(who)?; + let (liquidity, _) = Self::get_account_liquidity(who)?; if liquidity >= collateral_value { return Ok(voucher_balance); diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index a174981e0d..de5e08c349 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -1128,114 +1128,41 @@ impl Pallet { T::PalletId::get().into_account_truncating() } - fn get_lf_borrowed_value(_account: &T::AccountId) -> Result { - Ok(FixedU128::zero()) - } - - fn get_lf_base_position(_account: &T::AccountId) -> Result { - Ok(FixedU128::zero()) - } - - fn get_lf_liquidation_base_position(_account: &T::AccountId) -> Result { - Ok(FixedU128::zero()) - } - - pub fn get_account_liquidity( - account: &T::AccountId, - ) -> Result<(Liquidity, Shortfall, Liquidity, Shortfall), DispatchError> { + pub fn get_account_liquidity(account: &T::AccountId) -> Result<(Liquidity, Shortfall), DispatchError> { let total_borrow_value = Self::total_borrowed_value(account)?; let total_collateral_value = Self::total_collateral_value(account)?; - let lf_borrowed_value = Self::get_lf_borrowed_value(account)?; - let lf_base_position = Self::get_lf_base_position(account)?; log::trace!( target: "loans::get_account_liquidity", - "account: {:?}, total_borrow_value: {:?}, total_collateral_value: {:?}, lf_borrowed_value: {:?}, lf_base_position: {:?}", + "account: {:?}, total_borrow_value: {:?}, total_collateral_value: {:?}", account, total_borrow_value.into_inner(), total_collateral_value.into_inner(), - lf_borrowed_value.into_inner(), - lf_base_position.into_inner(), ); - match ( - total_collateral_value > total_borrow_value, - lf_base_position > lf_borrowed_value, - ) { - // TODO: simplify this function and use checked math operations - (true, true) => Ok(( - total_collateral_value - total_borrow_value, - FixedU128::zero(), - lf_base_position - lf_borrowed_value, - FixedU128::zero(), - )), - (true, false) => Ok(( - total_collateral_value - total_borrow_value, - FixedU128::zero(), - FixedU128::zero(), - lf_borrowed_value - lf_base_position, - )), - (false, true) => Ok(( - FixedU128::zero(), - total_borrow_value - total_collateral_value, - lf_base_position - lf_borrowed_value, - FixedU128::zero(), - )), - (false, false) => Ok(( - FixedU128::zero(), - total_borrow_value - total_collateral_value, - FixedU128::zero(), - lf_borrowed_value - lf_base_position, - )), + if total_collateral_value > total_borrow_value { + Ok((total_collateral_value - total_borrow_value, FixedU128::zero())) + } else { + Ok((FixedU128::zero(), total_borrow_value - total_collateral_value)) } } pub fn get_account_liquidation_threshold_liquidity( account: &T::AccountId, - ) -> Result<(Liquidity, Shortfall, Liquidity, Shortfall), DispatchError> { + ) -> Result<(Liquidity, Shortfall), DispatchError> { let total_borrow_value = Self::total_borrowed_value(account)?; let total_collateral_value = Self::total_liquidation_threshold_value(account)?; - let lf_borrowed_value = Self::get_lf_borrowed_value(account)?; - let lf_base_position = Self::get_lf_liquidation_base_position(account)?; - log::trace!( target: "loans::get_account_liquidation_threshold_liquidity", - "account: {:?}, total_borrow_value: {:?}, total_collateral_value: {:?}, lf_borrowed_value: {:?}, lf_base_position: {:?}", + "account: {:?}, total_borrow_value: {:?}, total_collateral_value: {:?}", account, total_borrow_value.into_inner(), total_collateral_value.into_inner(), - lf_borrowed_value.into_inner(), - lf_base_position.into_inner(), ); - - match ( - total_collateral_value > total_borrow_value, - lf_base_position > lf_borrowed_value, - ) { - (true, true) => Ok(( - total_collateral_value - total_borrow_value, - FixedU128::zero(), - lf_base_position - lf_borrowed_value, - FixedU128::zero(), - )), - (true, false) => Ok(( - total_collateral_value - total_borrow_value, - FixedU128::zero(), - FixedU128::zero(), - lf_borrowed_value - lf_base_position, - )), - (false, true) => Ok(( - FixedU128::zero(), - total_borrow_value - total_collateral_value, - lf_base_position - lf_borrowed_value, - FixedU128::zero(), - )), - (false, false) => Ok(( - FixedU128::zero(), - total_borrow_value - total_collateral_value, - FixedU128::zero(), - lf_borrowed_value - lf_base_position, - )), + if total_collateral_value > total_borrow_value { + Ok((total_collateral_value - total_borrow_value, FixedU128::zero())) + } else { + Ok((FixedU128::zero(), total_borrow_value - total_collateral_value)) } } @@ -1499,15 +1426,14 @@ impl Pallet { repay_amount, market ); - let (liquidity, shortfall, lf_liquidity, _) = Self::get_account_liquidation_threshold_liquidity(borrower)?; + let (_, shortfall) = Self::get_account_liquidation_threshold_liquidity(borrower)?; // C_other >= B_other + B_dot_over - // C_other >= B_other + max(B_dot - C_lf, 0) - // C_other + C_lf >= B_other + B_dot - B_dot + C_lf + max(B_dot - C_lf, 0) - // C_all - B_all >= max(0, C_lf - B_dot) - // C_all - B_all >= 0 && C_all - B_all >= max(0, C_lf - B_dot) - // shortfall == 0 && liquidity > lf_liquidity - if shortfall.is_zero() && liquidity >= lf_liquidity { + // C_other >= B_other + // C_other >= B_other + B_dot - B_dot + // C_all - B_all >= 0 + // shortfall == 0 + if shortfall.is_zero() { return Err(Error::::InsufficientShortfall.into()); } @@ -1756,8 +1682,8 @@ impl Pallet { // `account`: account that need a liquidity check // `reduce_amount`: values that will have an impact on liquidity fn ensure_liquidity(account: &T::AccountId, reduce_amount: FixedU128) -> DispatchResult { - let (total_liquidity, _, lf_liquidity, _) = Self::get_account_liquidity(account)?; - if total_liquidity >= lf_liquidity + reduce_amount { + let (total_liquidity, _) = Self::get_account_liquidity(account)?; + if total_liquidity >= reduce_amount { return Ok(()); } Err(Error::::InsufficientLiquidity.into()) diff --git a/crates/loans/src/mock.rs b/crates/loans/src/mock.rs index 75ed1544e5..107c693aa6 100644 --- a/crates/loans/src/mock.rs +++ b/crates/loans/src/mock.rs @@ -219,8 +219,6 @@ impl MockPriceFeeder { thread_local! { pub static PRICES: RefCell>> = { RefCell::new( - // Include a foreign assets to act as a liquidation-free collateral for now. - // TODO: Remove liquidation-free collateral vec![Token(KINT), Token(DOT), Token(KSM), Token(KBTC), Token(INTR), Token(IBTC), ForeignAsset(100000)] .iter() .map(|&x| (x, Some((Price::saturating_from_integer(1), 1)))) diff --git a/crates/loans/src/tests.rs b/crates/loans/src/tests.rs index 387cd46a4c..c01d085f04 100644 --- a/crates/loans/src/tests.rs +++ b/crates/loans/src/tests.rs @@ -21,7 +21,6 @@ mod lend_tokens; mod liquidate_borrow; mod market; -use currency::Amount; use frame_support::{assert_noop, assert_ok}; use sp_runtime::{ @@ -446,7 +445,7 @@ fn get_account_liquidity_works() { Loans::mint(Origin::signed(ALICE), IBTC, unit(200)).unwrap(); Loans::deposit_all_collateral(Origin::signed(ALICE), IBTC).unwrap(); - let (liquidity, _, _, _) = Loans::get_account_liquidity(&ALICE).unwrap(); + let (liquidity, _) = Loans::get_account_liquidity(&ALICE).unwrap(); assert_eq!(liquidity, FixedU128::from_inner(unit(100))); }) @@ -467,12 +466,12 @@ fn get_account_liquidation_threshold_liquidity_works() { Loans::borrow(Origin::signed(ALICE), KSM, unit(100)).unwrap(); Loans::borrow(Origin::signed(ALICE), DOT, unit(100)).unwrap(); - let (liquidity, _, _, _) = Loans::get_account_liquidation_threshold_liquidity(&ALICE).unwrap(); + let (liquidity, _) = Loans::get_account_liquidation_threshold_liquidity(&ALICE).unwrap(); assert_eq!(liquidity, FixedU128::from_inner(unit(20))); MockPriceFeeder::set_price(KSM, 2.into()); - let (liquidity, shortfall, _, _) = Loans::get_account_liquidation_threshold_liquidity(&ALICE).unwrap(); + let (liquidity, shortfall) = Loans::get_account_liquidation_threshold_liquidity(&ALICE).unwrap(); assert_eq!(liquidity, FixedU128::from_inner(unit(0))); assert_eq!(shortfall, FixedU128::from_inner(unit(80))); From e6bcfdab04b8160fb549ae04d7dc34420fdf58b7 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Thu, 27 Oct 2022 16:16:49 +0200 Subject: [PATCH 47/58] chore(loans): fix tests --- crates/loans/src/benchmarking.rs | 28 +++++------ standalone/runtime/tests/mock/mod.rs | 10 ++-- standalone/runtime/tests/test_loans.rs | 66 +++++++++++++------------- 3 files changed, 52 insertions(+), 52 deletions(-) diff --git a/crates/loans/src/benchmarking.rs b/crates/loans/src/benchmarking.rs index e4d50a69f8..bd902749c7 100644 --- a/crates/loans/src/benchmarking.rs +++ b/crates/loans/src/benchmarking.rs @@ -19,10 +19,10 @@ const SEED: u32 = 0; const KSM: CurrencyId = Token(KSM_CURRENCY); const KBTC: CurrencyId = Token(KBTC_CURRENCY); -const LendKSM: CurrencyId = LendToken(3); +const LEND_KSM: CurrencyId = LendToken(3); const LendKBTC: CurrencyId = LendToken(4); const DOT: CurrencyId = Token(DOT_CURRENCY); -const LendDOT: CurrencyId = LendToken(1); +const LEND_DOT: CurrencyId = LendToken(1); const KINT: CurrencyId = Token(KINT_CURRENCY); const RATE_MODEL_MOCK: InterestRateModel = InterestRateModel::Jump(JumpModel { @@ -67,7 +67,7 @@ fn transfer_initial_balance::set_balance( SystemOrigin::Root.into(), account_id.clone(), - LendKSM, + LEND_KSM, 10_000_000_000_000_u128, 0_u128, ) @@ -93,7 +93,7 @@ fn transfer_initial_balance::set_balance( SystemOrigin::Root.into(), account_id, - LendDOT, + LEND_DOT, 10_000_000_000_000_u128, 0_u128, ) @@ -125,9 +125,9 @@ benchmarks! { } add_market { - }: _(SystemOrigin::Root, DOT, pending_market_mock::(LendDOT)) + }: _(SystemOrigin::Root, DOT, pending_market_mock::(LEND_DOT)) verify { - assert_last_event::(Event::::NewMarket(DOT, pending_market_mock::(LendDOT)).into()); + assert_last_event::(Event::::NewMarket(DOT, pending_market_mock::(LEND_DOT)).into()); } activate_market { @@ -158,7 +158,7 @@ benchmarks! { Some(1_000_000_000_000_000_000_000u128) ) verify { - let mut market = pending_market_mock::(LendKSM); + let mut market = pending_market_mock::(LEND_KSM); market.reserve_factor = Ratio::from_percent(50); market.close_factor = Ratio::from_percent(15); assert_last_event::(Event::::UpdatedMarket(KSM, market).into()); @@ -330,17 +330,17 @@ benchmarks! { let borrowed_amount: u32 = 200_000_000; let liquidate_amount: u32 = 100_000_000; let incentive_amount: u32 = 110_000_000; - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), LendDOT, pending_market_mock::(KINT))); - assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), LendDOT)); - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KSM, pending_market_mock::(LendKSM))); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), LEND_DOT, pending_market_mock::(KINT))); + assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), LEND_DOT)); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KSM, pending_market_mock::(LEND_KSM))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KSM)); assert_ok!(Loans::::mint(SystemOrigin::Signed(bob.clone()).into(), KSM, deposit_amount.into())); - assert_ok!(Loans::::mint(SystemOrigin::Signed(alice.clone()).into(), LendDOT, deposit_amount.into())); - assert_ok!(Loans::::deposit_all_collateral(SystemOrigin::Signed(alice.clone()).into(), LendDOT)); + assert_ok!(Loans::::mint(SystemOrigin::Signed(alice.clone()).into(), LEND_DOT, deposit_amount.into())); + assert_ok!(Loans::::deposit_all_collateral(SystemOrigin::Signed(alice.clone()).into(), LEND_DOT)); set_account_borrows::(alice.clone(), KSM, borrowed_amount.into()); - }: _(SystemOrigin::Signed(bob.clone()), alice.clone(), KSM, liquidate_amount.into(), LendDOT) + }: _(SystemOrigin::Signed(bob.clone()), alice.clone(), KSM, liquidate_amount.into(), LEND_DOT) verify { - assert_last_event::(Event::::LiquidatedBorrow(bob.clone(), alice.clone(), KSM, LendDOT, liquidate_amount.into(), incentive_amount.into()).into()); + assert_last_event::(Event::::LiquidatedBorrow(bob.clone(), alice.clone(), KSM, LEND_DOT, liquidate_amount.into(), incentive_amount.into()).into()); } add_reserves { diff --git a/standalone/runtime/tests/mock/mod.rs b/standalone/runtime/tests/mock/mod.rs index 47e1fd24d4..d6c6c8dc7a 100644 --- a/standalone/runtime/tests/mock/mod.rs +++ b/standalone/runtime/tests/mock/mod.rs @@ -193,11 +193,11 @@ pub const DEFAULT_WRAPPED_CURRENCY: ::CurrencyId pub const DEFAULT_NATIVE_CURRENCY: ::CurrencyId = Token(INTR); pub const DEFAULT_GRIEFING_CURRENCY: ::CurrencyId = DEFAULT_NATIVE_CURRENCY; -pub const LendDOT: CurrencyId = LendToken(1); -pub const LendKINT: CurrencyId = LendToken(2); -pub const LendKSM: CurrencyId = LendToken(3); -pub const LendKBTC: CurrencyId = LendToken(4); -pub const LendIBTC: CurrencyId = LendToken(5); +pub const LEND_DOT: CurrencyId = LendToken(1); +pub const LEND_KINT: CurrencyId = LendToken(2); +pub const LEND_KSM: CurrencyId = LendToken(3); +pub const LEND_KBTC: CurrencyId = LendToken(4); +pub const LEND_IBTC: CurrencyId = LendToken(5); pub fn default_vault_id_of(hash: [u8; 32]) -> VaultId { VaultId { diff --git a/standalone/runtime/tests/test_loans.rs b/standalone/runtime/tests/test_loans.rs index 4d78f14730..c156cdabe4 100644 --- a/standalone/runtime/tests/test_loans.rs +++ b/standalone/runtime/tests/test_loans.rs @@ -65,17 +65,17 @@ fn test_real_market(execute: impl Fn() -> R) { set_up_market( Token(KINT), FixedU128::from_inner(115_942_028_985_507_246_376_810_000), - LendKINT, + LEND_KINT, ); set_up_market( Token(KSM), FixedU128::from_inner(4_573_498_406_135_805_461_670_000), - LendKSM, + LEND_KSM, ); set_up_market( Token(DOT), FixedU128::from_inner(324_433_053_239_464_036_596_000), - LendDOT, + LEND_DOT, ); execute() }); @@ -96,8 +96,8 @@ fn integration_test_liquidation() { .dispatch(origin_of(user.clone()))); // Check entries from orml-tokens directly - assert_eq!(free_balance(LendKINT, &user), 1000); - assert_eq!(reserved_balance(LendKINT, &user), 0); + assert_eq!(free_balance(LEND_KINT, &user), 1000); + assert_eq!(reserved_balance(LEND_KINT, &user), 0); assert_ok!(Call::Loans(LoansCall::mint { asset_id: ksm, @@ -106,14 +106,14 @@ fn integration_test_liquidation() { .dispatch(origin_of(lp.clone()))); // Check entries from orml-tokens directly - assert_eq!(free_balance(LendKSM, &lp), 50); - assert_eq!(reserved_balance(LendKSM, &lp), 0); + assert_eq!(free_balance(LEND_KSM, &lp), 50); + assert_eq!(reserved_balance(LEND_KSM, &lp), 0); assert_ok!(Call::Loans(LoansCall::deposit_all_collateral { asset_id: kint }).dispatch(origin_of(user.clone()))); // Check entries from orml-tokens directly - assert_eq!(free_balance(LendKINT, &user), 0); - assert_eq!(reserved_balance(LendKINT, &user), 1000); + assert_eq!(free_balance(LEND_KINT, &user), 0); + assert_eq!(reserved_balance(LEND_KINT, &user), 1000); assert_err!( Call::Loans(LoansCall::borrow { @@ -158,23 +158,23 @@ fn integration_test_liquidation() { }) .dispatch(origin_of(lp.clone()))); - assert_eq!(free_balance(LendKINT, &user), 0); + assert_eq!(free_balance(LEND_KINT, &user), 0); // borrower's reserved collateral is slashed - assert_eq!(reserved_balance(LendKINT, &user), 610); + assert_eq!(reserved_balance(LEND_KINT, &user), 610); // borrower's borrowed balance is unchanged assert_eq!(free_balance(ksm, &user), 1000000000015); // the liquidator receives most of the slashed collateral - assert_eq!(reserved_balance(LendKINT, &lp), 0); - assert_eq!(free_balance(LendKINT, &lp), 380); + assert_eq!(reserved_balance(LEND_KINT, &lp), 0); + assert_eq!(free_balance(LEND_KINT, &lp), 380); // the rest of the slashed collateral routed to the incentive reward account's free balance assert_eq!( - free_balance(LendKINT, &LoansPallet::incentive_reward_account_id().unwrap()), + free_balance(LEND_KINT, &LoansPallet::incentive_reward_account_id().unwrap()), 10 ); assert_eq!( - reserved_balance(LendKINT, &LoansPallet::incentive_reward_account_id().unwrap()), + reserved_balance(LEND_KINT, &LoansPallet::incentive_reward_account_id().unwrap()), 0 ); }); @@ -193,11 +193,11 @@ fn integration_test_lend_token_vault_insufficient_balance() { .dispatch(origin_of(account_of(USER)))); // Check entries from orml-tokens directly - assert_eq!(free_balance(LendDOT, &vault_account_id), 1000); - assert_eq!(reserved_balance(LendDOT, &vault_account_id), 0); + assert_eq!(free_balance(LEND_DOT, &vault_account_id), 1000); + assert_eq!(reserved_balance(LEND_DOT, &vault_account_id), 0); assert_eq!( - LoansPallet::account_deposits(LendDOT, vault_account_id.clone()), - reserved_balance(LendDOT, &vault_account_id) + LoansPallet::account_deposits(LEND_DOT, vault_account_id.clone()), + reserved_balance(LEND_DOT, &vault_account_id) ); let lend_tokens = LoansPallet::free_lend_tokens(dot, &vault_account_id).unwrap(); @@ -205,11 +205,11 @@ fn integration_test_lend_token_vault_insufficient_balance() { // Depositing all the collateral should leave none free for registering as a vault assert_ok!(Call::Loans(LoansCall::deposit_all_collateral { asset_id: dot }) .dispatch(origin_of(vault_account_id.clone()))); - assert_eq!(free_balance(LendDOT, &vault_account_id), 0); - assert_eq!(reserved_balance(LendDOT, &vault_account_id), 1000); + assert_eq!(free_balance(LEND_DOT, &vault_account_id), 0); + assert_eq!(reserved_balance(LEND_DOT, &vault_account_id), 1000); assert_eq!( LoansPallet::account_deposits(lend_tokens.currency(), vault_account_id.clone()), - reserved_balance(LendDOT, &vault_account_id) + reserved_balance(LEND_DOT, &vault_account_id) ); let lend_token_vault_id = PrimitiveVaultId::new(vault_account_id.clone(), lend_tokens.currency(), Token(IBTC)); @@ -221,13 +221,13 @@ fn integration_test_lend_token_vault_insufficient_balance() { // Withdraw the lend_tokens to use them for another purpose assert_ok!(Call::Loans(LoansCall::withdraw_all_collateral { asset_id: dot }) .dispatch(origin_of(vault_account_id.clone()))); - assert_eq!(free_balance(LendDOT, &vault_account_id), 1000); - assert_eq!(reserved_balance(LendDOT, &vault_account_id), 0); + assert_eq!(free_balance(LEND_DOT, &vault_account_id), 1000); + assert_eq!(reserved_balance(LEND_DOT, &vault_account_id), 0); // This time, registering a vault works because the lend_tokens are unlocked assert_ok!(get_register_vault_result(&lend_token_vault_id, lend_tokens)); - assert_eq!(free_balance(LendDOT, &vault_account_id), 0); - assert_eq!(reserved_balance(LendDOT, &vault_account_id), 1000); + assert_eq!(free_balance(LEND_DOT, &vault_account_id), 0); + assert_eq!(reserved_balance(LEND_DOT, &vault_account_id), 1000); assert_eq!( LoansPallet::account_deposits(lend_tokens.currency(), vault_account_id.clone()), 0 @@ -273,8 +273,8 @@ fn integration_test_lend_token_transfer_reserved_fails() { }) .dispatch(origin_of(vault_account_id.clone()))); - assert_eq!(free_balance(LendDOT, &vault_account_id), 1000); - assert_eq!(reserved_balance(LendDOT, &vault_account_id), 0); + assert_eq!(free_balance(LEND_DOT, &vault_account_id), 1000); + assert_eq!(reserved_balance(LEND_DOT, &vault_account_id), 0); let lend_tokens = LoansPallet::free_lend_tokens(dot, &vault_account_id).unwrap(); // Lock some lend_tokens into the lending market @@ -287,8 +287,8 @@ fn integration_test_lend_token_transfer_reserved_fails() { LoansPallet::account_deposits(lend_tokens.currency(), vault_account_id.clone()), reserved_balance(lend_tokens.currency(), &vault_account_id) ); - assert_eq!(free_balance(LendDOT, &vault_account_id), 500); - assert_eq!(reserved_balance(LendDOT, &vault_account_id), 500); + assert_eq!(free_balance(LEND_DOT, &vault_account_id), 500); + assert_eq!(reserved_balance(LEND_DOT, &vault_account_id), 500); let half_lend_tokens = lend_tokens.checked_div(&FixedU128::from_u32(2)).unwrap(); assert_eq!( @@ -302,8 +302,8 @@ fn integration_test_lend_token_transfer_reserved_fails() { TokensError::BalanceTooLow ); assert_ok!(half_lend_tokens.transfer(&vault_account_id, &lp_account_id)); - assert_eq!(free_balance(LendDOT, &vault_account_id), 0); - assert_eq!(reserved_balance(LendDOT, &vault_account_id), 500); - assert_eq!(free_balance(LendDOT, &lp_account_id), 500); + assert_eq!(free_balance(LEND_DOT, &vault_account_id), 0); + assert_eq!(reserved_balance(LEND_DOT, &vault_account_id), 500); + assert_eq!(free_balance(LEND_DOT, &lp_account_id), 500); }); } From ef6a7cbc38a12fb77590fcc3df6be581a2cbb3c1 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Thu, 27 Oct 2022 16:37:33 +0200 Subject: [PATCH 48/58] fix(loans): warnings --- crates/loans/src/lend_token.rs | 10 +++------- crates/loans/src/lib.rs | 1 + crates/loans/src/mock.rs | 2 +- crates/loans/src/tests/lend_tokens.rs | 9 +++------ crates/loans/src/tests/liquidate_borrow.rs | 1 - crates/loans/src/tests/market.rs | 2 +- crates/traits/src/lib.rs | 1 - standalone/runtime/tests/mock/loans_testing_utils.rs | 2 +- standalone/runtime/tests/test_loans.rs | 1 - 9 files changed, 10 insertions(+), 19 deletions(-) diff --git a/crates/loans/src/lend_token.rs b/crates/loans/src/lend_token.rs index 037e6bcc5b..b0bf03fac9 100644 --- a/crates/loans/src/lend_token.rs +++ b/crates/loans/src/lend_token.rs @@ -16,13 +16,9 @@ // limitations under the License. use crate::{AssetIdOf, BalanceOf, *}; -use frame_support::{ - require_transactional, - traits::tokens::{ - fungibles::{Inspect, Transfer}, - DepositConsequence, WithdrawConsequence, - }, -}; + +#[cfg(test)] +use frame_support::traits::tokens::{DepositConsequence, WithdrawConsequence}; #[cfg(test)] impl Pallet { diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index de5e08c349..fe5077d34d 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -69,6 +69,7 @@ mod tests; mod farming; mod interest; +#[cfg(test)] mod lend_token; mod rate_model; mod types; diff --git a/crates/loans/src/mock.rs b/crates/loans/src/mock.rs index 107c693aa6..c8402f2842 100644 --- a/crates/loans/src/mock.rs +++ b/crates/loans/src/mock.rs @@ -27,7 +27,7 @@ use frame_support::{ PalletId, }; use frame_system::EnsureRoot; -use mocktopus::{macros::mockable, mocking::*}; +use mocktopus::macros::mockable; use orml_traits::{parameter_type_with_key, DataFeeder, DataProvider, DataProviderExtended}; use primitives::{ CurrencyId::{ForeignAsset, LendToken, Token}, diff --git a/crates/loans/src/tests/lend_tokens.rs b/crates/loans/src/tests/lend_tokens.rs index a1febc4f93..05bda29830 100644 --- a/crates/loans/src/tests/lend_tokens.rs +++ b/crates/loans/src/tests/lend_tokens.rs @@ -3,16 +3,13 @@ use crate::{ market_mock, new_test_ext, AccountId, Loans, Origin, Test, Tokens, ALICE, DAVE, LEND_KBTC, LEND_KINT, LEND_KSM, }, tests::unit, - Config, Error, -}; -use frame_support::{ - assert_err, assert_noop, assert_ok, - traits::tokens::fungibles::{Inspect, Transfer}, + Error, }; +use frame_support::{assert_err, assert_noop, assert_ok, traits::tokens::fungibles::Inspect}; use orml_traits::{MultiCurrency, MultiReservableCurrency}; use primitives::{ Balance, - CurrencyId::{self, ForeignAsset, LendToken, Token}, + CurrencyId::{self, ForeignAsset, Token}, KBTC as KBTC_CURRENCY, KINT as KINT_CURRENCY, KSM as KSM_CURRENCY, }; use sp_runtime::{FixedPointNumber, TokenError}; diff --git a/crates/loans/src/tests/liquidate_borrow.rs b/crates/loans/src/tests/liquidate_borrow.rs index 4f2a721a74..8cc1c1e453 100644 --- a/crates/loans/src/tests/liquidate_borrow.rs +++ b/crates/loans/src/tests/liquidate_borrow.rs @@ -4,7 +4,6 @@ use crate::{ Error, MarketState, }; use frame_support::{assert_noop, assert_ok, traits::fungibles::Inspect}; -use pallet_traits::LoansApi; use primitives::{ CurrencyId::{self, Token}, Rate, DOT as DOT_CURRENCY, KBTC as KBTC_CURRENCY, KSM as KSM_CURRENCY, diff --git a/crates/loans/src/tests/market.rs b/crates/loans/src/tests/market.rs index e1fb4abb5d..554625598c 100644 --- a/crates/loans/src/tests/market.rs +++ b/crates/loans/src/tests/market.rs @@ -6,7 +6,7 @@ use crate::{ }; use frame_support::{assert_noop, assert_ok, error::BadOrigin}; use primitives::{ - CurrencyId::{self, ForeignAsset, LendToken, Token}, + CurrencyId::{self, ForeignAsset, Token}, Rate, Ratio, DOT as DOT_CURRENCY, }; use sp_runtime::{traits::Zero, FixedPointNumber}; diff --git a/crates/traits/src/lib.rs b/crates/traits/src/lib.rs index 67c63bc141..5b6f31e28e 100644 --- a/crates/traits/src/lib.rs +++ b/crates/traits/src/lib.rs @@ -2,7 +2,6 @@ use frame_support::dispatch::DispatchError; use num_bigint::{BigUint, ToBigUint}; -use sp_std::prelude::*; use primitives::{CurrencyId, PriceDetail}; diff --git a/standalone/runtime/tests/mock/loans_testing_utils.rs b/standalone/runtime/tests/mock/loans_testing_utils.rs index e3009f9790..2a4aa9cc79 100644 --- a/standalone/runtime/tests/mock/loans_testing_utils.rs +++ b/standalone/runtime/tests/mock/loans_testing_utils.rs @@ -1,7 +1,7 @@ use currency::Amount; use pallet_loans::JumpModel; -use crate::{assert_eq, *}; +use crate::*; pub const fn market_mock(lend_token_id: CurrencyId) -> Market { Market { diff --git a/standalone/runtime/tests/test_loans.rs b/standalone/runtime/tests/test_loans.rs index c156cdabe4..db3730c269 100644 --- a/standalone/runtime/tests/test_loans.rs +++ b/standalone/runtime/tests/test_loans.rs @@ -1,4 +1,3 @@ -use currency::Amount; use interbtc_runtime_standalone::{CurrencyId::Token, Tokens, KINT}; mod mock; use mock::{assert_eq, *}; From e7cf4f4d8b7698f86d11c8fb6df82b2aa26d9dcc Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Thu, 27 Oct 2022 16:58:34 +0200 Subject: [PATCH 49/58] feat: use latest orml --- Cargo.lock | 18 +++++++++--------- crates/currency/Cargo.toml | 4 ++-- crates/fee/Cargo.toml | 4 ++-- crates/issue/Cargo.toml | 8 ++++---- crates/nomination/Cargo.toml | 8 ++++---- crates/oracle/Cargo.toml | 4 ++-- crates/redeem/Cargo.toml | 8 ++++---- crates/replace/Cargo.toml | 8 ++++---- crates/staking/Cargo.toml | 4 ++-- crates/vault-registry/Cargo.toml | 4 ++-- parachain/runtime/interlay/Cargo.toml | 16 ++++++++-------- parachain/runtime/kintsugi/Cargo.toml | 16 ++++++++-------- parachain/runtime/runtime-tests/Cargo.toml | 16 ++++++++-------- parachain/runtime/testnet-interlay/Cargo.toml | 16 ++++++++-------- parachain/runtime/testnet-kintsugi/Cargo.toml | 16 ++++++++-------- standalone/runtime/Cargo.toml | 8 ++++---- 16 files changed, 79 insertions(+), 79 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f4a2af8a15..674f95bc06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6015,7 +6015,7 @@ dependencies = [ [[package]] name = "orml-asset-registry" version = "0.4.1-dev" -source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=44fda4432b71f49ee59a650cf4775db895ab97af#44fda4432b71f49ee59a650cf4775db895ab97af" +source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=2c48b626addafbea0227c068c9ab0fc16666b1b5#2c48b626addafbea0227c068c9ab0fc16666b1b5" dependencies = [ "frame-support", "frame-system", @@ -6052,7 +6052,7 @@ dependencies = [ [[package]] name = "orml-tokens" version = "0.4.1-dev" -source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=44fda4432b71f49ee59a650cf4775db895ab97af#44fda4432b71f49ee59a650cf4775db895ab97af" +source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=2c48b626addafbea0227c068c9ab0fc16666b1b5#2c48b626addafbea0227c068c9ab0fc16666b1b5" dependencies = [ "frame-support", "frame-system", @@ -6067,7 +6067,7 @@ dependencies = [ [[package]] name = "orml-traits" version = "0.4.1-dev" -source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=44fda4432b71f49ee59a650cf4775db895ab97af#44fda4432b71f49ee59a650cf4775db895ab97af" +source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=2c48b626addafbea0227c068c9ab0fc16666b1b5#2c48b626addafbea0227c068c9ab0fc16666b1b5" dependencies = [ "frame-support", "impl-trait-for-tuples", @@ -6085,7 +6085,7 @@ dependencies = [ [[package]] name = "orml-unknown-tokens" version = "0.4.1-dev" -source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=44fda4432b71f49ee59a650cf4775db895ab97af#44fda4432b71f49ee59a650cf4775db895ab97af" +source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=2c48b626addafbea0227c068c9ab0fc16666b1b5#2c48b626addafbea0227c068c9ab0fc16666b1b5" dependencies = [ "frame-support", "frame-system", @@ -6100,7 +6100,7 @@ dependencies = [ [[package]] name = "orml-utilities" version = "0.4.1-dev" -source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=44fda4432b71f49ee59a650cf4775db895ab97af#44fda4432b71f49ee59a650cf4775db895ab97af" +source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=2c48b626addafbea0227c068c9ab0fc16666b1b5#2c48b626addafbea0227c068c9ab0fc16666b1b5" dependencies = [ "frame-support", "parity-scale-codec", @@ -6114,7 +6114,7 @@ dependencies = [ [[package]] name = "orml-vesting" version = "0.4.1-dev" -source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=44fda4432b71f49ee59a650cf4775db895ab97af#44fda4432b71f49ee59a650cf4775db895ab97af" +source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=2c48b626addafbea0227c068c9ab0fc16666b1b5#2c48b626addafbea0227c068c9ab0fc16666b1b5" dependencies = [ "frame-support", "frame-system", @@ -6129,7 +6129,7 @@ dependencies = [ [[package]] name = "orml-xcm" version = "0.4.1-dev" -source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=44fda4432b71f49ee59a650cf4775db895ab97af#44fda4432b71f49ee59a650cf4775db895ab97af" +source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=2c48b626addafbea0227c068c9ab0fc16666b1b5#2c48b626addafbea0227c068c9ab0fc16666b1b5" dependencies = [ "frame-support", "frame-system", @@ -6143,7 +6143,7 @@ dependencies = [ [[package]] name = "orml-xcm-support" version = "0.4.1-dev" -source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=44fda4432b71f49ee59a650cf4775db895ab97af#44fda4432b71f49ee59a650cf4775db895ab97af" +source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=2c48b626addafbea0227c068c9ab0fc16666b1b5#2c48b626addafbea0227c068c9ab0fc16666b1b5" dependencies = [ "frame-support", "orml-traits", @@ -6157,7 +6157,7 @@ dependencies = [ [[package]] name = "orml-xtokens" version = "0.4.1-dev" -source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=44fda4432b71f49ee59a650cf4775db895ab97af#44fda4432b71f49ee59a650cf4775db895ab97af" +source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=2c48b626addafbea0227c068c9ab0fc16666b1b5#2c48b626addafbea0227c068c9ab0fc16666b1b5" dependencies = [ "cumulus-primitives-core", "frame-support", diff --git a/crates/currency/Cargo.toml b/crates/currency/Cargo.toml index f897afa603..cd88490211 100644 --- a/crates/currency/Cargo.toml +++ b/crates/currency/Cargo.toml @@ -21,8 +21,8 @@ pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } # for other pallets wanting to mock functions mocktopus = {version = "0.7.0", optional = true } diff --git a/crates/fee/Cargo.toml b/crates/fee/Cargo.toml index c056c2eeba..957a934cf8 100644 --- a/crates/fee/Cargo.toml +++ b/crates/fee/Cargo.toml @@ -35,8 +35,8 @@ pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = " currency = { path = "../currency", features = ["testing-utils"] } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } # Parachain dependencies primitives = { package = "interbtc-primitives", path = "../../primitives"} diff --git a/crates/issue/Cargo.toml b/crates/issue/Cargo.toml index d77c75db54..51e577d08a 100644 --- a/crates/issue/Cargo.toml +++ b/crates/issue/Cargo.toml @@ -35,8 +35,8 @@ vault-registry = { path = "../vault-registry", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false, optional = true } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false, optional = true } +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false, optional = true } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false, optional = true } [dev-dependencies] mocktopus = "0.7.0" @@ -47,8 +47,8 @@ reward = { path = "../reward" } staking = { path = "../staking" } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af" } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af" } +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5" } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5" } [features] default = ["std"] diff --git a/crates/nomination/Cargo.toml b/crates/nomination/Cargo.toml index 6fc35b82f3..6e5264396a 100644 --- a/crates/nomination/Cargo.toml +++ b/crates/nomination/Cargo.toml @@ -33,16 +33,16 @@ staking = { path = "../staking", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false, optional = true } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false, optional = true } +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false, optional = true } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false, optional = true } [dev-dependencies] mocktopus = "0.7.0" frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.29", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } [features] default = ["std"] diff --git a/crates/oracle/Cargo.toml b/crates/oracle/Cargo.toml index 173ecceba4..52a950c839 100644 --- a/crates/oracle/Cargo.toml +++ b/crates/oracle/Cargo.toml @@ -32,8 +32,8 @@ mocktopus = "0.7.0" frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.29", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } [features] default = ["std"] diff --git a/crates/redeem/Cargo.toml b/crates/redeem/Cargo.toml index c290a85100..31b4e7eb3f 100644 --- a/crates/redeem/Cargo.toml +++ b/crates/redeem/Cargo.toml @@ -33,8 +33,8 @@ vault-registry = { path = "../vault-registry", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false, optional = true } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false, optional = true } +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false, optional = true } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false, optional = true } [dev-dependencies] mocktopus = "0.7.0" @@ -46,8 +46,8 @@ staking = { path = "../staking" } currency = { path = "../currency", features = ["testing-utils"] } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af" } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af" } +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5" } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5" } [features] default = ["std"] diff --git a/crates/replace/Cargo.toml b/crates/replace/Cargo.toml index d023cc4316..578126d4e5 100644 --- a/crates/replace/Cargo.toml +++ b/crates/replace/Cargo.toml @@ -34,8 +34,8 @@ nomination = { path = "../nomination", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false, optional = true } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false, optional = true } +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false, optional = true } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false, optional = true } [dev-dependencies] mocktopus = "0.7.0" @@ -47,8 +47,8 @@ staking = { path = "../staking" } currency = { path = "../currency", features = ["testing-utils"] } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af" } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af" } +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5" } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5" } [features] default = ["std"] diff --git a/crates/staking/Cargo.toml b/crates/staking/Cargo.toml index d187a0e209..aa686c9c03 100644 --- a/crates/staking/Cargo.toml +++ b/crates/staking/Cargo.toml @@ -25,8 +25,8 @@ frame-system = { git = "https://github.com/paritytech/substrate", branch = "polk frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.29", default-features = false, optional = true } # note: can be remove after removal of migration -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } [dev-dependencies] mocktopus = "0.7.0" diff --git a/crates/vault-registry/Cargo.toml b/crates/vault-registry/Cargo.toml index be3fe88a7f..d821ecf2e3 100644 --- a/crates/vault-registry/Cargo.toml +++ b/crates/vault-registry/Cargo.toml @@ -37,8 +37,8 @@ staking = { path = "../staking", default-features = false } primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } [dev-dependencies] mocktopus = "0.7.0" diff --git a/parachain/runtime/interlay/Cargo.toml b/parachain/runtime/interlay/Cargo.toml index 178d7bdb20..98f48c8260 100644 --- a/parachain/runtime/interlay/Cargo.toml +++ b/parachain/runtime/interlay/Cargo.toml @@ -108,14 +108,14 @@ module-redeem-rpc-runtime-api = { path = "../../../crates/redeem/rpc/runtime-api module-replace-rpc-runtime-api = { path = "../../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-vesting = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } - -orml-xtokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-xcm-support = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-unknown-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-asset-registry= { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-vesting = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } + +orml-xtokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-xcm-support = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-unknown-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-asset-registry= { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } [dev-dependencies] hex = '0.4.2' diff --git a/parachain/runtime/kintsugi/Cargo.toml b/parachain/runtime/kintsugi/Cargo.toml index ea4550dea8..a1cda49b92 100644 --- a/parachain/runtime/kintsugi/Cargo.toml +++ b/parachain/runtime/kintsugi/Cargo.toml @@ -108,14 +108,14 @@ module-redeem-rpc-runtime-api = { path = "../../../crates/redeem/rpc/runtime-api module-replace-rpc-runtime-api = { path = "../../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-vesting = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } - -orml-xtokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-xcm-support = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-unknown-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-asset-registry= { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-vesting = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } + +orml-xtokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-xcm-support = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-unknown-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-asset-registry= { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } [dev-dependencies] hex = '0.4.2' diff --git a/parachain/runtime/runtime-tests/Cargo.toml b/parachain/runtime/runtime-tests/Cargo.toml index 0f8b4853bc..7b845a922b 100644 --- a/parachain/runtime/runtime-tests/Cargo.toml +++ b/parachain/runtime/runtime-tests/Cargo.toml @@ -114,14 +114,14 @@ module-redeem-rpc-runtime-api = { path = "../../../crates/redeem/rpc/runtime-api module-replace-rpc-runtime-api = { path = "../../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-vesting = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } - -orml-xtokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-xcm = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-xcm-support = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-unknown-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-vesting = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } + +orml-xtokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-xcm = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-xcm-support = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-unknown-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } [dev-dependencies] hex = '0.4.2' diff --git a/parachain/runtime/testnet-interlay/Cargo.toml b/parachain/runtime/testnet-interlay/Cargo.toml index c42dc860d0..8351d2ae4d 100644 --- a/parachain/runtime/testnet-interlay/Cargo.toml +++ b/parachain/runtime/testnet-interlay/Cargo.toml @@ -110,14 +110,14 @@ module-redeem-rpc-runtime-api = { path = "../../../crates/redeem/rpc/runtime-api module-replace-rpc-runtime-api = { path = "../../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-vesting = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } - -orml-xtokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-xcm-support = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-unknown-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-asset-registry= { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-vesting = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } + +orml-xtokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-xcm-support = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-unknown-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-asset-registry= { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } [dev-dependencies] hex = '0.4.2' diff --git a/parachain/runtime/testnet-kintsugi/Cargo.toml b/parachain/runtime/testnet-kintsugi/Cargo.toml index 994b2660ae..7db00241ce 100644 --- a/parachain/runtime/testnet-kintsugi/Cargo.toml +++ b/parachain/runtime/testnet-kintsugi/Cargo.toml @@ -110,14 +110,14 @@ module-redeem-rpc-runtime-api = { path = "../../../crates/redeem/rpc/runtime-api module-replace-rpc-runtime-api = { path = "../../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-vesting = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } - -orml-xtokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-xcm-support = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-unknown-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-asset-registry= { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-vesting = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } + +orml-xtokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-xcm-support = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-unknown-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-asset-registry= { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } [dev-dependencies] hex = '0.4.2' diff --git a/standalone/runtime/Cargo.toml b/standalone/runtime/Cargo.toml index d1b5f81b0a..70f1daecee 100644 --- a/standalone/runtime/Cargo.toml +++ b/standalone/runtime/Cargo.toml @@ -89,10 +89,10 @@ module-redeem-rpc-runtime-api = { path = "../../crates/redeem/rpc/runtime-api", module-replace-rpc-runtime-api = { path = "../../crates/replace/rpc/runtime-api", default-features = false } # Orml dependencies -orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-vesting = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } -orml-asset-registry = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "44fda4432b71f49ee59a650cf4775db895ab97af", default-features = false } +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-vesting = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-asset-registry = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.29", default-features = false } From bbc912d43e97fba799e1519e050febdc683efc8e Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Fri, 28 Oct 2022 00:44:29 +0200 Subject: [PATCH 50/58] fix(loans): upgrade polkadot --- Cargo.lock | 320 ++++++++++++++---------- crates/currency/Cargo.toml | 1 + crates/loans/Cargo.toml | 95 ++++--- crates/loans/rpc/Cargo.toml | 10 +- crates/loans/rpc/runtime-api/Cargo.toml | 4 +- crates/loans/src/weights.rs | 240 +++++++++--------- crates/traits/Cargo.toml | 59 ++--- 7 files changed, 399 insertions(+), 330 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 674f95bc06..abf8adf606 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -68,7 +68,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.7", + "getrandom 0.2.8", "once_cell", "version_check", ] @@ -129,9 +129,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.65" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" +checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" [[package]] name = "approx" @@ -253,11 +253,12 @@ dependencies = [ [[package]] name = "async-lock" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6" +checksum = "c8101efe8695a6c17e02911402145357e718ac92d3ff88ae8419e84b1707b685" dependencies = [ "event-listener", + "futures-lite", ] [[package]] @@ -329,9 +330,9 @@ checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" [[package]] name = "async-trait" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" +checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" dependencies = [ "proc-macro2", "quote", @@ -390,7 +391,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" dependencies = [ "futures-core", - "getrandom 0.2.7", + "getrandom 0.2.8", "instant", "pin-project-lite 0.2.9", "rand 0.8.5", @@ -438,9 +439,9 @@ checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" [[package]] name = "base64" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "beef" @@ -778,9 +779,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.11.0" +version = "3.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" [[package]] name = "byte-slice-cast" @@ -993,9 +994,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.22" +version = "3.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" +checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" dependencies = [ "atty", "bitflags", @@ -1119,9 +1120,9 @@ dependencies = [ [[package]] name = "comfy-table" -version = "6.1.0" +version = "6.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85914173c2f558d61613bfbbf1911f14e630895087a7ed2fafc0f5319e1536e7" +checksum = "1090f39f45786ec6dc6286f8ea9c75d0a7ef0a0d3cda674cef0c3af7b307fbc2" dependencies = [ "strum", "strum_macros", @@ -1406,9 +1407,9 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdffe87e1d521a10f9696f833fe502293ea446d7f256c06128293a4119bdf4cb" +checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" dependencies = [ "quote", "syn", @@ -1964,9 +1965,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.78" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f39818dcfc97d45b03953c1292efc4e80954e1583c4aa770bac1383e2310a4" +checksum = "6b7d4e43b25d3c994662706a1d4fcfc32aaa6afd287502c111b237093bb23f3a" dependencies = [ "cc", "cxxbridge-flags", @@ -1976,9 +1977,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.78" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e580d70777c116df50c390d1211993f62d40302881e54d4b79727acb83d0199" +checksum = "84f8829ddc213e2c1368e51a2564c552b65a8cb6a28f31e576270ac81d5e5827" dependencies = [ "cc", "codespan-reporting", @@ -1991,15 +1992,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.78" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56a46460b88d1cec95112c8c363f0e2c39afdb237f60583b0b36343bf627ea9c" +checksum = "e72537424b474af1460806647c41d4b6d35d09ef7fe031c5c2fa5766047cc56a" [[package]] name = "cxxbridge-macro" -version = "1.0.78" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747b608fecf06b0d72d440f27acc99288207324b793be2c17991839f3d4995ea" +checksum = "309e4fb93eed90e1e14bea0da16b209f81813ba9fc7830c20ed151dd7bc0a4d7" dependencies = [ "proc-macro2", "quote", @@ -2246,15 +2247,15 @@ dependencies = [ [[package]] name = "ed25519-zebra" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403ef3e961ab98f0ba902771d29f842058578bb1ce7e3c59dad5a6a93e784c69" +checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" dependencies = [ "curve25519-dalek 3.2.0", + "hashbrown 0.12.3", "hex", "rand_core 0.6.4", "sha2 0.9.9", - "thiserror", "zeroize", ] @@ -2530,14 +2531,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c" +checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3" dependencies = [ "cfg-if 1.0.0", "libc", "redox_syscall", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -2906,9 +2907,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f21eda599937fba36daeb58a22e8f5cee2d14c4a17b5b7739c7c8e5e3b8230c" +checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" dependencies = [ "futures-channel", "futures-core", @@ -2921,9 +2922,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050" +checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" dependencies = [ "futures-core", "futures-sink", @@ -2931,15 +2932,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" +checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" [[package]] name = "futures-executor" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ff63c23854bee61b6e9cd331d523909f238fc7636290b96826e9cfa5faa00ab" +checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" dependencies = [ "futures-core", "futures-task", @@ -2949,9 +2950,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68" +checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" [[package]] name = "futures-lite" @@ -2970,9 +2971,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17" +checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" dependencies = [ "proc-macro2", "quote", @@ -2992,15 +2993,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56" +checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" [[package]] name = "futures-task" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1" +checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" [[package]] name = "futures-timer" @@ -3010,9 +3011,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" +checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" dependencies = [ "futures-channel", "futures-core", @@ -3079,9 +3080,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if 1.0.0", "libc", @@ -3153,9 +3154,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca32592cf21ac7ccab1825cd87f6c9b3d9022c44d086172ed0966bec8af30be" +checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" dependencies = [ "bytes", "fnv", @@ -3406,9 +3407,9 @@ dependencies = [ [[package]] name = "iana-time-zone-haiku" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fde6edd6cef363e9359ed3c98ba64590ba9eecba2293eb5a723ab32aee8926aa" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" dependencies = [ "cxx", "cxx-build", @@ -3901,9 +3902,9 @@ checksum = "ec58677acfea8a15352d42fc87d11d63596ade9239e0a7c9352914417515dbe6" [[package]] name = "io-lifetimes" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ea37f355c05dde75b84bba2d767906ad522e97cd9e2eef2be7a4ab7fb442c06" +checksum = "e6e481ccbe3dea62107216d0d1138bb8ad8e5e5c43009a098bd1990272c497b0" [[package]] name = "ip_network" @@ -4423,9 +4424,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.135" +version = "0.2.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" +checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" [[package]] name = "libloading" @@ -4462,7 +4463,7 @@ dependencies = [ "bytes", "futures", "futures-timer", - "getrandom 0.2.7", + "getrandom 0.2.8", "instant", "lazy_static", "libp2p-autonat", @@ -4602,7 +4603,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74b4b888cfbeb1f5551acd3aa1366e01bf88ede26cc3c4645d0d2d004d5ca7b0" dependencies = [ "asynchronous-codec", - "base64 0.13.0", + "base64 0.13.1", "byteorder", "bytes", "fnv", @@ -5009,7 +5010,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" dependencies = [ "arrayref", - "base64 0.13.0", + "base64 0.13.1", "digest 0.9.0", "hmac-drbg", "libsecp256k1-core 0.3.0", @@ -5341,14 +5342,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -5599,7 +5600,7 @@ dependencies = [ "digest 0.10.5", "multihash-derive", "sha2 0.10.6", - "sha3 0.10.5", + "sha3", "unsigned-varint", ] @@ -6034,7 +6035,7 @@ dependencies = [ [[package]] name = "orml-oracle" version = "0.4.1-dev" -source = "git+https://github.com/interlay/open-runtime-module-library?branch=dan/hooks-weights-v1#208dfa5adf718095e62a88c92954f453a6a4b1fb" +source = "git+https://github.com/open-web3-stack/open-runtime-module-library?rev=2c48b626addafbea0227c068c9ab0fc16666b1b5#2c48b626addafbea0227c068c9ab0fc16666b1b5" dependencies = [ "frame-support", "frame-system", @@ -6578,6 +6579,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", + "sp-arithmetic", "sp-core", "sp-io", "sp-runtime", @@ -6959,9 +6961,6 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -7324,7 +7323,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.3", + "parking_lot_core 0.9.4", ] [[package]] @@ -7343,15 +7342,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" dependencies = [ "cfg-if 1.0.0", "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -7484,9 +7483,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" [[package]] name = "platforms" @@ -8622,9 +8621,9 @@ dependencies = [ [[package]] name = "polling" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899b00b9c8ab553c743b3e11e87c5c7d423b2a2de229ba95b24a756344748011" +checksum = "ab4609a838d88b73d8238967b60dd115cc08d38e2bbaf51ee1e4b695f89122e2" dependencies = [ "autocfg 1.1.0", "cfg-if 1.0.0", @@ -8746,18 +8745,18 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.46" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" dependencies = [ "unicode-ident", ] [[package]] name = "prometheus" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45c8babc29389186697fe5a2a4859d697825496b83db5d0b65271cdc0488e88c" +checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" dependencies = [ "cfg-if 1.0.0", "fnv", @@ -9003,7 +9002,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.7", + "getrandom 0.2.8", ] [[package]] @@ -9190,7 +9189,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.7", + "getrandom 0.2.8", "redox_syscall", "thiserror", ] @@ -9210,18 +9209,18 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.10" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8ebf632f3e32bf35133f620cf481f29c99ae0fb01450fd3d85eee0225274ec1" +checksum = "12a733f1746c929b4913fe48f8697fcf9c55e3304ba251a79ffb41adfeaf49c2" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.10" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caab98faa75ce294d40512ce514a46b15eafe78d72c9397a68ea45b3a88201b6" +checksum = "5887de4a01acafd221861463be6113e6e87275e79804e56779f4cdc131c60368" dependencies = [ "proc-macro2", "quote", @@ -9486,9 +9485,9 @@ dependencies = [ [[package]] name = "rpassword" -version = "7.0.0" +version = "7.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b763cb66df1c928432cc35053f8bd4cec3335d8559fc16010017d16b3c1680" +checksum = "20c9f5d2a0c3e2ea729ab3706d22217177770654c3ef5056b68b69d07332d3f5" dependencies = [ "libc", "winapi", @@ -9552,23 +9551,23 @@ dependencies = [ [[package]] name = "rustix" -version = "0.35.11" +version = "0.35.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbb2fda4666def1433b1b05431ab402e42a1084285477222b72d6c564c417cef" +checksum = "985947f9b6423159c4726323f373be0a21bdb514c5af06a849cb3d2dce2d01e8" dependencies = [ "bitflags", "errno", - "io-lifetimes 0.7.3", + "io-lifetimes 0.7.4", "libc", "linux-raw-sys 0.0.46", - "windows-sys", + "windows-sys 0.36.1", ] [[package]] name = "rustls" -version = "0.20.6" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" +checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" dependencies = [ "log", "ring", @@ -9594,7 +9593,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" dependencies = [ - "base64 0.13.0", + "base64 0.13.1", ] [[package]] @@ -10094,7 +10093,7 @@ dependencies = [ "parity-scale-codec", "parity-wasm 0.42.2", "rustix 0.33.7", - "rustix 0.35.11", + "rustix 0.35.12", "sc-allocator", "sc-executor-common", "sp-runtime-interface", @@ -10718,7 +10717,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" dependencies = [ "lazy_static", - "windows-sys", + "windows-sys 0.36.1", ] [[package]] @@ -10784,11 +10783,11 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7649a0b3ffb32636e60c7ce0d70511eda9c52c658cd0634e194d5a19943aeff" +checksum = "ff55dc09d460954e9ef2fa8a7ced735a964be9981fd50e870b2b3b0705e14964" dependencies = [ - "secp256k1-sys 0.6.0", + "secp256k1-sys 0.6.1", ] [[package]] @@ -10801,9 +10800,9 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7058dc8eaf3f2810d7828680320acda0b25a288f6d288e19278e249bbf74226b" +checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" dependencies = [ "cc", ] @@ -10883,18 +10882,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.145" +version = "1.0.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.145" +version = "1.0.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" dependencies = [ "proc-macro2", "quote", @@ -10903,9 +10902,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074" +checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" dependencies = [ "itoa", "ryu", @@ -10983,21 +10982,9 @@ dependencies = [ [[package]] name = "sha3" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2904bea16a1ae962b483322a1c7b81d976029203aea1f461e51cd7705db7ba9" -dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "keccak", - "opaque-debug 0.3.0", -] - -[[package]] -name = "sha3" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2904bea16a1ae962b483322a1c7b81d976029203aea1f461e51cd7705db7ba9" +checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" dependencies = [ "digest 0.10.5", "keccak", @@ -11140,7 +11127,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" dependencies = [ - "base64 0.13.0", + "base64 0.13.1", "bytes", "flate2", "futures", @@ -11379,7 +11366,7 @@ dependencies = [ "regex", "scale-info", "schnorrkel", - "secp256k1 0.24.0", + "secp256k1 0.24.1", "secrecy", "serde", "sp-core-hashing", @@ -11405,7 +11392,7 @@ dependencies = [ "byteorder", "digest 0.10.5", "sha2 0.10.6", - "sha3 0.10.5", + "sha3", "sp-std", "twox-hash", ] @@ -11495,7 +11482,7 @@ dependencies = [ "log", "parity-scale-codec", "parking_lot 0.12.1", - "secp256k1 0.24.0", + "secp256k1 0.24.1", "sp-core", "sp-externalities", "sp-keystore", @@ -11880,9 +11867,9 @@ checksum = "13287b4da9d1207a4f4929ac390916d64eacfe236a487e9a9f5b3be392be5162" [[package]] name = "ss58-registry" -version = "1.31.0" +version = "1.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1de151faef619cb7b5c26b32d42bc7ddccac0d202beb7a84344b44e9232b92f7" +checksum = "3ab7554f8a8b6f8d71cd5a8e6536ef116e2ce0504cf97ebf16311d58065dc8a6" dependencies = [ "Inflector", "num-format", @@ -12116,9 +12103,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.102" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" dependencies = [ "proc-macro2", "quote", @@ -12399,9 +12386,9 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.15.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" @@ -12560,9 +12547,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6edf2d6bc038a43d31353570e27270603f4648d18f5ed10c0e179abe43255af" +checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" dependencies = [ "futures-core", "pin-project-lite 0.2.9", @@ -13226,7 +13213,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1df23c642e1376892f3b72f311596976979cbf8b85469680cdd3a8a063d12a2" dependencies = [ "anyhow", - "base64 0.13.0", + "base64 0.13.1", "bincode", "directories-next", "file-per-thread-logger", @@ -13569,6 +13556,27 @@ dependencies = [ "windows_x86_64_msvc 0.36.1", ] +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.0", + "windows_i686_gnu 0.42.0", + "windows_i686_msvc 0.42.0", + "windows_x86_64_gnu 0.42.0", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + [[package]] name = "windows_aarch64_msvc" version = "0.34.0" @@ -13581,6 +13589,12 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" + [[package]] name = "windows_i686_gnu" version = "0.34.0" @@ -13593,6 +13607,12 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +[[package]] +name = "windows_i686_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" + [[package]] name = "windows_i686_msvc" version = "0.34.0" @@ -13605,6 +13625,12 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +[[package]] +name = "windows_i686_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" + [[package]] name = "windows_x86_64_gnu" version = "0.34.0" @@ -13617,6 +13643,18 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" + [[package]] name = "windows_x86_64_msvc" version = "0.34.0" @@ -13629,6 +13667,12 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" + [[package]] name = "winreg" version = "0.7.0" diff --git a/crates/currency/Cargo.toml b/crates/currency/Cargo.toml index cd88490211..85159fbb93 100644 --- a/crates/currency/Cargo.toml +++ b/crates/currency/Cargo.toml @@ -19,6 +19,7 @@ pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", # Parachain dependencies primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } +pallet-traits = { path = '../traits', default-features = false } # Orml dependencies orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } diff --git a/crates/loans/Cargo.toml b/crates/loans/Cargo.toml index 0d856ef810..352316b2d8 100644 --- a/crates/loans/Cargo.toml +++ b/crates/loans/Cargo.toml @@ -1,57 +1,78 @@ [package] -authors = ['Interlay Ltd'] -edition = '2021' -name = 'pallet-loans' -version = '1.9.3' +authors = ["Interlay Ltd"] +edition = "2021" +name = "pallet-loans" +version = "1.9.3" [package.metadata.docs.rs] -targets = ['x86_64-unknown-linux-gnu'] +targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = 'parity-scale-codec', version = '3.1.5', default-features = false } -frame-benchmarking = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false, optional = true } -frame-support = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } -frame-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } -num-traits = { default-features = false, version = '0.2' } -orml-traits = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } -orml-oracle = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } -orml-tokens = { git = "https://github.com/interlay/open-runtime-module-library", branch = "dan/hooks-weights-v1", default-features = false } -pallet-timestamp = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } -pallet-traits = { path = '../traits', default-features = false } -primitives = { package = 'interbtc-primitives', path = '../../primitives', default-features = false } -scale-info = { version = '2.1', default-features = false, features = ['derive'] } -serde = { version = '1.0.136', default-features = false, features = ['derive'], optional = true } -sp-io = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } -sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } -sp-std = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } -sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } +serde = { version = "1.0.136", default-features = false, features = ["derive"], optional = true } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +scale-info = { version = "2.1.0", default-features = false, features = ["derive"] } +num-traits = { default-features = false, version = "0.2" } + +# Substrate dependencies +sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.29", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.29", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.29", default-features = false } +sp-arithmetic = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.29", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.29", default-features = false } + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.29", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.29", default-features = false } +frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.29", default-features = false, optional = true } +pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.29", default-features = false } + +# Parachain dependencies currency = { path = "../currency", default-features = false } +pallet-traits = { path = "../traits", default-features = false } + +primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } + +# Orml dependencies +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } +orml-oracle = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "2c48b626addafbea0227c068c9ab0fc16666b1b5", default-features = false } [dev-dependencies] mocktopus = "0.7.0" [features] -default = ['std'] -runtime-benchmarks = ['frame-benchmarking'] -std = [ +default = ["std"] +std = [ + "serde/std", "codec/std", - "frame-benchmarking/std", - "frame-support/std", - "frame-system/std", + "scale-info/std", "num-traits/std", + + "sp-io/std", + "sp-core/std", + "sp-std/std", + "sp-arithmetic/std", + "sp-runtime/std", + + "frame-support/std", + "frame-system/std", + "frame-benchmarking/std", + "pallet-timestamp/std", + + "currency/std", + "pallet-traits/std", + + "primitives/std", + "orml-traits/std", "orml-oracle/std", "orml-tokens/std", - "pallet-timestamp/std", - "pallet-traits/std", - "primitives/std", - "scale-info/std", - "serde/std", - "sp-io/std", - "sp-runtime/std", - "sp-std/std" ] -try-runtime = ['frame-support/try-runtime'] +runtime-benchmarks = [ + "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", +] +try-runtime = ["frame-support/try-runtime"] [lib] doctest = false diff --git a/crates/loans/rpc/Cargo.toml b/crates/loans/rpc/Cargo.toml index 3b03ae2c45..8bf10c6464 100644 --- a/crates/loans/rpc/Cargo.toml +++ b/crates/loans/rpc/Cargo.toml @@ -9,11 +9,11 @@ codec = { package = 'parity-scale-codec', version = '3.1.5' } jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } primitives = { package = 'parallel-primitives', path = '../../../primitives', default-features = false } serde = { version = '1.0.136', features = ['derive'] } -sp-api = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26' } -sp-blockchain = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26' } -sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26' } -sp-rpc = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } -sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26' } +sp-api = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.29' } +sp-blockchain = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.29' } +sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.29' } +sp-rpc = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.29', default-features = false } +sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.29' } pallet-loans-rpc-runtime-api = { path = 'runtime-api', default-features = false } diff --git a/crates/loans/rpc/runtime-api/Cargo.toml b/crates/loans/rpc/runtime-api/Cargo.toml index d9ff669a1d..098d8fb2d5 100644 --- a/crates/loans/rpc/runtime-api/Cargo.toml +++ b/crates/loans/rpc/runtime-api/Cargo.toml @@ -7,8 +7,8 @@ version = '1.9.3' [dependencies] codec = { package = 'parity-scale-codec', version = '3.1.5', default-features = false, features = ['derive'] } primitives = { package = 'parallel-primitives', path = '../../../../primitives', default-features = false } -sp-api = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } -sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } +sp-api = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.29', default-features = false } +sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.29', default-features = false } [features] default = ['std'] diff --git a/crates/loans/src/weights.rs b/crates/loans/src/weights.rs index 3a79f0a6ff..762638aba7 100644 --- a/crates/loans/src/weights.rs +++ b/crates/loans/src/weights.rs @@ -79,52 +79,52 @@ impl WeightInfo for SubstrateWeight { // Storage: Loans ExchangeRate (r:0 w:1) // Storage: Loans BorrowIndex (r:0 w:1) fn add_market() -> Weight { - (61_518_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(61_518_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:1 w:1) fn activate_market() -> Weight { - (43_556_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(43_556_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:1 w:1) fn update_rate_model() -> Weight { - (45_600_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(45_600_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:1 w:1) fn update_market() -> Weight { - (45_777_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(45_777_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans UnderlyingAssetId (r:1 w:1) // Storage: Loans Markets (r:1 w:1) fn force_update_market() -> Weight { - (56_536_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(56_536_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: System Account (r:1 w:1) fn add_reward() -> Weight { - (98_928_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(98_928_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_missing_reward() -> Weight { - (81_317_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(81_317_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) @@ -133,9 +133,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Loans RewardSupplyState (r:1 w:1) // Storage: Loans RewardBorrowState (r:1 w:1) fn update_market_reward_speed() -> Weight { - (86_330_000 as Weight) - .saturating_add(T::DbWeight::get().reads(7 as Weight)) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(86_330_000 as u64) + .saturating_add(T::DbWeight::get().reads(7 as u64)) + .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) @@ -153,9 +153,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Loans AccountBorrows (r:1 w:0) // Storage: System Account (r:1 w:1) fn claim_reward() -> Weight { - (234_251_000 as Weight) - .saturating_add(T::DbWeight::get().reads(16 as Weight)) - .saturating_add(T::DbWeight::get().writes(7 as Weight)) + Weight::from_ref_time(234_251_000 as u64) + .saturating_add(T::DbWeight::get().reads(16 as u64)) + .saturating_add(T::DbWeight::get().writes(7 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans RewardSupplyState (r:1 w:1) @@ -172,9 +172,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Loans AccountBorrows (r:1 w:0) // Storage: System Account (r:1 w:1) fn claim_reward_for_market() -> Weight { - (214_273_000 as Weight) - .saturating_add(T::DbWeight::get().reads(14 as Weight)) - .saturating_add(T::DbWeight::get().writes(7 as Weight)) + Weight::from_ref_time(214_273_000 as u64) + .saturating_add(T::DbWeight::get().reads(14 as u64)) + .saturating_add(T::DbWeight::get().writes(7 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) @@ -193,9 +193,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Loans AccountEarned (r:1 w:1) // Storage: System Account (r:1 w:1) fn mint() -> Weight { - (250_616_000 as Weight) - .saturating_add(T::DbWeight::get().reads(18 as Weight)) - .saturating_add(T::DbWeight::get().writes(12 as Weight)) + Weight::from_ref_time(250_616_000 as u64) + .saturating_add(T::DbWeight::get().reads(18 as u64)) + .saturating_add(T::DbWeight::get().writes(12 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) @@ -217,9 +217,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Loans RewardAccured (r:1 w:1) // Storage: Loans BorrowIndex (r:1 w:0) fn borrow() -> Weight { - (356_136_000 as Weight) - .saturating_add(T::DbWeight::get().reads(24 as Weight)) - .saturating_add(T::DbWeight::get().writes(10 as Weight)) + Weight::from_ref_time(356_136_000 as u64) + .saturating_add(T::DbWeight::get().reads(24 as u64)) + .saturating_add(T::DbWeight::get().writes(10 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) @@ -237,9 +237,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Loans RewardSupplierIndex (r:1 w:1) // Storage: Loans RewardAccured (r:1 w:1) fn redeem() -> Weight { - (259_224_000 as Weight) - .saturating_add(T::DbWeight::get().reads(17 as Weight)) - .saturating_add(T::DbWeight::get().writes(11 as Weight)) + Weight::from_ref_time(259_224_000 as u64) + .saturating_add(T::DbWeight::get().reads(17 as u64)) + .saturating_add(T::DbWeight::get().writes(11 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) @@ -258,9 +258,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Loans RewardAccured (r:1 w:1) // Storage: System Account (r:1 w:1) fn redeem_all() -> Weight { - (277_962_000 as Weight) - .saturating_add(T::DbWeight::get().reads(18 as Weight)) - .saturating_add(T::DbWeight::get().writes(12 as Weight)) + Weight::from_ref_time(277_962_000 as u64) + .saturating_add(T::DbWeight::get().reads(18 as u64)) + .saturating_add(T::DbWeight::get().writes(12 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) @@ -276,9 +276,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: Loans TotalBorrows (r:1 w:1) fn repay_borrow() -> Weight { - (226_122_000 as Weight) - .saturating_add(T::DbWeight::get().reads(15 as Weight)) - .saturating_add(T::DbWeight::get().writes(10 as Weight)) + Weight::from_ref_time(226_122_000 as u64) + .saturating_add(T::DbWeight::get().reads(15 as u64)) + .saturating_add(T::DbWeight::get().writes(10 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) @@ -294,17 +294,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: Loans TotalBorrows (r:1 w:1) fn repay_borrow_all() -> Weight { - (225_556_000 as Weight) - .saturating_add(T::DbWeight::get().reads(15 as Weight)) - .saturating_add(T::DbWeight::get().writes(10 as Weight)) + Weight::from_ref_time(225_556_000 as u64) + .saturating_add(T::DbWeight::get().reads(15 as u64)) + .saturating_add(T::DbWeight::get().writes(10 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) // Storage: Loans AccountDeposits (r:1 w:1) fn collateral_asset() -> Weight { - (73_911_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(73_911_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans LiquidationFreeCollaterals (r:1 w:0) @@ -329,9 +329,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Loans RewardSupplySpeed (r:1 w:0) // Storage: Loans RewardSupplierIndex (r:3 w:3) fn liquidate_borrow() -> Weight { - (637_956_000 as Weight) - .saturating_add(T::DbWeight::get().reads(40 as Weight)) - .saturating_add(T::DbWeight::get().writes(20 as Weight)) + Weight::from_ref_time(637_956_000 as u64) + .saturating_add(T::DbWeight::get().reads(40 as u64)) + .saturating_add(T::DbWeight::get().writes(20 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) @@ -340,9 +340,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Loans TotalReserves (r:1 w:1) fn add_reserves() -> Weight { - (146_456_000 as Weight) - .saturating_add(T::DbWeight::get().reads(8 as Weight)) - .saturating_add(T::DbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(146_456_000 as u64) + .saturating_add(T::DbWeight::get().reads(8 as u64)) + .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) @@ -350,9 +350,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:2 w:2) fn reduce_reserves() -> Weight { - (131_943_000 as Weight) - .saturating_add(T::DbWeight::get().reads(7 as Weight)) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(131_943_000 as u64) + .saturating_add(T::DbWeight::get().reads(7 as u64)) + .saturating_add(T::DbWeight::get().writes(5 as u64)) } } @@ -364,52 +364,52 @@ impl WeightInfo for () { // Storage: Loans ExchangeRate (r:0 w:1) // Storage: Loans BorrowIndex (r:0 w:1) fn add_market() -> Weight { - (61_518_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(61_518_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:1 w:1) fn activate_market() -> Weight { - (43_556_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(43_556_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:1 w:1) fn update_rate_model() -> Weight { - (45_600_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(45_600_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:1 w:1) fn update_market() -> Weight { - (45_777_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(45_777_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans UnderlyingAssetId (r:1 w:1) // Storage: Loans Markets (r:1 w:1) fn force_update_market() -> Weight { - (56_536_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(56_536_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: System Account (r:1 w:1) fn add_reward() -> Weight { - (98_928_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(98_928_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_missing_reward() -> Weight { - (81_317_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(81_317_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) @@ -418,9 +418,9 @@ impl WeightInfo for () { // Storage: Loans RewardSupplyState (r:1 w:1) // Storage: Loans RewardBorrowState (r:1 w:1) fn update_market_reward_speed() -> Weight { - (86_330_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(7 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(86_330_000 as u64) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) @@ -438,9 +438,9 @@ impl WeightInfo for () { // Storage: Loans AccountBorrows (r:1 w:0) // Storage: System Account (r:1 w:1) fn claim_reward() -> Weight { - (234_251_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(16 as Weight)) - .saturating_add(RocksDbWeight::get().writes(7 as Weight)) + Weight::from_ref_time(234_251_000 as u64) + .saturating_add(RocksDbWeight::get().reads(16 as u64)) + .saturating_add(RocksDbWeight::get().writes(7 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans RewardSupplyState (r:1 w:1) @@ -457,9 +457,9 @@ impl WeightInfo for () { // Storage: Loans AccountBorrows (r:1 w:0) // Storage: System Account (r:1 w:1) fn claim_reward_for_market() -> Weight { - (214_273_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(14 as Weight)) - .saturating_add(RocksDbWeight::get().writes(7 as Weight)) + Weight::from_ref_time(214_273_000 as u64) + .saturating_add(RocksDbWeight::get().reads(14 as u64)) + .saturating_add(RocksDbWeight::get().writes(7 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) @@ -478,9 +478,9 @@ impl WeightInfo for () { // Storage: Loans AccountEarned (r:1 w:1) // Storage: System Account (r:1 w:1) fn mint() -> Weight { - (250_616_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(18 as Weight)) - .saturating_add(RocksDbWeight::get().writes(12 as Weight)) + Weight::from_ref_time(250_616_000 as u64) + .saturating_add(RocksDbWeight::get().reads(18 as u64)) + .saturating_add(RocksDbWeight::get().writes(12 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) @@ -502,9 +502,9 @@ impl WeightInfo for () { // Storage: Loans RewardAccured (r:1 w:1) // Storage: Loans BorrowIndex (r:1 w:0) fn borrow() -> Weight { - (356_136_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(24 as Weight)) - .saturating_add(RocksDbWeight::get().writes(10 as Weight)) + Weight::from_ref_time(356_136_000 as u64) + .saturating_add(RocksDbWeight::get().reads(24 as u64)) + .saturating_add(RocksDbWeight::get().writes(10 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) @@ -522,9 +522,9 @@ impl WeightInfo for () { // Storage: Loans RewardSupplierIndex (r:1 w:1) // Storage: Loans RewardAccured (r:1 w:1) fn redeem() -> Weight { - (259_224_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(17 as Weight)) - .saturating_add(RocksDbWeight::get().writes(11 as Weight)) + Weight::from_ref_time(259_224_000 as u64) + .saturating_add(RocksDbWeight::get().reads(17 as u64)) + .saturating_add(RocksDbWeight::get().writes(11 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) @@ -543,9 +543,9 @@ impl WeightInfo for () { // Storage: Loans RewardAccured (r:1 w:1) // Storage: System Account (r:1 w:1) fn redeem_all() -> Weight { - (277_962_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(18 as Weight)) - .saturating_add(RocksDbWeight::get().writes(12 as Weight)) + Weight::from_ref_time(277_962_000 as u64) + .saturating_add(RocksDbWeight::get().reads(18 as u64)) + .saturating_add(RocksDbWeight::get().writes(12 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) @@ -561,9 +561,9 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: Loans TotalBorrows (r:1 w:1) fn repay_borrow() -> Weight { - (226_122_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(15 as Weight)) - .saturating_add(RocksDbWeight::get().writes(10 as Weight)) + Weight::from_ref_time(226_122_000 as u64) + .saturating_add(RocksDbWeight::get().reads(15 as u64)) + .saturating_add(RocksDbWeight::get().writes(10 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) @@ -579,17 +579,17 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: Loans TotalBorrows (r:1 w:1) fn repay_borrow_all() -> Weight { - (225_556_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(15 as Weight)) - .saturating_add(RocksDbWeight::get().writes(10 as Weight)) + Weight::from_ref_time(225_556_000 as u64) + .saturating_add(RocksDbWeight::get().reads(15 as u64)) + .saturating_add(RocksDbWeight::get().writes(10 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) // Storage: Loans AccountDeposits (r:1 w:1) fn collateral_asset() -> Weight { - (73_911_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(73_911_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans LiquidationFreeCollaterals (r:1 w:0) @@ -614,9 +614,9 @@ impl WeightInfo for () { // Storage: Loans RewardSupplySpeed (r:1 w:0) // Storage: Loans RewardSupplierIndex (r:3 w:3) fn liquidate_borrow() -> Weight { - (637_956_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(40 as Weight)) - .saturating_add(RocksDbWeight::get().writes(20 as Weight)) + Weight::from_ref_time(637_956_000 as u64) + .saturating_add(RocksDbWeight::get().reads(40 as u64)) + .saturating_add(RocksDbWeight::get().writes(20 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) @@ -625,9 +625,9 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Loans TotalReserves (r:1 w:1) fn add_reserves() -> Weight { - (146_456_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(8 as Weight)) - .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(146_456_000 as u64) + .saturating_add(RocksDbWeight::get().reads(8 as u64)) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Loans Markets (r:2 w:0) @@ -635,8 +635,8 @@ impl WeightInfo for () { // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:2 w:2) fn reduce_reserves() -> Weight { - (131_943_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(7 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(131_943_000 as u64) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) } } diff --git a/crates/traits/Cargo.toml b/crates/traits/Cargo.toml index 00372c4ac7..44b8407476 100644 --- a/crates/traits/Cargo.toml +++ b/crates/traits/Cargo.toml @@ -1,36 +1,42 @@ [package] -authors = ['Parallel Team'] -edition = '2021' -name = 'pallet-traits' -version = '1.9.3' +authors = ["Parallel Team"] +edition = "2021" +name = "pallet-traits" +version = "1.9.3" [package.metadata.docs.rs] -targets = ['x86_64-unknown-linux-gnu'] +targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = '1.0.136',default-features=false, features = ['derive'], optional = true } -codec = { package = 'parity-scale-codec', version = '3.1.5', features = ['max-encoded-len'], default-features = false } -frame-support = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } -frame-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } -log = { version = "0.4", default-features = false } -num-bigint = { default-features = false, version = '0.4' } -num-traits = { default-features = false, version = '0.2' } -primitives = { package = 'interbtc-primitives', path = '../../primitives', default-features = false } -scale-info = { version = '2.1', default-features = false, features = ['derive'] } -sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } -sp-io = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } -sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } -sp-std = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26', default-features = false } -xcm = { git = 'https://github.com/paritytech/polkadot.git', branch = 'release-v0.9.28', default-features = false } -xcm-builder = { git = 'https://github.com/paritytech/polkadot.git', branch = 'release-v0.9.28', default-features = false } -xcm-executor = { git = 'https://github.com/paritytech/polkadot.git', branch = 'release-v0.9.28', default-features = false } +serde = { version = "1.0.136", default-features = false, features = [ + "derive", +], optional = true } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +scale-info = { version = "2.1.0", default-features = false, features = [ + "derive", +] } +num-traits = { default-features = false, version = "0.2" } +log = { version = "0.4", default-features = false } +num-bigint = { default-features = false, version = "0.4" } + +# Substrate dependencies +sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.29", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.29", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.29", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.29", default-features = false } + +frame-support = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.29", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.29", default-features = false } + +# Parachain dependencies +primitives = { package = "interbtc-primitives", path = "../../primitives", default-features = false } [dev-dependencies] -sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.26' } +sp-core = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.29" } [features] -default = ['std'] -std = [ +default = ["std"] +std = [ "serde/std", "codec/std", "frame-support/std", @@ -44,12 +50,9 @@ std = [ "sp-io/std", "sp-runtime/std", "sp-std/std", - "xcm/std", - "xcm-builder/std", - "xcm-executor/std" ] -try-runtime = ['frame-support/try-runtime'] +try-runtime = ["frame-support/try-runtime"] [lib] doctest = false From f40383c4921c99beafde88ced726ec2755acf9c4 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Fri, 28 Oct 2022 14:16:09 +0200 Subject: [PATCH 51/58] fix(loans): reset storage version --- crates/loans/src/lib.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index fe5077d34d..37a6cfb0be 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -135,14 +135,9 @@ impl OnTransfer, BalanceOf> for OnTrans } /// Utility type for managing upgrades/migrations. -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum Versions { - V1, - V2, - V3, - V4, - V5, - V6, + V0, } #[frame_support::pallet] @@ -451,7 +446,7 @@ pub mod pallet { /// DefaultVersion is using for initialize the StorageVersion #[pallet::type_value] pub(super) fn DefaultVersion() -> Versions { - Versions::V2 + Versions::V0 } /// Storage version of the pallet. From c089ac30b9158530ead3a254ec611c5851095dd5 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Fri, 28 Oct 2022 15:43:08 +0200 Subject: [PATCH 52/58] test(loans): zero amount extrinsics --- crates/loans/src/lib.rs | 2 +- crates/loans/src/tests.rs | 62 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 37a6cfb0be..aa3613c9a7 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -824,6 +824,7 @@ pub mod pallet { #[pallet::compact] mint_amount: BalanceOf, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; + ensure!(!mint_amount.is_zero(), Error::::InvalidAmount); Self::do_mint(&who, asset_id, mint_amount)?; Ok(().into()) @@ -1810,7 +1811,6 @@ impl Pallet { impl LoansTrait, AccountIdOf, BalanceOf, Amount> for Pallet { fn do_mint(supplier: &AccountIdOf, asset_id: AssetIdOf, amount: BalanceOf) -> Result<(), DispatchError> { - ensure!(!amount.is_zero(), Error::::InvalidAmount); Self::ensure_active_market(asset_id)?; Self::ensure_under_supply_cap(asset_id, amount)?; diff --git a/crates/loans/src/tests.rs b/crates/loans/src/tests.rs index c01d085f04..6157b33960 100644 --- a/crates/loans/src/tests.rs +++ b/crates/loans/src/tests.rs @@ -270,12 +270,72 @@ fn redeem_works() { } #[test] -fn redeem_fails() { +fn zero_amount_extrinsics_fail() { new_test_ext().execute_with(|| { + assert_noop!( + Loans::add_reward(Origin::signed(ALICE), unit(0)), + Error::::InvalidAmount + ); + assert_noop!( + Loans::withdraw_missing_reward(Origin::root(), BOB, unit(0)), + Error::::InvalidAmount + ); + assert_noop!( + Loans::mint(Origin::signed(ALICE), DOT, unit(0)), + Error::::InvalidAmount + ); assert_noop!( Loans::redeem(Origin::signed(ALICE), DOT, unit(0)), Error::::InvalidAmount ); + assert_noop!( + Loans::redeem_all(Origin::signed(ALICE), DOT), + Error::::InvalidAmount + ); + assert_noop!( + Loans::borrow(Origin::signed(ALICE), DOT, unit(0)), + Error::::InvalidAmount + ); + assert_noop!( + Loans::repay_borrow(Origin::signed(ALICE), DOT, unit(0)), + Error::::InvalidAmount + ); + assert_noop!( + Loans::repay_borrow_all(Origin::signed(ALICE), DOT), + Error::::InvalidAmount + ); + assert_noop!( + Loans::deposit_all_collateral(Origin::signed(ALICE), DOT), + Error::::InvalidAmount + ); + assert_noop!( + Loans::deposit_collateral(Origin::signed(ALICE), DOT, unit(0)), + Error::::InvalidAmount + ); + assert_noop!( + Loans::withdraw_all_collateral(Origin::signed(ALICE), DOT), + Error::::InvalidAmount + ); + assert_noop!( + Loans::withdraw_collateral(Origin::signed(ALICE), DOT, unit(0)), + Error::::InvalidAmount + ); + assert_noop!( + Loans::liquidate_borrow(Origin::signed(ALICE), BOB, DOT, unit(0), IBTC), + Error::::InvalidAmount + ); + assert_noop!( + Loans::add_reserves(Origin::root(), ALICE, DOT, unit(0)), + Error::::InvalidAmount + ); + assert_noop!( + Loans::reduce_reserves(Origin::root(), ALICE, DOT, unit(0)), + Error::::InvalidAmount + ); + assert_noop!( + Loans::reduce_incentive_reserves(Origin::root(), ALICE, DOT, unit(0)), + Error::::InvalidAmount + ); }) } From df3a2d9c1992c2fe7dba96eff77fe3dd5cf6b7da Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Fri, 28 Oct 2022 19:05:41 +0200 Subject: [PATCH 53/58] test(loans): improve comments for tests.rs --- crates/loans/src/farming.rs | 4 +++- crates/loans/src/lib.rs | 1 + crates/loans/src/tests.rs | 8 +++++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/crates/loans/src/farming.rs b/crates/loans/src/farming.rs index a54c0606be..e95b7d6798 100644 --- a/crates/loans/src/farming.rs +++ b/crates/loans/src/farming.rs @@ -123,7 +123,9 @@ impl Pallet { let lend_token_id = Self::lend_token_id(asset_id)?; RewardAccrued::::try_mutate(supplier, |total_reward| -> DispatchResult { - // Frozen balance is not counted towards the total + // Frozen balance is not counted towards the total, so emitted rewards + // may be lower than intended. + // No balance freezing is done currently, so this is correct. let total_balance = Self::balance(lend_token_id, supplier); let reward_delta = Self::calculate_reward_delta(total_balance, delta_index)?; *total_reward = total_reward diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index aa3613c9a7..4ab22e2b97 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -1710,6 +1710,7 @@ impl Pallet { } /// Get the total balance of `who`. + /// Ignores any frozen balance of this account. fn balance(asset_id: AssetIdOf, who: &T::AccountId) -> BalanceOf { as MultiCurrency>::total_balance(asset_id, who) } diff --git a/crates/loans/src/tests.rs b/crates/loans/src/tests.rs index 6157b33960..706dcda48f 100644 --- a/crates/loans/src/tests.rs +++ b/crates/loans/src/tests.rs @@ -822,7 +822,7 @@ fn update_exchange_rate_works() { // Initialize value of exchange rate is 0.02 assert_eq!(Loans::exchange_rate(DOT), Rate::saturating_from_rational(2, 100)); - // assert_ok!(Loans::update_exchange_rate(DOT)); + assert_ok!(Loans::accrue_interest(DOT)); assert_eq!( Loans::exchange_rate_stored(DOT).unwrap(), Rate::saturating_from_rational(2, 100) @@ -834,7 +834,6 @@ fn update_exchange_rate_works() { assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(10))); TotalBorrows::::insert(DOT, unit(5)); TotalReserves::::insert(DOT, unit(1)); - // assert_ok!(Loans::update_exchange_rate(DOT)); assert_eq!( Loans::exchange_rate_stored(DOT).unwrap(), Rate::saturating_from_rational(14, 500) @@ -923,6 +922,9 @@ fn ensure_enough_cash_works() { Error::::InsufficientCash, ); assert_ok!(Loans::ensure_enough_cash(KSM, unit(990))); + // Borrows don't count as cash + TotalBorrows::::insert(KSM, unit(20)); + assert_ok!(Loans::ensure_enough_cash(KSM, unit(1000))); }) } @@ -1001,7 +1003,7 @@ fn update_market_reward_speed_works() { } #[test] -fn reward_calculation_one_palyer_in_multi_markets_works() { +fn reward_calculation_one_player_in_multi_markets_works() { new_test_ext().execute_with(|| { assert_ok!(Loans::mint(Origin::signed(ALICE), DOT, unit(100))); assert_ok!(Loans::mint(Origin::signed(ALICE), KSM, unit(100))); From d8a6824b68dc4f765fb2c4580959073fdafa1c6c Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Mon, 31 Oct 2022 16:57:54 +0100 Subject: [PATCH 54/58] chore(loans): remove comment typo --- crates/currency/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/currency/src/lib.rs b/crates/currency/src/lib.rs index 1c41f80d1c..1612faac7d 100644 --- a/crates/currency/src/lib.rs +++ b/crates/currency/src/lib.rs @@ -44,7 +44,7 @@ where { fn convert(amount: &Amount, to: CurrencyId) -> Result, DispatchError> { if amount.currency().is_lend_token() && to.is_lend_token() { - // Exampe (lendDOT to lendINTR): carg + // Exampe (lendDOT to lendINTR): // collateral_amount(convert(underlying_amount(lendDOT_amount), underlying_id(lendINTR))) // collateral_amount(convert(dot_amount, INTR)) // collateral_amount(intr_amount) From ca6eccfa75ab92e27d6bd63e193ec8d2db085405 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Wed, 2 Nov 2022 14:41:43 +0100 Subject: [PATCH 55/58] fix(loans): failing test and warnings --- crates/loans/src/benchmarking.rs | 33 ++++++++++++++++---------------- crates/loans/src/tests.rs | 5 ++++- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/crates/loans/src/benchmarking.rs b/crates/loans/src/benchmarking.rs index bd902749c7..d9e9786a67 100644 --- a/crates/loans/src/benchmarking.rs +++ b/crates/loans/src/benchmarking.rs @@ -4,6 +4,7 @@ use super::*; use crate::{AccountBorrows, Pallet as Loans}; +#[allow(unused_imports)] use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller}; use frame_support::assert_ok; use frame_system::{self, RawOrigin as SystemOrigin}; @@ -20,7 +21,7 @@ const SEED: u32 = 0; const KSM: CurrencyId = Token(KSM_CURRENCY); const KBTC: CurrencyId = Token(KBTC_CURRENCY); const LEND_KSM: CurrencyId = LendToken(3); -const LendKBTC: CurrencyId = LendToken(4); +const LEND_KBTC: CurrencyId = LendToken(4); const DOT: CurrencyId = Token(DOT_CURRENCY); const LEND_DOT: CurrencyId = LendToken(1); const KINT: CurrencyId = Token(KINT_CURRENCY); @@ -139,7 +140,7 @@ benchmarks! { update_rate_model { }: _(SystemOrigin::Root, KBTC, RATE_MODEL_MOCK) verify { - let mut market = pending_market_mock::(LendKBTC); + let mut market = pending_market_mock::(LEND_KBTC); market.rate_model = RATE_MODEL_MOCK; assert_last_event::(Event::::UpdatedMarket(KBTC, market).into()); } @@ -165,9 +166,9 @@ benchmarks! { } force_update_market { - }: _(SystemOrigin::Root,KBTC, pending_market_mock::(LendKBTC)) + }: _(SystemOrigin::Root,KBTC, pending_market_mock::(LEND_KBTC)) verify { - assert_last_event::(Event::::UpdatedMarket(KBTC, pending_market_mock::(LendKBTC)).into()); + assert_last_event::(Event::::UpdatedMarket(KBTC, pending_market_mock::(LEND_KBTC)).into()); } add_reward { @@ -189,7 +190,7 @@ benchmarks! { } update_market_reward_speed { - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LEND_KBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); }: _(SystemOrigin::Root, KBTC, Some(1_000_000), Some(1_000_000)) verify { @@ -199,7 +200,7 @@ benchmarks! { claim_reward { let caller: T::AccountId = whitelisted_caller(); transfer_initial_balance::(caller.clone()); - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LEND_KBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, 100_000_000)); assert_ok!(Loans::::add_reward(SystemOrigin::Signed(caller.clone()).into(), 1_000_000_000_000_u128)); @@ -214,7 +215,7 @@ benchmarks! { claim_reward_for_market { let caller: T::AccountId = whitelisted_caller(); transfer_initial_balance::(caller.clone()); - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LEND_KBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, 100_000_000)); assert_ok!(Loans::::add_reward(SystemOrigin::Signed(caller.clone()).into(), 1_000_000_000_000_u128)); @@ -230,7 +231,7 @@ benchmarks! { mint { let caller: T::AccountId = whitelisted_caller(); transfer_initial_balance::(caller.clone()); - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LEND_KBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); let amount: u32 = 100_000; }: _(SystemOrigin::Signed(caller.clone()), KBTC, amount.into()) @@ -243,7 +244,7 @@ benchmarks! { transfer_initial_balance::(caller.clone()); let deposit_amount: u32 = 200_000_000; let borrowed_amount: u32 = 100_000_000; - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LEND_KBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); assert_ok!(Loans::::deposit_all_collateral(SystemOrigin::Signed(caller.clone()).into(), KBTC)); @@ -257,7 +258,7 @@ benchmarks! { transfer_initial_balance::(caller.clone()); let deposit_amount: u32 = 100_000_000; let redeem_amount: u32 = 100_000; - // assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); + // assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LEND_KBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); }: _(SystemOrigin::Signed(caller.clone()), KBTC, redeem_amount.into()) @@ -269,7 +270,7 @@ benchmarks! { let caller: T::AccountId = whitelisted_caller(); transfer_initial_balance::(caller.clone()); let deposit_amount: u32 = 100_000_000; - // assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); + // assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LEND_KBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); }: _(SystemOrigin::Signed(caller.clone()), KBTC) @@ -283,7 +284,7 @@ benchmarks! { let deposit_amount: u32 = 200_000_000; let borrowed_amount: u32 = 100_000_000; let repay_amount: u32 = 100; - // assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); + // assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LEND_KBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); assert_ok!(Loans::::deposit_all_collateral(SystemOrigin::Signed(caller.clone()).into(), KBTC)); @@ -298,7 +299,7 @@ benchmarks! { transfer_initial_balance::(caller.clone()); let deposit_amount: u32 = 200_000_000; let borrowed_amount: u32 = 100_000_000; - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LEND_KBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); @@ -313,7 +314,7 @@ benchmarks! { let caller: T::AccountId = whitelisted_caller(); transfer_initial_balance::(caller.clone()); let deposit_amount: u32 = 200_000_000; - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LEND_KBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::mint(SystemOrigin::Signed(caller.clone()).into(), KBTC, deposit_amount.into())); }: _(SystemOrigin::Signed(caller.clone()), KBTC) @@ -348,7 +349,7 @@ benchmarks! { let payer = T::Lookup::unlookup(caller.clone()); transfer_initial_balance::(caller.clone()); let amount: u32 = 2000; - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LEND_KBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); }: _(SystemOrigin::Root, payer, KBTC, amount.into()) verify { @@ -361,7 +362,7 @@ benchmarks! { transfer_initial_balance::(caller.clone()); let add_amount: u32 = 2000; let reduce_amount: u32 = 1000; - assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LendKBTC))); + assert_ok!(Loans::::add_market(SystemOrigin::Root.into(), KBTC, pending_market_mock::(LEND_KBTC))); assert_ok!(Loans::::activate_market(SystemOrigin::Root.into(), KBTC)); assert_ok!(Loans::::add_reserves(SystemOrigin::Root.into(), payer.clone(), KBTC, add_amount.into())); }: _(SystemOrigin::Root, payer, KBTC, reduce_amount.into()) diff --git a/crates/loans/src/tests.rs b/crates/loans/src/tests.rs index 706dcda48f..f7e5262305 100644 --- a/crates/loans/src/tests.rs +++ b/crates/loans/src/tests.rs @@ -924,7 +924,10 @@ fn ensure_enough_cash_works() { assert_ok!(Loans::ensure_enough_cash(KSM, unit(990))); // Borrows don't count as cash TotalBorrows::::insert(KSM, unit(20)); - assert_ok!(Loans::ensure_enough_cash(KSM, unit(1000))); + assert_noop!( + Loans::ensure_enough_cash(KSM, unit(1000)), + Error::::InsufficientCash + ); }) } From acc03a71f5582b0c7f144687544b54f425dad7e7 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Fri, 4 Nov 2022 12:53:18 +0100 Subject: [PATCH 56/58] feat(loans): calculate liquidity with checked math --- crates/loans/src/lib.rs | 16 ++++++++++++++-- crates/traits/src/loans.rs | 6 ------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 4ab22e2b97..487169a412 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -241,6 +241,8 @@ pub mod pallet { CodecError, /// Collateral is reserved and cannot be liquidated CollateralReserved, + /// Arithmetic underflow + ArithmeticUnderflow, } #[pallet::event] @@ -1137,9 +1139,19 @@ impl Pallet { total_collateral_value.into_inner(), ); if total_collateral_value > total_borrow_value { - Ok((total_collateral_value - total_borrow_value, FixedU128::zero())) + Ok(( + total_collateral_value + .checked_sub(&total_borrow_value) + .ok_or(Error::::ArithmeticUnderflow)?, + FixedU128::zero(), + )) } else { - Ok((FixedU128::zero(), total_borrow_value - total_collateral_value)) + Ok(( + FixedU128::zero(), + total_borrow_value + .checked_sub(&total_collateral_value) + .ok_or(Error::::ArithmeticUnderflow)?, + )) } } diff --git a/crates/traits/src/loans.rs b/crates/traits/src/loans.rs index 63d93d3a6c..2aa0a5ffaf 100644 --- a/crates/traits/src/loans.rs +++ b/crates/traits/src/loans.rs @@ -32,12 +32,6 @@ pub trait LoansApi { fn recompute_collateral_amount(underlying: &Amount) -> Result; } -pub trait LoansPositionDataProvider { - fn get_current_borrow_balance(borrower: &AccountId, asset_id: CurrencyId) -> Result; - - fn get_current_collateral_balance(supplier: &AccountId, asset_id: CurrencyId) -> Result; -} - pub trait LoansMarketDataProvider { fn get_market_info(asset_id: CurrencyId) -> Result; fn get_market_status(asset_id: CurrencyId) -> Result, DispatchError>; From 6f8811305f1abe2f42f6de7fa7593867420d2a63 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Fri, 4 Nov 2022 14:25:23 +0100 Subject: [PATCH 57/58] fix(loans): add missing copyright and authorship acks; reuse ArithmeticError --- crates/loans/Cargo.toml | 2 +- crates/loans/src/lib.rs | 6 ++---- crates/traits/Cargo.toml | 2 +- crates/traits/src/loans.rs | 3 +++ 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/crates/loans/Cargo.toml b/crates/loans/Cargo.toml index 352316b2d8..95f47024db 100644 --- a/crates/loans/Cargo.toml +++ b/crates/loans/Cargo.toml @@ -1,5 +1,5 @@ [package] -authors = ["Interlay Ltd"] +authors = ["Parallel Team", "Interlay Ltd"] edition = "2021" name = "pallet-loans" version = "1.9.3" diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 487169a412..812ee9fdc0 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -241,8 +241,6 @@ pub mod pallet { CodecError, /// Collateral is reserved and cannot be liquidated CollateralReserved, - /// Arithmetic underflow - ArithmeticUnderflow, } #[pallet::event] @@ -1142,7 +1140,7 @@ impl Pallet { Ok(( total_collateral_value .checked_sub(&total_borrow_value) - .ok_or(Error::::ArithmeticUnderflow)?, + .ok_or(ArithmeticError::Underflow)?, FixedU128::zero(), )) } else { @@ -1150,7 +1148,7 @@ impl Pallet { FixedU128::zero(), total_borrow_value .checked_sub(&total_collateral_value) - .ok_or(Error::::ArithmeticUnderflow)?, + .ok_or(ArithmeticError::Underflow)?, )) } } diff --git a/crates/traits/Cargo.toml b/crates/traits/Cargo.toml index 44b8407476..1e68be0a2d 100644 --- a/crates/traits/Cargo.toml +++ b/crates/traits/Cargo.toml @@ -1,5 +1,5 @@ [package] -authors = ["Parallel Team"] +authors = ["Parallel Team", "Interlay Ltd"] edition = "2021" name = "pallet-traits" version = "1.9.3" diff --git a/crates/traits/src/loans.rs b/crates/traits/src/loans.rs index 2aa0a5ffaf..b559343fac 100644 --- a/crates/traits/src/loans.rs +++ b/crates/traits/src/loans.rs @@ -1,3 +1,6 @@ +// Copyright 2022 Interlay. +// This file is part of Interlay. + // Copyright 2021 Parallel Finance Developer. // This file is part of Parallel Finance. From 13e038e403a8cf3186f7381a01e63824bf85cf35 Mon Sep 17 00:00:00 2001 From: Daniel Savu Date: Tue, 8 Nov 2022 13:52:28 +0100 Subject: [PATCH 58/58] fix(loans): use currency hooks on testnet; refactor constants; improve comments --- crates/currency/src/lib.rs | 8 ++++---- crates/loans/src/farming.rs | 2 +- crates/loans/src/lib.rs | 15 +++++++++++---- parachain/runtime/testnet-interlay/src/lib.rs | 7 ++++--- parachain/runtime/testnet-kintsugi/src/lib.rs | 7 ++++--- primitives/src/lib.rs | 2 +- standalone/runtime/src/lib.rs | 7 ++++--- standalone/runtime/tests/test_loans.rs | 2 +- 8 files changed, 30 insertions(+), 20 deletions(-) diff --git a/crates/currency/src/lib.rs b/crates/currency/src/lib.rs index 1612faac7d..1dd3ca1f32 100644 --- a/crates/currency/src/lib.rs +++ b/crates/currency/src/lib.rs @@ -44,7 +44,7 @@ where { fn convert(amount: &Amount, to: CurrencyId) -> Result, DispatchError> { if amount.currency().is_lend_token() && to.is_lend_token() { - // Exampe (lendDOT to lendINTR): + // Example (lendDOT to lendINTR): // collateral_amount(convert(underlying_amount(lendDOT_amount), underlying_id(lendINTR))) // collateral_amount(convert(dot_amount, INTR)) // collateral_amount(intr_amount) @@ -53,12 +53,12 @@ where let to_underlying_amount = Oracle::convert(&from_underlying_amount, to_underlying_id)?; Loans::recompute_collateral_amount(&to_underlying_amount) } else if amount.currency().is_lend_token() { - // Exampe: LendDOT -> INTR = + // Example: LendDOT -> INTR = // convert(underlying_amount(lendDOT_amount), INTR) // convert(dot_amount, INTR) Oracle::convert(&Loans::recompute_underlying_amount(amount)?, to) } else if to.is_lend_token() { - // Exampe (DOT to lendINTR): + // Example (DOT to lendINTR): // collateral_amount(convert(dot_amount, underlying_id(lendINTR))) // collateral_amount(convert(dot_amount, INTR)) // collateral_amount(intr_amount) @@ -68,7 +68,7 @@ where // get the equivalent lend_token amount using the internal exchange rate Loans::recompute_collateral_amount(&underlying_amount) } else { - // Exampe (DOT to INTR): + // Example (DOT to INTR): // convert(dot_amount, INTR) Oracle::convert(amount, to) } diff --git a/crates/loans/src/farming.rs b/crates/loans/src/farming.rs index e95b7d6798..828cc2ba3e 100644 --- a/crates/loans/src/farming.rs +++ b/crates/loans/src/farming.rs @@ -23,7 +23,7 @@ use crate::*; impl Pallet { pub(crate) fn reward_account_id() -> Result { let account_id: T::AccountId = T::PalletId::get().into_account_truncating(); - let entropy = (b"loans/farming", &[account_id]).using_encoded(blake2_256); + let entropy = (REWARD_ACCOUNT_PREFIX, &[account_id]).using_encoded(blake2_256); Ok(T::AccountId::decode(&mut &entropy[..]).map_err(|_| Error::::CodecError)?) } diff --git a/crates/loans/src/lib.rs b/crates/loans/src/lib.rs index 812ee9fdc0..a37b5e4f7f 100644 --- a/crates/loans/src/lib.rs +++ b/crates/loans/src/lib.rs @@ -76,11 +76,18 @@ mod types; pub mod weights; +pub const REWARD_ACCOUNT_PREFIX: &[u8; 13] = b"loans/farming"; +pub const INCENTIVE_ACCOUNT_PREFIX: &[u8; 15] = b"loans/incentive"; + type AccountIdOf = ::AccountId; type AssetIdOf = <::Assets as Inspect<::AccountId>>::AssetId; type BalanceOf = <::Assets as Inspect<::AccountId>>::Balance; pub struct OnSlashHook(marker::PhantomData); +// This implementation is not allowed to fail, so erors are logged instead of being propagated. +// If the slash-related FRAME traits are allowed to fail, this can be fixed. +// Opened a GitHub issue for this in the Substrate repo: https://github.com/paritytech/substrate/issues/12533 +// TODO: Propagate error once the issue is resolved upstream impl OnSlash, BalanceOf> for OnSlashHook { fn on_slash(currency_id: AssetIdOf, account_id: &T::AccountId, amount: BalanceOf) { if currency_id.is_lend_token() { @@ -105,6 +112,7 @@ impl OnSlash, BalanceOf> for OnSlashHoo } pub struct OnDepositHook(marker::PhantomData); +// TODO: upgrade to use orml-tokens posthooks once merged to master impl OnDeposit, BalanceOf> for OnDepositHook { fn on_deposit(currency_id: AssetIdOf, account_id: &T::AccountId, _: BalanceOf) -> DispatchResult { if currency_id.is_lend_token() { @@ -117,6 +125,7 @@ impl OnDeposit, BalanceOf> for OnDeposi } pub struct OnTransferHook(marker::PhantomData); +// TODO: upgrade to use orml-tokens posthooks once merged to master impl OnTransfer, BalanceOf> for OnTransferHook { fn on_transfer( currency_id: AssetIdOf, @@ -146,9 +155,7 @@ pub mod pallet { use super::*; #[pallet::config] - pub trait Config: - frame_system::Config + currency::Config, CurrencyId = CurrencyId> - { + pub trait Config: frame_system::Config + currency::Config> { type Event: From> + IsType<::Event>; /// The oracle price feeder @@ -1815,7 +1822,7 @@ impl Pallet { // Returns the incentive reward account pub fn incentive_reward_account_id() -> Result { let account_id: T::AccountId = T::PalletId::get().into_account_truncating(); - let entropy = (b"loans/incentive", &[account_id]).using_encoded(blake2_256); + let entropy = (INCENTIVE_ACCOUNT_PREFIX, &[account_id]).using_encoded(blake2_256); Ok(T::AccountId::decode(&mut &entropy[..]).map_err(|_| Error::::CodecError)?) } } diff --git a/parachain/runtime/testnet-interlay/src/lib.rs b/parachain/runtime/testnet-interlay/src/lib.rs index 1b65ff6187..48f5e18180 100644 --- a/parachain/runtime/testnet-interlay/src/lib.rs +++ b/parachain/runtime/testnet-interlay/src/lib.rs @@ -26,6 +26,7 @@ use frame_system::{ }; use orml_asset_registry::SequentialId; use orml_traits::{location::AbsoluteReserveProvider, parameter_type_with_key, MultiCurrency}; +use pallet_loans::{OnDepositHook, OnSlashHook, OnTransferHook}; use pallet_traits::OracleApi; use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment}; use primitives::PriceDetail; @@ -672,9 +673,9 @@ impl orml_tokens::Config for Runtime { type WeightInfo = (); type ExistentialDeposits = ExistentialDeposits; type OnDust = orml_tokens::TransferDust; - type OnSlash = (); - type OnDeposit = (); - type OnTransfer = (); + type OnSlash = OnSlashHook; + type OnDeposit = OnDepositHook; + type OnTransfer = OnTransferHook; type MaxLocks = MaxLocks; type DustRemovalWhitelist = DustRemovalWhitelist; type MaxReserves = ConstU32<0>; // we don't use named reserves diff --git a/parachain/runtime/testnet-kintsugi/src/lib.rs b/parachain/runtime/testnet-kintsugi/src/lib.rs index 18330fe1f0..501058da9b 100644 --- a/parachain/runtime/testnet-kintsugi/src/lib.rs +++ b/parachain/runtime/testnet-kintsugi/src/lib.rs @@ -26,6 +26,7 @@ use frame_system::{ }; use orml_asset_registry::SequentialId; use orml_traits::{location::AbsoluteReserveProvider, parameter_type_with_key, MultiCurrency}; +use pallet_loans::{OnDepositHook, OnSlashHook, OnTransferHook}; use pallet_traits::OracleApi; use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment}; use primitives::PriceDetail; @@ -672,9 +673,9 @@ impl orml_tokens::Config for Runtime { type WeightInfo = (); type ExistentialDeposits = ExistentialDeposits; type OnDust = orml_tokens::TransferDust; - type OnSlash = (); - type OnDeposit = (); - type OnTransfer = (); + type OnSlash = OnSlashHook; + type OnDeposit = OnDepositHook; + type OnTransfer = OnTransferHook; type MaxLocks = MaxLocks; type DustRemovalWhitelist = DustRemovalWhitelist; type MaxReserves = ConstU32<0>; // we don't use named reserves diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 8713c6b262..1c7d52166e 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -361,7 +361,7 @@ pub type UnsignedInner = u128; /// Loans pallet types pub type Price = FixedU128; -pub type Timestamp = u64; +pub type Timestamp = Moment; pub type PriceDetail = (Price, Timestamp); pub type Rate = FixedU128; pub type Ratio = Permill; diff --git a/standalone/runtime/src/lib.rs b/standalone/runtime/src/lib.rs index 8bfd34067f..00dc7826c4 100644 --- a/standalone/runtime/src/lib.rs +++ b/standalone/runtime/src/lib.rs @@ -25,6 +25,7 @@ use frame_system::{ }; use orml_asset_registry::SequentialId; use orml_traits::parameter_type_with_key; +use pallet_loans::{OnDepositHook, OnSlashHook, OnTransferHook}; use pallet_traits::OracleApi; use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment}; use sp_api::impl_runtime_apis; @@ -630,9 +631,9 @@ impl orml_tokens::Config for Runtime { type WeightInfo = (); type ExistentialDeposits = ExistentialDeposits; type OnDust = orml_tokens::TransferDust; - type OnSlash = (); - type OnDeposit = (); - type OnTransfer = (); + type OnSlash = OnSlashHook; + type OnDeposit = OnDepositHook; + type OnTransfer = OnTransferHook; type MaxLocks = MaxLocks; type DustRemovalWhitelist = DustRemovalWhitelist; type MaxReserves = ConstU32<0>; // we don't use named reserves diff --git a/standalone/runtime/tests/test_loans.rs b/standalone/runtime/tests/test_loans.rs index db3730c269..bf2ddaa6e8 100644 --- a/standalone/runtime/tests/test_loans.rs +++ b/standalone/runtime/tests/test_loans.rs @@ -296,7 +296,7 @@ fn integration_test_lend_token_transfer_reserved_fails() { ); // Transferring the full amount fails - assert_noop!( + assert_err!( lend_tokens.transfer(&vault_account_id, &lp_account_id), TokensError::BalanceTooLow );