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:
parent
40023fcef1
commit
740ff0c09e
|
@ -339,7 +339,7 @@ impl MangoClient {
|
|||
.collect())
|
||||
}
|
||||
|
||||
pub fn deposit(
|
||||
pub fn token_deposit(
|
||||
&self,
|
||||
token_name: &str,
|
||||
amount: u64,
|
||||
|
@ -356,7 +356,7 @@ impl MangoClient {
|
|||
program_id: mango_v4::id(),
|
||||
accounts: {
|
||||
let mut ams = anchor_lang::ToAccountMetas::to_account_metas(
|
||||
&mango_v4::accounts::Deposit {
|
||||
&mango_v4::accounts::TokenDeposit {
|
||||
group: self.group(),
|
||||
account: self.mango_account_cache.0,
|
||||
bank: bank.0,
|
||||
|
@ -373,7 +373,7 @@ impl MangoClient {
|
|||
ams.extend(health_check_metas.into_iter());
|
||||
ams
|
||||
},
|
||||
data: anchor_lang::InstructionData::data(&mango_v4::instruction::Deposit {
|
||||
data: anchor_lang::InstructionData::data(&mango_v4::instruction::TokenDeposit {
|
||||
amount,
|
||||
}),
|
||||
})
|
||||
|
|
|
@ -113,7 +113,7 @@ fn ensure_deposit(mango_client: &Arc<MangoClient>) -> Result<(), anyhow::Error>
|
|||
}
|
||||
|
||||
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(())
|
||||
|
|
|
@ -19,8 +19,20 @@ pub struct CloseAccount<'info> {
|
|||
pub token_program: Program<'info, Token>,
|
||||
}
|
||||
|
||||
pub fn close_account(_ctx: Context<CloseAccount>) -> Result<()> {
|
||||
// CRITICAL: currently can close any account, even one with bad health
|
||||
// TODO: Implement
|
||||
pub fn close_account(ctx: Context<CloseAccount>) -> Result<()> {
|
||||
let account = ctx.accounts.account.load()?;
|
||||
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(())
|
||||
}
|
||||
|
|
|
@ -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(())
|
||||
}
|
|
@ -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(())
|
||||
}
|
|
@ -23,10 +23,11 @@ pub struct CreateGroup<'info> {
|
|||
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()?;
|
||||
group.admin = ctx.accounts.admin.key();
|
||||
group.bump = *ctx.bumps.get("group").ok_or(MangoError::SomeError)?;
|
||||
group.group_num = group_num;
|
||||
group.testing = testing;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,53 +1,67 @@
|
|||
pub use self::margin_trade::*;
|
||||
pub use benchmark::*;
|
||||
pub use close_account::*;
|
||||
pub use close_group::*;
|
||||
pub use close_stub_oracle::*;
|
||||
pub use create_account::*;
|
||||
pub use create_group::*;
|
||||
pub use create_stub_oracle::*;
|
||||
pub use deposit::*;
|
||||
pub use liq_token_with_token::*;
|
||||
pub use perp_cancel_all_orders::*;
|
||||
pub use perp_cancel_all_orders_by_side::*;
|
||||
pub use perp_cancel_order::*;
|
||||
pub use perp_cancel_order_by_client_order_id::*;
|
||||
pub use perp_close_market::*;
|
||||
pub use perp_consume_events::*;
|
||||
pub use perp_create_market::*;
|
||||
pub use perp_place_order::*;
|
||||
pub use perp_update_funding::*;
|
||||
pub use register_token::*;
|
||||
pub use serum3_cancel_all_orders::*;
|
||||
pub use serum3_cancel_order::*;
|
||||
pub use serum3_close_open_orders::*;
|
||||
pub use serum3_create_open_orders::*;
|
||||
pub use serum3_deregister_market::*;
|
||||
pub use serum3_liq_force_cancel_orders::*;
|
||||
pub use serum3_place_order::*;
|
||||
pub use serum3_register_market::*;
|
||||
pub use serum3_settle_funds::*;
|
||||
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 withdraw::*;
|
||||
|
||||
mod benchmark;
|
||||
mod close_account;
|
||||
mod close_group;
|
||||
mod close_stub_oracle;
|
||||
mod create_account;
|
||||
mod create_group;
|
||||
mod create_stub_oracle;
|
||||
mod deposit;
|
||||
mod liq_token_with_token;
|
||||
pub mod margin_trade;
|
||||
mod margin_trade;
|
||||
mod perp_cancel_all_orders;
|
||||
mod perp_cancel_all_orders_by_side;
|
||||
mod perp_cancel_order;
|
||||
mod perp_cancel_order_by_client_order_id;
|
||||
mod perp_close_market;
|
||||
mod perp_consume_events;
|
||||
mod perp_create_market;
|
||||
mod perp_place_order;
|
||||
mod perp_update_funding;
|
||||
mod register_token;
|
||||
mod serum3_cancel_all_orders;
|
||||
mod serum3_cancel_order;
|
||||
mod serum3_close_open_orders;
|
||||
mod serum3_create_open_orders;
|
||||
mod serum3_deregister_market;
|
||||
mod serum3_liq_force_cancel_orders;
|
||||
mod serum3_place_order;
|
||||
mod serum3_register_market;
|
||||
mod serum3_settle_funds;
|
||||
mod set_stub_oracle;
|
||||
mod token_deposit;
|
||||
mod token_deregister;
|
||||
mod token_register;
|
||||
mod token_withdraw;
|
||||
mod update_index;
|
||||
mod withdraw;
|
||||
|
|
|
@ -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(())
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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(())
|
||||
}
|
|
@ -8,7 +8,7 @@ use crate::error::*;
|
|||
use crate::state::*;
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Deposit<'info> {
|
||||
pub struct TokenDeposit<'info> {
|
||||
pub group: AccountLoader<'info, Group>,
|
||||
|
||||
#[account(
|
||||
|
@ -36,7 +36,7 @@ pub struct Deposit<'info> {
|
|||
pub token_program: Program<'info, Token>,
|
||||
}
|
||||
|
||||
impl<'info> Deposit<'info> {
|
||||
impl<'info> TokenDeposit<'info> {
|
||||
pub fn transfer_ctx(&self) -> CpiContext<'_, '_, '_, 'info, token::Transfer<'info>> {
|
||||
let program = self.token_program.to_account_info();
|
||||
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.
|
||||
// That would save a lot of computation that needs to go into finding the
|
||||
// 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);
|
||||
|
||||
let token_index = ctx.accounts.bank.load()?.token_index;
|
|
@ -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(())
|
||||
}
|
|
@ -13,7 +13,7 @@ const INDEX_START: I80F48 = I80F48!(1_000_000);
|
|||
|
||||
#[derive(Accounts)]
|
||||
#[instruction(token_index: TokenIndex)]
|
||||
pub struct RegisterToken<'info> {
|
||||
pub struct TokenRegister<'info> {
|
||||
#[account(
|
||||
has_one = admin,
|
||||
)]
|
||||
|
@ -86,8 +86,8 @@ pub struct InterestRateParams {
|
|||
// TODO: should this be "configure_mint", we pass an explicit index, and allow
|
||||
// overwriting config as long as the mint account stays the same?
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn register_token(
|
||||
ctx: Context<RegisterToken>,
|
||||
pub fn token_register(
|
||||
ctx: Context<TokenRegister>,
|
||||
token_index: TokenIndex,
|
||||
name: String,
|
||||
interest_rate_params: InterestRateParams,
|
|
@ -7,7 +7,7 @@ use anchor_spl::token::TokenAccount;
|
|||
use fixed::types::I80F48;
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Withdraw<'info> {
|
||||
pub struct TokenWithdraw<'info> {
|
||||
pub group: AccountLoader<'info, Group>,
|
||||
|
||||
#[account(
|
||||
|
@ -36,7 +36,7 @@ pub struct Withdraw<'info> {
|
|||
pub token_program: Program<'info, Token>,
|
||||
}
|
||||
|
||||
impl<'info> Withdraw<'info> {
|
||||
impl<'info> TokenWithdraw<'info> {
|
||||
pub fn transfer_ctx(&self) -> CpiContext<'_, '_, '_, 'info, token::Transfer<'info>> {
|
||||
let program = self.token_program.to_account_info();
|
||||
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
|
||||
// right index for the mint.
|
||||
// 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);
|
||||
|
||||
let group = ctx.accounts.group.load()?;
|
|
@ -26,13 +26,17 @@ pub mod mango_v4 {
|
|||
|
||||
use super::*;
|
||||
|
||||
pub fn create_group(ctx: Context<CreateGroup>, group_num: u32) -> Result<()> {
|
||||
instructions::create_group(ctx, group_num)
|
||||
pub fn create_group(ctx: Context<CreateGroup>, group_num: u32, testing: u8) -> Result<()> {
|
||||
instructions::create_group(ctx, group_num, testing)
|
||||
}
|
||||
|
||||
pub fn close_group(ctx: Context<CloseGroup>) -> Result<()> {
|
||||
instructions::close_group(ctx)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn register_token(
|
||||
ctx: Context<RegisterToken>,
|
||||
pub fn token_register(
|
||||
ctx: Context<TokenRegister>,
|
||||
token_index: TokenIndex,
|
||||
name: String,
|
||||
interest_rate_params: InterestRateParams,
|
||||
|
@ -44,7 +48,7 @@ pub mod mango_v4 {
|
|||
init_liab_weight: f32,
|
||||
liquidation_fee: f32,
|
||||
) -> Result<()> {
|
||||
instructions::register_token(
|
||||
instructions::token_register(
|
||||
ctx,
|
||||
token_index,
|
||||
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<()> {
|
||||
instructions::update_index(ctx)
|
||||
}
|
||||
|
@ -86,16 +94,24 @@ pub mod mango_v4 {
|
|||
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<()> {
|
||||
instructions::set_stub_oracle(ctx, price)
|
||||
}
|
||||
|
||||
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
|
||||
instructions::deposit(ctx, amount)
|
||||
pub fn token_deposit(ctx: Context<TokenDeposit>, amount: u64) -> Result<()> {
|
||||
instructions::token_deposit(ctx, amount)
|
||||
}
|
||||
|
||||
pub fn withdraw(ctx: Context<Withdraw>, amount: u64, allow_borrow: bool) -> Result<()> {
|
||||
instructions::withdraw(ctx, amount, allow_borrow)
|
||||
pub fn token_withdraw(
|
||||
ctx: Context<TokenWithdraw>,
|
||||
amount: u64,
|
||||
allow_borrow: bool,
|
||||
) -> Result<()> {
|
||||
instructions::token_withdraw(ctx, amount, allow_borrow)
|
||||
}
|
||||
|
||||
pub fn margin_trade<'key, 'accounts, 'remaining, 'info>(
|
||||
|
@ -121,12 +137,20 @@ pub mod mango_v4 {
|
|||
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
|
||||
|
||||
pub fn serum3_create_open_orders(ctx: Context<Serum3CreateOpenOrders>) -> Result<()> {
|
||||
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)]
|
||||
pub fn serum3_place_order(
|
||||
ctx: Context<Serum3PlaceOrder>,
|
||||
|
@ -160,6 +184,10 @@ pub mod mango_v4 {
|
|||
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<()> {
|
||||
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
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
|
|
|
@ -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 program: AccountInfo<'info>,
|
||||
pub market: AccountInfo<'info>,
|
||||
|
|
|
@ -12,7 +12,10 @@ pub struct Group {
|
|||
pub admin: Pubkey,
|
||||
|
||||
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 reserved: [u8; 8],
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn iter_active(&self) -> impl Iterator<Item = &Serum3Account> {
|
||||
|
|
|
@ -367,7 +367,7 @@ impl<'keypair> ClientInstruction for MarginTradeInstruction<'keypair> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct WithdrawInstruction<'keypair> {
|
||||
pub struct TokenWithdrawInstruction<'keypair> {
|
||||
pub amount: u64,
|
||||
pub allow_borrow: bool,
|
||||
|
||||
|
@ -376,9 +376,9 @@ pub struct WithdrawInstruction<'keypair> {
|
|||
pub token_account: Pubkey,
|
||||
}
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl<'keypair> ClientInstruction for WithdrawInstruction<'keypair> {
|
||||
type Accounts = mango_v4::accounts::Withdraw;
|
||||
type Instruction = mango_v4::instruction::Withdraw;
|
||||
impl<'keypair> ClientInstruction for TokenWithdrawInstruction<'keypair> {
|
||||
type Accounts = mango_v4::accounts::TokenWithdraw;
|
||||
type Instruction = mango_v4::instruction::TokenWithdraw;
|
||||
async fn to_instruction(
|
||||
&self,
|
||||
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 account: Pubkey,
|
||||
|
@ -441,9 +441,9 @@ pub struct DepositInstruction<'keypair> {
|
|||
pub token_authority: &'keypair Keypair,
|
||||
}
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl<'keypair> ClientInstruction for DepositInstruction<'keypair> {
|
||||
type Accounts = mango_v4::accounts::Deposit;
|
||||
type Instruction = mango_v4::instruction::Deposit;
|
||||
impl<'keypair> ClientInstruction for TokenDepositInstruction<'keypair> {
|
||||
type Accounts = mango_v4::accounts::TokenDeposit;
|
||||
type Instruction = mango_v4::instruction::TokenDeposit;
|
||||
async fn to_instruction(
|
||||
&self,
|
||||
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 decimals: u8,
|
||||
pub util0: f32,
|
||||
|
@ -520,9 +520,9 @@ pub struct RegisterTokenInstruction<'keypair> {
|
|||
pub payer: &'keypair Keypair,
|
||||
}
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl<'keypair> ClientInstruction for RegisterTokenInstruction<'keypair> {
|
||||
type Accounts = mango_v4::accounts::RegisterToken;
|
||||
type Instruction = mango_v4::instruction::RegisterToken;
|
||||
impl<'keypair> ClientInstruction for TokenRegisterInstruction<'keypair> {
|
||||
type Accounts = mango_v4::accounts::TokenRegister;
|
||||
type Instruction = mango_v4::instruction::TokenRegister;
|
||||
async fn to_instruction(
|
||||
&self,
|
||||
_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 group: Pubkey,
|
||||
pub admin: &'keypair Keypair,
|
||||
|
@ -620,7 +687,7 @@ pub struct SetStubOracle<'keypair> {
|
|||
pub price: &'static str,
|
||||
}
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl<'keypair> ClientInstruction for SetStubOracle<'keypair> {
|
||||
impl<'keypair> ClientInstruction for SetStubOracleInstruction<'keypair> {
|
||||
type Accounts = mango_v4::accounts::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 admin: &'keypair Keypair,
|
||||
pub payer: &'keypair Keypair,
|
||||
|
@ -720,7 +832,10 @@ impl<'keypair> ClientInstruction for CreateGroupInstruction<'keypair> {
|
|||
_account_loader: impl ClientAccountLoader + 'async_trait,
|
||||
) -> (Self::Accounts, instruction::Instruction) {
|
||||
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(
|
||||
&[
|
||||
|
@ -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 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 account: 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 side: Serum3Side,
|
||||
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 account: Pubkey,
|
||||
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 group: Pubkey,
|
||||
pub account: Pubkey,
|
||||
|
|
|
@ -56,7 +56,7 @@ impl<'a> GroupWithTokensConfig<'a> {
|
|||
let oracle = create_stub_oracle_accounts.oracle;
|
||||
send_tx(
|
||||
solana,
|
||||
SetStubOracle {
|
||||
SetStubOracleInstruction {
|
||||
group,
|
||||
admin,
|
||||
mint: mint.pubkey,
|
||||
|
@ -69,7 +69,7 @@ impl<'a> GroupWithTokensConfig<'a> {
|
|||
let token_index = index as u16;
|
||||
let register_token_accounts = send_tx(
|
||||
solana,
|
||||
RegisterTokenInstruction {
|
||||
TokenRegisterInstruction {
|
||||
token_index,
|
||||
decimals: mint.decimals,
|
||||
util0: 0.40,
|
||||
|
|
|
@ -59,7 +59,7 @@ async fn test_basic() -> Result<(), TransportError> {
|
|||
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: deposit_amount,
|
||||
account,
|
||||
token_account: payer_mint0_account,
|
||||
|
@ -94,7 +94,7 @@ async fn test_basic() -> Result<(), TransportError> {
|
|||
|
||||
send_tx(
|
||||
solana,
|
||||
WithdrawInstruction {
|
||||
TokenWithdrawInstruction {
|
||||
amount: withdraw_amount,
|
||||
allow_borrow: true,
|
||||
account,
|
||||
|
@ -122,9 +122,25 @@ async fn test_basic() -> Result<(), TransportError> {
|
|||
}
|
||||
|
||||
//
|
||||
// TEST: Close account
|
||||
// TODO: This just checks execution, preconditions etc need to be tested!
|
||||
// TEST: Close account and de register bank
|
||||
//
|
||||
|
||||
// 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(
|
||||
solana,
|
||||
CloseAccountInstruction {
|
||||
|
@ -136,5 +152,46 @@ async fn test_basic() -> Result<(), TransportError> {
|
|||
.await
|
||||
.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(())
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ async fn test_group_address_lookup_tables() -> Result<()> {
|
|||
let oracle = create_stub_oracle_accounts.oracle;
|
||||
send_tx(
|
||||
solana,
|
||||
SetStubOracle {
|
||||
SetStubOracleInstruction {
|
||||
group,
|
||||
admin,
|
||||
mint: mint.pubkey,
|
||||
|
@ -134,7 +134,7 @@ async fn test_group_address_lookup_tables() -> Result<()> {
|
|||
for &payer_token in payer_mint_accounts {
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: deposit_amount,
|
||||
account,
|
||||
token_account: payer_token,
|
||||
|
@ -155,7 +155,7 @@ async fn test_group_address_lookup_tables() -> Result<()> {
|
|||
for &payer_token in payer_mint_accounts {
|
||||
send_tx(
|
||||
solana,
|
||||
WithdrawInstruction {
|
||||
TokenWithdrawInstruction {
|
||||
amount: withdraw_amount,
|
||||
allow_borrow: true,
|
||||
account,
|
||||
|
|
|
@ -55,7 +55,7 @@ async fn test_health_compute_tokens() -> Result<(), TransportError> {
|
|||
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: deposit_amount,
|
||||
account,
|
||||
token_account,
|
||||
|
@ -165,7 +165,7 @@ async fn test_health_compute_serum() -> Result<(), TransportError> {
|
|||
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: 10,
|
||||
account,
|
||||
token_account: payer_mint_accounts[0],
|
||||
|
@ -222,7 +222,7 @@ async fn test_health_compute_perp() -> Result<(), TransportError> {
|
|||
// Give the account some quote currency
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: 1000,
|
||||
account,
|
||||
token_account: payer_mint_accounts[0],
|
||||
|
@ -319,7 +319,7 @@ async fn test_health_compute_perp() -> Result<(), TransportError> {
|
|||
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: 10,
|
||||
account,
|
||||
token_account: payer_mint_accounts[0],
|
||||
|
|
|
@ -53,7 +53,7 @@ async fn test_liq_tokens_force_cancel() -> Result<(), TransportError> {
|
|||
for &token_account in payer_mint_accounts {
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: 10000,
|
||||
account: vault_account,
|
||||
token_account,
|
||||
|
@ -108,7 +108,7 @@ async fn test_liq_tokens_force_cancel() -> Result<(), TransportError> {
|
|||
let deposit_amount = 1000;
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: deposit_amount,
|
||||
account,
|
||||
token_account: payer_mint_accounts[1],
|
||||
|
@ -159,7 +159,7 @@ async fn test_liq_tokens_force_cancel() -> Result<(), TransportError> {
|
|||
//
|
||||
send_tx(
|
||||
solana,
|
||||
SetStubOracle {
|
||||
SetStubOracleInstruction {
|
||||
group,
|
||||
admin,
|
||||
mint: base_token.mint.pubkey,
|
||||
|
@ -173,7 +173,7 @@ async fn test_liq_tokens_force_cancel() -> Result<(), TransportError> {
|
|||
// can't withdraw
|
||||
assert!(send_tx(
|
||||
solana,
|
||||
WithdrawInstruction {
|
||||
TokenWithdrawInstruction {
|
||||
amount: 1,
|
||||
allow_borrow: false,
|
||||
account,
|
||||
|
@ -201,7 +201,7 @@ async fn test_liq_tokens_force_cancel() -> Result<(), TransportError> {
|
|||
// can withdraw again
|
||||
send_tx(
|
||||
solana,
|
||||
WithdrawInstruction {
|
||||
TokenWithdrawInstruction {
|
||||
amount: 2,
|
||||
allow_borrow: false,
|
||||
account,
|
||||
|
@ -258,7 +258,7 @@ async fn test_liq_tokens_with_token() -> Result<(), TransportError> {
|
|||
for &token_account in payer_mint_accounts {
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: 100000,
|
||||
account: vault_account,
|
||||
token_account,
|
||||
|
@ -289,7 +289,7 @@ async fn test_liq_tokens_with_token() -> Result<(), TransportError> {
|
|||
let deposit2_amount = 20;
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: deposit1_amount,
|
||||
account,
|
||||
token_account: payer_mint_accounts[2],
|
||||
|
@ -300,7 +300,7 @@ async fn test_liq_tokens_with_token() -> Result<(), TransportError> {
|
|||
.unwrap();
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: deposit2_amount,
|
||||
account,
|
||||
token_account: payer_mint_accounts[3],
|
||||
|
@ -314,7 +314,7 @@ async fn test_liq_tokens_with_token() -> Result<(), TransportError> {
|
|||
let borrow2_amount = 50;
|
||||
send_tx(
|
||||
solana,
|
||||
WithdrawInstruction {
|
||||
TokenWithdrawInstruction {
|
||||
amount: borrow1_amount,
|
||||
allow_borrow: true,
|
||||
account,
|
||||
|
@ -326,7 +326,7 @@ async fn test_liq_tokens_with_token() -> Result<(), TransportError> {
|
|||
.unwrap();
|
||||
send_tx(
|
||||
solana,
|
||||
WithdrawInstruction {
|
||||
TokenWithdrawInstruction {
|
||||
amount: borrow2_amount,
|
||||
allow_borrow: true,
|
||||
account,
|
||||
|
@ -342,7 +342,7 @@ async fn test_liq_tokens_with_token() -> Result<(), TransportError> {
|
|||
//
|
||||
send_tx(
|
||||
solana,
|
||||
SetStubOracle {
|
||||
SetStubOracleInstruction {
|
||||
group,
|
||||
admin,
|
||||
mint: borrow_token1.mint.pubkey,
|
||||
|
|
|
@ -64,7 +64,7 @@ async fn test_margin_trade() -> Result<(), BanksClientError> {
|
|||
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: provided_amount,
|
||||
account: provider_account,
|
||||
token_account: payer_mint0_account,
|
||||
|
@ -75,7 +75,7 @@ async fn test_margin_trade() -> Result<(), BanksClientError> {
|
|||
.unwrap();
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: provided_amount,
|
||||
account: provider_account,
|
||||
token_account: payer_mint1_account,
|
||||
|
@ -111,7 +111,7 @@ async fn test_margin_trade() -> Result<(), BanksClientError> {
|
|||
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: deposit_amount_initial,
|
||||
account,
|
||||
token_account: payer_mint0_account,
|
||||
|
|
|
@ -5,7 +5,7 @@ use fixed_macro::types::I80F48;
|
|||
use mango_v4::state::*;
|
||||
use 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;
|
||||
|
||||
|
@ -66,7 +66,7 @@ async fn test_perp() -> Result<(), TransportError> {
|
|||
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: deposit_amount,
|
||||
account: account_0,
|
||||
token_account: payer_mint_accounts[0],
|
||||
|
@ -78,7 +78,7 @@ async fn test_perp() -> Result<(), TransportError> {
|
|||
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: deposit_amount,
|
||||
account: account_0,
|
||||
token_account: payer_mint_accounts[1],
|
||||
|
@ -94,7 +94,7 @@ async fn test_perp() -> Result<(), TransportError> {
|
|||
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: deposit_amount,
|
||||
account: account_1,
|
||||
token_account: payer_mint_accounts[0],
|
||||
|
@ -106,7 +106,7 @@ async fn test_perp() -> Result<(), TransportError> {
|
|||
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: deposit_amount,
|
||||
account: account_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].quote_position_native, 100);
|
||||
|
||||
send_tx(
|
||||
solana,
|
||||
PerpCloseMarketInstruction {
|
||||
group,
|
||||
admin,
|
||||
perp_market,
|
||||
asks,
|
||||
bids,
|
||||
event_queue,
|
||||
sol_destination: payer.pubkey(),
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ async fn test_position_lifetime() -> Result<()> {
|
|||
for &payer_token in payer_mint_accounts {
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: funding_amount,
|
||||
account: funding_account,
|
||||
token_account: payer_token,
|
||||
|
@ -91,7 +91,7 @@ async fn test_position_lifetime() -> Result<()> {
|
|||
for &payer_token in payer_mint_accounts {
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: deposit_amount,
|
||||
account,
|
||||
token_account: payer_token,
|
||||
|
@ -106,7 +106,7 @@ async fn test_position_lifetime() -> Result<()> {
|
|||
for &payer_token in payer_mint_accounts {
|
||||
send_tx(
|
||||
solana,
|
||||
WithdrawInstruction {
|
||||
TokenWithdrawInstruction {
|
||||
amount: u64::MAX,
|
||||
allow_borrow: false,
|
||||
account,
|
||||
|
@ -141,7 +141,7 @@ async fn test_position_lifetime() -> Result<()> {
|
|||
let collateral_amount = 1000;
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: collateral_amount,
|
||||
account,
|
||||
token_account: payer_mint_accounts[0],
|
||||
|
@ -155,7 +155,7 @@ async fn test_position_lifetime() -> Result<()> {
|
|||
let borrow_amount = 10;
|
||||
send_tx(
|
||||
solana,
|
||||
WithdrawInstruction {
|
||||
TokenWithdrawInstruction {
|
||||
amount: borrow_amount,
|
||||
allow_borrow: true,
|
||||
account,
|
||||
|
@ -174,7 +174,7 @@ async fn test_position_lifetime() -> Result<()> {
|
|||
{
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
// deposit withdraw amount + some more to cover loan origination fees
|
||||
amount: borrow_amount + 2,
|
||||
account,
|
||||
|
@ -186,7 +186,7 @@ async fn test_position_lifetime() -> Result<()> {
|
|||
.unwrap();
|
||||
send_tx(
|
||||
solana,
|
||||
WithdrawInstruction {
|
||||
TokenWithdrawInstruction {
|
||||
// withdraw residual amount left
|
||||
amount: u64::MAX,
|
||||
allow_borrow: false,
|
||||
|
@ -202,7 +202,7 @@ async fn test_position_lifetime() -> Result<()> {
|
|||
// withdraw the collateral, closing the position
|
||||
send_tx(
|
||||
solana,
|
||||
WithdrawInstruction {
|
||||
TokenWithdrawInstruction {
|
||||
amount: collateral_amount,
|
||||
allow_borrow: false,
|
||||
account,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#![cfg(feature = "test-bpf")]
|
||||
|
||||
use solana_program_test::*;
|
||||
use solana_sdk::{signature::Keypair, transport::TransportError};
|
||||
use solana_sdk::{signature::Keypair, signer::Signer, transport::TransportError};
|
||||
|
||||
use mango_v4::{
|
||||
instructions::{Serum3OrderType, Serum3SelfTradeBehavior, Serum3Side},
|
||||
|
@ -65,7 +65,7 @@ async fn test_serum() -> Result<(), TransportError> {
|
|||
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: deposit_amount,
|
||||
account,
|
||||
token_account: payer_mint_accounts[0],
|
||||
|
@ -77,7 +77,7 @@ async fn test_serum() -> Result<(), TransportError> {
|
|||
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: deposit_amount,
|
||||
account,
|
||||
token_account: payer_mint_accounts[1],
|
||||
|
@ -204,5 +204,32 @@ async fn test_serum() -> Result<(), TransportError> {
|
|||
assert_eq!(native0, 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(())
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ async fn test_update_index() -> Result<(), TransportError> {
|
|||
for &token_account in payer_mint_accounts {
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: 10000,
|
||||
account: deposit_account,
|
||||
token_account,
|
||||
|
@ -73,7 +73,7 @@ async fn test_update_index() -> Result<(), TransportError> {
|
|||
|
||||
send_tx(
|
||||
solana,
|
||||
DepositInstruction {
|
||||
TokenDepositInstruction {
|
||||
amount: 100000,
|
||||
account: withdraw_account,
|
||||
token_account: payer_mint_accounts[1],
|
||||
|
@ -85,7 +85,7 @@ async fn test_update_index() -> Result<(), TransportError> {
|
|||
|
||||
send_tx(
|
||||
solana,
|
||||
WithdrawInstruction {
|
||||
TokenWithdrawInstruction {
|
||||
amount: 5000,
|
||||
allow_borrow: true,
|
||||
account: withdraw_account,
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import { BN } from '@project-serum/anchor';
|
||||
import { utf8 } from '@project-serum/anchor/dist/cjs/utils/bytes';
|
||||
import { PublicKey } from '@solana/web3.js';
|
||||
import bs58 from 'bs58';
|
||||
import { MangoClient } from '../client';
|
||||
import { I80F48, I80F48Dto } from './I80F48';
|
||||
|
||||
export const QUOTE_DECIMALS = 6;
|
||||
|
@ -145,30 +143,3 @@ export class MintInfo {
|
|||
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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { PublicKey } from '@solana/web3.js';
|
||||
import { MangoClient } from '../client';
|
||||
import { Bank } from './bank';
|
||||
import { Bank, MintInfo } from './bank';
|
||||
import { PerpMarket } from './perp';
|
||||
import { Serum3Market } from './serum3';
|
||||
|
||||
|
@ -16,6 +16,7 @@ export class Group {
|
|||
new Map(),
|
||||
new Map(),
|
||||
new Map(),
|
||||
new Map(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -26,6 +27,7 @@ export class Group {
|
|||
public banksMap: Map<string, Bank>,
|
||||
public serum3MarketsMap: Map<string, Serum3Market>,
|
||||
public perpMarketsMap: Map<string, PerpMarket>,
|
||||
public mintInfosMap: Map<string, MintInfo>,
|
||||
) {}
|
||||
|
||||
public findBank(tokenIndex: number): Bank | undefined {
|
||||
|
@ -36,6 +38,7 @@ export class Group {
|
|||
|
||||
public async reload(client: MangoClient) {
|
||||
await this.reloadBanks(client);
|
||||
await this.reloadMintInfos(client);
|
||||
await this.reloadSerum3Markets(client);
|
||||
await this.reloadPerpMarkets(client);
|
||||
}
|
||||
|
@ -45,6 +48,28 @@ export class Group {
|
|||
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) {
|
||||
const serum3Markets = await client.serum3GetMarket(this);
|
||||
this.serum3MarketsMap = new Map(
|
||||
|
|
|
@ -24,7 +24,7 @@ import {
|
|||
TransactionSignature,
|
||||
} from '@solana/web3.js';
|
||||
import bs58 from 'bs58';
|
||||
import { Bank, getMintInfoForTokenIndex } from './accounts/bank';
|
||||
import { Bank, MintInfo } from './accounts/bank';
|
||||
import { Group } from './accounts/group';
|
||||
import { I80F48 } from './accounts/I80F48';
|
||||
import { MangoAccount } from './accounts/mangoAccount';
|
||||
|
@ -56,10 +56,13 @@ export class MangoClient {
|
|||
|
||||
// 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;
|
||||
return await this.program.methods
|
||||
.createGroup(groupNum)
|
||||
.createGroup(groupNum, testing ? 1 : 0)
|
||||
.accounts({
|
||||
admin: adminPk,
|
||||
payer: adminPk,
|
||||
|
@ -67,6 +70,19 @@ export class MangoClient {
|
|||
.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> {
|
||||
const groupAccount = await this.program.account.group.fetch(groupPk);
|
||||
const group = Group.from(groupPk, groupAccount);
|
||||
|
@ -107,7 +123,7 @@ export class MangoClient {
|
|||
|
||||
// Tokens/Banks
|
||||
|
||||
public async registerToken(
|
||||
public async tokenRegister(
|
||||
group: Group,
|
||||
mintPk: PublicKey,
|
||||
oraclePk: PublicKey,
|
||||
|
@ -127,7 +143,7 @@ export class MangoClient {
|
|||
liquidationFee: number,
|
||||
): Promise<TransactionSignature> {
|
||||
return await this.program.methods
|
||||
.registerToken(
|
||||
.tokenRegister(
|
||||
tokenIndex,
|
||||
name,
|
||||
{ util0, rate0, util1, rate1, maxRate },
|
||||
|
@ -150,6 +166,27 @@ export class MangoClient {
|
|||
.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[]> {
|
||||
return (
|
||||
await this.program.account.bank.all([
|
||||
|
@ -163,6 +200,47 @@ export class MangoClient {
|
|||
).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
|
||||
|
||||
public async createStubOracle(
|
||||
|
@ -181,6 +259,21 @@ export class MangoClient {
|
|||
.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(
|
||||
group: Group,
|
||||
mintPk: PublicKey,
|
||||
|
@ -290,13 +383,12 @@ export class MangoClient {
|
|||
.accounts({
|
||||
account: mangoAccount.publicKey,
|
||||
owner: (this.program.provider as AnchorProvider).wallet.publicKey,
|
||||
solDestination: (this.program.provider as AnchorProvider).wallet
|
||||
.publicKey,
|
||||
solDestination: mangoAccount.owner,
|
||||
})
|
||||
.rpc();
|
||||
}
|
||||
|
||||
public async deposit(
|
||||
public async tokenDeposit(
|
||||
group: Group,
|
||||
mangoAccount: MangoAccount,
|
||||
tokenName: string,
|
||||
|
@ -345,7 +437,7 @@ export class MangoClient {
|
|||
await this.buildHealthRemainingAccounts(group, mangoAccount, [bank]);
|
||||
|
||||
return await this.program.methods
|
||||
.deposit(toNativeDecimals(amount, bank.mintDecimals))
|
||||
.tokenDeposit(toNativeDecimals(amount, bank.mintDecimals))
|
||||
.accounts({
|
||||
group: group.publicKey,
|
||||
account: mangoAccount.publicKey,
|
||||
|
@ -367,7 +459,7 @@ export class MangoClient {
|
|||
.rpc({ skipPreflight: true });
|
||||
}
|
||||
|
||||
public async withdraw(
|
||||
public async tokenWithdraw(
|
||||
group: Group,
|
||||
mangoAccount: MangoAccount,
|
||||
tokenName: string,
|
||||
|
@ -385,7 +477,7 @@ export class MangoClient {
|
|||
await this.buildHealthRemainingAccounts(group, mangoAccount, [bank]);
|
||||
|
||||
return await this.program.methods
|
||||
.withdraw(toNativeDecimals(amount, bank.mintDecimals), allowBorrow)
|
||||
.tokenWithdraw(toNativeDecimals(amount, bank.mintDecimals), allowBorrow)
|
||||
.accounts({
|
||||
group: group.publicKey,
|
||||
account: mangoAccount.publicKey,
|
||||
|
@ -427,6 +519,23 @@ export class MangoClient {
|
|||
.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(
|
||||
group: Group,
|
||||
baseTokenIndex?: number,
|
||||
|
@ -492,6 +601,32 @@ export class MangoClient {
|
|||
.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(
|
||||
group: Group,
|
||||
mangoAccount: MangoAccount,
|
||||
|
@ -589,6 +724,40 @@ export class MangoClient {
|
|||
.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(
|
||||
group: Group,
|
||||
mangoAccount: MangoAccount,
|
||||
|
@ -788,6 +957,27 @@ export class MangoClient {
|
|||
.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(
|
||||
group: Group,
|
||||
baseTokenIndex?: number,
|
||||
|
@ -999,7 +1189,7 @@ export class MangoClient {
|
|||
|
||||
const mintInfos = await Promise.all(
|
||||
[...new Set(tokenIndices)].map(async (tokenIndex) =>
|
||||
getMintInfoForTokenIndex(this, group.publicKey, tokenIndex),
|
||||
this.getMintInfoForTokenIndex(group, tokenIndex),
|
||||
),
|
||||
);
|
||||
healthRemainingAccounts.push(
|
||||
|
|
|
@ -49,11 +49,41 @@ export type MangoV4 = {
|
|||
{
|
||||
"name": "groupNum",
|
||||
"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": [
|
||||
{
|
||||
"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",
|
||||
"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",
|
||||
"accounts": [
|
||||
|
@ -412,7 +514,7 @@ export type MangoV4 = {
|
|||
]
|
||||
},
|
||||
{
|
||||
"name": "deposit",
|
||||
"name": "tokenDeposit",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "group",
|
||||
|
@ -458,7 +560,7 @@ export type MangoV4 = {
|
|||
]
|
||||
},
|
||||
{
|
||||
"name": "withdraw",
|
||||
"name": "tokenWithdraw",
|
||||
"accounts": [
|
||||
{
|
||||
"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",
|
||||
"accounts": [
|
||||
|
@ -704,6 +837,52 @@ export type MangoV4 = {
|
|||
],
|
||||
"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",
|
||||
"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",
|
||||
"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",
|
||||
"accounts": [
|
||||
|
@ -1763,12 +2049,16 @@ export type MangoV4 = {
|
|||
"name": "bump",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "testing",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "padding",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
3
|
||||
2
|
||||
]
|
||||
}
|
||||
},
|
||||
|
@ -2948,11 +3238,41 @@ export const IDL: MangoV4 = {
|
|||
{
|
||||
"name": "groupNum",
|
||||
"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": [
|
||||
{
|
||||
"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",
|
||||
"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",
|
||||
"accounts": [
|
||||
|
@ -3311,7 +3703,7 @@ export const IDL: MangoV4 = {
|
|||
]
|
||||
},
|
||||
{
|
||||
"name": "deposit",
|
||||
"name": "tokenDeposit",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "group",
|
||||
|
@ -3357,7 +3749,7 @@ export const IDL: MangoV4 = {
|
|||
]
|
||||
},
|
||||
{
|
||||
"name": "withdraw",
|
||||
"name": "tokenWithdraw",
|
||||
"accounts": [
|
||||
{
|
||||
"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",
|
||||
"accounts": [
|
||||
|
@ -3603,6 +4026,52 @@ export const IDL: MangoV4 = {
|
|||
],
|
||||
"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",
|
||||
"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",
|
||||
"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",
|
||||
"accounts": [
|
||||
|
@ -4662,12 +5238,16 @@ export const IDL: MangoV4 = {
|
|||
"name": "bump",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "testing",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "padding",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
3
|
||||
2
|
||||
]
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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();
|
|
@ -49,7 +49,7 @@ async function main() {
|
|||
// group
|
||||
console.log(`Creating Group...`);
|
||||
try {
|
||||
await client.createGroup(0);
|
||||
await client.createGroup(0, true);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ async function main() {
|
|||
const btcDevnetMint = new PublicKey(DEVNET_MINTS.get('BTC')!);
|
||||
const btcDevnetOracle = new PublicKey(DEVNET_ORACLES.get('BTC')!);
|
||||
try {
|
||||
await client.registerToken(
|
||||
await client.tokenRegister(
|
||||
group,
|
||||
btcDevnetMint,
|
||||
btcDevnetOracle,
|
||||
|
@ -94,8 +94,9 @@ async function main() {
|
|||
console.log(error);
|
||||
}
|
||||
const usdcDevnetOracle = await client.getStubOracle(group, usdcDevnetMint);
|
||||
console.log(`...created stub oracle ${usdcDevnetOracle.publicKey}`);
|
||||
try {
|
||||
await client.registerToken(
|
||||
await client.tokenRegister(
|
||||
group,
|
||||
usdcDevnetMint,
|
||||
usdcDevnetOracle.publicKey,
|
||||
|
@ -122,7 +123,7 @@ async function main() {
|
|||
const solDevnetMint = new PublicKey(DEVNET_MINTS.get('SOL')!);
|
||||
const solDevnetOracle = new PublicKey(DEVNET_ORACLES.get('SOL')!);
|
||||
try {
|
||||
await client.registerToken(
|
||||
await client.tokenRegister(
|
||||
group,
|
||||
solDevnetMint,
|
||||
solDevnetOracle,
|
||||
|
@ -151,7 +152,7 @@ async function main() {
|
|||
const orcaDevnetMint = new PublicKey(DEVNET_MINTS.get('ORCA')!);
|
||||
const orcaDevnetOracle = new PublicKey(DEVNET_ORACLES.get('ORCA')!);
|
||||
try {
|
||||
await client.registerToken(
|
||||
await client.tokenRegister(
|
||||
group,
|
||||
orcaDevnetMint,
|
||||
orcaDevnetOracle,
|
||||
|
|
|
@ -55,15 +55,15 @@ async function main() {
|
|||
if (true) {
|
||||
// deposit and withdraw
|
||||
console.log(`Depositing...5 USDC`);
|
||||
await client.deposit(group, mangoAccount, 'USDC', 5);
|
||||
await client.tokenDeposit(group, mangoAccount, 'USDC', 5);
|
||||
await mangoAccount.reload(client);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
// serum3
|
||||
|
@ -147,9 +147,6 @@ async function main() {
|
|||
console.log(order);
|
||||
}
|
||||
|
||||
// console.log(`Close mango account...`);
|
||||
// await client.closeMangoAccount(mangoAccount);
|
||||
|
||||
console.log(`Settling funds...`);
|
||||
await client.serum3SettleFunds(
|
||||
group,
|
||||
|
@ -157,6 +154,16 @@ async function main() {
|
|||
DEVNET_SERUM3_PROGRAM_ID,
|
||||
'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) {
|
||||
|
|
|
@ -82,7 +82,13 @@ async function main() {
|
|||
while (true) {
|
||||
try {
|
||||
console.log(`Withdrawing...${amount} 'BTC'`);
|
||||
await user2Client.withdraw(group, user2MangoAccount, token, amount, true);
|
||||
await user2Client.tokenWithdraw(
|
||||
group,
|
||||
user2MangoAccount,
|
||||
token,
|
||||
amount,
|
||||
true,
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue