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
83 changes: 58 additions & 25 deletions packages/margin_trading/sources/margin_manager.move
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ public fun withdraw<BaseAsset, QuoteAsset, WithdrawAsset>(
);

if (self.margin_pool_id.contains(&base_margin_pool.id())) {
let risk_ratio = self.risk_ratio(
let risk_ratio = self.risk_ratio_int(
registry,
base_oracle,
quote_oracle,
Expand All @@ -225,7 +225,7 @@ public fun withdraw<BaseAsset, QuoteAsset, WithdrawAsset>(
);
assert!(registry.can_withdraw(pool.id(), risk_ratio), EWithdrawRiskRatioExceeded);
} else if (self.margin_pool_id.contains(&quote_margin_pool.id())) {
let risk_ratio = self.risk_ratio(
let risk_ratio = self.risk_ratio_int(
registry,
base_oracle,
quote_oracle,
Expand Down Expand Up @@ -262,7 +262,7 @@ public fun borrow_base<BaseAsset, QuoteAsset>(
self.borrowed_base_shares = total_shares;
self.margin_pool_id = option::some(base_margin_pool.id());
self.deposit(registry, coin, ctx);
let risk_ratio = self.risk_ratio(
let risk_ratio = self.risk_ratio_int(
registry,
base_oracle,
quote_oracle,
Expand Down Expand Up @@ -305,7 +305,7 @@ public fun borrow_quote<BaseAsset, QuoteAsset>(
self.borrowed_quote_shares = total_shares;
self.margin_pool_id = option::some(quote_margin_pool.id());
self.deposit(registry, coin, ctx);
let risk_ratio = self.risk_ratio(
let risk_ratio = self.risk_ratio_int(
registry,
base_oracle,
quote_oracle,
Expand Down Expand Up @@ -384,7 +384,7 @@ public fun liquidate<BaseAsset, QuoteAsset, DebtAsset>(
// 1. Check that we can liquidate, cancel all open orders.
assert!(self.deepbook_pool == pool.id(), EIncorrectDeepBookPool);
assert!(self.margin_pool_id.contains(&margin_pool.id()), EIncorrectMarginPool);
let risk_ratio = self.risk_ratio(
let risk_ratio = self.risk_ratio_int(
registry,
base_oracle,
quote_oracle,
Expand Down Expand Up @@ -519,34 +519,36 @@ public fun liquidate<BaseAsset, QuoteAsset, DebtAsset>(
(base_coin, quote_coin, repay_coin)
}

// Get the risk ratio of the margin manager.
public fun risk_ratio<BaseAsset, QuoteAsset, DebtAsset>(
// Returns the risk ratio of the margin manager given the corresponding margin pools.
public fun risk_ratio<BaseAsset, QuoteAsset>(
self: &MarginManager<BaseAsset, QuoteAsset>,
registry: &MarginRegistry,
base_oracle: &PriceInfoObject,
quote_oracle: &PriceInfoObject,
pool: &Pool<BaseAsset, QuoteAsset>,
margin_pool: &MarginPool<DebtAsset>,
base_margin_pool: &MarginPool<BaseAsset>,
quote_margin_pool: &MarginPool<QuoteAsset>,
clock: &Clock,
): u64 {
assert!(
self.margin_pool_id.contains(&margin_pool.id()) || self.margin_pool_id.is_none(),
EIncorrectMarginPool,
);
let (assets_in_debt_unit, _, _) = self.assets_in_debt_unit(
registry,
pool,
base_oracle,
quote_oracle,
clock,
);
let borrowed_shares = self.borrowed_base_shares.max(self.borrowed_quote_shares);
let debt = margin_pool.borrow_shares_to_amount(borrowed_shares, clock);
let max_risk_ratio = margin_constants::max_risk_ratio();
if (assets_in_debt_unit > math::mul(debt, max_risk_ratio)) {
max_risk_ratio
let debt_is_base = self.borrowed_base_shares > 0;
if (debt_is_base) {
self.risk_ratio_int(
registry,
base_oracle,
quote_oracle,
pool,
base_margin_pool,
clock,
)
} else {
math::div(assets_in_debt_unit, debt)
self.risk_ratio_int(
registry,
base_oracle,
quote_oracle,
pool,
quote_margin_pool,
clock,
)
}
}

Expand Down Expand Up @@ -632,6 +634,37 @@ public(package) fun id<BaseAsset, QuoteAsset>(self: &MarginManager<BaseAsset, Qu
}

// === Private Functions ===
// Get the risk ratio of the margin manager.
fun risk_ratio_int<BaseAsset, QuoteAsset, DebtAsset>(
self: &MarginManager<BaseAsset, QuoteAsset>,
registry: &MarginRegistry,
base_oracle: &PriceInfoObject,
quote_oracle: &PriceInfoObject,
pool: &Pool<BaseAsset, QuoteAsset>,
margin_pool: &MarginPool<DebtAsset>,
clock: &Clock,
): u64 {
assert!(
self.margin_pool_id.contains(&margin_pool.id()) || self.margin_pool_id.is_none(),
EIncorrectMarginPool,
);
let (assets_in_debt_unit, _, _) = self.assets_in_debt_unit(
registry,
pool,
base_oracle,
quote_oracle,
clock,
);
let borrowed_shares = self.borrowed_base_shares.max(self.borrowed_quote_shares);
let debt = margin_pool.borrow_shares_to_amount(borrowed_shares, clock);
let max_risk_ratio = margin_constants::max_risk_ratio();
if (assets_in_debt_unit > math::mul(debt, max_risk_ratio)) {
max_risk_ratio
} else {
math::div(assets_in_debt_unit, debt)
}
}

fun new_margin_manager<BaseAsset, QuoteAsset>(
pool: &Pool<BaseAsset, QuoteAsset>,
registry: &MarginRegistry,
Expand Down
8 changes: 4 additions & 4 deletions packages/margin_trading/sources/margin_pool/margin_state.move
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,10 @@ public(package) fun borrow_shares_to_amount(
let ratio = if (self.borrow_shares == 0) {
constants::float_scaling()
} else {
math::div(self.borrow_shares, borrow)
math::div(borrow, self.borrow_shares)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

There's no actual change, just making ratio consistent

};

math::div(shares, ratio)
math::mul(shares, ratio)
}

public(package) fun supply_shares_to_amount(
Expand All @@ -146,10 +146,10 @@ public(package) fun supply_shares_to_amount(
let ratio = if (self.supply_shares == 0) {
constants::float_scaling()
} else {
math::div(self.supply_shares, supply)
math::div(supply, self.supply_shares)
};

math::div(shares, ratio)
math::mul(shares, ratio)
}

fun update(self: &mut State, config: &ProtocolConfig, clock: &Clock): u64 {
Expand Down
37 changes: 21 additions & 16 deletions packages/margin_trading/tests/margin_manager_math_tests.move
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use margin_trading::{
return_shared_3
}
};
use sui::test_utils::destroy;
use sui::{test_scenario::return_shared, test_utils::destroy};

const ENoError: u64 = 0;
const ECannotLiquidate: u64 = 1;
Expand Down Expand Up @@ -79,7 +79,7 @@ fun test_liquidation(error_code: u64) {
clock,
admin_cap,
maintainer_cap,
_btc_pool_id,
btc_pool_id,
usdc_pool_id,
_pool_id,
) = setup_btc_usd_margin_trading();
Expand All @@ -95,6 +95,7 @@ fun test_liquidation(error_code: u64) {
scenario.next_tx(test_constants::user1());
let mut mm = scenario.take_shared<MarginManager<BTC, USDC>>();
let mut usdc_pool = scenario.take_shared_by_id<MarginPool<USDC>>(usdc_pool_id);
let btc_pool = scenario.take_shared_by_id<MarginPool<BTC>>(btc_pool_id);

// Deposit 1 BTC worth $50
mm.deposit<BTC, USDC, BTC>(
Expand All @@ -116,7 +117,7 @@ fun test_liquidation(error_code: u64) {
);

assert!(
mm.risk_ratio(&registry, &btc_price, &usdc_price, &pool, &usdc_pool, &clock) == 1_250_000_000,
mm.risk_ratio(&registry, &btc_price, &usdc_price, &pool, &btc_pool,&usdc_pool, &clock) == 1_250_000_000,
0,
);

Expand All @@ -128,7 +129,7 @@ fun test_liquidation(error_code: u64) {
let repay_coin = mint_coin<USDC>(500 * test_constants::usdc_multiplier(), scenario.ctx());
let btc_price_40 = build_btc_price_info_object(&mut scenario, 40, &clock);
assert!(
mm.risk_ratio(&registry, &btc_price_40, &usdc_price, &pool, &usdc_pool, &clock) == 1_200_000_000,
mm.risk_ratio(&registry, &btc_price_40, &usdc_price, &pool, &btc_pool, &usdc_pool, &clock) == 1_200_000_000,
0,
);

Expand All @@ -149,7 +150,7 @@ fun test_liquidation(error_code: u64) {
let repay_coin = mint_coin<USDC>(500 * test_constants::usdc_multiplier(), scenario.ctx());
let btc_price_18 = build_btc_price_info_object(&mut scenario, 18, &clock);
assert!(
mm.risk_ratio(&registry, &btc_price_18, &usdc_price, &pool, &usdc_pool, &clock) == 1_090_000_000,
mm.risk_ratio(&registry, &btc_price_18, &usdc_price, &pool, &btc_pool, &usdc_pool, &clock) == 1_090_000_000,
0,
);

Expand All @@ -176,6 +177,7 @@ fun test_liquidation(error_code: u64) {

destroy_3!(remaining_repay_coin, base_coin, quote_coin);
return_shared_3!(mm, usdc_pool, pool);
return_shared(btc_pool);
destroy_3!(btc_price, usdc_price, btc_price_18);
cleanup_margin_test(registry, admin_cap, maintainer_cap, clock, scenario);
}
Expand Down Expand Up @@ -224,7 +226,7 @@ fun test_liquidation_quote_debt(error_code: u64) {
);

assert!(
mm.risk_ratio(&registry, &btc_price, &usdc_price, &pool, &usdc_pool, &clock) == 3_500_000_000,
mm.risk_ratio(&registry, &btc_price, &usdc_price, &pool, &btc_pool, &usdc_pool, &clock) == 3_500_000_000,
0,
);

Expand All @@ -244,7 +246,7 @@ fun test_liquidation_quote_debt(error_code: u64) {

// Risk ratio is now (500 + 100) / 200 = 3.0
assert!(
mm.risk_ratio(&registry, &btc_price, &usdc_price, &pool, &usdc_pool, &clock) == 3_000_000_000,
mm.risk_ratio(&registry, &btc_price, &usdc_price, &pool, &btc_pool, &usdc_pool, &clock) == 3_000_000_000,
0,
);

Expand Down Expand Up @@ -272,7 +274,7 @@ fun test_liquidation_quote_debt(error_code: u64) {
let repay_coin = mint_coin<USDC>(500 * test_constants::usdc_multiplier(), scenario.ctx());
let btc_price_115 = build_btc_price_info_object(&mut scenario, 115, &clock);
assert!(
mm.risk_ratio(&registry, &btc_price_115, &usdc_price, &pool, &usdc_pool, &clock) == 1_075_000_000,
mm.risk_ratio(&registry, &btc_price_115, &usdc_price, &pool, &btc_pool, &usdc_pool, &clock) == 1_075_000_000,
0,
);

Expand Down Expand Up @@ -350,7 +352,7 @@ fun test_liquidation_quote_debt_partial() {
);

assert!(
mm.risk_ratio(&registry, &btc_price, &usdc_price, &pool, &usdc_pool, &clock) == 3_500_000_000,
mm.risk_ratio(&registry, &btc_price, &usdc_price, &pool, &btc_pool, &usdc_pool, &clock) == 3_500_000_000,
0,
);

Expand All @@ -370,7 +372,7 @@ fun test_liquidation_quote_debt_partial() {

// Risk ratio is now (500 + 100) / 200 = 3.0
assert!(
mm.risk_ratio(&registry, &btc_price, &usdc_price, &pool, &usdc_pool, &clock) == 3_000_000_000,
mm.risk_ratio(&registry, &btc_price, &usdc_price, &pool, &btc_pool, &usdc_pool, &clock) == 3_000_000_000,
0,
);

Expand All @@ -381,7 +383,7 @@ fun test_liquidation_quote_debt_partial() {
let repay_coin = mint_coin<USDC>(90_125_000, scenario.ctx());
let btc_price_115 = build_btc_price_info_object(&mut scenario, 115, &clock);
assert!(
mm.risk_ratio(&registry, &btc_price_115, &usdc_price, &pool, &usdc_pool, &clock) == 1_075_000_000,
mm.risk_ratio(&registry, &btc_price_115, &usdc_price, &pool, &btc_pool, &usdc_pool, &clock) == 1_075_000_000,
0,
);

Expand Down Expand Up @@ -476,7 +478,7 @@ fun test_liquidation_base_debt_default() {
);

assert!(
mm.risk_ratio(&registry, &btc_price, &usdc_price, &pool, &btc_pool, &clock) == 3_500_000_000,
mm.risk_ratio(&registry, &btc_price, &usdc_price, &pool, &btc_pool, &usdc_pool, &clock) == 3_500_000_000,
0,
);

Expand All @@ -496,7 +498,7 @@ fun test_liquidation_base_debt_default() {

// Risk ratio is now (500 + 100) / 200 = 3.0
assert!(
mm.risk_ratio(&registry, &btc_price, &usdc_price, &pool, &btc_pool, &clock) == 3_000_000_000,
mm.risk_ratio(&registry, &btc_price, &usdc_price, &pool, &btc_pool, &usdc_pool, &clock) == 3_000_000_000,
0,
);

Expand Down Expand Up @@ -585,7 +587,7 @@ fun test_liquidation_base_debt() {
);

assert!(
mm.risk_ratio(&registry, &btc_price, &usdc_price, &pool, &btc_pool, &clock) == 3_500_000_000,
mm.risk_ratio(&registry, &btc_price, &usdc_price, &pool, &btc_pool, &usdc_pool, &clock) == 3_500_000_000,
0,
);

Expand All @@ -605,7 +607,7 @@ fun test_liquidation_base_debt() {

// Risk ratio is now (500 + 100) / 200 = 3.0
assert!(
mm.risk_ratio(&registry, &btc_price, &usdc_price, &pool, &btc_pool, &clock) == 3_000_000_000,
mm.risk_ratio(&registry, &btc_price, &usdc_price, &pool, &btc_pool, &usdc_pool, &clock) == 3_000_000_000,
0,
);

Expand All @@ -618,7 +620,7 @@ fun test_liquidation_base_debt() {
let btc_price_2200 = build_btc_price_info_object(&mut scenario, 2200, &clock);

assert!(
mm.risk_ratio(&registry, &btc_price_2200, &usdc_price, &pool, &btc_pool, &clock) == 1_068_181_825,
mm.risk_ratio(&registry, &btc_price_2200, &usdc_price, &pool, &btc_pool, &usdc_pool, &clock) == 1_068_181_825,
0,
);

Expand Down Expand Up @@ -702,6 +704,7 @@ fun test_btc_sui_liquidation(error_code: u64) {
&btc_price,
&sui_price,
&pool,
&btc_pool,
&sui_pool,
&clock,
);
Expand All @@ -721,6 +724,7 @@ fun test_btc_sui_liquidation(error_code: u64) {
&btc_price,
&sui_price,
&pool,
&btc_pool,
&sui_pool,
&clock,
);
Expand Down Expand Up @@ -751,6 +755,7 @@ fun test_btc_sui_liquidation(error_code: u64) {
&btc_price_crash,
&sui_price_spike,
&pool,
&btc_pool,
&sui_pool,
&clock,
);
Expand Down