Skip to content

Commit 8cd14cf

Browse files
committed
Merge branch 'dlp' into devnet
2 parents e6e3999 + 53a5009 commit 8cd14cf

File tree

8 files changed

+208
-50
lines changed

8 files changed

+208
-50
lines changed

programs/drift/src/instructions/lp_pool.rs

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ use anchor_lang::{prelude::*, Accounts, Key, Result};
22
use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface};
33

44
use crate::ids::lp_pool_swap_wallet;
5-
use crate::math::constants::{PERCENTAGE_PRECISION, PRICE_PRECISION_I64};
5+
use crate::math::constants::PRICE_PRECISION_I64;
66
use crate::math::oracle::OracleValidity;
7+
use crate::state::events::{DepositDirection, LPBorrowLendDepositRecord};
78
use crate::state::paused_operations::ConstituentLpOperation;
89
use crate::validation::whitelist::validate_whitelist_token;
910
use crate::{
@@ -26,7 +27,7 @@ use crate::{
2627
state::{
2728
amm_cache::{AmmCacheFixed, CacheInfo, AMM_POSITIONS_CACHE},
2829
constituent_map::{ConstituentMap, ConstituentSet},
29-
events::{emit_stack, LPMintRedeemRecord, LPSettleRecord, LPSwapRecord},
30+
events::{emit_stack, LPMintRedeemRecord, LPSwapRecord},
3031
lp_pool::{
3132
update_constituent_target_base_for_derivatives, AmmConstituentDatum,
3233
AmmConstituentMappingFixed, Constituent, ConstituentCorrelationsFixed,
@@ -1369,6 +1370,8 @@ pub fn handle_deposit_to_program_vault<'c: 'info, 'info>(
13691370
)?;
13701371
let remaining_accounts = &mut ctx.remaining_accounts.iter().peekable();
13711372

1373+
let mut constituent = ctx.accounts.constituent.load_mut()?;
1374+
13721375
if amount == 0 {
13731376
return Err(ErrorCode::InsufficientDeposit.into());
13741377
}
@@ -1382,8 +1385,14 @@ pub fn handle_deposit_to_program_vault<'c: 'info, 'info>(
13821385
Some(&oracle_data),
13831386
clock.unix_timestamp,
13841387
)?;
1388+
let token_balance_after_cumulative_interest_update = constituent
1389+
.spot_balance
1390+
.get_signed_token_amount(&spot_market)?;
1391+
1392+
let interest_accrued_token_amount = token_balance_after_cumulative_interest_update
1393+
.cast::<i64>()?
1394+
.safe_sub(constituent.last_spot_balance_token_amount)?;
13851395

1386-
let mut constituent = ctx.accounts.constituent.load_mut()?;
13871396
if constituent.last_oracle_slot < oracle_data_slot {
13881397
constituent.last_oracle_price = oracle_data.price;
13891398
constituent.last_oracle_slot = oracle_data_slot;
@@ -1454,6 +1463,27 @@ pub fn handle_deposit_to_program_vault<'c: 'info, 'info>(
14541463
"Constituent balance mismatch after withdraw from program vault"
14551464
)?;
14561465

1466+
let new_token_balance = constituent
1467+
.spot_balance
1468+
.get_signed_token_amount(&spot_market)?
1469+
.cast::<i64>()?;
1470+
1471+
emit!(LPBorrowLendDepositRecord {
1472+
ts: clock.unix_timestamp,
1473+
slot: clock.slot,
1474+
spot_market_index: spot_market.market_index,
1475+
constituent_index: constituent.constituent_index,
1476+
direction: DepositDirection::Deposit,
1477+
token_balance: new_token_balance,
1478+
last_token_balance: constituent.last_spot_balance_token_amount,
1479+
interest_accrued_token_amount,
1480+
amount_deposit_withdraw: amount,
1481+
});
1482+
constituent.last_spot_balance_token_amount = new_token_balance;
1483+
constituent.cumulative_spot_interest_accrued_token_amount = constituent
1484+
.cumulative_spot_interest_accrued_token_amount
1485+
.safe_add(interest_accrued_token_amount)?;
1486+
14571487
Ok(())
14581488
}
14591489

@@ -1474,19 +1504,28 @@ pub fn handle_withdraw_from_program_vault<'c: 'info, 'info>(
14741504
)?;
14751505
let remaining_accounts = &mut ctx.remaining_accounts.iter().peekable();
14761506

