use crate::{
    accounts_ix::FlashLoanType,
    state::{OracleType, PerpMarket, PerpPosition},
};
use anchor_lang::prelude::*;
use borsh::BorshSerialize;

#[inline(never)] // ensure fresh stack frame
pub fn emit_stack<T: anchor_lang::Event>(e: T) {
    use std::io::{Cursor, Write};

    // stack buffer, stack frames are 4kb
    let mut buffer = [0u8; 3000];

    let mut cursor = Cursor::new(&mut buffer[..]);
    cursor.write_all(&T::DISCRIMINATOR).unwrap();
    e.serialize(&mut cursor)
        .expect("event must fit into stack buffer");

    let pos = cursor.position() as usize;
    anchor_lang::solana_program::log::sol_log_data(&[&buffer[..pos]]);
}

pub fn emit_perp_balances(
    mango_group: Pubkey,
    mango_account: Pubkey,
    pp: &PerpPosition,
    pm: &PerpMarket,
) {
    emit_stack(PerpBalanceLog {
        mango_group,
        mango_account,
        market_index: pm.perp_market_index,
        base_position: pp.base_position_lots(),
        quote_position: pp.quote_position_native().to_bits(),
        long_settled_funding: pp.long_settled_funding.to_bits(),
        short_settled_funding: pp.short_settled_funding.to_bits(),
        long_funding: pm.long_funding.to_bits(),
        short_funding: pm.short_funding.to_bits(),
    });
}

#[event]
pub struct PerpBalanceLog {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub market_index: u16,
    pub base_position: i64,
    pub quote_position: i128,        // I80F48
    pub long_settled_funding: i128,  // I80F48
    pub short_settled_funding: i128, // I80F48
    pub long_funding: i128,          // I80F48
    pub short_funding: i128,         // I80F48
}

