Skip to content

Commit

Permalink
AL/BE-153. Controller refactor allowed functions. (#31)
Browse files Browse the repository at this point in the history
* [BE-153] Fixed do_redeem_insurance function

* [BE-153] 1. removed call to oracle from borrow_allowed(); 2. removed deposit_allowed() and use is_operation_allowed() instead; 3. removed repay_borrow_allowed() and use is_operation() instead;

* [BE-153] Moved calls of is_operation_allowed() to do_deposit(), do_redeem(), do_borrow() and do_repay() functions. Fixed tests for them.

* [BE-153] Resolved conflicts.
  • Loading branch information
lut1k committed Jan 20, 2021
1 parent 48ea51a commit 5b2b9fb
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 235 deletions.
65 changes: 6 additions & 59 deletions pallets/controller/src/lib.rs
Expand Up @@ -3,7 +3,7 @@
use codec::{Decode, Encode};
use frame_support::{decl_error, decl_event, decl_module, decl_storage, ensure, traits::Get};
use frame_system::{self as system, ensure_signed};
use minterest_primitives::{Balance, CurrencyId, Operation, Price, Rate};
use minterest_primitives::{Balance, CurrencyId, Operation, Rate};
use orml_traits::MultiCurrency;
use orml_utilities::with_transaction_result;
#[cfg(feature = "std")]
Expand Down Expand Up @@ -140,9 +140,6 @@ decl_error! {
/// Only happened when the balance went wrong and balance overflows the integer type.
BalanceOverflowed,

/// Operation (deposit, redeem, borrow, repay) is paused.
OperationPaused,

/// Maximum borrow rate cannot be set to 0.
MaxBorrowRateCannotBeZero,

Expand Down Expand Up @@ -577,25 +574,6 @@ impl<T: Trait> Module<T> {
}
}

/// Checks if the account should be allowed to deposit tokens in the given pool.
///
/// - `underlying_asset_id` - The CurrencyId to verify the redeem against.
/// - `depositor` - The account which would deposit the tokens.
/// - `deposit_amount` - The amount of underlying being supplied to the pool in exchange for
/// tokens.
/// Return Ok if the deposit is allowed, otherwise a semi-opaque error code.
pub fn deposit_allowed(
underlying_asset_id: CurrencyId,
_depositor: &T::AccountId,
_deposit_amount: Balance,
) -> DispatchResult {
ensure!(
Self::is_operation_allowed(underlying_asset_id, Operation::Deposit),
Error::<T>::OperationPaused
);
Ok(())
}

/// Checks if the account should be allowed to redeem tokens in the given pool.
///
/// - `underlying_asset_id` - The CurrencyId to verify the redeem against.
Expand All @@ -608,11 +586,6 @@ impl<T: Trait> Module<T> {
redeemer: &T::AccountId,
redeem_amount: Balance,
) -> DispatchResult {
ensure!(
Self::is_operation_allowed(underlying_asset_id, Operation::Redeem),
Error::<T>::OperationPaused
);

if LiquidityPools::<T>::check_user_available_collateral(&redeemer, underlying_asset_id) {
let (_, shortfall) =
Self::get_hypothetical_account_liquidity(&redeemer, underlying_asset_id, redeem_amount, 0)?;
Expand All @@ -634,16 +607,6 @@ impl<T: Trait> Module<T> {
who: &T::AccountId,
borrow_amount: Balance,
) -> DispatchResult {
ensure!(
Self::is_operation_allowed(underlying_asset_id, Operation::Borrow),
Error::<T>::OperationPaused
);

let oracle_price =
<Oracle<T>>::get_underlying_price(underlying_asset_id).map_err(|_| Error::<T>::OraclePriceError)?;

ensure!(oracle_price != Price::from_inner(0), Error::<T>::OraclePriceError);

//FIXME: add borrowCap checking

let (_, shortfall) = Self::get_hypothetical_account_liquidity(&who, underlying_asset_id, 0, borrow_amount)?;
Expand All @@ -653,27 +616,6 @@ impl<T: Trait> Module<T> {
Ok(())
}

/// Checks if the account should be allowed to repay a borrow in the given pool.
///
/// - `underlying_asset_id` - The CurrencyId to verify the repay against.
/// - `who` - The account which would repay the asset.
/// - `borrow_amount` - The amount of underlying assets the account would repay.
/// Return Ok if the borrow is allowed, otherwise a semi-opaque error code
pub fn repay_borrow_allowed(
underlying_asset_id: CurrencyId,
_who: &T::AccountId,
_repay_amount: Balance,
) -> DispatchResult {
ensure!(
Self::is_operation_allowed(underlying_asset_id, Operation::Repay),
Error::<T>::OperationPaused
);

let _borrow_index = <LiquidityPools<T>>::get_pool_borrow_index(underlying_asset_id);

Ok(())
}

/// Checks if a specific operation is allowed on a pool.
///
/// Return true - if operation is allowed, false - if operation is unallowed.
Expand Down Expand Up @@ -954,6 +896,11 @@ impl<T: Trait> Module<T> {
fn do_redeem_insurance(who: &T::AccountId, pool_id: CurrencyId, amount: Balance) -> DispatchResult {
ensure!(<LiquidityPools<T>>::pool_exists(&pool_id), Error::<T>::PoolNotFound);

ensure!(
amount <= T::MultiCurrency::free_balance(pool_id, &<LiquidityPools<T>>::pools_account_id()),
Error::<T>::NotEnoughBalance
);

let current_total_insurance = <LiquidityPools<T>>::get_pool_total_insurance(pool_id);
ensure!(amount <= current_total_insurance, Error::<T>::NotEnoughBalance);

Expand Down
20 changes: 12 additions & 8 deletions pallets/controller/src/mock.rs
Expand Up @@ -186,6 +186,10 @@ pub fn bob() -> Origin {
}
pub const ONE_HUNDRED: Balance = 100;
pub const BLOCKS_PER_YEAR: u128 = 5_256_000;
pub const DOLLARS: Balance = 1_000_000_000_000_000_000;
pub fn dollars<T: Into<u128>>(d: T) -> Balance {
DOLLARS.saturating_mul(d.into())
}

impl ExtBuilder {
pub fn user_balance(mut self, user: AccountId, currency_id: CurrencyId, balance: Balance) -> Self {
Expand Down Expand Up @@ -261,19 +265,19 @@ impl ExtBuilder {
}

pub fn alice_deposit_60_dot(self) -> Self {
self.user_balance(ALICE, CurrencyId::DOT, 40)
.user_balance(ALICE, CurrencyId::MDOT, 60)
.pool_balance(CurrencyId::DOT, 60)
self.user_balance(ALICE, CurrencyId::DOT, dollars(40_u128))
.user_balance(ALICE, CurrencyId::MDOT, dollars(60_u128))
.pool_balance(CurrencyId::DOT, dollars(60_u128))
.pool_mock(CurrencyId::DOT)
.pool_user_data(ALICE, CurrencyId::DOT, 0, Rate::from_inner(0), false)
.pool_user_data(ALICE, CurrencyId::DOT, Balance::zero(), Rate::zero(), false)
}

pub fn alice_deposit_20_eth(self) -> Self {
self.user_balance(ALICE, CurrencyId::ETH, 80)
.user_balance(ALICE, CurrencyId::METH, 20)
.pool_balance(CurrencyId::ETH, 20)
self.user_balance(ALICE, CurrencyId::ETH, dollars(80_u128))
.user_balance(ALICE, CurrencyId::METH, dollars(20_u128))
.pool_balance(CurrencyId::ETH, dollars(20_u128))
.pool_mock(CurrencyId::ETH)
.pool_user_data(ALICE, CurrencyId::ETH, 0, Rate::from_inner(0), false)
.pool_user_data(ALICE, CurrencyId::ETH, Balance::zero(), Rate::zero(), false)
}

pub fn build(self) -> sp_io::TestExternalities {
Expand Down
57 changes: 18 additions & 39 deletions pallets/controller/src/tests.rs
Expand Up @@ -5,10 +5,6 @@ use mock::*;

use frame_support::{assert_err, assert_noop, assert_ok};

fn dollars<T: Into<u128>>(d: T) -> Balance {
1_000_000_000_000_000_000_u128.saturating_mul(d.into())
}

fn multiplier_per_block_equal_max_value() -> ControllerData<BlockNumber> {
ControllerData {
timestamp: 0,
Expand Down Expand Up @@ -653,25 +649,20 @@ fn get_hypothetical_account_liquidity_two_currencies_from_borrow_should_work() {
});
}

#[test]
fn deposit_allowed_should_work() {
ExtBuilder::default().build().execute_with(|| {
assert_ok!(Controller::deposit_allowed(CurrencyId::DOT, &BOB, 10));
assert_noop!(
Controller::deposit_allowed(CurrencyId::KSM, &BOB, 10),
Error::<Runtime>::OperationPaused
);
});
}

#[test]
fn redeem_allowed_should_work() {
ExtBuilder::default().alice_deposit_60_dot().build().execute_with(|| {
assert_ok!(Controller::redeem_allowed(CurrencyId::DOT, &ALICE, 40));
assert_ok!(Controller::redeem_allowed(CurrencyId::DOT, &ALICE, dollars(40_u128)));

assert_noop!(
Controller::redeem_allowed(CurrencyId::KSM, &ALICE, 10),
Error::<Runtime>::OperationPaused
// collateral parameter is set to true.
assert_ok!(<LiquidityPools<Runtime>>::enable_as_collateral_internal(
&ALICE,
CurrencyId::DOT
));

assert_err!(
Controller::redeem_allowed(CurrencyId::DOT, &ALICE, dollars(100_u128)),
Error::<Runtime>::InsufficientLiquidity
);
});
}
Expand All @@ -681,7 +672,7 @@ fn borrow_allowed_should_work() {
ExtBuilder::default().alice_deposit_60_dot().build().execute_with(|| {
// collateral parameter is set to false. User can't borrow
assert_err!(
Controller::borrow_allowed(CurrencyId::DOT, &ALICE, 10),
Controller::borrow_allowed(CurrencyId::DOT, &ALICE, dollars(10_u128)),
Error::<Runtime>::InsufficientLiquidity
);

Expand All @@ -691,32 +682,15 @@ fn borrow_allowed_should_work() {
CurrencyId::DOT
));

assert_ok!(Controller::borrow_allowed(CurrencyId::DOT, &ALICE, 10));

assert_noop!(
Controller::borrow_allowed(CurrencyId::KSM, &ALICE, 10),
Error::<Runtime>::OperationPaused
);
assert_ok!(Controller::borrow_allowed(CurrencyId::DOT, &ALICE, dollars(10_u128)));

assert_noop!(
Controller::borrow_allowed(CurrencyId::DOT, &ALICE, 999),
Controller::borrow_allowed(CurrencyId::DOT, &ALICE, dollars(999_u128)),
Error::<Runtime>::InsufficientLiquidity
);
});
}

#[test]
fn repay_allowed_should_work() {
ExtBuilder::default().build().execute_with(|| {
assert_ok!(Controller::repay_borrow_allowed(CurrencyId::DOT, &BOB, 10));

assert_noop!(
Controller::repay_borrow_allowed(CurrencyId::KSM, &BOB, 10),
Error::<Runtime>::OperationPaused
);
});
}

#[test]
fn is_operation_allowed_should_work() {
ExtBuilder::default()
Expand Down Expand Up @@ -1194,6 +1168,7 @@ fn redeem_insurance_should_work() {
ExtBuilder::default()
.user_balance(ALICE, CurrencyId::DOT, ONE_HUNDRED)
.pool_total_insurance(CurrencyId::DOT, 1000)
.pool_balance(CurrencyId::DOT, 1000)
.build()
.execute_with(|| {
// ALICE redeem 100 DOT from pool insurance.
Expand All @@ -1202,6 +1177,10 @@ fn redeem_insurance_should_work() {
assert!(System::events().iter().any(|record| record.event == expected_event));

assert_eq!(TestPools::get_pool_total_insurance(CurrencyId::DOT), 875);
assert_eq!(
Currencies::free_balance(CurrencyId::DOT, &TestPools::pools_account_id()),
875,
);

// Bob is not added to the allow-list of admins, so this action is not available for him.
assert_noop!(
Expand Down
29 changes: 22 additions & 7 deletions pallets/minterest-protocol/src/lib.rs
Expand Up @@ -2,7 +2,7 @@

use frame_support::{decl_error, decl_event, decl_module, decl_storage, ensure, traits::Get};
use frame_system::{self as system, ensure_signed};
use minterest_primitives::{Balance, CurrencyId};
use minterest_primitives::{Balance, CurrencyId, Operation};
use orml_traits::MultiCurrency;
use orml_utilities::with_transaction_result;
use pallet_traits::Borrowing;
Expand Down Expand Up @@ -109,7 +109,10 @@ decl_error! {
CanotBeDisabledAsCollateral,

/// The user has not deposited funds into the pool.
CanotBeEnabledAsCollateral
CanotBeEnabledAsCollateral,

/// Operation (deposit, redeem, borrow, repay) is paused.
OperationPaused,
}
}

Expand Down Expand Up @@ -327,8 +330,10 @@ impl<T: Trait> Module<T> {
<Controller<T>>::accrue_interest_rate(underlying_asset_id).map_err(|_| Error::<T>::AccrueInterestFailed)?;

// Fail if deposit not allowed
<Controller<T>>::deposit_allowed(underlying_asset_id, &who, underlying_amount)
.map_err(|_| Error::<T>::DepositControllerRejection)?;
ensure!(
<Controller<T>>::is_operation_allowed(underlying_asset_id, Operation::Deposit),
Error::<T>::OperationPaused
);

let wrapped_id = <Controller<T>>::get_wrapped_id_by_underlying_asset_id(&underlying_asset_id)
.map_err(|_| Error::<T>::NotValidUnderlyingAssetId)?;
Expand Down Expand Up @@ -397,6 +402,10 @@ impl<T: Trait> Module<T> {
);

// Fail if redeem not allowed
ensure!(
<Controller<T>>::is_operation_allowed(underlying_asset_id, Operation::Redeem),
Error::<T>::OperationPaused
);
<Controller<T>>::redeem_allowed(underlying_asset_id, &who, wrapped_amount)
.map_err(|_| Error::<T>::RedeemControllerRejection)?;

Expand Down Expand Up @@ -436,6 +445,10 @@ impl<T: Trait> Module<T> {
<Controller<T>>::accrue_interest_rate(underlying_asset_id).map_err(|_| Error::<T>::AccrueInterestFailed)?;

// Fail if borrow not allowed
ensure!(
<Controller<T>>::is_operation_allowed(underlying_asset_id, Operation::Borrow),
Error::<T>::OperationPaused
);
<Controller<T>>::borrow_allowed(underlying_asset_id, &who, borrow_amount)
.map_err(|_| Error::<T>::BorrowControllerRejection)?;

Expand Down Expand Up @@ -481,9 +494,11 @@ impl<T: Trait> Module<T> {

<Controller<T>>::accrue_interest_rate(underlying_asset_id).map_err(|_| Error::<T>::AccrueInterestFailed)?;

// Fail if repayBorrow not allowed
<Controller<T>>::repay_borrow_allowed(underlying_asset_id, &who, repay_amount)
.map_err(|_| Error::<T>::RepayBorrowControllerRejection)?;
// Fail if repay_borrow not allowed
ensure!(
<Controller<T>>::is_operation_allowed(underlying_asset_id, Operation::Repay),
Error::<T>::OperationPaused
);

// Fetch the amount the borrower owes, with accumulated interest
let account_borrows = <Controller<T>>::borrow_balance_stored(&borrower, underlying_asset_id)
Expand Down
12 changes: 7 additions & 5 deletions pallets/minterest-protocol/src/mock.rs
Expand Up @@ -206,12 +206,14 @@ impl Default for ExtBuilder {
(ALICE, CurrencyId::MINT, ONE_MILL_DOLLARS),
(ALICE, CurrencyId::DOT, ONE_HUNDRED_DOLLARS),
(ALICE, CurrencyId::ETH, ONE_HUNDRED_DOLLARS),
(ALICE, CurrencyId::KSM, ONE_HUNDRED_DOLLARS),
(BOB, CurrencyId::MINT, ONE_MILL_DOLLARS),
(BOB, CurrencyId::DOT, ONE_HUNDRED_DOLLARS),
// seed: initial insurance, equal 10_000$
(TestPools::pools_account_id(), CurrencyId::ETH, TEN_THOUSAND_DOLLARS),
(TestPools::pools_account_id(), CurrencyId::DOT, TEN_THOUSAND_DOLLARS),
(TestPools::pools_account_id(), CurrencyId::KSM, TEN_THOUSAND_DOLLARS),
// seed: initial insurance = 10_000$, initial pool balance = 1_000_000$
(TestPools::pools_account_id(), CurrencyId::KSM, ONE_MILL_DOLLARS),
],
}
}
Expand Down Expand Up @@ -406,10 +408,10 @@ impl ExtBuilder {
(
CurrencyId::KSM,
PauseKeeper {
deposit_paused: false,
redeem_paused: false,
borrow_paused: false,
repay_paused: false,
deposit_paused: true,
redeem_paused: true,
borrow_paused: true,
repay_paused: true,
},
),
(
Expand Down

0 comments on commit 5b2b9fb

Please sign in to comment.