Skip to content

Commit 7a94a4a

Browse files
update aum considers amm cache (#1701)
1 parent 71db8bf commit 7a94a4a

File tree

7 files changed

+112
-8
lines changed

7 files changed

+112
-8
lines changed

programs/drift/src/instructions/lp_pool.rs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ use crate::{
2828
events::{LPMintRedeemRecord, LPSwapRecord},
2929
lp_pool::{
3030
calculate_target_weight, AmmConstituentDatum, AmmConstituentMappingFixed, Constituent,
31-
ConstituentCorrelations, ConstituentCorrelationsFixed, ConstituentTargetBaseFixed,
32-
LPPool, TargetsDatum, WeightValidationFlags, CONSTITUENT_CORRELATIONS_PDA_SEED,
31+
ConstituentCorrelationsFixed, ConstituentTargetBaseFixed, LPPool, TargetsDatum,
32+
WeightValidationFlags, CONSTITUENT_CORRELATIONS_PDA_SEED,
3333
},
3434
oracle::OraclePriceData,
3535
oracle_map::OracleMap,
36-
perp_market::{AmmCacheFixed, CacheInfo, MarketStatus, AMM_POSITIONS_CACHE},
36+
perp_market::{AmmCacheFixed, CacheInfo, AMM_POSITIONS_CACHE},
3737
perp_market_map::MarketSet,
3838
spot_market::{SpotBalanceType, SpotMarket},
3939
spot_market_map::get_writable_spot_market_set_from_many,
@@ -261,6 +261,23 @@ pub fn handle_update_lp_pool_aum<'c: 'info, 'info>(
261261
"Constituent target weights PDA does not match expected PDA"
262262
)?;
263263

264+
let amm_cache_key: &Pubkey = &ctx.accounts.amm_cache.key();
265+
let amm_cache: AccountZeroCopy<'_, CacheInfo, AmmCacheFixed> =
266+
ctx.accounts.amm_cache.load_zc()?;
267+
let expected_amm_pda = &Pubkey::create_program_address(
268+
&[
269+
AMM_POSITIONS_CACHE.as_ref(),
270+
amm_cache.fixed.bump.to_le_bytes().as_ref(),
271+
],
272+
&crate::ID,
273+
)
274+
.map_err(|_| ErrorCode::InvalidPDA)?;
275+
validate!(
276+
amm_cache_key.eq(expected_amm_pda),
277+
ErrorCode::InvalidPDA,
278+
"Amm cache PDA does not match expected PDA"
279+
)?;
280+
264281
let mut aum: u128 = 0;
265282
let mut crypto_delta = 0_i128;
266283
let mut oldest_slot = u64::MAX;
@@ -353,6 +370,14 @@ pub fn handle_update_lp_pool_aum<'c: 'info, 'info>(
353370
aum = aum.safe_add(constituent_aum.cast()?)?;
354371
}
355372

373+
for cache_datum in amm_cache.iter() {
374+
if cache_datum.quote_owed_from_lp > 0 {
375+
aum = aum.safe_sub(cache_datum.quote_owed_from_lp.abs().cast::<u128>()?)?;
376+
} else {
377+
aum = aum.safe_add(cache_datum.quote_owed_from_lp.abs().cast::<u128>()?)?;
378+
}
379+
}
380+
356381
lp_pool.oldest_oracle_slot = oldest_slot;
357382
lp_pool.last_aum = aum;
358383
lp_pool.last_aum_slot = slot;
@@ -1293,6 +1318,8 @@ pub struct UpdateLPPoolAum<'info> {
12931318
/// CHECK: checked in ConstituentTargetBaseZeroCopy checks
12941319
#[account(mut)]
12951320
pub constituent_target_base: AccountInfo<'info>,
1321+
/// CHECK: checked in AmmCacheZeroCopy checks
1322+
pub amm_cache: AccountInfo<'info>,
12961323
}
12971324

