Skip to content

Commit

Permalink
Program: collateral fees testing - add spot order
Browse files Browse the repository at this point in the history
  • Loading branch information
farnyser committed Jul 11, 2024
1 parent 4b7a42f commit 732fdd7
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 27 deletions.
160 changes: 143 additions & 17 deletions programs/mango-v4/tests/cases/test_collateral_fees.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![allow(unused_assignments)]

use super::*;
use crate::cases::test_serum::SerumOrderPlacer;
use anchor_spl::token::accessor::mint;
use num::ToPrimitive;
use std::collections::HashMap;
Expand Down Expand Up @@ -313,32 +314,62 @@ async fn test_collateral_fees_multi() -> Result<(), TransportError> {
Ok(())
}

// Test convention
//
// T = Token without collateral fee
// Tc = Token with collateral fee
// B_x = Balance of x
// O_x = Amount in OO for x (market will be x/T1)
// F_x = Collateral Fee charged on x
//
// Asset weight = 0.8
// Liab weight = 1.2
// All amounts in USD
// Base lot is 100

#[tokio::test]
async fn test_basics() -> Result<(), TransportError> {
let test_cases = parse_test_cases("\
B_T1 ; B_T2 ; B_Tc1 ; B_Tc2 ; B_Tc3 ; B_Tc4 ; O_T1 ; O_T2 ; O_Tc1 ; O_Tc2 ; O_Tc3 ; O_Tc4 ; CF_T1 ; CF_T2 ; CF_Tc1 ; CF_Tc2 ; CF_Tc3 ; CF_Tc4 \r\n \
-2000 ; 0 ; 10000 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; -300 ; 0 ; 0 ; 0 ; 0 ; 0 \r\n \
-2000 ; 0 ; 5000 ; 5000 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; -300 ; 0 ; 0 ; 0 ; 0 ; 0 \r\n \
-500 ; -1500 ; 10000 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; -75 ; -225 ; 0 ; 0 ; 0 ; 0 \r\n \
");

run_scenario(test_cases).await
}

