Skip to content

Commit

Permalink
program: add ability to delete initialized spot market (#998)
Browse files Browse the repository at this point in the history
* program: add ability to delete initialized spot market

* CHANGELOG
  • Loading branch information
crispheaney committed Apr 8, 2024
1 parent d42b066 commit 195089c
Show file tree
Hide file tree
Showing 8 changed files with 403 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Features

- program: rm admins ability to withdraw from if ([#990](https://github.com/drift-labs/protocol-v2/pull/990))
- program: add add ability to delete initialized spot market ([#998](https://github.com/drift-labs/protocol-v2/pull/998))

### Fixes

Expand Down
21 changes: 20 additions & 1 deletion programs/drift/src/controller/token.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::signer::get_signer_seeds;
use anchor_lang::prelude::*;
use anchor_spl::token::{self, Token, TokenAccount, Transfer};
use anchor_spl::token::{self, CloseAccount, Token, TokenAccount, Transfer};

pub fn send_from_program_vault<'info>(
token_program: &Program<'info, Token>,
Expand Down Expand Up @@ -38,3 +38,22 @@ pub fn receive<'info>(
let cpi_context = CpiContext::new(cpi_program, cpi_accounts);
token::transfer(cpi_context, amount)
}

pub fn close_vault<'info>(
token_program: &Program<'info, Token>,
account: &Account<'info, TokenAccount>,
destination: &AccountInfo<'info>,
authority: &AccountInfo<'info>,
nonce: u8,
) -> Result<()> {
let signature_seeds = get_signer_seeds(&nonce);
let signers = &[&signature_seeds[..]];
let cpi_accounts = CloseAccount {
account: account.to_account_info().clone(),
destination: destination.clone(),
authority: authority.to_account_info().clone(),
};
let cpi_program = token_program.to_account_info();
let cpi_context = CpiContext::new_with_signer(cpi_program, cpi_accounts, signers);
token::close_account(cpi_context)
}
108 changes: 108 additions & 0 deletions programs/drift/src/instructions/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use phoenix::quantities::WrapperU64;
use serum_dex::state::ToAlignedBytes;
use solana_program::msg;

use crate::controller::token::close_vault;
use crate::error::ErrorCode;
use crate::instructions::constraints::*;
use crate::load_mut;
Expand Down Expand Up @@ -822,6 +823,84 @@ pub fn handle_delete_initialized_perp_market(
Ok(())
}

pub fn handle_delete_initialized_spot_market(
ctx: Context<DeleteInitializedSpotMarket>,
market_index: u16,
) -> Result<()> {
let mut spot_market = ctx.accounts.spot_market.load()?;
let state = &mut ctx.accounts.state;

// to preserve all protocol invariants, can only remove the last market if it hasn't been "activated"

validate!(
state.number_of_spot_markets - 1 == market_index,
ErrorCode::InvalidMarketAccountforDeletion,
"state.number_of_spot_markets={} != market_index={}",
state.number_of_markets,
market_index
)?;
validate!(
spot_market.status == MarketStatus::Initialized,
ErrorCode::InvalidMarketAccountforDeletion,
"spot_market.status != Initialized",
)?;
validate!(
spot_market.deposit_balance == 0,
ErrorCode::InvalidMarketAccountforDeletion,
"spot_market.number_of_users={} != 0",
spot_market.deposit_balance,
)?;
validate!(
spot_market.borrow_balance == 0,
ErrorCode::InvalidMarketAccountforDeletion,
"spot_market.borrow_balance={} != 0",
spot_market.borrow_balance,
)?;
validate!(
spot_market.market_index == market_index,
ErrorCode::InvalidMarketAccountforDeletion,
"market_index={} != spot_market.market_index={}",
market_index,
spot_market.market_index
)?;

safe_decrement!(state.number_of_spot_markets, 1);

drop(spot_market);

validate!(
ctx.accounts.spot_market_vault.amount == 0,
ErrorCode::InvalidMarketAccountforDeletion,
"ctx.accounts.spot_market_vault.amount={}",
ctx.accounts.spot_market_vault.amount
)?;

close_vault(
&ctx.accounts.token_program,
&ctx.accounts.spot_market_vault,
&ctx.accounts.admin.to_account_info(),
&ctx.accounts.drift_signer,
state.signer_nonce,
)?;

validate!(
ctx.accounts.insurance_fund_vault.amount == 0,
ErrorCode::InvalidMarketAccountforDeletion,
"ctx.accounts.insurance_fund_vault.amount={}",
ctx.accounts.insurance_fund_vault.amount
)?;

close_vault(
&ctx.accounts.token_program,
&ctx.accounts.insurance_fund_vault,
&ctx.accounts.admin.to_account_info(),
&ctx.accounts.drift_signer,
state.signer_nonce,
)?;

Ok(())
}

#[access_control(
spot_market_valid(&ctx.accounts.spot_market)
)]
Expand Down Expand Up @@ -2575,6 +2654,35 @@ pub struct InitializeSpotMarket<'info> {
pub token_program: Program<'info, Token>,
}