1507+
let mut constituent = ctx.accounts.constituent.load_mut()?;
1508+
14771509
if amount == 0 {
14781510
return Err(ErrorCode::InsufficientDeposit.into());
14791511
}
14801512

14811513
let oracle_data = oracle_map.get_price_data(&oracle_id)?;
14821514
let oracle_data_slot = clock.slot - oracle_data.delay.max(0i64).cast::<u64>()?;
1515+
14831516
controller::spot_balance::update_spot_market_cumulative_interest(
14841517
&mut spot_market,
14851518
Some(&oracle_data),
14861519
clock.unix_timestamp,
14871520
)?;
1521+
let token_balance_after_cumulative_interest_update = constituent
1522+
.spot_balance
1523+
.get_signed_token_amount(&spot_market)?;
1524+
1525+
let interest_accrued_token_amount = token_balance_after_cumulative_interest_update
1526+
.cast::<i64>()?
1527+
.safe_sub(constituent.last_spot_balance_token_amount)?;
14881528

1489-
let mut constituent = ctx.accounts.constituent.load_mut()?;
14901529
if constituent.last_oracle_slot < oracle_data_slot {
14911530
constituent.last_oracle_price = oracle_data.price;
14921531
constituent.last_oracle_slot = oracle_data_slot;
@@ -1507,6 +1546,27 @@ pub fn handle_withdraw_from_program_vault<'c: 'info, 'info>(
15071546
Some(remaining_accounts),
15081547
)?;
15091548

1549+
let new_token_balance = constituent
1550+
.spot_balance
1551+
.get_signed_token_amount(&spot_market)?
1552+
.cast::<i64>()?;
1553+
1554+
emit!(LPBorrowLendDepositRecord {
1555+
ts: clock.unix_timestamp,
1556+
slot: clock.slot,
1557+
spot_market_index: spot_market.market_index,
1558+
constituent_index: constituent.constituent_index,
1559+
direction: DepositDirection::Withdraw,
1560+
token_balance: new_token_balance,
1561+
last_token_balance: constituent.last_spot_balance_token_amount,
1562+
interest_accrued_token_amount,
1563+
amount_deposit_withdraw: amount,
1564+
});
1565+
constituent.last_spot_balance_token_amount = new_token_balance;
1566+
constituent.cumulative_spot_interest_accrued_token_amount = constituent
1567+
.cumulative_spot_interest_accrued_token_amount
1568+
.safe_add(interest_accrued_token_amount)?;
1569+
15101570
Ok(())
15111571
}
15121572

programs/drift/src/state/constituent_map.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ impl<'a> ConstituentMap<'a> {
132132
"Constituent lp pool pubkey does not match lp pool pubkey"
133133
)?;
134134

