axelar-cgp-sui

Module 0x0::history

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.

use 0x0::balances;
use 0x0::constants;
use 0x0::math;
use 0x0::trade_params;
use 0x1::u128;
use 0x2::table;
use 0x2::tx_context;

Struct Volumes

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.

struct Volumes has copy, drop, store
Fields
total_volume: u128
total_staked_volume: u128
total_fees_collected: balances::Balances
historic_median: u128
trade_params: trade_params::TradeParams

Struct History

History represents the volume data for the current epoch and past epochs.

struct History has store
Fields
epoch: u64
epoch_created: u64
volumes: history::Volumes
historic_volumes: table::Table<u64, history::Volumes>
balance_to_burn: u64

Constants

const EHistoricVolumesNotFound: u64 = 0;

Function empty

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(friend) fun empty(trade_params: trade_params::TradeParams, epoch_created: u64, ctx: &mut tx_context::TxContext): history::History
Implementation
public(package) fun empty(
    trade_params: TradeParams,
    epoch_created: u64,
    ctx: &mut TxContext,
): History {
    let volumes = Volumes {
        total_volume: 0,
        total_staked_volume: 0,
        total_fees_collected: balances::empty(),
        historic_median: 0,
        trade_params,
    };
    let mut history = History {
        epoch: ctx.epoch(),
        epoch_created,
        volumes,
        historic_volumes: table::new(ctx),
        balance_to_burn: 0,
    };
    history.historic_volumes.add(ctx.epoch(), volumes);

    history
}

Function update

Update the epoch if it has changed. If there are accounts with rebates, add the current epoch’s volume data to the historic volumes.

public(friend) fun update(self: &mut history::History, trade_params: trade_params::TradeParams, ctx: &tx_context::TxContext)
Implementation
public(package) fun update(
    self: &mut History,
    trade_params: TradeParams,
    ctx: &TxContext,
) {
    let epoch = ctx.epoch();
    if (self.epoch == epoch) return;
    if (self.historic_volumes.contains(self.epoch)) {
        self.historic_volumes.remove(self.epoch);
    };
    self.update_historic_median();
    self.historic_volumes.add(self.epoch, self.volumes);

    self.epoch = epoch;
    self.reset_volumes(trade_params);
    self.historic_volumes.add(self.epoch, self.volumes);
}

Function reset_volumes

Reset the current epoch’s volume data.

public(friend) fun reset_volumes(self: &mut history::History, trade_params: trade_params::TradeParams)
Implementation
public(package) fun reset_volumes(
    self: &mut History,
    trade_params: TradeParams,
) {
    self.volumes =
        Volumes {
            total_volume: 0,
            total_staked_volume: 0,
            total_fees_collected: balances::empty(),
            historic_median: 0,
            trade_params,
        };
}

Function calculate_rebate_amount

Given the epoch’s volume data and the account’s volume data, calculate and returns rebate amount, updates the burn amount.

public(friend) fun calculate_rebate_amount(self: &mut history::History, prev_epoch: u64, maker_volume: u128, account_stake: u64): balances::Balances
Implementation
public(package) fun calculate_rebate_amount(
    self: &mut History,
    prev_epoch: u64,
    maker_volume: u128,
    account_stake: u64,
): Balances {
    assert!(
        self.historic_volumes.contains(prev_epoch),
        EHistoricVolumesNotFound,
    );
    let volumes = &mut self.historic_volumes[prev_epoch];
    if (volumes.trade_params.stake_required() > account_stake) {
        return balances::empty()
    };

    let maker_volume = maker_volume as u128;
    let other_maker_liquidity = volumes.total_volume - maker_volume;
    let maker_rebate_percentage = if (volumes.historic_median > 0) {
        constants::float_scaling_u128() - constants::float_scaling_u128().min(
            math::div_u128(other_maker_liquidity, volumes.historic_median),
        )
    } else {
        0
    };
    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)
    } 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;

    self.balance_to_burn = self.balance_to_burn + maker_burn;

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

Function update_historic_median

Updates the historic_median for past 28 epochs.

public(friend) fun update_historic_median(self: &mut history::History)
Implementation
public(package) fun update_historic_median(self: &mut History) {
    let epochs_since_creation = self.epoch - self.epoch_created;
    if (epochs_since_creation < constants::phase_out_epochs()) {
        self.volumes.historic_median = constants::max_u128();
        return
    };
    let mut median_vec = vector<u128>[];
    let mut i = self.epoch - constants::phase_out_epochs();
    while (i < self.epoch) {
        if (self.historic_volumes.contains(i)) {
            median_vec.push_back(self.historic_volumes[i].total_volume);
        } else {
            median_vec.push_back(0);
        };
        i = i + 1;
    };

    self.volumes.historic_median = math::median(median_vec);
}

Function add_volume

Add volume to the current epoch’s volume data. Increments the total volume and total staked volume.

public(friend) fun add_volume(self: &mut history::History, maker_volume: u64, account_stake: u64)
Implementation
public(package) fun add_volume(
    self: &mut History,
    maker_volume: u64,
    account_stake: u64,
) {
    if (maker_volume == 0) return;

    let maker_volume = maker_volume as u128;
    self.volumes.total_volume = self.volumes.total_volume + maker_volume;
    if (account_stake >= self.volumes.trade_params.stake_required()) {
        self.volumes.total_staked_volume =
            self.volumes.total_staked_volume + maker_volume;
    };
}

Function balance_to_burn

public(friend) fun balance_to_burn(self: &history::History): u64
Implementation
public(package) fun balance_to_burn(self: &History): u64 {
    self.balance_to_burn
}

Function reset_balance_to_burn

public(friend) fun reset_balance_to_burn(self: &mut history::History): u64
Implementation
public(package) fun reset_balance_to_burn(self: &mut History): u64 {
    let balance_to_burn = self.balance_to_burn;
    self.balance_to_burn = 0;

    balance_to_burn
}

Function historic_maker_fee

public(friend) fun historic_maker_fee(self: &history::History, epoch: u64): u64
Implementation
public(package) fun historic_maker_fee(self: &History, epoch: u64): u64 {
    assert!(self.historic_volumes.contains(epoch), EHistoricVolumesNotFound);

    self.historic_volumes[epoch].trade_params.maker_fee()
}

Function add_total_fees_collected

public(friend) fun add_total_fees_collected(self: &mut history::History, fees: balances::Balances)
Implementation
public(package) fun add_total_fees_collected(
    self: &mut History,
    fees: Balances,
) {
    self.volumes.total_fees_collected.add_balances(fees);
}