Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No refresh on some withdraws #51

Merged
merged 2 commits into from
Feb 6, 2025
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
17 changes: 12 additions & 5 deletions contracts/suilend/sources/lending_market.move
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,9 @@ module suilend::lending_market {
&mut lending_market.obligations,
obligation_owner_cap.obligation_id,
);
obligation::refresh<P>(obligation, &mut lending_market.reserves, clock);

let exist_stale_oracles = obligation::refresh<P>(obligation, &mut lending_market.reserves, clock);
obligation::assert_no_stale_oracles(exist_stale_oracles);

let reserve = vector::borrow_mut(&mut lending_market.reserves, reserve_array_index);
assert!(reserve::coin_type(reserve) == type_name::get<T>(), EWrongType);
Expand Down Expand Up @@ -478,7 +480,8 @@ module suilend::lending_market {
&mut lending_market.obligations,
obligation_owner_cap.obligation_id,
);
obligation::refresh<P>(obligation, &mut lending_market.reserves, clock);

let exist_stale_oracles = obligation::refresh<P>(obligation, &mut lending_market.reserves, clock);

let reserve = vector::borrow_mut(&mut lending_market.reserves, reserve_array_index);
assert!(reserve::coin_type(reserve) == type_name::get<T>(), EWrongType);
Expand All @@ -488,7 +491,7 @@ module suilend::lending_market {
max_withdraw_amount<P>(lending_market.rate_limiter, obligation, reserve, clock);
};

obligation::withdraw<P>(obligation, reserve, clock, amount);
obligation::withdraw<P>(obligation, reserve, clock, amount, exist_stale_oracles);

event::emit(WithdrawEvent {
lending_market_id,
Expand Down Expand Up @@ -522,7 +525,9 @@ module suilend::lending_market {
&mut lending_market.obligations,
obligation_id,
);
obligation::refresh<P>(obligation, &mut lending_market.reserves, clock);

let exist_stale_oracles = obligation::refresh<P>(obligation, &mut lending_market.reserves, clock);
obligation::assert_no_stale_oracles(exist_stale_oracles);

let (withdraw_ctoken_amount, required_repay_amount) = obligation::liquidate<P>(
obligation,
Expand Down Expand Up @@ -644,7 +649,9 @@ module suilend::lending_market {
&mut lending_market.obligations,
obligation_id,
);
obligation::refresh<P>(obligation, &mut lending_market.reserves, clock);

let exist_stale_oracles = obligation::refresh<P>(obligation, &mut lending_market.reserves, clock);
obligation::assert_no_stale_oracles(exist_stale_oracles);

let reserve = vector::borrow_mut(&mut lending_market.reserves, reserve_array_index);
assert!(reserve::coin_type(reserve) == type_name::get<T>(), EWrongType);
Expand Down
35 changes: 32 additions & 3 deletions contracts/suilend/sources/obligation.move
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ module suilend::obligation {
const ETooManyBorrows: u64 = 6;
const EObligationIsNotForgivable: u64 = 7;
const ECannotDepositAndBorrowSameAsset: u64 = 8;
const EOraclesAreStale: u64 = 9;

// === Constants ===
const CLOSE_FACTOR_PCT: u8 = 20;
Expand Down Expand Up @@ -100,6 +101,9 @@ module suilend::obligation {
user_reward_manager_index: u64,
}

// hot potato. used by obligation::refresh to indicate that prices are stale.
public struct ExistStaleOracles {}

// === Events ===
public struct ObligationDataEvent has copy, drop {
lending_market_id: address,
Expand Down Expand Up @@ -167,7 +171,9 @@ module suilend::obligation {
obligation: &mut Obligation<P>,
reserves: &mut vector<Reserve<P>>,
clock: &Clock,
) {
): Option<ExistStaleOracles> {
let mut exist_stale_oracles = false;

let mut i = 0;
let mut deposited_value_usd = decimal::from(0);
let mut allowed_borrow_value_usd = decimal::from(0);
Expand All @@ -179,7 +185,10 @@ module suilend::obligation {
let deposit_reserve = vector::borrow_mut(reserves, deposit.reserve_array_index);

reserve::compound_interest(deposit_reserve, clock);
reserve::assert_price_is_fresh(deposit_reserve, clock);

if (!reserve::is_price_fresh(deposit_reserve, clock)) {
exist_stale_oracles = true;
};

let market_value = reserve::ctoken_market_value(
deposit_reserve,
Expand Down Expand Up @@ -227,7 +236,9 @@ module suilend::obligation {

let borrow_reserve = vector::borrow_mut(reserves, borrow.reserve_array_index);
reserve::compound_interest(borrow_reserve, clock);
reserve::assert_price_is_fresh(borrow_reserve, clock);
if (!reserve::is_price_fresh(borrow_reserve, clock)) {
exist_stale_oracles = true;
};

compound_debt(borrow, borrow_reserve);

Expand Down Expand Up @@ -269,6 +280,12 @@ module suilend::obligation {
weighted_borrowed_value_upper_bound_usd;

obligation.borrowing_isolated_asset = borrowing_isolated_asset;

if (exist_stale_oracles) {
return option::some(ExistStaleOracles {})
};

option::none()
}

/// Process a deposit action
Expand Down Expand Up @@ -492,7 +509,14 @@ module suilend::obligation {
reserve: &mut Reserve<P>,
clock: &Clock,
ctoken_amount: u64,
stale_oracles: Option<ExistStaleOracles>,
) {
if (stale_oracles.is_some() && vector::is_empty(&obligation.borrows)) {
let ExistStaleOracles {} = option::destroy_some(stale_oracles);
} else {
assert_no_stale_oracles(stale_oracles);
};

withdraw_unchecked(obligation, reserve, clock, ctoken_amount);

assert!(is_healthy(obligation), EObligationIsNotHealthy);
Expand Down Expand Up @@ -834,6 +858,11 @@ module suilend::obligation {
)
}

public(package) fun assert_no_stale_oracles(exist_stale_oracles: Option<ExistStaleOracles>) {
assert!(option::is_none(&exist_stale_oracles), EOraclesAreStale);
option::destroy_none(exist_stale_oracles);
}

public(package) fun zero_out_rewards_if_looped<P>(
obligation: &mut Obligation<P>,
reserves: &mut vector<Reserve<P>>,
Expand Down
10 changes: 6 additions & 4 deletions contracts/suilend/sources/reserve.move
Original file line number Diff line number Diff line change
Expand Up @@ -236,11 +236,13 @@ module suilend::reserve {

// make sure we are using the latest published price on sui
public fun assert_price_is_fresh<P>(reserve: &Reserve<P>, clock: &Clock) {
assert!(is_price_fresh(reserve, clock), EPriceStale);
}

public(package) fun is_price_fresh<P>(reserve: &Reserve<P>, clock: &Clock): bool {
let cur_time_s = clock::timestamp_ms(clock) / 1000;
assert!(
cur_time_s - reserve.price_last_update_timestamp_s <= PRICE_STALENESS_THRESHOLD_S,
EPriceStale
);

cur_time_s - reserve.price_last_update_timestamp_s <= PRICE_STALENESS_THRESHOLD_S
}

// if SUI = $1, this returns decimal::from(1).
Expand Down
Loading