Skip to content

Commit

Permalink
program: add update_lp_market_position test for big k (#565)
Browse files Browse the repository at this point in the history
* start test

* improve lp_delta_quote

* improve per_lp_delta_quote

* fix tests/perpLpJit.ts

* fix tests/delistMarket.ts

* fix tests/liquidityProvider.ts

* CHANGELOG

---------

Co-authored-by: 0xbigz <[email protected]>
  • Loading branch information
crispheaney and 0xbigz committed Aug 8, 2023
1 parent 9009af4 commit 7db3fb4
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 14 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixes

- program: add update_lp_market_position test for big k ([#565](https://github.com/drift-labs/protocol-v2/pull/565))

### Breaking

## [2.37.0] - 2023-08-02
Expand Down
1 change: 1 addition & 0 deletions programs/drift/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ solana-security-txt = "1.1.0"
[dev-dependencies]
bytes = "1.2.0"
pyth = { path = "../pyth", features = ["no-entrypoint"]}
base64 = "0.13.0"
2 changes: 1 addition & 1 deletion programs/drift/src/controller/orders/amm_jit_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1541,7 +1541,7 @@ pub mod amm_jit {
);

assert_eq!(market.amm.quote_asset_amount_per_lp, 0);
assert_eq!(market_after.amm.quote_asset_amount_per_lp, -497271);
assert_eq!(market_after.amm.quote_asset_amount_per_lp, -497272);

assert_eq!(market.amm.base_asset_amount_per_lp, 0);
assert_eq!(market_after.amm.base_asset_amount_per_lp, 5000000);
Expand Down
8 changes: 7 additions & 1 deletion programs/drift/src/controller/position.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,12 +403,18 @@ pub fn update_lp_market_position(
total_lp_shares,
)?;

let per_lp_delta_quote = get_proportion_i128(
let mut per_lp_delta_quote = get_proportion_i128(
delta.quote_asset_amount.cast()?,
AMM_RESERVE_PRECISION,
total_lp_shares,
)?;

// user position delta is short => lp position delta is long
if per_lp_delta_base < 0 {
// add one => lp subtract 1
per_lp_delta_quote = per_lp_delta_quote.safe_add(1)?;
}

let lp_delta_base =
get_proportion_i128(per_lp_delta_base, user_lp_shares, AMM_RESERVE_PRECISION)?;
let lp_delta_quote =
Expand Down
110 changes: 109 additions & 1 deletion programs/drift/src/controller/position/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ use crate::controller::position::{
update_lp_market_position, update_position_and_market, PositionDelta,
};
use crate::math::constants::{
AMM_RESERVE_PRECISION, AMM_RESERVE_PRECISION_I128, BASE_PRECISION_I64,
AMM_RESERVE_PRECISION, AMM_RESERVE_PRECISION_I128, BASE_PRECISION_I64, QUOTE_PRECISION_I128,
};
use crate::state::perp_market::{AMMLiquiditySplit, PerpMarket, AMM};
use crate::state::user::PerpPosition;
use crate::test_utils::create_account_info;
use anchor_lang::prelude::AccountLoader;
use solana_program::pubkey::Pubkey;
use std::str::FromStr;

#[test]
fn full_amm_split() {
Expand Down Expand Up @@ -34,6 +38,110 @@ fn full_amm_split() {
);
}

#[test]
fn amm_split_large_k() {
let perp_market_str = String::from("Ct8MLGv1N/dvAH3EF67yBqaUQerctpm4yqpK+QNSrXCQz76p+B+ka+8Ni2/aLOukHaFdQJXR2jkqDS+O0MbHvA9M+sjCgLVtQwhkAQAAAAAAAAAAAAAAAAIAAAAAAAAAkI1kAQAAAAB6XWQBAAAAAO8yzWQAAAAAnJ7I3f///////////////2dHvwAAAAAAAAAAAAAAAABGiVjX6roAAAAAAAAAAAAAAAAAAAAAAAB1tO47J+xiAAAAAAAAAAAAGD03Fis3mgAAAAAAAAAAAJxiDwAAAAAAAAAAAAAAAABxqRCIGRxiAAAAAAAAAAAAEy8wZfK9YwAAAAAAAAAAAGZeZCE+g3sAAAAAAAAAAAAKYeQAAAAAAAAAAAAAAAAAlIvoyyc3mgAAAAAAAAAAAADQdQKjbgAAAAAAAAAAAAAAwu8g05H/////////////E6tNHAIAAAAAAAAAAAAAAO3mFwd0AAAAAAAAAAAAAAAAgPQg5rUAAAAAAAAAAAAAGkDtXR4AAAAAAAAAAAAAAEv0WeZW/f////////////9kUidaqAIAAAAAAAAAAAAA0ZMEr1H9/////////////w5/U3uqAgAAAAAAAAAAAAAANfbqfCd3AAAAAAAAAAAAIhABAAAAAAAiEAEAAAAAACIQAQAAAAAAY1QBAAAAAAA5f3WMVAAAAAAAAAAAAAAAFhkiihsAAAAAAAAAAAAAAO2EfWc5AAAAAAAAAAAAAACM/5CAQgAAAAAAAAAAAAAAvenX0SsAAAAAAAAAAAAAALgPUogZAAAAAAAAAAAAAAC01x97AAAAAAAAAAAAAAAAOXzVbgAAAAAAAAAAAAAAAMG4+QwBAAAAAAAAAAAAAABwHI3fLeJiAAAAAAAAAAAABvigOblGmgAAAAAAAAAAALeRnZsi9mIAAAAAAAAAAAAqgs3ynCeaAAAAAAAAAAAAQwhkAQAAAAAAAAAAAAAAAJOMZAEAAAAAFKJkAQAAAABTl2QBAAAAALFuZAEAAAAAgrx7DAAAAAAUAwAAAAAAAAN1TAYAAAAAuC7NZAAAAAAQDgAAAAAAAADh9QUAAAAAZAAAAAAAAAAA4fUFAAAAAAAAAAAAAAAAn2HvyMABAADGV6rZFwAAAE5Qg2oPAAAA8zHNZAAAAAAdYAAAAAAAAE2FAAAAAAAA6zLNZAAAAAD6AAAAaEIAABQDAAAUAwAAAAAAANcBAABkADIAZGQAAcDIUt4AAAAA0QQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI9qQbynsAAAAAAAAAAAAAAAAAAAAAAAAFNPTC1QRVJQICAgICAgICAgICAgICAgICAgICAgICAghuS1//////8A4fUFAAAAAAB0O6QLAAAAR7PdeQMAAAD+Mc1kAAAAAADKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAOULDwAAAAAAUBkAAAAAAADtAQAAAAAAAMgAAAAAAAAAECcAAKhhAADoAwAA9AEAAAAAAAAQJwAAZAIAAGQCAAAAAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==");
let mut decoded_bytes = base64::decode(perp_market_str).unwrap();
let perp_market_bytes = decoded_bytes.as_mut_slice();

let key = Pubkey::default();
let owner = Pubkey::from_str("dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH").unwrap();
let mut lamports = 0;
let perp_market_account_info =
create_account_info(&key, true, &mut lamports, perp_market_bytes, &owner);

let perp_market_loader: AccountLoader<PerpMarket> =
AccountLoader::try_from(&perp_market_account_info).unwrap();
let mut perp_market = perp_market_loader.load_mut().unwrap();

assert_eq!(perp_market.amm.base_asset_amount_per_lp, -574054756);
assert_eq!(perp_market.amm.quote_asset_amount_per_lp, 12535655);

let og_baapl = perp_market.amm.base_asset_amount_per_lp;
let og_qaapl = perp_market.amm.quote_asset_amount_per_lp;

// msg!("perp_market: {:?}", perp_market);

// min long order for $2.3
let delta = PositionDelta {
base_asset_amount: BASE_PRECISION_I64 / 10,
quote_asset_amount: -2300000,
};

update_lp_market_position(&mut perp_market, &delta, 0, AMMLiquiditySplit::Shared).unwrap();

assert_eq!(perp_market.amm.base_asset_amount_per_lp, -574054758);
assert_eq!(perp_market.amm.quote_asset_amount_per_lp, 12535655);

// min short order for $2.3
let delta = PositionDelta {
base_asset_amount: -BASE_PRECISION_I64 / 10,
quote_asset_amount: 2300000,
};

update_lp_market_position(&mut perp_market, &delta, 0, AMMLiquiditySplit::Shared).unwrap();

assert_eq!(perp_market.amm.base_asset_amount_per_lp, -574054756);
assert_eq!(perp_market.amm.quote_asset_amount_per_lp, 12535654);

// long order for $230
let delta = PositionDelta {
base_asset_amount: BASE_PRECISION_I64 * 10,
quote_asset_amount: -230000000,
};

update_lp_market_position(&mut perp_market, &delta, 0, AMMLiquiditySplit::Shared).unwrap();

assert_eq!(perp_market.amm.base_asset_amount_per_lp, -574055043);
assert_eq!(perp_market.amm.quote_asset_amount_per_lp, 12535660);

assert_eq!(
(perp_market.amm.sqrt_k as i128) * (og_baapl - perp_market.amm.base_asset_amount_per_lp)
/ AMM_RESERVE_PRECISION_I128,
9977763076
);
// assert_eq!((perp_market.amm.sqrt_k as i128) * (og_baapl-perp_market.amm.base_asset_amount_per_lp) / AMM_RESERVE_PRECISION_I128, 104297175);
assert_eq!(
(perp_market.amm.sqrt_k as i128) * (og_qaapl - perp_market.amm.quote_asset_amount_per_lp)
/ QUOTE_PRECISION_I128,
-173828625034
);
assert_eq!(
(perp_market.amm.sqrt_k as i128)
* (og_qaapl - perp_market.amm.quote_asset_amount_per_lp - 1)
/ QUOTE_PRECISION_I128,
-208594350041
);
// assert_eq!(243360075047/9977763076 < 23, true); // ensure rounding in favor

// long order for $230
let delta = PositionDelta {
base_asset_amount: -BASE_PRECISION_I64 * 10,
quote_asset_amount: 230000000,
};

let og_baapl = perp_market.amm.base_asset_amount_per_lp;
let og_qaapl = perp_market.amm.quote_asset_amount_per_lp;

update_lp_market_position(&mut perp_market, &delta, 0, AMMLiquiditySplit::Shared).unwrap();

assert_eq!(perp_market.amm.base_asset_amount_per_lp, -574054756);
assert_eq!(perp_market.amm.quote_asset_amount_per_lp, 12535653);

assert_eq!(
(perp_market.amm.sqrt_k as i128) * (og_baapl - perp_market.amm.base_asset_amount_per_lp)
/ AMM_RESERVE_PRECISION_I128,
-9977763076
);
// assert_eq!((perp_market.amm.sqrt_k as i128) * (og_baapl-perp_market.amm.base_asset_amount_per_lp) / AMM_RESERVE_PRECISION_I128, 104297175);
assert_eq!(
(perp_market.amm.sqrt_k as i128) * (og_qaapl - perp_market.amm.quote_asset_amount_per_lp)
/ QUOTE_PRECISION_I128,
243360075047
);
// assert_eq!(243360075047/9977763076 < 23, true); // ensure rounding in favor
}

#[test]
fn full_lp_split() {
let delta = PositionDelta {
Expand Down
2 changes: 1 addition & 1 deletion tests/delistMarket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,7 @@ describe('delist market', () => {
const userCostBasisBefore = marketBefore.amm.quoteAssetAmount;

console.log('userCostBasisBefore:', userCostBasisBefore.toString());
assert(userCostBasisBefore.eq(new BN(-1))); // from LP burn
assert(userCostBasisBefore.eq(new BN(-2))); // from LP burn

await liquidatorDriftClient.settlePNL(
await liquidatorDriftClient.getUserAccountPublicKey(),
Expand Down
12 changes: 6 additions & 6 deletions tests/liquidityProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -494,19 +494,19 @@ describe('liquidity providing', () => {
'=> net baa:',
driftClient.getPerpMarketAccount(0).amm.baseAssetAmountWithAmm.toString()
);
assert(user.perpPositions[0].quoteAssetAmount.eq(new BN(-1233600)));
assert(user.perpPositions[0].quoteAssetAmount.eq(new BN(-1233700)));
// assert(user.perpPositions[0].unsettledPnl.eq(new BN(900)));
// remainder goes into the last
assert(user.perpPositions[0].lastBaseAssetAmountPerLp.eq(new BN(12500000)));
assert(user.perpPositions[0].lastQuoteAssetAmountPerLp.eq(new BN(-12336)));
assert(user.perpPositions[0].lastQuoteAssetAmountPerLp.eq(new BN(-12337)));

market = await driftClient.getPerpMarketAccount(0);
console.log(
market.amm.quoteAssetAmountPerLp.toString(),
market.amm.baseAssetAmountPerLp.toString()
);
assert(market.amm.baseAssetAmountPerLp.eq(new BN(12500000)));
assert(market.amm.quoteAssetAmountPerLp.eq(new BN(-12336)));
assert(market.amm.quoteAssetAmountPerLp.eq(new BN(-12337)));

// remove
console.log('removing liquidity...');
Expand Down Expand Up @@ -934,7 +934,7 @@ describe('liquidity providing', () => {
console.log(user.perpPositions[0].baseAssetAmount.toString());
console.log(user.perpPositions[0].quoteAssetAmount.toString());
assert(user.perpPositions[0].baseAssetAmount.eq(new BN('10000000000'))); // lp is long
assert(user.perpPositions[0].quoteAssetAmount.eq(new BN(-9550785)));
assert(user.perpPositions[0].quoteAssetAmount.eq(new BN(-9550985)));

console.log('closing trader ...');
await adjustOraclePostSwap(tradeSize, SwapDirection.REMOVE, market);
Expand Down Expand Up @@ -1020,7 +1020,7 @@ describe('liquidity providing', () => {

assert(lpTokenAmount.eq(ZERO));
assert(user.perpPositions[0].baseAssetAmount.eq(new BN('-10000000000'))); // lp is short
assert(user.perpPositions[0].quoteAssetAmount.eq(new BN('11940740')));
assert(user.perpPositions[0].quoteAssetAmount.eq(new BN('11940540')));
assert(user.perpPositions[0].quoteEntryAmount.eq(new BN('11139500')));

console.log('closing trader...');
Expand Down Expand Up @@ -1125,7 +1125,7 @@ describe('liquidity providing', () => {
const baa = user.perpPositions[0].baseAssetAmount;
const qaa = user.perpPositions[0].quoteAssetAmount;
assert(baa.eq(new BN(10000000000)));
assert(qaa.eq(new BN(-6860362)));
assert(qaa.eq(new BN(-6860662)));

console.log('removing the other half of liquidity');
await driftClient.removePerpLpShares(market.marketIndex, otherHalfShares);
Expand Down
8 changes: 4 additions & 4 deletions tests/perpLpJit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1040,7 +1040,7 @@ describe('lp jit', () => {
console.log(marketAfter.amm.baseAssetAmountWithAmm.toString());

assert(marketAfter.amm.baseAssetAmountPerLp.eq(new BN(-5000000)));
assert(marketAfter.amm.quoteAssetAmountPerLp.eq(new BN(144606790)));
assert(marketAfter.amm.quoteAssetAmountPerLp.eq(new BN(144606790 - 1)));
assert(marketAfter.amm.baseAssetAmountWithUnsettledLp.eq(new BN(-5000000)));
assert(marketAfter.amm.baseAssetAmountWithAmm.eq(new BN(5000000)));

Expand All @@ -1057,7 +1057,7 @@ describe('lp jit', () => {
console.log('lpPnl:', lpPnl.toString());

assert(dustPos.toString() == '0');
assert(lpPnl.toString() == '6134172');
assert(lpPnl.toString() == '6134171');

const _sig2 = await driftClient.settleLP(
await driftClient.getUserAccountPublicKey(),
Expand Down Expand Up @@ -1121,7 +1121,7 @@ describe('lp jit', () => {
console.log(marketAfter2.amm.baseAssetAmountWithAmm.toString());

assert(marketAfter2.amm.baseAssetAmountPerLp.eq(new BN(-2500000)));
assert(marketAfter2.amm.quoteAssetAmountPerLp.eq(new BN(78437568)));
assert(marketAfter2.amm.quoteAssetAmountPerLp.eq(new BN(78437566)));
assert(
marketAfter2.amm.baseAssetAmountWithUnsettledLp.eq(new BN(-2500000))
);
Expand All @@ -1140,7 +1140,7 @@ describe('lp jit', () => {
console.log('lpPnl:', lpPnl2.toString());

assert(dustPos2.toString() == '0');
assert(lpPnl2.toString() == '3067087');
assert(lpPnl2.toString() == '3067086');

await driftClient.settleLP(
await driftClient.getUserAccountPublicKey(),
Expand Down

0 comments on commit 7db3fb4

Please sign in to comment.