-
Notifications
You must be signed in to change notification settings - Fork 1
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
base: devel
Are you sure you want to change the base?
Changes from 4 commits
0c5ac21
354f05d
ef586b5
a5430d4
1aed49b
77bd53f
5cd2ea0
9692726
f30f544
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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}; | ||
|
@@ -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, | ||
|
@@ -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. | ||
|
@@ -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); | ||
|
@@ -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; | ||
|
@@ -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); | ||
|
@@ -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); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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))) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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, | ||
|
@@ -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, | ||
|
@@ -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); | ||
} | ||
|
||
|
@@ -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 {}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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() { | ||
|
There was a problem hiding this comment.
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.