Skip to content

program: multi-piecewise-interest-rate-curve #1560

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

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
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
6 changes: 3 additions & 3 deletions programs/drift/src/controller/amm/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -513,8 +513,8 @@ fn update_pool_balances_test() {
market.pnl_pool.balance_type(),
)
.unwrap();
assert_eq!(pnl_pool_token_amount, 1_650_000_000 + 3);
assert_eq!(amm_fee_pool_token_amount, 16_666_666);
assert_eq!(pnl_pool_token_amount, 3_300_000_000 + 3);
assert_eq!(amm_fee_pool_token_amount, 33333333);

// negative fee pool
market.amm.total_fee_minus_distributions = -8_008_123_456;
Expand All @@ -539,7 +539,7 @@ fn update_pool_balances_test() {
market.pnl_pool.balance_type(),
)
.unwrap();
assert_eq!(pnl_pool_token_amount, 665678880);
assert_eq!(pnl_pool_token_amount, 2332345547);
assert_eq!(amm_fee_pool_token_amount, 0);
}

Expand Down
8 changes: 4 additions & 4 deletions programs/drift/src/controller/orders/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8056,7 +8056,7 @@ pub mod fulfill_spot_order_with_match {
)
.unwrap();

assert_eq!(base_filled, 166666666);
assert_eq!(base_filled, 333333333);
}

#[test]
Expand Down Expand Up @@ -8252,7 +8252,7 @@ pub mod fulfill_spot_order_with_match {
)
.unwrap();

assert_eq!(base_filled, 166666660);
assert_eq!(base_filled, 333333330);
}

#[test]
Expand Down Expand Up @@ -8450,7 +8450,7 @@ pub mod fulfill_spot_order_with_match {
)
.unwrap();

assert_eq!(base_filled, 166666660);
assert_eq!(base_filled, 333333330);
}

#[test]
Expand Down Expand Up @@ -8646,7 +8646,7 @@ pub mod fulfill_spot_order_with_match {
)
.unwrap();

assert_eq!(base_filled, 166666666);
assert_eq!(base_filled, 333333333);
}

