Skip to content
Merged
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
10 changes: 1 addition & 9 deletions programs/drift/src/ids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,4 @@ pub mod amm_spread_adjust_wallet {
declare_id!("w1DrTeayRMutAiwzfJfK9zLcpkF7RzwPy1BLCgQA1aF");
#[cfg(feature = "anchor-test")]
declare_id!("1ucYHAGrBbi1PaecC4Ptq5ocZLWGLBmbGWysoDGNB1N");
}

#[cfg(not(feature = "mainnet-beta"))]
pub const DLP_WHITELIST: [Pubkey; 2] = [
pubkey!("4rmhwytmKH1XsgGAUyUUH7U64HS5FtT6gM8HGKAfwcFE"),
pubkey!("1ucYHAGrBbi1PaecC4Ptq5ocZLWGLBmbGWysoDGNB1N"),
];
#[cfg(feature = "mainnet-beta")]
pub const DLP_WHITELIST: [Pubkey; 1] = [pubkey!("1ucYHAGrBbi1PaecC4Ptq5ocZLWGLBmbGWysoDGNB1N")];
}
8 changes: 8 additions & 0 deletions programs/drift/src/instructions/lp_admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub fn handle_initialize_lp_pool(
revenue_rebalance_period: u64,
max_aum: u128,
max_settle_quote_amount_per_market: u64,
whitelist_mint: Pubkey,
) -> Result<()> {
let lp_key = ctx.accounts.lp_pool.key();
let mut lp_pool = ctx.accounts.lp_pool.load_init()?;
Expand Down Expand Up @@ -81,6 +82,7 @@ pub fn handle_initialize_lp_pool(
volatility: 4,
xi: 2,
padding: 0,
whitelist_mint,
};

let amm_constituent_mapping = &mut ctx.accounts.amm_constituent_mapping;
Expand Down Expand Up @@ -349,6 +351,7 @@ pub struct LpPoolParams {
pub volatility: Option<u64>,
pub gamma_execution: Option<u8>,
pub xi: Option<u8>,
pub whitelist_mint: Option<Pubkey>,
}

pub fn handle_update_lp_pool_params<'info>(
Expand Down Expand Up @@ -385,6 +388,11 @@ pub fn handle_update_lp_pool_params<'info>(
lp_pool.xi = xi;
}

if let Some(whitelist_mint) = lp_pool_params.whitelist_mint {
msg!("whitelist_mint: {:?} -> {:?}", lp_pool.whitelist_mint, whitelist_mint);
lp_pool.whitelist_mint = whitelist_mint;
}

Ok(())
}

Expand Down
19 changes: 11 additions & 8 deletions programs/drift/src/instructions/lp_pool.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use anchor_lang::{prelude::*, Accounts, Key, Result};
use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface};

