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

Draft: eMode draft impl (WIP) #26

Open
wants to merge 9 commits into
base: devel
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 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 contracts/sources/cell.move
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ module suilend::cell {
public fun get<Element>(cell: &Cell<Element>): &Element {
option::borrow(&cell.element)
}

public fun get_mut<Element>(cell: &mut Cell<Element>): &mut Element {
option::borrow_mut(&mut cell.element)
}

public fun destroy<Element>(cell: Cell<Element>): Element {
let Cell { element } = cell;
Expand Down
17 changes: 17 additions & 0 deletions contracts/sources/lending_market.move
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,23 @@ module suilend::lending_market {
reserve::update_reserve_config<P>(reserve, config);
}

// TODO:Consider taking EModeConfig as param..
public fun set_emode_for_pair<P, T>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think it makes sense to get the type argument for the pair reserve as well, just as a sanity check.

_: &LendingMarketOwnerCap<P>,
lending_market: &mut LendingMarket<P>,
reserve_array_index: u64,
pair_reserve_array_index: u64,
open_ltv_pct: u8,
close_ltv_pct: u8,
) {
assert!(lending_market.version == CURRENT_VERSION, EIncorrectVersion);

let reserve = vector::borrow_mut(&mut lending_market.reserves, reserve_array_index);
assert!(reserve::coin_type(reserve) == type_name::get<T>(), EWrongType);

reserve::set_emode_for_pair<P>(reserve, pair_reserve_array_index, open_ltv_pct, close_ltv_pct);
}

public fun add_pool_reward<P, RewardType>(
_: &LendingMarketOwnerCap<P>,
lending_market: &mut LendingMarket<P>,
Expand Down
61 changes: 46 additions & 15 deletions contracts/sources/obligation.move
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@ module suilend::obligation {
use sui::object::{Self, UID, ID};
use sui::balance::{Balance};
use std::vector::{Self};
use sui::vec_map::{Self};
use sui::dynamic_field::{Self as df};
use sui::event::{Self};
use sui::tx_context::{TxContext};
use suilend::reserve::{Self, Reserve, config};
use suilend::reserve_config::{
open_ltv,
open_ltv,
close_ltv,
borrow_weight,
liquidation_bonus,
protocol_liquidation_fee,
isolated,
open_ltv_emode,
close_ltv_emode,
};
use sui::clock::{Clock};
use suilend::decimal::{Self, Decimal, mul, add, sub, div, gt, lt, min, floor, le, eq, saturating_sub};
Expand Down Expand Up @@ -45,6 +47,8 @@ module suilend::obligation {
const MAX_DEPOSITS: u64 = 5;
const MAX_BORROWS: u64 = 5;

struct EModeFlag has store, copy, drop {}

// === Structs ===
struct Obligation<phantom P> has key, store {
id: UID,
Expand Down Expand Up @@ -167,6 +171,9 @@ module suilend::obligation {
}
}

fun is_emode<P>(obligation: &Obligation<P>): bool {
df::exists_(&obligation.id, EModeFlag {})
}

/// update the obligation's borrowed amounts and health values. this is
/// called by the lending market prior to any borrow, withdraw, or liquidate operation.
Expand All @@ -179,6 +186,7 @@ module suilend::obligation {
let deposited_value_usd = decimal::from(0);
let allowed_borrow_value_usd = decimal::from(0);
let unhealthy_borrow_value_usd = decimal::from(0);
let is_emode = is_emode(obligation);

while (i < vector::length(&obligation.deposits)) {
let deposit = vector::borrow_mut(&mut obligation.deposits, i);
Expand All @@ -199,19 +207,35 @@ module suilend::obligation {

deposit.market_value = market_value;
deposited_value_usd = add(deposited_value_usd, market_value);

let (open_ltv, close_ltv) = if (is_emode) {
// There is only one borrow in such circunstance, hence the indexing to 0
let borrow_reserve_array_index = vector::borrow(&obligation.borrows, 0).reserve_array_index;

let emode_data = reserve_config::get_emode_ltvs(
config(deposit_reserve),
&borrow_reserve_array_index
);

(open_ltv_emode(emode_data), close_ltv_emode(emode_data))
} else {
(open_ltv(config(deposit_reserve)), close_ltv(config(deposit_reserve)))
};

allowed_borrow_value_usd = add(
allowed_borrow_value_usd,
mul(
market_value_lower_bound,
open_ltv(config(deposit_reserve))
)
open_ltv,
),
);

unhealthy_borrow_value_usd = add(
unhealthy_borrow_value_usd,
mul(
market_value,
close_ltv(config(deposit_reserve))
)
close_ltv,
),
);

i = i + 1;
Expand All @@ -221,6 +245,7 @@ module suilend::obligation {
obligation.allowed_borrow_value_usd = allowed_borrow_value_usd;
obligation.unhealthy_borrow_value_usd = unhealthy_borrow_value_usd;


let i = 0;
let unweighted_borrowed_value_usd = decimal::from(0);
let weighted_borrowed_value_usd = decimal::from(0);
Expand All @@ -240,23 +265,29 @@ module suilend::obligation {
let market_value_upper_bound = reserve::market_value_upper_bound(
borrow_reserve,
borrow.borrowed_amount
);
);

borrow.market_value = market_value;
unweighted_borrowed_value_usd = add(unweighted_borrowed_value_usd, market_value);

Copy link
Contributor

@0xripleys 0xripleys Oct 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

undo everything below here in this fn. this is purely formatting change, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the formatting stuff

let borrow_weighted_value_usd = mul(
market_value,
borrow_weight(config(borrow_reserve))
);

weighted_borrowed_value_usd = add(
weighted_borrowed_value_usd,
mul(
market_value,
borrow_weight(config(borrow_reserve))
)
borrow_weighted_value_usd
);

let borrow_weighted_value_upper_bound_usd = mul(
market_value_upper_bound,
borrow_weight(config(borrow_reserve))
);

weighted_borrowed_value_upper_bound_usd = add(
weighted_borrowed_value_upper_bound_usd,
mul(
market_value_upper_bound,
borrow_weight(config(borrow_reserve))
)
borrow_weighted_value_upper_bound_usd,
);

if (isolated(config(borrow_reserve))) {
Expand Down
16 changes: 16 additions & 0 deletions contracts/sources/reserve.move
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,22 @@ module suilend::reserve {
reserve_config::destroy(old);
}

public(friend) fun set_emode_for_pair<P>(
reserve: &mut Reserve<P>,
reserve_array_index: u64,
open_ltv_pct: u8,
close_ltv_pct: u8,
) {
let config = cell::get_mut(&mut reserve.config);

reserve_config::set_emode_for_pair(
config,
reserve_array_index,
open_ltv_pct,
close_ltv_pct,
);
}

public(friend) fun update_price<P>(
reserve: &mut Reserve<P>,
clock: &Clock,
Expand Down
101 changes: 101 additions & 0 deletions contracts/sources/reserve_config.move
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@ module suilend::reserve_config {
use suilend::decimal::{Decimal, Self, add, sub, mul, div, ge, le};
use sui::tx_context::{TxContext};
use sui::bag::{Self, Bag};
use sui::vec_map::{Self, VecMap};

friend suilend::reserve;
friend suilend::obligation;

#[test_only]
use sui::test_scenario::{Self};

const EInvalidReserveConfig: u64 = 0;
const EInvalidUtil: u64 = 1;

struct EModeKey has copy, store, drop {}

struct ReserveConfig has store {
// risk params
open_ltv_pct: u8,
Expand Down Expand Up @@ -57,6 +63,19 @@ module suilend::reserve_config {
fields: Bag
}

// struct EmodeConfig has store {
// // Corresponding to the deposited coin type
// reserve_array_indices: vector<u64>,
// emode_pairs: vector<EModeData>
// }

struct EModeData has store, copy, drop {
// Corresponding to the correlated pair
reserve_array_index: u64,
open_ltv_pct: u8,
close_ltv_pct: u8,
}

public fun create_reserve_config(
open_ltv_pct: u8,
close_ltv_pct: u8,
Expand Down Expand Up @@ -267,6 +286,15 @@ module suilend::reserve_config {
additional_fields
} = config;

let has_emode_field = bag::contains(&additional_fields, EModeKey {});

if (has_emode_field) {
let _emode_config: VecMap<u64, EModeData> = bag::remove(
&mut additional_fields,
EModeKey {},
);
};

bag::destroy_empty(additional_fields);
}

Expand Down Expand Up @@ -406,6 +434,79 @@ module suilend::reserve_config {
}


// === eMode Package Functions ==

public(friend) fun set_emode_for_pair(
reserve_config: &mut ReserveConfig,
reserve_array_index: u64,
open_ltv_pct: u8,
close_ltv_pct: u8,
) {
let has_emode_field = bag::contains(&reserve_config.additional_fields, EModeKey {});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use helper function


if (!has_emode_field) {
bag::add(
&mut reserve_config.additional_fields,
EModeKey {},
vec_map::empty<u64, EModeData>(),
)
};

let emode_config: &mut VecMap<u64, EModeData> = bag::borrow_mut(&mut reserve_config.additional_fields, EModeKey {});

// Check if there is already emode parameters for the reserve_array_index
let has_pair = vec_map::contains(emode_config, &reserve_array_index);

if (!has_pair) {
vec_map::insert(emode_config, reserve_array_index, EModeData {
reserve_array_index,
open_ltv_pct,
close_ltv_pct,
});
} else {
let emode_data = vec_map::get_mut(emode_config, &reserve_array_index);

emode_data.open_ltv_pct = open_ltv_pct;
emode_data.close_ltv_pct = close_ltv_pct;
};
}

public(friend) fun get_emode_config(
reserve_config: &ReserveConfig,
): &VecMap<u64, EModeData> {
bag::borrow(&reserve_config.additional_fields, EModeKey {})
}

public(friend) fun has_emode_config(
reserve_config: &ReserveConfig,
): bool {
bag::contains(&reserve_config.additional_fields, EModeKey {})
}

public(friend) fun open_ltv_emode(
emode_data: &EModeData,
): Decimal {
decimal::from_percent(emode_data.open_ltv_pct)
}

public(friend) fun close_ltv_emode(
emode_data: &EModeData,
): Decimal {
decimal::from_percent(emode_data.open_ltv_pct)
}

public(friend) fun get_emode_ltvs(
reserve_config: &ReserveConfig,
reserve_array_index: &u64,
): &EModeData {
let emode_config = get_emode_config(reserve_config);
let has_pair = vec_map::contains(emode_config, reserve_array_index);

assert!(has_pair, 0);

vec_map::get(emode_config, reserve_array_index)
}

// === Tests ==
#[test]
fun test_calculate_apr() {
Expand Down
Loading