Revert "Bank: store interest curve scale and target util separately (#755)"

This reverts commit 3b28856692.

It should not have been in deploy since it changes instruction ABI and
has not been released in v0.20.0
This commit is contained in:
Christian Kamm 2023-11-17 07:58:41 +01:00
parent 21b8c0dbfa
commit a96fb0f614
9 changed files with 48 additions and 128 deletions

View File

@ -42,8 +42,6 @@ pub fn token_edit(
token_conditional_swap_taker_fee_rate_opt: Option<f32>,
token_conditional_swap_maker_fee_rate_opt: Option<f32>,
flash_loan_swap_fee_rate_opt: Option<f32>,
interest_curve_scaling_opt: Option<f32>,
interest_target_utilization_opt: Option<f32>,
) -> Result<()> {
let group = ctx.accounts.group.load()?;
@ -341,27 +339,6 @@ pub fn token_edit(
bank.flash_loan_swap_fee_rate = fee_rate;
require_group_admin = true;
}
if let Some(interest_curve_scaling) = interest_curve_scaling_opt {
msg!(
"Interest curve scaling old {:?}, new {:?}",
bank.interest_curve_scaling,
interest_curve_scaling
);
require_gte!(interest_curve_scaling, 1.0);
bank.interest_curve_scaling = interest_curve_scaling.into();
require_group_admin = true;
}
if let Some(interest_target_utilization) = interest_target_utilization_opt {
msg!(
"Interest target utilization old {:?}, new {:?}",
bank.interest_target_utilization,
interest_target_utilization
);
require_gte!(interest_target_utilization, 0.0);
bank.interest_target_utilization = interest_target_utilization;
require_group_admin = true;
}
}
// account constraint #1

View File

