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

bigz/fix-amm-revenue-pool-transfer-last-settle-ts #447

Merged
merged 8 commits into from
Apr 28, 2023
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
235 changes: 136 additions & 99 deletions programs/drift/src/controller/amm.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::cmp::{max, min};
use std::cmp::{max, min, Ordering};

use anchor_lang::prelude::*;
use solana_program::msg;
Expand Down Expand Up @@ -382,6 +382,103 @@ pub fn get_fee_pool_tokens(
)?
.cast()
}
fn calculate_revenue_pool_transfer(
0xbigz marked this conversation as resolved.
Show resolved Hide resolved
market: &PerpMarket,
spot_market: &SpotMarket,
amm_fee_pool_token_amount_after: u128,
terminal_state_surplus: i128,
) -> DriftResult<i128> {
// Calculates the revenue pool transfer amount for a given market state (positive = send to revenue pool, negative = pull from revenue pool)
// If the AMM budget is above `FEE_POOL_TO_REVENUE_POOL_THRESHOLD` (in surplus), settle fees collected to the revenue pool depending on the health of the AMM state
// Otherwise, spull from the revenue pool (up to a constraint amount)

let amm_budget_surplus =
terminal_state_surplus.saturating_sub(FEE_POOL_TO_REVENUE_POOL_THRESHOLD.cast()?);

if amm_budget_surplus > 0 {
let fee_pool_threshold = amm_fee_pool_token_amount_after
.saturating_sub(
FEE_POOL_TO_REVENUE_POOL_THRESHOLD
.safe_add(market.amm.total_social_loss)?
.cast()?,
)
.cast()?;

let total_liq_fees_for_revenue_pool = market
.amm
.total_liquidation_fee
.min(
market
.insurance_claim
.quote_settled_insurance
.safe_add(market.insurance_claim.quote_max_insurance)?
.cast()?,
)
.cast::<i128>()?;

let max_revenue_to_settle = market
.insurance_claim
.revenue_withdraw_since_last_settle
.safe_add(
market
.insurance_claim
.max_revenue_withdraw_per_period
.cast()?,
)?
.min(market.amm.net_revenue_since_last_funding)
.max(0);

let total_fee_for_if = get_total_fee_lower_bound(market)?.cast::<i128>()?;

let revenue_pool_transfer = total_fee_for_if
.safe_add(total_liq_fees_for_revenue_pool)?
.saturating_sub(market.amm.total_fee_withdrawn.cast()?)
.max(0)
.min(fee_pool_threshold)
.min(max_revenue_to_settle.cast()?);

validate!(
revenue_pool_transfer >= 0,
ErrorCode::InsufficientPerpPnlPool,
"revenue_pool_transfer negative ({})",
revenue_pool_transfer
)?;

Ok(revenue_pool_transfer)
} else if amm_budget_surplus < 0 {
let max_revenue_withdraw_allowed = market
.insurance_claim
.max_revenue_withdraw_per_period
.cast::<i64>()?
.saturating_sub(market.insurance_claim.revenue_withdraw_since_last_settle)
.cast::<u128>()?
.min(
get_token_amount(
spot_market.revenue_pool.scaled_balance,
spot_market,
&SpotBalanceType::Deposit,
)?
.cast()?,
)
.min(
market
.insurance_claim
.max_revenue_withdraw_per_period
.cast()?,
);

if max_revenue_withdraw_allowed > 0 {
let revenue_pool_transfer = -(amm_budget_surplus
.abs()
.min(max_revenue_withdraw_allowed.cast()?));
Ok(revenue_pool_transfer)
} else {
Ok(0)
}
} else {
Ok(0)
}
}

