Skip to content

Commit

Permalink
Jli/cli pll claim evict (#31)
Browse files Browse the repository at this point in the history
* add get seat manager info

* add psm claim and evict seat

* add doc comments to claim and evict

* update versions for SDK and PSM

* check for market authority managed by PSM in get seat manager info

* increment version
  • Loading branch information
throwbackjams authored Apr 14, 2023
1 parent c2ca8ab commit 2c94ce1
Show file tree
Hide file tree
Showing 8 changed files with 185 additions and 12 deletions.
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "phoenix-cli"
version = "0.2.4"
version = "0.3.0"
description = "CLI and associated library for interacting with the Phoenix program from the command line"
edition = "2021"
license = "MIT"
Expand Down Expand Up @@ -34,7 +34,8 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
spl-associated-token-account = { version = "1.1.1", features = [ "no-entrypoint" ] }
phoenix-v1 = { version = "0.2.2", features = ["no-entrypoint"] }
phoenix-sdk = "0.3.6"
phoenix-sdk = "0.4.0"
bytemuck = "1.13.0"
reqwest = "0.11.14"
bincode = "1.3.3"
phoenix-seat-manager = "0.1.0"
25 changes: 18 additions & 7 deletions src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ pub enum PhoenixCLICommand {
/// Get the full order book for a given market
GetFullBook { market_pubkey: Pubkey },
/// Get the market events that occured in a given transaction signature
GetTransaction {
signature: Signature,
},
GetTransaction { signature: Signature },
/// Get the current status of a market
GetMarketStatus { market_pubkey: Pubkey },
/// Get the status and address of a seat for a given market and trader
Expand All @@ -47,11 +45,12 @@ pub enum PhoenixCLICommand {
#[clap(short, long, required = false)]
trader_pubkey: Option<Pubkey>,
},
/// Send a transaction on chain to allocate a seat for the payer on the given market. This will cost ~.0018 SOL for rent.
/// Note that the seat will have to then be approved by the market authority.
/// Send a transaction on chain to allocate a seat for the payer on the given market. This will cost ~.0018 SOL for rent.
/// Note that the seat will have to then be approved by the market authority. Only relevant for permissioned markets.
/// For permissionless markets (with an automated seat manager), you can claim a seat with the claim-seat CLI command.
RequestSeat { market_pubkey: Pubkey },
/// Mint tokens to a recipient for a given ticker string (for example SOL or USDC). Default amount is 100_000_000_000.
/// This is only for markets associated with the ellipsis token faucet.
/// This is only for markets associated with the ellipsis token faucet.
MintTokens {
/// Ticker string, example: SOL
mint_ticker: String,
Expand All @@ -62,7 +61,7 @@ pub enum PhoenixCLICommand {
amount: u64,
},
/// Mint both base and quote tokens to a recipient for a given market. Default amounts are 100_000_000_000 for base and 100_000_000 for quote.
/// This is only for markets associated with the ellipsis token faucet.
/// This is only for markets associated with the ellipsis token faucet.
MintTokensForMarket {
market_pubkey: Pubkey,
/// Pubkey of the recipient of the tokens
Expand All @@ -74,4 +73,16 @@ pub enum PhoenixCLICommand {
#[clap(short, long, required = false, default_value = "100000000")]
quote_amount: u64,
},
/// For the given market, get the seat manager data fields, including authority, successor, and designated market makers.
GetSeatManagerInfo { market_pubkey: Pubkey },
/// On the given market, claim a maker seat for the public key of the keypair at the indicated file path.
/// Indicate a different keypair file to use by specifying the file path with flag `-k`.
ClaimSeat { market_pubkey: Pubkey },
/// Evict a trader from the given market if that market's trader state is at capacity.
/// If no trader is given, this function will greedily find a trader to evict.
/// Note that eviction will not work if the market's trader state is not at capacity.
EvictSeat {
market_pubkey: Pubkey,
trader_to_evict: Option<Pubkey>,
},
}
20 changes: 20 additions & 0 deletions src/lib/helpers/market_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use phoenix::state::markets::{Ladder, Market};
use phoenix::state::OrderPacket;

use phoenix_sdk::sdk_client::*;
use phoenix_seat_manager::get_seat_manager_address;
use phoenix_seat_manager::seat_manager::SeatManager;
use solana_account_decoder::UiAccountEncoding;
use solana_client::rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig};
use solana_client::rpc_filter::{Memcmp, MemcmpEncodedBytes, RpcFilterType};
Expand Down Expand Up @@ -202,3 +204,21 @@ pub async fn get_market_header(

Ok(*header)
}

pub async fn get_seat_manager_data_with_market(
client: &EllipsisClient,
market: &Pubkey,
) -> anyhow::Result<SeatManager> {
let seat_manager_address = get_seat_manager_address(market).0;
get_seat_manager_data_with_pubkey(client, &seat_manager_address).await
}

pub async fn get_seat_manager_data_with_pubkey(
client: &EllipsisClient,
seat_manager_pubkey: &Pubkey,
) -> anyhow::Result<SeatManager> {
let seat_manager_account = client.get_account(seat_manager_pubkey).await?;
let seat_manager_data = SeatManager::load(&seat_manager_account.data)?;

Ok(*seat_manager_data)
}
3 changes: 3 additions & 0 deletions src/lib/processor/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
pub mod process_claim_seat;
pub mod process_evict_seat;
pub mod process_get_all_markets;
pub mod process_get_book_levels;
pub mod process_get_full_book;
pub mod process_get_market;
pub mod process_get_market_status;
pub mod process_get_open_orders;
pub mod process_get_seat_info;
pub mod process_get_seat_manager_info;
pub mod process_get_top_of_book;
pub mod process_get_traders_for_market;
pub mod process_get_transaction;
Expand Down
21 changes: 21 additions & 0 deletions src/lib/processor/process_claim_seat.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use ellipsis_client::EllipsisClient;
use phoenix_sdk::utils::create_claim_seat_ix_if_needed;
use solana_sdk::{pubkey::Pubkey, signer::Signer};

pub async fn process_claim_seat(
client: &EllipsisClient,
market_pubkey: &Pubkey,
) -> anyhow::Result<()> {
let claim_seat_ix =
create_claim_seat_ix_if_needed(client, market_pubkey, &client.payer.pubkey()).await?;
println!("Claiming seat for pubkey: {}", client.payer.pubkey());

if !claim_seat_ix.is_empty() {
let tx = client.sign_send_instructions(claim_seat_ix, vec![]).await?;
println!("Claim seat transaction: {}", tx);
} else {
println!("Seat already created for pubkey: {}", client.payer.pubkey());
}

Ok(())
}
50 changes: 50 additions & 0 deletions src/lib/processor/process_evict_seat.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use std::mem::size_of;

use ellipsis_client::EllipsisClient;
use phoenix::program::MarketHeader;
use phoenix_sdk::utils::get_evictable_trader_ix;
use phoenix_seat_manager::instruction_builders::{
create_evict_seat_instruction, EvictTraderAccountBackup,
};
use solana_sdk::pubkey::Pubkey;

pub async fn process_evict_seat(
client: &EllipsisClient,
market_pubkey: &Pubkey,
trader_to_evict: &Option<Pubkey>,
) -> anyhow::Result<()> {
let market_bytes = client.get_account_data(market_pubkey).await?;
let (header_bytes, _market_bytes) = market_bytes.split_at(size_of::<MarketHeader>());
let market_header = bytemuck::try_from_bytes::<MarketHeader>(header_bytes)
.map_err(|e| anyhow::anyhow!("Error deserializing market header. Error: {:?}", e))?;

let maybe_evict_trader_ix = if let Some(trader_pubkey) = trader_to_evict {
let evict_trader_state = EvictTraderAccountBackup {
trader_pubkey: *trader_pubkey,
base_token_account_backup: None,
quote_token_account_backup: None,
};
Some(create_evict_seat_instruction(
market_pubkey,
&market_header.base_params.mint_key,
&market_header.quote_params.mint_key,
trader_pubkey,
vec![evict_trader_state],
))
} else {
get_evictable_trader_ix(client, market_pubkey).await?
};

if let Some(evict_trader_ix) = maybe_evict_trader_ix {
println!("Evicting trader: {}", evict_trader_ix.accounts[13].pubkey);
let tx = client
.sign_send_instructions(vec![evict_trader_ix], vec![])
.await?;
println!("Evict trader tx: {}", tx);
} else {
println!("Cannot evict a trader when the market's trader state is not full.");
return Ok(());
}

Ok(())
}
50 changes: 50 additions & 0 deletions src/lib/processor/process_get_seat_manager_info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use std::mem::size_of;

use ellipsis_client::EllipsisClient;
use phoenix::program::MarketHeader;
use phoenix_seat_manager::{get_seat_manager_address, seat_manager::SeatManager};
use solana_sdk::pubkey::Pubkey;

use crate::helpers::market_helpers::get_seat_manager_data_with_market;

pub async fn process_get_seat_manager_info(
client: &EllipsisClient,
market_pubkey: &Pubkey,
) -> anyhow::Result<()> {
let seat_manager_address = get_seat_manager_address(market_pubkey).0;
let market_data = client.get_account_data(market_pubkey).await?;
let market_header =
bytemuck::from_bytes::<MarketHeader>(market_data.split_at(size_of::<MarketHeader>()).0);
if market_header.authority != seat_manager_address {
println!(
"Authority for Market {} is not the seat manager.",
market_pubkey
);
println!("Market authority: {}", market_header.authority);
println!("Seat manager address: {}", seat_manager_address);
return Ok(());
}
let seat_manager_info = get_seat_manager_data_with_market(client, market_pubkey).await?;
print_seat_manager_struct(&seat_manager_info, &seat_manager_address);
Ok(())
}

pub fn print_seat_manager_struct(seat_manager: &SeatManager, seat_manager_pubkey: &Pubkey) {
println!("Seat Manager Address: {}", seat_manager_pubkey);
println!("SM Market: {}", seat_manager.market);
println!("SM Authority: {}", seat_manager.authority);
println!("SM Successor: {}", seat_manager.successor);
println!(
"Number of designated market makers: {}",
seat_manager.num_makers
);

let dmms: Vec<&Pubkey> = seat_manager
.designated_market_makers
.iter()
.filter(|&&dmm| dmm != Pubkey::default())
.collect();
if !dmms.is_empty() {
println!("DMMs: {:?}", dmms);
}
}
23 changes: 20 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ use crate::command::PhoenixCLICommand;
use anyhow::anyhow;
use clap::Parser;
use ellipsis_client::EllipsisClient;
use phoenix_cli_processor::processor::process_claim_seat::process_claim_seat;
use phoenix_cli_processor::processor::process_evict_seat::process_evict_seat;
use phoenix_cli_processor::processor::{
process_get_all_markets::*, process_get_book_levels::*, process_get_full_book::*,
process_get_market::*, process_get_market_status::*, process_get_open_orders::*,
process_get_seat_info::*, process_get_top_of_book::*, process_get_traders_for_market::*,
process_get_transaction::*, process_mint_tokens::*, process_mint_tokens_for_market::*,
process_request_seat::*,
process_get_seat_info::*, process_get_seat_manager_info::*, process_get_top_of_book::*,
process_get_traders_for_market::*, process_get_transaction::*, process_mint_tokens::*,
process_mint_tokens_for_market::*, process_request_seat::*,
};
use phoenix_sdk::sdk_client::*;
use solana_cli_config::{Config, ConfigInput, CONFIG_FILE};
Expand Down Expand Up @@ -154,6 +156,21 @@ async fn main() -> anyhow::Result<()> {
)
.await?
}
PhoenixCLICommand::GetSeatManagerInfo { market_pubkey } => {
sdk.add_market(&market_pubkey).await?;
process_get_seat_manager_info(&sdk.client, &market_pubkey).await?;
}
PhoenixCLICommand::ClaimSeat { market_pubkey } => {
sdk.add_market(&market_pubkey).await?;
process_claim_seat(&sdk.client, &market_pubkey).await?
}
PhoenixCLICommand::EvictSeat {
market_pubkey,
trader_to_evict,
} => {
sdk.add_market(&market_pubkey).await?;
process_evict_seat(&sdk.client, &market_pubkey, &trader_to_evict).await?
}
}

Ok(())
Expand Down

0 comments on commit 2c94ce1

Please sign in to comment.