#[derive(Accounts)]
#[instruction(market_index: u16)]
pub struct DeleteInitializedSpotMarket<'info> {
#[account(mut)]
pub admin: Signer<'info>,
#[account(
mut,
has_one = admin
)]
pub state: Box<Account<'info, State>>,
#[account(mut, close = admin)]
pub spot_market: AccountLoader<'info, SpotMarket>,
#[account(
mut,
seeds = [b"spot_market_vault".as_ref(), market_index.to_le_bytes().as_ref()],
bump,
)]
pub spot_market_vault: Box<Account<'info, TokenAccount>>,
#[account(
mut,
seeds = [b"insurance_fund_vault".as_ref(), market_index.to_le_bytes().as_ref()],
bump,
)]
pub insurance_fund_vault: Box<Account<'info, TokenAccount>>,
/// CHECK: program signer
pub drift_signer: AccountInfo<'info>,
pub token_program: Program<'info, Token>,
}

#[derive(Accounts)]
#[instruction(market_index: u16)]
pub struct InitializeSerumFulfillmentConfig<'info> {
Expand Down
7 changes: 7 additions & 0 deletions programs/drift/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,13 @@ pub mod drift {
)
}

pub fn delete_initialized_spot_market(
ctx: Context<DeleteInitializedSpotMarket>,
market_index: u16,
) -> Result<()> {
handle_delete_initialized_spot_market(ctx, market_index)
}

pub fn initialize_serum_fulfillment_config(
ctx: Context<InitializeSerumFulfillmentConfig>,
market_index: u16,
Expand Down
49 changes: 49 additions & 0 deletions sdk/src/adminClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,55 @@ export class AdminClient extends DriftClient {
return initializeIx;
}

public async deleteInitializedSpotMarket(
marketIndex: number
): Promise<TransactionSignature> {
const deleteInitializeMarketIx =
await this.getDeleteInitializedSpotMarketIx(marketIndex);

const tx = await this.buildTransaction(deleteInitializeMarketIx);

const { txSig } = await this.sendTransaction(tx, [], this.opts);

return txSig;
}

public async getDeleteInitializedSpotMarketIx(
marketIndex: number
): Promise<TransactionInstruction> {
const spotMarketPublicKey = await getSpotMarketPublicKey(
this.program.programId,
marketIndex
);

const spotMarketVaultPublicKey = await getSpotMarketVaultPublicKey(
this.program.programId,
marketIndex
);

const insuranceFundVaultPublicKey = await getInsuranceFundVaultPublicKey(
this.program.programId,
marketIndex
);

return await this.program.instruction.deleteInitializedSpotMarket(
marketIndex,
{
accounts: {
state: await this.getStatePublicKey(),
admin: this.isSubscribed
? this.getStateAccount().admin
: this.wallet.publicKey,
spotMarket: spotMarketPublicKey,
spotMarketVault: spotMarketVaultPublicKey,
insuranceFundVault: insuranceFundVaultPublicKey,
driftSigner: this.getSignerPublicKey(),
tokenProgram: TOKEN_PROGRAM_ID,
},
}
);
}

public async initializeSerumFulfillmentConfig(
marketIndex: number,
serumMarket: PublicKey,
Expand Down
46 changes: 46 additions & 0 deletions sdk/src/idl/drift.json
Original file line number Diff line number Diff line change
Expand Up @@ -2696,6 +2696,52 @@
}
]
},
{
"name": "deleteInitializedSpotMarket",
"accounts": [
{
"name": "admin",
"isMut": true,
"isSigner": true
},
{
"name": "state",
"isMut": true,
"isSigner": false
},
{
"name": "spotMarket",
"isMut": true,
"isSigner": false
},
{
"name": "spotMarketVault",
"isMut": true,
"isSigner": false
},
{
"name": "insuranceFundVault",
"isMut": true,
"isSigner": false
},
{
"name": "driftSigner",
"isMut": false,
"isSigner": false
},
{
"name": "tokenProgram",
"isMut": false,
"isSigner": false
}
],
"args": [
{
"name": "marketIndex",
"type": "u16"
}
]
},
{
"name": "initializeSerumFulfillmentConfig",
"accounts": [
Expand Down
1 change: 1 addition & 0 deletions test-scripts/run-anchor-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ if [ "$1" != "--skip-build" ]; then
fi

test_files=(
deleteInitializedSpotMarket.ts
multipleSpotMakerOrders.ts
switchboardTxCus.ts
prelisting.ts
Expand Down
Loading

0 comments on commit 195089c

Please sign in to comment.