Skip to content

Commit 1f5ad9d

Browse files
committed
WIP: allow redeems to use reserve cash
1 parent 3c08fd4 commit 1f5ad9d

File tree

3 files changed

+24
-20
lines changed

3 files changed

+24
-20
lines changed

crates/loans/src/interest.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,9 @@ impl<T: Config> Pallet<T> {
129129
}
130130

131131
/// Calculate the borrowing utilization ratio of the specified market
132-
///
133-
/// utilizationRatio = totalBorrows / (totalCash + totalBorrows − totalReserves)
132+
/// `utilization_ratio = borrows / (cash + borrows - reserve)`
133+
/// Since the market can reach a state where `cash == 0 && borrows == reserve`,
134+
/// this rate can be infinitely large.
134135
pub(crate) fn calc_utilization_ratio(
135136
cash: BalanceOf<T>,
136137
borrows: BalanceOf<T>,
@@ -145,6 +146,9 @@ impl<T: Config> Pallet<T> {
145146
.and_then(|r| r.checked_sub(reserves))
146147
.ok_or(ArithmeticError::Overflow)?;
147148

149+
if total.is_zero() {
150+
return Err(DispatchError::Arithmetic(ArithmeticError::DivisionByZero));
151+
}
148152
Ok(Ratio::from_rational(borrows, total))
149153
}
150154

crates/loans/src/lib.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,13 +1195,12 @@ pub mod pallet {
11951195
Ok(().into())
11961196
}
11971197

1198-
/// Add reserves by transferring from payer.
1199-
/// TODO: This extrinsic currently does nothing useful. See the TODO comment
1200-
/// of the `ensure_enough_cash` function for more details. Based on that
1201-
/// TODO, decide whether this extrinsic should be kept.
1198+
/// Add reserves by transferring from payer. This is useful because the reserve balance can be used as
1199+
/// cash for redeeming. In case the market reaches 100% utilization, the protocol can deposit
1200+
/// more cash to the reserve, to allow users to exit (redeem) their lend token positions.
1201+
/// The reserve cash cannot be used to borrowing.
12021202
///
12031203
/// May only be called from `T::ReserveOrigin`.
1204-
///
12051204
/// - `payer`: the payer account.
12061205
/// - `asset_id`: the assets to be added.
12071206
/// - `add_amount`: the amount to be added.
@@ -1454,7 +1453,9 @@ impl<T: Config> Pallet<T> {
14541453
// Ensure there is enough cash in the market
14551454
let exchange_rate = Self::exchange_rate_stored(asset_id)?;
14561455
let redeem_amount = Self::calc_underlying_amount(voucher_amount, exchange_rate)?;
1457-
Self::ensure_enough_cash(asset_id, redeem_amount)?;
1456+
if Self::get_total_cash(asset_id) < redeem_amount {
1457+
return Err(Error::<T>::InsufficientCash.into());
1458+
}
14581459

14591460
// TODO: Only free lend tokens are redeemable. Replace logic below with this:
14601461
// if voucher_amount > Self::free_lend_tokens(asset_id, redeemer)?.amount() {
@@ -1511,7 +1512,7 @@ impl<T: Config> Pallet<T> {
15111512
/// Borrower shouldn't borrow more than their total collateral value allows
15121513
fn borrow_allowed(asset_id: AssetIdOf<T>, borrower: &T::AccountId, borrow_amount: BalanceOf<T>) -> DispatchResult {
15131514
Self::ensure_under_borrow_cap(asset_id, borrow_amount)?;
1514-
Self::ensure_enough_cash(asset_id, borrow_amount)?;
1515+
Self::ensure_borrow_cash(asset_id, borrow_amount)?;
15151516
let borrow_value = Self::get_asset_value(asset_id, borrow_amount)?;
15161517
Self::ensure_liquidity(borrower, borrow_value)?;
15171518

@@ -1833,7 +1834,7 @@ impl<T: Config> Pallet<T> {
18331834
/// https://github.com/compound-finance/compound-protocol/blob/a3214f67b73310d547e00fc578e8355911c9d376/contracts/CToken.sol#L518
18341835
/// - but getCashPrior is the entire balance of the contract:
18351836
/// https://github.com/compound-finance/compound-protocol/blob/a3214f67b73310d547e00fc578e8355911c9d376/contracts/CToken.sol#L1125
1836-
fn ensure_enough_cash(asset_id: AssetIdOf<T>, amount: BalanceOf<T>) -> DispatchResult {
1837+
fn ensure_borrow_cash(asset_id: AssetIdOf<T>, amount: BalanceOf<T>) -> DispatchResult {
18371838
let reducible_cash = Self::get_total_cash(asset_id)
18381839
.checked_sub(Self::total_reserves(asset_id))
18391840
.ok_or(ArithmeticError::Underflow)?;

crates/loans/src/tests.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ fn redeem_fails_when_insufficient_liquidity() {
362362
}
363363

364364
#[test]
365-
fn redeem_fails_when_would_use_reserved_balanace() {
365+
fn redeem_succeds_when_would_use_reserved_balanace() {
366366
new_test_ext().execute_with(|| {
367367
// Prepare: Bob Deposit 200 DOT
368368
assert_ok!(Loans::mint(RuntimeOrigin::signed(BOB), DOT, 200));
@@ -375,10 +375,9 @@ fn redeem_fails_when_would_use_reserved_balanace() {
375375
assert_ok!(Loans::borrow(RuntimeOrigin::signed(ALICE), DOT, 50));
376376
assert_ok!(Loans::add_reserves(RuntimeOrigin::root(), ALICE, DOT, 50));
377377

378-
assert_noop!(
379-
Loans::redeem(RuntimeOrigin::signed(BOB), DOT, 151),
380-
Error::<Test>::InsufficientCash
381-
);
378+
assert_ok!(Loans::redeem(RuntimeOrigin::signed(BOB), DOT, 151));
379+
let utilization_ratio = Loans::utilization_ratio(DOT);
380+
println!("utilization: {:?}", utilization_ratio);
382381
})
383382
}
384383

@@ -956,7 +955,7 @@ fn calc_collateral_amount_works() {
956955
}
957956

958957
#[test]
959-
fn ensure_enough_cash_works() {
958+
fn ensure_borrow_cash_works() {
960959
new_test_ext().execute_with(|| {
961960
assert_ok!(Tokens::set_balance(
962961
RuntimeOrigin::root(),
@@ -965,17 +964,17 @@ fn ensure_enough_cash_works() {
965964
unit(1000),
966965
0
967966
));
968-
assert_ok!(Loans::ensure_enough_cash(KSM, unit(1000)));
967+
assert_ok!(Loans::ensure_borrow_cash(KSM, unit(1000)));
969968
TotalReserves::<Test>::insert(KSM, unit(10));
970969
assert_noop!(
971-
Loans::ensure_enough_cash(KSM, unit(1000)),
970+
Loans::ensure_borrow_cash(KSM, unit(1000)),
972971
Error::<Test>::InsufficientCash,
973972
);
974-
assert_ok!(Loans::ensure_enough_cash(KSM, unit(990)));
973+
assert_ok!(Loans::ensure_borrow_cash(KSM, unit(990)));
975974
// Borrows don't count as cash
976975
TotalBorrows::<Test>::insert(KSM, unit(20));
977976
assert_noop!(
978-
Loans::ensure_enough_cash(KSM, unit(1000)),
977+
Loans::ensure_borrow_cash(KSM, unit(1000)),
979978
Error::<Test>::InsufficientCash
980979
);
981980
})

0 commit comments

Comments
 (0)