pub fn update_pool_balances(
market: &mut PerpMarket,
Expand Down Expand Up @@ -466,121 +563,61 @@ pub fn update_pool_balances(
.total_fee_minus_distributions
.safe_sub(market.amm.total_fee_withdrawn.cast()?)?;

if terminal_state_surplus < FEE_POOL_TO_REVENUE_POOL_THRESHOLD.cast()? {
// market can perform withdraw from revenue pool
if spot_market.insurance_fund.last_revenue_settle_ts
> market.insurance_claim.last_revenue_withdraw_ts
{
validate!(now >= market.insurance_claim.last_revenue_withdraw_ts && now >= spot_market.insurance_fund.last_revenue_settle_ts,
ErrorCode::BlockchainClockInconsistency,
"issue with clock unix timestamp {} < market.insurance_claim.last_revenue_withdraw_ts={}/spot_market.last_revenue_settle_ts={}",
now,
market.insurance_claim.last_revenue_withdraw_ts,
spot_market.insurance_fund.last_revenue_settle_ts,
)?;
market.insurance_claim.revenue_withdraw_since_last_settle = 0;
}
// market can perform withdraw from revenue pool
if spot_market.insurance_fund.last_revenue_settle_ts
> market.insurance_claim.last_revenue_withdraw_ts
{
validate!(now >= market.insurance_claim.last_revenue_withdraw_ts && now >= spot_market.insurance_fund.last_revenue_settle_ts,
ErrorCode::BlockchainClockInconsistency,
"issue with clock unix timestamp {} < market.insurance_claim.last_revenue_withdraw_ts={}/spot_market.last_revenue_settle_ts={}",
now,
market.insurance_claim.last_revenue_withdraw_ts,
spot_market.insurance_fund.last_revenue_settle_ts,
)?;
market.insurance_claim.revenue_withdraw_since_last_settle = 0;
}

let max_revenue_withdraw_allowed = market
.insurance_claim
.max_revenue_withdraw_per_period
.cast::<i64>()?
.safe_sub(market.insurance_claim.revenue_withdraw_since_last_settle)?
.cast::<u128>()?;
let revenue_pool_transfer = calculate_revenue_pool_transfer(
&market,
&spot_market,
amm_fee_pool_token_amount_after,
terminal_state_surplus,
)?;

if max_revenue_withdraw_allowed > 0 {
let spot_market_revenue_pool_amount = get_token_amount(
spot_market.revenue_pool.scaled_balance,
match revenue_pool_transfer.cmp(&0) {
Ordering::Greater => {
transfer_spot_balance_to_revenue_pool(
revenue_pool_transfer.unsigned_abs(),
spot_market,
&SpotBalanceType::Deposit,
&mut market.amm.fee_pool,
)?;

let revenue_pool_transfer: u128 = terminal_state_surplus
.safe_sub(FEE_POOL_TO_REVENUE_POOL_THRESHOLD.cast()?)?
.unsigned_abs()
.min(spot_market_revenue_pool_amount)
.min(max_revenue_withdraw_allowed);

market.amm.total_fee_withdrawn = market
.amm
.total_fee_withdrawn
.safe_add(revenue_pool_transfer.unsigned_abs())?;
}
Ordering::Less => {
transfer_revenue_pool_to_spot_balance(
revenue_pool_transfer,
revenue_pool_transfer.unsigned_abs(),
spot_market,
&mut market.amm.fee_pool,
)?;

market.amm.total_fee_minus_distributions = market
.amm
.total_fee_minus_distributions
.safe_add(revenue_pool_transfer.cast::<i128>()?)?;

market.insurance_claim.revenue_withdraw_since_last_settle = market
.insurance_claim
.revenue_withdraw_since_last_settle
.safe_add(revenue_pool_transfer.cast()?)?;

market.insurance_claim.last_revenue_withdraw_ts = now;
}
} else {
let fee_pool_threshold = amm_fee_pool_token_amount_after
.saturating_sub(
FEE_POOL_TO_REVENUE_POOL_THRESHOLD.safe_add(market.amm.total_social_loss)?,
)
.cast()?;
Ordering::Equal => (),
}

let total_liq_fees_for_revenue_pool: i128 = market
if revenue_pool_transfer != 0 {
market.amm.total_fee_minus_distributions = market
.amm
.total_liquidation_fee
.min(
market
.insurance_claim
.quote_settled_insurance
.safe_add(market.insurance_claim.quote_max_insurance)?
.cast()?,
)
.cast()?;

let max_revenue_to_settle = market
.insurance_claim
.revenue_withdraw_since_last_settle
.safe_add(
market
.insurance_claim
.max_revenue_withdraw_per_period
.cast()?,
)?
.min(market.amm.net_revenue_since_last_funding)
.max(0);

let total_fee_for_if = get_total_fee_lower_bound(market)?.cast::<i128>()?;

let revenue_pool_transfer = total_fee_for_if
.safe_add(total_liq_fees_for_revenue_pool)?
.safe_sub(market.amm.total_fee_withdrawn.cast()?)?
.max(0)
.min(fee_pool_threshold)
.min(max_revenue_to_settle.cast()?);

validate!(
revenue_pool_transfer >= 0,
ErrorCode::InsufficientPerpPnlPool,
"revenue_pool_transfer negative ({})",
revenue_pool_transfer,
)?;

transfer_spot_balance_to_revenue_pool(
revenue_pool_transfer.unsigned_abs(),
spot_market,
&mut market.amm.fee_pool,
)?;
.total_fee_minus_distributions
.safe_sub(revenue_pool_transfer)?;

market.insurance_claim.revenue_withdraw_since_last_settle = market
.insurance_claim
.revenue_withdraw_since_last_settle
.safe_sub(revenue_pool_transfer.cast()?)?;

market.amm.total_fee_withdrawn = market
.amm
.total_fee_withdrawn
.safe_add(revenue_pool_transfer.unsigned_abs())?;
market.insurance_claim.last_revenue_withdraw_ts = now;
}
}

Expand Down
Loading