Skip to content

Commit 21ff523

Browse files
committed
feat: add quote_lot_size for full decimal generality
Adopts the Serum/Openbook two-lot model. Previously the program was only correct when d_base >= d_quote (e.g. NVDAx/USDC), because quote amounts were computed as price × quantity raw quote tokens with no scaling on the quote side. With quote_lot_size, all raw-quote amounts become: raw_quote = price × quantity × quote_lot_size Choosing base_lot_size = 10^max(d_base - d_quote, 0) and quote_lot_size = 10^max(d_quote - d_base, 0) makes price the human-readable quote/base rate and tick_size=1 one atomic price increment regardless of which mint has more decimals. NVDAx (8 dec) / USDC (6 dec): base_lot_size=100, quote_lot_size=1 (values unchanged) WBTC (8 dec) / HD-USDC (18 dec): base_lot_size=1, quote_lot_size=10^10 Changes: InvalidQuoteLotSize error; quote_lot_size field on Market; new param in initialize_market; bid lock, gross_quote, and locked_for_this_fill in place_order all gain x quote_lot_size; bid cancel refund in cancel_order gains x quote_lot_size; settle_funds untouched (already operates on raw amounts in unsettled_*). Tests add QUOTE_LOT_SIZE=1, update all call sites and assertions, add rejection test for zero quote_lot_size. https://claude.ai/code/session_01G6iaAjzg8aoFwe8ZWWG9VR
1 parent 9c22bf2 commit 21ff523

7 files changed

Lines changed: 99 additions & 48 deletions

File tree

