Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Base and Quote Rebates #323

Merged
merged 6 commits into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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