12981325
/// `in`/`out` is in the program's POV for this swap. So `user_in_token_account` is the user owned token account

programs/drift/src/state/lp_pool.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,13 @@ impl LPPool {
256256
let lp_amount = if self.last_aum == 0 {
257257
token_amount_usd.safe_div(token_precision_denominator)?
258258
} else {
259+
msg!("token_amount_usd: {}", token_amount_usd);
260+
msg!("dlp_total_supply: {}", dlp_total_supply);
261+
msg!("last_aum: {}", self.last_aum);
262+
msg!(
263+
"token_precision_denominator: {}",
264+
token_precision_denominator
265+
);
259266
token_amount_usd
260267
.safe_mul(dlp_total_supply as u128)?
261268
.safe_div(self.last_aum.safe_mul(token_precision_denominator)?)?

programs/drift/src/state/zero_copy.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ where
8989
validate!(
9090
acct.owner == &program_id,
9191
ErrorCode::DefaultError,
92-
"invalid owner",
92+
"invalid owner {}, program_id: {}",
93+
acct.owner,
94+
program_id,
9395
)?;
9496

9597
let data = acct.try_borrow_data().safe_unwrap()?;

sdk/src/driftClient.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9815,6 +9815,7 @@ export class DriftClient {
98159815
this.program.programId,
98169816
lpPool.pubkey
98179817
),
9818+
ammCache: getAmmCachePublicKey(this.program.programId),
98189819
},
98199820
remainingAccounts,
98209821
});

sdk/src/idl/drift.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7649,6 +7649,11 @@
76497649
"name": "constituentTargetBase",
76507650
"isMut": true,
76517651
"isSigner": false
7652+
},
7653+
{
7654+
"name": "ammCache",
7655+
"isMut": false,
7656+
"isSigner": false
76527657
}
76537658
],
76547659
"args": []

sdk/src/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ export * from './accounts/fetch';
1212
export * from './accounts/webSocketDriftClientAccountSubscriber';
1313
export * from './accounts/webSocketInsuranceFundStakeAccountSubscriber';
1414
export * from './accounts/webSocketHighLeverageModeConfigAccountSubscriber';
15-
export * from './accounts/webSocketConstituentAccountSubscriber';
1615
export * from './accounts/bulkAccountLoader';
1716
export * from './accounts/bulkUserSubscription';
1817
export * from './accounts/bulkUserStatsSubscription';
@@ -23,9 +22,11 @@ export * from './accounts/pollingUserAccountSubscriber';
2322
export * from './accounts/pollingUserStatsAccountSubscriber';
2423
export * from './accounts/pollingInsuranceFundStakeAccountSubscriber';
2524
export * from './accounts/pollingHighLeverageModeConfigAccountSubscriber';
26-
export * from './accounts/pollingConstituentAccountSubscriber';
2725
export * from './accounts/basicUserAccountSubscriber';
2826
export * from './accounts/oneShotUserAccountSubscriber';
27+
export * from './constituentMap/constituentMap';
28+
export * from './constituentMap/pollingConstituentAccountSubscriber';
29+
export * from './constituentMap/webSocketConstituentAccountSubscriber';
2930
export * from './accounts/types';
3031
export * from './addresses/pda';
3132
export * from './adminClient';

tests/lpPool.ts

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import {
5252
mockOracleNoProgram,
5353
mockUSDCMint,
5454
mockUserUSDCAccountWithAuthority,
55+
overWriteMintAccount,
5556
overWritePerpMarket,
5657
overWriteSpotMarket,
5758
} from './testHelpers';
@@ -924,14 +925,69 @@ describe('LP Pool', () => {
924925
getConstituentPublicKey(program.programId, lpPoolKey, 0)
925926
)) as ConstituentAccount;
926927