use crate::ids::DLP_WHITELIST;
use crate::math::constants::{PERCENTAGE_PRECISION, PRICE_PRECISION_I64};
use crate::validation::whitelist::validate_whitelist_token;
use crate::{
controller::{
self,
Expand Down Expand Up @@ -46,7 +46,7 @@ use crate::{

use solana_program::sysvar::clock::Clock;

use super::optional_accounts::{load_maps, AccountMaps};
use super::optional_accounts::{load_maps, AccountMaps, get_whitelist_token};
use crate::controller::spot_balance::update_spot_market_cumulative_interest;
use crate::controller::token::{receive, send_from_program_vault_with_signature_seeds};
use crate::instructions::constraints::*;
Expand Down Expand Up @@ -603,12 +603,6 @@ pub fn handle_lp_pool_add_liquidity<'c: 'info, 'info>(
in_amount: u128,
min_mint_amount: u64,
) -> Result<()> {
#[cfg(not(feature = "anchor-test"))]
validate!(
DLP_WHITELIST.contains(&ctx.accounts.authority.key()),
ErrorCode::UnauthorizedDlpAuthority,
"User is not whitelisted for DLP deposits"
)?;
let state = &ctx.accounts.state;

validate!(
Expand Down Expand Up @@ -659,6 +653,15 @@ pub fn handle_lp_pool_add_liquidity<'c: 'info, 'info>(
Some(state.oracle_guard_rails),
)?;

let whitelist_mint = &lp_pool.whitelist_mint;
if !whitelist_mint.eq(&Pubkey::default()) {
validate_whitelist_token(
get_whitelist_token(remaining_accounts)?,
whitelist_mint,
&ctx.accounts.authority.key(),
)?;
}

let mut in_spot_market = spot_market_map.get_ref_mut(&in_market_index)?;

let in_oracle_id = in_spot_market.oracle_id();
Expand Down
2 changes: 2 additions & 0 deletions programs/drift/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1775,6 +1775,7 @@ pub mod drift {
revenue_rebalance_period: u64,
max_aum: u128,
max_settle_quote_amount_per_market: u64,
whitelist_mint: Pubkey,
) -> Result<()> {
handle_initialize_lp_pool(
ctx,
Expand All @@ -1784,6 +1785,7 @@ pub mod drift {
revenue_rebalance_period,
max_aum,
max_settle_quote_amount_per_market,
whitelist_mint,
)
}

Expand Down
4 changes: 3 additions & 1 deletion programs/drift/src/state/lp_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ pub struct LPPool {
pub pubkey: Pubkey,
// vault token mint
pub mint: Pubkey, // 32, 96
// whitelist mint
pub whitelist_mint: Pubkey,
// constituent target base pubkey
pub constituent_target_base: Pubkey,
// constituent correlations pubkey
Expand Down Expand Up @@ -119,7 +121,7 @@ pub struct LPPool {
}

impl Size for LPPool {
const SIZE: usize = 328;
const SIZE: usize = 360;
}

impl LPPool {
Expand Down
16 changes: 13 additions & 3 deletions sdk/src/adminClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4943,7 +4943,8 @@ export class AdminClient extends DriftClient {
revenueRebalancePeriod: BN,
maxAum: BN,
maxSettleQuoteAmountPerMarket: BN,
mint: Keypair
mint: Keypair,
whitelistMint?: PublicKey
): Promise<TransactionSignature> {
const ixs = await this.getInitializeLpPoolIx(
name,
Expand All @@ -4952,7 +4953,8 @@ export class AdminClient extends DriftClient {
revenueRebalancePeriod,
maxAum,
maxSettleQuoteAmountPerMarket,
mint
mint,
whitelistMint
);
const tx = await this.buildTransaction(ixs);
const { txSig } = await this.sendTransaction(tx, [mint]);
Expand All @@ -4966,7 +4968,8 @@ export class AdminClient extends DriftClient {
revenueRebalancePeriod: BN,
maxAum: BN,
maxSettleQuoteAmountPerMarket: BN,
mint: Keypair
mint: Keypair,
whitelistMint?: PublicKey
): Promise<TransactionInstruction[]> {
const lpPool = getLpPoolPublicKey(this.program.programId, encodeName(name));
const ammConstituentMapping = getAmmConstituentMappingPublicKey(
Expand Down Expand Up @@ -5007,6 +5010,7 @@ export class AdminClient extends DriftClient {
revenueRebalancePeriod,
maxAum,
maxSettleQuoteAmountPerMarket,
whitelistMint ?? PublicKey.default,
{
accounts: {
admin: this.wallet.publicKey,
Expand Down Expand Up @@ -5234,6 +5238,10 @@ export class AdminClient extends DriftClient {
lpPoolName: number[],
updateLpPoolParams: {
maxSettleQuoteAmount?: BN;
volatility?: BN;
gammaExecution?: number;
xi?: number;
whitelistMint?: PublicKey;
}
): Promise<TransactionSignature> {
const ixs = await this.getUpdateLpPoolParamsIx(
Expand All @@ -5252,6 +5260,7 @@ export class AdminClient extends DriftClient {
volatility?: BN;
gammaExecution?: number;
xi?: number;
whitelistMint?: PublicKey;
}
): Promise<TransactionInstruction[]> {
const lpPool = getLpPoolPublicKey(this.program.programId, lpPoolName);
Expand All @@ -5263,6 +5272,7 @@ export class AdminClient extends DriftClient {
volatility: null,
gammaExecution: null,
xi: null,
whitelistMint: null,
},
updateLpPoolParams
),
Expand Down
12 changes: 12 additions & 0 deletions sdk/src/driftClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10667,6 +10667,18 @@ export class DriftClient {
lpPool.pubkey
);

if (!lpPool.whitelistMint.equals(PublicKey.default)) {
const associatedTokenPublicKey = await getAssociatedTokenAddress(
lpPool.whitelistMint,
this.wallet.publicKey
);
remainingAccounts.push({
pubkey: associatedTokenPublicKey,
isWritable: false,
isSigner: false,
});
}

const lpPoolAddLiquidityIx = this.program.instruction.lpPoolAddLiquidity(
inMarketIndex,
inAmount,
Expand Down
14 changes: 14 additions & 0 deletions sdk/src/idl/drift.json
Original file line number Diff line number Diff line change
Expand Up @@ -7433,6 +7433,10 @@
{
"name": "maxSettleQuoteAmountPerMarket",
"type": "u64"
},
{
"name": "whitelistMint",
"type": "publicKey"
}
]
},
Expand Down Expand Up @@ -9617,6 +9621,10 @@
"name": "mint",
"type": "publicKey"
},
{
"name": "whitelistMint",
"type": "publicKey"
},
{
"name": "constituentTargetBase",
"type": "publicKey"
Expand Down Expand Up @@ -11807,6 +11815,12 @@
"type": {
"option": "u8"
}
},
{
"name": "whitelistMint",
"type": {
"option": "publicKey"
}
}
]
}
Expand Down
1 change: 1 addition & 0 deletions sdk/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1666,6 +1666,7 @@ export type LPPoolAccount = {
cumulativeQuoteSentToPerpMarkets: BN;
cumulativeQuoteReceivedFromPerpMarkets: BN;
constituents: number;
whitelistMint: PublicKey;
};

export type ConstituentSpotBalance = {
Expand Down
100 changes: 93 additions & 7 deletions tests/lpPool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import {
Keypair,
LAMPORTS_PER_SOL,
PublicKey,
SystemProgram,
Transaction,
} from '@solana/web3.js';
import { getAssociatedTokenAddress, getMint } from '@solana/spl-token';
import { createAssociatedTokenAccountIdempotentInstruction, createAssociatedTokenAccountInstruction, createInitializeMint2Instruction, createMintToInstruction, getAssociatedTokenAddress, getAssociatedTokenAddressSync, getMint, MINT_SIZE, TOKEN_PROGRAM_ID } from '@solana/spl-token';

import {
BN,
Expand Down Expand Up @@ -110,16 +111,12 @@ describe('LP Pool', () => {
encodeName(lpPoolName)
);

let whitelistMint: PublicKey;

before(async () => {
const context = await startAnchor(
'',
[
{
name: 'token_2022',
programId: new PublicKey(
'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb'
),
},
],
[
{
Expand Down Expand Up @@ -282,6 +279,32 @@ describe('LP Pool', () => {
.getActivePerpPositions()
.filter((x) => !x.baseAssetAmount.eq(ZERO)).length == 2
);

console.log('create whitelist mint');
const whitelistKeypair = Keypair.generate();
const transaction = new Transaction().add(
SystemProgram.createAccount({
fromPubkey: bankrunContextWrapper.provider.wallet.publicKey,
newAccountPubkey: whitelistKeypair.publicKey,
space: MINT_SIZE,
lamports: 10_000_000_000,
programId: TOKEN_PROGRAM_ID,
}),
createInitializeMint2Instruction(
whitelistKeypair.publicKey,
0,
bankrunContextWrapper.provider.wallet.publicKey,
bankrunContextWrapper.provider.wallet.publicKey,
TOKEN_PROGRAM_ID
)
);

await bankrunContextWrapper.sendTransaction(transaction, [whitelistKeypair]);

const whitelistMintInfo = await bankrunContextWrapper.connection.getAccountInfo(whitelistKeypair.publicKey)
console.log('whitelistMintInfo', whitelistMintInfo);

whitelistMint = whitelistKeypair.publicKey;
});

after(async () => {
Expand Down Expand Up @@ -1551,4 +1574,67 @@ describe('LP Pool', () => {
new BN(500).mul(new BN(10 ** 9))
);
});

it('whitelist mint', async () => {
await adminClient.updateLpPoolParams(encodeName(lpPoolName), {
whitelistMint: whitelistMint,
});

const lpPool = await adminClient.getLpPoolAccount(encodeName(lpPoolName));
assert(lpPool.whitelistMint.equals(whitelistMint));

console.log('lpPool.whitelistMint', lpPool.whitelistMint.toString());

const tx = new Transaction();
tx.add(await adminClient.getUpdateLpPoolAumIxs(lpPool, [0, 1, 2, 3]));
tx.add(
...(await adminClient.getLpPoolAddLiquidityIx({
lpPool,
inAmount: new BN(1000).mul(QUOTE_PRECISION),
minMintAmount: new BN(1),
inMarketIndex: 0,
}))
);
try {
await adminClient.sendTransaction(tx);
assert(false, 'Should have thrown');

} catch (e) {
assert(e.toString().includes('0x1789')); // invalid whitelist token
}

const whitelistMintAta = getAssociatedTokenAddressSync(
whitelistMint,
adminClient.wallet.publicKey,
);
const ix = createAssociatedTokenAccountInstruction(
bankrunContextWrapper.context.payer.publicKey,
whitelistMintAta,
adminClient.wallet.publicKey,
whitelistMint,
);
const mintToIx = createMintToInstruction(
whitelistMint,
whitelistMintAta,
bankrunContextWrapper.provider.wallet.publicKey,
1,
);
await bankrunContextWrapper.sendTransaction(
new Transaction().add(ix, mintToIx)
);

const txAfter = new Transaction();
txAfter.add(await adminClient.getUpdateLpPoolAumIxs(lpPool, [0, 1, 2, 3]));
txAfter.add(
...(await adminClient.getLpPoolAddLiquidityIx({
lpPool,
inAmount: new BN(1000).mul(QUOTE_PRECISION),
minMintAmount: new BN(1),
inMarketIndex: 0,
}))
);

// successfully call add liquidity
await adminClient.sendTransaction(txAfter);
});
});