edit tokens, perp markets, mango accounts, allow delegate to perform certain operations (#94)
Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>
This commit is contained in:
parent
dc4aee885b
commit
d74cc78a84
|
@ -9,6 +9,7 @@ pub struct CloseAccount<'info> {
|
|||
|
||||
#[account(
|
||||
mut,
|
||||
// note: should never be the delegate
|
||||
has_one = owner,
|
||||
has_one = group,
|
||||
close = sol_destination
|
||||
|
|
|
@ -17,7 +17,6 @@ pub struct CreateAccount<'info> {
|
|||
space = 8 + std::mem::size_of::<MangoAccount>(),
|
||||
)]
|
||||
pub account: AccountLoader<'info, MangoAccount>,
|
||||
|
||||
pub owner: Signer<'info>,
|
||||
|
||||
#[account(mut)]
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
use crate::error::MangoError;
|
||||
use anchor_lang::prelude::*;
|
||||
|
||||
use crate::state::*;
|
||||
use crate::util::fill32_from_str;
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct EditAccount<'info> {
|
||||
pub group: AccountLoader<'info, Group>,
|
||||
|
||||
#[account(
|
||||
mut,
|
||||
// Note: should never be the delegate
|
||||
has_one = owner,
|
||||
has_one = group,
|
||||
)]
|
||||
pub account: AccountLoader<'info, MangoAccount>,
|
||||
pub owner: Signer<'info>,
|
||||
}
|
||||
|
||||
pub fn edit_account(
|
||||
ctx: Context<EditAccount>,
|
||||
name_opt: Option<String>,
|
||||
// note: can also be used to unset by using the default pubkey here as a param
|
||||
delegate_opt: Option<Pubkey>,
|
||||
) -> Result<()> {
|
||||
require!(
|
||||
name_opt.is_some() || delegate_opt.is_some(),
|
||||
MangoError::SomeError
|
||||
);
|
||||
|
||||
let mut account = ctx.accounts.account.load_mut()?;
|
||||
|
||||
// msg!("old account {:#?}", account);
|
||||
|
||||
// note: unchanged fields are inline, and match exact definition in create_account
|
||||
// please maintain, and don't remove, makes it easy to reason about which support modification by owner
|
||||
|
||||
if let Some(name) = name_opt {
|
||||
account.name = fill32_from_str(name)?;
|
||||
}
|
||||
|
||||
// unchanged -
|
||||
// owner
|
||||
// account_num
|
||||
// bump
|
||||
|
||||
if let Some(delegate) = delegate_opt {
|
||||
account.delegate = delegate;
|
||||
}
|
||||
|
||||
// unchanged -
|
||||
// tokens
|
||||
// serum3
|
||||
// perps
|
||||
// being_liquidated
|
||||
// is_bankrupt
|
||||
|
||||
// msg!("new account {:#?}", account);
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -32,7 +32,7 @@ pub struct FlashLoan<'info> {
|
|||
#[account(
|
||||
mut,
|
||||
has_one = group,
|
||||
has_one = owner,
|
||||
constraint = account.load()?.is_owner_or_delegate(owner.key()),
|
||||
)]
|
||||
pub account: AccountLoader<'info, MangoAccount>,
|
||||
|
||||
|
|
|
@ -37,11 +37,12 @@ pub struct FlashLoan2End<'info> {
|
|||
pub group: AccountLoader<'info, Group>,
|
||||
#[account(
|
||||
mut,
|
||||
has_one = owner,
|
||||
has_one = group,
|
||||
constraint = account.load()?.is_owner_or_delegate(owner.key()),
|
||||
)]
|
||||
pub account: AccountLoader<'info, MangoAccount>,
|
||||
pub owner: Signer<'info>,
|
||||
|
||||
pub token_program: Program<'info, Token>,
|
||||
}
|
||||
|
||||
|
|
|
@ -40,10 +40,11 @@ pub struct FlashLoan3Begin<'info> {
|
|||
pub struct FlashLoan3End<'info> {
|
||||
#[account(
|
||||
mut,
|
||||
has_one = owner,
|
||||
constraint = account.load()?.is_owner_or_delegate(owner.key()),
|
||||
)]
|
||||
pub account: AccountLoader<'info, MangoAccount>,
|
||||
pub owner: Signer<'info>,
|
||||
|
||||
pub token_program: Program<'info, Token>,
|
||||
}
|
||||
|
||||
|
|
|
@ -15,9 +15,9 @@ pub struct LiqTokenWithToken<'info> {
|
|||
#[account(
|
||||
mut,
|
||||
has_one = group,
|
||||
constraint = liqor.load()?.owner == liqor_owner.key() || liqor.load()?.delegate == liqor_owner.key(),
|
||||
)]
|
||||
pub liqor: AccountLoader<'info, MangoAccount>,
|
||||
#[account(address = liqor.load()?.owner)]
|
||||
pub liqor_owner: Signer<'info>,
|
||||
|
||||
#[account(
|
||||
|
|
|
@ -6,6 +6,7 @@ pub use compute_account_data::*;
|
|||
pub use create_account::*;
|
||||
pub use create_group::*;
|
||||
pub use create_stub_oracle::*;
|
||||
pub use edit_account::*;
|
||||
pub use flash_loan::*;
|
||||
pub use flash_loan2::*;
|
||||
pub use flash_loan3::*;
|
||||
|
@ -17,6 +18,7 @@ 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_edit_market::*;
|
||||
pub use perp_place_order::*;
|
||||
pub use perp_update_funding::*;
|
||||
pub use serum3_cancel_all_orders::*;
|
||||
|
@ -32,6 +34,7 @@ pub use set_stub_oracle::*;
|
|||
pub use token_add_bank::*;
|
||||
pub use token_deposit::*;
|
||||
pub use token_deregister::*;
|
||||
pub use token_edit::*;
|
||||
pub use token_register::*;
|
||||
pub use token_withdraw::*;
|
||||
pub use update_index::*;
|
||||
|
@ -44,6 +47,7 @@ mod compute_account_data;
|
|||
mod create_account;
|
||||
mod create_group;
|
||||
mod create_stub_oracle;
|
||||
mod edit_account;
|
||||
mod flash_loan;
|
||||
mod flash_loan2;
|
||||
mod flash_loan3;
|
||||
|
@ -55,6 +59,7 @@ mod perp_cancel_order_by_client_order_id;
|
|||
mod perp_close_market;
|
||||
mod perp_consume_events;
|
||||
mod perp_create_market;
|
||||
mod perp_edit_market;
|
||||
mod perp_place_order;
|
||||
mod perp_update_funding;
|
||||
mod serum3_cancel_all_orders;
|
||||
|
@ -70,6 +75,7 @@ mod set_stub_oracle;
|
|||
mod token_add_bank;
|
||||
mod token_deposit;
|
||||
mod token_deregister;
|
||||
mod token_edit;
|
||||
mod token_register;
|
||||
mod token_withdraw;
|
||||
mod update_index;
|
||||
|
|
|
@ -10,9 +10,10 @@ pub struct PerpCancelAllOrders<'info> {
|
|||
#[account(
|
||||
mut,
|
||||
has_one = group,
|
||||
has_one = owner,
|
||||
constraint = account.load()?.is_owner_or_delegate(owner.key()),
|
||||
)]
|
||||
pub account: AccountLoader<'info, MangoAccount>,
|
||||
pub owner: Signer<'info>,
|
||||
|
||||
#[account(
|
||||
mut,
|
||||
|
@ -25,8 +26,6 @@ pub struct PerpCancelAllOrders<'info> {
|
|||
pub asks: AccountLoader<'info, BookSide>,
|
||||
#[account(mut)]
|
||||
pub bids: AccountLoader<'info, BookSide>,
|
||||
|
||||
pub owner: Signer<'info>,
|
||||
}
|
||||
|
||||
pub fn perp_cancel_all_orders(ctx: Context<PerpCancelAllOrders>, limit: u8) -> Result<()> {
|
||||
|
|
|
@ -10,9 +10,10 @@ pub struct PerpCancelAllOrdersBySide<'info> {
|
|||
#[account(
|
||||
mut,
|
||||
has_one = group,
|
||||
has_one = owner,
|
||||
constraint = account.load()?.is_owner_or_delegate(owner.key()),
|
||||
)]
|
||||
pub account: AccountLoader<'info, MangoAccount>,
|
||||
pub owner: Signer<'info>,
|
||||
|
||||
#[account(
|
||||
mut,
|
||||
|
@ -25,8 +26,6 @@ pub struct PerpCancelAllOrdersBySide<'info> {
|
|||
pub asks: AccountLoader<'info, BookSide>,
|
||||
#[account(mut)]
|
||||
pub bids: AccountLoader<'info, BookSide>,
|
||||
|
||||
pub owner: Signer<'info>,
|
||||
}
|
||||
|
||||
pub fn perp_cancel_all_orders_by_side(
|
||||
|
|
|
@ -10,9 +10,10 @@ pub struct PerpCancelOrder<'info> {
|
|||
#[account(
|
||||
mut,
|
||||
has_one = group,
|
||||
has_one = owner,
|
||||
constraint = account.load()?.is_owner_or_delegate(owner.key()),
|
||||
)]
|
||||
pub account: AccountLoader<'info, MangoAccount>,
|
||||
pub owner: Signer<'info>,
|
||||
|
||||
#[account(
|
||||
mut,
|
||||
|
@ -25,8 +26,6 @@ pub struct PerpCancelOrder<'info> {
|
|||
pub asks: AccountLoader<'info, BookSide>,
|
||||
#[account(mut)]
|
||||
pub bids: AccountLoader<'info, BookSide>,
|
||||
|
||||
pub owner: Signer<'info>,
|
||||
}
|
||||
|
||||
pub fn perp_cancel_order(ctx: Context<PerpCancelOrder>, order_id: i128) -> Result<()> {
|
||||
|
|
|
@ -10,9 +10,10 @@ pub struct PerpCancelOrderByClientOrderId<'info> {
|
|||
#[account(
|
||||
mut,
|
||||
has_one = group,
|
||||
has_one = owner,
|
||||
constraint = account.load()?.is_owner_or_delegate(owner.key()),
|
||||
)]
|
||||
pub account: AccountLoader<'info, MangoAccount>,
|
||||
pub owner: Signer<'info>,
|
||||
|
||||
#[account(
|
||||
mut,
|
||||
|
@ -25,8 +26,6 @@ pub struct PerpCancelOrderByClientOrderId<'info> {
|
|||
pub asks: AccountLoader<'info, BookSide>,
|
||||
#[account(mut)]
|
||||
pub bids: AccountLoader<'info, BookSide>,
|
||||
|
||||
pub owner: Signer<'info>,
|
||||
}
|
||||
|
||||
pub fn perp_cancel_order_by_client_order_id(
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
use crate::state::*;
|
||||
use anchor_lang::prelude::*;
|
||||
use fixed::types::I80F48;
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct PerpEditMarket<'info> {
|
||||
#[account(
|
||||
has_one = admin,
|
||||
)]
|
||||
pub group: AccountLoader<'info, Group>,
|
||||
pub admin: Signer<'info>,
|
||||
|
||||
#[account(
|
||||
mut,
|
||||
has_one = group
|
||||
)]
|
||||
pub perp_market: AccountLoader<'info, PerpMarket>,
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn perp_edit_market(
|
||||
ctx: Context<PerpEditMarket>,
|
||||
oracle_opt: Option<Pubkey>,
|
||||
oracle_config_opt: Option<OracleConfig>,
|
||||
base_token_index_opt: Option<TokenIndex>,
|
||||
base_token_decimals_opt: Option<u8>,
|
||||
maint_asset_weight_opt: Option<f32>,
|
||||
init_asset_weight_opt: Option<f32>,
|
||||
maint_liab_weight_opt: Option<f32>,
|
||||
init_liab_weight_opt: Option<f32>,
|
||||
liquidation_fee_opt: Option<f32>,
|
||||
maker_fee_opt: Option<f32>,
|
||||
taker_fee_opt: Option<f32>,
|
||||
min_funding_opt: Option<f32>,
|
||||
max_funding_opt: Option<f32>,
|
||||
impact_quantity_opt: Option<i64>,
|
||||
) -> Result<()> {
|
||||
let mut perp_market = ctx.accounts.perp_market.load_mut()?;
|
||||
|
||||
// note: unchanged fields are inline, and match exact definition in perp_register_market
|
||||
// please maintain, and don't remove, makes it easy to reason about which support admin modification
|
||||
|
||||
// unchanged -
|
||||
// name
|
||||
// group
|
||||
|
||||
if let Some(oracle) = oracle_opt {
|
||||
perp_market.oracle = oracle;
|
||||
}
|
||||
if let Some(oracle_config) = oracle_config_opt {
|
||||
perp_market.oracle_config = oracle_config;
|
||||
};
|
||||
|
||||
// unchanged -
|
||||
// bids
|
||||
// asks
|
||||
// event_queue
|
||||
// quote_lot_size
|
||||
// base_lot_size
|
||||
|
||||
if let Some(maint_asset_weight) = maint_asset_weight_opt {
|
||||
perp_market.maint_asset_weight = I80F48::from_num(maint_asset_weight);
|
||||
}
|
||||
if let Some(init_asset_weight) = init_asset_weight_opt {
|
||||
perp_market.init_asset_weight = I80F48::from_num(init_asset_weight);
|
||||
}
|
||||
if let Some(maint_liab_weight) = maint_liab_weight_opt {
|
||||
perp_market.maint_liab_weight = I80F48::from_num(maint_liab_weight);
|
||||
}
|
||||
if let Some(init_liab_weight) = init_liab_weight_opt {
|
||||
perp_market.init_liab_weight = I80F48::from_num(init_liab_weight);
|
||||
}
|
||||
if let Some(liquidation_fee) = liquidation_fee_opt {
|
||||
perp_market.liquidation_fee = I80F48::from_num(liquidation_fee);
|
||||
}
|
||||
|
||||
if let Some(maker_fee) = maker_fee_opt {
|
||||
perp_market.maker_fee = I80F48::from_num(maker_fee);
|
||||
}
|
||||
if let Some(taker_fee) = taker_fee_opt {
|
||||
perp_market.taker_fee = I80F48::from_num(taker_fee);
|
||||
}
|
||||
|
||||
if let Some(min_funding) = min_funding_opt {
|
||||
perp_market.min_funding = I80F48::from_num(min_funding);
|
||||
}
|
||||
if let Some(max_funding) = max_funding_opt {
|
||||
perp_market.max_funding = I80F48::from_num(max_funding);
|
||||
}
|
||||
if let Some(impact_quantity) = impact_quantity_opt {
|
||||
perp_market.impact_quantity = impact_quantity;
|
||||
}
|
||||
|
||||
// unchanged -
|
||||
// long_funding
|
||||
// short_funding
|
||||
// funding_last_updated
|
||||
// open_interest
|
||||
// seq_num
|
||||
// fees_accrued
|
||||
// bump
|
||||
|
||||
if let Some(base_token_decimals) = base_token_decimals_opt {
|
||||
perp_market.base_token_decimals = base_token_decimals;
|
||||
}
|
||||
|
||||
// unchanged -
|
||||
// perp_market_index
|
||||
|
||||
if let Some(base_token_index) = base_token_index_opt {
|
||||
perp_market.base_token_index = base_token_index;
|
||||
}
|
||||
|
||||
// unchanged -
|
||||
// quote_token_index
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -14,9 +14,10 @@ pub struct PerpPlaceOrder<'info> {
|
|||
#[account(
|
||||
mut,
|
||||
has_one = group,
|
||||
has_one = owner,
|
||||
constraint = account.load()?.is_owner_or_delegate(owner.key()),
|
||||
)]
|
||||
pub account: AccountLoader<'info, MangoAccount>,
|
||||
pub owner: Signer<'info>,
|
||||
|
||||
#[account(
|
||||
mut,
|
||||
|
@ -36,8 +37,6 @@ pub struct PerpPlaceOrder<'info> {
|
|||
|
||||
/// CHECK: The oracle can be one of several different account types and the pubkey is checked above
|
||||
pub oracle: UncheckedAccount<'info>,
|
||||
|
||||
pub owner: Signer<'info>,
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
|
|
@ -10,7 +10,7 @@ pub struct Serum3CancelAllOrders<'info> {
|
|||
#[account(
|
||||
mut,
|
||||
has_one = group,
|
||||
has_one = owner,
|
||||
constraint = account.load()?.is_owner_or_delegate(owner.key()),
|
||||
)]
|
||||
pub account: AccountLoader<'info, MangoAccount>,
|
||||
pub owner: Signer<'info>,
|
||||
|
|
|
@ -17,7 +17,7 @@ pub struct Serum3CancelOrder<'info> {
|
|||
#[account(
|
||||
mut,
|
||||
has_one = group,
|
||||
has_one = owner,
|
||||
constraint = account.load()?.is_owner_or_delegate(owner.key()),
|
||||
)]
|
||||
pub account: AccountLoader<'info, MangoAccount>,
|
||||
pub owner: Signer<'info>,
|
||||
|
|
|
@ -10,7 +10,7 @@ pub struct Serum3CloseOpenOrders<'info> {
|
|||
#[account(
|
||||
mut,
|
||||
has_one = group,
|
||||
has_one = owner,
|
||||
constraint = account.load()?.is_owner_or_delegate(owner.key()),
|
||||
)]
|
||||
pub account: AccountLoader<'info, MangoAccount>,
|
||||
pub owner: Signer<'info>,
|
||||
|
|
|
@ -10,9 +10,10 @@ pub struct Serum3CreateOpenOrders<'info> {
|
|||
#[account(
|
||||
mut,
|
||||
has_one = group,
|
||||
has_one = owner,
|
||||
constraint = account.load()?.is_owner_or_delegate(owner.key()),
|
||||
)]
|
||||
pub account: AccountLoader<'info, MangoAccount>,
|
||||
pub owner: Signer<'info>,
|
||||
|
||||
#[account(
|
||||
has_one = group,
|
||||
|
@ -38,8 +39,6 @@ pub struct Serum3CreateOpenOrders<'info> {
|
|||
/// CHECK: Newly created by serum cpi call
|
||||
pub open_orders: UncheckedAccount<'info>,
|
||||
|
||||
pub owner: Signer<'info>,
|
||||
|
||||
#[account(mut)]
|
||||
pub payer: Signer<'info>,
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ pub struct Serum3PlaceOrder<'info> {
|
|||
#[account(
|
||||
mut,
|
||||
has_one = group,
|
||||
has_one = owner,
|
||||
constraint = account.load()?.is_owner_or_delegate(owner.key()),
|
||||
)]
|
||||
pub account: AccountLoader<'info, MangoAccount>,
|
||||
pub owner: Signer<'info>,
|
||||
|
|
|
@ -18,7 +18,7 @@ pub struct Serum3SettleFunds<'info> {
|
|||
#[account(
|
||||
mut,
|
||||
has_one = group,
|
||||
has_one = owner,
|
||||
constraint = account.load()?.is_owner_or_delegate(owner.key()),
|
||||
)]
|
||||
pub account: AccountLoader<'info, MangoAccount>,
|
||||
pub owner: Signer<'info>,
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
use anchor_lang::prelude::*;
|
||||
|
||||
use fixed::types::I80F48;
|
||||
|
||||
use super::InterestRateParams;
|
||||
use crate::accounts_zerocopy::LoadMutZeroCopyRef;
|
||||
|
||||
use crate::state::*;
|
||||
|
||||
#[derive(Accounts)]
|
||||
#[instruction(token_index: TokenIndex, bank_num: u64)]
|
||||
pub struct TokenEdit<'info> {
|
||||
#[account(
|
||||
has_one = admin,
|
||||
)]
|
||||
pub group: AccountLoader<'info, Group>,
|
||||
pub admin: Signer<'info>,
|
||||
|
||||
#[account(
|
||||
has_one = group
|
||||
)]
|
||||
pub mint_info: AccountLoader<'info, MintInfo>,
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn token_edit(
|
||||
ctx: Context<TokenEdit>,
|
||||
bank_num: u64,
|
||||
oracle_opt: Option<Pubkey>,
|
||||
oracle_config_opt: Option<OracleConfig>,
|
||||
interest_rate_params_opt: Option<InterestRateParams>,
|
||||
loan_fee_rate_opt: Option<f32>,
|
||||
loan_origination_fee_rate_opt: Option<f32>,
|
||||
maint_asset_weight_opt: Option<f32>,
|
||||
init_asset_weight_opt: Option<f32>,
|
||||
maint_liab_weight_opt: Option<f32>,
|
||||
init_liab_weight_opt: Option<f32>,
|
||||
liquidation_fee_opt: Option<f32>,
|
||||
) -> Result<()> {
|
||||
ctx.accounts
|
||||
.mint_info
|
||||
.load()?
|
||||
.verify_banks_ais(ctx.remaining_accounts)?;
|
||||
|
||||
for ai in ctx.remaining_accounts.iter() {
|
||||
let mut bank = ai.load_mut::<Bank>()?;
|
||||
|
||||
// note: unchanged fields are inline, and match exact definition in register_token
|
||||
// please maintain, and don't remove, makes it easy to reason about which support admin modification
|
||||
|
||||
// unchanged -
|
||||
// name
|
||||
// group
|
||||
// mint
|
||||
// vault
|
||||
|
||||
if let Some(oracle) = oracle_opt {
|
||||
bank.oracle = oracle;
|
||||
}
|
||||
if let Some(oracle_config) = oracle_config_opt {
|
||||
bank.oracle_config = oracle_config;
|
||||
};
|
||||
|
||||
// unchanged -
|
||||
// deposit_index
|
||||
// borrow_index
|
||||
// cached_indexed_total_deposits
|
||||
// cached_indexed_total_borrows
|
||||
// indexed_deposits
|
||||
// indexed_borrows
|
||||
// last_updated
|
||||
|
||||
if let Some(ref interest_rate_params) = interest_rate_params_opt {
|
||||
// TODO: add a require! verifying relation between the parameters
|
||||
bank.util0 = I80F48::from_num(interest_rate_params.util0);
|
||||
bank.rate0 = I80F48::from_num(interest_rate_params.rate0);
|
||||
bank.util1 = I80F48::from_num(interest_rate_params.util1);
|
||||
bank.rate1 = I80F48::from_num(interest_rate_params.rate1);
|
||||
bank.max_rate = I80F48::from_num(interest_rate_params.max_rate);
|
||||
}
|
||||
|
||||
// unchanged -
|
||||
// collected_fees_native
|
||||
|
||||
if let Some(loan_origination_fee_rate) = loan_origination_fee_rate_opt {
|
||||
bank.loan_origination_fee_rate = I80F48::from_num(loan_origination_fee_rate);
|
||||
}
|
||||
if let Some(loan_fee_rate) = loan_fee_rate_opt {
|
||||
bank.loan_fee_rate = I80F48::from_num(loan_fee_rate);
|
||||
}
|
||||
|
||||
if let Some(maint_asset_weight) = maint_asset_weight_opt {
|
||||
bank.maint_asset_weight = I80F48::from_num(maint_asset_weight);
|
||||
}
|
||||
if let Some(init_asset_weight) = init_asset_weight_opt {
|
||||
bank.init_asset_weight = I80F48::from_num(init_asset_weight);
|
||||
}
|
||||
if let Some(maint_liab_weight) = maint_liab_weight_opt {
|
||||
bank.maint_liab_weight = I80F48::from_num(maint_liab_weight);
|
||||
}
|
||||
if let Some(init_liab_weight) = init_liab_weight_opt {
|
||||
bank.init_liab_weight = I80F48::from_num(init_liab_weight);
|
||||
}
|
||||
if let Some(liquidation_fee) = liquidation_fee_opt {
|
||||
bank.liquidation_fee = I80F48::from_num(liquidation_fee);
|
||||
}
|
||||
|
||||
// unchanged -
|
||||
// dust
|
||||
// flash_loan_vault_initial
|
||||
// flash_loan_approved_amount
|
||||
// token_index
|
||||
// bump
|
||||
// mint_decimals
|
||||
// bank_num
|
||||
// reserved
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -16,6 +16,7 @@ pub struct TokenWithdraw<'info> {
|
|||
#[account(
|
||||
mut,
|
||||
has_one = group,
|
||||
// note: should never be the delegate
|
||||
has_one = owner,
|
||||
)]
|
||||
pub account: AccountLoader<'info, MangoAccount>,
|
||||
|
|
|
@ -3,7 +3,6 @@ use anchor_lang::prelude::*;
|
|||
use crate::logs::UpdateIndexLog;
|
||||
use crate::{
|
||||
accounts_zerocopy::{LoadMutZeroCopyRef, LoadZeroCopyRef},
|
||||
error::MangoError,
|
||||
state::{Bank, MintInfo},
|
||||
};
|
||||
use checked_math as cm;
|
||||
|
@ -14,21 +13,14 @@ pub struct UpdateIndex<'info> {
|
|||
}
|
||||
|
||||
pub fn update_index(ctx: Context<UpdateIndex>) -> Result<()> {
|
||||
let mint_info = ctx.accounts.mint_info.load()?;
|
||||
|
||||
let total_banks = mint_info
|
||||
.banks
|
||||
.iter()
|
||||
.filter(|bank| *bank != &Pubkey::default())
|
||||
.count();
|
||||
|
||||
require_eq!(total_banks, ctx.remaining_accounts.len());
|
||||
let all_banks = ctx.remaining_accounts;
|
||||
check_banks(all_banks, &mint_info)?;
|
||||
ctx.accounts
|
||||
.mint_info
|
||||
.load()?
|
||||
.verify_banks_ais(ctx.remaining_accounts)?;
|
||||
|
||||
let mut indexed_total_deposits = I80F48::ZERO;
|
||||
let mut indexed_total_borrows = I80F48::ZERO;
|
||||
for ai in all_banks.iter() {
|
||||
for ai in ctx.remaining_accounts.iter() {
|
||||
let bank = ai.load::<Bank>()?;
|
||||
indexed_total_deposits = cm!(indexed_total_deposits + bank.indexed_deposits);
|
||||
indexed_total_borrows = cm!(indexed_total_borrows + bank.indexed_borrows);
|
||||
|
@ -36,7 +28,7 @@ pub fn update_index(ctx: Context<UpdateIndex>) -> Result<()> {
|
|||
|
||||
let now_ts = Clock::get()?.unix_timestamp;
|
||||
let (diff_ts, deposit_index, borrow_index) = {
|
||||
let mut some_bank = all_banks[0].load_mut::<Bank>()?;
|
||||
let mut some_bank = ctx.remaining_accounts[0].load_mut::<Bank>()?;
|
||||
|
||||
// TODO: should we enforce a minimum window between 2 update_index ix calls?
|
||||
let diff_ts = I80F48::from_num(now_ts - some_bank.last_updated);
|
||||
|
@ -53,7 +45,7 @@ pub fn update_index(ctx: Context<UpdateIndex>) -> Result<()> {
|
|||
msg!("deposit_index {}", deposit_index);
|
||||
msg!("borrow_index {}", borrow_index);
|
||||
|
||||
for ai in all_banks.iter() {
|
||||
for ai in ctx.remaining_accounts.iter() {
|
||||
let mut bank = ai.load_mut::<Bank>()?;
|
||||
|
||||
bank.cached_indexed_total_deposits = indexed_total_deposits;
|
||||
|
@ -77,22 +69,3 @@ pub fn update_index(ctx: Context<UpdateIndex>) -> Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_banks(all_banks: &[AccountInfo], mint_info: &MintInfo) -> Result<()> {
|
||||
for (idx, ai) in all_banks.iter().enumerate() {
|
||||
match ai.load::<Bank>() {
|
||||
Ok(bank) => {
|
||||
if mint_info.token_index != bank.token_index
|
||||
|| mint_info.group != bank.group
|
||||
// todo: just below check should be enough, above 2 checks are superfluous and defensive
|
||||
|| mint_info.banks[idx] != ai.key()
|
||||
{
|
||||
return Err(error!(MangoError::SomeError));
|
||||
}
|
||||
}
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -71,6 +71,37 @@ pub mod mango_v4 {
|
|||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn token_edit(
|
||||
ctx: Context<TokenEdit>,
|
||||
bank_num: u64,
|
||||
oracle_opt: Option<Pubkey>,
|
||||
oracle_config_opt: Option<OracleConfig>,
|
||||
interest_rate_params_opt: Option<InterestRateParams>,
|
||||
loan_fee_rate_opt: Option<f32>,
|
||||
loan_origination_fee_rate_opt: Option<f32>,
|
||||
maint_asset_weight_opt: Option<f32>,
|
||||
init_asset_weight_opt: Option<f32>,
|
||||
maint_liab_weight_opt: Option<f32>,
|
||||
init_liab_weight_opt: Option<f32>,
|
||||
liquidation_fee_opt: Option<f32>,
|
||||
) -> Result<()> {
|
||||
instructions::token_edit(
|
||||
ctx,
|
||||
bank_num,
|
||||
oracle_opt,
|
||||
oracle_config_opt,
|
||||
interest_rate_params_opt,
|
||||
loan_fee_rate_opt,
|
||||
loan_origination_fee_rate_opt,
|
||||
maint_asset_weight_opt,
|
||||
init_asset_weight_opt,
|
||||
maint_liab_weight_opt,
|
||||
init_liab_weight_opt,
|
||||
liquidation_fee_opt,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn token_add_bank(
|
||||
ctx: Context<TokenAddBank>,
|
||||
|
@ -99,7 +130,13 @@ pub mod mango_v4 {
|
|||
instructions::create_account(ctx, account_num, name)
|
||||
}
|
||||
|
||||
// TODO set delegate
|
||||
pub fn edit_account(
|
||||
ctx: Context<EditAccount>,
|
||||
name_opt: Option<String>,
|
||||
delegate_opt: Option<Pubkey>,
|
||||
) -> Result<()> {
|
||||
instructions::edit_account(ctx, name_opt, delegate_opt)
|
||||
}
|
||||
|
||||
pub fn close_account(ctx: Context<CloseAccount>) -> Result<()> {
|
||||
instructions::close_account(ctx)
|
||||
|
@ -182,6 +219,11 @@ pub mod mango_v4 {
|
|||
instructions::serum3_register_market(ctx, market_index, name)
|
||||
}
|
||||
|
||||
// note:
|
||||
// pub fn serum3_edit_market - doesn't exist since a mango serum3 market only contains the properties
|
||||
// registered base and quote token pairs, and serum3 external market its pointing to, and none of them
|
||||
// should be edited once set on creation
|
||||
|
||||
pub fn serum3_deregister_market(ctx: Context<Serum3DeregisterMarket>) -> Result<()> {
|
||||
instructions::serum3_deregister_market(ctx)
|
||||
}
|
||||
|
@ -309,6 +351,43 @@ pub mod mango_v4 {
|
|||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn perp_edit_market(
|
||||
ctx: Context<PerpEditMarket>,
|
||||
oracle_opt: Option<Pubkey>,
|
||||
oracle_config_opt: Option<OracleConfig>,
|
||||
base_token_index_opt: Option<TokenIndex>,
|
||||
base_token_decimals_opt: Option<u8>,
|
||||
maint_asset_weight_opt: Option<f32>,
|
||||
init_asset_weight_opt: Option<f32>,
|
||||
maint_liab_weight_opt: Option<f32>,
|
||||
init_liab_weight_opt: Option<f32>,
|
||||
liquidation_fee_opt: Option<f32>,
|
||||
maker_fee_opt: Option<f32>,
|
||||
taker_fee_opt: Option<f32>,
|
||||
min_funding_opt: Option<f32>,
|
||||
max_funding_opt: Option<f32>,
|
||||
impact_quantity_opt: Option<i64>,
|
||||
) -> Result<()> {
|
||||
instructions::perp_edit_market(
|
||||
ctx,
|
||||
oracle_opt,
|
||||
oracle_config_opt,
|
||||
base_token_index_opt,
|
||||
base_token_decimals_opt,
|
||||
maint_asset_weight_opt,
|
||||
init_asset_weight_opt,
|
||||
maint_liab_weight_opt,
|
||||
init_liab_weight_opt,
|
||||
liquidation_fee_opt,
|
||||
maker_fee_opt,
|
||||
taker_fee_opt,
|
||||
min_funding_opt,
|
||||
max_funding_opt,
|
||||
impact_quantity_opt,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn perp_close_market(ctx: Context<PerpCloseMarket>) -> Result<()> {
|
||||
instructions::perp_close_market(ctx)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ use std::mem::size_of;
|
|||
pub type TokenIndex = u16;
|
||||
|
||||
#[account(zero_copy)]
|
||||
#[derive(Debug)]
|
||||
pub struct Group {
|
||||
// Relying on Anchor's discriminator be sufficient for our versioning needs?
|
||||
// pub meta_data: MetaData,
|
||||
|
|
|
@ -770,6 +770,10 @@ impl MangoAccount {
|
|||
.unwrap()
|
||||
.trim_matches(char::from(0))
|
||||
}
|
||||
|
||||
pub fn is_owner_or_delegate(&self, ix_signer: Pubkey) -> bool {
|
||||
self.owner == ix_signer || self.delegate == ix_signer
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MangoAccount {
|
||||
|
|
|
@ -2,7 +2,9 @@ use anchor_lang::prelude::*;
|
|||
use static_assertions::const_assert_eq;
|
||||
use std::mem::size_of;
|
||||
|
||||
use super::TokenIndex;
|
||||
use crate::{accounts_zerocopy::LoadZeroCopyRef, error::MangoError};
|
||||
|
||||
use super::{Bank, TokenIndex};
|
||||
|
||||
pub const MAX_BANKS: usize = 6;
|
||||
|
||||
|
@ -44,4 +46,30 @@ impl MintInfo {
|
|||
pub fn first_vault(&self) -> Pubkey {
|
||||
self.vaults[0]
|
||||
}
|
||||
|
||||
pub fn verify_banks_ais(&self, all_bank_ais: &[AccountInfo]) -> Result<()> {
|
||||
let total_banks = self
|
||||
.banks
|
||||
.iter()
|
||||
.filter(|bank| *bank != &Pubkey::default())
|
||||
.count();
|
||||
require_eq!(total_banks, all_bank_ais.len());
|
||||
|
||||
for (idx, ai) in all_bank_ais.iter().enumerate() {
|
||||
match ai.load::<Bank>() {
|
||||
Ok(bank) => {
|
||||
if self.token_index != bank.token_index
|
||||
|| self.group != bank.group
|
||||
// todo: just below check should be enough, above 2 checks are superfluous and defensive
|
||||
|| self.banks[idx] != ai.key()
|
||||
{
|
||||
return Err(error!(MangoError::SomeError));
|
||||
}
|
||||
}
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ use super::{Book, OracleConfig};
|
|||
pub type PerpMarketIndex = u16;
|
||||
|
||||
#[account(zero_copy)]
|
||||
#[derive(Debug)]
|
||||
pub struct PerpMarket {
|
||||
pub name: [u8; 16],
|
||||
|
||||
|
|
|
@ -1296,6 +1296,53 @@ impl<'keypair> ClientInstruction for CreateAccountInstruction<'keypair> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct EditAccountInstruction<'keypair> {
|
||||
pub account_num: u8,
|
||||
pub group: Pubkey,
|
||||
pub owner: &'keypair Keypair,
|
||||
pub name: String,
|
||||
pub delegate: Pubkey,
|
||||
}
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl<'keypair> ClientInstruction for EditAccountInstruction<'keypair> {
|
||||
type Accounts = mango_v4::accounts::EditAccount;
|
||||
type Instruction = mango_v4::instruction::EditAccount;
|
||||
async fn to_instruction(
|
||||
&self,
|
||||
_account_loader: impl ClientAccountLoader + 'async_trait,
|
||||
) -> (Self::Accounts, instruction::Instruction) {
|
||||
let program_id = mango_v4::id();
|
||||
let instruction = mango_v4::instruction::EditAccount {
|
||||
name_opt: Option::from(self.name.to_string()),
|
||||
delegate_opt: Option::from(self.delegate),
|
||||
};
|
||||
|
||||
let account = Pubkey::find_program_address(
|
||||
&[
|
||||
self.group.as_ref(),
|
||||
b"MangoAccount".as_ref(),
|
||||
self.owner.pubkey().as_ref(),
|
||||
&self.account_num.to_le_bytes(),
|
||||
],
|
||||
&program_id,
|
||||
)
|
||||
.0;
|
||||
|
||||
let accounts = mango_v4::accounts::EditAccount {
|
||||
group: self.group,
|
||||
account,
|
||||
owner: self.owner.pubkey(),
|
||||
};
|
||||
|
||||
let instruction = make_instruction(program_id, &accounts, instruction);
|
||||
(accounts, instruction)
|
||||
}
|
||||
|
||||
fn signers(&self) -> Vec<&Keypair> {
|
||||
vec![self.owner]
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CloseAccountInstruction<'keypair> {
|
||||
pub group: Pubkey,
|
||||
pub account: Pubkey,
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
#![cfg(feature = "test-bpf")]
|
||||
|
||||
use fixed::types::I80F48;
|
||||
use solana_program_test::*;
|
||||
use solana_sdk::{signature::Keypair, signature::Signer, transport::TransportError};
|
||||
|
||||
use mango_v4::state::*;
|
||||
use program_test::*;
|
||||
|
||||
mod program_test;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_delegate() -> Result<(), TransportError> {
|
||||
let context = TestContext::new().await;
|
||||
let solana = &context.solana.clone();
|
||||
|
||||
let admin = &Keypair::new();
|
||||
let owner = &context.users[0].key;
|
||||
let payer = &context.users[1].key;
|
||||
let delegate = &context.users[1].key;
|
||||
let mints = &context.mints[0..1];
|
||||
let payer_mint0_account = context.users[1].token_accounts[0];
|
||||
|
||||
//
|
||||
// SETUP: Create a group, register a token (mint0), create an account
|
||||
//
|
||||
|
||||
let mango_setup::GroupWithTokens { group, tokens } = mango_setup::GroupWithTokensConfig {
|
||||
admin,
|
||||
payer,
|
||||
mints,
|
||||
}
|
||||
.create(solana)
|
||||
.await;
|
||||
let bank = tokens[0].bank;
|
||||
|
||||
let account = send_tx(
|
||||
solana,
|
||||
CreateAccountInstruction {
|
||||
account_num: 0,
|
||||
group,
|
||||
owner,
|
||||
payer,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
.account;
|
||||
|
||||
// deposit
|
||||
send_tx(
|
||||
solana,
|
||||
TokenDepositInstruction {
|
||||
amount: 100,
|
||||
account,
|
||||
token_account: payer_mint0_account,
|
||||
token_authority: payer,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
//
|
||||
// TEST: Edit account - Set delegate
|
||||
//
|
||||
{
|
||||
send_tx(
|
||||
solana,
|
||||
EditAccountInstruction {
|
||||
delegate: delegate.pubkey(),
|
||||
account_num: 0,
|
||||
group,
|
||||
owner,
|
||||
name: "new_name".to_owned(),
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
//
|
||||
// TEST: Edit account as delegate - should fail
|
||||
//
|
||||
{
|
||||
let res = send_tx(
|
||||
solana,
|
||||
EditAccountInstruction {
|
||||
delegate: delegate.pubkey(),
|
||||
account_num: 0,
|
||||
group,
|
||||
owner: delegate,
|
||||
name: "new_name".to_owned(),
|
||||
},
|
||||
)
|
||||
.await;
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
//
|
||||
// TEST: Withdraw funds as delegate should fail
|
||||
//
|
||||
{
|
||||
let withdraw_amount = 50;
|
||||
let res = send_tx(
|
||||
solana,
|
||||
TokenWithdrawInstruction {
|
||||
amount: withdraw_amount,
|
||||
allow_borrow: true,
|
||||
account,
|
||||
owner: delegate,
|
||||
token_account: payer_mint0_account,
|
||||
},
|
||||
)
|
||||
.await;
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
//
|
||||
// TEST: Close account as delegate should fail
|
||||
//
|
||||
{
|
||||
let bank_data: Bank = solana.get_account(bank).await;
|
||||
send_tx(
|
||||
solana,
|
||||
TokenWithdrawInstruction {
|
||||
amount: bank_data.native_deposits().to_num(),
|
||||
allow_borrow: false,
|
||||
account,
|
||||
owner,
|
||||
token_account: payer_mint0_account,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let res = send_tx(
|
||||
solana,
|
||||
CloseAccountInstruction {
|
||||
group,
|
||||
account,
|
||||
owner: delegate,
|
||||
sol_destination: payer.pubkey(),
|
||||
},
|
||||
)
|
||||
.await;
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -20,7 +20,7 @@ cp -v ./target/types/mango_v4.ts ./ts/client/src/mango_v4.ts
|
|||
if [[ -z "${NO_DEPLOY}" ]]; then
|
||||
# publish program
|
||||
solana --url https://mango.devnet.rpcpool.com program deploy --program-id $PROGRAM_ID \
|
||||
-k $WALLET_WITH_FUNDS target/deploy/mango_v4.so
|
||||
-k $WALLET_WITH_FUNDS target/deploy/mango_v4.so --skip-fee-check
|
||||
|
||||
# # publish idl
|
||||
# anchor idl upgrade --provider.cluster https://mango.devnet.rpcpool.com --provider.wallet $WALLET_WITH_FUNDS \
|
||||
|
|
|
@ -141,9 +141,39 @@ export class Bank {
|
|||
}
|
||||
|
||||
toString(): string {
|
||||
return `Bank ${
|
||||
this.tokenIndex
|
||||
} deposit index - ${this.depositIndex.toNumber()}, borrow index - ${this.borrowIndex.toNumber()}`;
|
||||
return (
|
||||
'Bank ' +
|
||||
'\n token index -' +
|
||||
this.tokenIndex +
|
||||
'\n deposit index -' +
|
||||
this.depositIndex.toNumber() +
|
||||
'\n borrow index -' +
|
||||
this.borrowIndex.toNumber() +
|
||||
'\n cachedIndexedTotalDeposits -' +
|
||||
this.cachedIndexedTotalDeposits.toNumber() +
|
||||
'\n cachedIndexedTotalBorrows -' +
|
||||
this.cachedIndexedTotalBorrows.toNumber() +
|
||||
'\n maxRate -' +
|
||||
this.maxRate.toNumber() +
|
||||
'\n util0 -' +
|
||||
this.util0.toNumber() +
|
||||
'\n rate0 -' +
|
||||
this.rate0.toNumber() +
|
||||
'\n util1 -' +
|
||||
this.util1.toNumber() +
|
||||
'\n rate1 -' +
|
||||
this.rate1.toNumber() +
|
||||
'\n maintAssetWeight -' +
|
||||
this.maintAssetWeight.toNumber() +
|
||||
'\n initAssetWeight -' +
|
||||
this.initAssetWeight.toNumber() +
|
||||
'\n maintLiabWeight -' +
|
||||
this.maintLiabWeight.toNumber() +
|
||||
'\n initLiabWeight -' +
|
||||
this.initLiabWeight.toNumber() +
|
||||
'\n liquidationFee -' +
|
||||
this.liquidationFee.toNumber()
|
||||
);
|
||||
}
|
||||
|
||||
nativeDeposits(): I80F48 {
|
||||
|
|
|
@ -234,6 +234,7 @@ export class MangoAccount {
|
|||
let res = 'MangoAccount';
|
||||
res = res + '\n pk: ' + this.publicKey.toString();
|
||||
res = res + '\n name: ' + this.name;
|
||||
res = res + '\n delegate: ' + this.delegate;
|
||||
|
||||
res =
|
||||
this.tokensActive().length > 0
|
||||
|
|
|
@ -126,6 +126,28 @@ export class PerpMarket {
|
|||
const quoteUnit = Math.pow(10, QUOTE_DECIMALS);
|
||||
return new BN(uiQuote * quoteUnit).div(this.quoteLotSize);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return (
|
||||
'PerpMarket ' +
|
||||
'\n perpMarketIndex -' +
|
||||
this.perpMarketIndex +
|
||||
'\n maintAssetWeight -' +
|
||||
this.maintAssetWeight.toNumber() +
|
||||
'\n initAssetWeight -' +
|
||||
this.initAssetWeight.toNumber() +
|
||||
'\n maintLiabWeight -' +
|
||||
this.maintLiabWeight.toNumber() +
|
||||
'\n initLiabWeight -' +
|
||||
this.initLiabWeight.toNumber() +
|
||||
'\n liquidationFee -' +
|
||||
this.liquidationFee.toNumber() +
|
||||
'\n makerFee -' +
|
||||
this.makerFee.toNumber() +
|
||||
'\n takerFee -' +
|
||||
this.takerFee.toNumber()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class Side {
|
||||
|
|
|
@ -151,7 +151,6 @@ export class MangoClient {
|
|||
initLiabWeight: number,
|
||||
liquidationFee: number,
|
||||
): Promise<TransactionSignature> {
|
||||
const bn = I80F48.fromNumber(oracleConfFilter).getData();
|
||||
return await this.program.methods
|
||||
.tokenRegister(
|
||||
tokenIndex,
|
||||
|
@ -182,6 +181,60 @@ export class MangoClient {
|
|||
.rpc();
|
||||
}
|
||||
|
||||
public async tokenEdit(
|
||||
group: Group,
|
||||
tokenName: string,
|
||||
oracle: PublicKey,
|
||||
oracleConfFilter: number,
|
||||
util0: number,
|
||||
rate0: number,
|
||||
util1: number,
|
||||
rate1: number,
|
||||
maxRate: number,
|
||||
loanFeeRate: number,
|
||||
loanOriginationFeeRate: number,
|
||||
maintAssetWeight: number,
|
||||
initAssetWeight: number,
|
||||
maintLiabWeight: number,
|
||||
initLiabWeight: number,
|
||||
liquidationFee: number,
|
||||
): Promise<TransactionSignature> {
|
||||
const bank = group.banksMap.get(tokenName)!;
|
||||
const mintInfo = group.mintInfosMap.get(bank.tokenIndex)!;
|
||||
|
||||
return await this.program.methods
|
||||
.tokenEdit(
|
||||
new BN(0),
|
||||
oracle,
|
||||
{
|
||||
confFilter: {
|
||||
val: I80F48.fromNumber(oracleConfFilter).getData(),
|
||||
},
|
||||
} as any, // future: nested custom types dont typecheck, fix if possible?
|
||||
{ util0, rate0, util1, rate1, maxRate },
|
||||
loanFeeRate,
|
||||
loanOriginationFeeRate,
|
||||
maintAssetWeight,
|
||||
initAssetWeight,
|
||||
maintLiabWeight,
|
||||
initLiabWeight,
|
||||
liquidationFee,
|
||||
)
|
||||
.accounts({
|
||||
group: group.publicKey,
|
||||
admin: (this.program.provider as AnchorProvider).wallet.publicKey,
|
||||
mintInfo: mintInfo.publicKey,
|
||||
})
|
||||
.remainingAccounts([
|
||||
{
|
||||
pubkey: bank.publicKey,
|
||||
isWritable: true,
|
||||
isSigner: false,
|
||||
} as AccountMeta,
|
||||
])
|
||||
.rpc({ skipPreflight: true });
|
||||
}
|
||||
|
||||
public async tokenDeregister(
|
||||
group: Group,
|
||||
tokenName: string,
|
||||
|
@ -388,6 +441,20 @@ export class MangoClient {
|
|||
.rpc();
|
||||
}
|
||||
|
||||
public async editMangoAccount(
|
||||
group: Group,
|
||||
name?: string,
|
||||
delegate?: PublicKey,
|
||||
): Promise<TransactionSignature> {
|
||||
return await this.program.methods
|
||||
.editAccount(name, delegate)
|
||||
.accounts({
|
||||
group: group.publicKey,
|
||||
owner: (this.program.provider as AnchorProvider).wallet.publicKey,
|
||||
})
|
||||
.rpc();
|
||||
}
|
||||
|
||||
public async getMangoAccount(mangoAccount: MangoAccount) {
|
||||
return MangoAccount.from(
|
||||
mangoAccount.publicKey,
|
||||
|
@ -1048,6 +1115,55 @@ export class MangoClient {
|
|||
.rpc();
|
||||
}
|
||||
|
||||
async perpEditMarket(
|
||||
group: Group,
|
||||
perpMarketName: string,
|
||||
oracle: PublicKey,
|
||||
oracleConfFilter: number,
|
||||
baseTokenIndex: number,
|
||||
baseTokenDecimals: number,
|
||||
maintAssetWeight: number,
|
||||
initAssetWeight: number,
|
||||
maintLiabWeight: number,
|
||||
initLiabWeight: number,
|
||||
liquidationFee: number,
|
||||
makerFee: number,
|
||||
takerFee: number,
|
||||
minFunding: number,
|
||||
maxFunding: number,
|
||||
impactQuantity: number,
|
||||
): Promise<TransactionSignature> {
|
||||
const perpMarket = group.perpMarketsMap.get(perpMarketName)!;
|
||||
|
||||
return await this.program.methods
|
||||
.perpEditMarket(
|
||||
oracle,
|
||||
{
|
||||
confFilter: {
|
||||
val: I80F48.fromNumber(oracleConfFilter).getData(),
|
||||
},
|
||||
} as any, // future: nested custom types dont typecheck, fix if possible?
|
||||
baseTokenIndex,
|
||||
baseTokenDecimals,
|
||||
maintAssetWeight,
|
||||
initAssetWeight,
|
||||
maintLiabWeight,
|
||||
initLiabWeight,
|
||||
liquidationFee,
|
||||
makerFee,
|
||||
takerFee,
|
||||
minFunding,
|
||||
maxFunding,
|
||||
new BN(impactQuantity),
|
||||
)
|
||||
.accounts({
|
||||
group: group.publicKey,
|
||||
admin: (this.program.provider as AnchorProvider).wallet.publicKey,
|
||||
perpMarket: perpMarket.publicKey,
|
||||
})
|
||||
.rpc();
|
||||
}
|
||||
|
||||
async perpCloseMarket(
|
||||
group: Group,
|
||||
perpMarketName: string,
|
||||
|
|
|
@ -264,6 +264,96 @@ export type MangoV4 = {
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tokenEdit",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "group",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "admin",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "mintInfo",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "bankNum",
|
||||
"type": "u64"
|
||||
},
|
||||
{
|
||||
"name": "oracleOpt",
|
||||
"type": {
|
||||
"option": "publicKey"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "oracleConfigOpt",
|
||||
"type": {
|
||||
"option": {
|
||||
"defined": "OracleConfig"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "interestRateParamsOpt",
|
||||
"type": {
|
||||
"option": {
|
||||
"defined": "InterestRateParams"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "loanFeeRateOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "loanOriginationFeeRateOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "maintAssetWeightOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "initAssetWeightOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "maintLiabWeightOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "initLiabWeightOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "liquidationFeeOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tokenAddBank",
|
||||
"accounts": [
|
||||
|
@ -518,6 +608,40 @@ export type MangoV4 = {
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "editAccount",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "group",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "nameOpt",
|
||||
"type": {
|
||||
"option": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "delegateOpt",
|
||||
"type": {
|
||||
"option": "publicKey"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "closeAccount",
|
||||
"accounts": [
|
||||
|
@ -1046,6 +1170,11 @@ export type MangoV4 = {
|
|||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "serumMarket",
|
||||
"isMut": false,
|
||||
|
@ -1085,11 +1214,6 @@ export type MangoV4 = {
|
|||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "payer",
|
||||
"isMut": true,
|
||||
|
@ -1787,6 +1911,114 @@ export type MangoV4 = {
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "perpEditMarket",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "group",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "admin",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "perpMarket",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "oracleOpt",
|
||||
"type": {
|
||||
"option": "publicKey"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "oracleConfigOpt",
|
||||
"type": {
|
||||
"option": {
|
||||
"defined": "OracleConfig"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "baseTokenIndexOpt",
|
||||
"type": {
|
||||
"option": "u16"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "baseTokenDecimalsOpt",
|
||||
"type": {
|
||||
"option": "u8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "maintAssetWeightOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "initAssetWeightOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "maintLiabWeightOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "initLiabWeightOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "liquidationFeeOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "makerFeeOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "takerFeeOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "minFundingOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "maxFundingOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "impactQuantityOpt",
|
||||
"type": {
|
||||
"option": "i64"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "perpCloseMarket",
|
||||
"accounts": [
|
||||
|
@ -1846,6 +2078,11 @@ export type MangoV4 = {
|
|||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "perpMarket",
|
||||
"isMut": true,
|
||||
|
@ -1870,11 +2107,6 @@ export type MangoV4 = {
|
|||
"name": "oracle",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
|
@ -1929,6 +2161,11 @@ export type MangoV4 = {
|
|||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "perpMarket",
|
||||
"isMut": true,
|
||||
|
@ -1943,11 +2180,6 @@ export type MangoV4 = {
|
|||
"name": "bids",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
|
@ -1970,6 +2202,11 @@ export type MangoV4 = {
|
|||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "perpMarket",
|
||||
"isMut": true,
|
||||
|
@ -1984,11 +2221,6 @@ export type MangoV4 = {
|
|||
"name": "bids",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
|
@ -2011,6 +2243,11 @@ export type MangoV4 = {
|
|||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "perpMarket",
|
||||
"isMut": true,
|
||||
|
@ -2025,11 +2262,6 @@ export type MangoV4 = {
|
|||
"name": "bids",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
|
@ -2052,6 +2284,11 @@ export type MangoV4 = {
|
|||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "perpMarket",
|
||||
"isMut": true,
|
||||
|
@ -2066,11 +2303,6 @@ export type MangoV4 = {
|
|||
"name": "bids",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
|
@ -4414,6 +4646,96 @@ export const IDL: MangoV4 = {
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tokenEdit",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "group",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "admin",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "mintInfo",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "bankNum",
|
||||
"type": "u64"
|
||||
},
|
||||
{
|
||||
"name": "oracleOpt",
|
||||
"type": {
|
||||
"option": "publicKey"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "oracleConfigOpt",
|
||||
"type": {
|
||||
"option": {
|
||||
"defined": "OracleConfig"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "interestRateParamsOpt",
|
||||
"type": {
|
||||
"option": {
|
||||
"defined": "InterestRateParams"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "loanFeeRateOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "loanOriginationFeeRateOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "maintAssetWeightOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "initAssetWeightOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "maintLiabWeightOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "initLiabWeightOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "liquidationFeeOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tokenAddBank",
|
||||
"accounts": [
|
||||
|
@ -4668,6 +4990,40 @@ export const IDL: MangoV4 = {
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "editAccount",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "group",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "nameOpt",
|
||||
"type": {
|
||||
"option": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "delegateOpt",
|
||||
"type": {
|
||||
"option": "publicKey"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "closeAccount",
|
||||
"accounts": [
|
||||
|
@ -5196,6 +5552,11 @@ export const IDL: MangoV4 = {
|
|||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "serumMarket",
|
||||
"isMut": false,
|
||||
|
@ -5235,11 +5596,6 @@ export const IDL: MangoV4 = {
|
|||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "payer",
|
||||
"isMut": true,
|
||||
|
@ -5937,6 +6293,114 @@ export const IDL: MangoV4 = {
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "perpEditMarket",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "group",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "admin",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "perpMarket",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "oracleOpt",
|
||||
"type": {
|
||||
"option": "publicKey"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "oracleConfigOpt",
|
||||
"type": {
|
||||
"option": {
|
||||
"defined": "OracleConfig"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "baseTokenIndexOpt",
|
||||
"type": {
|
||||
"option": "u16"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "baseTokenDecimalsOpt",
|
||||
"type": {
|
||||
"option": "u8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "maintAssetWeightOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "initAssetWeightOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "maintLiabWeightOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "initLiabWeightOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "liquidationFeeOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "makerFeeOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "takerFeeOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "minFundingOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "maxFundingOpt",
|
||||
"type": {
|
||||
"option": "f32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "impactQuantityOpt",
|
||||
"type": {
|
||||
"option": "i64"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "perpCloseMarket",
|
||||
"accounts": [
|
||||
|
@ -5996,6 +6460,11 @@ export const IDL: MangoV4 = {
|
|||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "perpMarket",
|
||||
"isMut": true,
|
||||
|
@ -6020,11 +6489,6 @@ export const IDL: MangoV4 = {
|
|||
"name": "oracle",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
|
@ -6079,6 +6543,11 @@ export const IDL: MangoV4 = {
|
|||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "perpMarket",
|
||||
"isMut": true,
|
||||
|
@ -6093,11 +6562,6 @@ export const IDL: MangoV4 = {
|
|||
"name": "bids",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
|
@ -6120,6 +6584,11 @@ export const IDL: MangoV4 = {
|
|||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "perpMarket",
|
||||
"isMut": true,
|
||||
|
@ -6134,11 +6603,6 @@ export const IDL: MangoV4 = {
|
|||
"name": "bids",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
|
@ -6161,6 +6625,11 @@ export const IDL: MangoV4 = {
|
|||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "perpMarket",
|
||||
"isMut": true,
|
||||
|
@ -6175,11 +6644,6 @@ export const IDL: MangoV4 = {
|
|||
"name": "bids",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
|
@ -6202,6 +6666,11 @@ export const IDL: MangoV4 = {
|
|||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "perpMarket",
|
||||
"isMut": true,
|
||||
|
@ -6216,11 +6685,6 @@ export const IDL: MangoV4 = {
|
|||
"name": "bids",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
|
|
|
@ -255,6 +255,116 @@ async function main() {
|
|||
);
|
||||
console.log(`...created perp market ${perpMarkets[0].publicKey}`);
|
||||
|
||||
//
|
||||
// edit
|
||||
//
|
||||
|
||||
console.log(`Editing USDC...`);
|
||||
try {
|
||||
let sig = await client.tokenEdit(
|
||||
group,
|
||||
'USDC',
|
||||
btcDevnetOracle,
|
||||
0.1,
|
||||
0.3,
|
||||
0.08,
|
||||
0.81,
|
||||
0.91,
|
||||
0.75,
|
||||
0.0007,
|
||||
1.7,
|
||||
0.9,
|
||||
0.7,
|
||||
1.3,
|
||||
1.5,
|
||||
0.04,
|
||||
);
|
||||
console.log(`https://explorer.solana.com/tx/${sig}?cluster=devnet`);
|
||||
await group.reloadAll(client);
|
||||
console.log(group.banksMap.get('USDC').toString());
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
console.log(`Resetting USDC...`);
|
||||
try {
|
||||
let sig = await client.tokenEdit(
|
||||
group,
|
||||
'USDC',
|
||||
usdcDevnetOracle.publicKey,
|
||||
0.1,
|
||||
0.4,
|
||||
0.07,
|
||||
0.8,
|
||||
0.9,
|
||||
1.5,
|
||||
0.0005,
|
||||
1.5,
|
||||
0.8,
|
||||
0.6,
|
||||
1.2,
|
||||
1.4,
|
||||
0.02,
|
||||
);
|
||||
console.log(`https://explorer.solana.com/tx/${sig}?cluster=devnet`);
|
||||
await group.reloadAll(client);
|
||||
console.log(group.banksMap.get('USDC').toString());
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
console.log(`Editing perp market...`);
|
||||
try {
|
||||
let sig = await client.perpEditMarket(
|
||||
group,
|
||||
'BTC-PERP',
|
||||
btcDevnetOracle,
|
||||
0.2,
|
||||
1,
|
||||
6,
|
||||
0.9,
|
||||
0.9,
|
||||
1.035,
|
||||
1.06,
|
||||
0.013,
|
||||
0.0003,
|
||||
0.1,
|
||||
0.07,
|
||||
0.07,
|
||||
1001,
|
||||
);
|
||||
console.log(`https://explorer.solana.com/tx/${sig}?cluster=devnet`);
|
||||
await group.reloadAll(client);
|
||||
console.log(group.perpMarketsMap.get('BTC-PERP').toString());
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
console.log(`Resetting perp market...`);
|
||||
try {
|
||||
let sig = await client.perpEditMarket(
|
||||
group,
|
||||
'BTC-PERP',
|
||||
btcDevnetOracle,
|
||||
0.1,
|
||||
0,
|
||||
6,
|
||||
1,
|
||||
0.95,
|
||||
1.025,
|
||||
1.05,
|
||||
0.012,
|
||||
0.0002,
|
||||
0.0,
|
||||
0.05,
|
||||
0.05,
|
||||
100,
|
||||
);
|
||||
console.log(`https://explorer.solana.com/tx/${sig}?cluster=devnet`);
|
||||
await group.reloadAll(client);
|
||||
console.log(group.perpMarketsMap.get('BTC-PERP').toString());
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
process.exit();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
import { AnchorProvider, Wallet } from '@project-serum/anchor';
|
||||
import { Connection, Keypair } from '@solana/web3.js';
|
||||
import fs from 'fs';
|
||||
import { OrderType, Side } from '../accounts/perp';
|
||||
import {
|
||||
Serum3OrderType,
|
||||
Serum3SelfTradeBehavior,
|
||||
Serum3Side,
|
||||
} from '../accounts/serum3';
|
||||
import { MangoClient } from '../client';
|
||||
import { MANGO_V4_ID } from '../constants';
|
||||
|
||||
//
|
||||
// An example for users based on high level api i.e. the client
|
||||
// Create
|
||||
// process.env.USER_KEYPAIR - mango account owner keypair path
|
||||
// process.env.ADMIN_KEYPAIR - group admin keypair path (useful for automatically finding the group)
|
||||
//
|
||||
// This script deposits some tokens, places some serum orders, cancels them, places some perp orders
|
||||
//
|
||||
|
||||
async function main() {
|
||||
const options = AnchorProvider.defaultOptions();
|
||||
const connection = new Connection(
|
||||
'https://mango.devnet.rpcpool.com',
|
||||
options,
|
||||
);
|
||||
|
||||
// mango account owner
|
||||
const user = Keypair.fromSecretKey(
|
||||
Buffer.from(
|
||||
JSON.parse(fs.readFileSync(process.env.USER_KEYPAIR!, 'utf-8')),
|
||||
),
|
||||
);
|
||||
const userWallet = new Wallet(user);
|
||||
const userProvider = new AnchorProvider(connection, userWallet, options);
|
||||
const client = await MangoClient.connect(
|
||||
userProvider,
|
||||
'devnet',
|
||||
MANGO_V4_ID['devnet'],
|
||||
);
|
||||
console.log(`User ${userWallet.publicKey.toBase58()}`);
|
||||
|
||||
// delegate
|
||||
const delegate = Keypair.fromSecretKey(
|
||||
Buffer.from(JSON.parse(fs.readFileSync(process.env.DELEGATE!, 'utf-8'))),
|
||||
);
|
||||
const delegateWallet = new Wallet(delegate);
|
||||
const delegateProvider = new AnchorProvider(
|
||||
connection,
|
||||
delegateWallet,
|
||||
options,
|
||||
);
|
||||
// Note: simply create a client with delegate and use this client to execute ixs
|
||||
const delegateClient = await MangoClient.connect(
|
||||
delegateProvider,
|
||||
'devnet',
|
||||
MANGO_V4_ID['devnet'],
|
||||
);
|
||||
console.log(`Delegate ${delegateWallet.publicKey.toBase58()}`);
|
||||
|
||||
// fetch group
|
||||
const admin = Keypair.fromSecretKey(
|
||||
Buffer.from(
|
||||
JSON.parse(fs.readFileSync(process.env.ADMIN_KEYPAIR!, 'utf-8')),
|
||||
),
|
||||
);
|
||||
const group = await delegateClient.getGroupForAdmin(admin.publicKey, 0);
|
||||
console.log(group.toString());
|
||||
|
||||
// fetch mango account using owners pubkey
|
||||
console.log(`Fetching mangoaccount...`);
|
||||
const mangoAccount = (
|
||||
await delegateClient.getMangoAccountForOwner(group, user.publicKey)
|
||||
)[0];
|
||||
console.log(`...created/found mangoAccount ${mangoAccount.publicKey}`);
|
||||
console.log(mangoAccount.toString());
|
||||
|
||||
if (true) {
|
||||
// set delegate, and change name
|
||||
console.log(`...changing mango account name, and setting a delegate`);
|
||||
await client.editMangoAccount(
|
||||
group,
|
||||
'my_changed_name',
|
||||
delegate.publicKey,
|
||||
);
|
||||
await mangoAccount.reload(client, group);
|
||||
console.log(mangoAccount.toString());
|
||||
}
|
||||
|
||||
if (true) {
|
||||
// deposit
|
||||
console.log(`...depositing 50 USDC`);
|
||||
await client.tokenDeposit(group, mangoAccount, 'USDC', 50);
|
||||
await mangoAccount.reload(client, group);
|
||||
|
||||
console.log(`...depositing 0.0005 BTC`);
|
||||
await client.tokenDeposit(group, mangoAccount, 'BTC', 0.0005);
|
||||
await mangoAccount.reload(client, group);
|
||||
|
||||
// serum3
|
||||
console.log(`...placing serum3 bid`);
|
||||
await delegateClient.serum3PlaceOrder(
|
||||
group,
|
||||
mangoAccount,
|
||||
'BTC/USDC',
|
||||
Serum3Side.bid,
|
||||
20,
|
||||
0.0001,
|
||||
Serum3SelfTradeBehavior.decrementTake,
|
||||
Serum3OrderType.limit,
|
||||
Date.now(),
|
||||
10,
|
||||
);
|
||||
await mangoAccount.reload(delegateClient, group);
|
||||
|
||||
console.log(`...current own orders on OB`);
|
||||
let orders = await delegateClient.getSerum3Orders(
|
||||
group,
|
||||
|
||||
'BTC/USDC',
|
||||
);
|
||||
for (const order of orders) {
|
||||
console.log(
|
||||
` - order orderId ${order.orderId}, ${order.side}, ${order.price}, ${order.size}`,
|
||||
);
|
||||
console.log(` - cancelling order with ${order.orderId}`);
|
||||
await delegateClient.serum3CancelOrder(
|
||||
group,
|
||||
mangoAccount,
|
||||
'BTC/USDC',
|
||||
order.side === 'buy' ? Serum3Side.bid : Serum3Side.ask,
|
||||
order.orderId,
|
||||
);
|
||||
}
|
||||
|
||||
console.log(`...settling funds`);
|
||||
await delegateClient.serum3SettleFunds(
|
||||
group,
|
||||
mangoAccount,
|
||||
|
||||
'BTC/USDC',
|
||||
);
|
||||
}
|
||||
|
||||
if (true) {
|
||||
// perps
|
||||
console.log(`...placing perp bid`);
|
||||
try {
|
||||
await delegateClient.perpPlaceOrder(
|
||||
group,
|
||||
mangoAccount,
|
||||
'BTC-PERP',
|
||||
Side.bid,
|
||||
30000,
|
||||
0.000001,
|
||||
30000 * 0.000001,
|
||||
Math.floor(Math.random() * 99999),
|
||||
OrderType.limit,
|
||||
0,
|
||||
1,
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
process.exit();
|
||||
}
|
||||
|
||||
main();
|
|
@ -1,5 +1,5 @@
|
|||
import { AnchorProvider, Wallet } from '@project-serum/anchor';
|
||||
import { Connection, Keypair } from '@solana/web3.js';
|
||||
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
|
||||
import fs from 'fs';
|
||||
import { OrderType, Side } from '../accounts/perp';
|
||||
import {
|
||||
|
@ -61,32 +61,47 @@ async function main() {
|
|||
console.log(`...created/found mangoAccount ${mangoAccount.publicKey}`);
|
||||
console.log(mangoAccount.toString());
|
||||
|
||||
await mangoAccount.reloadAccountData(client, group);
|
||||
|
||||
if (true) {
|
||||
// deposit and withdraw
|
||||
console.log(`Depositing...50 USDC`);
|
||||
await client.tokenDeposit(group, mangoAccount, 'USDC', 50);
|
||||
await mangoAccount.reload(client, group);
|
||||
|
||||
console.log(`Depositing...0.0005 BTC`);
|
||||
await client.tokenDeposit(group, mangoAccount, 'BTC', 0.0005);
|
||||
await mangoAccount.reload(client, group);
|
||||
|
||||
console.log(`Withdrawing...0.1 ORCA`);
|
||||
await client.tokenWithdraw2(
|
||||
group,
|
||||
mangoAccount,
|
||||
'ORCA',
|
||||
0.1 * Math.pow(10, group.banksMap.get('ORCA').mintDecimals),
|
||||
true,
|
||||
// set delegate, and change name
|
||||
console.log(`...changing mango account name, and setting a delegate`);
|
||||
const randomKey = new PublicKey(
|
||||
'4ZkS7ZZkxfsC3GtvvsHP3DFcUeByU9zzZELS4r8HCELo',
|
||||
);
|
||||
await client.editMangoAccount(group, 'my_changed_name', randomKey);
|
||||
await mangoAccount.reload(client, group);
|
||||
console.log(mangoAccount.toString());
|
||||
|
||||
console.log(`...resetting mango account name, and re-setting a delegate`);
|
||||
await client.editMangoAccount(group, 'my_mango_account', PublicKey.default);
|
||||
await mangoAccount.reload(client, group);
|
||||
console.log(mangoAccount.toString());
|
||||
}
|
||||
|
||||
if (true) {
|
||||
// deposit and withdraw
|
||||
console.log(`...depositing 50 USDC`);
|
||||
await client.tokenDeposit(group, mangoAccount, 'USDC', 50);
|
||||
await mangoAccount.reload(client, group);
|
||||
|
||||
console.log(`...depositing 0.0005 BTC`);
|
||||
await client.tokenDeposit(group, mangoAccount, 'BTC', 0.0005);
|
||||
await mangoAccount.reload(client, group);
|
||||
|
||||
// witdrawing fails if no (other) user has deposited ORCA in the group
|
||||
// console.log(`Withdrawing...0.1 ORCA`);
|
||||
// await client.tokenWithdraw2(
|
||||
// group,
|
||||
// mangoAccount,
|
||||
// 'ORCA',
|
||||
// 0.1 * Math.pow(10, group.banksMap.get('ORCA').mintDecimals),
|
||||
// true,
|
||||
// );
|
||||
// await mangoAccount.reload(client, group);
|
||||
// console.log(mangoAccount.toString());
|
||||
|
||||
// serum3
|
||||
console.log(
|
||||
`Placing serum3 bid which would not be settled since its relatively low then midprice...`,
|
||||
`...placing serum3 bid which would not be settled since its relatively low then midprice`,
|
||||
);
|
||||
await client.serum3PlaceOrder(
|
||||
group,
|
||||
|
@ -103,7 +118,7 @@ async function main() {
|
|||
);
|
||||
await mangoAccount.reload(client, group);
|
||||
|
||||
console.log(`Placing serum3 bid way above midprice...`);
|
||||
console.log(`...placing serum3 bid way above midprice`);
|
||||
await client.serum3PlaceOrder(
|
||||
group,
|
||||
mangoAccount,
|
||||
|
@ -119,7 +134,7 @@ async function main() {
|
|||
);
|
||||
await mangoAccount.reload(client, group);
|
||||
|
||||
console.log(`Placing serum3 ask way below midprice...`);
|
||||
console.log(`...placing serum3 ask way below midprice`);
|
||||
await client.serum3PlaceOrder(
|
||||
group,
|
||||
mangoAccount,
|
||||
|
@ -134,7 +149,7 @@ async function main() {
|
|||
10,
|
||||
);
|
||||
|
||||
console.log(`Current own orders on OB...`);
|
||||
console.log(`...current own orders on OB`);
|
||||
let orders = await client.getSerum3Orders(
|
||||
group,
|
||||
|
||||
|
@ -142,9 +157,9 @@ async function main() {
|
|||
);
|
||||
for (const order of orders) {
|
||||
console.log(
|
||||
` - Order orderId ${order.orderId}, ${order.side}, ${order.price}, ${order.size}`,
|
||||
` - order orderId ${order.orderId}, ${order.side}, ${order.price}, ${order.size}`,
|
||||
);
|
||||
console.log(` - Cancelling order with ${order.orderId}`);
|
||||
console.log(` - cancelling order with ${order.orderId}`);
|
||||
await client.serum3CancelOrder(
|
||||
group,
|
||||
mangoAccount,
|
||||
|
@ -155,7 +170,7 @@ async function main() {
|
|||
);
|
||||
}
|
||||
|
||||
console.log(`Current own orders on OB...`);
|
||||
console.log(`...current own orders on OB`);
|
||||
orders = await client.getSerum3Orders(
|
||||
group,
|
||||
|
||||
|
@ -165,7 +180,7 @@ async function main() {
|
|||
console.log(order);
|
||||
}
|
||||
|
||||
console.log(`Settling funds...`);
|
||||
console.log(`...settling funds`);
|
||||
await client.serum3SettleFunds(
|
||||
group,
|
||||
mangoAccount,
|
||||
|
@ -177,23 +192,23 @@ async function main() {
|
|||
if (true) {
|
||||
await mangoAccount.reload(client, group);
|
||||
console.log(
|
||||
'mangoAccount.getEquity() ' +
|
||||
'...mangoAccount.getEquity() ' +
|
||||
toUiDecimals(mangoAccount.getEquity().toNumber()),
|
||||
);
|
||||
console.log(
|
||||
'mangoAccount.getCollateralValue() ' +
|
||||
'...mangoAccount.getCollateralValue() ' +
|
||||
toUiDecimals(mangoAccount.getCollateralValue().toNumber()),
|
||||
);
|
||||
console.log(
|
||||
'mangoAccount.getAssetsVal() ' +
|
||||
'...mangoAccount.getAssetsVal() ' +
|
||||
toUiDecimals(mangoAccount.getAssetsVal().toNumber()),
|
||||
);
|
||||
console.log(
|
||||
'mangoAccount.getLiabsVal() ' +
|
||||
'...mangoAccount.getLiabsVal() ' +
|
||||
toUiDecimals(mangoAccount.getLiabsVal().toNumber()),
|
||||
);
|
||||
console.log(
|
||||
"mangoAccount.getMaxWithdrawWithBorrowForToken(group, 'SOL') " +
|
||||
'...mangoAccount.getMaxWithdrawWithBorrowForToken(group, "SOL") ' +
|
||||
toUiDecimals(
|
||||
(
|
||||
await mangoAccount.getMaxWithdrawWithBorrowForToken(group, 'SOL')
|
||||
|
@ -201,7 +216,7 @@ async function main() {
|
|||
),
|
||||
);
|
||||
console.log(
|
||||
"mangoAccount.getSerum3MarketMarginAvailable(group, 'BTC/USDC') " +
|
||||
"...mangoAccount.getSerum3MarketMarginAvailable(group, 'BTC/USDC') " +
|
||||
toUiDecimals(
|
||||
mangoAccount
|
||||
.getSerum3MarketMarginAvailable(group, 'BTC/USDC')
|
||||
|
@ -209,7 +224,7 @@ async function main() {
|
|||
),
|
||||
);
|
||||
console.log(
|
||||
"mangoAccount.getPerpMarketMarginAvailable(group, 'BTC-PERP') " +
|
||||
"...mangoAccount.getPerpMarketMarginAvailable(group, 'BTC-PERP') " +
|
||||
toUiDecimals(
|
||||
mangoAccount
|
||||
.getPerpMarketMarginAvailable(group, 'BTC-PERP')
|
||||
|
@ -220,7 +235,7 @@ async function main() {
|
|||
|
||||
if (true) {
|
||||
// perps
|
||||
console.log(`Placing perp bid...`);
|
||||
console.log(`...placing perp bid`);
|
||||
try {
|
||||
await client.perpPlaceOrder(
|
||||
group,
|
||||
|
@ -239,7 +254,7 @@ async function main() {
|
|||
console.log(error);
|
||||
}
|
||||
|
||||
console.log(`Placing perp ask...`);
|
||||
console.log(`...placing perp ask`);
|
||||
await client.perpPlaceOrder(
|
||||
group,
|
||||
mangoAccount,
|
||||
|
@ -257,7 +272,7 @@ async function main() {
|
|||
while (true) {
|
||||
// TODO: quotePositionNative might be buggy on program side, investigate...
|
||||
console.log(
|
||||
`Waiting for self trade to consume (note: make sure keeper crank is running)...`,
|
||||
`...waiting for self trade to consume (note: make sure keeper crank is running)`,
|
||||
);
|
||||
await mangoAccount.reload(client, group);
|
||||
console.log(mangoAccount.toString());
|
||||
|
|
Loading…
Reference in New Issue