Skip to content

Commit

Permalink
Base and Quote Rebates (#323)
Browse files Browse the repository at this point in the history
* rebate

* just deep rebates

* wip rebates

* rebate tests

* update functions

* cleanup
  • Loading branch information
tonylee08 authored Feb 3, 2025
1 parent f86f0a8 commit 46c4592
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 25 deletions.
4 changes: 2 additions & 2 deletions packages/deepbook/sources/state/balances.move
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

/// `Balances` represents the three assets make up a pool: base, quote, and deep.
/// Whenever funds are moved, they are moved in the form of `Balances`.
/// `Balances` represents the three assets make up a pool: base, quote, and
/// deep. Whenever funds are moved, they are moved in the form of `Balances`.
module deepbook::balances;

use deepbook::math;
Expand Down
29 changes: 15 additions & 14 deletions packages/deepbook/sources/state/history.move
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
// SPDX-License-Identifier: Apache-2.0

/// History module tracks the volume data for the current epoch and past epochs.
/// It also tracks past trade params. Past maker fees are used to calculate fills for
/// old orders. The historic median is used to calculate rebates and burns.
/// It also tracks past trade params. Past maker fees are used to calculate
/// fills for old orders. The historic median is used to calculate rebates and
/// burns.
module deepbook::history;

use deepbook::balances::{Self, Balances};
Expand All @@ -20,7 +21,8 @@ const EHistoricVolumesNotFound: u64 = 0;
/// `Volumes` represents volume data for a single epoch.
/// Using flashloans on a whitelisted pool, assuming 1_000_000 * 1_000_000_000
/// in volume per trade, at 1 trade per millisecond, the total volume can reach
/// 1_000_000 * 1_000_000_000 * 1000 * 60 * 60 * 24 * 365 = 8.64e22 in one epoch.
/// 1_000_000 * 1_000_000_000 * 1000 * 60 * 60 * 24 * 365 = 8.64e22 in one
/// epoch.
public struct Volumes has store, copy, drop {
total_volume: u128,
total_staked_volume: u128,
Expand All @@ -39,8 +41,8 @@ public struct History has store {
}

// === Public-Package Functions ===
/// Create a new `History` instance. Called once upon pool creation. A single blank
/// `Volumes` instance is created and added to the historic_volumes table.
/// Create a new `History` instance. Called once upon pool creation. A single
/// blank `Volumes` instance is created and added to the historic_volumes table.
public(package) fun empty(
trade_params: TradeParams,
epoch_created: u64,
Expand Down Expand Up @@ -129,21 +131,20 @@ public(package) fun calculate_rebate_amount(
};
let maker_rebate_percentage = maker_rebate_percentage as u64;
let maker_volume_proportion = if (volumes.total_staked_volume > 0) {
math::div_u128(maker_volume, volumes.total_staked_volume)
(math::div_u128(maker_volume, volumes.total_staked_volume)) as u64
} else {
0
};
let maker_fee_proportion =
math::mul_u128(
maker_volume_proportion,
volumes.total_fees_collected.deep() as u128,
) as u64;
let maker_rebate = math::mul(maker_rebate_percentage, maker_fee_proportion);
let maker_burn = maker_fee_proportion - maker_rebate;
let mut max_rebates = volumes.total_fees_collected;
max_rebates.mul(maker_volume_proportion); // Maximum rebates possible
let mut rebates = max_rebates;
rebates.mul(maker_rebate_percentage); // Actual rebates

let maker_burn = max_rebates.deep() - rebates.deep();

self.balance_to_burn = self.balance_to_burn + maker_burn;

balances::new(0, 0, maker_rebate)
rebates
}

/// Updates the historic_median for past 28 epochs.
Expand Down
33 changes: 24 additions & 9 deletions packages/deepbook/tests/state/history_tests.move
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ fun test_rebate_amount() {
history.set_current_volumes(
10 * FLOAT_SCALING,
5 * FLOAT_SCALING,
balances::new(0, 0, 1_000_000_000),
balances::new(500_000, 2_500_000, 1_000_000_000),
);

// epoch 30
Expand All @@ -55,6 +55,8 @@ fun test_rebate_amount() {
(3 * FLOAT_SCALING) as u128,
1_000_000,
);
assert!(rebate.base() == 90_000, EWrongRebateAmount);
assert!(rebate.quote() == 450_000, EWrongRebateAmount);
assert!(rebate.deep() == 180_000_000, EWrongRebateAmount);

test_utils::destroy(history);
Expand All @@ -79,7 +81,7 @@ fun test_epoch_skipped() {
history.set_current_volumes(
10 * FLOAT_SCALING,
5 * FLOAT_SCALING,
balances::new(0, 0, 500_000_000),
balances::new(500_000, 2_500_000, 500_000_000),
);
epochs_to_advance = epochs_to_advance - 1;
};
Expand All @@ -91,7 +93,7 @@ fun test_epoch_skipped() {
history.set_current_volumes(
10 * FLOAT_SCALING,
5 * FLOAT_SCALING,
balances::new(0, 0, 1_000_000_000),
balances::new(500_000, 2_500_000, 1_000_000_000),
);

// epoch 31
Expand All @@ -104,20 +106,26 @@ fun test_epoch_skipped() {
0,
1_000_000,
);
assert!(rebate_epoch_0_alice.base() == 0, EWrongRebateAmount);
assert!(rebate_epoch_0_alice.quote() == 0, EWrongRebateAmount);
assert!(rebate_epoch_0_alice.deep() == 0, EWrongRebateAmount);

let rebate_epoch_1_alice = history.calculate_rebate_amount(
28,
0,
1_000_000,
);
assert!(rebate_epoch_1_alice.base() == 0, EWrongRebateAmount);
assert!(rebate_epoch_1_alice.quote() == 0, EWrongRebateAmount);
assert!(rebate_epoch_1_alice.deep() == 0, EWrongRebateAmount);

let rebate_epoch_1_bob = history.calculate_rebate_amount(
29,
(3 * FLOAT_SCALING) as u128,
1_000_000,
);
assert!(rebate_epoch_1_bob.base() == 90_000, EWrongRebateAmount);
assert!(rebate_epoch_1_bob.quote() == 450_000, EWrongRebateAmount);
assert!(rebate_epoch_1_bob.deep() == 180_000_000, EWrongRebateAmount);

test_utils::destroy(history);
Expand All @@ -141,7 +149,7 @@ fun test_other_maker_volume_above_phase_out() {
history.set_current_volumes(
10 * FLOAT_SCALING,
5 * FLOAT_SCALING,
balances::new(0, 0, 500_000_000),
balances::new(500_000, 2_500_000, 500_000_000),
);
epochs_to_advance = epochs_to_advance - 1;
};
Expand All @@ -153,7 +161,7 @@ fun test_other_maker_volume_above_phase_out() {
history.set_current_volumes(
15 * FLOAT_SCALING,
5 * FLOAT_SCALING,
balances::new(0, 0, 1_000_000_000),
balances::new(500_000, 2_500_000, 1_000_000_000),
);

// epoch 30
Expand All @@ -165,14 +173,17 @@ fun test_other_maker_volume_above_phase_out() {
(3 * FLOAT_SCALING) as u128,
1_000_000,
);
assert!(rebate.base() == 0, EWrongRebateAmount);
assert!(rebate.quote() == 0, EWrongRebateAmount);
assert!(rebate.deep() == 0, EWrongRebateAmount);

test_utils::destroy(history);
end(test);
}

#[test]
/// Pool is created on epoch 0, up till epoch 27 should still grant close to the maximum rebate.
/// Pool is created on epoch 0,
/// up till epoch 27 should still grant close to the maximum rebate.
/// Epoch 28 should return the normal rebate.
fun test_rebate_edge_epoch_ok() {
let owner: address = @0x1;
Expand All @@ -185,7 +196,7 @@ fun test_rebate_edge_epoch_ok() {
history.set_current_volumes(
10 * FLOAT_SCALING,
5 * FLOAT_SCALING,
balances::new(0, 0, 500_000_000),
balances::new(500_000, 2_500_000, 500_000_000),
);
let mut epochs_to_advance = constants::phase_out_epochs() - 1;

Expand All @@ -195,13 +206,15 @@ fun test_rebate_edge_epoch_ok() {
history.set_current_volumes(
10 * FLOAT_SCALING,
5 * FLOAT_SCALING,
balances::new(0, 0, 500_000_000),
balances::new(500_000, 2_500_000, 500_000_000),
);
let rebate = history.calculate_rebate_amount(
0,
(3 * FLOAT_SCALING) as u128,
1_000_000,
);
assert!(rebate.base() == 300_000, EWrongRebateAmount);
assert!(rebate.quote() == 1_500_000, EWrongRebateAmount);
assert!(rebate.deep() == 300_000_000, EWrongRebateAmount);
epochs_to_advance = epochs_to_advance - 1;
};
Expand All @@ -213,7 +226,7 @@ fun test_rebate_edge_epoch_ok() {
history.set_current_volumes(
10 * FLOAT_SCALING,
5 * FLOAT_SCALING,
balances::new(0, 0, 1_000_000_000),
balances::new(500_000, 1_000_000, 1_000_000_000),
);

// epoch 29
Expand All @@ -225,6 +238,8 @@ fun test_rebate_edge_epoch_ok() {
(3 * FLOAT_SCALING) as u128,
1_000_000,
);
assert!(rebate.base() == 90_000, EWrongRebateAmount);
assert!(rebate.quote() == 180_000, EWrongRebateAmount);
assert!(rebate.deep() == 180_000_000, EWrongRebateAmount);

test_utils::destroy(history);
Expand Down

0 comments on commit 46c4592

Please sign in to comment.