928+
let lpPool = (await adminClient.program.account.lpPool.fetch(
929+
lpPoolKey
930+
)) as LPPoolAccount;
931+
927932
assert(ammCache.cache[0].quoteOwedFromLp.eq(owedAmount.divn(2)));
928933
assert(constituent.tokenBalance.eq(ZERO));
934+
assert(lpPool.lastAum.eq(ZERO));
935+
936+
// Deposit here to DLP to make sure aum calc work with perp market debt
937+
await overWriteMintAccount(
938+
bankrunContextWrapper,
939+
lpPool.mint,
940+
BigInt(lpPool.lastAum.toNumber())
941+
);
942+
await adminClient.lpPoolAddLiquidity({
943+
lpPool,
944+
inAmount: new BN(1000).mul(QUOTE_PRECISION),
945+
minMintAmount: new BN(1),
946+
inMarketIndex: 0,
947+
});
948+
949+
await adminClient.updateLpPoolAum(lpPool, [0, 1, 2]);
950+
951+
lpPool = (await adminClient.program.account.lpPool.fetch(
952+
lpPoolKey
953+
)) as LPPoolAccount;
954+
955+
let aum = new BN(0);
956+
for (let i = 0; i <= 2; i++) {
957+
const constituent = (await adminClient.program.account.constituent.fetch(
958+
getConstituentPublicKey(program.programId, lpPoolKey, i)
959+
)) as ConstituentAccount;
960+
aum = aum.add(
961+
constituent.tokenBalance
962+
.mul(constituent.lastOraclePrice)
963+
.div(QUOTE_PRECISION)
964+
);
965+
}
966+
967+
// Overwrite the amm cache with amount owed
968+
ammCache = (await adminClient.program.account.ammCache.fetch(
969+
getAmmCachePublicKey(program.programId)
970+
)) as AmmCache;
971+
for (let i = 0; i <= ammCache.cache.length - 1; i++) {
972+
aum = aum.sub(ammCache.cache[i].quoteOwedFromLp);
973+
}
974+
assert(lpPool.lastAum.eq(aum));
929975
});
930976

931977
it('perp market will transfer with the constituent vault if it should send more than its owed', async () => {
978+
let lpPool = (await adminClient.program.account.lpPool.fetch(
979+
lpPoolKey
980+
)) as LPPoolAccount;
981+
const aumBefore = lpPool.lastAum;
982+
let constituent = (await adminClient.program.account.constituent.fetch(
983+
getConstituentPublicKey(program.programId, lpPoolKey, 0)
984+
)) as ConstituentAccount;
985+
932986
let ammCache = (await adminClient.program.account.ammCache.fetch(
933987
getAmmCachePublicKey(program.programId)
934988
)) as AmmCache;
989+
990+
const balanceBefore = constituent.tokenBalance;
935991
const owedAmount = ammCache.cache[0].quoteOwedFromLp;
936992

937993
// Give the perp market half of its owed amount
@@ -954,11 +1010,16 @@ describe('LP Pool', () => {
9541010
ammCache = (await adminClient.program.account.ammCache.fetch(
9551011
getAmmCachePublicKey(program.programId)
9561012
)) as AmmCache;
957-
const constituent = (await adminClient.program.account.constituent.fetch(
1013+
constituent = (await adminClient.program.account.constituent.fetch(
9581014
getConstituentPublicKey(program.programId, lpPoolKey, 0)
9591015
)) as ConstituentAccount;
9601016

1017+
lpPool = (await adminClient.program.account.lpPool.fetch(
1018+
lpPoolKey
1019+
)) as LPPoolAccount;
1020+
9611021
assert(ammCache.cache[0].quoteOwedFromLp.eq(ZERO));
962-
assert(constituent.tokenBalance.eq(owedAmount));
1022+
assert(constituent.tokenBalance.eq(balanceBefore.add(owedAmount)));
1023+
assert(lpPool.lastAum.eq(aumBefore.add(owedAmount)));
9631024
});
9641025
});

0 commit comments

Comments
 (0)