Close various things (#65)

* close bank, vaults, mint infos, stub oracles, serum OO (doesnt work, throws https://github.com/project-serum/serum-dex/blob/master/dex/src/error.rs\#L88), close serum market

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>

* serum oo closing example in ts

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>

* Fix from code review

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>
This commit is contained in:
microwavedcola1 2022-06-09 18:27:31 +02:00 committed by GitHub
parent 40023fcef1
commit 740ff0c09e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 1933 additions and 158 deletions

View File

@ -339,7 +339,7 @@ impl MangoClient {
.collect()) .collect())
} }
pub fn deposit( pub fn token_deposit(
&self, &self,
token_name: &str, token_name: &str,
amount: u64, amount: u64,
@ -356,7 +356,7 @@ impl MangoClient {
program_id: mango_v4::id(), program_id: mango_v4::id(),
accounts: { accounts: {
let mut ams = anchor_lang::ToAccountMetas::to_account_metas( let mut ams = anchor_lang::ToAccountMetas::to_account_metas(
&mango_v4::accounts::Deposit { &mango_v4::accounts::TokenDeposit {
group: self.group(), group: self.group(),
account: self.mango_account_cache.0, account: self.mango_account_cache.0,
bank: bank.0, bank: bank.0,
@ -373,7 +373,7 @@ impl MangoClient {
ams.extend(health_check_metas.into_iter()); ams.extend(health_check_metas.into_iter());
ams ams
}, },
data: anchor_lang::InstructionData::data(&mango_v4::instruction::Deposit { data: anchor_lang::InstructionData::data(&mango_v4::instruction::TokenDeposit {
amount, amount,
}), }),
}) })

View File

@ -113,7 +113,7 @@ fn ensure_deposit(mango_client: &Arc<MangoClient>) -> Result<(), anyhow::Error>
} }
log::info!("Depositing {} {}", deposit_native, bank.name()); log::info!("Depositing {} {}", deposit_native, bank.name());
mango_client.deposit(bank.name(), desired_balance.to_num())?; mango_client.token_deposit(bank.name(), desired_balance.to_num())?;
} }
Ok(()) Ok(())

View File

@ -19,8 +19,20 @@ pub struct CloseAccount<'info> {
pub token_program: Program<'info, Token>, pub token_program: Program<'info, Token>,
} }
pub fn close_account(_ctx: Context<CloseAccount>) -> Result<()> { pub fn close_account(ctx: Context<CloseAccount>) -> Result<()> {
// CRITICAL: currently can close any account, even one with bad health let account = ctx.accounts.account.load()?;
// TODO: Implement require_eq!(account.being_liquidated, 0);
require_eq!(account.delegate, Pubkey::default());
require_eq!(account.is_bankrupt, 0);
for ele in account.tokens.values {
require_eq!(ele.is_active(), false);
}
for ele in account.serum3.values {
require_eq!(ele.is_active(), false);
}
for ele in account.perps.accounts {
require_eq!(ele.is_active(), false);
}
Ok(()) Ok(())
} }

View File

@ -0,0 +1,26 @@
use crate::state::*;
use anchor_lang::prelude::*;
use anchor_spl::token::Token;
#[derive(Accounts)]
pub struct CloseGroup<'info> {
#[account(
mut,
constraint = group.load()?.testing == 1,
has_one = admin,
close = sol_destination
)]
pub group: AccountLoader<'info, Group>,
pub admin: Signer<'info>,
#[account(mut)]
pub sol_destination: UncheckedAccount<'info>,
pub token_program: Program<'info, Token>,
}
pub fn close_group(_ctx: Context<CloseGroup>) -> Result<()> {
// TODO: checks
Ok(())
}

View File

@ -0,0 +1,31 @@
use anchor_lang::prelude::*;
use anchor_spl::token::Token;
use crate::state::*;
#[derive(Accounts)]
pub struct CloseStubOracle<'info> {
#[account(
constraint = group.load()?.testing == 1,
has_one = admin,
)]
pub group: AccountLoader<'info, Group>,
pub admin: Signer<'info>,
// match stub oracle to group
#[account(
mut,
has_one = group,
close = sol_destination
)]
pub oracle: AccountLoader<'info, StubOracle>,
#[account(mut)]
pub sol_destination: UncheckedAccount<'info>,
pub token_program: Program<'info, Token>,
}
pub fn close_stub_oracle(_ctx: Context<CloseStubOracle>) -> Result<()> {
Ok(())
}

View File

@ -23,10 +23,11 @@ pub struct CreateGroup<'info> {
pub system_program: Program<'info, System>, pub system_program: Program<'info, System>,
} }
pub fn create_group(ctx: Context<CreateGroup>, group_num: u32) -> Result<()> { pub fn create_group(ctx: Context<CreateGroup>, group_num: u32, testing: u8) -> Result<()> {
let mut group = ctx.accounts.group.load_init()?; let mut group = ctx.accounts.group.load_init()?;
group.admin = ctx.accounts.admin.key(); group.admin = ctx.accounts.admin.key();
group.bump = *ctx.bumps.get("group").ok_or(MangoError::SomeError)?; group.bump = *ctx.bumps.get("group").ok_or(MangoError::SomeError)?;
group.group_num = group_num; group.group_num = group_num;
group.testing = testing;
Ok(()) Ok(())
} }

View File

@ -1,53 +1,67 @@
pub use self::margin_trade::*; pub use self::margin_trade::*;
pub use benchmark::*; pub use benchmark::*;
pub use close_account::*; pub use close_account::*;
pub use close_group::*;
pub use close_stub_oracle::*;
pub use create_account::*; pub use create_account::*;
pub use create_group::*; pub use create_group::*;
pub use create_stub_oracle::*; pub use create_stub_oracle::*;
pub use deposit::*;
pub use liq_token_with_token::*; pub use liq_token_with_token::*;
pub use perp_cancel_all_orders::*; pub use perp_cancel_all_orders::*;
pub use perp_cancel_all_orders_by_side::*; pub use perp_cancel_all_orders_by_side::*;
pub use perp_cancel_order::*; pub use perp_cancel_order::*;
pub use perp_cancel_order_by_client_order_id::*; pub use perp_cancel_order_by_client_order_id::*;
pub use perp_close_market::*;
pub use perp_consume_events::*; pub use perp_consume_events::*;
pub use perp_create_market::*; pub use perp_create_market::*;
pub use perp_place_order::*; pub use perp_place_order::*;
pub use perp_update_funding::*; pub use perp_update_funding::*;
pub use register_token::*; pub use serum3_cancel_all_orders::*;
pub use serum3_cancel_order::*; pub use serum3_cancel_order::*;
pub use serum3_close_open_orders::*;
pub use serum3_create_open_orders::*; pub use serum3_create_open_orders::*;
pub use serum3_deregister_market::*;
pub use serum3_liq_force_cancel_orders::*; pub use serum3_liq_force_cancel_orders::*;
pub use serum3_place_order::*; pub use serum3_place_order::*;
pub use serum3_register_market::*; pub use serum3_register_market::*;
pub use serum3_settle_funds::*; pub use serum3_settle_funds::*;
pub use set_stub_oracle::*; pub use set_stub_oracle::*;
pub use token_deposit::*;
pub use token_deregister::*;
pub use token_register::*;
pub use token_withdraw::*;
pub use update_index::*; pub use update_index::*;
pub use withdraw::*;
mod benchmark; mod benchmark;
mod close_account; mod close_account;
mod close_group;
mod close_stub_oracle;
mod create_account; mod create_account;
mod create_group; mod create_group;
mod create_stub_oracle; mod create_stub_oracle;
mod deposit;
mod liq_token_with_token; mod liq_token_with_token;
pub mod margin_trade; mod margin_trade;
mod perp_cancel_all_orders; mod perp_cancel_all_orders;
mod perp_cancel_all_orders_by_side; mod perp_cancel_all_orders_by_side;
mod perp_cancel_order; mod perp_cancel_order;
mod perp_cancel_order_by_client_order_id; mod perp_cancel_order_by_client_order_id;
mod perp_close_market;
mod perp_consume_events; mod perp_consume_events;
mod perp_create_market; mod perp_create_market;
mod perp_place_order; mod perp_place_order;
mod perp_update_funding; mod perp_update_funding;
mod register_token; mod serum3_cancel_all_orders;
mod serum3_cancel_order; mod serum3_cancel_order;
mod serum3_close_open_orders;
mod serum3_create_open_orders; mod serum3_create_open_orders;
mod serum3_deregister_market;
mod serum3_liq_force_cancel_orders; mod serum3_liq_force_cancel_orders;
mod serum3_place_order; mod serum3_place_order;
mod serum3_register_market; mod serum3_register_market;
mod serum3_settle_funds; mod serum3_settle_funds;
mod set_stub_oracle; mod set_stub_oracle;
mod token_deposit;
mod token_deregister;
mod token_register;
mod token_withdraw;
mod update_index; mod update_index;
mod withdraw;

View File

@ -0,0 +1,52 @@
use anchor_lang::prelude::*;
use anchor_spl::token::Token;
use crate::state::*;
#[derive(Accounts)]
pub struct PerpCloseMarket<'info> {
#[account(
constraint = group.load()?.testing == 1,
has_one = admin,
)]
pub group: AccountLoader<'info, Group>,
pub admin: Signer<'info>,
#[account(
mut,
has_one = group,
has_one = bids,
has_one = asks,
has_one = event_queue,
close = sol_destination
)]
pub perp_market: AccountLoader<'info, PerpMarket>,
#[account(
mut,
close = sol_destination
)]
pub bids: AccountLoader<'info, BookSide>,
#[account(
mut,
close = sol_destination
)]
pub asks: AccountLoader<'info, BookSide>,
#[account(
mut,
close = sol_destination
)]
pub event_queue: AccountLoader<'info, EventQueue>,
#[account(mut)]
pub sol_destination: UncheckedAccount<'info>,
pub token_program: Program<'info, Token>,
}
#[allow(clippy::too_many_arguments)]
pub fn perp_close_market(_ctx: Context<PerpCloseMarket>) -> Result<()> {
Ok(())
}

View File

@ -0,0 +1,86 @@
use anchor_lang::prelude::*;
use crate::error::*;
use crate::state::*;
#[derive(Accounts)]
pub struct Serum3CancelAllOrders<'info> {
pub group: AccountLoader<'info, Group>,
#[account(
mut,
has_one = group,
has_one = owner,
)]
pub account: AccountLoader<'info, MangoAccount>,
pub owner: Signer<'info>,
// Validated inline
#[account(mut)]
pub open_orders: UncheckedAccount<'info>,
#[account(
has_one = group,
has_one = serum_program,
has_one = serum_market_external,
)]
pub serum_market: AccountLoader<'info, Serum3Market>,
pub serum_program: UncheckedAccount<'info>,
#[account(mut)]
pub serum_market_external: UncheckedAccount<'info>,
// These accounts are forwarded directly to the serum cpi call
// and are validated there.
#[account(mut)]
pub market_bids: UncheckedAccount<'info>,
#[account(mut)]
pub market_asks: UncheckedAccount<'info>,
#[account(mut)]
pub market_event_queue: UncheckedAccount<'info>,
}
pub fn serum3_cancel_all_orders(ctx: Context<Serum3CancelAllOrders>, limit: u8) -> Result<()> {
//
// Validation
//
{
let account = ctx.accounts.account.load()?;
require!(account.is_bankrupt == 0, MangoError::IsBankrupt);
let serum_market = ctx.accounts.serum_market.load()?;
// Validate open_orders
require!(
account
.serum3
.find(serum_market.market_index)
.ok_or_else(|| error!(MangoError::SomeError))?
.open_orders
== ctx.accounts.open_orders.key(),
MangoError::SomeError
);
}
//
// Cancel
//
cpi_cancel_all_orders(ctx.accounts, limit)?;
Ok(())
}
fn cpi_cancel_all_orders(ctx: &Serum3CancelAllOrders, limit: u8) -> Result<()> {
use crate::serum3_cpi;
let group = ctx.group.load()?;
serum3_cpi::CancelOrder {
program: ctx.serum_program.to_account_info(),
market: ctx.serum_market_external.to_account_info(),
bids: ctx.market_bids.to_account_info(),
asks: ctx.market_asks.to_account_info(),
event_queue: ctx.market_event_queue.to_account_info(),
open_orders: ctx.open_orders.to_account_info(),
open_orders_authority: ctx.group.to_account_info(),
}
.cancel_all(&group, limit)
}

View File