#[test]
Expand Down
149 changes: 107 additions & 42 deletions programs/drift/src/controller/spot_balance/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use crate::math::constants::{
use crate::math::margin::{
calculate_margin_requirement_and_total_collateral_and_liability_info, MarginRequirementType,
};
use crate::math::spot_balance::calculate_borrow_rate;
use crate::math::spot_withdraw::{
calculate_max_borrow_token_amount, calculate_min_deposit_token_amount,
calculate_token_utilization_limits, check_withdraw_limits,
Expand Down Expand Up @@ -269,6 +270,7 @@ fn test_daily_withdraw_limits() {
};
sol_spot_market.deposit_balance = 50 * SPOT_BALANCE_PRECISION;
sol_spot_market.deposit_token_twap = (500 * SPOT_BALANCE_PRECISION) as u64;
sol_spot_market.optimal_utilization = 1_000_000 as u32; //20% APR

sol_spot_market.optimal_borrow_rate = SPOT_RATE_PRECISION_U32 / 5; //20% APR
sol_spot_market.max_borrow_rate = SPOT_RATE_PRECISION_U32; //100% APR
Expand Down Expand Up @@ -345,9 +347,10 @@ fn test_daily_withdraw_limits() {
assert_eq!(sol_spot_market.deposit_balance, 50000000000);
assert_eq!(sol_spot_market.borrow_balance, 8000000002);
assert_eq!(sol_spot_market.borrow_token_twap, 0);

update_spot_market_cumulative_interest(&mut sol_spot_market, None, now + 3655 * 24).unwrap();
assert_eq!(sol_spot_market.deposit_token_twap, 500072987867);
assert_eq!(sol_spot_market.borrow_token_twap, 80072075950);
assert_eq!(sol_spot_market.deposit_token_twap, 500007120768);
assert_eq!(sol_spot_market.borrow_token_twap, 80006208813);

update_spot_balances_and_cumulative_deposits_with_limits(
100000 * 100000,
Expand Down Expand Up @@ -486,7 +489,7 @@ fn test_check_withdraw_limits() {
0,
)
.unwrap();
assert_eq!(mbt, 600000);
assert_eq!(mbt, 642857);

let valid_withdraw = check_withdraw_limits(&spot_market, Some(&user), Some(0)).unwrap();
assert!(valid_withdraw);
Expand Down Expand Up @@ -575,7 +578,7 @@ fn test_check_withdraw_limits_below_optimal_utilization() {
assert_eq!(mdt_dep, 153000000000000);

assert_eq!(max_bor, 142800000000000);
assert_eq!(mbt_bor, 142600000000000);
assert_eq!(mbt_bor, 151342857142857);

let valid_withdraw = check_withdraw_limits(&sol_spot_market, None, None).unwrap();
assert_eq!(valid_withdraw, true);
Expand Down Expand Up @@ -623,17 +626,17 @@ fn test_check_withdraw_limits_above_optimal_utilization() {
initial_liability_weight: 12 * SPOT_WEIGHT_PRECISION / 10,
maintenance_liability_weight: 11 * SPOT_WEIGHT_PRECISION / 10,
deposit_balance: 200_000 * SPOT_BALANCE_PRECISION, // 200k sol
borrow_balance: 140_000 * SPOT_BALANCE_PRECISION,
borrow_balance: 155_000 * SPOT_BALANCE_PRECISION,
liquidator_fee: LIQUIDATION_FEE_PRECISION / 1000,
deposit_token_twap: 204000000000000_u64,
borrow_token_twap: 192200000000000_u64,
utilization_twap: 800000, // 80%
utilization_twap: 890000, // 89%
status: MarketStatus::Active,

..SpotMarket::default()
};

assert_eq!(sol_spot_market.get_utilization().unwrap(), 838627);
assert_eq!(sol_spot_market.get_utilization().unwrap(), 928480);
assert!(
sol_spot_market.get_utilization().unwrap() > sol_spot_market.optimal_utilization as u128
); // below optimal util
Expand Down Expand Up @@ -670,14 +673,14 @@ fn test_check_withdraw_limits_above_optimal_utilization() {
.unwrap();

assert_eq!(deposit_tokens_1, 204000000000000);
assert_eq!(borrow_tokens_1, 171080000000000);
assert_eq!(borrow_tokens_1, 189410000000000);

// utilization bands differ from others
assert_eq!(min_dep, 190088888888888); //174571.428571
assert_eq!(min_dep, 200433862433862);
assert_eq!(mdt_dep, 153000000000000);

assert_eq!(max_bor, 183600000000000);
assert_eq!(mbt_bor, 163200000000000);
assert_eq!(max_bor, 192780000000000);
assert_eq!(mbt_bor, 178500000000000);

// without passing a user, since borrows are above the built in limit of 80% will fail
let valid_withdraw = check_withdraw_limits(&sol_spot_market, None, None).unwrap();
Expand Down Expand Up @@ -1215,9 +1218,11 @@ fn check_fee_collection_larger_nums() {

update_spot_market_cumulative_interest(&mut spot_market, None, now + 100).unwrap();

assert_eq!(spot_market.revenue_pool.scaled_balance, 3844266986);
assert_eq!(spot_market.cumulative_deposit_interest, 10000346004);
assert_eq!(spot_market.cumulative_borrow_interest, 10000711270);
let br = calculate_borrow_rate(&spot_market, spot_market.get_utilization().unwrap()).unwrap();
assert_eq!(br, 20173678);
assert_eq!(spot_market.revenue_pool.scaled_balance, 3457492406);
assert_eq!(spot_market.cumulative_deposit_interest, 10000311188);
assert_eq!(spot_market.cumulative_borrow_interest, 10000639702);
assert_eq!(spot_market.last_interest_ts, 100);
assert_eq!(spot_market.last_twap_ts, 100);
assert_eq!(spot_market.utilization_twap, 624);
Expand All @@ -1241,19 +1246,19 @@ fn check_fee_collection_larger_nums() {
)
.unwrap();

assert_eq!(deposit_tokens_1, 1000038444799);
assert_eq!(borrow_tokens_1, 540548444855);
assert_eq!(if_tokens_1, 3844399);
assert_eq!(deposit_tokens_1, 1000034576399);
assert_eq!(borrow_tokens_1, 540544576533);
assert_eq!(if_tokens_1, 3457599);

update_spot_market_cumulative_interest(&mut spot_market, None, now + 7500).unwrap();

assert_eq!(spot_market.last_interest_ts, 7500);
assert_eq!(spot_market.last_twap_ts, 7500);
assert_eq!(spot_market.utilization_twap, 46976);
assert_eq!(spot_market.utilization_twap, 46964);

assert_eq!(spot_market.cumulative_deposit_interest, 10025953120);
assert_eq!(spot_market.cumulative_borrow_interest, 10053351363);
assert_eq!(spot_market.revenue_pool.scaled_balance, 287632341391);
assert_eq!(spot_market.cumulative_deposit_interest, 10023340555);
assert_eq!(spot_market.cumulative_borrow_interest, 10047980763);
assert_eq!(spot_market.revenue_pool.scaled_balance, 258744322775);

let deposit_tokens_2 = get_token_amount(
spot_market.deposit_balance,
Expand All @@ -1274,14 +1279,14 @@ fn check_fee_collection_larger_nums() {
)
.unwrap();

assert_eq!(deposit_tokens_2, 1002883690837);
assert_eq!(borrow_tokens_2, 543393694522);
assert_eq!(if_tokens_2, 288378837);
assert_eq!(deposit_tokens_2, 1002593403746);
assert_eq!(borrow_tokens_2, 543103408221);
assert_eq!(if_tokens_2, 259348246);

//assert >=0
assert_eq!(
(borrow_tokens_2 - borrow_tokens_1) - (deposit_tokens_2 - deposit_tokens_1),
3629
4341
);

update_spot_market_cumulative_interest(
Expand All @@ -1293,9 +1298,11 @@ fn check_fee_collection_larger_nums() {

now = now + 750 + (60 * 60 * 24 * 365);

assert_eq!(spot_market.cumulative_deposit_interest, 120056141117);
assert_eq!(spot_market.cumulative_borrow_interest, 236304445676);
assert_eq!(spot_market.revenue_pool.scaled_balance, 102149084836788);
assert_eq!(spot_market.get_utilization().unwrap(), 961580);

assert_eq!(spot_market.cumulative_deposit_interest, 108608729074);
assert_eq!(spot_market.cumulative_borrow_interest, 212759822472);
assert_eq!(spot_market.revenue_pool.scaled_balance, 101141669831135);

let deposit_tokens_3 = get_token_amount(
spot_market.deposit_balance,
Expand All @@ -1316,24 +1323,24 @@ fn check_fee_collection_larger_nums() {
)
.unwrap();

assert_eq!(deposit_tokens_3, 13231976606113);
assert_eq!(borrow_tokens_3, 12772491593234);
assert_eq!(if_tokens_3, 1226362494413);
assert_eq!(deposit_tokens_3, 11959359729078);
assert_eq!(borrow_tokens_3, 11499881164435);
assert_eq!(if_tokens_3, 1098486821678);

assert_eq!((borrow_tokens_3 - borrow_tokens_2), 12229097898712);
assert_eq!((deposit_tokens_3 - deposit_tokens_2), 12229092915276);
assert_eq!((borrow_tokens_3 - borrow_tokens_2), 10956777756214);
assert_eq!((deposit_tokens_3 - deposit_tokens_2), 10956766325332);

// assert >= 0
assert_eq!(
(borrow_tokens_3 - borrow_tokens_2) - (deposit_tokens_3 - deposit_tokens_2),
4_983_436 //$4.98 missing
11430882 //$11.43 missing
);

let mut if_balance_2 = 0;

// settle IF pool to 100% utilization boundary
// only half of depositors available claim was settled (to protect vault)
assert_eq!(spot_market.revenue_pool.scaled_balance, 102149084836788);
assert_eq!(spot_market.revenue_pool.scaled_balance, 101141669831135);
spot_market.insurance_fund.revenue_settle_period = 1;
let settle_amount = settle_revenue_to_insurance_fund(
deposit_tokens_3 as u64,
Expand All @@ -1343,15 +1350,15 @@ fn check_fee_collection_larger_nums() {
true,
)
.unwrap();
assert_eq!(settle_amount, 229742506020);
assert_eq!(settle_amount, 229739282275);
assert_eq!(spot_market.insurance_fund.user_shares, 0);
assert_eq!(spot_market.insurance_fund.total_shares, 0);
if_balance_2 += settle_amount;
assert_eq!(if_balance_2, 229742506020);
assert_eq!(if_tokens_3 - (settle_amount as u128), 996619988393); // w/ update interest for settle_spot_market_to_if
assert_eq!(if_balance_2, 229739282275);
assert_eq!(if_tokens_3 - (settle_amount as u128), 868747539403); // w/ update interest for settle_spot_market_to_if

assert_eq!(spot_market.revenue_pool.scaled_balance, 83024042298956);
assert_eq!(spot_market.utilization_twap, 965274);
assert_eq!(spot_market.revenue_pool.scaled_balance, 79996002243946);
assert_eq!(spot_market.utilization_twap, 961580);

let deposit_tokens_4 = get_token_amount(
spot_market.deposit_balance,
Expand All @@ -1372,8 +1379,66 @@ fn check_fee_collection_larger_nums() {
)
.unwrap();

assert_eq!(deposit_tokens_4 - borrow_tokens_4, 229742506021);
assert_eq!(if_tokens_4, 996833556273);
assert_eq!(deposit_tokens_4 - borrow_tokens_4, 229739282275);
assert_eq!(if_tokens_4, 868870384546);
}

#[test]
fn test_multi_stage_borrow_rate_curve() {
let mut spot_market = SpotMarket {
market_index: 0,
oracle_source: OracleSource::QuoteAsset,
cumulative_deposit_interest: SPOT_CUMULATIVE_INTEREST_PRECISION,
cumulative_borrow_interest: SPOT_CUMULATIVE_INTEREST_PRECISION,
decimals: 6,
initial_asset_weight: SPOT_WEIGHT_PRECISION,
maintenance_asset_weight: SPOT_WEIGHT_PRECISION,
deposit_balance: 1_000_000 * SPOT_BALANCE_PRECISION,
borrow_balance: 0,
deposit_token_twap: QUOTE_PRECISION_U64 / 2,

optimal_utilization: SPOT_UTILIZATION_PRECISION_U32 * 70 / 100, // 70%
optimal_borrow_rate: SPOT_RATE_PRECISION_U32 * 10 / 100, // 10%
max_borrow_rate: SPOT_RATE_PRECISION_U32 * 500 / 100, // 500%
..SpotMarket::default()
};

// Store all rates to verify monotonicity and smoothness later
let mut last_rate = 0_u128;
let mut last_rate_delta = 0_u128;
let mut rate_jumps = 0_u128;
for i in 0..=200 {
let utilization = i * 5_000; // 0.5% increments

let rate = calculate_borrow_rate(&spot_market, utilization).unwrap();
println!("Utilization: {} => Rate: {}", utilization, rate);

if (rate - last_rate) > (last_rate_delta + 1) && last_rate_delta != 0 {
rate_jumps += 1;
}

println!("rate deltas: {} => {}", (rate - last_rate), last_rate_delta);

assert!(
(rate - last_rate) >= last_rate_delta.saturating_sub(1),
"Rate of change should not decrease by much"
);
last_rate_delta = rate - last_rate;

// Check monotonic increasing
assert!(rate >= last_rate, "Rate should not decrease");
last_rate = rate;

if utilization == spot_market.optimal_utilization as u128 {
assert!(((rate as i32) - (spot_market.optimal_borrow_rate as i32)).abs() <= 1)
}

if utilization == 1000000_u128 {
assert_eq!(rate as u32, spot_market.max_borrow_rate)
}
}

assert_eq!(rate_jumps, 5);
}

#[test]
Expand Down
4 changes: 2 additions & 2 deletions programs/drift/src/math/orders/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ mod get_max_fill_amounts {
let (max_base, max_quote) =
get_max_fill_amounts(&user, 0, &base_market, &quote_market, true).unwrap();

assert_eq!(max_base, Some(16666666666));
assert_eq!(max_base, Some(33333333333));
assert_eq!(max_quote, None);
}

Expand Down Expand Up @@ -704,7 +704,7 @@ mod get_max_fill_amounts {
get_max_fill_amounts(&user, 0, &base_market, &quote_market, true).unwrap();

assert_eq!(max_base, None);
assert_eq!(max_quote, Some(16666666));
assert_eq!(max_quote, Some(33333333));
}
}

Expand Down
Loading
Loading