#![cfg(feature = "test-bpf")] use solana_program_test::*; use solana_sdk::{signature::Keypair, signer::Signer, transport::TransportError}; use mango_v4::{ instructions::{Serum3OrderType, Serum3SelfTradeBehavior, Serum3Side}, state::*, }; use program_test::*; mod program_test; #[tokio::test] async fn test_serum() -> Result<(), TransportError> { let context = TestContext::new().await; let solana = &context.solana.clone(); let admin = &Keypair::new(); let owner = &context.users[0].key; let payer = &context.users[1].key; let mints = &context.mints[0..2]; let payer_mint_accounts = &context.users[1].token_accounts[0..=2]; // // SETUP: Create a group and an account // let mango_setup::GroupWithTokens { group, tokens, .. } = mango_setup::GroupWithTokensConfig { admin, payer, mints, } .create(solana) .await; let base_token = &tokens[0]; let quote_token = &tokens[1]; let account = send_tx( solana, AccountCreateInstruction { account_num: 0, account_size: AccountSize::Large, group, owner, payer, }, ) .await .unwrap() .account; // // SETUP: Create serum market // let serum_market_cookie = context .serum .list_spot_market(&base_token.mint, "e_token.mint) .await; // // SETUP: Deposit user funds // { let deposit_amount = 1000; send_tx( solana, TokenDepositInstruction { amount: deposit_amount, account, token_account: payer_mint_accounts[0], token_authority: payer.clone(), bank_index: 0, }, ) .await .unwrap(); send_tx( solana, TokenDepositInstruction { amount: deposit_amount, account, token_account: payer_mint_accounts[1], token_authority: payer.clone(), bank_index: 0, }, ) .await .unwrap(); } // // TEST: Register a serum market // let serum_market = send_tx( solana, Serum3RegisterMarketInstruction { group, admin, serum_program: context.serum.program_id, serum_market_external: serum_market_cookie.market, market_index: 0, base_bank: base_token.bank, quote_bank: quote_token.bank, payer, }, ) .await .unwrap() .serum_market; // // TEST: Create an open orders account // let open_orders = send_tx( solana, Serum3CreateOpenOrdersInstruction { account, serum_market, owner, payer, }, ) .await .unwrap() .open_orders; let account_data = get_mango_account(solana, account).await; assert_eq!( account_data .serum3_iter_active() .map(|v| (v.open_orders, v.market_index)) .collect::>(), [(open_orders, 0)] ); // // TEST: Place an order // send_tx( solana, Serum3PlaceOrderInstruction { side: Serum3Side::Bid, limit_price: 10, // in quote_lot (10) per base lot (100) max_base_qty: 1, // in base lot (100) max_native_quote_qty_including_fees: 100, self_trade_behavior: Serum3SelfTradeBehavior::DecrementTake, order_type: Serum3OrderType::Limit, client_order_id: 0, limit: 10, account, owner, serum_market, }, ) .await .unwrap(); let native0 = account_position(solana, account, base_token.bank).await; let native1 = account_position(solana, account, quote_token.bank).await; assert_eq!(native0, 1000); assert_eq!(native1, 900); // get the order id let open_orders_bytes = solana.get_account_data(open_orders).await.unwrap(); let open_orders_data: &serum_dex::state::OpenOrders = bytemuck::from_bytes( &open_orders_bytes[5..5 + std::mem::size_of::()], ); let order_id = open_orders_data.orders[0]; assert!(order_id != 0); // // TEST: Cancel the order // send_tx( solana, Serum3CancelOrderInstruction { side: Serum3Side::Bid, order_id, account, owner, serum_market, }, ) .await .unwrap(); // // TEST: Settle, moving the freed up funds back // send_tx( solana, Serum3SettleFundsInstruction { account, owner, serum_market, }, ) .await .unwrap(); let native0 = account_position(solana, account, base_token.bank).await; let native1 = account_position(solana, account, quote_token.bank).await; assert_eq!(native0, 1000); assert_eq!(native1, 1000); // close oo account // TODO: custom program error: 0x2a TooManyOpenOrders https://github.com/project-serum/serum-dex/blob/master/dex/src/error.rs#L88 // send_tx( // solana, // Serum3CloseOpenOrdersInstruction { // account, // serum_market, // owner, // sol_destination: payer.pubkey(), // }, // ) // .await // .unwrap(); // deregister serum3 market send_tx( solana, Serum3DeregisterMarketInstruction { group, admin, serum_market_external: serum_market_cookie.market, sol_destination: payer.pubkey(), }, ) .await .unwrap(); Ok(()) }