#[tokio::test]
async fn test_with_csv() -> Result<(), TransportError> {
/// Test convention
///
/// T = Token without collateral fee
/// Tc = Token with collateral fee
/// B_x = Balance of x
/// R_x = Amount reserved in OO for x
/// F_x = Collateral Fee charged on x
///
/// Asset weight = 0.8
/// Liab weight = 1.2
/// All amounts in USD
async fn test_creating_borrow_from_oo() -> Result<(), TransportError> {
let test_cases = parse_test_cases("\
B_T1 ; B_T2 ; B_Tc1 ; B_Tc2 ; B_Tc3 ; B_Tc4 ; O_T1 ; O_T2 ; O_Tc1 ; O_Tc2 ; O_Tc3 ; O_Tc4 ; CF_T1 ; CF_T2 ; CF_Tc1 ; CF_Tc2 ; CF_Tc3 ; CF_Tc4 \r\n \
-2000 ; 0 ; 10000 ; 0 ; 0 ; 0 ; 0 ; 200 ; 0 ; 0 ; 0 ; 0 ; -300 ; 0 ; 0 ; 0 ; 0 ; 0 \r\n \
-2000 ; 0 ; 10000 ; 0 ; 0 ; 0 ; 0 ; 0 ; 300 ; 0 ; 0 ; 0 ; -300 ; 0 ; 0 ; 0 ; 0 ; 0 \r\n \
");

run_scenario(test_cases).await
}

#[tokio::test]
async fn test_hiding_collateral_using_oo() -> Result<(), TransportError> {
let test_cases = parse_test_cases("\
B_T1 ; B_T2 ; B_Tc1 ; B_Tc2 ; B_Tc3 ; B_Tc4 ; R_T1 ; R_T2 ; R_Tc1 ; R_Tc2 ; R_Tc3 ; R_Tc4 ; CF_T1 ; CF_T2 ; CF_Tc1 ; CF_Tc2 ; CF_Tc3 ; CF_Tc4 \r\n \
-200 ; 0 ; 1000 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; -30 ; 0 ; 0 ; 0 ; 0 ; 0 \r\n \
-200 ; 0 ; 500 ; 500 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; -30 ; 0 ; 0 ; 0 ; 0 ; 0 \r\n \
-50 ; -150 ; 1000 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; -7.5 ; -22.5 ; 0 ; 0 ; 0 ; 0 \r\n \
B_T1 ; B_T2 ; B_Tc1 ; B_Tc2 ; B_Tc3 ; B_Tc4 ; O_T1 ; O_T2 ; O_Tc1 ; O_Tc2 ; O_Tc3 ; O_Tc4 ; CF_T1 ; CF_T2 ; CF_Tc1 ; CF_Tc2 ; CF_Tc3 ; CF_Tc4 \r\n \
-2000 ; 0 ; 10000 ; 0 ; 0 ; 0 ; 0 ; -200 ; 0 ; 0 ; 0 ; 0 ; -300 ; 0 ; 0 ; 0 ; 0 ; 0 \r\n \
-2000 ; 0 ; 10000 ; 0 ; 0 ; 0 ; 0 ; 0 ; -300 ; 0 ; 0 ; 0 ; -300 ; 0 ; 0 ; 0 ; 0 ; 0 \r\n \
");

run_scenario(test_cases).await
}

async fn run_scenario(test_cases: Vec<Vec<f64>>) -> Result<(), TransportError> {
for test_case in test_cases {
if test_case.len() == 0 {
continue;
}
let context = TestContext::new().await;

let mut test_builder = TestContextBuilder::new();
test_builder.test().set_compute_max_units(200_000);
let context = test_builder.start_default().await;
let solana = &context.solana.clone();

let admin = TestKeypair::new();
Expand Down Expand Up @@ -399,6 +430,8 @@ async fn test_with_csv() -> Result<(), TransportError> {
.unwrap()
.account;

// For Spot order

let hour = 60 * 60;

send_tx(
Expand Down Expand Up @@ -443,6 +476,28 @@ async fn test_with_csv() -> Result<(), TransportError> {
}
}

// Setup orders
for (index, order) in test_case[6..12].iter().enumerate() {
if *order == 0.0 {
continue;
}

create_order(
solana,
&context,
group,
admin,
owner,
&context.users[0],
account,
(index + 1) as f64,
(order / (index + 1) as f64).floor() as i64,
&tokens[index],
&tokens[0],
)
.await;
}

//
// TEST
//
Expand Down Expand Up @@ -503,6 +558,77 @@ fn parse_test_cases(test_cases: &str) -> Vec<Vec<f64>> {
.collect_vec()
}

async fn create_order(
solana: &Arc<SolanaCookie>,
context: &TestContext,
group: Pubkey,
admin: TestKeypair,
owner: TestKeypair,
payer: &UserCookie,
account: Pubkey,
price: f64,
quantity: i64,
base_token: &Token,
quote_token: &Token,
) -> Option<(u128, u64)> {
let serum_market_cookie = context
.serum
.list_spot_market(&base_token.mint, &quote_token.mint)
.await;

//
// 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: payer.key,
},
)
.await
.unwrap()
.serum_market;

//
// TEST: Create an open orders account
//
let open_orders = send_tx(
solana,
Serum3CreateOpenOrdersInstruction {
account,
serum_market,
owner,
payer: payer.key,
},
)
.await
.unwrap()
.open_orders;

let mut order_placer = SerumOrderPlacer {
solana: solana.clone(),
serum: context.serum.clone(),
account,
owner: owner.clone(),
serum_market,
open_orders,
next_client_order_id: 0,
};

if quantity > 0 {
order_placer.bid_maker(price, quantity as u64).await
} else {
order_placer.ask(price, quantity.abs() as u64).await
}
}

async fn withdraw(
context: &TestContext,
solana: &Arc<SolanaCookie>,
Expand Down
20 changes: 10 additions & 10 deletions programs/mango-v4/tests/cases/test_serum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ use mango_v4::accounts_ix::{Serum3OrderType, Serum3SelfTradeBehavior, Serum3Side
use mango_v4::serum3_cpi::{load_open_orders_bytes, OpenOrdersSlim};
use std::sync::Arc;

struct SerumOrderPlacer {
solana: Arc<SolanaCookie>,
serum: Arc<SerumCookie>,
account: Pubkey,
owner: TestKeypair,
serum_market: Pubkey,
open_orders: Pubkey,
next_client_order_id: u64,
pub struct SerumOrderPlacer {
pub solana: Arc<SolanaCookie>,
pub serum: Arc<SerumCookie>,
pub account: Pubkey,
pub owner: TestKeypair,
pub serum_market: Pubkey,
pub open_orders: Pubkey,
pub next_client_order_id: u64,
}

impl SerumOrderPlacer {
Expand Down Expand Up @@ -72,7 +72,7 @@ impl SerumOrderPlacer {
send_tx(&self.solana, ix).await
}

async fn bid_maker(&mut self, limit_price: f64, max_base: u64) -> Option<(u128, u64)> {
pub async fn bid_maker(&mut self, limit_price: f64, max_base: u64) -> Option<(u128, u64)> {
self.try_bid(limit_price, max_base, false).await.unwrap();
self.find_order_id_for_client_order_id(self.next_client_order_id - 1)
.await
Expand Down Expand Up @@ -109,7 +109,7 @@ impl SerumOrderPlacer {
.await
}

async fn ask(&mut self, limit_price: f64, max_base: u64) -> Option<(u128, u64)> {
pub async fn ask(&mut self, limit_price: f64, max_base: u64) -> Option<(u128, u64)> {
self.try_ask(limit_price, max_base).await.unwrap();
self.find_order_id_for_client_order_id(self.next_client_order_id - 1)
.await
Expand Down

0 comments on commit 732fdd7

Please sign in to comment.