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
4 changes: 4 additions & 0 deletions common/src/borrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,8 @@ impl<'a> BorrowPositionGuard<'a> {
.increase_collateral_asset_deposit(amount)
.unwrap_or_else(|| env::panic_str("Borrow position collateral asset overflow"));

asset_op!(self.market.collateral_asset_deposited += amount);

MarketEvent::CollateralDeposited {
account_id: self.account_id.clone(),
collateral_asset_amount: amount,
Expand All @@ -394,6 +396,8 @@ impl<'a> BorrowPositionGuard<'a> {
.decrease_collateral_asset_deposit(amount)
.unwrap_or_else(|| env::panic_str("Borrow position collateral asset underflow"));

asset_op!(self.market.collateral_asset_deposited -= amount);

MarketEvent::CollateralWithdrawn {
account_id: self.account_id.clone(),
collateral_asset_amount: amount,
Expand Down
35 changes: 24 additions & 11 deletions common/src/market/impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,19 @@ use near_sdk::{
};

use crate::{
asset::BorrowAssetAmount,
asset::{BorrowAssetAmount, CollateralAssetAmount},
asset_op,
borrow::{BorrowPosition, BorrowPositionGuard, BorrowPositionRef},
chunked_append_only_list::ChunkedAppendOnlyList,
event::MarketEvent,
market::MarketConfiguration,
market::{MarketConfiguration, WithdrawalResolution},
number::Decimal,
snapshot::Snapshot,
static_yield::StaticYieldRecord,
supply::{SupplyPosition, SupplyPositionGuard, SupplyPositionRef},
withdrawal_queue::{error::WithdrawalQueueLockError, WithdrawalQueue},
};

use super::WithdrawalResolution;

#[derive(BorshStorageKey)]
#[near]
enum StorageKey {
Expand All @@ -35,10 +33,20 @@ enum StorageKey {
pub struct Market {
prefix: Vec<u8>,
pub configuration: MarketConfiguration,
/// Total amount of borrow asset earning interest in the market.
pub borrow_asset_deposited_active: BorrowAssetAmount,
/// Mapping of upcoming snapshot indices to amounts of borrow asset that will be activated.
pub borrow_asset_deposited_incoming: HashMap<u32, BorrowAssetAmount>,
/// Sending borrow asset out, because if somebody sends the contract borrow asset, it's ok for the
/// contract to attempt to fulfill withdrawal request, even if the market thinks it doesn't have
/// enough to fulfill.
pub borrow_asset_in_flight: BorrowAssetAmount,
/// Amount of borrow asset that has been withdrawn (is in use by) by borrowers.
///
/// `borrow_asset_deposited_active - borrow_asset_borrowed >= 0` should always be true.
pub borrow_asset_borrowed: BorrowAssetAmount,
/// Market-wide collateral asset deposit tracking.
pub collateral_asset_deposited: CollateralAssetAmount,
pub(crate) supply_positions: UnorderedMap<AccountId, SupplyPosition>,
pub(crate) borrow_positions: UnorderedMap<AccountId, BorrowPosition>,
pub current_snapshot: Snapshot,
Expand Down Expand Up @@ -66,7 +74,7 @@ impl Market {

let first_snapshot = Snapshot::new(configuration.time_chunk_configuration.previous());
let mut current_snapshot = first_snapshot.clone();
current_snapshot.time_chunk = configuration.time_chunk_configuration.now();
current_snapshot.set_time_chunk(configuration.time_chunk_configuration.now());

let mut self_ = Self {
prefix: prefix.clone(),
Expand All @@ -75,6 +83,7 @@ impl Market {
borrow_asset_deposited_incoming: HashMap::new(),
borrow_asset_in_flight: 0.into(),
borrow_asset_borrowed: 0.into(),
collateral_asset_deposited: 0.into(),
supply_positions: UnorderedMap::new(key!(SupplyPositions)),
borrow_positions: UnorderedMap::new(key!(BorrowPositions)),
current_snapshot,
Expand Down Expand Up @@ -117,13 +126,16 @@ impl Market {
self.current_snapshot.update_active(
self.borrow_asset_deposited_active,
self.borrow_asset_borrowed,
self.collateral_asset_deposited,
&self.configuration.borrow_interest_rate_strategy,
);
self.current_snapshot.add_yield(yield_distribution);
self.current_snapshot.deposited_incoming = *self
.borrow_asset_deposited_incoming
.get(&self.finalized_snapshots.len())
.unwrap_or(&0.into());
self.current_snapshot.set_borrow_asset_deposited_incoming(
*self
.borrow_asset_deposited_incoming
.get(&self.finalized_snapshots.len())
.unwrap_or(&0.into()),
);
} else {
// Otherwise, finalize the current snapshot and create a new one.
let deposited_incoming = self
Expand All @@ -132,11 +144,12 @@ impl Market {
.unwrap_or(0.into());
asset_op!(self.borrow_asset_deposited_active += deposited_incoming);
let mut snapshot = Snapshot::new(time_chunk);
snapshot.yield_distribution = yield_distribution;
snapshot.deposited_incoming = deposited_incoming;
snapshot.set_yield_distribution(yield_distribution);
snapshot.set_borrow_asset_deposited_incoming(deposited_incoming);
snapshot.update_active(
self.borrow_asset_deposited_active,
self.borrow_asset_borrowed,
self.collateral_asset_deposited,
&self.configuration.borrow_interest_rate_strategy,
);
std::mem::swap(&mut snapshot, &mut self.current_snapshot);
Expand Down
86 changes: 63 additions & 23 deletions common/src/snapshot.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,35 @@
use near_sdk::{env, json_types::U64, near};

use crate::{
asset::BorrowAssetAmount, asset_op, interest_rate_strategy::InterestRateStrategy,
number::Decimal, time_chunk::TimeChunk,
asset::{BorrowAssetAmount, CollateralAssetAmount},
asset_op,
interest_rate_strategy::InterestRateStrategy,
number::Decimal,
time_chunk::TimeChunk,
};

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[near(serializers = [borsh, json])]
pub struct Snapshot {
pub time_chunk: TimeChunk,
pub end_timestamp_ms: U64,
deposited_active: BorrowAssetAmount,
pub deposited_incoming: BorrowAssetAmount,
borrowed: BorrowAssetAmount,
pub yield_distribution: BorrowAssetAmount,
pub(crate) time_chunk: TimeChunk,
pub(crate) end_timestamp_ms: U64,
pub(crate) borrow_asset_deposited_active: BorrowAssetAmount,
borrow_asset_deposited_incoming: BorrowAssetAmount,
borrow_asset_borrowed: BorrowAssetAmount,
collateral_asset_deposited: CollateralAssetAmount,
yield_distribution: BorrowAssetAmount,
interest_rate: Decimal,
}

impl Snapshot {
pub fn new(time_chunk: TimeChunk) -> Self {
Self {
time_chunk,
end_timestamp_ms: near_sdk::env::block_timestamp_ms().into(),
deposited_active: 0.into(),
deposited_incoming: 0.into(),
borrowed: 0.into(),
end_timestamp_ms: env::block_timestamp_ms().into(),
borrow_asset_deposited_active: 0.into(),
borrow_asset_deposited_incoming: 0.into(),
borrow_asset_borrowed: 0.into(),
collateral_asset_deposited: 0.into(),
yield_distribution: BorrowAssetAmount::zero(),
interest_rate: Decimal::ZERO,
}
Expand All @@ -36,35 +41,70 @@ impl Snapshot {

pub fn update_active(
&mut self,
deposited_active: BorrowAssetAmount,
borrowed: BorrowAssetAmount,
borrow_asset_deposited_active: BorrowAssetAmount,
borrow_asset_borrowed: BorrowAssetAmount,
collateral_asset_deposited: CollateralAssetAmount,
interest_rate_strategy: &InterestRateStrategy,
) {
self.end_timestamp_ms = env::block_timestamp_ms().into();
self.deposited_active = deposited_active;
self.borrowed = borrowed;
self.borrow_asset_deposited_active = borrow_asset_deposited_active;
self.borrow_asset_borrowed = borrow_asset_borrowed;
self.collateral_asset_deposited = collateral_asset_deposited;
self.interest_rate = interest_rate_strategy.at(self.usage_ratio());
}

pub fn usage_ratio(&self) -> Decimal {
if self.deposited_active.is_zero() || self.borrowed.is_zero() {
if self.borrow_asset_deposited_active.is_zero() || self.borrow_asset_borrowed.is_zero() {
Decimal::ZERO
} else if self.borrowed >= self.deposited_active {
} else if self.borrow_asset_borrowed >= self.borrow_asset_deposited_active {
Decimal::ONE
} else {
Decimal::from(self.borrowed) / Decimal::from(self.deposited_active)
Decimal::from(self.borrow_asset_borrowed)
/ Decimal::from(self.borrow_asset_deposited_active)
}
}

pub fn set_time_chunk(&mut self, time_chunk: TimeChunk) {
self.time_chunk = time_chunk;
}

pub fn set_borrow_asset_deposited_incoming(&mut self, amount: BorrowAssetAmount) {
self.borrow_asset_deposited_incoming = amount;
}

pub fn set_yield_distribution(&mut self, amount: BorrowAssetAmount) {
self.yield_distribution = amount;
}

pub fn time_chunk(&self) -> &TimeChunk {
&self.time_chunk
}

pub fn end_timestamp_ms(&self) -> U64 {
self.end_timestamp_ms
}

pub fn borrow_asset_deposited_incoming(&self) -> BorrowAssetAmount {
self.borrow_asset_deposited_incoming
}

pub fn collateral_asset_deposited(&self) -> CollateralAssetAmount {
self.collateral_asset_deposited
}

pub fn yield_distribution(&self) -> BorrowAssetAmount {
self.yield_distribution
}

pub fn interest_rate(&self) -> Decimal {
self.interest_rate
}

pub fn deposited_active(&self) -> BorrowAssetAmount {
self.deposited_active
pub fn borrow_asset_deposited_active(&self) -> BorrowAssetAmount {
self.borrow_asset_deposited_active
}

pub fn borrowed(&self) -> BorrowAssetAmount {
self.borrowed
pub fn borrow_asset_borrowed(&self) -> BorrowAssetAmount {
self.borrow_asset_borrowed
}
}
6 changes: 3 additions & 3 deletions common/src/supply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,9 @@ impl<M: Deref<Target = Market>> SupplyPositionRef<M> {
amount += u128::from(incoming.amount);
}

if !snapshot.deposited_active().is_zero() {
accumulated += amount * Decimal::from(snapshot.yield_distribution)
/ Decimal::from(snapshot.deposited_active());
if !snapshot.borrow_asset_deposited_active.is_zero() {
accumulated += amount * Decimal::from(snapshot.yield_distribution())
/ Decimal::from(snapshot.borrow_asset_deposited_active);
}

next_snapshot_index = i as u32 + 1;
Expand Down
4 changes: 2 additions & 2 deletions contract/market/src/impl_market_external.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,11 +292,11 @@ impl MarketExternalInterface for Contract {
}

fn get_last_yield_rate(&self) -> Decimal {
let deposited: Decimal = self.current_snapshot.deposited_active().into();
let deposited: Decimal = self.current_snapshot.borrow_asset_deposited_active().into();
if deposited.is_zero() {
return Decimal::ZERO;
}
let borrowed: Decimal = self.current_snapshot.borrowed().into();
let borrowed: Decimal = self.current_snapshot.borrow_asset_borrowed().into();
let supply_weight: Decimal = self.configuration.yield_weights.supply.get().into();
let total_weight: Decimal = self.configuration.yield_weights.total_weight().get().into();

Expand Down
6 changes: 3 additions & 3 deletions contract/market/tests/happy_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ async fn test_happy(#[case] borrow_mt: bool, #[case] collateral_mt: bool) {

let snapshots = c.list_finalized_snapshots(None, None).await;
assert_eq!(snapshots.len(), 1);
assert!(snapshots[0].yield_distribution.is_zero());
assert!(snapshots[0].deposited_active().is_zero());
assert!(snapshots[0].borrowed().is_zero());
assert!(snapshots[0].yield_distribution().is_zero());
assert!(snapshots[0].borrow_asset_deposited_active().is_zero());
assert!(snapshots[0].borrow_asset_borrowed().is_zero());

// Step 1: Supply user sends tokens to contract to use for borrows.
c.supply(&supply_user, 1100).await;
Expand Down
Loading
Loading