Renames in MangoAccount

- Accessors in MangoAccountValue
- PerpPositions -> PerpPosition
This commit is contained in:
Christian Kamm 2022-08-18 13:45:31 +02:00
parent ec850b7bd3
commit 09fc5f716b
36 changed files with 310 additions and 297 deletions

View File

@ -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()

View File

@ -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

View File

@ -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) => {

View File

@ -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");

View File

@ -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);
}

View File

@ -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<_>>()
})

View File

@ -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);
}
}

View File

@ -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(())

View File

@ -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(())

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)?;
}
};
}

View File

@ -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(),

View File

@ -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;

View File

@ -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(())
}

View File

@ -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(())

View File

@ -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(),

View File

@ -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)?;

View File

@ -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() {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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
);
}

View File

@ -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 =

View File

@ -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());

View File

@ -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

View File

@ -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

View File

@ -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)]

View File

@ -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;
}
}

View File

@ -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": [