#[event]
pub struct TokenBalanceLog {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub token_index: u16,       // IDL doesn't support usize
    pub indexed_position: i128, // on client convert i128 to I80F48 easily by passing in the BN to I80F48 ctor
    pub deposit_index: i128,    // I80F48
    pub borrow_index: i128,     // I80F48
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct FlashLoanTokenDetail {
    pub token_index: u16,
    pub change_amount: i128,
    pub loan: i128,
    pub loan_origination_fee: i128,
    pub deposit_index: i128,
    pub borrow_index: i128,
    pub price: i128,
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct FlashLoanTokenDetailV2 {
    pub token_index: u16,

    /// The amount by which the user's token position changed at the end
    ///
    /// So if the user repaid the approved_amount in full, it'd be 0.
    ///
    /// Does NOT include the loan_origination_fee or deposit_fee, so the true
    /// change is `change_amount - loan_origination_fee - deposit_fee`.
    pub change_amount: i128,

    /// The amount that was a loan (<= approved_amount, depends on user's deposits)
    pub loan: i128,

    /// The fee paid on the loan, not included in `loan` or `change_amount`
    pub loan_origination_fee: i128,

    pub deposit_index: i128,
    pub borrow_index: i128,
    pub price: i128,

    /// Deposit fee paid for positive change_amount.
    ///
    /// Not factored into change_amount.
    pub deposit_fee: i128,

    /// The amount that was transfered out to the user
    pub approved_amount: u64,
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct FlashLoanTokenDetailV3 {
    pub token_index: u16,

    /// The amount by which the user's token position changed at the end
    ///
    /// So if the user repaid the approved_amount in full, it'd be 0.
    ///
    /// Does NOT include the loan_origination_fee or deposit_fee, so the true
    /// change is `change_amount - loan_origination_fee - deposit_fee`.
    pub change_amount: i128,

    /// The amount that was a loan (<= approved_amount, depends on user's deposits)
    pub loan: i128,

    /// The fee paid on the loan, not included in `loan` or `change_amount`
    pub loan_origination_fee: i128,

    pub deposit_index: i128,
    pub borrow_index: i128,
    pub price: i128,

    /// Swap fee paid on the in token of a swap.
    ///
    /// Not factored into change_amount.
    pub swap_fee: i128,

    /// The amount that was transfered out to the user
    pub approved_amount: u64,
}

#[event]
pub struct FlashLoanLog {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub token_loan_details: Vec<FlashLoanTokenDetail>,
    pub flash_loan_type: FlashLoanType,
}

#[event]
pub struct FlashLoanLogV2 {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub token_loan_details: Vec<FlashLoanTokenDetailV2>,
    pub flash_loan_type: FlashLoanType,
}

#[event]
pub struct FlashLoanLogV3 {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub token_loan_details: Vec<FlashLoanTokenDetailV3>,
    pub flash_loan_type: FlashLoanType,
}

#[event]
pub struct WithdrawLog {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub signer: Pubkey,
    pub token_index: u16,
    pub quantity: u64,
    pub price: i128, // I80F48
}

#[event]
pub struct DepositLog {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub signer: Pubkey,
    pub token_index: u16,
    pub quantity: u64,
    pub price: i128, // I80F48
}

#[event]
pub struct FillLog {
    pub mango_group: Pubkey,
    pub market_index: u16,
    pub taker_side: u8, // side from the taker's POV
    pub maker_slot: u8,
    pub maker_out: bool, // true if maker order quantity == 0
    pub timestamp: u64,
    pub seq_num: u64, // note: usize same as u64

    pub maker: Pubkey,
    pub maker_order_id: u128,
    pub maker_fee: i128,

    // Timestamp of when the maker order was placed; copied over from the LeafNode
    pub maker_timestamp: u64,

    pub taker: Pubkey,
    pub taker_order_id: u128,
    pub taker_client_order_id: u64,
    pub taker_fee: i128,

    pub price: i64,
    pub quantity: i64, // number of base lots
}

#[event]
pub struct FillLogV2 {
    pub mango_group: Pubkey,
    pub market_index: u16,
    pub taker_side: u8, // side from the taker's POV
    pub maker_slot: u8,
    pub maker_out: bool, // true if maker order quantity == 0
    pub timestamp: u64,
    pub seq_num: u64, // note: usize same as u64

    pub maker: Pubkey,
    pub maker_client_order_id: u64,
    pub maker_fee: f32,

    // Timestamp of when the maker order was placed; copied over from the LeafNode
    pub maker_timestamp: u64,

    pub taker: Pubkey,
    pub taker_client_order_id: u64,
    pub taker_fee: f32,

    pub price: i64,
    pub quantity: i64, // number of base lots
}

#[event]
pub struct FillLogV3 {
    pub mango_group: Pubkey,
    pub market_index: u16,
    pub taker_side: u8, // side from the taker's POV
    pub maker_slot: u8,
    pub maker_out: bool, // true if maker order quantity == 0
    pub timestamp: u64,
    pub seq_num: u64, // note: usize same as u64

    pub maker: Pubkey,
    pub maker_client_order_id: u64,
    pub maker_fee: f32,

    // Timestamp of when the maker order was placed; copied over from the LeafNode
    pub maker_timestamp: u64,

    pub taker: Pubkey,
    pub taker_client_order_id: u64,
    pub taker_fee: f32,

    pub price: i64,
    pub quantity: i64,         // number of base lots
    pub maker_closed_pnl: f64, // settle-token-native units
    pub taker_closed_pnl: f64, // settle-token-native units
}

#[event]
pub struct PerpUpdateFundingLog {
    pub mango_group: Pubkey,
    pub market_index: u16,
    pub long_funding: i128,
    pub short_funding: i128,
    pub price: i128,
    pub oracle_slot: u64,
    pub stable_price: i128,
    pub fees_accrued: i128,
    pub fees_settled: i128,
    pub open_interest: i64,
    pub instantaneous_funding_rate: i128,
}

#[event]
pub struct PerpUpdateFundingLogV2 {
    pub mango_group: Pubkey,
    pub market_index: u16,
    pub long_funding: i128,
    pub short_funding: i128,
    pub price: i128,
    pub oracle_slot: u64,
    pub oracle_confidence: i128,
    pub oracle_type: OracleType,
    pub stable_price: i128,
    pub fees_accrued: i128,
    pub fees_settled: i128,
    pub open_interest: i64,
    pub instantaneous_funding_rate: i128,
}

#[event]
pub struct UpdateIndexLog {
    pub mango_group: Pubkey,
    pub token_index: u16,
    pub deposit_index: i128,   // I80F48
    pub borrow_index: i128,    // I80F48
    pub avg_utilization: i128, // I80F48
    pub price: i128,           // I80F48
    pub stable_price: i128,    // I80F48
    pub collected_fees: i128,  // I80F48
    pub loan_fee_rate: i128,   // I80F48
    pub total_borrows: i128,
    pub total_deposits: i128,
    pub borrow_rate: i128,
    pub deposit_rate: i128,
}

#[event]
pub struct UpdateRateLog {
    pub mango_group: Pubkey,
    pub token_index: u16,
    pub rate0: i128,    // I80F48
    pub rate1: i128,    // I80F48
    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,
    pub liqee: Pubkey,
    pub liqor: Pubkey,
    pub asset_token_index: u16,
    pub liab_token_index: u16,
    pub asset_transfer: i128, // I80F48
    pub liab_transfer: i128,  // I80F48
    pub asset_price: i128,    // I80F48
    pub liab_price: i128,     // I80F48
    pub bankruptcy: bool,
}

#[event]
pub struct TokenLiqWithTokenLogV2 {
    pub mango_group: Pubkey,
    pub liqee: Pubkey,
    pub liqor: Pubkey,
    pub asset_token_index: u16,
    pub liab_token_index: u16,
    pub asset_transfer_from_liqee: i128, // I80F48
    pub asset_transfer_to_liqor: i128,   // I80F48
    pub asset_liquidation_fee: i128,     // I80F48
    pub liab_transfer: i128,             // I80F48
    pub asset_price: i128,               // I80F48
    pub liab_price: i128,                // I80F48
    pub bankruptcy: bool,
}

#[event]
pub struct Serum3OpenOrdersBalanceLog {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub base_token_index: u16,
    pub quote_token_index: u16,
    pub base_total: u64,
    pub base_free: u64,
    pub quote_total: u64,
    pub quote_free: u64,
    pub referrer_rebates_accrued: u64,
}

#[event]
pub struct Serum3OpenOrdersBalanceLogV2 {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub market_index: u16,
    pub base_token_index: u16,
    pub quote_token_index: u16,
    pub base_total: u64,
    pub base_free: u64,
    pub quote_total: u64,
    pub quote_free: u64,
    pub referrer_rebates_accrued: u64,
}

#[derive(PartialEq, Copy, Clone, Debug, AnchorSerialize, AnchorDeserialize)]
#[repr(u8)]
pub enum LoanOriginationFeeInstruction {
    Unknown,
    LiqTokenBankruptcy,
    LiqTokenWithToken,
    Serum3LiqForceCancelOrders,
    Serum3PlaceOrder,
    Serum3SettleFunds,
    TokenWithdraw,
    TokenConditionalSwapTrigger,
}

#[event]
pub struct WithdrawLoanOriginationFeeLog {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub token_index: u16,
    pub loan_origination_fee: i128, // I80F48
    pub instruction: LoanOriginationFeeInstruction,
}

#[event]
pub struct WithdrawLoanLog {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub token_index: u16,
    pub loan_amount: i128,
    pub loan_origination_fee: i128,
    pub instruction: LoanOriginationFeeInstruction,
    pub price: Option<i128>, // Ideally would log price everywhere but in serum3_settle_funds oracle is not a passed in account
}

#[event]
pub struct TokenLiqBankruptcyLog {
    pub mango_group: Pubkey,
    pub liqee: Pubkey,
    pub liqor: Pubkey,
    pub liab_token_index: u16,
    pub initial_liab_native: i128,
    pub liab_price: i128,
    pub insurance_token_index: u16,
    pub insurance_transfer: i128,
    pub socialized_loss: i128,
    pub starting_liab_deposit_index: i128,
    pub ending_liab_deposit_index: i128,
}

#[event]
pub struct DeactivateTokenPositionLog {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub token_index: u16,
    pub cumulative_deposit_interest: f64,
    pub cumulative_borrow_interest: f64,
}

#[event]
pub struct DeactivatePerpPositionLog {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub market_index: u16,
    pub cumulative_long_funding: f64,
    pub cumulative_short_funding: f64,
    pub maker_volume: u64,
    pub taker_volume: u64,
    pub perp_spot_transfers: i64,
}

#[event]
pub struct TokenMetaDataLog {
    pub mango_group: Pubkey,
    pub mint: Pubkey,
    pub token_index: u16,
    pub mint_decimals: u8,
    pub oracle: Pubkey,
    pub mint_info: Pubkey,
}

#[event]
pub struct TokenMetaDataLogV2 {
    pub mango_group: Pubkey,
    pub mint: Pubkey,
    pub token_index: u16,
    pub mint_decimals: u8,
    pub oracle: Pubkey,
    pub fallback_oracle: Pubkey,
    pub mint_info: Pubkey,
}

#[event]
pub struct PerpMarketMetaDataLog {
    pub mango_group: Pubkey,
    pub perp_market: Pubkey,
    pub perp_market_index: u16,
    pub base_decimals: u8,
    pub base_lot_size: i64,
    pub quote_lot_size: i64,
    pub oracle: Pubkey,
}

#[event]
pub struct Serum3RegisterMarketLog {
    pub mango_group: Pubkey,
    pub serum_market: Pubkey,
    pub market_index: u16,
    pub base_token_index: u16,
    pub quote_token_index: u16,
    pub serum_program: Pubkey,
    pub serum_program_external: Pubkey,
}

#[event]
pub struct PerpLiqBaseOrPositivePnlLog {
    pub mango_group: Pubkey,
    pub perp_market_index: u16,
    pub liqor: Pubkey,
    pub liqee: Pubkey,
    pub base_transfer: i64,
    pub quote_transfer: i128,
    pub pnl_transfer: i128,
    pub pnl_settle_limit_transfer: i128,
    pub price: i128,
}

#[event]
pub struct PerpLiqBaseOrPositivePnlLogV2 {
    pub mango_group: Pubkey,
    pub perp_market_index: u16,
    pub liqor: Pubkey,
    pub liqee: Pubkey,
    pub base_transfer_liqee: i64,
    pub quote_transfer_liqee: i128,
    pub quote_transfer_liqor: i128,
    pub quote_platform_fee: i128,
    pub pnl_transfer: i128,
    pub pnl_settle_limit_transfer: i128,
    pub price: i128,
}

#[event]
pub struct PerpLiqBaseOrPositivePnlLogV3 {
    pub mango_group: Pubkey,
    pub perp_market_index: u16,
    pub liqor: Pubkey,
    pub liqee: Pubkey,
    pub base_transfer_liqee: i64,
    pub quote_transfer_liqee: i128,
    pub quote_transfer_liqor: i128,
    pub quote_platform_fee: i128,
    pub pnl_transfer: i128,
    pub pnl_settle_limit_transfer_recurring: i64,
    pub pnl_settle_limit_transfer_oneshot: i64,
    pub price: i128,
}

#[event]
pub struct PerpLiqBankruptcyLog {
    pub mango_group: Pubkey,
    pub liqee: Pubkey,
    pub liqor: Pubkey,
    pub perp_market_index: u16,
    pub insurance_transfer: i128,
    pub socialized_loss: i128,
    pub starting_long_funding: i128,
    pub starting_short_funding: i128,
    pub ending_long_funding: i128,
    pub ending_short_funding: i128,
}

#[event]
pub struct PerpLiqNegativePnlOrBankruptcyLog {
    pub mango_group: Pubkey,
    pub liqee: Pubkey,
    pub liqor: Pubkey,
    pub perp_market_index: u16,
    pub settlement: i128,
}

#[event]
pub struct PerpSettlePnlLog {
    pub mango_group: Pubkey,
    pub mango_account_a: Pubkey,
    pub mango_account_b: Pubkey,
    pub perp_market_index: u16,
    pub settlement: i128,
    pub settler: Pubkey,
    pub fee: i128,
}

#[event]
pub struct PerpSettleFeesLog {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub perp_market_index: u16,
    pub settlement: i128,
}

#[event]
pub struct AccountBuybackFeesWithMngoLog {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub buyback_fees: i128,
    pub buyback_mngo: i128,
    pub mngo_buyback_price: i128,
    pub oracle_price: i128,
}

#[event]
pub struct FilledPerpOrderLog {
    pub mango_group: Pubkey,
    pub perp_market_index: u16,
    pub seq_num: u64,
}

#[event]
pub struct PerpTakerTradeLog {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub perp_market_index: u16,
    pub taker_side: u8,
    pub total_base_lots_taken: i64, // includes decremented base lots
    pub total_base_lots_decremented: i64, // from DecrementTake self-trades
    pub total_quote_lots_taken: i64, // exclusive fees paid, includes decremented quote lots
    pub total_quote_lots_decremented: i64, // from DecrementTake self-trades
    pub taker_fees_paid: i128,      // in native quote units
    pub fee_penalty: i128,          // in native quote units
}

#[event]
pub struct PerpForceClosePositionLog {
    pub mango_group: Pubkey,
    pub perp_market_index: u16,
    pub account_a: Pubkey,
    pub account_b: Pubkey,
    pub base_transfer: i64,
    pub quote_transfer: i128,
    pub price: i128,
}

#[event]
pub struct TokenForceCloseBorrowsWithTokenLog {
    pub mango_group: Pubkey,
    pub liqor: Pubkey,
    pub liqee: Pubkey,
    pub asset_token_index: u16,
    pub liab_token_index: u16,
    pub asset_transfer: i128,
    pub liab_transfer: i128,
    pub asset_price: i128,
    pub liab_price: i128,
    pub fee_factor: i128,
}

#[event]
pub struct TokenForceCloseBorrowsWithTokenLogV2 {
    pub mango_group: Pubkey,
    pub liqor: Pubkey,
    pub liqee: Pubkey,
    pub asset_token_index: u16,
    pub liab_token_index: u16,
    pub asset_transfer_from_liqee: i128, // I80F48
    pub asset_transfer_to_liqor: i128,   // I80F48
    pub asset_liquidation_fee: i128,     // I80F48
    pub liab_transfer: i128,             // I80F48
    pub asset_price: i128,               // I80F48
    pub liab_price: i128,                // I80F48
    /// including liqor and platform liquidation fees
    pub fee_factor: i128, // I80F48
}

#[event]
pub struct TokenConditionalSwapCreateLog {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub id: u64,
    pub max_buy: u64,
    pub max_sell: u64,
    pub expiry_timestamp: u64,
    pub price_lower_limit: f64,
    pub price_upper_limit: f64,
    pub price_premium_rate: f64,
    pub taker_fee_rate: f32,
    pub maker_fee_rate: f32,
    pub buy_token_index: u16,
    pub sell_token_index: u16,
    pub allow_creating_deposits: bool,
    pub allow_creating_borrows: bool,
}

#[event]
pub struct TokenConditionalSwapCreateLogV2 {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub id: u64,
    pub max_buy: u64,
    pub max_sell: u64,
    pub expiry_timestamp: u64,
    pub price_lower_limit: f64,
    pub price_upper_limit: f64,
    pub price_premium_rate: f64,
    pub taker_fee_rate: f32,
    pub maker_fee_rate: f32,
    pub buy_token_index: u16,
    pub sell_token_index: u16,
    pub allow_creating_deposits: bool,
    pub allow_creating_borrows: bool,
    pub display_price_style: u8,
    pub intention: u8,
}

#[event]
pub struct TokenConditionalSwapCreateLogV3 {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub id: u64,
    pub max_buy: u64,
    pub max_sell: u64,
    pub expiry_timestamp: u64,
    pub price_lower_limit: f64,
    pub price_upper_limit: f64,
    pub price_premium_rate: f64,
    pub taker_fee_rate: f32,
    pub maker_fee_rate: f32,
    pub buy_token_index: u16,
    pub sell_token_index: u16,
    pub allow_creating_deposits: bool,
    pub allow_creating_borrows: bool,
    pub display_price_style: u8,
    pub intention: u8,
    pub tcs_type: u8,
    pub start_timestamp: u64,
    pub duration_seconds: u64,
}

#[event]
pub struct TokenConditionalSwapTriggerLog {
    pub mango_group: Pubkey,
    pub liqee: Pubkey,
    pub liqor: Pubkey,
    pub token_conditional_swap_id: u64,
    pub buy_token_index: u16,
    pub sell_token_index: u16,
    pub buy_amount: u64,        // amount the liqee got
    pub sell_amount: u64,       // amount the liqee paid (including fees)
    pub maker_fee: u64,         // in native units of sell token (included in sell amount)
    pub taker_fee: u64, // in native units of sell token (deducted from the sell amount the liqor received)
    pub buy_token_price: i128, // I80F48
    pub sell_token_price: i128, // I80F48
    pub closed: bool,
}

#[event]
pub struct TokenConditionalSwapTriggerLogV2 {
    pub mango_group: Pubkey,
    pub liqee: Pubkey,
    pub liqor: Pubkey,
    pub token_conditional_swap_id: u64,
    pub buy_token_index: u16,
    pub sell_token_index: u16,
    pub buy_amount: u64,        // amount the liqee got
    pub sell_amount: u64,       // amount the liqee paid (including fees)
    pub maker_fee: u64,         // in native units of sell token (included in sell amount)
    pub taker_fee: u64, // in native units of sell token (deducted from the sell amount the liqor received)
    pub buy_token_price: i128, // I80F48
    pub sell_token_price: i128, // I80F48
    pub closed: bool,
    pub display_price_style: u8,
    pub intention: u8,
}

#[event]
pub struct TokenConditionalSwapTriggerLogV3 {
    pub mango_group: Pubkey,
    pub liqee: Pubkey,
    pub liqor: Pubkey,
    pub token_conditional_swap_id: u64,
    pub buy_token_index: u16,
    pub sell_token_index: u16,
    pub buy_amount: u64,        // amount the liqee got
    pub sell_amount: u64,       // amount the liqee paid (including fees)
    pub maker_fee: u64,         // in native units of sell token (included in sell amount)
    pub taker_fee: u64, // in native units of sell token (deducted from the sell amount the liqor received)
    pub buy_token_price: i128, // I80F48
    pub sell_token_price: i128, // I80F48
    pub closed: bool,
    pub display_price_style: u8,
    pub intention: u8,
    pub tcs_type: u8,
    pub start_timestamp: u64,
}

#[event]
pub struct TokenConditionalSwapCancelLog {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub id: u64,
}

#[event]
pub struct TokenConditionalSwapStartLog {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub caller: Pubkey,
    pub token_conditional_swap_id: u64,
    pub incentive_token_index: u16,
    pub incentive_amount: u64,
}

#[event]
pub struct TokenCollateralFeeLog {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub token_index: u16,
    pub asset_usage_fraction: i128,
    pub fee: i128,
    pub price: i128,
}

#[event]
pub struct ForceWithdrawLog {
    pub mango_group: Pubkey,
    pub mango_account: Pubkey,
    pub token_index: u16,
    pub quantity: u64,
    pub price: i128, // I80F48
    pub to_token_account: Pubkey,
}