135-
// constituent index 276 bytes from front of account
136-
let constituent_index = u16::from_le_bytes(*array_ref![data, 292, 2]);
135+
// constituent index 308 bytes from front of account
136+
let constituent_index = u16::from_le_bytes(*array_ref![data, 308, 2]);
137137
if constituent_map.0.contains_key(&constituent_index) {
138138
msg!(
139139
"Can not include same constituent index twice {}",
@@ -183,7 +183,7 @@ impl<'a> ConstituentMap<'a> {
183183
}
184184

185185
// market index 1160 bytes from front of account
186-
let constituent_index = u16::from_le_bytes(*array_ref![data, 292, 2]);
186+
let constituent_index = u16::from_le_bytes(*array_ref![data, 308, 2]);
187187

188188
let is_writable = account_info.is_writable;
189189
let account_loader: AccountLoader<Constituent> =
@@ -221,7 +221,7 @@ impl<'a> ConstituentMap<'a> {
221221
return Err(ErrorCode::ConstituentCouldNotLoad);
222222
}
223223

224-
let constituent_index = u16::from_le_bytes(*array_ref![data, 292, 2]);
224+
let constituent_index = u16::from_le_bytes(*array_ref![data, 308, 2]);
225225

226226
if constituent_map.0.contains_key(&constituent_index) {
227227
msg!(

programs/drift/src/state/events.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -873,3 +873,21 @@ pub struct LPMintRedeemRecord {
873873
impl Size for LPMintRedeemRecord {
874874
const SIZE: usize = 328;
875875
}
876+
877+
#[event]
878+
#[derive(Default)]
879+
pub struct LPBorrowLendDepositRecord {
880+
pub ts: i64,
881+
pub slot: u64,
882+
pub spot_market_index: u16,
883+
pub constituent_index: u16,
884+
pub direction: DepositDirection,
885+
pub token_balance: i64,
886+
pub last_token_balance: i64,
887+
pub interest_accrued_token_amount: i64,
888+
pub amount_deposit_withdraw: u64,
889+
}
890+
891+
impl Size for LPBorrowLendDepositRecord {
892+
const SIZE: usize = 72;
893+
}

programs/drift/src/state/lp_pool.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,9 @@ pub struct Constituent {
785785
/// spot borrow-lend balance for constituent
786786
pub spot_balance: ConstituentSpotBalance, // should be in constituent base asset
787787

788+
pub last_spot_balance_token_amount: i64, // token precision
789+
pub cumulative_spot_interest_accrued_token_amount: i64, // token precision
790+
788791
/// max deviation from target_weight allowed for the constituent
789792
/// precision: PERCENTAGE_PRECISION
790793
pub max_weight_deviation: i64,
@@ -844,7 +847,7 @@ pub struct Constituent {
844847
}
845848

846849
impl Size for Constituent {
847-
const SIZE: usize = 304;
850+
const SIZE: usize = 320;
848851
}
849852

850853
#[derive(BitFlags, Clone, Copy, PartialEq, Debug, Eq)]

programs/drift/src/state/lp_pool/tests.rs

Lines changed: 47 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,14 +1047,14 @@ mod swap_tests {
10471047
#[test]
10481048
fn test_get_remove_liquidity_mint_amount_with_existing_aum_6_decimals_large_aum() {
10491049
get_remove_liquidity_mint_amount_scenario(
1050-
100_000_000_000 * 1_000_000, // last_aum ($100,000,000,000)
1051-
0, // now
1052-
6, // in_decimals
1053-
100_000_000_000 * 1_000_000, // in_amount
1054-
100_000_000_000 * 1_000_000, // dlp_total_supply
1055-
99990000000000000, // expected_out_amount
1056-
10000000000000, // expected_lp_fee
1057-
349765020000000, // expected_out_fee_amount
1050+
100_000_000_000 * 1_000_000, // last_aum ($100,000,000,000)
1051+
0, // now
1052+
6, // in_decimals
1053+
100_000_000_000 * 1_000_000 - 1_000_000, // Leave in QUOTE AMOUNT
1054+
100_000_000_000 * 1_000_000, // dlp_total_supply
1055+
99989999900000000, // expected_out_amount
1056+
9999999999900, // expected_lp_fee
1057+
349765019650200, // expected_out_fee_amount
10581058
1,
10591059
2,
10601060
2,
@@ -1065,14 +1065,14 @@ mod swap_tests {
10651065
#[test]
10661066
fn test_get_remove_liquidity_mint_amount_with_existing_aum_8_decimals_large_aum() {
10671067
get_remove_liquidity_mint_amount_scenario(
1068-
10_000_000_000_000_000, // last_aum ($10,000,000,000)
1069-
0, // now
1070-
8, // in_decimals
1071-
10_000_000_000 * 100_000_000, // in_amount
1072-
10_000_000_000 * 1_000_000, // dlp_total_supply
1073-
9_999_000_000_000_000_0000, // expected_out_amount
1074-
100000000000000, // expected_lp_fee
1075-
3764623500000000000, // expected_out_fee_amount
1068+
10_000_000_000_000_000, // last_aum ($10,000,000,000)
1069+
0, // now
1070+
8, // in_decimals
1071+
10_000_000_000 * 1_000_000 - 1_000_000, // in_amount
1072+
10_000_000_000 * 1_000_000, // dlp_total_supply
1073+
999899999000000000, // expected_out_amount
1074+
(10_000_000_000 * 1_000_000 - 1_000_000) / 10000, // expected_lp_fee
1075+
3497650196502000, // expected_out_fee_amount
10761076
1,
10771077
2,
10781078
2,
@@ -1540,6 +1540,7 @@ mod swap_fee_tests {
15401540

15411541
#[cfg(test)]
15421542
mod settle_tests {
1543+
use crate::math::constants::{QUOTE_PRECISION, QUOTE_PRECISION_I64, QUOTE_PRECISION_U64};
15431544
use crate::math::lp_pool::perp_lp_pool_settlement::{
15441545
calculate_settlement_amount, update_cache_info, SettlementContext, SettlementDirection,
15451546
SettlementResult,
@@ -1570,35 +1571,38 @@ mod settle_tests {
15701571
#[test]
15711572
fn test_lp_to_perp_settlement_sufficient_balance() {
15721573
let ctx = SettlementContext {
1573-
quote_owed_from_lp: 500,
1574-
quote_constituent_token_balance: 1000,
1575-
fee_pool_balance: 300,
1576-
pnl_pool_balance: 200,
1574+
quote_owed_from_lp: 500 * QUOTE_PRECISION_I64,
1575+
quote_constituent_token_balance: 1000 * QUOTE_PRECISION_U64,
1576+
fee_pool_balance: 300 * QUOTE_PRECISION,
1577+
pnl_pool_balance: 200 * QUOTE_PRECISION,
15771578
quote_market: &create_mock_spot_market(),
1578-
max_settle_quote_amount: 10000,
1579+
max_settle_quote_amount: 10000 * QUOTE_PRECISION_U64,
15791580
};
15801581

15811582
let result = calculate_settlement_amount(&ctx).unwrap();
15821583
assert_eq!(result.direction, SettlementDirection::FromLpPool);
1583-
assert_eq!(result.amount_transferred, 500);
1584+
assert_eq!(result.amount_transferred, 500 * QUOTE_PRECISION_U64);
15841585
assert_eq!(result.fee_pool_used, 0);
15851586
assert_eq!(result.pnl_pool_used, 0);
15861587
}
15871588

15881589
#[test]
15891590
fn test_lp_to_perp_settlement_insufficient_balance() {
15901591
let ctx = SettlementContext {
1591-
quote_owed_from_lp: 1500,
1592-
quote_constituent_token_balance: 1000,
1593-
fee_pool_balance: 300,
1594-
pnl_pool_balance: 200,
1592+
quote_owed_from_lp: 1500 * QUOTE_PRECISION_I64,
1593+
quote_constituent_token_balance: 1000 * QUOTE_PRECISION_U64,
1594+
fee_pool_balance: 300 * QUOTE_PRECISION,
1595+
pnl_pool_balance: 200 * QUOTE_PRECISION,
15951596
quote_market: &create_mock_spot_market(),
1596-
max_settle_quote_amount: 10000,
1597+
max_settle_quote_amount: 10000 * QUOTE_PRECISION_U64,
15971598
};
15981599

15991600
let result = calculate_settlement_amount(&ctx).unwrap();
16001601
assert_eq!(result.direction, SettlementDirection::FromLpPool);
1601-
assert_eq!(result.amount_transferred, 1000); // Limited by LP balance
1602+
assert_eq!(
1603+
result.amount_transferred,
1604+
1000 * QUOTE_PRECISION_U64 - QUOTE_PRECISION_U64
1605+
); // Limited by LP balance
16021606
}
16031607

16041608
#[test]
@@ -1809,17 +1813,20 @@ mod settle_tests {
18091813
fn test_exact_boundary_settlements() {
18101814
// Test when quote_owed exactly equals LP balance
18111815
let ctx = SettlementContext {
1812-
quote_owed_from_lp: 1000,
1813-
quote_constituent_token_balance: 1000,
1814-
fee_pool_balance: 500,
1815-
pnl_pool_balance: 300,
1816+
quote_owed_from_lp: 1000 * QUOTE_PRECISION_I64,
1817+
quote_constituent_token_balance: 1000 * QUOTE_PRECISION_U64,
1818+
fee_pool_balance: 500 * QUOTE_PRECISION,
1819+
pnl_pool_balance: 300 * QUOTE_PRECISION,
18161820
quote_market: &create_mock_spot_market(),
1817-
max_settle_quote_amount: 10000,
1821+
max_settle_quote_amount: 10000 * QUOTE_PRECISION_U64,
18181822
};
18191823

18201824
let result = calculate_settlement_amount(&ctx).unwrap();
18211825
assert_eq!(result.direction, SettlementDirection::FromLpPool);
1822-
assert_eq!(result.amount_transferred, 1000);
1826+
assert_eq!(
1827+
result.amount_transferred,
1828+
1000 * QUOTE_PRECISION_U64 - QUOTE_PRECISION_U64
1829+
); // Leave QUOTE PRECISION
18231830

18241831
// Test when negative quote_owed exactly equals total pool balance
18251832
let ctx = SettlementContext {
@@ -1852,7 +1859,7 @@ mod settle_tests {
18521859

18531860
let result = calculate_settlement_amount(&ctx).unwrap();
18541861
assert_eq!(result.direction, SettlementDirection::FromLpPool);
1855-
assert_eq!(result.amount_transferred, 1);
1862+
assert_eq!(result.amount_transferred, 0); // Cannot transfer if less than QUOTE_PRECISION
18561863

18571864
// Test with minimal negative amount
18581865
let ctx = SettlementContext {
@@ -2052,17 +2059,17 @@ mod settle_tests {
20522059
#[test]
20532060
fn test_lp_to_perp_capped_with_max() {
20542061
let ctx = SettlementContext {
2055-
quote_owed_from_lp: 1100,
2056-
quote_constituent_token_balance: 2000,
2062+
quote_owed_from_lp: 1100 * QUOTE_PRECISION_I64,
2063+
quote_constituent_token_balance: 2000 * QUOTE_PRECISION_U64,
20572064
fee_pool_balance: 0, // No fee pool
2058-
pnl_pool_balance: 1200,
2065+
pnl_pool_balance: 1200 * QUOTE_PRECISION,
20592066
quote_market: &create_mock_spot_market(),
2060-
max_settle_quote_amount: 1000,
2067+
max_settle_quote_amount: 1000 * QUOTE_PRECISION_U64,
20612068
};
20622069

20632070
let result = calculate_settlement_amount(&ctx).unwrap();
20642071
assert_eq!(result.direction, SettlementDirection::FromLpPool);
2065-
assert_eq!(result.amount_transferred, 1000);
2072+
assert_eq!(result.amount_transferred, 1000 * QUOTE_PRECISION_U64); // Leave QUOTE PRECISION in the balance
20662073
assert_eq!(result.fee_pool_used, 0);
20672074
assert_eq!(result.pnl_pool_used, 0);
20682075
}

sdk/src/events/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
LPMintRedeemRecord,
2525
LPSettleRecord,
2626
LPSwapRecord,
27+
LPBorrowLendDepositRecord,
2728
} from '../types';
2829
import { EventEmitter } from 'events';
2930

@@ -147,7 +148,8 @@ export type DriftEvent =
147148
| Event<TransferProtocolIfSharesToRevenuePoolRecord>
148149
| Event<LPSettleRecord>
149150
| Event<LPMintRedeemRecord>
150-
| Event<LPSwapRecord>;
151+
| Event<LPSwapRecord>
152+
| Event<LPBorrowLendDepositRecord>;
151153

152154
export interface EventSubscriberEvents {
153155
newEvent: (event: WrappedEvent<EventType>) => void;

0 commit comments

Comments
 (0)