Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 21 additions & 45 deletions common/src/borrow.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use std::{
borrow::{Borrow, BorrowMut},
ops::{Deref, DerefMut},
};
use std::ops::{Deref, DerefMut};

use near_sdk::{env, json_types::U64, near, AccountId};

Expand Down Expand Up @@ -203,7 +200,7 @@ impl<M> LinkedBorrowPosition<M> {
}
}

impl<M: Borrow<Market>> LinkedBorrowPosition<M> {
impl<M: Deref<Target = Market>> LinkedBorrowPosition<M> {
pub fn with_pending_interest(&mut self) {
self.position.borrow_asset_fees.pending_estimate =
self.calculate_interest(u32::MAX).get_amount();
Expand All @@ -214,9 +211,8 @@ impl<M: Borrow<Market>> LinkedBorrowPosition<M> {
}

pub(crate) fn calculate_last_snapshot_interest(&self) -> BorrowAssetAmount {
let market: &Market = self.market.borrow();
let last_snapshot = market.get_last_snapshot();
let interest_rate = market.get_interest_rate_for_snapshot(last_snapshot);
let last_snapshot = self.market.get_last_snapshot();
let interest_rate = self.market.get_interest_rate_for_snapshot(last_snapshot);
let duration_ms = Decimal::from(env::block_timestamp_ms() - last_snapshot.timestamp_ms.0);
let ms_in_a_year = Decimal::from(MS_IN_A_YEAR);
let interest_rate_part: Decimal = interest_rate * duration_ms / ms_in_a_year;
Expand All @@ -242,7 +238,6 @@ impl<M: Borrow<Market>> LinkedBorrowPosition<M> {
)]
let mut it = self
.market
.borrow()
.snapshots
.iter()
.enumerate()
Expand All @@ -264,7 +259,6 @@ impl<M: Borrow<Market>> LinkedBorrowPosition<M> {

let interest_rate_per_year: Decimal = self
.market
.borrow()
.configuration
.borrow_interest_rate_strategy
.at(snapshot.usage_ratio());
Expand Down Expand Up @@ -297,22 +291,19 @@ impl<M: Borrow<Market>> LinkedBorrowPosition<M> {

pub fn can_be_liquidated(&self, price_pair: &PricePair, block_timestamp_ms: u64) -> bool {
self.market
.borrow()
.configuration
.borrow_status(&self.position, price_pair, block_timestamp_ms)
.is_liquidation()
}

pub fn is_within_minimum_initial_collateral_ratio(&self, price_pair: &PricePair) -> bool {
self.market
.borrow()
.configuration
.is_within_minimum_initial_collateral_ratio(&self.position, price_pair)
}

pub fn is_within_minimum_collateral_ratio(&self, price_pair: &PricePair) -> bool {
self.market
.borrow()
.configuration
.is_within_minimum_collateral_ratio(&self.position, price_pair)
}
Expand All @@ -322,7 +313,6 @@ impl<M: Borrow<Market>> LinkedBorrowPosition<M> {
price_pair: &PricePair,
) -> Option<BorrowAssetAmount> {
self.market
.borrow()
.configuration
.minimum_acceptable_liquidation_amount(
self.position.collateral_asset_deposit,
Expand All @@ -331,34 +321,33 @@ impl<M: Borrow<Market>> LinkedBorrowPosition<M> {
}
}

pub struct LinkedBorrowPositionMut<M: BorrowMut<Market>>(LinkedBorrowPosition<M>);
pub struct LinkedBorrowPositionMut<'a>(LinkedBorrowPosition<&'a mut Market>);

impl<M: BorrowMut<Market>> Drop for LinkedBorrowPositionMut<M> {
impl Drop for LinkedBorrowPositionMut<'_> {
fn drop(&mut self) {
self.0
.market
.borrow_mut()
.borrow_positions
.insert(&self.0.account_id, &self.0.position);
}
}

impl<M: BorrowMut<Market>> Deref for LinkedBorrowPositionMut<M> {
type Target = LinkedBorrowPosition<M>;
impl<'a> Deref for LinkedBorrowPositionMut<'a> {
type Target = LinkedBorrowPosition<&'a mut Market>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl<M: BorrowMut<Market>> DerefMut for LinkedBorrowPositionMut<M> {
impl DerefMut for LinkedBorrowPositionMut<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

impl<M: BorrowMut<Market>> LinkedBorrowPositionMut<M> {
pub fn new(market: M, account_id: AccountId, position: BorrowPosition) -> Self {
impl<'a> LinkedBorrowPositionMut<'a> {
pub fn new(market: &'a mut Market, account_id: AccountId, position: BorrowPosition) -> Self {
Self(LinkedBorrowPosition::new(market, account_id, position))
}

Expand Down Expand Up @@ -398,7 +387,6 @@ impl<M: BorrowMut<Market>> LinkedBorrowPositionMut<M> {
self.accumulate_interest();

self.market
.borrow_mut()
.borrow_asset_in_flight
.join(amount)
.unwrap_or_else(|| env::panic_str("Borrow asset in flight amount overflow"));
Expand All @@ -419,7 +407,6 @@ impl<M: BorrowMut<Market>> LinkedBorrowPositionMut<M> {
// This should never panic, because a given amount of in-flight borrow
// asset should always be added before it is removed.
self.market
.borrow_mut()
.borrow_asset_in_flight
.split(amount)
.unwrap_or_else(|| env::panic_str("Borrow asset in flight amount underflow"));
Expand All @@ -442,11 +429,10 @@ impl<M: BorrowMut<Market>> LinkedBorrowPositionMut<M> {
.unwrap_or_else(|| env::panic_str("Increase borrow asset principal overflow"));

self.market
.borrow_mut()
.borrow_asset_borrowed
.join(amount)
.unwrap_or_else(|| env::panic_str("Borrow asset borrowed overflow"));
self.market.borrow_mut().snapshot();
self.market.snapshot();

MarketEvent::BorrowWithdrawn {
account_id: self.account_id.clone(),
Expand All @@ -466,18 +452,16 @@ impl<M: BorrowMut<Market>> LinkedBorrowPositionMut<M> {
.unwrap_or_else(|e| env::panic_str(&e.to_string()));

self.market
.borrow_mut()
.record_borrow_asset_yield_distribution(liability_reduction.amount_to_fees);

// SAFETY: It should be impossible to panic here, since assets that
// have not yet been borrowed cannot be repaid.
self.market
.borrow_mut()
.borrow_asset_borrowed
.split(liability_reduction.amount_to_principal)
.unwrap_or_else(|| env::panic_str("Borrow asset borrowed underflow"));

self.market.borrow_mut().snapshot();
self.market.snapshot();

MarketEvent::BorrowRepaid {
account_id: self.account_id.clone(),
Expand All @@ -491,7 +475,7 @@ impl<M: BorrowMut<Market>> LinkedBorrowPositionMut<M> {
}

pub fn accumulate_interest(&mut self) -> InterestAccumulationProof {
self.market.borrow_mut().snapshot();
self.market.snapshot();

let accumulation_record = self.calculate_interest(u32::MAX);

Expand Down Expand Up @@ -535,29 +519,21 @@ impl<M: BorrowMut<Market>> LinkedBorrowPositionMut<M> {
}
.emit();

let snapshot_index = self.market.borrow_mut().snapshot();
let snapshot_index = self.market.snapshot();
self.position.full_liquidation(snapshot_index);

self.market
.borrow_mut()
.borrow_asset_borrowed
.split(principal);
self.market.borrow_asset_borrowed.split(principal);

// TODO: Is it correct to only care about the original principal here?
if recovered_amount.split(principal).is_some() {
// distribute yield
// Distribute yield.
// record_borrow_asset_yield_distribution will take snapshot, no need to do it.
self.market
.borrow_mut()
.record_borrow_asset_yield_distribution(recovered_amount);
} else {
// we took a loss
// TODO: some sort of recovery for suppliers
//
// Might look something like this:
// self.borrow_asset_deposited.split(principal);
// (?)
todo!("Took a loss during liquidation");
// Took a loss on liquidation.
// This can be detected from the event (borrow_asset_principal > borrow_asset_recovered?).
// Deficit should be covered by protocol insurance.
// No need for additional action.
}
}
}
8 changes: 4 additions & 4 deletions common/src/market/impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ impl Market {
pub fn get_linked_supply_position_mut(
&mut self,
account_id: AccountId,
) -> Option<LinkedSupplyPositionMut<&mut Self>> {
) -> Option<LinkedSupplyPositionMut> {
self.supply_positions
.get(&account_id)
.map(|position| LinkedSupplyPositionMut::new(self, account_id, position))
Expand All @@ -183,7 +183,7 @@ impl Market {
pub fn get_or_create_linked_supply_position_mut(
&mut self,
account_id: AccountId,
) -> LinkedSupplyPositionMut<&mut Self> {
) -> LinkedSupplyPositionMut {
let position = self
.supply_positions
.get(&account_id)
Expand All @@ -208,7 +208,7 @@ impl Market {
pub fn get_linked_borrow_position_mut(
&mut self,
account_id: AccountId,
) -> Option<LinkedBorrowPositionMut<&mut Self>> {
) -> Option<LinkedBorrowPositionMut> {
self.borrow_positions
.get(&account_id)
.map(|position| LinkedBorrowPositionMut::new(self, account_id, position))
Expand All @@ -217,7 +217,7 @@ impl Market {
pub fn get_or_create_linked_borrow_position_mut(
&mut self,
account_id: AccountId,
) -> LinkedBorrowPositionMut<&mut Self> {
) -> LinkedBorrowPositionMut {
let position = self
.borrow_positions
.get(&account_id)
Expand Down
59 changes: 20 additions & 39 deletions common/src/supply.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use std::{
borrow::{Borrow, BorrowMut},
ops::{Deref, DerefMut},
};
use std::ops::{Deref, DerefMut};

use near_sdk::{env, json_types::U64, near, AccountId};

Expand Down Expand Up @@ -99,7 +96,7 @@ impl<M> LinkedSupplyPosition<M> {
}
}

impl<M: Borrow<Market>> LinkedSupplyPosition<M> {
impl<M: Deref<Target = Market>> LinkedSupplyPosition<M> {
pub fn with_pending_yield_estimate(&mut self) {
self.position.borrow_asset_yield.pending_estimate = self.calculate_yield().get_amount();
self.position
Expand All @@ -114,29 +111,16 @@ impl<M: Borrow<Market>> LinkedSupplyPosition<M> {
return BorrowAssetAmount::zero();
}

let last_snapshot = self.market.borrow().get_last_snapshot();
let last_snapshot = self.market.get_last_snapshot();
let total_deposited: Decimal = last_snapshot.deposited.into();
if total_deposited.is_zero() {
// divzero safety
return BorrowAssetAmount::zero();
}
let supply_weight = Decimal::from(
self.market
.borrow()
.configuration
.yield_weights
.supply
.get(),
);
let supply_weight = Decimal::from(self.market.configuration.yield_weights.supply.get());
// This is guaranteed to be nonzero, so no divzero issue.
let total_weight = Decimal::from(
self.market
.borrow()
.configuration
.yield_weights
.total_weight()
.get(),
);
let total_weight =
Decimal::from(self.market.configuration.yield_weights.total_weight().get());
let total_yield_distribution: Decimal = last_snapshot.yield_distribution.into();
let estimate_current_snapshot =
total_yield_distribution * deposit * supply_weight / total_deposited / total_weight;
Expand All @@ -159,7 +143,7 @@ impl<M: Borrow<Market>> LinkedSupplyPosition<M> {

let mut accumulated = Decimal::ZERO;

let mut it = self.market.borrow().snapshots.iter();
let mut it = self.market.snapshots.iter();
// Skip the last snapshot, which may be incomplete.
it.next_back();

Expand All @@ -184,39 +168,38 @@ impl<M: Borrow<Market>> LinkedSupplyPosition<M> {
}
}

pub struct LinkedSupplyPositionMut<M: BorrowMut<Market>>(LinkedSupplyPosition<M>);
pub struct LinkedSupplyPositionMut<'a>(LinkedSupplyPosition<&'a mut Market>);

impl<M: BorrowMut<Market>> Drop for LinkedSupplyPositionMut<M> {
impl Drop for LinkedSupplyPositionMut<'_> {
fn drop(&mut self) {
self.0
.market
.borrow_mut()
.supply_positions
.insert(&self.0.account_id, &self.0.position);
}
}

impl<M: BorrowMut<Market>> Deref for LinkedSupplyPositionMut<M> {
type Target = LinkedSupplyPosition<M>;
impl<'a> Deref for LinkedSupplyPositionMut<'a> {
type Target = LinkedSupplyPosition<&'a mut Market>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl<M: BorrowMut<Market>> DerefMut for LinkedSupplyPositionMut<M> {
impl DerefMut for LinkedSupplyPositionMut<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

impl<M: BorrowMut<Market>> LinkedSupplyPositionMut<M> {
pub fn new(market: M, account_id: AccountId, position: SupplyPosition) -> Self {
impl<'a> LinkedSupplyPositionMut<'a> {
pub fn new(market: &'a mut Market, account_id: AccountId, position: SupplyPosition) -> Self {
Self(LinkedSupplyPosition::new(market, account_id, position))
}

pub fn accumulate_yield(&mut self) -> YieldAccumulationProof {
self.market.borrow_mut().snapshot();
self.market.snapshot();

let accumulation_record = self.calculate_yield();

Expand Down Expand Up @@ -252,16 +235,15 @@ impl<M: BorrowMut<Market>> LinkedSupplyPositionMut<M> {
self.0.position.started_at_block_timestamp_ms.unwrap().0;
let supply_duration = block_timestamp_ms.saturating_sub(started_at_block_timestamp_ms);

let market: &mut Market = self.market.borrow_mut();

market
self.market
.borrow_asset_deposited
.split(amount)
.unwrap_or_else(|| env::panic_str("Borrow asset deposited underflow"));

market.snapshot();
self.market.snapshot();

let amount_to_fees = market
let amount_to_fees = self
.market
.configuration
.supply_withdrawal_fee
.of(amount, supply_duration)
Expand Down Expand Up @@ -296,12 +278,11 @@ impl<M: BorrowMut<Market>> LinkedSupplyPositionMut<M> {
.unwrap_or_else(|| env::panic_str("Supply position borrow asset overflow"));

self.market
.borrow_mut()
.borrow_asset_deposited
.join(amount)
.unwrap_or_else(|| env::panic_str("Borrow asset deposited overflow"));

self.market.borrow_mut().snapshot();
self.market.snapshot();

MarketEvent::SupplyDeposited {
account_id: self.account_id.clone(),
Expand Down
Loading