@ -38,8 +38,6 @@ pub fn token_register(
token_conditional_swap_taker_fee_rate: f32,
token_conditional_swap_maker_fee_rate: f32,
flash_loan_swap_fee_rate: f32,
interest_curve_scaling: f32,
interest_target_utilization: f32,
) -> Result<()> {
// Require token 0 to be in the insurance token
if token_index == INSURANCE_TOKEN_INDEX {
@ -109,9 +107,9 @@ pub fn token_register(
fees_withdrawn: 0,
token_conditional_swap_taker_fee_rate,
token_conditional_swap_maker_fee_rate,
flash_loan_swap_fee_rate: flash_loan_swap_fee_rate,
interest_target_utilization,
interest_curve_scaling: interest_curve_scaling.into(),
flash_loan_swap_fee_rate,
interest_target_utilization: 0.0, // unused in v0.20.0
interest_curve_scaling: 0.0, // unused in v0.20.0
deposits_in_serum: 0,
reserved: [0; 2072],
};

View File

@ -94,8 +94,8 @@ pub fn token_register_trustless(
token_conditional_swap_taker_fee_rate: 0.0005,
token_conditional_swap_maker_fee_rate: 0.0005,
flash_loan_swap_fee_rate: 0.0,
interest_target_utilization: 0.5,
interest_curve_scaling: 4.0,
interest_target_utilization: 0.0, // unused in v0.20.0
interest_curve_scaling: 0.0, // unused in v0.20.0
deposits_in_serum: 0,
reserved: [0; 2072],
};

View File

@ -2,7 +2,7 @@ use anchor_lang::prelude::*;
use crate::accounts_ix::*;
use crate::error::MangoError;
use crate::logs::{UpdateIndexLog, UpdateRateLogV2};
use crate::logs::{UpdateIndexLog, UpdateRateLog};
use crate::state::HOUR;
use crate::{
accounts_zerocopy::{AccountInfoRef, LoadMutZeroCopyRef, LoadZeroCopyRef},
@ -140,54 +140,32 @@ pub fn token_update_index_and_rate(ctx: Context<TokenUpdateIndexAndRate>) -> Res
// compute optimal rates, and max rate and set them on the bank
{
let mut some_bank = ctx.remaining_accounts[0].load_mut::<Bank>()?;
let some_bank = ctx.remaining_accounts[0].load::<Bank>()?;
let diff_ts = I80F48::from_num(now_ts - some_bank.bank_rate_last_updated);
// update each hour
if diff_ts > HOUR {
// First setup when new parameters are introduced
if some_bank.interest_curve_scaling == 0.0 {
let old_max_rate = 0.5;
some_bank.interest_curve_scaling =
some_bank.max_rate.to_num::<f64>() / old_max_rate;
some_bank.interest_target_utilization = some_bank.util0.to_num();
let (rate0, rate1, max_rate) = some_bank.compute_rates();
let descale_factor = I80F48::from_num(1.0 / some_bank.interest_curve_scaling);
some_bank.rate0 *= descale_factor;
some_bank.rate1 *= descale_factor;
some_bank.max_rate *= descale_factor;
}
some_bank.update_interest_rate_scaling();
let rate0 = some_bank.rate0;
let rate1 = some_bank.rate1;
let max_rate = some_bank.max_rate;
let scaling = some_bank.interest_curve_scaling;
let target_util = some_bank.interest_target_utilization;
emit!(UpdateRateLogV2 {
emit!(UpdateRateLog {
mango_group: mint_info.group.key(),
token_index: mint_info.token_index,
rate0: rate0.to_bits(),
util0: some_bank.util0.to_bits(),
rate1: rate1.to_bits(),
util1: some_bank.util1.to_bits(),
max_rate: max_rate.to_bits(),
curve_scaling: some_bank.interest_curve_scaling,
target_utilization: some_bank.interest_target_utilization,
});
drop(some_bank);
// Apply the new parameters to all banks
msg!("rate0 {}", rate0);
msg!("rate1 {}", rate1);
msg!("max_rate {}", max_rate);
for ai in ctx.remaining_accounts.iter() {
let mut bank = ai.load_mut::<Bank>()?;
bank.bank_rate_last_updated = now_ts;
bank.interest_curve_scaling = scaling;
bank.interest_target_utilization = target_util;
bank.rate0 = rate0;
bank.rate1 = rate1;
bank.max_rate = max_rate;

View File

@ -150,8 +150,6 @@ pub mod mango_v4 {
token_conditional_swap_taker_fee_rate: f32,
token_conditional_swap_maker_fee_rate: f32,
flash_loan_swap_fee_rate: f32,
interest_curve_scaling: f32,
interest_target_utilization: f32,
) -> Result<()> {
#[cfg(feature = "enable-gpl")]
instructions::token_register(
@ -179,8 +177,6 @@ pub mod mango_v4 {
token_conditional_swap_taker_fee_rate,
token_conditional_swap_maker_fee_rate,
flash_loan_swap_fee_rate,
interest_curve_scaling,
interest_target_utilization,
)?;
Ok(())
}
@ -225,8 +221,6 @@ pub mod mango_v4 {
token_conditional_swap_taker_fee_rate_opt: Option<f32>,
token_conditional_swap_maker_fee_rate_opt: Option<f32>,
flash_loan_swap_fee_rate_opt: Option<f32>,
interest_curve_scaling_opt: Option<f32>,
interest_target_utilization_opt: Option<f32>,
) -> Result<()> {
#[cfg(feature = "enable-gpl")]
instructions::token_edit(
@ -258,8 +252,6 @@ pub mod mango_v4 {
token_conditional_swap_taker_fee_rate_opt,
token_conditional_swap_maker_fee_rate_opt,
flash_loan_swap_fee_rate_opt,
interest_curve_scaling_opt,
interest_target_utilization_opt,
)?;
Ok(())
}

View File

@ -300,20 +300,6 @@ pub struct UpdateRateLog {
pub max_rate: i128, // I80F48
}
#[event]
pub struct UpdateRateLogV2 {
pub mango_group: Pubkey,
pub token_index: u16,
// contrary to v1 these do not have curve_scaling factored in!
pub rate0: i128, // I80F48
pub util0: i128, // I80F48
pub rate1: i128, // I80F48
pub util1: i128, // I80F48
pub max_rate: i128, // I80F48
pub curve_scaling: f64,
pub target_utilization: f32,
}
#[event]
pub struct TokenLiqWithTokenLog {
pub mango_group: Pubkey,

View File

@ -18,6 +18,7 @@ pub const DAY: i64 = 86400;
pub const DAY_I80F48: I80F48 = I80F48::from_bits(86_400 * I80F48::ONE.to_bits());
pub const ONE_BPS: I80F48 = I80F48::from_bits(28147497671);
pub const YEAR_I80F48: I80F48 = I80F48::from_bits(31_536_000 * I80F48::ONE.to_bits());
pub const MINIMUM_MAX_RATE: I80F48 = I80F48::from_bits(I80F48::ONE.to_bits() / 2);
#[derive(Derivative)]
#[derivative(Debug)]
@ -150,12 +151,12 @@ pub struct Bank {
/// Target utilization: If actual utilization is higher, scale up interest.
/// If it's lower, scale down interest (if possible)
pub interest_target_utilization: f32,
pub interest_target_utilization: f32, // unused in v0.20.0
/// Current interest curve scaling, always >= 1.0
///
/// Except when first migrating to having this field, then 0.0
pub interest_curve_scaling: f64,
pub interest_curve_scaling: f64, // unused in v0.20.0
// user deposits that were moved into serum open orders
// can be negative due to multibank, then it'd need to be balanced in the keeper
@ -262,15 +263,15 @@ impl Bank {
token_index: existing_bank.token_index,
mint_decimals: existing_bank.mint_decimals,
oracle_config: existing_bank.oracle_config,
stable_price_model: existing_bank.stable_price_model,
stable_price_model: StablePriceModel::default(),
min_vault_to_deposits_ratio: existing_bank.min_vault_to_deposits_ratio,
net_borrow_limit_per_window_quote: existing_bank.net_borrow_limit_per_window_quote,
net_borrow_limit_window_size_ts: existing_bank.net_borrow_limit_window_size_ts,
last_net_borrows_window_start_ts: existing_bank.last_net_borrows_window_start_ts,
borrow_weight_scale_start_quote: existing_bank.borrow_weight_scale_start_quote,
deposit_weight_scale_start_quote: existing_bank.deposit_weight_scale_start_quote,
reduce_only: existing_bank.reduce_only,
force_close: existing_bank.force_close,
borrow_weight_scale_start_quote: f64::MAX,
deposit_weight_scale_start_quote: f64::MAX,
reduce_only: 0,
force_close: 0,
padding: [0; 6],
token_conditional_swap_taker_fee_rate: existing_bank
.token_conditional_swap_taker_fee_rate,
@ -289,7 +290,7 @@ impl Bank {
require_gte!(self.rate0, I80F48::ZERO);
require_gte!(self.util1, I80F48::ZERO);
require_gte!(self.rate1, I80F48::ZERO);
require_gte!(self.max_rate, I80F48::ZERO);
require_gte!(self.max_rate, MINIMUM_MAX_RATE);
require_gte!(self.loan_fee_rate, 0.0);
require_gte!(self.loan_origination_fee_rate, 0.0);
require_gte!(self.maint_asset_weight, 0.0);
@ -305,8 +306,6 @@ impl Bank {
require_gte!(self.token_conditional_swap_taker_fee_rate, 0.0);
require_gte!(self.token_conditional_swap_maker_fee_rate, 0.0);
require_gte!(self.flash_loan_swap_fee_rate, 0.0);
require_gte!(self.interest_curve_scaling, 1.0);
require_gte!(self.interest_target_utilization, 0.0);
Ok(())
}
@ -816,7 +815,6 @@ impl Bank {
self.util1,
self.rate1,
self.max_rate,
self.interest_curve_scaling,
)
}
@ -830,9 +828,8 @@ impl Bank {
util1: I80F48,
rate1: I80F48,
max_rate: I80F48,
scaling: f64,
) -> I80F48 {
let v = if utilization <= util0 {
if utilization <= util0 {
let slope = rate0 / util0;
slope * utilization
} else if utilization <= util1 {
@ -843,13 +840,6 @@ impl Bank {
let extra_util = utilization - util1;
let slope = (max_rate - rate1) / (I80F48::ONE - util1);
rate1 + slope * extra_util
};
// scaling will be 0 when it's introduced
if scaling == 0.0 {
v
} else {
v * I80F48::from_num(scaling)
}
}
@ -885,23 +875,34 @@ impl Bank {
}
// computes new optimal rates and max rate
pub fn update_interest_rate_scaling(&mut self) {
// Interest increases above target_util, decreases below
let target_util = self.interest_target_utilization as f64;
pub fn compute_rates(&self) -> (I80F48, I80F48, I80F48) {
// interest rate legs 2 and 3 are seen as punitive legs, encouraging utilization to move towards optimal utilization
// lets choose util0 as optimal utilization and 0 to utli0 as the leg where we want the utlization to preferably be
let optimal_util = self.util0;
// use avg_utilization and not instantaneous_utilization so that rates cannot be manipulated easily
let avg_util = self.avg_utilization.to_num::<f64>();
let avg_util = self.avg_utilization;
// move rates up when utilization is above optimal utilization, and vice versa
// util factor is between -1 (avg util = 0) and +1 (avg util = 100%)
let util_factor = if avg_util > target_util {
(avg_util - target_util) / (1.0 - target_util)
let util_factor = if avg_util > optimal_util {
(avg_util - optimal_util) / (I80F48::ONE - optimal_util)
} else {
(avg_util - target_util) / target_util
(avg_util - optimal_util) / optimal_util
};
let adjustment = 1.0 + self.adjustment_factor.to_num::<f64>() * util_factor;
let adjustment = I80F48::ONE + self.adjustment_factor * util_factor;
self.interest_curve_scaling = (self.interest_curve_scaling * adjustment).max(1.0)
// 1. irrespective of which leg current utilization is in, update all rates
// 2. only update rates as long as new adjusted rates are above MINIMUM_MAX_RATE,
// since we don't want to fall to such low rates that it would take a long time to
// recover to high rates if utilization suddently increases to a high value
if (self.max_rate * adjustment) > MINIMUM_MAX_RATE {
(
(self.rate0 * adjustment),
(self.rate1 * adjustment),
(self.max_rate * adjustment),
)
} else {
(self.rate0, self.rate1, self.max_rate)
}
}
pub fn oracle_price(

View File

@ -997,8 +997,6 @@ impl ClientInstruction for TokenRegisterInstruction {
token_conditional_swap_taker_fee_rate: 0.0,
token_conditional_swap_maker_fee_rate: 0.0,
flash_loan_swap_fee_rate: 0.0,
interest_curve_scaling: 1.0,
interest_target_utilization: 0.5,
};
let bank = Pubkey::find_program_address(
@ -1243,8 +1241,6 @@ pub fn token_edit_instruction_default() -> mango_v4::instruction::TokenEdit {
token_conditional_swap_taker_fee_rate_opt: None,
token_conditional_swap_maker_fee_rate_opt: None,
flash_loan_swap_fee_rate_opt: None,
interest_curve_scaling_opt: None,
interest_target_utilization_opt: None,
}
}

View File

@ -25,8 +25,6 @@ export interface TokenRegisterParams {
tokenConditionalSwapTakerFeeRate: number;
tokenConditionalSwapMakerFeeRate: number;
flashLoanSwapFeeRate: number;
interestCurveScaling: number;
interestTargetUtilization: number;
}
export const DefaultTokenRegisterParams: TokenRegisterParams = {
@ -37,10 +35,10 @@ export const DefaultTokenRegisterParams: TokenRegisterParams = {
groupInsuranceFund: false,
interestRateParams: {
util0: 0.5,
rate0: 0.018,
rate0: 0.072,
util1: 0.8,
rate1: 0.05,
maxRate: 0.5,
rate1: 0.2,
maxRate: 2,
adjustmentFactor: 0.004,
},
loanFeeRate: 0.0005,
@ -62,8 +60,6 @@ export const DefaultTokenRegisterParams: TokenRegisterParams = {
tokenConditionalSwapTakerFeeRate: 0.0005,
tokenConditionalSwapMakerFeeRate: 0.0005,
flashLoanSwapFeeRate: 0.0005,
interestCurveScaling: 4.0,
interestTargetUtilization: 0.5,
};
export interface TokenEditParams {
@ -94,8 +90,6 @@ export interface TokenEditParams {
tokenConditionalSwapTakerFeeRate: number | null;
tokenConditionalSwapMakerFeeRate: number | null;
flashLoanSwapFeeRate: number | null;
interestCurveScaling: number | null;
interestTargetUtilization: number | null;
}
export const NullTokenEditParams: TokenEditParams = {
@ -126,8 +120,6 @@ export const NullTokenEditParams: TokenEditParams = {
tokenConditionalSwapTakerFeeRate: null,
tokenConditionalSwapMakerFeeRate: null,
flashLoanSwapFeeRate: null,
interestCurveScaling: null,
interestTargetUtilization: null,
};
export interface PerpEditParams {