@ -0,0 +1,72 @@
use anchor_lang::prelude::*;
use crate::error::MangoError;
use crate::state::*;
#[derive(Accounts)]
pub struct Serum3CloseOpenOrders<'info> {
pub group: AccountLoader<'info, Group>,
#[account(
mut,
has_one = group,
has_one = owner,
)]
pub account: AccountLoader<'info, MangoAccount>,
pub owner: Signer<'info>,
#[account(
has_one = group,
has_one = serum_program,
has_one = serum_market_external,
)]
pub serum_market: AccountLoader<'info, Serum3Market>,
pub serum_program: UncheckedAccount<'info>,
pub serum_market_external: UncheckedAccount<'info>,
#[account(mut)]
pub open_orders: UncheckedAccount<'info>,
#[account(mut)]
pub sol_destination: UncheckedAccount<'info>,
}
pub fn serum3_close_open_orders(ctx: Context<Serum3CloseOpenOrders>) -> Result<()> {
//
// Validation
//
let mut account = ctx.accounts.account.load_mut()?;
let serum_market = ctx.accounts.serum_market.load()?;
require!(account.is_bankrupt == 0, MangoError::IsBankrupt);
// Validate open_orders
require!(
account
.serum3
.find(serum_market.market_index)
.ok_or_else(|| error!(MangoError::SomeError))?
.open_orders
== ctx.accounts.open_orders.key(),
MangoError::SomeError
);
//
// close OO
//
cpi_close_open_orders(ctx.accounts)?;
account.serum3.deactivate(serum_market.market_index)?;
Ok(())
}
fn cpi_close_open_orders(ctx: &Serum3CloseOpenOrders) -> Result<()> {
use crate::serum3_cpi;
let group = ctx.group.load()?;
serum3_cpi::CloseOpenOrders {
program: ctx.serum_program.to_account_info(),
market: ctx.serum_market_external.to_account_info(),
open_orders: ctx.open_orders.to_account_info(),
open_orders_authority: ctx.group.to_account_info(),
sol_destination: ctx.sol_destination.to_account_info(),
}
.call(&group)
}

View File

@ -0,0 +1,31 @@
use anchor_lang::prelude::*;
use anchor_spl::token::Token;
use crate::state::*;
#[derive(Accounts)]
pub struct Serum3DeregisterMarket<'info> {
#[account(
mut,
constraint = group.load()?.testing == 1,
has_one = admin,
)]
pub group: AccountLoader<'info, Group>,
pub admin: Signer<'info>,
#[account(
mut,
has_one = group,
close = sol_destination
)]
pub serum_market: AccountLoader<'info, Serum3Market>,
#[account(mut)]
pub sol_destination: UncheckedAccount<'info>,
pub token_program: Program<'info, Token>,
}
pub fn serum3_deregister_market(_ctx: Context<Serum3DeregisterMarket>) -> Result<()> {
Ok(())
}

View File

