Renames in MangoAccount
- Accessors in MangoAccountValue - PerpPositions -> PerpPosition
This commit is contained in:
parent
ec850b7bd3
commit
09fc5f716b
|
@ -321,8 +321,8 @@ impl MangoClient {
|
|||
let account = self.mango_account()?;
|
||||
|
||||
let token_indexes = liqee
|
||||
.token_iter_active()
|
||||
.chain(account.token_iter_active())
|
||||
.active_token_positions()
|
||||
.chain(account.active_token_positions())
|
||||
.map(|ta| ta.token_index)
|
||||
.unique();
|
||||
|
||||
|
@ -334,12 +334,12 @@ impl MangoClient {
|
|||
}
|
||||
|
||||
let serum_oos = liqee
|
||||
.serum3_iter_active()
|
||||
.chain(account.serum3_iter_active())
|
||||
.active_serum3_orders()
|
||||
.chain(account.active_serum3_orders())
|
||||
.map(|&s| s.open_orders);
|
||||
let perp_markets = liqee
|
||||
.perp_iter_active_accounts()
|
||||
.chain(account.perp_iter_active_accounts())
|
||||
.active_perp_positions()
|
||||
.chain(account.active_perp_positions())
|
||||
.map(|&pa| self.context.perp_market_address(pa.market_index));
|
||||
|
||||
Ok(banks
|
||||
|
@ -543,7 +543,7 @@ impl MangoClient {
|
|||
let s3 = self.serum3_data(name)?;
|
||||
|
||||
let account = self.mango_account()?;
|
||||
let open_orders = account.serum3_find(s3.market_index).unwrap().open_orders;
|
||||
let open_orders = account.serum3_orders(s3.market_index).unwrap().open_orders;
|
||||
|
||||
let health_check_metas = self.derive_health_check_remaining_account_metas(vec![], false)?;
|
||||
|
||||
|
@ -658,7 +658,7 @@ impl MangoClient {
|
|||
let s3 = self.serum3_data(name)?;
|
||||
|
||||
let account = self.mango_account()?;
|
||||
let open_orders = account.serum3_find(s3.market_index).unwrap().open_orders;
|
||||
let open_orders = account.serum3_orders(s3.market_index).unwrap().open_orders;
|
||||
|
||||
self.program()
|
||||
.request()
|
||||
|
@ -700,7 +700,7 @@ impl MangoClient {
|
|||
.get(market_name)
|
||||
.unwrap();
|
||||
let account = self.mango_account()?;
|
||||
let open_orders = account.serum3_find(market_index).unwrap().open_orders;
|
||||
let open_orders = account.serum3_orders(market_index).unwrap().open_orders;
|
||||
|
||||
let open_orders_bytes = self.account_fetcher.fetch_raw_account(open_orders)?.data;
|
||||
let open_orders_data: &serum_dex::state::OpenOrders = bytemuck::from_bytes(
|
||||
|
@ -732,7 +732,7 @@ impl MangoClient {
|
|||
let s3 = self.serum3_data(market_name)?;
|
||||
|
||||
let account = self.mango_account()?;
|
||||
let open_orders = account.serum3_find(s3.market_index).unwrap().open_orders;
|
||||
let open_orders = account.serum3_orders(s3.market_index).unwrap().open_orders;
|
||||
|
||||
self.program()
|
||||
.request()
|
||||
|
|
|
@ -211,29 +211,32 @@ impl MangoGroupContext {
|
|||
// figure out all the banks/oracles that need to be passed for the health check
|
||||
let mut banks = vec![];
|
||||
let mut oracles = vec![];
|
||||
for position in account.token_iter_active() {
|
||||
for position in account.active_token_positions() {
|
||||
let mint_info = self.mint_info(position.token_index);
|
||||
banks.push(mint_info.first_bank());
|
||||
oracles.push(mint_info.oracle);
|
||||
}
|
||||
for affected_token_index in affected_tokens {
|
||||
if account
|
||||
.token_iter_active()
|
||||
.active_token_positions()
|
||||
.find(|p| p.token_index == affected_token_index)
|
||||
.is_none()
|
||||
{
|
||||
// If there is not yet an active position for the token, we need to pass
|
||||
// the bank/oracle for health check anyway.
|
||||
let new_position = account.token_iter().position(|p| !p.is_active()).unwrap();
|
||||
let new_position = account
|
||||
.all_token_positions()
|
||||
.position(|p| !p.is_active())
|
||||
.unwrap();
|
||||
let mint_info = self.mint_info(affected_token_index);
|
||||
banks.insert(new_position, mint_info.first_bank());
|
||||
oracles.insert(new_position, mint_info.oracle);
|
||||
}
|
||||
}
|
||||
|
||||
let serum_oos = account.serum3_iter_active().map(|&s| s.open_orders);
|
||||
let serum_oos = account.active_serum3_orders().map(|&s| s.open_orders);
|
||||
let perp_markets = account
|
||||
.perp_iter_active_accounts()
|
||||
.active_perp_positions()
|
||||
.map(|&pa| self.perp_market_address(pa.market_index));
|
||||
|
||||
Ok(banks
|
||||
|
|
|
@ -77,7 +77,7 @@ fn ensure_oo(mango_client: &Arc<MangoClient>) -> Result<(), anyhow::Error> {
|
|||
let account = mango_client.mango_account()?;
|
||||
|
||||
for (market_index, serum3_market) in mango_client.context.serum3_markets.iter() {
|
||||
if account.serum3_find(*market_index).is_none() {
|
||||
if account.serum3_orders(*market_index).is_none() {
|
||||
mango_client.serum3_create_open_orders(serum3_market.market.name())?;
|
||||
}
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ fn ensure_deposit(mango_client: &Arc<MangoClient>) -> Result<(), anyhow::Error>
|
|||
let bank = mango_client.first_bank(token_index)?;
|
||||
let desired_balance = I80F48::from_num(10_000 * 10u64.pow(bank.mint_decimals as u32));
|
||||
|
||||
let token_account_opt = mango_account.token_find(token_index);
|
||||
let token_account_opt = mango_account.token_position(token_index).ok();
|
||||
|
||||
let deposit_native = match token_account_opt {
|
||||
Some(token_account) => {
|
||||
|
|
|
@ -20,8 +20,8 @@ pub fn new_health_cache_(
|
|||
account_fetcher: &chain_data::AccountFetcher,
|
||||
account: &MangoAccountValue,
|
||||
) -> anyhow::Result<HealthCache> {
|
||||
let active_token_len = account.token_iter_active().count();
|
||||
let active_perp_len = account.perp_iter_active_accounts().count();
|
||||
let active_token_len = account.active_token_positions().count();
|
||||
let active_perp_len = account.active_perp_positions().count();
|
||||
|
||||
let metas = context.derive_health_check_remaining_account_metas(account, vec![], false)?;
|
||||
let accounts = metas
|
||||
|
@ -138,7 +138,7 @@ pub fn maybe_liquidate_account(
|
|||
|
||||
// find asset and liab tokens
|
||||
let mut tokens = account
|
||||
.token_iter_active()
|
||||
.active_token_positions()
|
||||
.map(|token_position| {
|
||||
let token = mango_client.context.token(token_position.token_index);
|
||||
let bank = account_fetcher.fetch::<Bank>(&token.mint_info.first_bank())?;
|
||||
|
@ -164,8 +164,8 @@ pub fn maybe_liquidate_account(
|
|||
|
||||
// Ensure the tokens are activated, so they appear in the health cache and
|
||||
// max_swap_source() will work.
|
||||
liqor.token_get_mut_or_create(source)?;
|
||||
liqor.token_get_mut_or_create(target)?;
|
||||
liqor.ensure_token_position(source)?;
|
||||
liqor.ensure_token_position(target)?;
|
||||
|
||||
let health_cache =
|
||||
new_health_cache_(&mango_client.context, account_fetcher, &liqor).expect("always ok");
|
||||
|
|
|
@ -68,7 +68,7 @@ pub fn zero_all_non_quote(
|
|||
let account = account_fetcher.fetch_mango_account(mango_account_address)?;
|
||||
|
||||
let tokens = account
|
||||
.token_iter_active()
|
||||
.active_token_positions()
|
||||
.map(|token_position| {
|
||||
let token = mango_client.context.token(token_position.token_index);
|
||||
Ok((
|
||||
|
@ -140,7 +140,7 @@ pub fn zero_all_non_quote(
|
|||
let bank = TokenState::bank(token, account_fetcher)?;
|
||||
amount = mango_client
|
||||
.mango_account()?
|
||||
.token_get(token_index)
|
||||
.token_position_and_raw_index(token_index)
|
||||
.map(|(position, _)| position.native(&bank))
|
||||
.unwrap_or(I80F48::ZERO);
|
||||
} else if token_state.native_position < 0 {
|
||||
|
@ -167,7 +167,7 @@ pub fn zero_all_non_quote(
|
|||
let bank = TokenState::bank(token, account_fetcher)?;
|
||||
amount = mango_client
|
||||
.mango_account()?
|
||||
.token_get(token_index)
|
||||
.token_position_and_raw_index(token_index)
|
||||
.map(|(position, _)| position.native(&bank))
|
||||
.unwrap_or(I80F48::ZERO);
|
||||
}
|
||||
|
|
|
@ -164,7 +164,7 @@ async fn feed_snapshots(
|
|||
})
|
||||
.flat_map(|mango_account| {
|
||||
mango_account
|
||||
.serum3_iter_active()
|
||||
.active_serum3_orders()
|
||||
.map(|serum3account| serum3account.open_orders)
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
|
|
|
@ -32,13 +32,13 @@ pub fn account_close(ctx: Context<AccountClose>) -> Result<()> {
|
|||
// don't perform checks if group is just testing
|
||||
if !group.is_testing() {
|
||||
require!(!account.fixed.being_liquidated(), MangoError::SomeError);
|
||||
for ele in account.token_iter() {
|
||||
for ele in account.all_token_positions() {
|
||||
require_eq!(ele.is_active(), false);
|
||||
}
|
||||
for ele in account.serum3_iter() {
|
||||
for ele in account.all_serum3_orders() {
|
||||
require_eq!(ele.is_active(), false);
|
||||
}
|
||||
for ele in account.perp_iter() {
|
||||
for ele in account.all_perp_positions() {
|
||||
require_eq!(ele.is_active(), false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -265,7 +265,7 @@ pub fn flash_loan_end<'key, 'accounts, 'remaining, 'info>(
|
|||
require_neq!(bank.flash_loan_token_account_initial, u64::MAX);
|
||||
|
||||
// Create the token position now, so we can compute the pre-health with fixed order health accounts
|
||||
let (_, raw_token_index, _) = account.token_get_mut_or_create(bank.token_index)?;
|
||||
let (_, raw_token_index, _) = account.ensure_token_position(bank.token_index)?;
|
||||
|
||||
// Transfer any excess over the inital balance of the token account back
|
||||
// into the vault. Compute the total change in the vault balance.
|
||||
|
@ -337,7 +337,7 @@ pub fn flash_loan_end<'key, 'accounts, 'remaining, 'info>(
|
|||
let mut token_loan_details = Vec::with_capacity(changes.len());
|
||||
for (change, price) in changes.iter().zip(prices.iter()) {
|
||||
let mut bank = health_ais[change.bank_index].load_mut::<Bank>()?;
|
||||
let position = account.token_get_mut_raw(change.raw_token_index);
|
||||
let position = account.token_position_mut_by_raw_index(change.raw_token_index);
|
||||
let native = position.native(&bank);
|
||||
let approved_amount = I80F48::from(bank.flash_loan_approved_amount);
|
||||
|
||||
|
@ -398,7 +398,7 @@ pub fn flash_loan_end<'key, 'accounts, 'remaining, 'info>(
|
|||
|
||||
// Deactivate inactive token accounts after health check
|
||||
for raw_token_index in deactivated_token_positions {
|
||||
account.token_deactivate(raw_token_index);
|
||||
account.deactivate_token_position(raw_token_index);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -99,7 +99,7 @@ pub fn liq_token_bankruptcy(
|
|||
let (liab_bank, liab_price, opt_quote_bank_and_price) =
|
||||
account_retriever.banks_mut_and_oracles(liab_token_index, QUOTE_TOKEN_INDEX)?;
|
||||
let liab_deposit_index = liab_bank.deposit_index;
|
||||
let (liqee_liab, liqee_raw_token_index) = liqee.token_get_mut(liab_token_index)?;
|
||||
let (liqee_liab, liqee_raw_token_index) = liqee.token_position_mut(liab_token_index)?;
|
||||
let initial_liab_native = liqee_liab.native(&liab_bank);
|
||||
let mut remaining_liab_loss = -initial_liab_native;
|
||||
require_gt!(remaining_liab_loss, I80F48::ZERO);
|
||||
|
@ -158,12 +158,12 @@ pub fn liq_token_bankruptcy(
|
|||
|
||||
// credit the liqor
|
||||
let (liqor_quote, liqor_quote_raw_token_index, _) =
|
||||
liqor.token_get_mut_or_create(QUOTE_TOKEN_INDEX)?;
|
||||
liqor.ensure_token_position(QUOTE_TOKEN_INDEX)?;
|
||||
let liqor_quote_active = quote_bank.deposit(liqor_quote, insurance_transfer_i80f48)?;
|
||||
|
||||
// transfer liab from liqee to liqor
|
||||
let (liqor_liab, liqor_liab_raw_token_index, _) =
|
||||
liqor.token_get_mut_or_create(liab_token_index)?;
|
||||
liqor.ensure_token_position(liab_token_index)?;
|
||||
let liqor_liab_active = liab_bank.withdraw_with_fee(liqor_liab, liab_transfer)?;
|
||||
|
||||
// Check liqor's health
|
||||
|
@ -172,10 +172,10 @@ pub fn liq_token_bankruptcy(
|
|||
require!(liqor_health >= 0, MangoError::HealthMustBePositive);
|
||||
|
||||
if !liqor_quote_active {
|
||||
liqor.token_deactivate(liqor_quote_raw_token_index);
|
||||
liqor.deactivate_token_position(liqor_quote_raw_token_index);
|
||||
}
|
||||
if !liqor_liab_active {
|
||||
liqor.token_deactivate(liqor_liab_raw_token_index);
|
||||
liqor.deactivate_token_position(liqor_liab_raw_token_index);
|
||||
}
|
||||
} else {
|
||||
// For liab_token_index == QUOTE_TOKEN_INDEX: the insurance fund deposits directly into liqee,
|
||||
|
@ -240,7 +240,7 @@ pub fn liq_token_bankruptcy(
|
|||
.maybe_recover_from_being_liquidated(liqee_init_health);
|
||||
|
||||
if !liqee_liab_active {
|
||||
liqee.token_deactivate(liqee_raw_token_index);
|
||||
liqee.deactivate_token_position(liqee_raw_token_index);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -88,11 +88,13 @@ pub fn liq_token_with_token(
|
|||
|
||||
// The main complication here is that we can't keep the liqee_asset_position and liqee_liab_position
|
||||
// borrows alive at the same time. Possibly adding get_mut_pair() would be helpful.
|
||||
let (liqee_asset_position, liqee_asset_raw_index) = liqee.token_get(asset_token_index)?;
|
||||
let (liqee_asset_position, liqee_asset_raw_index) =
|
||||
liqee.token_position_and_raw_index(asset_token_index)?;
|
||||
let liqee_asset_native = liqee_asset_position.native(asset_bank);
|
||||
require!(liqee_asset_native.is_positive(), MangoError::SomeError);
|
||||
|
||||
let (liqee_liab_position, liqee_liab_raw_index) = liqee.token_get(liab_token_index)?;
|
||||
let (liqee_liab_position, liqee_liab_raw_index) =
|
||||
liqee.token_position_and_raw_index(liab_token_index)?;
|
||||
let liqee_liab_native = liqee_liab_position.native(liab_bank);
|
||||
require!(liqee_liab_native.is_negative(), MangoError::SomeError);
|
||||
|
||||
|
@ -135,23 +137,23 @@ pub fn liq_token_with_token(
|
|||
// is nominally in-use.
|
||||
|
||||
// Apply the balance changes to the liqor and liqee accounts
|
||||
let liqee_liab_position = liqee.token_get_mut_raw(liqee_liab_raw_index);
|
||||
let liqee_liab_position = liqee.token_position_mut_by_raw_index(liqee_liab_raw_index);
|
||||
let liqee_liab_active =
|
||||
liab_bank.deposit_with_dusting(liqee_liab_position, liab_transfer)?;
|
||||
let liqee_liab_position_indexed = liqee_liab_position.indexed_position;
|
||||
|
||||
let (liqor_liab_position, liqor_liab_raw_index, _) =
|
||||
liqor.token_get_mut_or_create(liab_token_index)?;
|
||||
liqor.ensure_token_position(liab_token_index)?;
|
||||
let liqor_liab_active = liab_bank.withdraw_with_fee(liqor_liab_position, liab_transfer)?;
|
||||
let liqor_liab_position_indexed = liqor_liab_position.indexed_position;
|
||||
let liqee_liab_native_after = liqee_liab_position.native(&liab_bank);
|
||||
|
||||
let (liqor_asset_position, liqor_asset_raw_index, _) =
|
||||
liqor.token_get_mut_or_create(asset_token_index)?;
|
||||
liqor.ensure_token_position(asset_token_index)?;
|
||||
let liqor_asset_active = asset_bank.deposit(liqor_asset_position, asset_transfer)?;
|
||||
let liqor_asset_position_indexed = liqor_asset_position.indexed_position;
|
||||
|
||||
let liqee_asset_position = liqee.token_get_mut_raw(liqee_asset_raw_index);
|
||||
let liqee_asset_position = liqee.token_position_mut_by_raw_index(liqee_asset_raw_index);
|
||||
let liqee_asset_active =
|
||||
asset_bank.withdraw_without_fee_with_dusting(liqee_asset_position, asset_transfer)?;
|
||||
let liqee_asset_position_indexed = liqee_asset_position.indexed_position;
|
||||
|
@ -229,16 +231,16 @@ pub fn liq_token_with_token(
|
|||
|
||||
// Since we use a scanning account retriever, it's safe to deactivate inactive token positions
|
||||
if !liqee_asset_active {
|
||||
liqee.token_deactivate(liqee_asset_raw_index);
|
||||
liqee.deactivate_token_position(liqee_asset_raw_index);
|
||||
}
|
||||
if !liqee_liab_active {
|
||||
liqee.token_deactivate(liqee_liab_raw_index);
|
||||
liqee.deactivate_token_position(liqee_liab_raw_index);
|
||||
}
|
||||
if !liqor_asset_active {
|
||||
liqor.token_deactivate(liqor_asset_raw_index);
|
||||
liqor.deactivate_token_position(liqor_asset_raw_index);
|
||||
}
|
||||
if !liqor_liab_active {
|
||||
liqor.token_deactivate(liqor_liab_raw_index)
|
||||
liqor.deactivate_token_position(liqor_liab_raw_index)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,5 +46,5 @@ pub fn perp_cancel_order(ctx: Context<PerpCancelOrder>, order_id: i128) -> Resul
|
|||
MangoError::SomeError // InvalidOwner
|
||||
);
|
||||
|
||||
account.perp_remove_order(order.owner_slot as usize, order.quantity)
|
||||
account.remove_perp_order(order.owner_slot as usize, order.quantity)
|
||||
}
|
||||
|
|
|
@ -49,5 +49,5 @@ pub fn perp_cancel_order_by_client_order_id(
|
|||
MangoError::SomeError // InvalidOwner
|
||||
);
|
||||
|
||||
account.perp_remove_order(order.owner_slot as usize, order.quantity)
|
||||
account.remove_perp_order(order.owner_slot as usize, order.quantity)
|
||||
}
|
||||
|
|
|
@ -50,12 +50,12 @@ pub fn perp_consume_events(ctx: Context<PerpConsumeEvents>, limit: usize) -> Res
|
|||
let mal: AccountLoaderDynamic<MangoAccount> =
|
||||
AccountLoaderDynamic::try_from(ai)?;
|
||||
let mut ma = mal.load_mut()?;
|
||||
ma.perp_execute_maker(
|
||||
ma.execute_perp_maker(
|
||||
perp_market.perp_market_index,
|
||||
&mut perp_market,
|
||||
fill,
|
||||
)?;
|
||||
ma.perp_execute_taker(
|
||||
ma.execute_perp_taker(
|
||||
perp_market.perp_market_index,
|
||||
&mut perp_market,
|
||||
fill,
|
||||
|
@ -65,7 +65,7 @@ pub fn perp_consume_events(ctx: Context<PerpConsumeEvents>, limit: usize) -> Res
|
|||
fill.maker,
|
||||
perp_market.perp_market_index as u64,
|
||||
fill.price,
|
||||
ma.perp_find_account(perp_market.perp_market_index).unwrap(),
|
||||
ma.perp_position(perp_market.perp_market_index).unwrap(),
|
||||
&perp_market,
|
||||
);
|
||||
}
|
||||
|
@ -91,12 +91,12 @@ pub fn perp_consume_events(ctx: Context<PerpConsumeEvents>, limit: usize) -> Res
|
|||
AccountLoaderDynamic::try_from(ai)?;
|
||||
let mut taker = mal.load_mut()?;
|
||||
|
||||
maker.perp_execute_maker(
|
||||
maker.execute_perp_maker(
|
||||
perp_market.perp_market_index,
|
||||
&mut perp_market,
|
||||
fill,
|
||||
)?;
|
||||
taker.perp_execute_taker(
|
||||
taker.execute_perp_taker(
|
||||
perp_market.perp_market_index,
|
||||
&mut perp_market,
|
||||
fill,
|
||||
|
@ -106,9 +106,7 @@ pub fn perp_consume_events(ctx: Context<PerpConsumeEvents>, limit: usize) -> Res
|
|||
fill.maker,
|
||||
perp_market.perp_market_index as u64,
|
||||
fill.price,
|
||||
maker
|
||||
.perp_find_account(perp_market.perp_market_index)
|
||||
.unwrap(),
|
||||
maker.perp_position(perp_market.perp_market_index).unwrap(),
|
||||
&perp_market,
|
||||
);
|
||||
emit_perp_balances(
|
||||
|
@ -116,9 +114,7 @@ pub fn perp_consume_events(ctx: Context<PerpConsumeEvents>, limit: usize) -> Res
|
|||
fill.taker,
|
||||
perp_market.perp_market_index as u64,
|
||||
fill.price,
|
||||
taker
|
||||
.perp_find_account(perp_market.perp_market_index)
|
||||
.unwrap(),
|
||||
taker.perp_position(perp_market.perp_market_index).unwrap(),
|
||||
&perp_market,
|
||||
);
|
||||
}
|
||||
|
@ -161,7 +157,7 @@ pub fn perp_consume_events(ctx: Context<PerpConsumeEvents>, limit: usize) -> Res
|
|||
AccountLoaderDynamic::try_from(ai)?;
|
||||
let mut ma = mal.load_mut()?;
|
||||
|
||||
ma.perp_remove_order(out.owner_slot as usize, out.quantity)?;
|
||||
ma.remove_perp_order(out.owner_slot as usize, out.quantity)?;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ pub fn serum3_cancel_all_orders(ctx: Context<Serum3CancelAllOrders>, limit: u8)
|
|||
// Validate open_orders
|
||||
require!(
|
||||
account
|
||||
.serum3_find(serum_market.market_index)
|
||||
.serum3_orders(serum_market.market_index)
|
||||
.ok_or_else(|| error!(MangoError::SomeError))?
|
||||
.open_orders
|
||||
== ctx.accounts.open_orders.key(),
|
||||
|
|
|
@ -67,7 +67,7 @@ pub fn serum3_cancel_order(
|
|||
// Validate open_orders
|
||||
require!(
|
||||
account
|
||||
.serum3_find(serum_market.market_index)
|
||||
.serum3_orders(serum_market.market_index)
|
||||
.ok_or_else(|| error!(MangoError::SomeError))?
|
||||
.open_orders
|
||||
== ctx.accounts.open_orders.key(),
|
||||
|
@ -111,7 +111,7 @@ pub fn decrease_maybe_loan(
|
|||
before_oo: &OpenOrdersSlim,
|
||||
after_oo: &OpenOrdersSlim,
|
||||
) {
|
||||
let serum3_account = account.serum3_find_mut(market_index).unwrap();
|
||||
let serum3_account = account.serum3_orders_mut(market_index).unwrap();
|
||||
|
||||
if after_oo.native_coin_free > before_oo.native_coin_free {
|
||||
let native_coin_free_increase = after_oo.native_coin_free - before_oo.native_coin_free;
|
||||
|
|
|
@ -46,7 +46,7 @@ pub fn serum3_close_open_orders(ctx: Context<Serum3CloseOpenOrders>) -> Result<(
|
|||
// Validate open_orders
|
||||
require!(
|
||||
account
|
||||
.serum3_find(serum_market.market_index)
|
||||
.serum3_orders(serum_market.market_index)
|
||||
.ok_or_else(|| error!(MangoError::SomeError))?
|
||||
.open_orders
|
||||
== ctx.accounts.open_orders.key(),
|
||||
|
@ -59,7 +59,7 @@ pub fn serum3_close_open_orders(ctx: Context<Serum3CloseOpenOrders>) -> Result<(
|
|||
cpi_close_open_orders(ctx.accounts)?;
|
||||
|
||||
// TODO: decrement in_use_count on the base token and quote token
|
||||
account.serum3_deactivate(serum_market.market_index)?;
|
||||
account.deactivate_serum3_orders(serum_market.market_index)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ pub fn serum3_create_open_orders(ctx: Context<Serum3CreateOpenOrders>) -> Result
|
|||
MangoError::SomeError
|
||||
);
|
||||
|
||||
let serum_account = account.serum3_create(serum_market.market_index)?;
|
||||
let serum_account = account.create_serum3_orders(serum_market.market_index)?;
|
||||
serum_account.open_orders = ctx.accounts.open_orders.key();
|
||||
serum_account.base_token_index = serum_market.base_token_index;
|
||||
serum_account.quote_token_index = serum_market.quote_token_index;
|
||||
|
@ -61,9 +61,9 @@ pub fn serum3_create_open_orders(ctx: Context<Serum3CreateOpenOrders>) -> Result
|
|||
// Make it so that the token_account_map for the base and quote currency
|
||||
// stay permanently blocked. Otherwise users may end up in situations where
|
||||
// they can't settle a market because they don't have free token_account_map!
|
||||
let (quote_position, _, _) = account.token_get_mut_or_create(serum_market.quote_token_index)?;
|
||||
let (quote_position, _, _) = account.ensure_token_position(serum_market.quote_token_index)?;
|
||||
quote_position.in_use_count += 1;
|
||||
let (base_position, _, _) = account.token_get_mut_or_create(serum_market.base_token_index)?;
|
||||
let (base_position, _, _) = account.ensure_token_position(serum_market.base_token_index)?;
|
||||
base_position.in_use_count += 1;
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -75,7 +75,7 @@ pub fn serum3_liq_force_cancel_orders(
|
|||
// Validate open_orders
|
||||
require!(
|
||||
account
|
||||
.serum3_find(serum_market.market_index)
|
||||
.serum3_orders(serum_market.market_index)
|
||||
.ok_or_else(|| error!(MangoError::SomeError))?
|
||||
.open_orders
|
||||
== ctx.accounts.open_orders.key(),
|
||||
|
|
|
@ -172,7 +172,7 @@ pub fn serum3_place_order(
|
|||
// Validate open_orders
|
||||
require!(
|
||||
account
|
||||
.serum3_find(serum_market.market_index)
|
||||
.serum3_orders(serum_market.market_index)
|
||||
.ok_or_else(|| error!(MangoError::SomeError))?
|
||||
.open_orders
|
||||
== ctx.accounts.open_orders.key(),
|
||||
|
@ -308,7 +308,7 @@ pub fn inc_maybe_loan(
|
|||
before_oo: &OpenOrdersSlim,
|
||||
after_oo: &OpenOrdersSlim,
|
||||
) {
|
||||
let serum3_account = account.serum3_find_mut(market_index).unwrap();
|
||||
let serum3_account = account.serum3_orders_mut(market_index).unwrap();
|
||||
|
||||
if after_oo.native_coin_reserved() > before_oo.native_coin_reserved() {
|
||||
let native_coin_reserved_increase =
|
||||
|
@ -334,10 +334,10 @@ pub struct VaultDifferenceResult {
|
|||
impl VaultDifferenceResult {
|
||||
pub fn deactivate_inactive_token_accounts(&self, account: &mut MangoAccountRefMut) {
|
||||
if !self.base_active {
|
||||
account.token_deactivate(self.base_raw_index);
|
||||
account.deactivate_token_position(self.base_raw_index);
|
||||
}
|
||||
if !self.quote_active {
|
||||
account.token_deactivate(self.quote_raw_index);
|
||||
account.deactivate_token_position(self.quote_raw_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -355,11 +355,11 @@ pub fn apply_vault_difference(
|
|||
// charged if an order executes and the loan materializes? Otherwise MMs that place
|
||||
// an order without having the funds will be charged for each place_order!
|
||||
|
||||
let (base_position, base_raw_index) = account.token_get_mut(base_bank.token_index)?;
|
||||
let (base_position, base_raw_index) = account.token_position_mut(base_bank.token_index)?;
|
||||
let base_change = I80F48::from(after_base_vault) - I80F48::from(before_base_vault);
|
||||
let base_active = base_bank.change_with_fee(base_position, base_change)?;
|
||||
|
||||
let (quote_position, quote_raw_index) = account.token_get_mut(quote_bank.token_index)?;
|
||||
let (quote_position, quote_raw_index) = account.token_position_mut(quote_bank.token_index)?;
|
||||
let quote_change = I80F48::from(after_quote_vault) - I80F48::from(before_quote_vault);
|
||||
let quote_active = quote_bank.change_with_fee(quote_position, quote_change)?;
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ pub fn serum3_settle_funds(ctx: Context<Serum3SettleFunds>) -> Result<()> {
|
|||
// Validate open_orders
|
||||
require!(
|
||||
account
|
||||
.serum3_find(serum_market.market_index)
|
||||
.serum3_orders(serum_market.market_index)
|
||||
.ok_or_else(|| error!(MangoError::SomeError))?
|
||||
.open_orders
|
||||
== ctx.accounts.open_orders.key(),
|
||||
|
@ -172,7 +172,7 @@ pub fn charge_maybe_fees(
|
|||
account: &mut MangoAccountRefMut,
|
||||
after_oo: &OpenOrdersSlim,
|
||||
) -> Result<()> {
|
||||
let serum3_account = account.serum3_find_mut(market_index).unwrap();
|
||||
let serum3_account = account.serum3_orders_mut(market_index).unwrap();
|
||||
|
||||
let maybe_actualized_coin_loan = I80F48::from_num::<u64>(
|
||||
serum3_account
|
||||
|
@ -184,7 +184,7 @@ pub fn charge_maybe_fees(
|
|||
serum3_account.previous_native_coin_reserved = after_oo.native_coin_reserved();
|
||||
|
||||
// loan origination fees
|
||||
let coin_token_account = account.token_get_mut(coin_bank.token_index)?.0;
|
||||
let coin_token_account = account.token_position_mut(coin_bank.token_index)?.0;
|
||||
let coin_token_native = coin_token_account.native(coin_bank);
|
||||
|
||||
if coin_token_native.is_negative() {
|
||||
|
@ -198,7 +198,7 @@ pub fn charge_maybe_fees(
|
|||
}
|
||||
}
|
||||
|
||||
let serum3_account = account.serum3_find_mut(market_index).unwrap();
|
||||
let serum3_account = account.serum3_orders_mut(market_index).unwrap();
|
||||
let maybe_actualized_pc_loan = I80F48::from_num::<u64>(
|
||||
serum3_account
|
||||
.previous_native_pc_reserved
|
||||
|
@ -209,7 +209,7 @@ pub fn charge_maybe_fees(
|
|||
serum3_account.previous_native_pc_reserved = after_oo.native_pc_reserved();
|
||||
|
||||
// loan origination fees
|
||||
let pc_token_account = account.token_get_mut(pc_bank.token_index)?.0;
|
||||
let pc_token_account = account.token_position_mut(pc_bank.token_index)?.0;
|
||||
let pc_token_native = pc_token_account.native(pc_bank);
|
||||
|
||||
if pc_token_native.is_negative() {
|
||||
|
|
|
@ -57,7 +57,7 @@ pub fn token_deposit(ctx: Context<TokenDeposit>, amount: u64) -> Result<()> {
|
|||
let mut account = ctx.accounts.account.load_mut()?;
|
||||
|
||||
let (position, raw_token_index, active_token_index) =
|
||||
account.token_get_mut_or_create(token_index)?;
|
||||
account.ensure_token_position(token_index)?;
|
||||
|
||||
let amount_i80f48 = I80F48::from(amount);
|
||||
let position_is_active = {
|
||||
|
@ -103,7 +103,7 @@ pub fn token_deposit(ctx: Context<TokenDeposit>, amount: u64) -> Result<()> {
|
|||
// Deposits can deactivate a position if they cancel out a previous borrow.
|
||||
//
|
||||
if !position_is_active {
|
||||
account.token_deactivate(raw_token_index);
|
||||
account.deactivate_token_position(raw_token_index);
|
||||
}
|
||||
|
||||
emit!(DepositLog {
|
||||
|
|
|
@ -58,7 +58,7 @@ pub fn token_withdraw(ctx: Context<TokenWithdraw>, amount: u64, allow_borrow: bo
|
|||
let mut account = ctx.accounts.account.load_mut()?;
|
||||
|
||||
let (position, raw_token_index, active_token_index) =
|
||||
account.token_get_mut_or_create(token_index)?;
|
||||
account.ensure_token_position(token_index)?;
|
||||
|
||||
// The bank will also be passed in remainingAccounts. Use an explicit scope
|
||||
// to drop the &mut before we borrow it immutably again later.
|
||||
|
@ -144,7 +144,7 @@ pub fn token_withdraw(ctx: Context<TokenWithdraw>, amount: u64, allow_borrow: bo
|
|||
// deactivated.
|
||||
//
|
||||
if !position_is_active {
|
||||
account.token_deactivate(raw_token_index);
|
||||
account.deactivate_token_position(raw_token_index);
|
||||
}
|
||||
|
||||
emit!(WithdrawLog {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
instructions::FlashLoanType,
|
||||
state::{PerpMarket, PerpPositions},
|
||||
state::{PerpMarket, PerpPosition},
|
||||
};
|
||||
use anchor_lang::prelude::*;
|
||||
use borsh::BorshSerialize;
|
||||
|
@ -11,7 +11,7 @@ pub fn emit_perp_balances(
|
|||
mango_account: Pubkey,
|
||||
market_index: u64,
|
||||
price: i64,
|
||||
pp: &PerpPositions,
|
||||
pp: &PerpPosition,
|
||||
pm: &PerpMarket,
|
||||
) {
|
||||
emit!(PerpBalanceLog {
|
||||
|
|
|
@ -15,7 +15,7 @@ pub fn compute_equity(
|
|||
let mut token_equity_map = HashMap::new();
|
||||
|
||||
// token contributions
|
||||
for (_i, position) in account.token_iter_active().enumerate() {
|
||||
for (_i, position) in account.active_token_positions().enumerate() {
|
||||
let (bank, oracle_price) = retriever.scanned_bank_and_oracle(position.token_index)?;
|
||||
// converts the token value to the basis token value for health computations
|
||||
// TODO: health basis token == USDC?
|
||||
|
@ -24,7 +24,7 @@ pub fn compute_equity(
|
|||
}
|
||||
|
||||
// token contributions from Serum3
|
||||
for (_i, serum_account) in account.serum3_iter_active().enumerate() {
|
||||
for (_i, serum_account) in account.active_serum3_orders().enumerate() {
|
||||
let oo = retriever.scanned_serum_oo(&serum_account.open_orders)?;
|
||||
|
||||
// note base token value
|
||||
|
|
|
@ -63,9 +63,9 @@ pub fn new_fixed_order_account_retriever<'a, 'info>(
|
|||
ais: &'a [AccountInfo<'info>],
|
||||
account: &MangoAccountRef,
|
||||
) -> Result<FixedOrderAccountRetriever<AccountInfoRef<'a, 'info>>> {
|
||||
let active_token_len = account.token_iter_active().count();
|
||||
let active_serum3_len = account.serum3_iter_active().count();
|
||||
let active_perp_len = account.perp_iter_active_accounts().count();
|
||||
let active_token_len = account.active_token_positions().count();
|
||||
let active_serum3_len = account.active_serum3_orders().count();
|
||||
let active_perp_len = account.active_perp_positions().count();
|
||||
let expected_ais = cm!(active_token_len * 2 // banks + oracles
|
||||
+ active_perp_len // PerpMarkets
|
||||
+ active_serum3_len); // open_orders
|
||||
|
@ -787,7 +787,7 @@ pub fn new_health_cache(
|
|||
// token contribution from token accounts
|
||||
let mut token_infos = vec![];
|
||||
|
||||
for (i, position) in account.token_iter_active().enumerate() {
|
||||
for (i, position) in account.active_token_positions().enumerate() {
|
||||
let (bank, oracle_price) =
|
||||
retriever.bank_and_oracle(&account.fixed.group, i, position.token_index)?;
|
||||
|
||||
|
@ -810,7 +810,7 @@ pub fn new_health_cache(
|
|||
// Fill the TokenInfo balance with free funds in serum3 oo accounts, and fill
|
||||
// the serum3_max_reserved with their reserved funds. Also build Serum3Infos.
|
||||
let mut serum3_infos = vec![];
|
||||
for (i, serum_account) in account.serum3_iter_active().enumerate() {
|
||||
for (i, serum_account) in account.active_serum3_orders().enumerate() {
|
||||
let oo = retriever.serum_oo(i, &serum_account.open_orders)?;
|
||||
|
||||
// find the TokenInfos for the market's base and quote tokens
|
||||
|
@ -847,8 +847,8 @@ pub fn new_health_cache(
|
|||
|
||||
// TODO: also account for perp funding in health
|
||||
// health contribution from perp accounts
|
||||
let mut perp_infos = Vec::with_capacity(account.perp_iter_active_accounts().count());
|
||||
for (i, perp_account) in account.perp_iter_active_accounts().enumerate() {
|
||||
let mut perp_infos = Vec::with_capacity(account.active_perp_positions().count());
|
||||
for (i, perp_account) in account.active_perp_positions().enumerate() {
|
||||
let perp_market =
|
||||
retriever.perp_market(&account.fixed.group, i, perp_account.market_index)?;
|
||||
|
||||
|
@ -1074,20 +1074,20 @@ mod tests {
|
|||
bank1
|
||||
.data()
|
||||
.deposit(
|
||||
account.token_get_mut_or_create(1).unwrap().0,
|
||||
account.ensure_token_position(1).unwrap().0,
|
||||
I80F48::from(100),
|
||||
)
|
||||
.unwrap();
|
||||
bank2
|
||||
.data()
|
||||
.withdraw_without_fee(
|
||||
account.token_get_mut_or_create(4).unwrap().0,
|
||||
account.ensure_token_position(4).unwrap().0,
|
||||
I80F48::from(10),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut oo1 = TestAccount::<OpenOrders>::new_zeroed();
|
||||
let serum3account = account.serum3_create(2).unwrap();
|
||||
let serum3account = account.create_serum3_orders(2).unwrap();
|
||||
serum3account.open_orders = oo1.pubkey;
|
||||
serum3account.base_token_index = 4;
|
||||
serum3account.quote_token_index = 1;
|
||||
|
@ -1107,7 +1107,7 @@ mod tests {
|
|||
perp1.data().maint_liab_weight = I80F48::from_num(1.0 + 0.1f64);
|
||||
perp1.data().quote_lot_size = 100;
|
||||
perp1.data().base_lot_size = 10;
|
||||
let perpaccount = account.perp_get_account_mut_or_create(9).unwrap().0;
|
||||
let perpaccount = account.ensure_perp_position(9).unwrap().0;
|
||||
perpaccount.base_position_lots = 3;
|
||||
perpaccount.quote_position_native = -I80F48::from(310u16);
|
||||
perpaccount.bids_base_lots = 7;
|
||||
|
@ -1254,27 +1254,27 @@ mod tests {
|
|||
bank1
|
||||
.data()
|
||||
.change_without_fee(
|
||||
account.token_get_mut_or_create(1).unwrap().0,
|
||||
account.ensure_token_position(1).unwrap().0,
|
||||
I80F48::from(testcase.token1),
|
||||
)
|
||||
.unwrap();
|
||||
bank2
|
||||
.data()
|
||||
.change_without_fee(
|
||||
account.token_get_mut_or_create(4).unwrap().0,
|
||||
account.ensure_token_position(4).unwrap().0,
|
||||
I80F48::from(testcase.token2),
|
||||
)
|
||||
.unwrap();
|
||||
bank3
|
||||
.data()
|
||||
.change_without_fee(
|
||||
account.token_get_mut_or_create(5).unwrap().0,
|
||||
account.ensure_token_position(5).unwrap().0,
|
||||
I80F48::from(testcase.token3),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut oo1 = TestAccount::<OpenOrders>::new_zeroed();
|
||||
let serum3account1 = account.serum3_create(2).unwrap();
|
||||
let serum3account1 = account.create_serum3_orders(2).unwrap();
|
||||
serum3account1.open_orders = oo1.pubkey;
|
||||
serum3account1.base_token_index = 4;
|
||||
serum3account1.quote_token_index = 1;
|
||||
|
@ -1282,7 +1282,7 @@ mod tests {
|
|||
oo1.data().native_coin_total = testcase.oo_1_2.1;
|
||||
|
||||
let mut oo2 = TestAccount::<OpenOrders>::new_zeroed();
|
||||
let serum3account2 = account.serum3_create(3).unwrap();
|
||||
let serum3account2 = account.create_serum3_orders(3).unwrap();
|
||||
serum3account2.open_orders = oo2.pubkey;
|
||||
serum3account2.base_token_index = 5;
|
||||
serum3account2.quote_token_index = 1;
|
||||
|
@ -1299,7 +1299,7 @@ mod tests {
|
|||
perp1.data().maint_liab_weight = I80F48::from_num(1.0 + 0.1f64);
|
||||
perp1.data().quote_lot_size = 100;
|
||||
perp1.data().base_lot_size = 10;
|
||||
let perpaccount = account.perp_get_account_mut_or_create(9).unwrap().0;
|
||||
let perpaccount = account.ensure_perp_position(9).unwrap().0;
|
||||
perpaccount.base_position_lots = testcase.perp1.0;
|
||||
perpaccount.quote_position_native = I80F48::from(testcase.perp1.1);
|
||||
perpaccount.bids_base_lots = testcase.perp1.2;
|
||||
|
|
|
@ -22,7 +22,7 @@ use super::Serum3MarketIndex;
|
|||
use super::Side;
|
||||
use super::TokenIndex;
|
||||
use super::FREE_ORDER_SLOT;
|
||||
use super::{PerpPositions, Serum3Orders, TokenPosition};
|
||||
use super::{PerpPosition, Serum3Orders, TokenPosition};
|
||||
use checked_math as cm;
|
||||
|
||||
type BorshVecLength = u32;
|
||||
|
@ -87,7 +87,7 @@ pub struct MangoAccount {
|
|||
// that is active on this MangoAccount.
|
||||
pub serum3: Vec<Serum3Orders>,
|
||||
pub padding6: u32,
|
||||
pub perps: Vec<PerpPositions>,
|
||||
pub perps: Vec<PerpPosition>,
|
||||
pub padding7: u32,
|
||||
pub perp_open_orders: Vec<PerpOpenOrders>,
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ impl Default for MangoAccount {
|
|||
padding5: Default::default(),
|
||||
serum3: vec![Serum3Orders::default(); 5],
|
||||
padding6: Default::default(),
|
||||
perps: vec![PerpPositions::default(); 2],
|
||||
perps: vec![PerpPosition::default(); 2],
|
||||
padding7: Default::default(),
|
||||
perp_open_orders: vec![PerpOpenOrders::default(); 2],
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ impl MangoAccount {
|
|||
|
||||
pub fn dynamic_perp_oo_vec_offset(token_count: u8, serum3_count: u8, perp_count: u8) -> usize {
|
||||
Self::dynamic_perp_vec_offset(token_count, serum3_count)
|
||||
+ (BORSH_VEC_SIZE_BYTES + size_of::<PerpPositions>() * usize::from(perp_count))
|
||||
+ (BORSH_VEC_SIZE_BYTES + size_of::<PerpPosition>() * usize::from(perp_count))
|
||||
+ BORSH_VEC_PADDING_BYTES
|
||||
}
|
||||
|
||||
|
@ -185,8 +185,7 @@ fn test_serialization_match() {
|
|||
account.tokens.resize(8, TokenPosition::default());
|
||||
account.tokens[0].token_index = 5;
|
||||
account.serum3.resize(8, Serum3Orders::default());
|
||||
account.serum3[0].open_orders = Pubkey::new_unique();
|
||||
account.perps.resize(8, PerpPositions::default());
|
||||
account.perps.resize(8, PerpPosition::default());
|
||||
account.perps[0].market_index = 6;
|
||||
account
|
||||
.perp_open_orders
|
||||
|
@ -209,15 +208,15 @@ fn test_serialization_match() {
|
|||
assert_eq!(account.net_settled, account2.fixed.net_settled);
|
||||
assert_eq!(
|
||||
account.tokens[0].token_index,
|
||||
account2.token_get_raw(0).token_index
|
||||
account2.token_position_by_raw_index(0).token_index
|
||||
);
|
||||
assert_eq!(
|
||||
account.serum3[0].open_orders,
|
||||
account2.serum3_get_raw(0).open_orders
|
||||
account2.serum3_orders_by_raw_index(0).open_orders
|
||||
);
|
||||
assert_eq!(
|
||||
account.perps[0].market_index,
|
||||
account2.perp_get_raw(0).market_index
|
||||
account2.perp_position_by_raw_index(0).market_index
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -362,11 +361,11 @@ impl MangoAccountDynamicHeader {
|
|||
+ raw_index * size_of::<Serum3Orders>()
|
||||
}
|
||||
|
||||
// offset into dynamic data where 1st PerpPositions would be found
|
||||
// offset into dynamic data where 1st PerpPosition would be found
|
||||
fn perp_offset(&self, raw_index: usize) -> usize {
|
||||
MangoAccount::dynamic_perp_vec_offset(self.token_count, self.serum3_count)
|
||||
+ BORSH_VEC_SIZE_BYTES
|
||||
+ raw_index * size_of::<PerpPositions>()
|
||||
+ raw_index * size_of::<PerpPosition>()
|
||||
}
|
||||
|
||||
fn perp_oo_offset(&self, raw_index: usize) -> usize {
|
||||
|
@ -449,85 +448,85 @@ impl<
|
|||
/// Returns
|
||||
/// - the position
|
||||
/// - the raw index into the token positions list (for use with get_raw/deactivate)
|
||||
pub fn token_get(&self, token_index: TokenIndex) -> Result<(&TokenPosition, usize)> {
|
||||
self.token_iter()
|
||||
pub fn token_position_and_raw_index(
|
||||
&self,
|
||||
token_index: TokenIndex,
|
||||
) -> Result<(&TokenPosition, usize)> {
|
||||
self.all_token_positions()
|
||||
.enumerate()
|
||||
.find_map(|(raw_index, p)| p.is_active_for_token(token_index).then(|| (p, raw_index)))
|
||||
.ok_or_else(|| error_msg!("position for token index {} not found", token_index))
|
||||
}
|
||||
|
||||
// get TokenPosition at raw_index
|
||||
pub fn token_get_raw(&self, raw_index: usize) -> &TokenPosition {
|
||||
pub fn token_position(&self, token_index: TokenIndex) -> Result<&TokenPosition> {
|
||||
self.token_position_and_raw_index(token_index)
|
||||
.map(|(p, _)| p)
|
||||
}
|
||||
|
||||
pub fn token_position_by_raw_index(&self, raw_index: usize) -> &TokenPosition {
|
||||
get_helper(self.dynamic(), self.header().token_offset(raw_index))
|
||||
}
|
||||
|
||||
// get iter over all TokenPositions (including inactive)
|
||||
pub fn token_iter(&self) -> impl Iterator<Item = &TokenPosition> + '_ {
|
||||
(0..self.header().token_count()).map(|i| self.token_get_raw(i))
|
||||
pub fn all_token_positions(&self) -> impl Iterator<Item = &TokenPosition> + '_ {
|
||||
(0..self.header().token_count()).map(|i| self.token_position_by_raw_index(i))
|
||||
}
|
||||
|
||||
// get iter over all active TokenPositions
|
||||
pub fn token_iter_active(&self) -> impl Iterator<Item = &TokenPosition> + '_ {
|
||||
pub fn active_token_positions(&self) -> impl Iterator<Item = &TokenPosition> + '_ {
|
||||
(0..self.header().token_count())
|
||||
.map(|i| self.token_get_raw(i))
|
||||
.map(|i| self.token_position_by_raw_index(i))
|
||||
.filter(|token| token.is_active())
|
||||
}
|
||||
|
||||
pub fn token_find(&self, token_index: TokenIndex) -> Option<&TokenPosition> {
|
||||
self.token_iter_active()
|
||||
.find(|p| p.is_active_for_token(token_index))
|
||||
pub fn serum3_orders(&self, market_index: Serum3MarketIndex) -> Option<&Serum3Orders> {
|
||||
self.active_serum3_orders()
|
||||
.find(|p| p.is_active_for_market(market_index))
|
||||
}
|
||||
|
||||
// get Serum3Orders at raw_index
|
||||
pub fn serum3_get_raw(&self, raw_index: usize) -> &Serum3Orders {
|
||||
pub fn serum3_orders_by_raw_index(&self, raw_index: usize) -> &Serum3Orders {
|
||||
get_helper(self.dynamic(), self.header().serum3_offset(raw_index))
|
||||
}
|
||||
|
||||
pub fn serum3_iter(&self) -> impl Iterator<Item = &Serum3Orders> + '_ {
|
||||
(0..self.header().serum3_count()).map(|i| self.serum3_get_raw(i))
|
||||
pub fn all_serum3_orders(&self) -> impl Iterator<Item = &Serum3Orders> + '_ {
|
||||
(0..self.header().serum3_count()).map(|i| self.serum3_orders_by_raw_index(i))
|
||||
}
|
||||
|
||||
pub fn serum3_iter_active(&self) -> impl Iterator<Item = &Serum3Orders> + '_ {
|
||||
pub fn active_serum3_orders(&self) -> impl Iterator<Item = &Serum3Orders> + '_ {
|
||||
(0..self.header().serum3_count())
|
||||
.map(|i| self.serum3_get_raw(i))
|
||||
.map(|i| self.serum3_orders_by_raw_index(i))
|
||||
.filter(|serum3_order| serum3_order.is_active())
|
||||
}
|
||||
|
||||
pub fn serum3_find(&self, market_index: Serum3MarketIndex) -> Option<&Serum3Orders> {
|
||||
self.serum3_iter_active()
|
||||
pub fn perp_position(&self, market_index: PerpMarketIndex) -> Option<&PerpPosition> {
|
||||
self.active_perp_positions()
|
||||
.find(|p| p.is_active_for_market(market_index))
|
||||
}
|
||||
|
||||
// get PerpPosition at raw_index
|
||||
pub fn perp_get_raw(&self, raw_index: usize) -> &PerpPositions {
|
||||
pub fn perp_position_by_raw_index(&self, raw_index: usize) -> &PerpPosition {
|
||||
get_helper(self.dynamic(), self.header().perp_offset(raw_index))
|
||||
}
|
||||
|
||||
pub fn perp_iter(&self) -> impl Iterator<Item = &PerpPositions> {
|
||||
(0..self.header().perp_count()).map(|i| self.perp_get_raw(i))
|
||||
pub fn all_perp_positions(&self) -> impl Iterator<Item = &PerpPosition> {
|
||||
(0..self.header().perp_count()).map(|i| self.perp_position_by_raw_index(i))
|
||||
}
|
||||
|
||||
pub fn perp_iter_active_accounts(&self) -> impl Iterator<Item = &PerpPositions> {
|
||||
pub fn active_perp_positions(&self) -> impl Iterator<Item = &PerpPosition> {
|
||||
(0..self.header().perp_count())
|
||||
.map(|i| self.perp_get_raw(i))
|
||||
.map(|i| self.perp_position_by_raw_index(i))
|
||||
.filter(|p| p.is_active())
|
||||
}
|
||||
|
||||
pub fn perp_find_account(&self, market_index: PerpMarketIndex) -> Option<&PerpPositions> {
|
||||
self.perp_iter_active_accounts()
|
||||
.find(|p| p.is_active_for_market(market_index))
|
||||
}
|
||||
|
||||
pub fn perp_oo_get_raw(&self, raw_index: usize) -> &PerpOpenOrders {
|
||||
pub fn perp_orders_by_raw_index(&self, raw_index: usize) -> &PerpOpenOrders {
|
||||
get_helper(self.dynamic(), self.header().perp_oo_offset(raw_index))
|
||||
}
|
||||
|
||||
pub fn perp_oo_iter(&self) -> impl Iterator<Item = &PerpOpenOrders> {
|
||||
(0..self.header().perp_oo_count()).map(|i| self.perp_oo_get_raw(i))
|
||||
pub fn all_perp_orders(&self) -> impl Iterator<Item = &PerpOpenOrders> {
|
||||
(0..self.header().perp_oo_count()).map(|i| self.perp_orders_by_raw_index(i))
|
||||
}
|
||||
|
||||
pub fn perp_next_order_slot(&self) -> Option<usize> {
|
||||
self.perp_oo_iter()
|
||||
self.all_perp_orders()
|
||||
.position(|&oo| oo.order_market == FREE_ORDER_SLOT)
|
||||
}
|
||||
|
||||
|
@ -537,7 +536,7 @@ impl<
|
|||
client_order_id: u64,
|
||||
) -> Option<(i128, Side)> {
|
||||
for i in 0..self.header().perp_oo_count() {
|
||||
let oo = self.perp_oo_get_raw(i);
|
||||
let oo = self.perp_orders_by_raw_index(i);
|
||||
if oo.order_market == market_index && oo.client_order_id == client_order_id {
|
||||
return Some((oo.order_id, oo.order_side));
|
||||
}
|
||||
|
@ -551,7 +550,7 @@ impl<
|
|||
order_id: i128,
|
||||
) -> Option<Side> {
|
||||
for i in 0..self.header().perp_oo_count() {
|
||||
let oo = self.perp_oo_get_raw(i);
|
||||
let oo = self.perp_orders_by_raw_index(i);
|
||||
if oo.order_market == market_index && oo.order_id == order_id {
|
||||
return Some(oo.order_side);
|
||||
}
|
||||
|
@ -596,20 +595,20 @@ impl<
|
|||
/// Returns
|
||||
/// - the position
|
||||
/// - the raw index into the token positions list (for use with get_raw/deactivate)
|
||||
pub fn token_get_mut(
|
||||
pub fn token_position_mut(
|
||||
&mut self,
|
||||
token_index: TokenIndex,
|
||||
) -> Result<(&mut TokenPosition, usize)> {
|
||||
let raw_index = self
|
||||
.token_iter()
|
||||
.all_token_positions()
|
||||
.enumerate()
|
||||
.find_map(|(raw_index, p)| p.is_active_for_token(token_index).then(|| raw_index))
|
||||
.ok_or_else(|| error_msg!("position for token index {} not found", token_index))?;
|
||||
Ok((self.token_get_mut_raw(raw_index), raw_index))
|
||||
Ok((self.token_position_mut_by_raw_index(raw_index), raw_index))
|
||||
}
|
||||
|
||||
// get mut TokenPosition at raw_index
|
||||
pub fn token_get_mut_raw(&mut self, raw_index: usize) -> &mut TokenPosition {
|
||||
pub fn token_position_mut_by_raw_index(&mut self, raw_index: usize) -> &mut TokenPosition {
|
||||
let offset = self.header().token_offset(raw_index);
|
||||
get_helper_mut(self.dynamic_mut(), offset)
|
||||
}
|
||||
|
@ -619,13 +618,13 @@ impl<
|
|||
/// - the position
|
||||
/// - the raw index into the token positions list (for use with get_raw)
|
||||
/// - the active index, for use with FixedOrderAccountRetriever
|
||||
pub fn token_get_mut_or_create(
|
||||
pub fn ensure_token_position(
|
||||
&mut self,
|
||||
token_index: TokenIndex,
|
||||
) -> Result<(&mut TokenPosition, usize, usize)> {
|
||||
let mut active_index = 0;
|
||||
let mut match_or_free = None;
|
||||
for (raw_index, position) in self.token_iter().enumerate() {
|
||||
for (raw_index, position) in self.all_token_positions().enumerate() {
|
||||
if position.is_active_for_token(token_index) {
|
||||
// Can't return early because of lifetimes
|
||||
match_or_free = Some((raw_index, active_index));
|
||||
|
@ -638,7 +637,7 @@ impl<
|
|||
}
|
||||
}
|
||||
if let Some((raw_index, bank_index)) = match_or_free {
|
||||
let v = self.token_get_mut_raw(raw_index);
|
||||
let v = self.token_position_mut_by_raw_index(raw_index);
|
||||
if !v.is_active_for_token(token_index) {
|
||||
*v = TokenPosition {
|
||||
indexed_position: I80F48::ZERO,
|
||||
|
@ -655,101 +654,101 @@ impl<
|
|||
}
|
||||
}
|
||||
|
||||
pub fn token_deactivate(&mut self, raw_index: usize) {
|
||||
assert!(self.token_get_mut_raw(raw_index).in_use_count == 0);
|
||||
self.token_get_mut_raw(raw_index).token_index = TokenIndex::MAX;
|
||||
pub fn deactivate_token_position(&mut self, raw_index: usize) {
|
||||
assert!(self.token_position_mut_by_raw_index(raw_index).in_use_count == 0);
|
||||
self.token_position_mut_by_raw_index(raw_index).token_index = TokenIndex::MAX;
|
||||
}
|
||||
|
||||
// get mut Serum3Orders at raw_index
|
||||
pub fn serum3_get_mut_raw(&mut self, raw_index: usize) -> &mut Serum3Orders {
|
||||
pub fn serum3_orders_mut_by_raw_index(&mut self, raw_index: usize) -> &mut Serum3Orders {
|
||||
let offset = self.header().serum3_offset(raw_index);
|
||||
get_helper_mut(self.dynamic_mut(), offset)
|
||||
}
|
||||
|
||||
pub fn serum3_create(&mut self, market_index: Serum3MarketIndex) -> Result<&mut Serum3Orders> {
|
||||
if self.serum3_find(market_index).is_some() {
|
||||
pub fn create_serum3_orders(
|
||||
&mut self,
|
||||
market_index: Serum3MarketIndex,
|
||||
) -> Result<&mut Serum3Orders> {
|
||||
if self.serum3_orders(market_index).is_some() {
|
||||
return err!(MangoError::Serum3OpenOrdersExistAlready);
|
||||
}
|
||||
|
||||
let raw_index_opt = self.serum3_iter().position(|p| !p.is_active());
|
||||
let raw_index_opt = self.all_serum3_orders().position(|p| !p.is_active());
|
||||
if let Some(raw_index) = raw_index_opt {
|
||||
*(self.serum3_get_mut_raw(raw_index)) = Serum3Orders {
|
||||
*(self.serum3_orders_mut_by_raw_index(raw_index)) = Serum3Orders {
|
||||
market_index: market_index as Serum3MarketIndex,
|
||||
..Serum3Orders::default()
|
||||
};
|
||||
return Ok(self.serum3_get_mut_raw(raw_index));
|
||||
return Ok(self.serum3_orders_mut_by_raw_index(raw_index));
|
||||
} else {
|
||||
return err!(MangoError::NoFreeSerum3OpenOrdersIndex);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serum3_deactivate(&mut self, market_index: Serum3MarketIndex) -> Result<()> {
|
||||
pub fn deactivate_serum3_orders(&mut self, market_index: Serum3MarketIndex) -> Result<()> {
|
||||
let raw_index = self
|
||||
.serum3_iter()
|
||||
.all_serum3_orders()
|
||||
.position(|p| p.is_active_for_market(market_index))
|
||||
.ok_or_else(|| error_msg!("serum3 open orders index {} not found", market_index))?;
|
||||
self.serum3_get_mut_raw(raw_index).market_index = Serum3MarketIndex::MAX;
|
||||
self.serum3_orders_mut_by_raw_index(raw_index).market_index = Serum3MarketIndex::MAX;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn serum3_find_mut(
|
||||
pub fn serum3_orders_mut(
|
||||
&mut self,
|
||||
market_index: Serum3MarketIndex,
|
||||
) -> Option<&mut Serum3Orders> {
|
||||
let raw_index_opt = self
|
||||
.serum3_iter_active()
|
||||
.active_serum3_orders()
|
||||
.position(|p| p.is_active_for_market(market_index));
|
||||
raw_index_opt.map(|raw_index| self.serum3_get_mut_raw(raw_index))
|
||||
raw_index_opt.map(|raw_index| self.serum3_orders_mut_by_raw_index(raw_index))
|
||||
}
|
||||
|
||||
// get mut PerpPosition at raw_index
|
||||
pub fn perp_get_mut_raw(&mut self, raw_index: usize) -> &mut PerpPositions {
|
||||
pub fn perp_position_mut_by_raw_index(&mut self, raw_index: usize) -> &mut PerpPosition {
|
||||
let offset = self.header().perp_offset(raw_index);
|
||||
get_helper_mut(self.dynamic_mut(), offset)
|
||||
}
|
||||
|
||||
pub fn perp_oo_get_mut_raw(&mut self, raw_index: usize) -> &mut PerpOpenOrders {
|
||||
pub fn perp_orders_mut_by_raw_index(&mut self, raw_index: usize) -> &mut PerpOpenOrders {
|
||||
let offset = self.header().perp_oo_offset(raw_index);
|
||||
get_helper_mut(self.dynamic_mut(), offset)
|
||||
}
|
||||
|
||||
pub fn perp_get_account_mut_or_create(
|
||||
pub fn ensure_perp_position(
|
||||
&mut self,
|
||||
perp_market_index: PerpMarketIndex,
|
||||
) -> Result<(&mut PerpPositions, usize)> {
|
||||
) -> Result<(&mut PerpPosition, usize)> {
|
||||
let mut raw_index_opt = self
|
||||
.perp_iter_active_accounts()
|
||||
.active_perp_positions()
|
||||
.position(|p| p.is_active_for_market(perp_market_index));
|
||||
if raw_index_opt.is_none() {
|
||||
raw_index_opt = self.perp_iter().position(|p| !p.is_active());
|
||||
raw_index_opt = self.all_perp_positions().position(|p| !p.is_active());
|
||||
if let Some(raw_index) = raw_index_opt {
|
||||
*(self.perp_get_mut_raw(raw_index)) = PerpPositions {
|
||||
*(self.perp_position_mut_by_raw_index(raw_index)) = PerpPosition {
|
||||
market_index: perp_market_index,
|
||||
..Default::default()
|
||||
};
|
||||
}
|
||||
}
|
||||
if let Some(raw_index) = raw_index_opt {
|
||||
Ok((self.perp_get_mut_raw(raw_index), raw_index))
|
||||
Ok((self.perp_position_mut_by_raw_index(raw_index), raw_index))
|
||||
} else {
|
||||
err!(MangoError::NoFreePerpPositionIndex)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn perp_deactivate_account(&mut self, raw_index: usize) {
|
||||
self.perp_get_mut_raw(raw_index).market_index = PerpMarketIndex::MAX;
|
||||
pub fn deactivate_perp_position(&mut self, raw_index: usize) {
|
||||
self.perp_position_mut_by_raw_index(raw_index).market_index = PerpMarketIndex::MAX;
|
||||
}
|
||||
|
||||
pub fn perp_add_order(
|
||||
pub fn add_perp_order(
|
||||
&mut self,
|
||||
perp_market_index: PerpMarketIndex,
|
||||
side: Side,
|
||||
order: &LeafNode,
|
||||
) -> Result<()> {
|
||||
let mut perp_account = self
|
||||
.perp_get_account_mut_or_create(perp_market_index)
|
||||
.unwrap()
|
||||
.0;
|
||||
let mut perp_account = self.ensure_perp_position(perp_market_index).unwrap().0;
|
||||
match side {
|
||||
Side::Bid => {
|
||||
perp_account.bids_base_lots = cm!(perp_account.bids_base_lots + order.quantity);
|
||||
|
@ -760,7 +759,7 @@ impl<
|
|||
};
|
||||
let slot = order.owner_slot as usize;
|
||||
|
||||
let mut oo = self.perp_oo_get_mut_raw(slot);
|
||||
let mut oo = self.perp_orders_mut_by_raw_index(slot);
|
||||
oo.order_market = perp_market_index;
|
||||
oo.order_side = side;
|
||||
oo.order_id = order.key;
|
||||
|
@ -768,16 +767,13 @@ impl<
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn perp_remove_order(&mut self, slot: usize, quantity: i64) -> Result<()> {
|
||||
pub fn remove_perp_order(&mut self, slot: usize, quantity: i64) -> Result<()> {
|
||||
{
|
||||
let oo = self.perp_oo_get_mut_raw(slot);
|
||||
let oo = self.perp_orders_mut_by_raw_index(slot);
|
||||
require_neq!(oo.order_market, FREE_ORDER_SLOT);
|
||||
let order_side = oo.order_side;
|
||||
let perp_market_index = oo.order_market;
|
||||
let perp_account = self
|
||||
.perp_get_account_mut_or_create(perp_market_index)
|
||||
.unwrap()
|
||||
.0;
|
||||
let perp_account = self.ensure_perp_position(perp_market_index).unwrap().0;
|
||||
|
||||
// accounting
|
||||
match order_side {
|
||||
|
@ -791,7 +787,7 @@ impl<
|
|||
}
|
||||
|
||||
// release space
|
||||
let oo = self.perp_oo_get_mut_raw(slot);
|
||||
let oo = self.perp_orders_mut_by_raw_index(slot);
|
||||
oo.order_market = FREE_ORDER_SLOT;
|
||||
oo.order_side = Side::Bid;
|
||||
oo.order_id = 0i128;
|
||||
|
@ -799,16 +795,13 @@ impl<
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn perp_execute_maker(
|
||||
pub fn execute_perp_maker(
|
||||
&mut self,
|
||||
perp_market_index: PerpMarketIndex,
|
||||
perp_market: &mut PerpMarket,
|
||||
fill: &FillEvent,
|
||||
) -> Result<()> {
|
||||
let pa = self
|
||||
.perp_get_account_mut_or_create(perp_market_index)
|
||||
.unwrap()
|
||||
.0;
|
||||
let pa = self.ensure_perp_position(perp_market_index).unwrap().0;
|
||||
pa.settle_funding(perp_market);
|
||||
|
||||
let side = fill.taker_side.invert_side();
|
||||
|
@ -827,7 +820,7 @@ impl<
|
|||
pa.quote_position_native = pa.quote_position_native.checked_add(quote - fees).unwrap();
|
||||
|
||||
if fill.maker_out {
|
||||
self.perp_remove_order(fill.maker_slot as usize, base_change.abs())
|
||||
self.remove_perp_order(fill.maker_slot as usize, base_change.abs())
|
||||
} else {
|
||||
match side {
|
||||
Side::Bid => {
|
||||
|
@ -841,16 +834,13 @@ impl<
|
|||
}
|
||||
}
|
||||
|
||||
pub fn perp_execute_taker(
|
||||
pub fn execute_perp_taker(
|
||||
&mut self,
|
||||
perp_market_index: PerpMarketIndex,
|
||||
perp_market: &mut PerpMarket,
|
||||
fill: &FillEvent,
|
||||
) -> Result<()> {
|
||||
let pa = self
|
||||
.perp_get_account_mut_or_create(perp_market_index)
|
||||
.unwrap()
|
||||
.0;
|
||||
let pa = self.ensure_perp_position(perp_market_index).unwrap().0;
|
||||
pa.settle_funding(perp_market);
|
||||
|
||||
let (base_change, quote_change) = fill.base_quote_change(fill.taker_side);
|
||||
|
@ -959,12 +949,12 @@ impl<
|
|||
sol_memmove(
|
||||
&mut dynamic[new_header.perp_offset(0)],
|
||||
&mut dynamic[old_header.perp_offset(0)],
|
||||
size_of::<PerpPositions>() * old_header.perp_count(),
|
||||
size_of::<PerpPosition>() * old_header.perp_count(),
|
||||
);
|
||||
}
|
||||
for i in old_header.perp_count..new_perp_count {
|
||||
*get_helper_mut(dynamic, new_header.perp_offset(i.into())) =
|
||||
PerpPositions::default();
|
||||
PerpPosition::default();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -147,7 +147,7 @@ impl Default for Serum3Orders {
|
|||
#[zero_copy]
|
||||
#[derive(AnchorSerialize, AnchorDeserialize, Derivative)]
|
||||
#[derivative(Debug)]
|
||||
pub struct PerpPositions {
|
||||
pub struct PerpPosition {
|
||||
pub market_index: PerpMarketIndex,
|
||||
#[derivative(Debug = "ignore")]
|
||||
pub padding: [u8; 6],
|
||||
|
@ -181,13 +181,13 @@ pub struct PerpPositions {
|
|||
#[derivative(Debug = "ignore")]
|
||||
pub reserved: [u8; 64],
|
||||
}
|
||||
const_assert_eq!(size_of::<PerpPositions>(), 8 + 7 * 8 + 3 * 16 + 64);
|
||||
const_assert_eq!(size_of::<PerpPositions>() % 8, 0);
|
||||
const_assert_eq!(size_of::<PerpPosition>(), 8 + 7 * 8 + 3 * 16 + 64);
|
||||
const_assert_eq!(size_of::<PerpPosition>() % 8, 0);
|
||||
|
||||
unsafe impl bytemuck::Pod for PerpPositions {}
|
||||
unsafe impl bytemuck::Zeroable for PerpPositions {}
|
||||
unsafe impl bytemuck::Pod for PerpPosition {}
|
||||
unsafe impl bytemuck::Zeroable for PerpPosition {}
|
||||
|
||||
impl Default for PerpPositions {
|
||||
impl Default for PerpPosition {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
market_index: PerpMarketIndex::MAX,
|
||||
|
@ -207,7 +207,7 @@ impl Default for PerpPositions {
|
|||
}
|
||||
}
|
||||
|
||||
impl PerpPositions {
|
||||
impl PerpPosition {
|
||||
/// Add taker trade after it has been matched but before it has been process on EventQueue
|
||||
pub fn add_taker_trade(&mut self, side: Side, base_lots: i64, quote_lots: i64) {
|
||||
match side {
|
||||
|
@ -373,10 +373,10 @@ mod tests {
|
|||
use fixed::types::I80F48;
|
||||
use rand::Rng;
|
||||
|
||||
use super::PerpPositions;
|
||||
use super::PerpPosition;
|
||||
|
||||
fn create_perp_position(base_pos: i64, quote_pos: i64, entry_pos: i64) -> PerpPositions {
|
||||
let mut pos = PerpPositions::default();
|
||||
fn create_perp_position(base_pos: i64, quote_pos: i64, entry_pos: i64) -> PerpPosition {
|
||||
let mut pos = PerpPosition::default();
|
||||
pos.base_position_lots = base_pos;
|
||||
pos.quote_position_native = I80F48::from(quote_pos);
|
||||
pos.quote_entry_native = entry_pos;
|
||||
|
|
|
@ -265,7 +265,7 @@ impl<'a> Book<'a> {
|
|||
// Record the taker trade in the account already, even though it will only be
|
||||
// realized when the fill event gets executed
|
||||
let perp_account = mango_account
|
||||
.perp_get_account_mut_or_create(market.perp_market_index)?
|
||||
.ensure_perp_position(market.perp_market_index)?
|
||||
.0;
|
||||
perp_account.add_taker_trade(side, match_base_lots, match_quote_lots);
|
||||
|
||||
|
@ -373,7 +373,7 @@ impl<'a> Book<'a> {
|
|||
price_lots
|
||||
);
|
||||
|
||||
mango_account.perp_add_order(market.perp_market_index, side, &new_order)?;
|
||||
mango_account.add_perp_order(market.perp_market_index, side, &new_order)?;
|
||||
}
|
||||
|
||||
// if there were matched taker quote apply ref fees
|
||||
|
@ -393,7 +393,7 @@ impl<'a> Book<'a> {
|
|||
side_to_cancel_option: Option<Side>,
|
||||
) -> Result<()> {
|
||||
for i in 0..mango_account.header.perp_oo_count() {
|
||||
let oo = mango_account.perp_oo_get_raw(i);
|
||||
let oo = mango_account.perp_orders_by_raw_index(i);
|
||||
if oo.order_market == FREE_ORDER_SLOT
|
||||
|| oo.order_market != perp_market.perp_market_index
|
||||
{
|
||||
|
@ -411,7 +411,7 @@ impl<'a> Book<'a> {
|
|||
|
||||
if let Ok(leaf_node) = self.cancel_order(order_id, order_side) {
|
||||
mango_account
|
||||
.perp_remove_order(leaf_node.owner_slot as usize, leaf_node.quantity)?
|
||||
.remove_perp_order(leaf_node.owner_slot as usize, leaf_node.quantity)?
|
||||
};
|
||||
|
||||
limit -= 1;
|
||||
|
@ -459,7 +459,7 @@ fn apply_fees(
|
|||
|
||||
let taker_fees = taker_quote_native * market.taker_fee;
|
||||
let perp_account = mango_account
|
||||
.perp_get_account_mut_or_create(market.perp_market_index)?
|
||||
.ensure_perp_position(market.perp_market_index)?
|
||||
.0;
|
||||
perp_account.quote_position_native -= taker_fees;
|
||||
market.fees_accrued += taker_fees + maker_fees;
|
||||
|
|
|
@ -124,7 +124,7 @@ mod tests {
|
|||
u8::MAX,
|
||||
)
|
||||
.unwrap();
|
||||
account.perp_oo_get_raw(0).order_id
|
||||
account.perp_orders_by_raw_index(0).order_id
|
||||
};
|
||||
|
||||
// insert bids until book side is full
|
||||
|
@ -225,25 +225,34 @@ mod tests {
|
|||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
maker.perp_oo_get_mut_raw(0).order_market,
|
||||
maker.perp_orders_mut_by_raw_index(0).order_market,
|
||||
market.perp_market_index
|
||||
);
|
||||
assert_eq!(maker.perp_oo_get_mut_raw(1).order_market, FREE_ORDER_SLOT);
|
||||
assert_ne!(maker.perp_oo_get_mut_raw(0).order_id, 0);
|
||||
assert_eq!(maker.perp_oo_get_mut_raw(0).client_order_id, 42);
|
||||
assert_eq!(maker.perp_oo_get_mut_raw(0).order_side, Side::Bid);
|
||||
assert_eq!(
|
||||
maker.perp_orders_mut_by_raw_index(1).order_market,
|
||||
FREE_ORDER_SLOT
|
||||
);
|
||||
assert_ne!(maker.perp_orders_mut_by_raw_index(0).order_id, 0);
|
||||
assert_eq!(maker.perp_orders_mut_by_raw_index(0).client_order_id, 42);
|
||||
assert_eq!(maker.perp_orders_mut_by_raw_index(0).order_side, Side::Bid);
|
||||
assert!(bookside_contains_key(
|
||||
&book.bids,
|
||||
maker.perp_oo_get_mut_raw(0).order_id
|
||||
maker.perp_orders_mut_by_raw_index(0).order_id
|
||||
));
|
||||
assert!(bookside_contains_price(&book.bids, price));
|
||||
assert_eq!(maker.perp_get_raw(0).bids_base_lots, bid_quantity);
|
||||
assert_eq!(maker.perp_get_raw(0).asks_base_lots, 0);
|
||||
assert_eq!(maker.perp_get_raw(0).taker_base_lots, 0);
|
||||
assert_eq!(maker.perp_get_raw(0).taker_quote_lots, 0);
|
||||
assert_eq!(maker.perp_get_raw(0).base_position_lots, 0);
|
||||
assert_eq!(
|
||||
maker.perp_get_raw(0).quote_position_native.to_num::<u32>(),
|
||||
maker.perp_position_by_raw_index(0).bids_base_lots,
|
||||
bid_quantity
|
||||
);
|
||||
assert_eq!(maker.perp_position_by_raw_index(0).asks_base_lots, 0);
|
||||
assert_eq!(maker.perp_position_by_raw_index(0).taker_base_lots, 0);
|
||||
assert_eq!(maker.perp_position_by_raw_index(0).taker_quote_lots, 0);
|
||||
assert_eq!(maker.perp_position_by_raw_index(0).base_position_lots, 0);
|
||||
assert_eq!(
|
||||
maker
|
||||
.perp_position_by_raw_index(0)
|
||||
.quote_position_native
|
||||
.to_num::<u32>(),
|
||||
0
|
||||
);
|
||||
assert_eq!(event_queue.len(), 0);
|
||||
|
@ -269,7 +278,8 @@ mod tests {
|
|||
.unwrap();
|
||||
// the remainder of the maker order is still on the book
|
||||
// (the maker account is unchanged: it was not even passed in)
|
||||
let order = bookside_leaf_by_key(&book.bids, maker.perp_oo_get_raw(0).order_id).unwrap();
|
||||
let order =
|
||||
bookside_leaf_by_key(&book.bids, maker.perp_orders_by_raw_index(0).order_id).unwrap();
|
||||
assert_eq!(order.price(), price);
|
||||
assert_eq!(order.quantity, bid_quantity - match_quantity);
|
||||
|
||||
|
@ -281,17 +291,23 @@ mod tests {
|
|||
);
|
||||
|
||||
// the taker account is updated
|
||||
assert_eq!(taker.perp_oo_get_raw(0).order_market, FREE_ORDER_SLOT);
|
||||
assert_eq!(taker.perp_get_raw(0).bids_base_lots, 0);
|
||||
assert_eq!(taker.perp_get_raw(0).asks_base_lots, 0);
|
||||
assert_eq!(taker.perp_get_raw(0).taker_base_lots, -match_quantity);
|
||||
assert_eq!(
|
||||
taker.perp_get_raw(0).taker_quote_lots,
|
||||
taker.perp_orders_by_raw_index(0).order_market,
|
||||
FREE_ORDER_SLOT
|
||||
);
|
||||
assert_eq!(taker.perp_position_by_raw_index(0).bids_base_lots, 0);
|
||||
assert_eq!(taker.perp_position_by_raw_index(0).asks_base_lots, 0);
|
||||
assert_eq!(
|
||||
taker.perp_position_by_raw_index(0).taker_base_lots,
|
||||
-match_quantity
|
||||
);
|
||||
assert_eq!(
|
||||
taker.perp_position_by_raw_index(0).taker_quote_lots,
|
||||
match_quantity * price
|
||||
);
|
||||
assert_eq!(taker.perp_get_raw(0).base_position_lots, 0);
|
||||
assert_eq!(taker.perp_position_by_raw_index(0).base_position_lots, 0);
|
||||
assert_eq!(
|
||||
taker.perp_get_raw(0).quote_position_native,
|
||||
taker.perp_position_by_raw_index(0).quote_position_native,
|
||||
-match_quote * market.taker_fee
|
||||
);
|
||||
|
||||
|
@ -311,34 +327,40 @@ mod tests {
|
|||
|
||||
// simulate event queue processing
|
||||
maker
|
||||
.perp_execute_maker(market.perp_market_index, &mut market, &fill)
|
||||
.execute_perp_maker(market.perp_market_index, &mut market, &fill)
|
||||
.unwrap();
|
||||
taker
|
||||
.perp_execute_taker(market.perp_market_index, &mut market, &fill)
|
||||
.execute_perp_taker(market.perp_market_index, &mut market, &fill)
|
||||
.unwrap();
|
||||
assert_eq!(market.open_interest, 2 * match_quantity);
|
||||
|
||||
assert_eq!(maker.perp_oo_get_raw(0).order_market, 0);
|
||||
assert_eq!(maker.perp_orders_by_raw_index(0).order_market, 0);
|
||||
assert_eq!(
|
||||
maker.perp_get_raw(0).bids_base_lots,
|
||||
maker.perp_position_by_raw_index(0).bids_base_lots,
|
||||
bid_quantity - match_quantity
|
||||
);
|
||||
assert_eq!(maker.perp_get_raw(0).asks_base_lots, 0);
|
||||
assert_eq!(maker.perp_get_raw(0).taker_base_lots, 0);
|
||||
assert_eq!(maker.perp_get_raw(0).taker_quote_lots, 0);
|
||||
assert_eq!(maker.perp_get_raw(0).base_position_lots, match_quantity);
|
||||
assert_eq!(maker.perp_position_by_raw_index(0).asks_base_lots, 0);
|
||||
assert_eq!(maker.perp_position_by_raw_index(0).taker_base_lots, 0);
|
||||
assert_eq!(maker.perp_position_by_raw_index(0).taker_quote_lots, 0);
|
||||
assert_eq!(
|
||||
maker.perp_get_raw(0).quote_position_native,
|
||||
maker.perp_position_by_raw_index(0).base_position_lots,
|
||||
match_quantity
|
||||
);
|
||||
assert_eq!(
|
||||
maker.perp_position_by_raw_index(0).quote_position_native,
|
||||
-match_quote - match_quote * market.maker_fee
|
||||
);
|
||||
|
||||
assert_eq!(taker.perp_get_raw(0).bids_base_lots, 0);
|
||||
assert_eq!(taker.perp_get_raw(0).asks_base_lots, 0);
|
||||
assert_eq!(taker.perp_get_raw(0).taker_base_lots, 0);
|
||||
assert_eq!(taker.perp_get_raw(0).taker_quote_lots, 0);
|
||||
assert_eq!(taker.perp_get_raw(0).base_position_lots, -match_quantity);
|
||||
assert_eq!(taker.perp_position_by_raw_index(0).bids_base_lots, 0);
|
||||
assert_eq!(taker.perp_position_by_raw_index(0).asks_base_lots, 0);
|
||||
assert_eq!(taker.perp_position_by_raw_index(0).taker_base_lots, 0);
|
||||
assert_eq!(taker.perp_position_by_raw_index(0).taker_quote_lots, 0);
|
||||
assert_eq!(
|
||||
taker.perp_get_raw(0).quote_position_native,
|
||||
taker.perp_position_by_raw_index(0).base_position_lots,
|
||||
-match_quantity
|
||||
);
|
||||
assert_eq!(
|
||||
taker.perp_position_by_raw_index(0).quote_position_native,
|
||||
match_quote - match_quote * market.taker_fee
|
||||
);
|
||||
}
|
||||
|
|
|
@ -181,19 +181,19 @@ async fn derive_health_check_remaining_account_metas(
|
|||
if let Some(affected_bank) = affected_bank {
|
||||
let bank: Bank = account_loader.load(&affected_bank).await.unwrap();
|
||||
adjusted_account
|
||||
.token_get_mut_or_create(bank.token_index)
|
||||
.ensure_token_position(bank.token_index)
|
||||
.unwrap();
|
||||
}
|
||||
if let Some(affected_perp_market_index) = affected_perp_market_index {
|
||||
adjusted_account
|
||||
.perp_get_account_mut_or_create(affected_perp_market_index)
|
||||
.ensure_perp_position(affected_perp_market_index)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// figure out all the banks/oracles that need to be passed for the health check
|
||||
let mut banks = vec![];
|
||||
let mut oracles = vec![];
|
||||
for position in adjusted_account.token_iter_active() {
|
||||
for position in adjusted_account.active_token_positions() {
|
||||
let mint_info =
|
||||
get_mint_info_by_token_index(account_loader, account, position.token_index).await;
|
||||
banks.push(mint_info.first_bank());
|
||||
|
@ -201,10 +201,10 @@ async fn derive_health_check_remaining_account_metas(
|
|||
}
|
||||
|
||||
let perp_markets = adjusted_account
|
||||
.perp_iter_active_accounts()
|
||||
.active_perp_positions()
|
||||
.map(|perp| get_perp_market_address_by_index(account.fixed.group, perp.market_index));
|
||||
|
||||
let serum_oos = account.serum3_iter_active().map(|&s| s.open_orders);
|
||||
let serum_oos = account.active_serum3_orders().map(|&s| s.open_orders);
|
||||
|
||||
let to_account_meta = |pubkey| AccountMeta {
|
||||
pubkey,
|
||||
|
@ -237,8 +237,8 @@ async fn derive_liquidation_remaining_account_metas(
|
|||
let mut banks = vec![];
|
||||
let mut oracles = vec![];
|
||||
let token_indexes = liqee
|
||||
.token_iter_active()
|
||||
.chain(liqor.token_iter_active())
|
||||
.active_token_positions()
|
||||
.chain(liqor.active_token_positions())
|
||||
.map(|ta| ta.token_index)
|
||||
.unique();
|
||||
for token_index in token_indexes {
|
||||
|
@ -255,14 +255,14 @@ async fn derive_liquidation_remaining_account_metas(
|
|||
}
|
||||
|
||||
let perp_markets = liqee
|
||||
.perp_iter_active_accounts()
|
||||
.chain(liqee.perp_iter_active_accounts())
|
||||
.active_perp_positions()
|
||||
.chain(liqee.active_perp_positions())
|
||||
.map(|perp| get_perp_market_address_by_index(liqee.fixed.group, perp.market_index))
|
||||
.unique();
|
||||
|
||||
let serum_oos = liqee
|
||||
.serum3_iter_active()
|
||||
.chain(liqor.serum3_iter_active())
|
||||
.active_serum3_orders()
|
||||
.chain(liqor.active_serum3_orders())
|
||||
.map(|&s| s.open_orders);
|
||||
|
||||
let to_account_meta = |pubkey| AccountMeta {
|
||||
|
@ -297,7 +297,7 @@ pub async fn account_position(solana: &SolanaCookie, account: Pubkey, bank: Pubk
|
|||
let account_data = get_mango_account(solana, account).await;
|
||||
let bank_data: Bank = solana.get_account(bank).await;
|
||||
let native = account_data
|
||||
.token_find(bank_data.token_index)
|
||||
.token_position(bank_data.token_index)
|
||||
.unwrap()
|
||||
.native(&bank_data);
|
||||
native.round().to_num::<i64>()
|
||||
|
@ -306,14 +306,14 @@ pub async fn account_position(solana: &SolanaCookie, account: Pubkey, bank: Pubk
|
|||
pub async fn account_position_closed(solana: &SolanaCookie, account: Pubkey, bank: Pubkey) -> bool {
|
||||
let account_data = get_mango_account(solana, account).await;
|
||||
let bank_data: Bank = solana.get_account(bank).await;
|
||||
account_data.token_find(bank_data.token_index).is_none()
|
||||
account_data.token_position(bank_data.token_index).is_err()
|
||||
}
|
||||
|
||||
pub async fn account_position_f64(solana: &SolanaCookie, account: Pubkey, bank: Pubkey) -> f64 {
|
||||
let account_data = get_mango_account(solana, account).await;
|
||||
let bank_data: Bank = solana.get_account(bank).await;
|
||||
let native = account_data
|
||||
.token_find(bank_data.token_index)
|
||||
.token_position(bank_data.token_index)
|
||||
.unwrap()
|
||||
.native(&bank_data);
|
||||
native.to_num::<f64>()
|
||||
|
@ -1527,7 +1527,7 @@ impl<'keypair> ClientInstruction for Serum3PlaceOrderInstruction<'keypair> {
|
|||
.unwrap();
|
||||
let serum_market: Serum3Market = account_loader.load(&self.serum_market).await.unwrap();
|
||||
let open_orders = account
|
||||
.serum3_find(serum_market.market_index)
|
||||
.serum3_orders(serum_market.market_index)
|
||||
.unwrap()
|
||||
.open_orders;
|
||||
let quote_info =
|
||||
|
@ -1629,7 +1629,7 @@ impl<'keypair> ClientInstruction for Serum3CancelOrderInstruction<'keypair> {
|
|||
.unwrap();
|
||||
let serum_market: Serum3Market = account_loader.load(&self.serum_market).await.unwrap();
|
||||
let open_orders = account
|
||||
.serum3_find(serum_market.market_index)
|
||||
.serum3_orders(serum_market.market_index)
|
||||
.unwrap()
|
||||
.open_orders;
|
||||
|
||||
|
@ -1690,7 +1690,7 @@ impl<'keypair> ClientInstruction for Serum3CancelAllOrdersInstruction<'keypair>
|
|||
.unwrap();
|
||||
let serum_market: Serum3Market = account_loader.load(&self.serum_market).await.unwrap();
|
||||
let open_orders = account
|
||||
.serum3_find(serum_market.market_index)
|
||||
.serum3_orders(serum_market.market_index)
|
||||
.unwrap()
|
||||
.open_orders;
|
||||
|
||||
|
@ -1751,7 +1751,7 @@ impl<'keypair> ClientInstruction for Serum3SettleFundsInstruction<'keypair> {
|
|||
.unwrap();
|
||||
let serum_market: Serum3Market = account_loader.load(&self.serum_market).await.unwrap();
|
||||
let open_orders = account
|
||||
.serum3_find(serum_market.market_index)
|
||||
.serum3_orders(serum_market.market_index)
|
||||
.unwrap()
|
||||
.open_orders;
|
||||
let quote_info =
|
||||
|
@ -1827,7 +1827,7 @@ impl ClientInstruction for Serum3LiqForceCancelOrdersInstruction {
|
|||
.unwrap();
|
||||
let serum_market: Serum3Market = account_loader.load(&self.serum_market).await.unwrap();
|
||||
let open_orders = account
|
||||
.serum3_find(serum_market.market_index)
|
||||
.serum3_orders(serum_market.market_index)
|
||||
.unwrap()
|
||||
.open_orders;
|
||||
let quote_info =
|
||||
|
|
|
@ -563,7 +563,7 @@ async fn test_liq_tokens_with_token() -> Result<(), TransportError> {
|
|||
// Liqee's remaining collateral got dusted, only borrows remain
|
||||
// but the borrow amount is so tiny, that being_liquidated is already switched off
|
||||
let liqee = get_mango_account(solana, account).await;
|
||||
assert_eq!(liqee.token_iter_active().count(), 1);
|
||||
assert_eq!(liqee.active_token_positions().count(), 1);
|
||||
assert!(account_position_f64(solana, account, borrow_token1.bank).await > -1.0);
|
||||
assert!(!liqee.being_liquidated());
|
||||
|
||||
|
|
|
@ -231,7 +231,7 @@ async fn test_margin_trade() -> Result<(), BanksClientError> {
|
|||
);
|
||||
// Check that position is fully deactivated
|
||||
let account_data = get_mango_account(solana, account).await;
|
||||
assert_eq!(account_data.token_iter_active().count(), 0);
|
||||
assert_eq!(account_data.active_token_positions().count(), 0);
|
||||
|
||||
//
|
||||
// TEST: Activating a token via margin trade
|
||||
|
|
|
@ -130,7 +130,7 @@ async fn test_position_lifetime() -> Result<()> {
|
|||
|
||||
// Check that positions are fully deactivated
|
||||
let account = get_mango_account(solana, account).await;
|
||||
assert_eq!(account.token_iter_active().count(), 0);
|
||||
assert_eq!(account.active_token_positions().count(), 0);
|
||||
|
||||
// No user tokens got lost
|
||||
for &payer_token in payer_mint_accounts {
|
||||
|
@ -230,7 +230,7 @@ async fn test_position_lifetime() -> Result<()> {
|
|||
|
||||
// Check that positions are fully deactivated
|
||||
let account = get_mango_account(solana, account).await;
|
||||
assert_eq!(account.token_iter_active().count(), 0);
|
||||
assert_eq!(account.active_token_positions().count(), 0);
|
||||
|
||||
// No user tokens got lost
|
||||
// TODO: -1 is a workaround for rounding down in withdraw
|
||||
|
|
|
@ -130,7 +130,7 @@ async fn test_serum() -> Result<(), TransportError> {
|
|||
let account_data = get_mango_account(solana, account).await;
|
||||
assert_eq!(
|
||||
account_data
|
||||
.serum3_iter_active()
|
||||
.active_serum3_orders()
|
||||
.map(|v| (v.open_orders, v.market_index))
|
||||
.collect::<Vec<_>>(),
|
||||
[(open_orders, 0)]
|
||||
|
|
|
@ -16,7 +16,7 @@ import {
|
|||
export class MangoAccount {
|
||||
public tokens: TokenPosition[];
|
||||
public serum3: Serum3Orders[];
|
||||
public perps: PerpPositions[];
|
||||
public perps: PerpPosition[];
|
||||
public name: string;
|
||||
|
||||
static from(
|
||||
|
@ -79,7 +79,7 @@ export class MangoAccount {
|
|||
this.name = utf8.decode(new Uint8Array(name)).split('\x00')[0];
|
||||
this.tokens = tokens.map((dto) => TokenPosition.from(dto));
|
||||
this.serum3 = serum3.map((dto) => Serum3Orders.from(dto));
|
||||
this.perps = perps.map((dto) => PerpPositions.from(dto));
|
||||
this.perps = perps.map((dto) => PerpPosition.from(dto));
|
||||
}
|
||||
|
||||
async reload(client: MangoClient, group: Group) {
|
||||
|
@ -360,7 +360,7 @@ export class MangoAccount {
|
|||
return this.serum3.filter((serum3) => serum3.isActive());
|
||||
}
|
||||
|
||||
perpActive(): PerpPositions[] {
|
||||
perpActive(): PerpPosition[] {
|
||||
return this.perps.filter((perp) => perp.isActive());
|
||||
}
|
||||
|
||||
|
@ -532,10 +532,10 @@ export class Serum3PositionDto {
|
|||
) {}
|
||||
}
|
||||
|
||||
export class PerpPositions {
|
||||
export class PerpPosition {
|
||||
static PerpMarketIndexUnset = 65535;
|
||||
static from(dto: PerpPositionDto) {
|
||||
return new PerpPositions(
|
||||
return new PerpPosition(
|
||||
dto.marketIndex,
|
||||
dto.basePositionLots.toNumber(),
|
||||
dto.quotePositionNative.val.toNumber(),
|
||||
|
@ -557,7 +557,7 @@ export class PerpPositions {
|
|||
) {}
|
||||
|
||||
isActive(): boolean {
|
||||
return this.marketIndex != PerpPositions.PerpMarketIndexUnset;
|
||||
return this.marketIndex != PerpPosition.PerpMarketIndexUnset;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3083,7 +3083,7 @@ export type MangoV4 = {
|
|||
"name": "perps",
|
||||
"type": {
|
||||
"vec": {
|
||||
"defined": "PerpPositions"
|
||||
"defined": "PerpPosition"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -3978,7 +3978,7 @@ export type MangoV4 = {
|
|||
}
|
||||
},
|
||||
{
|
||||
"name": "PerpPositions",
|
||||
"name": "PerpPosition",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
|
@ -8146,7 +8146,7 @@ export const IDL: MangoV4 = {
|
|||
"name": "perps",
|
||||
"type": {
|
||||
"vec": {
|
||||
"defined": "PerpPositions"
|
||||
"defined": "PerpPosition"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -9041,7 +9041,7 @@ export const IDL: MangoV4 = {
|
|||
}
|
||||
},
|
||||
{
|
||||
"name": "PerpPositions",
|
||||
"name": "PerpPosition",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
|
|
Loading…
Reference in New Issue