use std::time::Duration;
use gmsol_model::{
fixed::Fixed,
num::MulDiv,
params::{
fee::{BorrowingFeeKinkModelParamsForOneSide, BorrowingFeeParams},
FeeParams, PositionParams, PriceImpactParams,
},
price::Prices,
test::{TestMarket, TestMarketConfig, TestPosition},
Balance, BaseMarketExt, BorrowingFeeMarket, BorrowingFeeMarketExt, LiquidityMarketExt,
LiquidityMarketMutExt, MarketAction, PnlFactorKind, PositionExt, PositionMutExt,
};
#[test]
fn test_total_borrowing_with_high_borrowing_factor() -> gmsol_model::Result<()> {
let unit = Fixed::<u128, 20>::ONE.into_inner();
let max_open_interest = 1_157_920_900_000 * unit;
let amount = 5789604500 * 10_u128.pow(9);
let mut market = TestMarket::<u128, 20>::with_config(TestMarketConfig {
borrowing_fee_params: BorrowingFeeParams::builder()
.receiver_factor(0)
.exponent_for_long(unit)
.exponent_for_short(unit)
.factor_for_long(2_780_000_000_000 * 20)
.factor_for_short(2_780_000_000_000 * 20)
.build(),
max_open_interest,
swap_impact_params: PriceImpactParams::builder()
.positive_factor(0)
.negative_factor(0)
.exponent(unit)
.build(),
position_impact_params: PriceImpactParams::builder()
.positive_factor(0)
.negative_factor(0)
.exponent(unit)
.build(),
min_collateral_factor_for_oi: 0,
borrowing_fee_kink_model_params: BorrowingFeeKinkModelParamsForOneSide::builder()
.optimal_usage_factor(0)
.base_borrowing_factor(0)
.above_optimal_usage_borrowing_factor(0)
.build(),
..Default::default()
});
let prices = Prices::new_for_test(20_000_000_000_000, 20_000_000_000_000, 100_000_000_000_000);
market.deposit(amount, amount, prices)?.execute()?;
let mut position = TestPosition::long(true);
_ = position
.ops(&mut market)
.increase(prices, amount * 1_000_000, max_open_interest, None)?
.execute()?;
let factor = market.borrowing_factor_per_second(true, &prices)?;
println!("borrowing factor per second: {factor}");
market.move_clock_forward(Duration::from_secs(3600 * 24 * 365 * 100));
_ = position
.ops(&mut market)
.decrease(prices, 0, None, 0, Default::default())?
.execute()?;
let total_borrowing = market.total_borrowing_pool()?;
println!("{total_borrowing:#?}");
Ok(())
}
#[test]
fn test_total_borrowing_with_high_borrowing_factor_2() -> gmsol_model::Result<()> {
const YEAR_SECONDS: u64 = 365 * 24 * 60 * 60;
let unit = Fixed::<u128, 20>::ONE.into_inner();
let price_decimals = 10_u128.pow(9);
let _unit_token = 10_u128.pow(11);
let price = 100_000 * price_decimals;
let max_deposit_amount = i128::MAX as u128 / price;
let years = 100u64;
let factor_per_year = 1000 / 100 * unit;
let factor_per_second = factor_per_year / YEAR_SECONDS as u128;
let max_oi = u128::MAX
.checked_mul_div(&unit, &(factor_per_year * years as u128))
.unwrap();
let factor = factor_per_second
.checked_mul_div(&(max_deposit_amount * price), &max_oi)
.unwrap();
let mut market = TestMarket::<u128, 20>::with_config(TestMarketConfig {
max_pool_amount: u128::MAX,
max_open_interest: u128::MAX,
max_pool_value_for_deposit: u128::MAX,
swap_fee_params: FeeParams::builder()
.fee_receiver_factor(0)
.positive_impact_fee_factor(0)
.negative_impact_fee_factor(0)
.build(),
order_fee_params: FeeParams::builder()
.fee_receiver_factor(0)
.positive_impact_fee_factor(0)
.negative_impact_fee_factor(0)
.build(),
borrowing_fee_params: BorrowingFeeParams::builder()
.receiver_factor(0)
.exponent_for_long(unit)
.exponent_for_short(unit)
.factor_for_long(factor)
.factor_for_short(factor)
.build(),
swap_impact_params: PriceImpactParams::builder()
.positive_factor(0)
.negative_factor(0)
.exponent(unit)
.build(),
position_impact_params: PriceImpactParams::builder()
.positive_factor(0)
.negative_factor(0)
.exponent(unit)
.build(),
min_collateral_factor_for_oi: 0,
position_params: PositionParams::builder()
.min_collateral_value(0)
.min_collateral_factor(0)
.min_position_size_usd(0)
.max_positive_position_impact_factor(5_000_000)
.max_negative_position_impact_factor(5_000_000)
.max_position_impact_factor_for_liquidations(2_500_000)
.build(),
borrowing_fee_kink_model_params: BorrowingFeeKinkModelParamsForOneSide::builder()
.optimal_usage_factor(0)
.base_borrowing_factor(0)
.above_optimal_usage_borrowing_factor(0)
.build(),
..Default::default()
});
let prices = Prices::new_for_test(price, price, price);
market.deposit(max_deposit_amount, 0, prices)?.execute()?;
println!(
"pool value: {}",
market.pool_value(&prices, PnlFactorKind::MaxAfterDeposit, true)?
);
let mut position_1 = TestPosition::long(true);
_ = position_1
.ops(&mut market)
.increase(prices, max_deposit_amount, max_oi / 2, None)?
.execute()?;
let mut position_2 = TestPosition::long(true);
_ = position_2
.ops(&mut market)
.increase(prices, max_deposit_amount, max_oi / 2, None)?
.execute()?;
let factor = market.borrowing_factor_per_second(true, &prices)?;
println!("borrowing factor per second: {factor}");
println!(
"collateral value of position 1: {}",
position_1.ops(&mut market).collateral_value(&prices)?
);
println!(
"collateral value of position 2: {}",
position_2.ops(&mut market).collateral_value(&prices)?
);
market.move_clock_forward(Duration::from_secs(YEAR_SECONDS * years));
_ = position_1
.ops(&mut market)
.decrease(prices, 0, None, 0, Default::default())?
.execute()?;
_ = position_2
.ops(&mut market)
.decrease(prices, 0, None, 0, Default::default())?
.execute()?;
let open_interest = market.open_interest()?.long_amount()?;
let total_borrowing = market.total_borrowing_pool()?;
let cbf = market.cumulative_borrowing_factor(true)?;
println!("open interest: {open_interest:#?}");
println!("total borrowing: {total_borrowing:#?}");
println!("cumulative borrowing factor: {cbf:#?}");
Ok(())
}