@ -8,7 +8,7 @@ use crate::error::*;
use crate::state::*; use crate::state::*;
#[derive(Accounts)] #[derive(Accounts)]
pub struct Deposit<'info> { pub struct TokenDeposit<'info> {
pub group: AccountLoader<'info, Group>, pub group: AccountLoader<'info, Group>,
#[account( #[account(
@ -36,7 +36,7 @@ pub struct Deposit<'info> {
pub token_program: Program<'info, Token>, pub token_program: Program<'info, Token>,
} }
impl<'info> Deposit<'info> { impl<'info> TokenDeposit<'info> {
pub fn transfer_ctx(&self) -> CpiContext<'_, '_, '_, 'info, token::Transfer<'info>> { pub fn transfer_ctx(&self) -> CpiContext<'_, '_, '_, 'info, token::Transfer<'info>> {
let program = self.token_program.to_account_info(); let program = self.token_program.to_account_info();
let accounts = token::Transfer { let accounts = token::Transfer {
@ -51,7 +51,7 @@ impl<'info> Deposit<'info> {
// TODO: It may make sense to have the token_index passed in from the outside. // TODO: It may make sense to have the token_index passed in from the outside.
// That would save a lot of computation that needs to go into finding the // That would save a lot of computation that needs to go into finding the
// right index for the mint. // right index for the mint.
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> { pub fn token_deposit(ctx: Context<TokenDeposit>, amount: u64) -> Result<()> {
require!(amount > 0, MangoError::SomeError); require!(amount > 0, MangoError::SomeError);
let token_index = ctx.accounts.bank.load()?.token_index; let token_index = ctx.accounts.bank.load()?.token_index;

View File

@ -0,0 +1,60 @@
use anchor_lang::prelude::*;
use anchor_spl::token::{self, CloseAccount, Token, TokenAccount};
use crate::state::*;
#[derive(Accounts)]
pub struct TokenDeregister<'info> {
#[account(
constraint = group.load()?.testing == 1,
has_one = admin,
)]
pub group: AccountLoader<'info, Group>,
pub admin: Signer<'info>,
// match bank to group
// match bank to vault
#[account(
mut,
has_one = group,
has_one = vault,
close = sol_destination
)]
pub bank: AccountLoader<'info, Bank>,
#[account(mut)]
pub vault: Account<'info, TokenAccount>,
// match mint info to bank
#[account(
mut,
has_one = bank,
close = sol_destination
)]
pub mint_info: AccountLoader<'info, MintInfo>,
#[account(mut)]
pub sol_destination: UncheckedAccount<'info>,
pub token_program: Program<'info, Token>,
}
#[allow(clippy::too_many_arguments)]
pub fn token_deregister(ctx: Context<TokenDeregister>) -> Result<()> {
let group = ctx.accounts.group.load()?;
let group_seeds = group_seeds!(group);
let cpi_accounts = CloseAccount {
account: ctx.accounts.vault.to_account_info(),
destination: ctx.accounts.sol_destination.to_account_info(),
authority: ctx.accounts.group.to_account_info(),
};
let cpi_program = ctx.accounts.token_program.to_account_info();
token::close_account(CpiContext::new_with_signer(
cpi_program,
cpi_accounts,
&[group_seeds],
))?;
ctx.accounts.vault.exit(ctx.program_id)?;
Ok(())
}

View File

@ -13,7 +13,7 @@ const INDEX_START: I80F48 = I80F48!(1_000_000);
#[derive(Accounts)] #[derive(Accounts)]
#[instruction(token_index: TokenIndex)] #[instruction(token_index: TokenIndex)]
pub struct RegisterToken<'info> { pub struct TokenRegister<'info> {
#[account( #[account(
has_one = admin, has_one = admin,
)] )]
@ -86,8 +86,8 @@ pub struct InterestRateParams {
// TODO: should this be "configure_mint", we pass an explicit index, and allow // TODO: should this be "configure_mint", we pass an explicit index, and allow
// overwriting config as long as the mint account stays the same? // overwriting config as long as the mint account stays the same?
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn register_token( pub fn token_register(
ctx: Context<RegisterToken>, ctx: Context<TokenRegister>,
token_index: TokenIndex, token_index: TokenIndex,
name: String, name: String,
interest_rate_params: InterestRateParams, interest_rate_params: InterestRateParams,

View File

@ -7,7 +7,7 @@ use anchor_spl::token::TokenAccount;
use fixed::types::I80F48; use fixed::types::I80F48;
#[derive(Accounts)] #[derive(Accounts)]
pub struct Withdraw<'info> { pub struct TokenWithdraw<'info> {
pub group: AccountLoader<'info, Group>, pub group: AccountLoader<'info, Group>,
#[account( #[account(
@ -36,7 +36,7 @@ pub struct Withdraw<'info> {
pub token_program: Program<'info, Token>, pub token_program: Program<'info, Token>,
} }
impl<'info> Withdraw<'info> { impl<'info> TokenWithdraw<'info> {
pub fn transfer_ctx(&self) -> CpiContext<'_, '_, '_, 'info, token::Transfer<'info>> { pub fn transfer_ctx(&self) -> CpiContext<'_, '_, '_, 'info, token::Transfer<'info>> {
let program = self.token_program.to_account_info(); let program = self.token_program.to_account_info();
let accounts = token::Transfer { let accounts = token::Transfer {
@ -52,7 +52,7 @@ impl<'info> Withdraw<'info> {
// That would save a lot of computation that needs to go into finding the // That would save a lot of computation that needs to go into finding the
// right index for the mint. // right index for the mint.
// TODO: https://github.com/blockworks-foundation/mango-v4/commit/15961ec81c7e9324b37d79d0e2a1650ce6bd981d comments // TODO: https://github.com/blockworks-foundation/mango-v4/commit/15961ec81c7e9324b37d79d0e2a1650ce6bd981d comments
pub fn withdraw(ctx: Context<Withdraw>, amount: u64, allow_borrow: bool) -> Result<()> { pub fn token_withdraw(ctx: Context<TokenWithdraw>, amount: u64, allow_borrow: bool) -> Result<()> {
require!(amount > 0, MangoError::SomeError); require!(amount > 0, MangoError::SomeError);
let group = ctx.accounts.group.load()?; let group = ctx.accounts.group.load()?;

View File

@ -26,13 +26,17 @@ pub mod mango_v4 {
use super::*; use super::*;
pub fn create_group(ctx: Context<CreateGroup>, group_num: u32) -> Result<()> { pub fn create_group(ctx: Context<CreateGroup>, group_num: u32, testing: u8) -> Result<()> {
instructions::create_group(ctx, group_num) instructions::create_group(ctx, group_num, testing)
}
pub fn close_group(ctx: Context<CloseGroup>) -> Result<()> {
instructions::close_group(ctx)
} }
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn register_token( pub fn token_register(
ctx: Context<RegisterToken>, ctx: Context<TokenRegister>,
token_index: TokenIndex, token_index: TokenIndex,
name: String, name: String,
interest_rate_params: InterestRateParams, interest_rate_params: InterestRateParams,
@ -44,7 +48,7 @@ pub mod mango_v4 {
init_liab_weight: f32, init_liab_weight: f32,
liquidation_fee: f32, liquidation_fee: f32,
) -> Result<()> { ) -> Result<()> {
instructions::register_token( instructions::token_register(
ctx, ctx,
token_index, token_index,
name, name,
@ -59,6 +63,10 @@ pub mod mango_v4 {
) )
} }
pub fn token_deregister(ctx: Context<TokenDeregister>) -> Result<()> {
instructions::token_deregister(ctx)
}
pub fn update_index(ctx: Context<UpdateIndex>) -> Result<()> { pub fn update_index(ctx: Context<UpdateIndex>) -> Result<()> {
instructions::update_index(ctx) instructions::update_index(ctx)
} }
@ -86,16 +94,24 @@ pub mod mango_v4 {
instructions::create_stub_oracle(ctx, price) instructions::create_stub_oracle(ctx, price)
} }
pub fn close_stub_oracle(ctx: Context<CloseStubOracle>) -> Result<()> {
instructions::close_stub_oracle(ctx)
}
pub fn set_stub_oracle(ctx: Context<SetStubOracle>, price: I80F48) -> Result<()> { pub fn set_stub_oracle(ctx: Context<SetStubOracle>, price: I80F48) -> Result<()> {
instructions::set_stub_oracle(ctx, price) instructions::set_stub_oracle(ctx, price)
} }
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> { pub fn token_deposit(ctx: Context<TokenDeposit>, amount: u64) -> Result<()> {
instructions::deposit(ctx, amount) instructions::token_deposit(ctx, amount)
} }
pub fn withdraw(ctx: Context<Withdraw>, amount: u64, allow_borrow: bool) -> Result<()> { pub fn token_withdraw(
instructions::withdraw(ctx, amount, allow_borrow) ctx: Context<TokenWithdraw>,
amount: u64,
allow_borrow: bool,
) -> Result<()> {
instructions::token_withdraw(ctx, amount, allow_borrow)
} }
pub fn margin_trade<'key, 'accounts, 'remaining, 'info>( pub fn margin_trade<'key, 'accounts, 'remaining, 'info>(
@ -121,12 +137,20 @@ pub mod mango_v4 {
instructions::serum3_register_market(ctx, market_index, name) instructions::serum3_register_market(ctx, market_index, name)
} }
pub fn serum3_deregister_market(ctx: Context<Serum3DeregisterMarket>) -> Result<()> {
instructions::serum3_deregister_market(ctx)
}
// TODO serum3_change_spot_market_params // TODO serum3_change_spot_market_params
pub fn serum3_create_open_orders(ctx: Context<Serum3CreateOpenOrders>) -> Result<()> { pub fn serum3_create_open_orders(ctx: Context<Serum3CreateOpenOrders>) -> Result<()> {
instructions::serum3_create_open_orders(ctx) instructions::serum3_create_open_orders(ctx)
} }
pub fn serum3_close_open_orders(ctx: Context<Serum3CloseOpenOrders>) -> Result<()> {
instructions::serum3_close_open_orders(ctx)
}
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn serum3_place_order( pub fn serum3_place_order(
ctx: Context<Serum3PlaceOrder>, ctx: Context<Serum3PlaceOrder>,
@ -160,6 +184,10 @@ pub mod mango_v4 {
instructions::serum3_cancel_order(ctx, side, order_id) instructions::serum3_cancel_order(ctx, side, order_id)
} }
pub fn serum3_cancel_all_orders(ctx: Context<Serum3CancelAllOrders>, limit: u8) -> Result<()> {
instructions::serum3_cancel_all_orders(ctx, limit)
}
pub fn serum3_settle_funds(ctx: Context<Serum3SettleFunds>) -> Result<()> { pub fn serum3_settle_funds(ctx: Context<Serum3SettleFunds>) -> Result<()> {
instructions::serum3_settle_funds(ctx) instructions::serum3_settle_funds(ctx)
} }
@ -234,6 +262,10 @@ pub mod mango_v4 {
) )
} }
pub fn perp_close_market(ctx: Context<PerpCloseMarket>) -> Result<()> {
instructions::perp_close_market(ctx)
}
// TODO perp_change_perp_market_params // TODO perp_change_perp_market_params
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]

View File

@ -161,6 +161,42 @@ impl<'info> InitOpenOrders<'info> {
} }
} }
pub struct CloseOpenOrders<'info> {
pub program: AccountInfo<'info>,
pub market: AccountInfo<'info>,
pub open_orders: AccountInfo<'info>,
pub open_orders_authority: AccountInfo<'info>,
pub sol_destination: AccountInfo<'info>,
}
impl<'info> CloseOpenOrders<'info> {
pub fn call(self, group: &Group) -> Result<()> {
let data = serum_dex::instruction::MarketInstruction::CloseOpenOrders.pack();
let instruction = solana_program::instruction::Instruction {
program_id: *self.program.key,
data,
accounts: vec![
AccountMeta::new(*self.open_orders.key, false),
AccountMeta::new_readonly(*self.open_orders_authority.key, true),
AccountMeta::new(*self.sol_destination.key, false),
AccountMeta::new_readonly(*self.market.key, false),
],
};
let account_infos = [
self.program,
self.open_orders,
self.open_orders_authority,
self.sol_destination,
self.market,
];
let seeds = group_seeds!(group);
solana_program::program::invoke_signed_unchecked(&instruction, &account_infos, &[seeds])?;
Ok(())
}
}
pub struct SettleFunds<'info> { pub struct SettleFunds<'info> {
pub program: AccountInfo<'info>, pub program: AccountInfo<'info>,
pub market: AccountInfo<'info>, pub market: AccountInfo<'info>,

View File

@ -12,7 +12,10 @@ pub struct Group {
pub admin: Pubkey, pub admin: Pubkey,
pub bump: u8, pub bump: u8,
pub padding: [u8; 3], // Only support closing/deregistering groups, stub oracles, tokens, and markets
// if testing == 1
pub testing: u8,
pub padding: [u8; 2],
pub group_num: u32, pub group_num: u32,
pub reserved: [u8; 8], pub reserved: [u8; 8],
} }

View File

@ -277,8 +277,16 @@ impl MangoAccountSerum3 {
} }
} }
pub fn deactivate(&mut self, index: usize) { pub fn deactivate(&mut self, market_index: Serum3MarketIndex) -> Result<()> {
let index = self
.values
.iter()
.position(|p| p.is_active_for_market(market_index))
.ok_or(MangoError::SomeError)?;
self.values[index].market_index = Serum3MarketIndex::MAX; self.values[index].market_index = Serum3MarketIndex::MAX;
Ok(())
} }
pub fn iter_active(&self) -> impl Iterator<Item = &Serum3Account> { pub fn iter_active(&self) -> impl Iterator<Item = &Serum3Account> {

View File

@ -367,7 +367,7 @@ impl<'keypair> ClientInstruction for MarginTradeInstruction<'keypair> {
} }
} }
pub struct WithdrawInstruction<'keypair> { pub struct TokenWithdrawInstruction<'keypair> {
pub amount: u64, pub amount: u64,
pub allow_borrow: bool, pub allow_borrow: bool,
@ -376,9 +376,9 @@ pub struct WithdrawInstruction<'keypair> {
pub token_account: Pubkey, pub token_account: Pubkey,
} }
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl<'keypair> ClientInstruction for WithdrawInstruction<'keypair> { impl<'keypair> ClientInstruction for TokenWithdrawInstruction<'keypair> {
type Accounts = mango_v4::accounts::Withdraw; type Accounts = mango_v4::accounts::TokenWithdraw;
type Instruction = mango_v4::instruction::Withdraw; type Instruction = mango_v4::instruction::TokenWithdraw;
async fn to_instruction( async fn to_instruction(
&self, &self,
account_loader: impl ClientAccountLoader + 'async_trait, account_loader: impl ClientAccountLoader + 'async_trait,
@ -433,7 +433,7 @@ impl<'keypair> ClientInstruction for WithdrawInstruction<'keypair> {
} }
} }
pub struct DepositInstruction<'keypair> { pub struct TokenDepositInstruction<'keypair> {
pub amount: u64, pub amount: u64,
pub account: Pubkey, pub account: Pubkey,
@ -441,9 +441,9 @@ pub struct DepositInstruction<'keypair> {
pub token_authority: &'keypair Keypair, pub token_authority: &'keypair Keypair,
} }
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl<'keypair> ClientInstruction for DepositInstruction<'keypair> { impl<'keypair> ClientInstruction for TokenDepositInstruction<'keypair> {
type Accounts = mango_v4::accounts::Deposit; type Accounts = mango_v4::accounts::TokenDeposit;
type Instruction = mango_v4::instruction::Deposit; type Instruction = mango_v4::instruction::TokenDeposit;
async fn to_instruction( async fn to_instruction(
&self, &self,
account_loader: impl ClientAccountLoader + 'async_trait, account_loader: impl ClientAccountLoader + 'async_trait,
@ -497,7 +497,7 @@ impl<'keypair> ClientInstruction for DepositInstruction<'keypair> {
} }
} }
pub struct RegisterTokenInstruction<'keypair> { pub struct TokenRegisterInstruction<'keypair> {
pub token_index: TokenIndex, pub token_index: TokenIndex,
pub decimals: u8, pub decimals: u8,
pub util0: f32, pub util0: f32,
@ -520,9 +520,9 @@ pub struct RegisterTokenInstruction<'keypair> {
pub payer: &'keypair Keypair, pub payer: &'keypair Keypair,
} }
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl<'keypair> ClientInstruction for RegisterTokenInstruction<'keypair> { impl<'keypair> ClientInstruction for TokenRegisterInstruction<'keypair> {
type Accounts = mango_v4::accounts::RegisterToken; type Accounts = mango_v4::accounts::TokenRegister;
type Instruction = mango_v4::instruction::RegisterToken; type Instruction = mango_v4::instruction::TokenRegister;
async fn to_instruction( async fn to_instruction(
&self, &self,
_account_loader: impl ClientAccountLoader + 'async_trait, _account_loader: impl ClientAccountLoader + 'async_trait,
@ -612,7 +612,74 @@ impl<'keypair> ClientInstruction for RegisterTokenInstruction<'keypair> {
} }
} }
pub struct SetStubOracle<'keypair> { pub struct TokenDeregisterInstruction<'keypair> {
pub admin: &'keypair Keypair,
pub payer: &'keypair Keypair,
pub group: Pubkey,
pub mint: Pubkey,
pub token_index: TokenIndex,
pub sol_destination: Pubkey,
}
#[async_trait::async_trait(?Send)]
impl<'keypair> ClientInstruction for TokenDeregisterInstruction<'keypair> {
type Accounts = mango_v4::accounts::TokenDeregister;
type Instruction = mango_v4::instruction::TokenDeregister;
async fn to_instruction(
&self,
_loader: impl ClientAccountLoader + 'async_trait,
) -> (Self::Accounts, Instruction) {
let program_id = mango_v4::id();
let instruction = Self::Instruction {};
let bank = Pubkey::find_program_address(
&[
self.group.as_ref(),
b"Bank".as_ref(),
&self.token_index.to_le_bytes(),
],
&program_id,
)
.0;
let vault = Pubkey::find_program_address(
&[
self.group.as_ref(),
b"Vault".as_ref(),
&self.token_index.to_le_bytes(),
],
&program_id,
)
.0;
let mint_info = Pubkey::find_program_address(
&[
self.group.as_ref(),
b"MintInfo".as_ref(),
self.mint.as_ref(),
],
&program_id,
)
.0;
let accounts = Self::Accounts {
admin: self.admin.pubkey(),
group: self.group,
bank,
vault,
mint_info,
sol_destination: self.sol_destination,
token_program: Token::id(),
};
let instruction = make_instruction(program_id, &accounts, instruction);
(accounts, instruction)
}
fn signers(&self) -> Vec<&Keypair> {
vec![self.admin]
}
}
pub struct SetStubOracleInstruction<'keypair> {
pub mint: Pubkey, pub mint: Pubkey,
pub group: Pubkey, pub group: Pubkey,
pub admin: &'keypair Keypair, pub admin: &'keypair Keypair,
@ -620,7 +687,7 @@ pub struct SetStubOracle<'keypair> {
pub price: &'static str, pub price: &'static str,
} }
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl<'keypair> ClientInstruction for SetStubOracle<'keypair> { impl<'keypair> ClientInstruction for SetStubOracleInstruction<'keypair> {
type Accounts = mango_v4::accounts::SetStubOracle; type Accounts = mango_v4::accounts::SetStubOracle;
type Instruction = mango_v4::instruction::SetStubOracle; type Instruction = mango_v4::instruction::SetStubOracle;
@ -707,6 +774,51 @@ impl<'keypair> ClientInstruction for CreateStubOracle<'keypair> {
} }
} }
pub struct CloseStubOracleInstruction<'keypair> {
pub group: Pubkey,
pub mint: Pubkey,
pub admin: &'keypair Keypair,
pub sol_destination: Pubkey,
}
#[async_trait::async_trait(?Send)]
impl<'keypair> ClientInstruction for CloseStubOracleInstruction<'keypair> {
type Accounts = mango_v4::accounts::CloseStubOracle;
type Instruction = mango_v4::instruction::CloseStubOracle;
async fn to_instruction(
&self,
_loader: impl ClientAccountLoader + 'async_trait,
) -> (Self::Accounts, Instruction) {
let program_id = mango_v4::id();
let instruction = Self::Instruction {};
let oracle = Pubkey::find_program_address(
&[
self.group.as_ref(),
b"StubOracle".as_ref(),
self.mint.as_ref(),
],
&program_id,
)
.0;
let accounts = Self::Accounts {
group: self.group,
admin: self.admin.pubkey(),
oracle,
sol_destination: self.sol_destination,
token_program: Token::id(),
};
let instruction = make_instruction(program_id, &accounts, instruction);
(accounts, instruction)
}
fn signers(&self) -> Vec<&Keypair> {
vec![self.admin]
}
}
pub struct CreateGroupInstruction<'keypair> { pub struct CreateGroupInstruction<'keypair> {
pub admin: &'keypair Keypair, pub admin: &'keypair Keypair,
pub payer: &'keypair Keypair, pub payer: &'keypair Keypair,
@ -720,7 +832,10 @@ impl<'keypair> ClientInstruction for CreateGroupInstruction<'keypair> {
_account_loader: impl ClientAccountLoader + 'async_trait, _account_loader: impl ClientAccountLoader + 'async_trait,
) -> (Self::Accounts, instruction::Instruction) { ) -> (Self::Accounts, instruction::Instruction) {
let program_id = mango_v4::id(); let program_id = mango_v4::id();
let instruction = Self::Instruction { group_num: 0 }; let instruction = Self::Instruction {
group_num: 0,
testing: 1,
};
let group = Pubkey::find_program_address( let group = Pubkey::find_program_address(
&[ &[
@ -748,6 +863,38 @@ impl<'keypair> ClientInstruction for CreateGroupInstruction<'keypair> {
} }
} }
pub struct CloseGroupInstruction<'keypair> {
pub admin: &'keypair Keypair,
pub group: Pubkey,
pub sol_destination: Pubkey,
}
#[async_trait::async_trait(?Send)]
impl<'keypair> ClientInstruction for CloseGroupInstruction<'keypair> {
type Accounts = mango_v4::accounts::CloseGroup;
type Instruction = mango_v4::instruction::CloseGroup;
async fn to_instruction(
&self,
_account_loader: impl ClientAccountLoader + 'async_trait,
) -> (Self::Accounts, instruction::Instruction) {
let program_id = mango_v4::id();
let instruction = Self::Instruction {};
let accounts = Self::Accounts {
group: self.group,
admin: self.admin.pubkey(),
sol_destination: self.sol_destination,
token_program: Token::id(),
};
let instruction = make_instruction(program_id, &accounts, instruction);
(accounts, instruction)
}
fn signers(&self) -> Vec<&Keypair> {
vec![self.admin]
}
}
pub struct CreateAccountInstruction<'keypair> { pub struct CreateAccountInstruction<'keypair> {
pub account_num: u8, pub account_num: u8,
@ -887,6 +1034,50 @@ impl<'keypair> ClientInstruction for Serum3RegisterMarketInstruction<'keypair> {
} }
} }
pub struct Serum3DeregisterMarketInstruction<'keypair> {
pub group: Pubkey,
pub admin: &'keypair Keypair,
pub serum_market_external: Pubkey,
pub sol_destination: Pubkey,
}
#[async_trait::async_trait(?Send)]
impl<'keypair> ClientInstruction for Serum3DeregisterMarketInstruction<'keypair> {
type Accounts = mango_v4::accounts::Serum3DeregisterMarket;
type Instruction = mango_v4::instruction::Serum3DeregisterMarket;
async fn to_instruction(
&self,
_account_loader: impl ClientAccountLoader + 'async_trait,
) -> (Self::Accounts, instruction::Instruction) {
let program_id = mango_v4::id();
let instruction = Self::Instruction {};
let serum_market = Pubkey::find_program_address(
&[
self.group.as_ref(),
b"Serum3Market".as_ref(),
self.serum_market_external.as_ref(),
],
&program_id,
)
.0;
let accounts = Self::Accounts {
group: self.group,
admin: self.admin.pubkey(),
serum_market,
sol_destination: self.sol_destination,
token_program: Token::id(),
};
let instruction = make_instruction(program_id, &accounts, instruction);
(accounts, instruction)
}
fn signers(&self) -> Vec<&Keypair> {
vec![self.admin]
}
}
pub struct Serum3CreateOpenOrdersInstruction<'keypair> { pub struct Serum3CreateOpenOrdersInstruction<'keypair> {
pub account: Pubkey, pub account: Pubkey,
pub serum_market: Pubkey, pub serum_market: Pubkey,
@ -938,6 +1129,55 @@ impl<'keypair> ClientInstruction for Serum3CreateOpenOrdersInstruction<'keypair>
} }
} }
pub struct Serum3CloseOpenOrdersInstruction<'keypair> {
pub account: Pubkey,
pub serum_market: Pubkey,
pub owner: &'keypair Keypair,
pub sol_destination: Pubkey,
}
#[async_trait::async_trait(?Send)]
impl<'keypair> ClientInstruction for Serum3CloseOpenOrdersInstruction<'keypair> {
type Accounts = mango_v4::accounts::Serum3CloseOpenOrders;
type Instruction = mango_v4::instruction::Serum3CloseOpenOrders;
async fn to_instruction(
&self,
account_loader: impl ClientAccountLoader + 'async_trait,
) -> (Self::Accounts, instruction::Instruction) {
let program_id = mango_v4::id();
let instruction = Self::Instruction {};
let account: MangoAccount = account_loader.load(&self.account).await.unwrap();
let serum_market: Serum3Market = account_loader.load(&self.serum_market).await.unwrap();
let open_orders = Pubkey::find_program_address(
&[
self.account.as_ref(),
b"Serum3OO".as_ref(),
self.serum_market.as_ref(),
],
&program_id,
)
.0;
let accounts = Self::Accounts {
group: account.group,
account: self.account,
serum_market: self.serum_market,
serum_program: serum_market.serum_program,
serum_market_external: serum_market.serum_market_external,
open_orders,
owner: self.owner.pubkey(),
sol_destination: self.sol_destination,
};
let instruction = make_instruction(program_id, &accounts, instruction);
(accounts, instruction)
}
fn signers(&self) -> Vec<&Keypair> {
vec![self.owner]
}
}
pub struct Serum3PlaceOrderInstruction<'keypair> { pub struct Serum3PlaceOrderInstruction<'keypair> {
pub side: Serum3Side, pub side: Serum3Side,
pub limit_price: u64, pub limit_price: u64,
@ -1115,6 +1355,65 @@ impl<'keypair> ClientInstruction for Serum3CancelOrderInstruction<'keypair> {
} }
} }
pub struct Serum3CancelAllOrdersInstruction<'keypair> {
pub limit: u8,
pub account: Pubkey,
pub owner: &'keypair Keypair,
pub serum_market: Pubkey,
}
#[async_trait::async_trait(?Send)]
impl<'keypair> ClientInstruction for Serum3CancelAllOrdersInstruction<'keypair> {
type Accounts = mango_v4::accounts::Serum3CancelAllOrders;
type Instruction = mango_v4::instruction::Serum3CancelAllOrders;
async fn to_instruction(
&self,
account_loader: impl ClientAccountLoader + 'async_trait,
) -> (Self::Accounts, instruction::Instruction) {
let program_id = mango_v4::id();
let instruction = Self::Instruction { limit: self.limit };
let account: MangoAccount = account_loader.load(&self.account).await.unwrap();
let serum_market: Serum3Market = account_loader.load(&self.serum_market).await.unwrap();
let open_orders = account
.serum3
.find(serum_market.market_index)
.unwrap()
.open_orders;
let market_external_bytes = account_loader
.load_bytes(&serum_market.serum_market_external)
.await
.unwrap();
let market_external: &serum_dex::state::MarketState = bytemuck::from_bytes(
&market_external_bytes[5..5 + std::mem::size_of::<serum_dex::state::MarketState>()],
);
// unpack the data, to avoid unaligned references
let bids = market_external.bids;
let asks = market_external.asks;
let event_q = market_external.event_q;
let accounts = Self::Accounts {
group: account.group,
account: self.account,
open_orders,
serum_market: self.serum_market,
serum_program: serum_market.serum_program,
serum_market_external: serum_market.serum_market_external,
market_bids: from_serum_style_pubkey(&bids),
market_asks: from_serum_style_pubkey(&asks),
market_event_queue: from_serum_style_pubkey(&event_q),
owner: self.owner.pubkey(),
};
let instruction = make_instruction(program_id, &accounts, instruction);
(accounts, instruction)
}
fn signers(&self) -> Vec<&Keypair> {
vec![self.owner]
}
}
pub struct Serum3SettleFundsInstruction<'keypair> { pub struct Serum3SettleFundsInstruction<'keypair> {
pub account: Pubkey, pub account: Pubkey,
pub owner: &'keypair Keypair, pub owner: &'keypair Keypair,
@ -1415,6 +1714,46 @@ impl<'keypair> ClientInstruction for PerpCreateMarketInstruction<'keypair> {
} }
} }
pub struct PerpCloseMarketInstruction<'keypair> {
pub group: Pubkey,
pub admin: &'keypair Keypair,
pub perp_market: Pubkey,
pub asks: Pubkey,
pub bids: Pubkey,
pub event_queue: Pubkey,
pub sol_destination: Pubkey,
}
#[async_trait::async_trait(?Send)]
impl<'keypair> ClientInstruction for PerpCloseMarketInstruction<'keypair> {
type Accounts = mango_v4::accounts::PerpCloseMarket;
type Instruction = mango_v4::instruction::PerpCloseMarket;
async fn to_instruction(
&self,
_loader: impl ClientAccountLoader + 'async_trait,
) -> (Self::Accounts, instruction::Instruction) {
let program_id = mango_v4::id();
let instruction = Self::Instruction {};
let accounts = Self::Accounts {
group: self.group,
admin: self.admin.pubkey(),
perp_market: self.perp_market,
asks: self.asks,
bids: self.bids,
event_queue: self.event_queue,
token_program: Token::id(),
sol_destination: self.sol_destination,
};
let instruction = make_instruction(program_id, &accounts, instruction);
(accounts, instruction)
}
fn signers(&self) -> Vec<&Keypair> {
vec![self.admin]
}
}
pub struct PerpPlaceOrderInstruction<'keypair> { pub struct PerpPlaceOrderInstruction<'keypair> {
pub group: Pubkey, pub group: Pubkey,
pub account: Pubkey, pub account: Pubkey,

View File

@ -56,7 +56,7 @@ impl<'a> GroupWithTokensConfig<'a> {
let oracle = create_stub_oracle_accounts.oracle; let oracle = create_stub_oracle_accounts.oracle;
send_tx( send_tx(
solana, solana,
SetStubOracle { SetStubOracleInstruction {
group, group,
admin, admin,
mint: mint.pubkey, mint: mint.pubkey,
@ -69,7 +69,7 @@ impl<'a> GroupWithTokensConfig<'a> {
let token_index = index as u16; let token_index = index as u16;
let register_token_accounts = send_tx( let register_token_accounts = send_tx(
solana, solana,
RegisterTokenInstruction { TokenRegisterInstruction {
token_index, token_index,
decimals: mint.decimals, decimals: mint.decimals,
util0: 0.40, util0: 0.40,

View File

@ -59,7 +59,7 @@ async fn test_basic() -> Result<(), TransportError> {
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: deposit_amount, amount: deposit_amount,
account, account,
token_account: payer_mint0_account, token_account: payer_mint0_account,
@ -94,7 +94,7 @@ async fn test_basic() -> Result<(), TransportError> {
send_tx( send_tx(
solana, solana,
WithdrawInstruction { TokenWithdrawInstruction {
amount: withdraw_amount, amount: withdraw_amount,
allow_borrow: true, allow_borrow: true,
account, account,
@ -122,9 +122,25 @@ async fn test_basic() -> Result<(), TransportError> {
} }
// //
// TEST: Close account // TEST: Close account and de register bank
// TODO: This just checks execution, preconditions etc need to be tested!
// //
// withdraw whatever is remaining, can't close bank vault without this
let bank_data: Bank = solana.get_account(bank).await;
send_tx(
solana,
TokenWithdrawInstruction {
amount: bank_data.native_total_deposits().to_num(),
allow_borrow: false,
account,
owner,
token_account: payer_mint0_account,
},
)
.await
.unwrap();
// close account
send_tx( send_tx(
solana, solana,
CloseAccountInstruction { CloseAccountInstruction {
@ -136,5 +152,46 @@ async fn test_basic() -> Result<(), TransportError> {
.await .await
.unwrap(); .unwrap();
// deregister bank - closes bank, mint info, and bank vault
let bank_data: Bank = solana.get_account(bank).await;
send_tx(
solana,
TokenDeregisterInstruction {
admin,
payer,
group,
mint: bank_data.mint,
token_index: bank_data.token_index,
sol_destination: payer.pubkey(),
},
)
.await
.unwrap();
// close stub oracle
send_tx(
solana,
CloseStubOracleInstruction {
group,
mint: bank_data.mint,
admin,
sol_destination: payer.pubkey(),
},
)
.await
.unwrap();
// close group
send_tx(
solana,
CloseGroupInstruction {
group,
admin,
sol_destination: payer.pubkey(),
},
)
.await
.unwrap();
Ok(()) Ok(())
} }

View File

@ -66,7 +66,7 @@ async fn test_group_address_lookup_tables() -> Result<()> {
let oracle = create_stub_oracle_accounts.oracle; let oracle = create_stub_oracle_accounts.oracle;
send_tx( send_tx(
solana, solana,
SetStubOracle { SetStubOracleInstruction {
group, group,
admin, admin,
mint: mint.pubkey, mint: mint.pubkey,
@ -134,7 +134,7 @@ async fn test_group_address_lookup_tables() -> Result<()> {
for &payer_token in payer_mint_accounts { for &payer_token in payer_mint_accounts {
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: deposit_amount, amount: deposit_amount,
account, account,
token_account: payer_token, token_account: payer_token,
@ -155,7 +155,7 @@ async fn test_group_address_lookup_tables() -> Result<()> {
for &payer_token in payer_mint_accounts { for &payer_token in payer_mint_accounts {
send_tx( send_tx(
solana, solana,
WithdrawInstruction { TokenWithdrawInstruction {
amount: withdraw_amount, amount: withdraw_amount,
allow_borrow: true, allow_borrow: true,
account, account,

View File

@ -55,7 +55,7 @@ async fn test_health_compute_tokens() -> Result<(), TransportError> {
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: deposit_amount, amount: deposit_amount,
account, account,
token_account, token_account,
@ -165,7 +165,7 @@ async fn test_health_compute_serum() -> Result<(), TransportError> {
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: 10, amount: 10,
account, account,
token_account: payer_mint_accounts[0], token_account: payer_mint_accounts[0],
@ -222,7 +222,7 @@ async fn test_health_compute_perp() -> Result<(), TransportError> {
// Give the account some quote currency // Give the account some quote currency
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: 1000, amount: 1000,
account, account,
token_account: payer_mint_accounts[0], token_account: payer_mint_accounts[0],
@ -319,7 +319,7 @@ async fn test_health_compute_perp() -> Result<(), TransportError> {
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: 10, amount: 10,
account, account,
token_account: payer_mint_accounts[0], token_account: payer_mint_accounts[0],

View File

@ -53,7 +53,7 @@ async fn test_liq_tokens_force_cancel() -> Result<(), TransportError> {
for &token_account in payer_mint_accounts { for &token_account in payer_mint_accounts {
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: 10000, amount: 10000,
account: vault_account, account: vault_account,
token_account, token_account,
@ -108,7 +108,7 @@ async fn test_liq_tokens_force_cancel() -> Result<(), TransportError> {
let deposit_amount = 1000; let deposit_amount = 1000;
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: deposit_amount, amount: deposit_amount,
account, account,
token_account: payer_mint_accounts[1], token_account: payer_mint_accounts[1],
@ -159,7 +159,7 @@ async fn test_liq_tokens_force_cancel() -> Result<(), TransportError> {
// //
send_tx( send_tx(
solana, solana,
SetStubOracle { SetStubOracleInstruction {
group, group,
admin, admin,
mint: base_token.mint.pubkey, mint: base_token.mint.pubkey,
@ -173,7 +173,7 @@ async fn test_liq_tokens_force_cancel() -> Result<(), TransportError> {
// can't withdraw // can't withdraw
assert!(send_tx( assert!(send_tx(
solana, solana,
WithdrawInstruction { TokenWithdrawInstruction {
amount: 1, amount: 1,
allow_borrow: false, allow_borrow: false,
account, account,
@ -201,7 +201,7 @@ async fn test_liq_tokens_force_cancel() -> Result<(), TransportError> {
// can withdraw again // can withdraw again
send_tx( send_tx(
solana, solana,
WithdrawInstruction { TokenWithdrawInstruction {
amount: 2, amount: 2,
allow_borrow: false, allow_borrow: false,
account, account,
@ -258,7 +258,7 @@ async fn test_liq_tokens_with_token() -> Result<(), TransportError> {
for &token_account in payer_mint_accounts { for &token_account in payer_mint_accounts {
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: 100000, amount: 100000,
account: vault_account, account: vault_account,
token_account, token_account,
@ -289,7 +289,7 @@ async fn test_liq_tokens_with_token() -> Result<(), TransportError> {
let deposit2_amount = 20; let deposit2_amount = 20;
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: deposit1_amount, amount: deposit1_amount,
account, account,
token_account: payer_mint_accounts[2], token_account: payer_mint_accounts[2],
@ -300,7 +300,7 @@ async fn test_liq_tokens_with_token() -> Result<(), TransportError> {
.unwrap(); .unwrap();
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: deposit2_amount, amount: deposit2_amount,
account, account,
token_account: payer_mint_accounts[3], token_account: payer_mint_accounts[3],
@ -314,7 +314,7 @@ async fn test_liq_tokens_with_token() -> Result<(), TransportError> {
let borrow2_amount = 50; let borrow2_amount = 50;
send_tx( send_tx(
solana, solana,
WithdrawInstruction { TokenWithdrawInstruction {
amount: borrow1_amount, amount: borrow1_amount,
allow_borrow: true, allow_borrow: true,
account, account,
@ -326,7 +326,7 @@ async fn test_liq_tokens_with_token() -> Result<(), TransportError> {
.unwrap(); .unwrap();
send_tx( send_tx(
solana, solana,
WithdrawInstruction { TokenWithdrawInstruction {
amount: borrow2_amount, amount: borrow2_amount,
allow_borrow: true, allow_borrow: true,
account, account,
@ -342,7 +342,7 @@ async fn test_liq_tokens_with_token() -> Result<(), TransportError> {
// //
send_tx( send_tx(
solana, solana,
SetStubOracle { SetStubOracleInstruction {
group, group,
admin, admin,
mint: borrow_token1.mint.pubkey, mint: borrow_token1.mint.pubkey,

View File

@ -64,7 +64,7 @@ async fn test_margin_trade() -> Result<(), BanksClientError> {
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: provided_amount, amount: provided_amount,
account: provider_account, account: provider_account,
token_account: payer_mint0_account, token_account: payer_mint0_account,
@ -75,7 +75,7 @@ async fn test_margin_trade() -> Result<(), BanksClientError> {
.unwrap(); .unwrap();
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: provided_amount, amount: provided_amount,
account: provider_account, account: provider_account,
token_account: payer_mint1_account, token_account: payer_mint1_account,
@ -111,7 +111,7 @@ async fn test_margin_trade() -> Result<(), BanksClientError> {
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: deposit_amount_initial, amount: deposit_amount_initial,
account, account,
token_account: payer_mint0_account, token_account: payer_mint0_account,

View File

@ -5,7 +5,7 @@ use fixed_macro::types::I80F48;
use mango_v4::state::*; use mango_v4::state::*;
use program_test::*; use program_test::*;
use solana_program_test::*; use solana_program_test::*;
use solana_sdk::{signature::Keypair, transport::TransportError}; use solana_sdk::{signature::Keypair, signer::Signer, transport::TransportError};
mod program_test; mod program_test;
@ -66,7 +66,7 @@ async fn test_perp() -> Result<(), TransportError> {
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: deposit_amount, amount: deposit_amount,
account: account_0, account: account_0,
token_account: payer_mint_accounts[0], token_account: payer_mint_accounts[0],
@ -78,7 +78,7 @@ async fn test_perp() -> Result<(), TransportError> {
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: deposit_amount, amount: deposit_amount,
account: account_0, account: account_0,
token_account: payer_mint_accounts[1], token_account: payer_mint_accounts[1],
@ -94,7 +94,7 @@ async fn test_perp() -> Result<(), TransportError> {
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: deposit_amount, amount: deposit_amount,
account: account_1, account: account_1,
token_account: payer_mint_accounts[0], token_account: payer_mint_accounts[0],
@ -106,7 +106,7 @@ async fn test_perp() -> Result<(), TransportError> {
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: deposit_amount, amount: deposit_amount,
account: account_1, account: account_1,
token_account: payer_mint_accounts[1], token_account: payer_mint_accounts[1],
@ -402,6 +402,21 @@ async fn test_perp() -> Result<(), TransportError> {
assert_eq!(mango_account_1.perps.accounts[0].base_position_lots, -1); assert_eq!(mango_account_1.perps.accounts[0].base_position_lots, -1);
assert_eq!(mango_account_1.perps.accounts[0].quote_position_native, 100); assert_eq!(mango_account_1.perps.accounts[0].quote_position_native, 100);
send_tx(
solana,
PerpCloseMarketInstruction {
group,
admin,
perp_market,
asks,
bids,
event_queue,
sol_destination: payer.pubkey(),
},
)
.await
.unwrap();
Ok(()) Ok(())
} }

View File

@ -68,7 +68,7 @@ async fn test_position_lifetime() -> Result<()> {
for &payer_token in payer_mint_accounts { for &payer_token in payer_mint_accounts {
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: funding_amount, amount: funding_amount,
account: funding_account, account: funding_account,
token_account: payer_token, token_account: payer_token,
@ -91,7 +91,7 @@ async fn test_position_lifetime() -> Result<()> {
for &payer_token in payer_mint_accounts { for &payer_token in payer_mint_accounts {
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: deposit_amount, amount: deposit_amount,
account, account,
token_account: payer_token, token_account: payer_token,
@ -106,7 +106,7 @@ async fn test_position_lifetime() -> Result<()> {
for &payer_token in payer_mint_accounts { for &payer_token in payer_mint_accounts {
send_tx( send_tx(
solana, solana,
WithdrawInstruction { TokenWithdrawInstruction {
amount: u64::MAX, amount: u64::MAX,
allow_borrow: false, allow_borrow: false,
account, account,
@ -141,7 +141,7 @@ async fn test_position_lifetime() -> Result<()> {
let collateral_amount = 1000; let collateral_amount = 1000;
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: collateral_amount, amount: collateral_amount,
account, account,
token_account: payer_mint_accounts[0], token_account: payer_mint_accounts[0],
@ -155,7 +155,7 @@ async fn test_position_lifetime() -> Result<()> {
let borrow_amount = 10; let borrow_amount = 10;
send_tx( send_tx(
solana, solana,
WithdrawInstruction { TokenWithdrawInstruction {
amount: borrow_amount, amount: borrow_amount,
allow_borrow: true, allow_borrow: true,
account, account,
@ -174,7 +174,7 @@ async fn test_position_lifetime() -> Result<()> {
{ {
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
// deposit withdraw amount + some more to cover loan origination fees // deposit withdraw amount + some more to cover loan origination fees
amount: borrow_amount + 2, amount: borrow_amount + 2,
account, account,
@ -186,7 +186,7 @@ async fn test_position_lifetime() -> Result<()> {
.unwrap(); .unwrap();
send_tx( send_tx(
solana, solana,
WithdrawInstruction { TokenWithdrawInstruction {
// withdraw residual amount left // withdraw residual amount left
amount: u64::MAX, amount: u64::MAX,
allow_borrow: false, allow_borrow: false,
@ -202,7 +202,7 @@ async fn test_position_lifetime() -> Result<()> {
// withdraw the collateral, closing the position // withdraw the collateral, closing the position
send_tx( send_tx(
solana, solana,
WithdrawInstruction { TokenWithdrawInstruction {
amount: collateral_amount, amount: collateral_amount,
allow_borrow: false, allow_borrow: false,
account, account,

View File

@ -1,7 +1,7 @@
#![cfg(feature = "test-bpf")] #![cfg(feature = "test-bpf")]
use solana_program_test::*; use solana_program_test::*;
use solana_sdk::{signature::Keypair, transport::TransportError}; use solana_sdk::{signature::Keypair, signer::Signer, transport::TransportError};
use mango_v4::{ use mango_v4::{
instructions::{Serum3OrderType, Serum3SelfTradeBehavior, Serum3Side}, instructions::{Serum3OrderType, Serum3SelfTradeBehavior, Serum3Side},
@ -65,7 +65,7 @@ async fn test_serum() -> Result<(), TransportError> {
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: deposit_amount, amount: deposit_amount,
account, account,
token_account: payer_mint_accounts[0], token_account: payer_mint_accounts[0],
@ -77,7 +77,7 @@ async fn test_serum() -> Result<(), TransportError> {
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: deposit_amount, amount: deposit_amount,
account, account,
token_account: payer_mint_accounts[1], token_account: payer_mint_accounts[1],
@ -204,5 +204,32 @@ async fn test_serum() -> Result<(), TransportError> {
assert_eq!(native0, 1000); assert_eq!(native0, 1000);
assert_eq!(native1, 1000); assert_eq!(native1, 1000);
// close oo account
// TODO: custom program error: 0x2a TooManyOpenOrders https://github.com/project-serum/serum-dex/blob/master/dex/src/error.rs#L88
// send_tx(
// solana,
// Serum3CloseOpenOrdersInstruction {
// account,
// serum_market,
// owner,
// sol_destination: payer.pubkey(),
// },
// )
// .await
// .unwrap();
// deregister serum3 market
send_tx(
solana,
Serum3DeregisterMarketInstruction {
group,
admin,
serum_market_external: serum_market_cookie.market,
sol_destination: payer.pubkey(),
},
)
.await
.unwrap();
Ok(()) Ok(())
} }

View File

@ -47,7 +47,7 @@ async fn test_update_index() -> Result<(), TransportError> {
for &token_account in payer_mint_accounts { for &token_account in payer_mint_accounts {
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: 10000, amount: 10000,
account: deposit_account, account: deposit_account,
token_account, token_account,
@ -73,7 +73,7 @@ async fn test_update_index() -> Result<(), TransportError> {
send_tx( send_tx(
solana, solana,
DepositInstruction { TokenDepositInstruction {
amount: 100000, amount: 100000,
account: withdraw_account, account: withdraw_account,
token_account: payer_mint_accounts[1], token_account: payer_mint_accounts[1],
@ -85,7 +85,7 @@ async fn test_update_index() -> Result<(), TransportError> {
send_tx( send_tx(
solana, solana,
WithdrawInstruction { TokenWithdrawInstruction {
amount: 5000, amount: 5000,
allow_borrow: true, allow_borrow: true,
account: withdraw_account, account: withdraw_account,

View File

@ -1,8 +1,6 @@
import { BN } from '@project-serum/anchor'; import { BN } from '@project-serum/anchor';
import { utf8 } from '@project-serum/anchor/dist/cjs/utils/bytes'; import { utf8 } from '@project-serum/anchor/dist/cjs/utils/bytes';
import { PublicKey } from '@solana/web3.js'; import { PublicKey } from '@solana/web3.js';
import bs58 from 'bs58';
import { MangoClient } from '../client';
import { I80F48, I80F48Dto } from './I80F48'; import { I80F48, I80F48Dto } from './I80F48';
export const QUOTE_DECIMALS = 6; export const QUOTE_DECIMALS = 6;
@ -145,30 +143,3 @@ export class MintInfo {
public oracle: PublicKey, public oracle: PublicKey,
) {} ) {}
} }
export async function getMintInfoForTokenIndex(
client: MangoClient,
groupPk: PublicKey,
tokenIndex: number,
): Promise<MintInfo[]> {
const tokenIndexBuf = Buffer.alloc(2);
tokenIndexBuf.writeUInt16LE(tokenIndex);
return (
await client.program.account.mintInfo.all([
{
memcmp: {
bytes: groupPk.toBase58(),
offset: 8,
},
},
{
memcmp: {
bytes: bs58.encode(tokenIndexBuf),
offset: 200,
},
},
])
).map((tuple) => {
return MintInfo.from(tuple.publicKey, tuple.account);
});
}

View File

@ -1,6 +1,6 @@
import { PublicKey } from '@solana/web3.js'; import { PublicKey } from '@solana/web3.js';
import { MangoClient } from '../client'; import { MangoClient } from '../client';
import { Bank } from './bank'; import { Bank, MintInfo } from './bank';
import { PerpMarket } from './perp'; import { PerpMarket } from './perp';
import { Serum3Market } from './serum3'; import { Serum3Market } from './serum3';
@ -16,6 +16,7 @@ export class Group {
new Map(), new Map(),
new Map(), new Map(),
new Map(), new Map(),
new Map(),
); );
} }
@ -26,6 +27,7 @@ export class Group {
public banksMap: Map<string, Bank>, public banksMap: Map<string, Bank>,
public serum3MarketsMap: Map<string, Serum3Market>, public serum3MarketsMap: Map<string, Serum3Market>,
public perpMarketsMap: Map<string, PerpMarket>, public perpMarketsMap: Map<string, PerpMarket>,
public mintInfosMap: Map<string, MintInfo>,
) {} ) {}
public findBank(tokenIndex: number): Bank | undefined { public findBank(tokenIndex: number): Bank | undefined {
@ -36,6 +38,7 @@ export class Group {
public async reload(client: MangoClient) { public async reload(client: MangoClient) {
await this.reloadBanks(client); await this.reloadBanks(client);
await this.reloadMintInfos(client);
await this.reloadSerum3Markets(client); await this.reloadSerum3Markets(client);
await this.reloadPerpMarkets(client); await this.reloadPerpMarkets(client);
} }
@ -45,6 +48,28 @@ export class Group {
this.banksMap = new Map(banks.map((bank) => [bank.name, bank])); this.banksMap = new Map(banks.map((bank) => [bank.name, bank]));
} }
public async reloadMintInfos(client: MangoClient) {
const mintInfos = await client.getMintInfosForGroup(this);
this.mintInfosMap = new Map(
mintInfos.map((mintInfo) => {
// console.log(
// Array.from(this.banksMap.values()).find(
// (bank) => bank.mint.toBase58() === mintInfo.mint.toBase58(),
// ),
// );
return [
Array.from(this.banksMap.values()).find(
(bank) => bank.mint.toBase58() === mintInfo.mint.toBase58(),
)?.name!,
mintInfo,
];
}),
);
// console.log(this.banksMap);
// console.log(this.mintInfosMap);
}
public async reloadSerum3Markets(client: MangoClient) { public async reloadSerum3Markets(client: MangoClient) {
const serum3Markets = await client.serum3GetMarket(this); const serum3Markets = await client.serum3GetMarket(this);
this.serum3MarketsMap = new Map( this.serum3MarketsMap = new Map(

View File

@ -24,7 +24,7 @@ import {
TransactionSignature, TransactionSignature,
} from '@solana/web3.js'; } from '@solana/web3.js';
import bs58 from 'bs58'; import bs58 from 'bs58';
import { Bank, getMintInfoForTokenIndex } from './accounts/bank'; import { Bank, MintInfo } from './accounts/bank';
import { Group } from './accounts/group'; import { Group } from './accounts/group';
import { I80F48 } from './accounts/I80F48'; import { I80F48 } from './accounts/I80F48';
import { MangoAccount } from './accounts/mangoAccount'; import { MangoAccount } from './accounts/mangoAccount';
@ -56,10 +56,13 @@ export class MangoClient {
// Group // Group
public async createGroup(groupNum: number): Promise<TransactionSignature> { public async createGroup(
groupNum: number,
testing: boolean,
): Promise<TransactionSignature> {
const adminPk = (this.program.provider as AnchorProvider).wallet.publicKey; const adminPk = (this.program.provider as AnchorProvider).wallet.publicKey;
return await this.program.methods return await this.program.methods
.createGroup(groupNum) .createGroup(groupNum, testing ? 1 : 0)
.accounts({ .accounts({
admin: adminPk, admin: adminPk,
payer: adminPk, payer: adminPk,
@ -67,6 +70,19 @@ export class MangoClient {
.rpc(); .rpc();
} }
public async closeGroup(group: Group): Promise<TransactionSignature> {
const adminPk = (this.program.provider as AnchorProvider).wallet.publicKey;
return await this.program.methods
.closeGroup()
.accounts({
group: group.publicKey,
admin: adminPk,
solDestination: (this.program.provider as AnchorProvider).wallet
.publicKey,
})
.rpc();
}
public async getGroup(groupPk: PublicKey): Promise<Group> { public async getGroup(groupPk: PublicKey): Promise<Group> {
const groupAccount = await this.program.account.group.fetch(groupPk); const groupAccount = await this.program.account.group.fetch(groupPk);
const group = Group.from(groupPk, groupAccount); const group = Group.from(groupPk, groupAccount);
@ -107,7 +123,7 @@ export class MangoClient {
// Tokens/Banks // Tokens/Banks
public async registerToken( public async tokenRegister(
group: Group, group: Group,
mintPk: PublicKey, mintPk: PublicKey,
oraclePk: PublicKey, oraclePk: PublicKey,
@ -127,7 +143,7 @@ export class MangoClient {
liquidationFee: number, liquidationFee: number,
): Promise<TransactionSignature> { ): Promise<TransactionSignature> {
return await this.program.methods return await this.program.methods
.registerToken( .tokenRegister(
tokenIndex, tokenIndex,
name, name,
{ util0, rate0, util1, rate1, maxRate }, { util0, rate0, util1, rate1, maxRate },
@ -150,6 +166,27 @@ export class MangoClient {
.rpc(); .rpc();
} }
public async tokenDeregister(
group: Group,
tokenName: string,
): Promise<TransactionSignature> {
const bank = group.banksMap.get(tokenName)!;
const adminPk = (this.program.provider as AnchorProvider).wallet.publicKey;
return await this.program.methods
.tokenDeregister()
.accounts({
group: group.publicKey,
admin: adminPk,
bank: bank.publicKey,
vault: bank.vault,
mintInfo: group.mintInfosMap.get(bank.name)?.publicKey,
solDestination: (this.program.provider as AnchorProvider).wallet
.publicKey,
})
.rpc();
}
public async getBanksForGroup(group: Group): Promise<Bank[]> { public async getBanksForGroup(group: Group): Promise<Bank[]> {
return ( return (
await this.program.account.bank.all([ await this.program.account.bank.all([
@ -163,6 +200,47 @@ export class MangoClient {
).map((tuple) => Bank.from(tuple.publicKey, tuple.account)); ).map((tuple) => Bank.from(tuple.publicKey, tuple.account));
} }
public async getMintInfosForGroup(group: Group): Promise<MintInfo[]> {
return (
await this.program.account.mintInfo.all([
{
memcmp: {
bytes: group.publicKey.toBase58(),
offset: 8,
},
},
])
).map((tuple) => {
return MintInfo.from(tuple.publicKey, tuple.account);
});
}
public async getMintInfoForTokenIndex(
group: Group,
tokenIndex: number,
): Promise<MintInfo[]> {
const tokenIndexBuf = Buffer.alloc(2);
tokenIndexBuf.writeUInt16LE(tokenIndex);
return (
await this.program.account.mintInfo.all([
{
memcmp: {
bytes: group.publicKey.toBase58(),
offset: 8,
},
},
{
memcmp: {
bytes: bs58.encode(tokenIndexBuf),
offset: 200,
},
},
])
).map((tuple) => {
return MintInfo.from(tuple.publicKey, tuple.account);
});
}
// Stub Oracle // Stub Oracle
public async createStubOracle( public async createStubOracle(
@ -181,6 +259,21 @@ export class MangoClient {
.rpc(); .rpc();
} }
public async closeStubOracle(
group: Group,
oracle: PublicKey,
): Promise<TransactionSignature> {
return await this.program.methods
.closeStubOracle()
.accounts({
group: group.publicKey,
oracle: oracle,
solDestination: (this.program.provider as AnchorProvider).wallet
.publicKey,
})
.rpc();
}
public async setStubOracle( public async setStubOracle(
group: Group, group: Group,
mintPk: PublicKey, mintPk: PublicKey,
@ -290,13 +383,12 @@ export class MangoClient {
.accounts({ .accounts({
account: mangoAccount.publicKey, account: mangoAccount.publicKey,
owner: (this.program.provider as AnchorProvider).wallet.publicKey, owner: (this.program.provider as AnchorProvider).wallet.publicKey,
solDestination: (this.program.provider as AnchorProvider).wallet solDestination: mangoAccount.owner,
.publicKey,
}) })
.rpc(); .rpc();
} }
public async deposit( public async tokenDeposit(
group: Group, group: Group,
mangoAccount: MangoAccount, mangoAccount: MangoAccount,
tokenName: string, tokenName: string,
@ -345,7 +437,7 @@ export class MangoClient {
await this.buildHealthRemainingAccounts(group, mangoAccount, [bank]); await this.buildHealthRemainingAccounts(group, mangoAccount, [bank]);
return await this.program.methods return await this.program.methods
.deposit(toNativeDecimals(amount, bank.mintDecimals)) .tokenDeposit(toNativeDecimals(amount, bank.mintDecimals))
.accounts({ .accounts({
group: group.publicKey, group: group.publicKey,
account: mangoAccount.publicKey, account: mangoAccount.publicKey,
@ -367,7 +459,7 @@ export class MangoClient {
.rpc({ skipPreflight: true }); .rpc({ skipPreflight: true });
} }
public async withdraw( public async tokenWithdraw(
group: Group, group: Group,
mangoAccount: MangoAccount, mangoAccount: MangoAccount,
tokenName: string, tokenName: string,
@ -385,7 +477,7 @@ export class MangoClient {
await this.buildHealthRemainingAccounts(group, mangoAccount, [bank]); await this.buildHealthRemainingAccounts(group, mangoAccount, [bank]);
return await this.program.methods return await this.program.methods
.withdraw(toNativeDecimals(amount, bank.mintDecimals), allowBorrow) .tokenWithdraw(toNativeDecimals(amount, bank.mintDecimals), allowBorrow)
.accounts({ .accounts({
group: group.publicKey, group: group.publicKey,
account: mangoAccount.publicKey, account: mangoAccount.publicKey,
@ -427,6 +519,23 @@ export class MangoClient {
.rpc(); .rpc();
} }
public async serum3deregisterMarket(
group: Group,
serum3MarketName: string,
): Promise<TransactionSignature> {
const serum3Market = group.serum3MarketsMap.get(serum3MarketName)!;
return await this.program.methods
.serum3DeregisterMarket()
.accounts({
group: group.publicKey,
serumMarket: serum3Market.publicKey,
solDestination: (this.program.provider as AnchorProvider).wallet
.publicKey,
})
.rpc();
}
public async serum3GetMarket( public async serum3GetMarket(
group: Group, group: Group,
baseTokenIndex?: number, baseTokenIndex?: number,
@ -492,6 +601,32 @@ export class MangoClient {
.rpc(); .rpc();
} }
public async serum3CloseOpenOrders(
group: Group,
mangoAccount: MangoAccount,
serum3MarketName: string,
): Promise<TransactionSignature> {
const serum3Market = group.serum3MarketsMap.get(serum3MarketName)!;
let openOrders = mangoAccount.serum3.find(
(account) => account.marketIndex === serum3Market.marketIndex,
)?.openOrders;
return await this.program.methods
.serum3CloseOpenOrders()
.accounts({
group: group.publicKey,
account: mangoAccount.publicKey,
serumMarket: serum3Market.publicKey,
serumProgram: serum3Market.serumProgram,
serumMarketExternal: serum3Market.serumMarketExternal,
openOrders,
solDestination: (this.program.provider as AnchorProvider).wallet
.publicKey,
})
.rpc();
}
public async serum3PlaceOrder( public async serum3PlaceOrder(
group: Group, group: Group,
mangoAccount: MangoAccount, mangoAccount: MangoAccount,
@ -589,6 +724,40 @@ export class MangoClient {
.rpc(); .rpc();
} }
async serum3CancelAllorders(
group: Group,
mangoAccount: MangoAccount,
serum3ProgramId: PublicKey,
serum3MarketName: string,
limit: number,
) {
const serum3Market = group.serum3MarketsMap.get(serum3MarketName)!;
const serum3MarketExternal = await Market.load(
this.program.provider.connection,
serum3Market.serumMarketExternal,
{ commitment: this.program.provider.connection.commitment },
serum3ProgramId,
);
return await this.program.methods
.serum3CancelAllOrders(limit)
.accounts({
group: group.publicKey,
account: mangoAccount.publicKey,
owner: (this.program.provider as AnchorProvider).wallet.publicKey,
openOrders: mangoAccount.findSerum3Account(serum3Market.marketIndex)
?.openOrders,
serumMarket: serum3Market.publicKey,
serumProgram: serum3ProgramId,
serumMarketExternal: serum3Market.serumMarketExternal,
marketBids: serum3MarketExternal.bidsAddress,
marketAsks: serum3MarketExternal.asksAddress,
marketEventQueue: serum3MarketExternal.decoded.eventQueue,
})
.rpc();
}
async serum3SettleFunds( async serum3SettleFunds(
group: Group, group: Group,
mangoAccount: MangoAccount, mangoAccount: MangoAccount,
@ -788,6 +957,27 @@ export class MangoClient {
.rpc(); .rpc();
} }
async perpCloseMarket(
group: Group,
perpMarketName: string,
): Promise<TransactionSignature> {
const perpMarket = group.perpMarketsMap.get(perpMarketName)!;
return await this.program.methods
.perpCloseMarket()
.accounts({
group: group.publicKey,
admin: (this.program.provider as AnchorProvider).wallet.publicKey,
perpMarket: perpMarket.publicKey,
asks: perpMarket.asks,
bids: perpMarket.bids,
eventQueue: perpMarket.eventQueue,
solDestination: (this.program.provider as AnchorProvider).wallet
.publicKey,
})
.rpc();
}
public async perpGetMarket( public async perpGetMarket(
group: Group, group: Group,
baseTokenIndex?: number, baseTokenIndex?: number,
@ -999,7 +1189,7 @@ export class MangoClient {
const mintInfos = await Promise.all( const mintInfos = await Promise.all(
[...new Set(tokenIndices)].map(async (tokenIndex) => [...new Set(tokenIndices)].map(async (tokenIndex) =>
getMintInfoForTokenIndex(this, group.publicKey, tokenIndex), this.getMintInfoForTokenIndex(group, tokenIndex),
), ),
); );
healthRemainingAccounts.push( healthRemainingAccounts.push(

View File

@ -49,11 +49,41 @@ export type MangoV4 = {
{ {
"name": "groupNum", "name": "groupNum",
"type": "u32" "type": "u32"
},
{
"name": "testing",
"type": "u8"
} }
] ]
}, },
{ {
"name": "registerToken", "name": "closeGroup",
"accounts": [
{
"name": "group",
"isMut": true,
"isSigner": false
},
{
"name": "admin",
"isMut": false,
"isSigner": true
},
{
"name": "solDestination",
"isMut": true,
"isSigner": false
},
{
"name": "tokenProgram",
"isMut": false,
"isSigner": false
}
],
"args": []
},
{
"name": "tokenRegister",
"accounts": [ "accounts": [
{ {
"name": "group", "name": "group",
@ -214,6 +244,47 @@ export type MangoV4 = {
} }
] ]
}, },
{
"name": "tokenDeregister",
"accounts": [
{
"name": "group",
"isMut": false,
"isSigner": false
},
{
"name": "admin",
"isMut": false,
"isSigner": true
},
{
"name": "bank",
"isMut": true,
"isSigner": false
},
{
"name": "vault",
"isMut": true,
"isSigner": false
},
{
"name": "mintInfo",
"isMut": true,
"isSigner": false
},
{
"name": "solDestination",
"isMut": true,
"isSigner": false
},
{
"name": "tokenProgram",
"isMut": false,
"isSigner": false
}
],
"args": []
},
{ {
"name": "updateIndex", "name": "updateIndex",
"accounts": [ "accounts": [
@ -378,6 +449,37 @@ export type MangoV4 = {
} }
] ]
}, },
{
"name": "closeStubOracle",
"accounts": [
{
"name": "group",
"isMut": false,
"isSigner": false
},
{
"name": "admin",
"isMut": false,
"isSigner": true
},
{
"name": "oracle",
"isMut": true,
"isSigner": false
},
{
"name": "solDestination",
"isMut": true,
"isSigner": false
},
{
"name": "tokenProgram",
"isMut": false,
"isSigner": false
}
],
"args": []
},
{ {
"name": "setStubOracle", "name": "setStubOracle",
"accounts": [ "accounts": [
@ -412,7 +514,7 @@ export type MangoV4 = {
] ]
}, },
{ {
"name": "deposit", "name": "tokenDeposit",
"accounts": [ "accounts": [
{ {
"name": "group", "name": "group",
@ -458,7 +560,7 @@ export type MangoV4 = {
] ]
}, },
{ {
"name": "withdraw", "name": "tokenWithdraw",
"accounts": [ "accounts": [
{ {
"name": "group", "name": "group",
@ -629,6 +731,37 @@ export type MangoV4 = {
} }
] ]
}, },
{
"name": "serum3DeregisterMarket",
"accounts": [
{
"name": "group",
"isMut": true,
"isSigner": false
},
{
"name": "admin",
"isMut": false,
"isSigner": true
},
{
"name": "serumMarket",
"isMut": true,
"isSigner": false
},
{
"name": "solDestination",
"isMut": true,
"isSigner": false
},
{
"name": "tokenProgram",
"isMut": false,
"isSigner": false
}
],
"args": []
},
{ {
"name": "serum3CreateOpenOrders", "name": "serum3CreateOpenOrders",
"accounts": [ "accounts": [
@ -704,6 +837,52 @@ export type MangoV4 = {
], ],
"args": [] "args": []
}, },
{
"name": "serum3CloseOpenOrders",
"accounts": [
{
"name": "group",
"isMut": false,
"isSigner": false
},
{
"name": "account",
"isMut": true,
"isSigner": false
},
{
"name": "owner",
"isMut": false,
"isSigner": true
},
{
"name": "serumMarket",
"isMut": false,
"isSigner": false
},
{
"name": "serumProgram",
"isMut": false,
"isSigner": false
},
{
"name": "serumMarketExternal",
"isMut": false,
"isSigner": false
},
{
"name": "openOrders",
"isMut": true,
"isSigner": false
},
{
"name": "solDestination",
"isMut": true,
"isSigner": false
}
],
"args": []
},
{ {
"name": "serum3PlaceOrder", "name": "serum3PlaceOrder",
"accounts": [ "accounts": [
@ -911,6 +1090,67 @@ export type MangoV4 = {
} }
] ]
}, },
{
"name": "serum3CancelAllOrders",
"accounts": [
{
"name": "group",
"isMut": false,
"isSigner": false
},
{
"name": "account",
"isMut": true,
"isSigner": false
},
{
"name": "owner",
"isMut": false,
"isSigner": true
},
{
"name": "openOrders",
"isMut": true,
"isSigner": false
},
{
"name": "serumMarket",
"isMut": false,
"isSigner": false
},
{
"name": "serumProgram",
"isMut": false,
"isSigner": false
},
{
"name": "serumMarketExternal",
"isMut": true,
"isSigner": false
},
{
"name": "marketBids",
"isMut": true,
"isSigner": false
},
{
"name": "marketAsks",
"isMut": true,
"isSigner": false
},
{
"name": "marketEventQueue",
"isMut": true,
"isSigner": false
}
],
"args": [
{
"name": "limit",
"type": "u8"
}
]
},
{ {
"name": "serum3SettleFunds", "name": "serum3SettleFunds",
"accounts": [ "accounts": [
@ -1270,6 +1510,52 @@ export type MangoV4 = {
} }
] ]
}, },
{
"name": "perpCloseMarket",
"accounts": [
{
"name": "group",
"isMut": false,
"isSigner": false
},
{
"name": "admin",
"isMut": false,
"isSigner": true
},
{
"name": "perpMarket",
"isMut": true,
"isSigner": false
},
{
"name": "bids",
"isMut": true,
"isSigner": false
},
{
"name": "asks",
"isMut": true,
"isSigner": false
},
{
"name": "eventQueue",
"isMut": true,
"isSigner": false
},
{
"name": "solDestination",
"isMut": true,
"isSigner": false
},
{
"name": "tokenProgram",
"isMut": false,
"isSigner": false
}
],
"args": []
},
{ {
"name": "perpPlaceOrder", "name": "perpPlaceOrder",
"accounts": [ "accounts": [
@ -1763,12 +2049,16 @@ export type MangoV4 = {
"name": "bump", "name": "bump",
"type": "u8" "type": "u8"
}, },
{
"name": "testing",
"type": "u8"
},
{ {
"name": "padding", "name": "padding",
"type": { "type": {
"array": [ "array": [
"u8", "u8",
3 2
] ]
} }
}, },
@ -2948,11 +3238,41 @@ export const IDL: MangoV4 = {
{ {
"name": "groupNum", "name": "groupNum",
"type": "u32" "type": "u32"
},
{
"name": "testing",
"type": "u8"
} }
] ]
}, },
{ {
"name": "registerToken", "name": "closeGroup",
"accounts": [
{
"name": "group",
"isMut": true,
"isSigner": false
},
{
"name": "admin",
"isMut": false,
"isSigner": true
},
{
"name": "solDestination",
"isMut": true,
"isSigner": false
},
{
"name": "tokenProgram",
"isMut": false,
"isSigner": false
}
],
"args": []
},
{
"name": "tokenRegister",
"accounts": [ "accounts": [
{ {
"name": "group", "name": "group",
@ -3113,6 +3433,47 @@ export const IDL: MangoV4 = {
} }
] ]
}, },
{
"name": "tokenDeregister",
"accounts": [
{
"name": "group",
"isMut": false,
"isSigner": false
},
{
"name": "admin",
"isMut": false,
"isSigner": true
},
{
"name": "bank",
"isMut": true,
"isSigner": false
},
{
"name": "vault",
"isMut": true,
"isSigner": false
},
{
"name": "mintInfo",
"isMut": true,
"isSigner": false
},
{
"name": "solDestination",
"isMut": true,
"isSigner": false
},
{
"name": "tokenProgram",
"isMut": false,
"isSigner": false
}
],
"args": []
},
{ {
"name": "updateIndex", "name": "updateIndex",
"accounts": [ "accounts": [
@ -3277,6 +3638,37 @@ export const IDL: MangoV4 = {
} }
] ]
}, },
{
"name": "closeStubOracle",
"accounts": [
{
"name": "group",
"isMut": false,
"isSigner": false
},
{
"name": "admin",
"isMut": false,
"isSigner": true
},
{
"name": "oracle",
"isMut": true,
"isSigner": false
},
{
"name": "solDestination",
"isMut": true,
"isSigner": false
},
{
"name": "tokenProgram",
"isMut": false,
"isSigner": false
}
],
"args": []
},
{ {
"name": "setStubOracle", "name": "setStubOracle",
"accounts": [ "accounts": [
@ -3311,7 +3703,7 @@ export const IDL: MangoV4 = {
] ]
}, },
{ {
"name": "deposit", "name": "tokenDeposit",
"accounts": [ "accounts": [
{ {
"name": "group", "name": "group",
@ -3357,7 +3749,7 @@ export const IDL: MangoV4 = {
] ]
}, },
{ {
"name": "withdraw", "name": "tokenWithdraw",
"accounts": [ "accounts": [
{ {
"name": "group", "name": "group",
@ -3528,6 +3920,37 @@ export const IDL: MangoV4 = {
} }
] ]
}, },
{
"name": "serum3DeregisterMarket",
"accounts": [
{
"name": "group",
"isMut": true,
"isSigner": false
},
{
"name": "admin",
"isMut": false,
"isSigner": true
},
{
"name": "serumMarket",
"isMut": true,
"isSigner": false
},
{
"name": "solDestination",
"isMut": true,
"isSigner": false
},
{
"name": "tokenProgram",
"isMut": false,
"isSigner": false
}
],
"args": []
},
{ {
"name": "serum3CreateOpenOrders", "name": "serum3CreateOpenOrders",
"accounts": [ "accounts": [
@ -3603,6 +4026,52 @@ export const IDL: MangoV4 = {
], ],
"args": [] "args": []
}, },
{
"name": "serum3CloseOpenOrders",
"accounts": [
{
"name": "group",
"isMut": false,
"isSigner": false
},
{
"name": "account",
"isMut": true,
"isSigner": false
},
{
"name": "owner",
"isMut": false,
"isSigner": true
},
{
"name": "serumMarket",
"isMut": false,
"isSigner": false
},
{
"name": "serumProgram",
"isMut": false,
"isSigner": false
},
{
"name": "serumMarketExternal",
"isMut": false,
"isSigner": false
},
{
"name": "openOrders",
"isMut": true,
"isSigner": false
},
{
"name": "solDestination",
"isMut": true,
"isSigner": false
}
],
"args": []
},
{ {
"name": "serum3PlaceOrder", "name": "serum3PlaceOrder",
"accounts": [ "accounts": [
@ -3810,6 +4279,67 @@ export const IDL: MangoV4 = {
} }
] ]
}, },
{
"name": "serum3CancelAllOrders",
"accounts": [
{
"name": "group",
"isMut": false,
"isSigner": false
},
{
"name": "account",
"isMut": true,
"isSigner": false
},
{
"name": "owner",
"isMut": false,
"isSigner": true
},
{
"name": "openOrders",
"isMut": true,
"isSigner": false
},
{
"name": "serumMarket",
"isMut": false,
"isSigner": false
},
{
"name": "serumProgram",
"isMut": false,
"isSigner": false
},
{
"name": "serumMarketExternal",
"isMut": true,
"isSigner": false
},
{
"name": "marketBids",
"isMut": true,
"isSigner": false
},
{
"name": "marketAsks",
"isMut": true,
"isSigner": false
},
{
"name": "marketEventQueue",
"isMut": true,
"isSigner": false
}
],
"args": [
{
"name": "limit",
"type": "u8"
}
]
},
{ {
"name": "serum3SettleFunds", "name": "serum3SettleFunds",
"accounts": [ "accounts": [
@ -4169,6 +4699,52 @@ export const IDL: MangoV4 = {
} }
] ]
}, },
{
"name": "perpCloseMarket",
"accounts": [
{
"name": "group",
"isMut": false,
"isSigner": false
},
{
"name": "admin",
"isMut": false,
"isSigner": true
},
{
"name": "perpMarket",
"isMut": true,
"isSigner": false
},
{
"name": "bids",
"isMut": true,
"isSigner": false
},
{
"name": "asks",
"isMut": true,
"isSigner": false
},
{
"name": "eventQueue",
"isMut": true,
"isSigner": false
},
{
"name": "solDestination",
"isMut": true,
"isSigner": false
},
{
"name": "tokenProgram",
"isMut": false,
"isSigner": false
}
],
"args": []
},
{ {
"name": "perpPlaceOrder", "name": "perpPlaceOrder",
"accounts": [ "accounts": [
@ -4662,12 +5238,16 @@ export const IDL: MangoV4 = {
"name": "bump", "name": "bump",
"type": "u8" "type": "u8"
}, },
{
"name": "testing",
"type": "u8"
},
{ {
"name": "padding", "name": "padding",
"type": { "type": {
"array": [ "array": [
"u8", "u8",
3 2
] ]
} }
}, },

View File

@ -0,0 +1,93 @@
import { AnchorProvider, Wallet } from '@project-serum/anchor';
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
import fs from 'fs';
import { MangoClient } from '../client';
export const DEVNET_MINTS = new Map([
['USDC', '8FRFC6MoGGkMFQwngccyu69VnYbzykGeez7ignHVAFSN'], // use devnet usdc
]);
async function main() {
const options = AnchorProvider.defaultOptions();
const connection = new Connection(
'https://mango.devnet.rpcpool.com',
options,
);
const admin = Keypair.fromSecretKey(
Buffer.from(
JSON.parse(fs.readFileSync(process.env.ADMIN_KEYPAIR!, 'utf-8')),
),
);
const adminWallet = new Wallet(admin);
console.log(`Admin ${adminWallet.publicKey.toBase58()}`);
const adminProvider = new AnchorProvider(connection, adminWallet, options);
const client = await MangoClient.connect(adminProvider, true);
const group = await client.getGroupForAdmin(admin.publicKey);
console.log(`Group ${group.publicKey}`);
let sig;
// close stub oracle
const usdcDevnetMint = new PublicKey(DEVNET_MINTS.get('USDC')!);
try {
const usdcDevnetOracle = await client.getStubOracle(group, usdcDevnetMint);
let sig = await client.closeStubOracle(group, usdcDevnetOracle.publicKey);
console.log(
`Closed USDC stub oracle, sig https://explorer.solana.com/address/${sig}?cluster=devnet`,
);
} catch (error) {
console.error(error);
}
// close all bank
for (const bank of group.banksMap.values()) {
try {
sig = await client.tokenDeregister(group, bank.name);
console.log(
`Removed token ${bank.name}, sig https://explorer.solana.com/address/${sig}?cluster=devnet`,
);
} catch (error) {
console.error(error);
}
}
// deregister all serum markets
for (const market of group.serum3MarketsMap.values()) {
try {
sig = await client.serum3deregisterMarket(group, market.name);
console.log(
`Deregistered serum market ${market.name}, sig https://explorer.solana.com/address/${sig}?cluster=devnet`,
);
} catch (error) {
console.error(error);
}
}
// close all perp markets
for (const market of group.perpMarketsMap.values()) {
try {
sig = await client.perpCloseMarket(group, market.name);
console.log(
`Closed perp market ${market.name}, sig https://explorer.solana.com/address/${sig}?cluster=devnet`,
);
} catch (error) {
console.error(error);
}
}
// finally, close the group
try {
sig = await client.closeGroup(group);
console.log(
`Closed group, sig https://explorer.solana.com/address/${sig}?cluster=devnet`,
);
} catch (error) {
console.error(error);
}
process.exit();
}
main();

View File

@ -49,7 +49,7 @@ async function main() {
// group // group
console.log(`Creating Group...`); console.log(`Creating Group...`);
try { try {
await client.createGroup(0); await client.createGroup(0, true);
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }
@ -61,7 +61,7 @@ async function main() {
const btcDevnetMint = new PublicKey(DEVNET_MINTS.get('BTC')!); const btcDevnetMint = new PublicKey(DEVNET_MINTS.get('BTC')!);
const btcDevnetOracle = new PublicKey(DEVNET_ORACLES.get('BTC')!); const btcDevnetOracle = new PublicKey(DEVNET_ORACLES.get('BTC')!);
try { try {
await client.registerToken( await client.tokenRegister(
group, group,
btcDevnetMint, btcDevnetMint,
btcDevnetOracle, btcDevnetOracle,
@ -94,8 +94,9 @@ async function main() {
console.log(error); console.log(error);
} }
const usdcDevnetOracle = await client.getStubOracle(group, usdcDevnetMint); const usdcDevnetOracle = await client.getStubOracle(group, usdcDevnetMint);
console.log(`...created stub oracle ${usdcDevnetOracle.publicKey}`);
try { try {
await client.registerToken( await client.tokenRegister(
group, group,
usdcDevnetMint, usdcDevnetMint,
usdcDevnetOracle.publicKey, usdcDevnetOracle.publicKey,
@ -122,7 +123,7 @@ async function main() {
const solDevnetMint = new PublicKey(DEVNET_MINTS.get('SOL')!); const solDevnetMint = new PublicKey(DEVNET_MINTS.get('SOL')!);
const solDevnetOracle = new PublicKey(DEVNET_ORACLES.get('SOL')!); const solDevnetOracle = new PublicKey(DEVNET_ORACLES.get('SOL')!);
try { try {
await client.registerToken( await client.tokenRegister(
group, group,
solDevnetMint, solDevnetMint,
solDevnetOracle, solDevnetOracle,
@ -151,7 +152,7 @@ async function main() {
const orcaDevnetMint = new PublicKey(DEVNET_MINTS.get('ORCA')!); const orcaDevnetMint = new PublicKey(DEVNET_MINTS.get('ORCA')!);
const orcaDevnetOracle = new PublicKey(DEVNET_ORACLES.get('ORCA')!); const orcaDevnetOracle = new PublicKey(DEVNET_ORACLES.get('ORCA')!);
try { try {
await client.registerToken( await client.tokenRegister(
group, group,
orcaDevnetMint, orcaDevnetMint,
orcaDevnetOracle, orcaDevnetOracle,

View File

@ -55,15 +55,15 @@ async function main() {
if (true) { if (true) {
// deposit and withdraw // deposit and withdraw
console.log(`Depositing...5 USDC`); console.log(`Depositing...5 USDC`);
await client.deposit(group, mangoAccount, 'USDC', 5); await client.tokenDeposit(group, mangoAccount, 'USDC', 5);
await mangoAccount.reload(client); await mangoAccount.reload(client);
console.log(`Depositing...0.0005 BTC`); console.log(`Depositing...0.0005 BTC`);
await client.deposit(group, mangoAccount, 'BTC', 0.0005); await client.tokenDeposit(group, mangoAccount, 'BTC', 0.0005);
await mangoAccount.reload(client); await mangoAccount.reload(client);
console.log(`Withdrawing...1 USDC`); console.log(`Withdrawing...1 USDC`);
await client.withdraw(group, mangoAccount, 'USDC', 1, false); await client.tokenWithdraw(group, mangoAccount, 'USDC', 1, false);
await mangoAccount.reload(client); await mangoAccount.reload(client);
// serum3 // serum3
@ -147,9 +147,6 @@ async function main() {
console.log(order); console.log(order);
} }
// console.log(`Close mango account...`);
// await client.closeMangoAccount(mangoAccount);
console.log(`Settling funds...`); console.log(`Settling funds...`);
await client.serum3SettleFunds( await client.serum3SettleFunds(
group, group,
@ -157,6 +154,16 @@ async function main() {
DEVNET_SERUM3_PROGRAM_ID, DEVNET_SERUM3_PROGRAM_ID,
'BTC/USDC', 'BTC/USDC',
); );
// try {
// console.log(`Close OO...`);
// await client.serum3CloseOpenOrders(group, mangoAccount, 'BTC/USDC');
// } catch (error) {
// console.log(error);
// }
// console.log(`Close mango account...`);
// await client.closeMangoAccount(mangoAccount);
} }
if (true) { if (true) {

View File

@ -82,7 +82,13 @@ async function main() {
while (true) { while (true) {
try { try {
console.log(`Withdrawing...${amount} 'BTC'`); console.log(`Withdrawing...${amount} 'BTC'`);
await user2Client.withdraw(group, user2MangoAccount, token, amount, true); await user2Client.tokenWithdraw(
group,
user2MangoAccount,
token,
amount,
true,
);
} catch (error) { } catch (error) {
console.log(error); console.log(error);
break; break;