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
|
||||
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(())
|
||||
|
|
|
@ -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.
|
||||
//
|
||||
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 {
|
||||
|
|
|
@ -170,7 +170,16 @@ pub fn token_liq_bankruptcy(
|
|||
let (liqor_quote, liqor_quote_raw_token_index, _) =
|
||||
liqor.ensure_token_position(QUOTE_TOKEN_INDEX)?;
|
||||
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
|
||||
let (liqor_liab, liqor_liab_raw_token_index, _) =
|
||||
|
@ -178,6 +187,16 @@ pub fn token_liq_bankruptcy(
|
|||
let (liqor_liab_active, loan_origination_fee) =
|
||||
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
|
||||
if !liqor.fixed.is_in_health_region() {
|
||||
let liqor_health =
|
||||
|
@ -185,16 +204,6 @@ pub fn token_liq_bankruptcy(
|
|||
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() {
|
||||
emit!(WithdrawLoanOriginationFeeLog {
|
||||
mango_group: ctx.accounts.group.key(),
|
||||
|
@ -206,10 +215,16 @@ pub fn token_liq_bankruptcy(
|
|||
}
|
||||
|
||||
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 {
|
||||
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 {
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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
|
||||
emit!(TokenBalanceLog {
|
||||
mango_group: ctx.accounts.group.key(),
|
||||
|
@ -297,7 +302,7 @@ pub fn token_liq_bankruptcy(
|
|||
.maybe_recover_from_being_liquidated(liqee_init_health);
|
||||
|
||||
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 {
|
||||
|
|
|
@ -143,24 +143,24 @@ pub fn token_liq_with_token(
|
|||
// 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_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, _) =
|
||||
liqor.ensure_token_position(liab_token_index)?;
|
||||
let (liqor_liab_active, loan_origination_fee) =
|
||||
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 (liqor_asset_position, liqor_asset_raw_index, _) =
|
||||
liqor.ensure_token_position(asset_token_index)?;
|
||||
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_active =
|
||||
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);
|
||||
|
||||
// Update the health cache
|
||||
|
@ -184,7 +184,7 @@ pub fn token_liq_with_token(
|
|||
mango_group: ctx.accounts.group.key(),
|
||||
mango_account: ctx.accounts.liqee.key(),
|
||||
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(),
|
||||
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_account: ctx.accounts.liqee.key(),
|
||||
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(),
|
||||
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_account: ctx.accounts.liqor.key(),
|
||||
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(),
|
||||
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_account: ctx.accounts.liqor.key(),
|
||||
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(),
|
||||
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
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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
|
||||
|
|
|
@ -152,7 +152,7 @@ pub fn token_withdraw(ctx: Context<TokenWithdraw>, amount: u64, allow_borrow: bo
|
|||
// deactivated.
|
||||
//
|
||||
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 {
|
||||
|
|
|
@ -207,3 +207,12 @@ pub struct LiquidateTokenBankruptcyLog {
|
|||
pub insurance_transfer: 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> {
|
||||
require_gte!(native_amount, 0);
|
||||
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
|
||||
// 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
|
||||
cm!(self.indexed_borrows -= indexed_change);
|
||||
position.indexed_position = new_indexed_value;
|
||||
self.update_cumulative_interest(position, opening_indexed_position);
|
||||
return Ok(true);
|
||||
} else if new_native_position < I80F48::ONE && allow_dusting {
|
||||
// if there's less than one token deposited, zero the position
|
||||
cm!(self.dust += new_native_position);
|
||||
cm!(self.indexed_borrows += position.indexed_position);
|
||||
position.indexed_position = I80F48::ZERO;
|
||||
self.update_cumulative_interest(position, opening_indexed_position);
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
|
@ -256,6 +259,7 @@ impl Bank {
|
|||
let indexed_change = div_rounding_up(native_amount, self.deposit_index);
|
||||
cm!(self.indexed_deposits += indexed_change);
|
||||
cm!(position.indexed_position += indexed_change);
|
||||
self.update_cumulative_interest(position, opening_indexed_position);
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
@ -317,6 +321,7 @@ impl Bank {
|
|||
) -> Result<(bool, I80F48)> {
|
||||
require_gte!(native_amount, 0);
|
||||
let native_position = position.native(self);
|
||||
let opening_indexed_position = position.indexed_position;
|
||||
|
||||
if native_position.is_positive() {
|
||||
let new_native_position = cm!(native_position - native_amount);
|
||||
|
@ -327,12 +332,14 @@ impl Bank {
|
|||
cm!(self.dust += new_native_position);
|
||||
cm!(self.indexed_deposits -= position.indexed_position);
|
||||
position.indexed_position = I80F48::ZERO;
|
||||
self.update_cumulative_interest(position, opening_indexed_position);
|
||||
return Ok((false, I80F48::ZERO));
|
||||
} else {
|
||||
// withdraw some deposits leaving a positive balance
|
||||
let indexed_change = cm!(native_amount / self.deposit_index);
|
||||
cm!(self.indexed_deposits -= indexed_change);
|
||||
cm!(position.indexed_position -= indexed_change);
|
||||
self.update_cumulative_interest(position, opening_indexed_position);
|
||||
return Ok((true, I80F48::ZERO));
|
||||
}
|
||||
}
|
||||
|
@ -355,6 +362,7 @@ impl Bank {
|
|||
let indexed_change = cm!(native_amount / self.borrow_index);
|
||||
cm!(self.indexed_borrows += indexed_change);
|
||||
cm!(position.indexed_position -= indexed_change);
|
||||
self.update_cumulative_interest(position, opening_indexed_position);
|
||||
|
||||
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(
|
||||
&self,
|
||||
indexed_total_deposits: I80F48,
|
||||
|
@ -634,8 +666,11 @@ mod tests {
|
|||
indexed_position: I80F48::ZERO,
|
||||
token_index: 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(),
|
||||
reserved: [0; 40],
|
||||
reserved: [0; 16],
|
||||
};
|
||||
|
||||
account.indexed_position = indexed(I80F48::from_num(start), &bank);
|
||||
|
|
|
@ -24,6 +24,7 @@ use super::TokenIndex;
|
|||
use super::FREE_ORDER_SLOT;
|
||||
use super::{HealthCache, HealthType};
|
||||
use super::{PerpPosition, Serum3Orders, TokenPosition};
|
||||
use crate::logs::DeactivateTokenPositionLog;
|
||||
use checked_math as cm;
|
||||
|
||||
type BorshVecLength = u32;
|
||||
|
@ -72,10 +73,12 @@ pub struct MangoAccount {
|
|||
|
||||
pub padding: [u8; 1],
|
||||
|
||||
// (Display only)
|
||||
// Cumulative (deposits - withdraws)
|
||||
// using USD prices at the time of the deposit/withdraw
|
||||
// in USD units with 6 decimals
|
||||
pub net_deposits: i64,
|
||||
// (Display only)
|
||||
// Cumulative settles on perp positions
|
||||
// TODO: unimplemented
|
||||
pub net_settled: i64,
|
||||
|
@ -616,8 +619,11 @@ impl<
|
|||
indexed_position: I80F48::ZERO,
|
||||
token_index,
|
||||
in_use_count: 0,
|
||||
cumulative_deposit_interest: 0.0,
|
||||
cumulative_borrow_interest: 0.0,
|
||||
previous_index: I80F48::ZERO,
|
||||
padding: Default::default(),
|
||||
reserved: [0; 40],
|
||||
reserved: [0; 16],
|
||||
};
|
||||
}
|
||||
Ok((v, raw_index, bank_index))
|
||||
|
@ -632,6 +638,24 @@ impl<
|
|||
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
|
||||
pub fn serum3_orders_mut_by_raw_index(&mut self, raw_index: usize) -> &mut Serum3Orders {
|
||||
let offset = self.header().serum3_offset(raw_index);
|
||||
|
|
|
@ -32,13 +32,24 @@ pub struct TokenPosition {
|
|||
pub padding: [u8; 5],
|
||||
|
||||
#[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::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);
|
||||
|
||||
impl Default for TokenPosition {
|
||||
|
@ -47,8 +58,11 @@ impl Default for TokenPosition {
|
|||
indexed_position: I80F48::ZERO,
|
||||
token_index: TokenIndex::MAX,
|
||||
in_use_count: 0,
|
||||
cumulative_deposit_interest: 0.0,
|
||||
cumulative_borrow_interest: 0.0,
|
||||
previous_index: I80F48::ZERO,
|
||||
padding: Default::default(),
|
||||
reserved: [0; 40],
|
||||
reserved: [0; 16],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4487,9 +4487,23 @@ export type MangoV4 = {
|
|||
"type": {
|
||||
"array": [
|
||||
"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
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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": [
|
||||
|
@ -10588,9 +10632,23 @@ export const IDL: MangoV4 = {
|
|||
"type": {
|
||||
"array": [
|
||||
"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
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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": [
|
||||
|
|
Loading…
Reference in New Issue