add a test for consume events, add debug impl for mango account for easy debugging in tests

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>
This commit is contained in:
microwavedcola1 2022-05-05 10:25:32 +02:00
parent d38ca0de4c
commit 9f5a2fd32e
4 changed files with 228 additions and 9 deletions

View File

@ -23,6 +23,7 @@ pub const MAX_PERP_OPEN_ORDERS: usize = 8;
pub const FREE_ORDER_SLOT: PerpMarketIndex = PerpMarketIndex::MAX;
#[zero_copy]
#[derive(Debug)]
pub struct TokenAccount {
// TODO: Why did we have deposits and borrows as two different values
// if only one of them was allowed to be != 0 at a time?
@ -75,6 +76,21 @@ const_assert_eq!(
);
const_assert_eq!(size_of::<MangoAccountTokens>() % 8, 0);
impl std::fmt::Debug for MangoAccountTokens {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MangoAccountTokens")
.field(
"values",
&self
.values
.iter()
.filter(|value| value.is_active())
.collect::<Vec<&TokenAccount>>(),
)
.finish()
}
}
impl Default for MangoAccountTokens {
fn default() -> Self {
Self::new()
@ -153,6 +169,7 @@ impl MangoAccountTokens {
}
#[zero_copy]
#[derive(Debug)]
pub struct Serum3Account {
pub open_orders: Pubkey,
@ -201,6 +218,21 @@ const_assert_eq!(
);
const_assert_eq!(size_of::<MangoAccountSerum3>() % 8, 0);
impl std::fmt::Debug for MangoAccountSerum3 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MangoAccountSerum3")
.field(
"values",
&self
.values
.iter()
.filter(|value| value.is_active())
.collect::<Vec<&Serum3Account>>(),
)
.finish()
}
}
impl Default for MangoAccountSerum3 {
fn default() -> Self {
Self::new()
@ -245,6 +277,7 @@ impl MangoAccountSerum3 {
}
#[zero_copy]
#[derive(Debug)]
pub struct PerpAccount {
pub market_index: PerpMarketIndex,
pub reserved: [u8; 6],
@ -341,6 +374,55 @@ const_assert_eq!(
);
const_assert_eq!(size_of::<MangoAccountPerps>() % 8, 0);
impl std::fmt::Debug for MangoAccountPerps {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MangoAccountPerps")
.field(
"accounts",
&self
.accounts
.iter()
.filter(|value| value.is_active())
.collect::<Vec<&PerpAccount>>(),
)
.field(
"order_market",
&self
.order_market
.iter()
.filter(|value| **value != PerpMarketIndex::MAX)
.collect::<Vec<&PerpMarketIndex>>(),
)
.field(
"order_side",
&self
.order_side
.iter()
.zip(self.order_id)
.filter(|value| value.1 != 0)
.map(|value| value.0)
.collect::<Vec<&Side>>(),
)
.field(
"order_id",
&self
.order_id
.iter()
.filter(|value| **value != 0)
.collect::<Vec<&i128>>(),
)
.field(
"order_client_id",
&self
.order_client_id
.iter()
.filter(|value| **value != 0)
.collect::<Vec<&u64>>(),
)
.finish()
}
}
impl MangoAccountPerps {
pub fn new() -> Self {
Self {
@ -553,6 +635,30 @@ const_assert_eq!(
);
const_assert_eq!(size_of::<MangoAccount>() % 8, 0);
impl std::fmt::Debug for MangoAccount {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MangoAccount")
.field(
"name",
&std::str::from_utf8(&self.name)
.unwrap()
.trim_matches(char::from(0)),
)
.field("group", &self.group)
.field("owner", &self.owner)
.field("delegate", &self.delegate)
.field("tokens", &self.tokens)
.field("serum3", &self.serum3)
.field("perps", &self.perps)
.field("being_liquidated", &self.being_liquidated)
.field("is_bankrupt", &self.is_bankrupt)
.field("account_num", &self.account_num)
.field("bump", &self.bump)
.field("reserved", &self.reserved)
.finish()
}
}
#[macro_export]
macro_rules! account_seeds {
( $account:expr ) => {

View File

@ -90,6 +90,15 @@ impl PerpMarket {
.unwrap()
}
pub fn native_price_to_lot(&self, price: I80F48) -> i64 {
price
.checked_mul(I80F48::from_num(self.base_lot_size))
.unwrap()
.checked_div(I80F48::from_num(self.quote_lot_size))
.unwrap()
.to_num()
}
/// Is `native_price` an acceptable order for the `side` of this market, given `oracle_price`?
pub fn inside_price_limit(
&self,

View File

@ -1390,6 +1390,44 @@ impl<'keypair> ClientInstruction for PerpPlaceOrderInstruction<'keypair> {
vec![self.owner]
}
}
pub struct PerpConsumeEventsInstruction {
pub group: Pubkey,
pub perp_market: Pubkey,
pub event_queue: Pubkey,
pub mango_accounts: Vec<Pubkey>,
}
#[async_trait::async_trait(?Send)]
impl ClientInstruction for PerpConsumeEventsInstruction {
type Accounts = mango_v4::accounts::PerpConsumeEvents;
type Instruction = mango_v4::instruction::PerpConsumeEvents;
async fn to_instruction(
&self,
_loader: impl ClientAccountLoader + 'async_trait,
) -> (Self::Accounts, instruction::Instruction) {
let program_id = mango_v4::id();
let instruction = Self::Instruction { limit: 10 };
let accounts = Self::Accounts {
group: self.group,
perp_market: self.perp_market,
event_queue: self.event_queue,
};
let mut instruction = make_instruction(program_id, &accounts, instruction);
instruction
.accounts
.extend(self.mango_accounts.iter().map(|ma| AccountMeta {
pubkey: *ma,
is_signer: false,
is_writable: true,
}));
(accounts, instruction)
}
fn signers(&self) -> Vec<&Keypair> {
vec![]
}
}
pub struct BenchmarkInstruction {}
#[async_trait::async_trait(?Send)]
impl ClientInstruction for BenchmarkInstruction {

View File

@ -1,11 +1,11 @@
#![cfg(all(feature = "test-bpf"))]
use fixed_macro::types::I80F48;
use mango_v4::state::*;
use program_test::*;
use solana_program_test::*;
use solana_sdk::signature::Keypair;
use program_test::*;
mod program_test;
#[tokio::test]
@ -31,7 +31,7 @@ async fn test_perp() -> Result<(), BanksClientError> {
.create(solana)
.await;
let account = send_tx(
let account_0 = send_tx(
solana,
CreateAccountInstruction {
account_num: 0,
@ -44,6 +44,19 @@ async fn test_perp() -> Result<(), BanksClientError> {
.unwrap()
.account;
let account_1 = send_tx(
solana,
CreateAccountInstruction {
account_num: 1,
group,
owner,
payer,
},
)
.await
.unwrap()
.account;
//
// SETUP: Deposit user funds
//
@ -54,7 +67,7 @@ async fn test_perp() -> Result<(), BanksClientError> {
solana,
DepositInstruction {
amount: deposit_amount,
account,
account: account_0,
token_account: payer_mint_accounts[0],
token_authority: payer,
},
@ -66,7 +79,35 @@ async fn test_perp() -> Result<(), BanksClientError> {
solana,
DepositInstruction {
amount: deposit_amount,
account,
account: account_0,
token_account: payer_mint_accounts[1],
token_authority: payer,
},
)
.await
.unwrap();
}
{
let deposit_amount = 1000;
send_tx(
solana,
DepositInstruction {
amount: deposit_amount,
account: account_1,
token_account: payer_mint_accounts[0],
token_authority: payer,
},
)
.await
.unwrap();
send_tx(
solana,
DepositInstruction {
amount: deposit_amount,
account: account_1,
token_account: payer_mint_accounts[1],
token_authority: payer,
},
@ -122,11 +163,16 @@ async fn test_perp() -> Result<(), BanksClientError> {
.await
.unwrap();
let price_lots = {
let perp_market = solana.get_account::<PerpMarket>(perp_market).await;
perp_market.native_price_to_lot(I80F48!(1))
};
send_tx(
solana,
PerpPlaceOrderInstruction {
group,
account,
account: account_0,
perp_market,
asks,
bids,
@ -134,7 +180,7 @@ async fn test_perp() -> Result<(), BanksClientError> {
oracle: tokens[0].oracle,
owner,
side: Side::Bid,
price_lots: 1,
price_lots,
max_base_lots: 1,
max_quote_lots: i64::MAX,
},
@ -146,7 +192,7 @@ async fn test_perp() -> Result<(), BanksClientError> {
solana,
PerpPlaceOrderInstruction {
group,
account,
account: account_1,
perp_market,
asks,
bids,
@ -154,7 +200,7 @@ async fn test_perp() -> Result<(), BanksClientError> {
oracle: tokens[0].oracle,
owner,
side: Side::Ask,
price_lots: 1,
price_lots,
max_base_lots: 1,
max_quote_lots: i64::MAX,
},
@ -162,5 +208,25 @@ async fn test_perp() -> Result<(), BanksClientError> {
.await
.unwrap();
send_tx(
solana,
PerpConsumeEventsInstruction {
group,
perp_market,
event_queue,
mango_accounts: vec![account_0, account_1],
},
)
.await
.unwrap();
let mango_account_0 = solana.get_account::<MangoAccount>(account_0).await;
assert_eq!(mango_account_0.perps.accounts[0].base_position_lots, 1);
assert!(mango_account_0.perps.accounts[0].quote_position_native < -100.019);
let mango_account_1 = solana.get_account::<MangoAccount>(account_1).await;
assert_eq!(mango_account_1.perps.accounts[0].base_position_lots, -1);
assert_eq!(mango_account_1.perps.accounts[0].quote_position_native, 100);
Ok(())
}