Clarkeni/onchain interest (#244)
* Onchain interest calculation * Fix to TokenBalanceLog for token_liq_bankruptcy (was previously using liqee liab position for liqor liab position). * Log cumulative interest when token position is deactivated.
This commit is contained in:
parent
984695e8d0
commit
01a958cd22
|
@ -394,7 +394,7 @@ pub fn flash_loan_end<'key, 'accounts, 'remaining, 'info>(
|
||||||
|
|
||||||
// Deactivate inactive token accounts after health check
|
// Deactivate inactive token accounts after health check
|
||||||
for raw_token_index in deactivated_token_positions {
|
for raw_token_index in deactivated_token_positions {
|
||||||
account.deactivate_token_position(raw_token_index);
|
account.deactivate_token_position_and_log(raw_token_index, ctx.accounts.account.key());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -112,7 +112,7 @@ pub fn token_deposit(ctx: Context<TokenDeposit>, amount: u64) -> Result<()> {
|
||||||
// Deposits can deactivate a position if they cancel out a previous borrow.
|
// Deposits can deactivate a position if they cancel out a previous borrow.
|
||||||
//
|
//
|
||||||
if !position_is_active {
|
if !position_is_active {
|
||||||
account.deactivate_token_position(raw_token_index);
|
account.deactivate_token_position_and_log(raw_token_index, ctx.accounts.account.key());
|
||||||
}
|
}
|
||||||
|
|
||||||
emit!(DepositLog {
|
emit!(DepositLog {
|
||||||
|
|
|
@ -170,7 +170,16 @@ pub fn token_liq_bankruptcy(
|
||||||
let (liqor_quote, liqor_quote_raw_token_index, _) =
|
let (liqor_quote, liqor_quote_raw_token_index, _) =
|
||||||
liqor.ensure_token_position(QUOTE_TOKEN_INDEX)?;
|
liqor.ensure_token_position(QUOTE_TOKEN_INDEX)?;
|
||||||
let liqor_quote_active = quote_bank.deposit(liqor_quote, insurance_transfer_i80f48)?;
|
let liqor_quote_active = quote_bank.deposit(liqor_quote, insurance_transfer_i80f48)?;
|
||||||
let liqor_quote_indexed_position = liqor_quote.indexed_position;
|
|
||||||
|
// liqor quote
|
||||||
|
emit!(TokenBalanceLog {
|
||||||
|
mango_group: ctx.accounts.group.key(),
|
||||||
|
mango_account: ctx.accounts.liqor.key(),
|
||||||
|
token_index: QUOTE_TOKEN_INDEX,
|
||||||
|
indexed_position: liqor_quote.indexed_position.to_bits(),
|
||||||
|
deposit_index: quote_deposit_index.to_bits(),
|
||||||
|
borrow_index: quote_borrow_index.to_bits(),
|
||||||
|
});
|
||||||
|
|
||||||
// transfer liab from liqee to liqor
|
// transfer liab from liqee to liqor
|
||||||
let (liqor_liab, liqor_liab_raw_token_index, _) =
|
let (liqor_liab, liqor_liab_raw_token_index, _) =
|
||||||
|
@ -178,6 +187,16 @@ pub fn token_liq_bankruptcy(
|
||||||
let (liqor_liab_active, loan_origination_fee) =
|
let (liqor_liab_active, loan_origination_fee) =
|
||||||
liab_bank.withdraw_with_fee(liqor_liab, liab_transfer)?;
|
liab_bank.withdraw_with_fee(liqor_liab, liab_transfer)?;
|
||||||
|
|
||||||
|
// liqor liab
|
||||||
|
emit!(TokenBalanceLog {
|
||||||
|
mango_group: ctx.accounts.group.key(),
|
||||||
|
mango_account: ctx.accounts.liqor.key(),
|
||||||
|
token_index: liab_token_index,
|
||||||
|
indexed_position: liqor_liab.indexed_position.to_bits(),
|
||||||
|
deposit_index: liab_deposit_index.to_bits(),
|
||||||
|
borrow_index: liab_borrow_index.to_bits(),
|
||||||
|
});
|
||||||
|
|
||||||
// Check liqor's health
|
// Check liqor's health
|
||||||
if !liqor.fixed.is_in_health_region() {
|
if !liqor.fixed.is_in_health_region() {
|
||||||
let liqor_health =
|
let liqor_health =
|
||||||
|
@ -185,16 +204,6 @@ pub fn token_liq_bankruptcy(
|
||||||
require!(liqor_health >= 0, MangoError::HealthMustBePositive);
|
require!(liqor_health >= 0, MangoError::HealthMustBePositive);
|
||||||
}
|
}
|
||||||
|
|
||||||
// liqor quote
|
|
||||||
emit!(TokenBalanceLog {
|
|
||||||
mango_group: ctx.accounts.group.key(),
|
|
||||||
mango_account: ctx.accounts.liqor.key(),
|
|
||||||
token_index: QUOTE_TOKEN_INDEX,
|
|
||||||
indexed_position: liqor_quote_indexed_position.to_bits(),
|
|
||||||
deposit_index: quote_deposit_index.to_bits(),
|
|
||||||
borrow_index: quote_borrow_index.to_bits(),
|
|
||||||
});
|
|
||||||
|
|
||||||
if loan_origination_fee.is_positive() {
|
if loan_origination_fee.is_positive() {
|
||||||
emit!(WithdrawLoanOriginationFeeLog {
|
emit!(WithdrawLoanOriginationFeeLog {
|
||||||
mango_group: ctx.accounts.group.key(),
|
mango_group: ctx.accounts.group.key(),
|
||||||
|
@ -206,10 +215,16 @@ pub fn token_liq_bankruptcy(
|
||||||
}
|
}
|
||||||
|
|
||||||
if !liqor_quote_active {
|
if !liqor_quote_active {
|
||||||
liqor.deactivate_token_position(liqor_quote_raw_token_index);
|
liqor.deactivate_token_position_and_log(
|
||||||
|
liqor_quote_raw_token_index,
|
||||||
|
ctx.accounts.liqor.key(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if !liqor_liab_active {
|
if !liqor_liab_active {
|
||||||
liqor.deactivate_token_position(liqor_liab_raw_token_index);
|
liqor.deactivate_token_position_and_log(
|
||||||
|
liqor_liab_raw_token_index,
|
||||||
|
ctx.accounts.liqor.key(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// For liab_token_index == QUOTE_TOKEN_INDEX: the insurance fund deposits directly into liqee,
|
// For liab_token_index == QUOTE_TOKEN_INDEX: the insurance fund deposits directly into liqee,
|
||||||
|
@ -265,16 +280,6 @@ pub fn token_liq_bankruptcy(
|
||||||
require_eq!(liqee_liab.indexed_position, I80F48::ZERO);
|
require_eq!(liqee_liab.indexed_position, I80F48::ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
// liqor liab
|
|
||||||
emit!(TokenBalanceLog {
|
|
||||||
mango_group: ctx.accounts.group.key(),
|
|
||||||
mango_account: ctx.accounts.liqor.key(),
|
|
||||||
token_index: liab_token_index,
|
|
||||||
indexed_position: liqee_liab.indexed_position.to_bits(),
|
|
||||||
deposit_index: liab_deposit_index.to_bits(),
|
|
||||||
borrow_index: liab_borrow_index.to_bits(),
|
|
||||||
});
|
|
||||||
|
|
||||||
// liqee liab
|
// liqee liab
|
||||||
emit!(TokenBalanceLog {
|
emit!(TokenBalanceLog {
|
||||||
mango_group: ctx.accounts.group.key(),
|
mango_group: ctx.accounts.group.key(),
|
||||||
|
@ -297,7 +302,7 @@ pub fn token_liq_bankruptcy(
|
||||||
.maybe_recover_from_being_liquidated(liqee_init_health);
|
.maybe_recover_from_being_liquidated(liqee_init_health);
|
||||||
|
|
||||||
if !liqee_liab_active {
|
if !liqee_liab_active {
|
||||||
liqee.deactivate_token_position(liqee_raw_token_index);
|
liqee.deactivate_token_position_and_log(liqee_raw_token_index, ctx.accounts.liqee.key());
|
||||||
}
|
}
|
||||||
|
|
||||||
emit!(LiquidateTokenBankruptcyLog {
|
emit!(LiquidateTokenBankruptcyLog {
|
||||||
|
|
|
@ -143,24 +143,24 @@ pub fn token_liq_with_token(
|
||||||
// Apply the balance changes to the liqor and liqee accounts
|
// Apply the balance changes to the liqor and liqee accounts
|
||||||
let liqee_liab_position = liqee.token_position_mut_by_raw_index(liqee_liab_raw_index);
|
let liqee_liab_position = liqee.token_position_mut_by_raw_index(liqee_liab_raw_index);
|
||||||
let liqee_liab_active = liab_bank.deposit_with_dusting(liqee_liab_position, liab_transfer)?;
|
let liqee_liab_active = liab_bank.deposit_with_dusting(liqee_liab_position, liab_transfer)?;
|
||||||
let liqee_liab_position_indexed = liqee_liab_position.indexed_position;
|
let liqee_liab_indexed_position = liqee_liab_position.indexed_position;
|
||||||
|
|
||||||
let (liqor_liab_position, liqor_liab_raw_index, _) =
|
let (liqor_liab_position, liqor_liab_raw_index, _) =
|
||||||
liqor.ensure_token_position(liab_token_index)?;
|
liqor.ensure_token_position(liab_token_index)?;
|
||||||
let (liqor_liab_active, loan_origination_fee) =
|
let (liqor_liab_active, loan_origination_fee) =
|
||||||
liab_bank.withdraw_with_fee(liqor_liab_position, liab_transfer)?;
|
liab_bank.withdraw_with_fee(liqor_liab_position, liab_transfer)?;
|
||||||
let liqor_liab_position_indexed = liqor_liab_position.indexed_position;
|
let liqor_liab_indexed_position = liqor_liab_position.indexed_position;
|
||||||
let liqee_liab_native_after = liqee_liab_position.native(liab_bank);
|
let liqee_liab_native_after = liqee_liab_position.native(liab_bank);
|
||||||
|
|
||||||
let (liqor_asset_position, liqor_asset_raw_index, _) =
|
let (liqor_asset_position, liqor_asset_raw_index, _) =
|
||||||
liqor.ensure_token_position(asset_token_index)?;
|
liqor.ensure_token_position(asset_token_index)?;
|
||||||
let liqor_asset_active = asset_bank.deposit(liqor_asset_position, asset_transfer)?;
|
let liqor_asset_active = asset_bank.deposit(liqor_asset_position, asset_transfer)?;
|
||||||
let liqor_asset_position_indexed = liqor_asset_position.indexed_position;
|
let liqor_asset_indexed_position = liqor_asset_position.indexed_position;
|
||||||
|
|
||||||
let liqee_asset_position = liqee.token_position_mut_by_raw_index(liqee_asset_raw_index);
|
let liqee_asset_position = liqee.token_position_mut_by_raw_index(liqee_asset_raw_index);
|
||||||
let liqee_asset_active =
|
let liqee_asset_active =
|
||||||
asset_bank.withdraw_without_fee_with_dusting(liqee_asset_position, asset_transfer)?;
|
asset_bank.withdraw_without_fee_with_dusting(liqee_asset_position, asset_transfer)?;
|
||||||
let liqee_asset_position_indexed = liqee_asset_position.indexed_position;
|
let liqee_asset_indexed_position = liqee_asset_position.indexed_position;
|
||||||
let liqee_assets_native_after = liqee_asset_position.native(asset_bank);
|
let liqee_assets_native_after = liqee_asset_position.native(asset_bank);
|
||||||
|
|
||||||
// Update the health cache
|
// Update the health cache
|
||||||
|
@ -184,7 +184,7 @@ pub fn token_liq_with_token(
|
||||||
mango_group: ctx.accounts.group.key(),
|
mango_group: ctx.accounts.group.key(),
|
||||||
mango_account: ctx.accounts.liqee.key(),
|
mango_account: ctx.accounts.liqee.key(),
|
||||||
token_index: asset_token_index,
|
token_index: asset_token_index,
|
||||||
indexed_position: liqee_asset_position_indexed.to_bits(),
|
indexed_position: liqee_asset_indexed_position.to_bits(),
|
||||||
deposit_index: asset_bank.deposit_index.to_bits(),
|
deposit_index: asset_bank.deposit_index.to_bits(),
|
||||||
borrow_index: asset_bank.borrow_index.to_bits(),
|
borrow_index: asset_bank.borrow_index.to_bits(),
|
||||||
});
|
});
|
||||||
|
@ -193,7 +193,7 @@ pub fn token_liq_with_token(
|
||||||
mango_group: ctx.accounts.group.key(),
|
mango_group: ctx.accounts.group.key(),
|
||||||
mango_account: ctx.accounts.liqee.key(),
|
mango_account: ctx.accounts.liqee.key(),
|
||||||
token_index: liab_token_index,
|
token_index: liab_token_index,
|
||||||
indexed_position: liqee_liab_position_indexed.to_bits(),
|
indexed_position: liqee_liab_indexed_position.to_bits(),
|
||||||
deposit_index: liab_bank.deposit_index.to_bits(),
|
deposit_index: liab_bank.deposit_index.to_bits(),
|
||||||
borrow_index: liab_bank.borrow_index.to_bits(),
|
borrow_index: liab_bank.borrow_index.to_bits(),
|
||||||
});
|
});
|
||||||
|
@ -202,7 +202,7 @@ pub fn token_liq_with_token(
|
||||||
mango_group: ctx.accounts.group.key(),
|
mango_group: ctx.accounts.group.key(),
|
||||||
mango_account: ctx.accounts.liqor.key(),
|
mango_account: ctx.accounts.liqor.key(),
|
||||||
token_index: asset_token_index,
|
token_index: asset_token_index,
|
||||||
indexed_position: liqor_asset_position_indexed.to_bits(),
|
indexed_position: liqor_asset_indexed_position.to_bits(),
|
||||||
deposit_index: asset_bank.deposit_index.to_bits(),
|
deposit_index: asset_bank.deposit_index.to_bits(),
|
||||||
borrow_index: asset_bank.borrow_index.to_bits(),
|
borrow_index: asset_bank.borrow_index.to_bits(),
|
||||||
});
|
});
|
||||||
|
@ -211,7 +211,7 @@ pub fn token_liq_with_token(
|
||||||
mango_group: ctx.accounts.group.key(),
|
mango_group: ctx.accounts.group.key(),
|
||||||
mango_account: ctx.accounts.liqor.key(),
|
mango_account: ctx.accounts.liqor.key(),
|
||||||
token_index: liab_token_index,
|
token_index: liab_token_index,
|
||||||
indexed_position: liqor_liab_position_indexed.to_bits(),
|
indexed_position: liqor_liab_indexed_position.to_bits(),
|
||||||
deposit_index: liab_bank.deposit_index.to_bits(),
|
deposit_index: liab_bank.deposit_index.to_bits(),
|
||||||
borrow_index: liab_bank.borrow_index.to_bits(),
|
borrow_index: liab_bank.borrow_index.to_bits(),
|
||||||
});
|
});
|
||||||
|
@ -228,16 +228,16 @@ pub fn token_liq_with_token(
|
||||||
|
|
||||||
// Since we use a scanning account retriever, it's safe to deactivate inactive token positions
|
// Since we use a scanning account retriever, it's safe to deactivate inactive token positions
|
||||||
if !liqee_asset_active {
|
if !liqee_asset_active {
|
||||||
liqee.deactivate_token_position(liqee_asset_raw_index);
|
liqee.deactivate_token_position_and_log(liqee_asset_raw_index, ctx.accounts.liqee.key());
|
||||||
}
|
}
|
||||||
if !liqee_liab_active {
|
if !liqee_liab_active {
|
||||||
liqee.deactivate_token_position(liqee_liab_raw_index);
|
liqee.deactivate_token_position_and_log(liqee_liab_raw_index, ctx.accounts.liqee.key());
|
||||||
}
|
}
|
||||||
if !liqor_asset_active {
|
if !liqor_asset_active {
|
||||||
liqor.deactivate_token_position(liqor_asset_raw_index);
|
liqor.deactivate_token_position_and_log(liqor_asset_raw_index, ctx.accounts.liqor.key());
|
||||||
}
|
}
|
||||||
if !liqor_liab_active {
|
if !liqor_liab_active {
|
||||||
liqor.deactivate_token_position(liqor_liab_raw_index)
|
liqor.deactivate_token_position_and_log(liqor_liab_raw_index, ctx.accounts.liqor.key())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check liqee health again
|
// Check liqee health again
|
||||||
|
|
|
@ -152,7 +152,7 @@ pub fn token_withdraw(ctx: Context<TokenWithdraw>, amount: u64, allow_borrow: bo
|
||||||
// deactivated.
|
// deactivated.
|
||||||
//
|
//
|
||||||
if !position_is_active {
|
if !position_is_active {
|
||||||
account.deactivate_token_position(raw_token_index);
|
account.deactivate_token_position_and_log(raw_token_index, ctx.accounts.account.key());
|
||||||
}
|
}
|
||||||
|
|
||||||
emit!(WithdrawLog {
|
emit!(WithdrawLog {
|
||||||
|
|
|
@ -207,3 +207,12 @@ pub struct LiquidateTokenBankruptcyLog {
|
||||||
pub insurance_transfer: i128,
|
pub insurance_transfer: i128,
|
||||||
pub socialized_loss: i128,
|
pub socialized_loss: i128,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[event]
|
||||||
|
pub struct DeactivateTokenPositionLog {
|
||||||
|
pub mango_group: Pubkey,
|
||||||
|
pub mango_account: Pubkey,
|
||||||
|
pub token_index: u16,
|
||||||
|
pub cumulative_deposit_interest: f32,
|
||||||
|
pub cumulative_borrow_interest: f32,
|
||||||
|
}
|
||||||
|
|
|
@ -210,6 +210,7 @@ impl Bank {
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
require_gte!(native_amount, 0);
|
require_gte!(native_amount, 0);
|
||||||
let native_position = position.native(self);
|
let native_position = position.native(self);
|
||||||
|
let opening_indexed_position = position.indexed_position;
|
||||||
|
|
||||||
// Adding DELTA to amount/index helps because (amount/index)*index <= amount, but
|
// Adding DELTA to amount/index helps because (amount/index)*index <= amount, but
|
||||||
// we want to ensure that users can withdraw the same amount they have deposited, so
|
// we want to ensure that users can withdraw the same amount they have deposited, so
|
||||||
|
@ -235,12 +236,14 @@ impl Bank {
|
||||||
// pay back borrows only, leaving a negative position
|
// pay back borrows only, leaving a negative position
|
||||||
cm!(self.indexed_borrows -= indexed_change);
|
cm!(self.indexed_borrows -= indexed_change);
|
||||||
position.indexed_position = new_indexed_value;
|
position.indexed_position = new_indexed_value;
|
||||||
|
self.update_cumulative_interest(position, opening_indexed_position);
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
} else if new_native_position < I80F48::ONE && allow_dusting {
|
} else if new_native_position < I80F48::ONE && allow_dusting {
|
||||||
// if there's less than one token deposited, zero the position
|
// if there's less than one token deposited, zero the position
|
||||||
cm!(self.dust += new_native_position);
|
cm!(self.dust += new_native_position);
|
||||||
cm!(self.indexed_borrows += position.indexed_position);
|
cm!(self.indexed_borrows += position.indexed_position);
|
||||||
position.indexed_position = I80F48::ZERO;
|
position.indexed_position = I80F48::ZERO;
|
||||||
|
self.update_cumulative_interest(position, opening_indexed_position);
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,6 +259,7 @@ impl Bank {
|
||||||
let indexed_change = div_rounding_up(native_amount, self.deposit_index);
|
let indexed_change = div_rounding_up(native_amount, self.deposit_index);
|
||||||
cm!(self.indexed_deposits += indexed_change);
|
cm!(self.indexed_deposits += indexed_change);
|
||||||
cm!(position.indexed_position += indexed_change);
|
cm!(position.indexed_position += indexed_change);
|
||||||
|
self.update_cumulative_interest(position, opening_indexed_position);
|
||||||
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
@ -317,6 +321,7 @@ impl Bank {
|
||||||
) -> Result<(bool, I80F48)> {
|
) -> Result<(bool, I80F48)> {
|
||||||
require_gte!(native_amount, 0);
|
require_gte!(native_amount, 0);
|
||||||
let native_position = position.native(self);
|
let native_position = position.native(self);
|
||||||
|
let opening_indexed_position = position.indexed_position;
|
||||||
|
|
||||||
if native_position.is_positive() {
|
if native_position.is_positive() {
|
||||||
let new_native_position = cm!(native_position - native_amount);
|
let new_native_position = cm!(native_position - native_amount);
|
||||||
|
@ -327,12 +332,14 @@ impl Bank {
|
||||||
cm!(self.dust += new_native_position);
|
cm!(self.dust += new_native_position);
|
||||||
cm!(self.indexed_deposits -= position.indexed_position);
|
cm!(self.indexed_deposits -= position.indexed_position);
|
||||||
position.indexed_position = I80F48::ZERO;
|
position.indexed_position = I80F48::ZERO;
|
||||||
|
self.update_cumulative_interest(position, opening_indexed_position);
|
||||||
return Ok((false, I80F48::ZERO));
|
return Ok((false, I80F48::ZERO));
|
||||||
} else {
|
} else {
|
||||||
// withdraw some deposits leaving a positive balance
|
// withdraw some deposits leaving a positive balance
|
||||||
let indexed_change = cm!(native_amount / self.deposit_index);
|
let indexed_change = cm!(native_amount / self.deposit_index);
|
||||||
cm!(self.indexed_deposits -= indexed_change);
|
cm!(self.indexed_deposits -= indexed_change);
|
||||||
cm!(position.indexed_position -= indexed_change);
|
cm!(position.indexed_position -= indexed_change);
|
||||||
|
self.update_cumulative_interest(position, opening_indexed_position);
|
||||||
return Ok((true, I80F48::ZERO));
|
return Ok((true, I80F48::ZERO));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -355,6 +362,7 @@ impl Bank {
|
||||||
let indexed_change = cm!(native_amount / self.borrow_index);
|
let indexed_change = cm!(native_amount / self.borrow_index);
|
||||||
cm!(self.indexed_borrows += indexed_change);
|
cm!(self.indexed_borrows += indexed_change);
|
||||||
cm!(position.indexed_position -= indexed_change);
|
cm!(position.indexed_position -= indexed_change);
|
||||||
|
self.update_cumulative_interest(position, opening_indexed_position);
|
||||||
|
|
||||||
Ok((true, loan_origination_fee))
|
Ok((true, loan_origination_fee))
|
||||||
}
|
}
|
||||||
|
@ -401,6 +409,30 @@ impl Bank {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_cumulative_interest(
|
||||||
|
&self,
|
||||||
|
position: &mut TokenPosition,
|
||||||
|
opening_indexed_position: I80F48,
|
||||||
|
) {
|
||||||
|
if opening_indexed_position.is_positive() {
|
||||||
|
let interest =
|
||||||
|
cm!((self.deposit_index - position.previous_index) * opening_indexed_position)
|
||||||
|
.to_num::<f32>();
|
||||||
|
position.cumulative_deposit_interest += interest;
|
||||||
|
} else {
|
||||||
|
let interest =
|
||||||
|
cm!((self.borrow_index - position.previous_index) * opening_indexed_position)
|
||||||
|
.to_num::<f32>();
|
||||||
|
position.cumulative_borrow_interest += interest;
|
||||||
|
}
|
||||||
|
|
||||||
|
if position.indexed_position.is_positive() {
|
||||||
|
position.previous_index = self.deposit_index
|
||||||
|
} else {
|
||||||
|
position.previous_index = self.borrow_index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn compute_index(
|
pub fn compute_index(
|
||||||
&self,
|
&self,
|
||||||
indexed_total_deposits: I80F48,
|
indexed_total_deposits: I80F48,
|
||||||
|
@ -634,8 +666,11 @@ mod tests {
|
||||||
indexed_position: I80F48::ZERO,
|
indexed_position: I80F48::ZERO,
|
||||||
token_index: 0,
|
token_index: 0,
|
||||||
in_use_count: if is_in_use { 1 } else { 0 },
|
in_use_count: if is_in_use { 1 } else { 0 },
|
||||||
|
cumulative_deposit_interest: 0.0,
|
||||||
|
cumulative_borrow_interest: 0.0,
|
||||||
|
previous_index: I80F48::ZERO,
|
||||||
padding: Default::default(),
|
padding: Default::default(),
|
||||||
reserved: [0; 40],
|
reserved: [0; 16],
|
||||||
};
|
};
|
||||||
|
|
||||||
account.indexed_position = indexed(I80F48::from_num(start), &bank);
|
account.indexed_position = indexed(I80F48::from_num(start), &bank);
|
||||||
|
|
|
@ -24,6 +24,7 @@ use super::TokenIndex;
|
||||||
use super::FREE_ORDER_SLOT;
|
use super::FREE_ORDER_SLOT;
|
||||||
use super::{HealthCache, HealthType};
|
use super::{HealthCache, HealthType};
|
||||||
use super::{PerpPosition, Serum3Orders, TokenPosition};
|
use super::{PerpPosition, Serum3Orders, TokenPosition};
|
||||||
|
use crate::logs::DeactivateTokenPositionLog;
|
||||||
use checked_math as cm;
|
use checked_math as cm;
|
||||||
|
|
||||||
type BorshVecLength = u32;
|
type BorshVecLength = u32;
|
||||||
|
@ -72,10 +73,12 @@ pub struct MangoAccount {
|
||||||
|
|
||||||
pub padding: [u8; 1],
|
pub padding: [u8; 1],
|
||||||
|
|
||||||
|
// (Display only)
|
||||||
// Cumulative (deposits - withdraws)
|
// Cumulative (deposits - withdraws)
|
||||||
// using USD prices at the time of the deposit/withdraw
|
// using USD prices at the time of the deposit/withdraw
|
||||||
// in USD units with 6 decimals
|
// in USD units with 6 decimals
|
||||||
pub net_deposits: i64,
|
pub net_deposits: i64,
|
||||||
|
// (Display only)
|
||||||
// Cumulative settles on perp positions
|
// Cumulative settles on perp positions
|
||||||
// TODO: unimplemented
|
// TODO: unimplemented
|
||||||
pub net_settled: i64,
|
pub net_settled: i64,
|
||||||
|
@ -616,8 +619,11 @@ impl<
|
||||||
indexed_position: I80F48::ZERO,
|
indexed_position: I80F48::ZERO,
|
||||||
token_index,
|
token_index,
|
||||||
in_use_count: 0,
|
in_use_count: 0,
|
||||||
|
cumulative_deposit_interest: 0.0,
|
||||||
|
cumulative_borrow_interest: 0.0,
|
||||||
|
previous_index: I80F48::ZERO,
|
||||||
padding: Default::default(),
|
padding: Default::default(),
|
||||||
reserved: [0; 40],
|
reserved: [0; 16],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Ok((v, raw_index, bank_index))
|
Ok((v, raw_index, bank_index))
|
||||||
|
@ -632,6 +638,24 @@ impl<
|
||||||
self.token_position_mut_by_raw_index(raw_index).token_index = TokenIndex::MAX;
|
self.token_position_mut_by_raw_index(raw_index).token_index = TokenIndex::MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deactivate_token_position_and_log(
|
||||||
|
&mut self,
|
||||||
|
raw_index: usize,
|
||||||
|
mango_account_pubkey: Pubkey,
|
||||||
|
) {
|
||||||
|
let mango_group = self.fixed.deref_or_borrow().group;
|
||||||
|
let token_position = self.token_position_mut_by_raw_index(raw_index);
|
||||||
|
assert!(token_position.in_use_count == 0);
|
||||||
|
emit!(DeactivateTokenPositionLog {
|
||||||
|
mango_group: mango_group,
|
||||||
|
mango_account: mango_account_pubkey,
|
||||||
|
token_index: token_position.token_index,
|
||||||
|
cumulative_deposit_interest: token_position.cumulative_deposit_interest,
|
||||||
|
cumulative_borrow_interest: token_position.cumulative_borrow_interest,
|
||||||
|
});
|
||||||
|
self.token_position_mut_by_raw_index(raw_index).token_index = TokenIndex::MAX;
|
||||||
|
}
|
||||||
|
|
||||||
// get mut Serum3Orders at raw_index
|
// get mut Serum3Orders at raw_index
|
||||||
pub fn serum3_orders_mut_by_raw_index(&mut self, raw_index: usize) -> &mut Serum3Orders {
|
pub fn serum3_orders_mut_by_raw_index(&mut self, raw_index: usize) -> &mut Serum3Orders {
|
||||||
let offset = self.header().serum3_offset(raw_index);
|
let offset = self.header().serum3_offset(raw_index);
|
||||||
|
|
|
@ -32,13 +32,24 @@ pub struct TokenPosition {
|
||||||
pub padding: [u8; 5],
|
pub padding: [u8; 5],
|
||||||
|
|
||||||
#[derivative(Debug = "ignore")]
|
#[derivative(Debug = "ignore")]
|
||||||
pub reserved: [u8; 40],
|
pub reserved: [u8; 16],
|
||||||
|
|
||||||
|
// bookkeeping variable for onchain interest calculation
|
||||||
|
// either deposit_index or borrow_index at last indexed_position change
|
||||||
|
pub previous_index: I80F48,
|
||||||
|
|
||||||
|
// (Display only)
|
||||||
|
// Cumulative deposit interest in token native units
|
||||||
|
pub cumulative_deposit_interest: f32,
|
||||||
|
// (Display only)
|
||||||
|
// Cumulative borrow interest in token native units
|
||||||
|
pub cumulative_borrow_interest: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl bytemuck::Pod for TokenPosition {}
|
unsafe impl bytemuck::Pod for TokenPosition {}
|
||||||
unsafe impl bytemuck::Zeroable for TokenPosition {}
|
unsafe impl bytemuck::Zeroable for TokenPosition {}
|
||||||
|
|
||||||
const_assert_eq!(size_of::<TokenPosition>(), 24 + 40);
|
const_assert_eq!(size_of::<TokenPosition>(), 64);
|
||||||
const_assert_eq!(size_of::<TokenPosition>() % 8, 0);
|
const_assert_eq!(size_of::<TokenPosition>() % 8, 0);
|
||||||
|
|
||||||
impl Default for TokenPosition {
|
impl Default for TokenPosition {
|
||||||
|
@ -47,8 +58,11 @@ impl Default for TokenPosition {
|
||||||
indexed_position: I80F48::ZERO,
|
indexed_position: I80F48::ZERO,
|
||||||
token_index: TokenIndex::MAX,
|
token_index: TokenIndex::MAX,
|
||||||
in_use_count: 0,
|
in_use_count: 0,
|
||||||
|
cumulative_deposit_interest: 0.0,
|
||||||
|
cumulative_borrow_interest: 0.0,
|
||||||
|
previous_index: I80F48::ZERO,
|
||||||
padding: Default::default(),
|
padding: Default::default(),
|
||||||
reserved: [0; 40],
|
reserved: [0; 16],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4487,9 +4487,23 @@ export type MangoV4 = {
|
||||||
"type": {
|
"type": {
|
||||||
"array": [
|
"array": [
|
||||||
"u8",
|
"u8",
|
||||||
40
|
8
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "previousIndex",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cumulativeDepositInterest",
|
||||||
|
"type": "i64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cumulativeBorrowInterest",
|
||||||
|
"type": "i64"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -5978,6 +5992,36 @@ export type MangoV4 = {
|
||||||
"index": false
|
"index": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DeactivateTokenPositionLog",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "mangoGroup",
|
||||||
|
"type": "publicKey",
|
||||||
|
"index": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mangoAccount",
|
||||||
|
"type": "publicKey",
|
||||||
|
"index": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tokenIndex",
|
||||||
|
"type": "u16",
|
||||||
|
"index": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cumulativeDepositInterest",
|
||||||
|
"type": "i64",
|
||||||
|
"index": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cumulativeBorrowInterest",
|
||||||
|
"type": "i64",
|
||||||
|
"index": false
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"errors": [
|
"errors": [
|
||||||
|
@ -10588,9 +10632,23 @@ export const IDL: MangoV4 = {
|
||||||
"type": {
|
"type": {
|
||||||
"array": [
|
"array": [
|
||||||
"u8",
|
"u8",
|
||||||
40
|
8
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "previousIndex",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cumulativeDepositInterest",
|
||||||
|
"type": "i64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cumulativeBorrowInterest",
|
||||||
|
"type": "i64"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -12079,6 +12137,36 @@ export const IDL: MangoV4 = {
|
||||||
"index": false
|
"index": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DeactivateTokenPositionLog",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "mangoGroup",
|
||||||
|
"type": "publicKey",
|
||||||
|
"index": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mangoAccount",
|
||||||
|
"type": "publicKey",
|
||||||
|
"index": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tokenIndex",
|
||||||
|
"type": "u16",
|
||||||
|
"index": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cumulativeDepositInterest",
|
||||||
|
"type": "i64",
|
||||||
|
"index": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cumulativeBorrowInterest",
|
||||||
|
"type": "i64",
|
||||||
|
"index": false
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"errors": [
|
"errors": [
|
||||||
|
|
Loading…
Reference in New Issue