defi/order-book/anchor/programs/order-book/src/errors.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ pub enum ErrorCode {
2626
#[msg("Base lot size must be greater than zero")]
2727
InvalidBaseLotSize,
2828

29+
#[msg("Quote lot size must be greater than zero")]
30+
InvalidQuoteLotSize,
31+
2932
#[msg("Quantity is below minimum order size")]
3033
BelowMinOrderSize,
3134

defi/order-book/anchor/programs/order-book/src/instructions/cancel_order.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,13 @@ pub fn handle_cancel_order(context: Context<CancelOrder>) -> Result<()> {
2727
let market_user = &mut context.accounts.market_user;
2828
match order.side {
2929
OrderSide::Bid => {
30-
// u128 intermediate: the lock was originally taken on a
31-
// u64 quote balance, so price * remaining must fit u64
32-
// — but the multiplication itself can transiently exceed
33-
// u64. Mirror the same pattern as place_order: widen,
34-
// multiply, narrow.
30+
// u128 intermediates mirror the bid-lock formula in place_order:
31+
// raw_quote = price × remaining × quote_lot_size
3532
let quote_amount: u64 = (order.price as u128)
3633
.checked_mul(remaining as u128)
3734
.ok_or(ErrorCode::NumericalOverflow)?
35+
.checked_mul(context.accounts.market.quote_lot_size as u128)
36+
.ok_or(ErrorCode::NumericalOverflow)?
3837
.try_into()
3938
.map_err(|_| error!(ErrorCode::NumericalOverflow))?;
4039
market_user.unsettled_quote = market_user

defi/order-book/anchor/programs/order-book/src/instructions/initialize_market.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ pub fn handle_initialize_market(
1313
fee_basis_points: u16,
1414
tick_size: u64,
1515
base_lot_size: u64,
16+
quote_lot_size: u64,
1617
min_order_size: u64,
1718
) -> Result<()> {
1819
require!(tick_size > 0, ErrorCode::InvalidTickSize);
1920
require!(base_lot_size > 0, ErrorCode::InvalidBaseLotSize);
21+
require!(quote_lot_size > 0, ErrorCode::InvalidQuoteLotSize);
2022
require!(min_order_size > 0, ErrorCode::BelowMinOrderSize);
2123
require!(
2224
fee_basis_points <= MAX_FEE_BASIS_POINTS,
@@ -34,6 +36,7 @@ pub fn handle_initialize_market(
3436
market.fee_basis_points = fee_basis_points;
3537
market.tick_size = tick_size;
3638
market.base_lot_size = base_lot_size;
39+
market.quote_lot_size = quote_lot_size;
3740
market.min_order_size = min_order_size;
3841
market.is_active = true;
3942
market.bump = context.bumps.market;

defi/order-book/anchor/programs/order-book/src/instructions/place_order.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ pub fn handle_place_order<'info>(
6767
(price as u128)
6868
.checked_mul(quantity as u128)
6969
.ok_or(ErrorCode::NumericalOverflow)?
70+
.checked_mul(market.quote_lot_size as u128)
71+
.ok_or(ErrorCode::NumericalOverflow)?
7072
.try_into()
7173
.map_err(|_| error!(ErrorCode::NumericalOverflow))?,
7274
context.accounts.quote_vault.to_account_info(),
@@ -194,6 +196,8 @@ pub fn handle_place_order<'info>(
194196
let gross_quote: u64 = (fill.fill_price as u128)
195197
.checked_mul(fill.fill_quantity as u128)
196198
.ok_or(ErrorCode::NumericalOverflow)?
199+
.checked_mul(market.quote_lot_size as u128)
200+
.ok_or(ErrorCode::NumericalOverflow)?
197201
.try_into()
198202
.map_err(|_| error!(ErrorCode::NumericalOverflow))?;
199203

@@ -239,6 +243,8 @@ pub fn handle_place_order<'info>(
239243
let locked_for_this_fill: u64 = (price as u128)
240244
.checked_mul(fill.fill_quantity as u128)
241245
.ok_or(ErrorCode::NumericalOverflow)?
246+
.checked_mul(market.quote_lot_size as u128)
247+
.ok_or(ErrorCode::NumericalOverflow)?
242248
.try_into()
243249
.map_err(|_| error!(ErrorCode::NumericalOverflow))?;
244250
let rebate: u64 = locked_for_this_fill

defi/order-book/anchor/programs/order-book/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ pub mod order_book {
2020
fee_basis_points: u16,
2121
tick_size: u64,
2222
base_lot_size: u64,
23+
quote_lot_size: u64,
2324
min_order_size: u64,
2425
) -> Result<()> {
2526
instructions::initialize_market::handle_initialize_market(
2627
context,
2728
fee_basis_points,
2829
tick_size,
2930
base_lot_size,
31+
quote_lot_size,
3032
min_order_size,
3133
)
3234
}

defi/order-book/anchor/programs/order-book/src/state/market.rs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,35 @@ pub struct Market {
3131

3232
pub tick_size: u64,
3333

34-
// Number of raw base-token units per lot. Quantities throughout the
35-
// program are in lots; this factor converts them to raw token units for
36-
// SPL transfers. For a base mint with d_base decimals and quote with
37-
// d_quote, set base_lot_size = 10^(d_base - d_quote) so that one raw
38-
// quote unit buys exactly one lot of base at price = 1, making `price`
39-
// equal to the human-readable USDC-per-token rate.
34+
// Two-lot model (mirrors Serum/Openbook): both sides of the book are
35+
// denominated in their respective lots rather than raw token units.
36+
// This makes `price` and `quantity` human-readable regardless of the
37+
// individual mints' decimal counts.
4038
//
41-
// Example — NVDAx (8 dec) / USDC (6 dec):
42-
// base_lot_size = 10^(8-6) = 100 raw NVDAx per lot
43-
// price = 130 → $130.00 per NVDAx share
44-
// tick_size = 1 → $1.00 minimum price increment
39+
// raw_base = quantity × base_lot_size
40+
// raw_quote = quantity × price × quote_lot_size
41+
//
42+
// Choose:
43+
// base_lot_size = 10^max(d_base − d_quote, 0)
44+
// quote_lot_size = 10^max(d_quote − d_base, 0)
45+
//
46+
// so that exactly one of the two is > 1 (or both are 1 when d_base == d_quote).
47+
// With those values `price` equals the human-readable quote/base rate and
48+
// `tick_size = 1` is a single atomic increment.
49+
//
50+
// Examples:
51+
// NVDAx (8 dec) / USDC (6 dec): base_lot_size=100, quote_lot_size=1
52+
// price=130, qty=1 lot → 130 × 1 × 1 = 130 raw USDC per 100 raw NVDAx
53+
// = $130.00 per NVDAx share ✓
54+
//
55+
// WBTC (8 dec) / HD-USDC (18 dec): base_lot_size=1, quote_lot_size=10^10
56+
// price=60_000, qty=1 satoshi-lot → 60_000 × 1 × 10^10 = 6×10^14 raw HD-USDC
57+
// = $60,000 per BTC ✓
4558
pub base_lot_size: u64,
4659

60+
// Raw quote-token units per quote lot. See base_lot_size comment above.
61+
pub quote_lot_size: u64,
62+
4763
pub min_order_size: u64,
4864

4965
pub is_active: bool,

defi/order-book/anchor/programs/order-book/tests/test_order_book.rs

Lines changed: 55 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -43,20 +43,20 @@ const MARKET_USER_SEED: &[u8] = b"market_user";
4343
// `#[account(zero)]` check fails if the account size is wrong.
4444
const ORDER_BOOK_ACCOUNT_SIZE: u64 = order_book::state::ORDER_BOOK_ACCOUNT_SIZE as u64;
4545

46-
// NVDAx has 8 decimals on-chain; USDC has 6. Because the program stores
47-
// price as raw_quote per raw_base, one tick = 10^(base_dec - quote_dec) = 100
48-
// USDC/share — the minimum representable price step with these two mints.
46+
// NVDAx has 8 decimals on-chain; USDC has 6.
4947
const BASE_DECIMALS: u8 = 8; // NVDAx (https://explorer.solana.com/address/Xsc9qvGR1efVDFGLrVsmkzv3qi45LTBjeUKSPmx9qEh)
5048
const QUOTE_DECIMALS: u8 = 6; // USDC
5149

52-
// Market parameters used across every test. `tick_size = 1` and
53-
// `base_lot_size = 100` match the NVDAx/USDC decimal configuration
54-
// (BASE_DECIMALS=8, QUOTE_DECIMALS=6): price = human USDC/share,
55-
// tick = $1.00, 1 lot = 100 raw NVDAx. A dedicated test overrides
56-
// tick_size to verify the tick check fires.
50+
// Two-lot model for NVDAx/USDC (d_base=8, d_quote=6):
51+
// base_lot_size = 10^max(8-6, 0) = 100 → 1 lot = 100 raw NVDAx
52+
// quote_lot_size = 10^max(6-8, 0) = 1 → 1 quote-lot = 1 raw USDC
53+
// raw_base = quantity × 100
54+
// raw_quote = price × quantity × 1 (= human USDC/share × lots)
55+
// tick_size = 1 → $1.00 minimum price increment
5756
const FEE_BASIS_POINTS: u16 = 10;
5857
const TICK_SIZE: u64 = 1;
5958
const BASE_LOT_SIZE: u64 = 100;
59+
const QUOTE_LOT_SIZE: u64 = 1;
6060
const MIN_ORDER_SIZE: u64 = 1;
6161

6262
// Funding for each trader's token accounts. Large enough to cover every
@@ -254,6 +254,7 @@ fn build_initialize_market_ix(
254254
fee_basis_points: u16,
255255
tick_size: u64,
256256
base_lot_size: u64,
257+
quote_lot_size: u64,
257258
min_order_size: u64,
258259
) -> Instruction {
259260
Instruction::new_with_bytes(
@@ -262,6 +263,7 @@ fn build_initialize_market_ix(
262263
fee_basis_points,
263264
tick_size,
264265
base_lot_size,
266+
quote_lot_size,
265267
min_order_size,
266268
}
267269
.data(),
@@ -454,7 +456,7 @@ fn initialize_market_and_users(sc: &mut Scenario) {
454456
// program, zero-initialized) before initialize_market's `#[account(zero)]`
455457
// check passes.
456458
let create_ix = build_create_order_book_account_ix(sc, &sc.authority.pubkey());
457-
let init_ix = build_initialize_market_ix(sc, FEE_BASIS_POINTS, TICK_SIZE, BASE_LOT_SIZE, MIN_ORDER_SIZE);
459+
let init_ix = build_initialize_market_ix(sc, FEE_BASIS_POINTS, TICK_SIZE, BASE_LOT_SIZE, QUOTE_LOT_SIZE, MIN_ORDER_SIZE);
458460
send_transaction_from_instructions(
459461
&mut sc.svm,
460462
vec![create_ix, init_ix],
@@ -497,7 +499,7 @@ fn initialize_market_sets_market_and_order_book() {
497499
let mut sc = full_setup();
498500

499501
let create_ix = build_create_order_book_account_ix(&sc, &sc.authority.pubkey());
500-
let ix = build_initialize_market_ix(&sc, FEE_BASIS_POINTS, TICK_SIZE, BASE_LOT_SIZE, MIN_ORDER_SIZE);
502+
let ix = build_initialize_market_ix(&sc, FEE_BASIS_POINTS, TICK_SIZE, BASE_LOT_SIZE, QUOTE_LOT_SIZE, MIN_ORDER_SIZE);
501503
send_transaction_from_instructions(
502504
&mut sc.svm,
503505
vec![create_ix, ix],
@@ -545,7 +547,7 @@ fn create_market_user_tracks_market_and_owner() {
545547
let mut sc = full_setup();
546548

547549
let create_ix = build_create_order_book_account_ix(&sc, &sc.authority.pubkey());
548-
let init_ix = build_initialize_market_ix(&sc, FEE_BASIS_POINTS, TICK_SIZE, BASE_LOT_SIZE, MIN_ORDER_SIZE);
550+
let init_ix = build_initialize_market_ix(&sc, FEE_BASIS_POINTS, TICK_SIZE, BASE_LOT_SIZE, QUOTE_LOT_SIZE, MIN_ORDER_SIZE);
549551
send_transaction_from_instructions(
550552
&mut sc.svm,
551553
vec![create_ix, init_ix],
@@ -597,8 +599,8 @@ fn place_bid_locks_quote_in_vault() {
597599
send_transaction_from_instructions(&mut sc.svm, vec![ix], &[&sc.buyer], &sc.buyer.pubkey())
598600
.unwrap();
599601

600-
// A bid locks price * quantity in the quote vault.
601-
let locked_quote = BID_PRICE * BID_QUANTITY;
602+
// A bid locks price * quantity * quote_lot_size raw quote tokens.
603+
let locked_quote = BID_PRICE * BID_QUANTITY * QUOTE_LOT_SIZE;
602604
assert_eq!(
603605
get_token_account_balance(&sc.svm, &sc.quote_vault.pubkey()).unwrap(),
604606
locked_quote
@@ -693,7 +695,7 @@ fn place_order_rejects_unaligned_tick() {
693695
let unusual_tick_size: u64 = 50;
694696
let create_ix = build_create_order_book_account_ix(&sc, &sc.authority.pubkey());
695697
let init_ix =
696-
build_initialize_market_ix(&sc, FEE_BASIS_POINTS, unusual_tick_size, BASE_LOT_SIZE, MIN_ORDER_SIZE);
698+
build_initialize_market_ix(&sc, FEE_BASIS_POINTS, unusual_tick_size, BASE_LOT_SIZE, QUOTE_LOT_SIZE, MIN_ORDER_SIZE);
697699
send_transaction_from_instructions(
698700
&mut sc.svm,
699701
vec![create_ix, init_ix],
@@ -750,7 +752,7 @@ fn place_order_rejects_below_min_order_size() {
750752
let elevated_min_order_size: u64 = 10;
751753
let create_ix = build_create_order_book_account_ix(&sc, &sc.authority.pubkey());
752754
let init_ix =
753-
build_initialize_market_ix(&sc, FEE_BASIS_POINTS, TICK_SIZE, BASE_LOT_SIZE, elevated_min_order_size);
755+
build_initialize_market_ix(&sc, FEE_BASIS_POINTS, TICK_SIZE, BASE_LOT_SIZE, QUOTE_LOT_SIZE, elevated_min_order_size);
754756
send_transaction_from_instructions(
755757
&mut sc.svm,
756758
vec![create_ix, init_ix],
@@ -1087,7 +1089,7 @@ fn initialize_market_rejects_zero_tick_size() {
10871089

10881090
let zero_tick_size: u64 = 0;
10891091
let create_ix = build_create_order_book_account_ix(&sc, &sc.authority.pubkey());
1090-
let ix = build_initialize_market_ix(&sc, FEE_BASIS_POINTS, zero_tick_size, BASE_LOT_SIZE, MIN_ORDER_SIZE);
1092+
let ix = build_initialize_market_ix(&sc, FEE_BASIS_POINTS, zero_tick_size, BASE_LOT_SIZE, QUOTE_LOT_SIZE, MIN_ORDER_SIZE);
10911093
let result = send_transaction_from_instructions(
10921094
&mut sc.svm,
10931095
vec![create_ix, ix],
@@ -1108,7 +1110,7 @@ fn initialize_market_rejects_zero_base_lot_size() {
11081110
let mut sc = full_setup();
11091111

11101112
let create_ix = build_create_order_book_account_ix(&sc, &sc.authority.pubkey());
1111-
let ix = build_initialize_market_ix(&sc, FEE_BASIS_POINTS, TICK_SIZE, 0, MIN_ORDER_SIZE);
1113+
let ix = build_initialize_market_ix(&sc, FEE_BASIS_POINTS, TICK_SIZE, 0, QUOTE_LOT_SIZE, MIN_ORDER_SIZE);
11121114
let result = send_transaction_from_instructions(
11131115
&mut sc.svm,
11141116
vec![create_ix, ix],
@@ -1124,6 +1126,27 @@ fn initialize_market_rejects_zero_base_lot_size() {
11241126
assert!(result.is_err(), "base_lot_size == 0 must be rejected");
11251127
}
11261128

1129+
#[test]
1130+
fn initialize_market_rejects_zero_quote_lot_size() {
1131+
let mut sc = full_setup();
1132+
1133+
let create_ix = build_create_order_book_account_ix(&sc, &sc.authority.pubkey());
1134+
let ix = build_initialize_market_ix(&sc, FEE_BASIS_POINTS, TICK_SIZE, BASE_LOT_SIZE, 0, MIN_ORDER_SIZE);
1135+
let result = send_transaction_from_instructions(
1136+
&mut sc.svm,
1137+
vec![create_ix, ix],
1138+
&[
1139+
&sc.authority,
1140+
&sc.order_book,
1141+
&sc.base_vault,
1142+
&sc.quote_vault,
1143+
&sc.fee_vault,
1144+
],
1145+
&sc.authority.pubkey(),
1146+
);
1147+
assert!(result.is_err(), "quote_lot_size == 0 must be rejected");
1148+
}
1149+
11271150
#[test]
11281151
fn initialize_market_rejects_oversized_fee() {
11291152
let mut sc = full_setup();
@@ -1136,6 +1159,7 @@ fn initialize_market_rejects_oversized_fee() {
11361159
over_cap_fee_basis_points,
11371160
TICK_SIZE,
11381161
BASE_LOT_SIZE,
1162+
QUOTE_LOT_SIZE,
11391163
MIN_ORDER_SIZE,
11401164
);
11411165
let result = send_transaction_from_instructions(
@@ -1238,7 +1262,7 @@ fn taker_bid_fully_crosses_best_ask() {
12381262
// that trader starting balances easily cover it.
12391263
const PRICE: u64 = 1000;
12401264
const QUANTITY: u64 = 100;
1241-
const EXPECTED_GROSS_QUOTE: u64 = PRICE * QUANTITY;
1265+
const EXPECTED_GROSS_QUOTE: u64 = PRICE * QUANTITY * QUOTE_LOT_SIZE;
12421266
const EXPECTED_FEE: u64 = EXPECTED_GROSS_QUOTE * FEE_BASIS_POINTS as u64 / 10_000;
12431267
const EXPECTED_NET_TO_MAKER: u64 = EXPECTED_GROSS_QUOTE - EXPECTED_FEE;
12441268

@@ -1316,7 +1340,7 @@ fn taker_ask_fully_crosses_best_bid() {
13161340
const MAKER_BID_ID: u64 = 1;
13171341
const PRICE: u64 = 1000;
13181342
const QUANTITY: u64 = 100;
1319-
const EXPECTED_GROSS_QUOTE: u64 = PRICE * QUANTITY;
1343+
const EXPECTED_GROSS_QUOTE: u64 = PRICE * QUANTITY * QUOTE_LOT_SIZE;
13201344
const EXPECTED_FEE: u64 = EXPECTED_GROSS_QUOTE * FEE_BASIS_POINTS as u64 / 10_000;
13211345
const EXPECTED_NET_TO_TAKER: u64 = EXPECTED_GROSS_QUOTE - EXPECTED_FEE;
13221346

@@ -1618,14 +1642,13 @@ fn taker_crosses_multiple_resting_orders_best_price_first() {
16181642
assert_eq!(buyer_base, TAKER_BID_QUANTITY * BASE_LOT_SIZE);
16191643

16201644
// Price-improvement rebate: taker locked at 1000/unit but 30 units
1621-
// filled at 900. Rebate = (1000 - 900) * 30 = 3_000.
1622-
const PRICE_IMPROVEMENT_REBATE: u64 = (TAKER_BID_PRICE - BEST_ASK_PRICE) * BEST_ASK_QUANTITY;
1645+
// filled at 900. Rebate = (1000 - 900) * 30 * quote_lot_size.
1646+
const PRICE_IMPROVEMENT_REBATE: u64 = (TAKER_BID_PRICE - BEST_ASK_PRICE) * BEST_ASK_QUANTITY * QUOTE_LOT_SIZE;
16231647
assert_eq!(buyer_quote_rebate, PRICE_IMPROVEMENT_REBATE);
16241648

1625-
// Seller's net unsettled_quote = sum of (fill_price * fill_qty - fee)
1626-
// across both fills.
1627-
let gross_one: u64 = BEST_ASK_PRICE * BEST_ASK_QUANTITY;
1628-
let gross_two: u64 = SECOND_ASK_PRICE * SECOND_ASK_QUANTITY;
1649+
// Seller's net unsettled_quote = sum of (fill_price * fill_qty * quote_lot_size - fee).
1650+
let gross_one: u64 = BEST_ASK_PRICE * BEST_ASK_QUANTITY * QUOTE_LOT_SIZE;
1651+
let gross_two: u64 = SECOND_ASK_PRICE * SECOND_ASK_QUANTITY * QUOTE_LOT_SIZE;
16291652
let fee_one: u64 = gross_one * FEE_BASIS_POINTS as u64 / 10_000;
16301653
let fee_two: u64 = gross_two * FEE_BASIS_POINTS as u64 / 10_000;
16311654
let expected_seller_quote = (gross_one - fee_one) + (gross_two - fee_two);
@@ -1783,16 +1806,15 @@ fn taker_bid_gets_price_improvement_from_resting_ask() {
17831806
.unwrap();
17841807

17851808
// Maker got 900-per-unit (minus fee), not 1000.
1786-
let gross_to_maker: u64 = MAKER_ASK_PRICE * QUANTITY;
1809+
let gross_to_maker: u64 = MAKER_ASK_PRICE * QUANTITY * QUOTE_LOT_SIZE;
17871810
let fee: u64 = gross_to_maker * FEE_BASIS_POINTS as u64 / 10_000;
17881811
let expected_net_to_maker: u64 = gross_to_maker - fee;
17891812
let (_, seller_quote) = read_user_unsettled(&sc.svm, &sc.seller_market_user);
17901813
assert_eq!(seller_quote, expected_net_to_maker);
17911814

1792-
// Taker locked (TAKER_BID_PRICE * QUANTITY) of quote up front; only
1793-
// (MAKER_ASK_PRICE * QUANTITY) was spent. The difference is the
1794-
// price-improvement rebate.
1795-
let expected_rebate: u64 = (TAKER_BID_PRICE - MAKER_ASK_PRICE) * QUANTITY;
1815+
// Taker locked (TAKER_BID_PRICE * QUANTITY * QUOTE_LOT_SIZE) up front;
1816+
// only (MAKER_ASK_PRICE * QUANTITY * QUOTE_LOT_SIZE) was spent.
1817+
let expected_rebate: u64 = (TAKER_BID_PRICE - MAKER_ASK_PRICE) * QUANTITY * QUOTE_LOT_SIZE;
17961818
let (buyer_base, buyer_quote) = read_user_unsettled(&sc.svm, &sc.buyer_market_user);
17971819
assert_eq!(buyer_base, QUANTITY * BASE_LOT_SIZE);
17981820
assert_eq!(buyer_quote, expected_rebate);
@@ -1808,7 +1830,7 @@ fn fee_vault_receives_exactly_bps_of_taker_gross() {
18081830
const MAKER_ASK_ID: u64 = 1;
18091831
const PRICE: u64 = 500;
18101832
const QUANTITY: u64 = 200;
1811-
const GROSS: u64 = PRICE * QUANTITY;
1833+
const GROSS: u64 = PRICE * QUANTITY * QUOTE_LOT_SIZE;
18121834
const EXPECTED_FEE: u64 = GROSS * FEE_BASIS_POINTS as u64 / 10_000;
18131835

18141836
let __ix5 = build_place_order_ix(
@@ -1865,7 +1887,7 @@ fn authority_can_withdraw_fees_after_match() {
18651887
const MAKER_ASK_ID: u64 = 1;
18661888
const PRICE: u64 = 2000;
18671889
const QUANTITY: u64 = 50;
1868-
const GROSS: u64 = PRICE * QUANTITY;
1890+
const GROSS: u64 = PRICE * QUANTITY * QUOTE_LOT_SIZE;
18691891
const EXPECTED_FEE: u64 = GROSS * FEE_BASIS_POINTS as u64 / 10_000;
18701892

18711893
let __ix7 = build_place_order_ix(
@@ -1934,7 +1956,7 @@ fn settle_funds_after_match_pays_out_both_unsettled_balances() {
19341956
const MAKER_ASK_ID: u64 = 1;
19351957
const PRICE: u64 = 1000;
19361958
const QUANTITY: u64 = 100;
1937-
const GROSS: u64 = PRICE * QUANTITY;
1959+
const GROSS: u64 = PRICE * QUANTITY * QUOTE_LOT_SIZE;
19381960
const EXPECTED_FEE: u64 = GROSS * FEE_BASIS_POINTS as u64 / 10_000;
19391961
const EXPECTED_NET_QUOTE_TO_SELLER: u64 = GROSS - EXPECTED_FEE;
19401962

0 commit comments

Comments
 (0)