PerpUpdateFunding: update automatically on PerpPlaceOrder (#287)
This commit is contained in:
parent
efec1eb906
commit
b6361bad37
|
@ -80,6 +80,8 @@ pub fn perp_create_market(
|
|||
"settlement tokens != USDC are not fully implemented"
|
||||
);
|
||||
|
||||
let now_ts: u64 = Clock::get()?.unix_timestamp.try_into().unwrap();
|
||||
|
||||
let mut perp_market = ctx.accounts.perp_market.load_init()?;
|
||||
*perp_market = PerpMarket {
|
||||
group: ctx.accounts.group.key(),
|
||||
|
@ -106,14 +108,14 @@ pub fn perp_create_market(
|
|||
impact_quantity,
|
||||
long_funding: I80F48::ZERO,
|
||||
short_funding: I80F48::ZERO,
|
||||
funding_last_updated: Clock::get()?.unix_timestamp,
|
||||
funding_last_updated: now_ts,
|
||||
open_interest: 0,
|
||||
seq_num: 0,
|
||||
fees_accrued: I80F48::ZERO,
|
||||
fees_settled: I80F48::ZERO,
|
||||
bump: *ctx.bumps.get("perp_market").ok_or(MangoError::SomeError)?,
|
||||
base_decimals,
|
||||
registration_time: Clock::get()?.unix_timestamp,
|
||||
registration_time: now_ts,
|
||||
padding1: Default::default(),
|
||||
padding2: Default::default(),
|
||||
padding3: Default::default(),
|
||||
|
|
|
@ -39,6 +39,23 @@ pub fn perp_place_order(ctx: Context<PerpPlaceOrder>, order: Order, limit: u8) -
|
|||
require_gte!(order.max_base_lots, 0);
|
||||
require_gte!(order.max_quote_lots, 0);
|
||||
|
||||
let now_ts: u64 = Clock::get()?.unix_timestamp.try_into().unwrap();
|
||||
let oracle_price;
|
||||
|
||||
// Update funding if possible.
|
||||
//
|
||||
// Doing this automatically here makes it impossible for attackers to add orders to the orderbook
|
||||
// before triggering the funding computation.
|
||||
{
|
||||
let mut perp_market = ctx.accounts.perp_market.load_mut()?;
|
||||
let book = ctx.accounts.orderbook.load_mut()?;
|
||||
|
||||
oracle_price =
|
||||
perp_market.oracle_price(&AccountInfoRef::borrow(ctx.accounts.oracle.as_ref())?)?;
|
||||
|
||||
perp_market.update_funding(&book, oracle_price, now_ts)?;
|
||||
}
|
||||
|
||||
let mut account = ctx.accounts.account.load_mut()?;
|
||||
require!(
|
||||
account.fixed.is_owner_or_delegate(ctx.accounts.owner.key()),
|
||||
|
@ -79,10 +96,7 @@ pub fn perp_place_order(ctx: Context<PerpPlaceOrder>, order: Order, limit: u8) -
|
|||
|
||||
let mut event_queue = ctx.accounts.event_queue.load_mut()?;
|
||||
|
||||
let oracle_price =
|
||||
perp_market.oracle_price(&AccountInfoRef::borrow(ctx.accounts.oracle.as_ref())?)?;
|
||||
|
||||
let now_ts = Clock::get()?.unix_timestamp as u64;
|
||||
let now_ts: u64 = Clock::get()?.unix_timestamp.try_into().unwrap();
|
||||
|
||||
// TODO apply reduce_only flag to compute final base_lots, also process event queue
|
||||
require!(order.reduce_only == false, MangoError::SomeError);
|
||||
|
|
|
@ -3,8 +3,6 @@ use anchor_lang::prelude::*;
|
|||
use crate::accounts_zerocopy::*;
|
||||
use crate::state::{Group, OrderBook, PerpMarket};
|
||||
|
||||
use crate::logs::PerpUpdateFundingLog;
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct PerpUpdateFunding<'info> {
|
||||
pub group: AccountLoader<'info, Group>, // Required for group metadata parsing
|
||||
|
@ -23,8 +21,7 @@ pub struct PerpUpdateFunding<'info> {
|
|||
pub oracle: UncheckedAccount<'info>,
|
||||
}
|
||||
pub fn perp_update_funding(ctx: Context<PerpUpdateFunding>) -> Result<()> {
|
||||
// TODO: should we enforce a minimum window between 2 update_funding ix calls?
|
||||
let now_ts = Clock::get()?.unix_timestamp;
|
||||
let now_ts: u64 = Clock::get()?.unix_timestamp.try_into().unwrap();
|
||||
|
||||
let mut perp_market = ctx.accounts.perp_market.load_mut()?;
|
||||
let book = ctx.accounts.orderbook.load_mut()?;
|
||||
|
@ -32,17 +29,7 @@ pub fn perp_update_funding(ctx: Context<PerpUpdateFunding>) -> Result<()> {
|
|||
let oracle_price =
|
||||
perp_market.oracle_price(&AccountInfoRef::borrow(ctx.accounts.oracle.as_ref())?)?;
|
||||
|
||||
perp_market.update_funding(&book, oracle_price, now_ts as u64)?;
|
||||
|
||||
emit!(PerpUpdateFundingLog {
|
||||
mango_group: ctx.accounts.group.key(),
|
||||
market_index: perp_market.perp_market_index,
|
||||
long_funding: perp_market.long_funding.to_bits(),
|
||||
short_funding: perp_market.long_funding.to_bits(),
|
||||
price: oracle_price.to_bits(),
|
||||
fees_accrued: perp_market.fees_accrued.to_bits(),
|
||||
open_interest: perp_market.open_interest,
|
||||
});
|
||||
perp_market.update_funding(&book, oracle_price, now_ts)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ pub fn serum3_register_market(
|
|||
bump: *ctx.bumps.get("serum_market").ok_or(MangoError::SomeError)?,
|
||||
padding1: Default::default(),
|
||||
padding2: Default::default(),
|
||||
registration_time: Clock::get()?.unix_timestamp,
|
||||
registration_time: Clock::get()?.unix_timestamp.try_into().unwrap(),
|
||||
reserved: [0; 128],
|
||||
};
|
||||
|
||||
|
|
|
@ -151,7 +151,7 @@ pub fn token_register(
|
|||
banks: Default::default(),
|
||||
vaults: Default::default(),
|
||||
oracle: ctx.accounts.oracle.key(),
|
||||
registration_time: Clock::get()?.unix_timestamp,
|
||||
registration_time: Clock::get()?.unix_timestamp.try_into().unwrap(),
|
||||
reserved: [0; 2560],
|
||||
};
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ pub fn token_register_trustless(
|
|||
banks: Default::default(),
|
||||
vaults: Default::default(),
|
||||
oracle: ctx.accounts.oracle.key(),
|
||||
registration_time: Clock::get()?.unix_timestamp,
|
||||
registration_time: Clock::get()?.unix_timestamp.try_into().unwrap(),
|
||||
reserved: [0; 2560],
|
||||
};
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ pub struct MintInfo {
|
|||
pub vaults: [Pubkey; MAX_BANKS],
|
||||
pub oracle: Pubkey,
|
||||
|
||||
pub registration_time: i64,
|
||||
pub registration_time: u64,
|
||||
|
||||
pub reserved: [u8; 2560],
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ pub enum OrderParams {
|
|||
impl Order {
|
||||
/// Convert an input expiry timestamp to a time_in_force value
|
||||
pub fn tif_from_expiry(expiry_timestamp: u64) -> Option<u8> {
|
||||
let now_ts = Clock::get().unwrap().unix_timestamp as u64;
|
||||
let now_ts: u64 = Clock::get().unwrap().unix_timestamp.try_into().unwrap();
|
||||
if expiry_timestamp != 0 {
|
||||
// If expiry is far in the future, clamp to 255 seconds
|
||||
let tif = expiry_timestamp.saturating_sub(now_ts).min(255);
|
||||
|
|
|
@ -11,6 +11,7 @@ use crate::state::{oracle, TokenIndex};
|
|||
use crate::util::checked_math as cm;
|
||||
|
||||
use super::{orderbook, OracleConfig, OrderBook, DAY_I80F48};
|
||||
use crate::logs::PerpUpdateFundingLog;
|
||||
|
||||
pub type PerpMarketIndex = u16;
|
||||
|
||||
|
@ -69,7 +70,8 @@ pub struct PerpMarket {
|
|||
pub impact_quantity: i64,
|
||||
pub long_funding: I80F48,
|
||||
pub short_funding: I80F48,
|
||||
pub funding_last_updated: i64,
|
||||
/// timestamp that funding was last updated in
|
||||
pub funding_last_updated: u64,
|
||||
|
||||
///
|
||||
pub open_interest: i64,
|
||||
|
@ -93,7 +95,7 @@ pub struct PerpMarket {
|
|||
|
||||
pub padding2: [u8; 6],
|
||||
|
||||
pub registration_time: i64,
|
||||
pub registration_time: u64,
|
||||
|
||||
/// Fees settled in native quote currency
|
||||
pub fees_settled: I80F48,
|
||||
|
@ -154,6 +156,10 @@ impl PerpMarket {
|
|||
oracle_price: I80F48,
|
||||
now_ts: u64,
|
||||
) -> Result<()> {
|
||||
if now_ts <= self.funding_last_updated {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let index_price = oracle_price;
|
||||
let oracle_price_lots = self.native_price_to_lot(oracle_price);
|
||||
|
||||
|
@ -181,7 +187,17 @@ impl PerpMarket {
|
|||
|
||||
self.long_funding += funding_delta;
|
||||
self.short_funding += funding_delta;
|
||||
self.funding_last_updated = now_ts as i64;
|
||||
self.funding_last_updated = now_ts;
|
||||
|
||||
emit!(PerpUpdateFundingLog {
|
||||
mango_group: self.group,
|
||||
market_index: self.perp_market_index,
|
||||
long_funding: self.long_funding.to_bits(),
|
||||
short_funding: self.long_funding.to_bits(),
|
||||
price: oracle_price.to_bits(),
|
||||
fees_accrued: self.fees_accrued.to_bits(),
|
||||
open_interest: self.open_interest,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ pub struct Serum3Market {
|
|||
|
||||
pub padding2: [u8; 5],
|
||||
|
||||
pub registration_time: i64,
|
||||
pub registration_time: u64,
|
||||
|
||||
pub reserved: [u8; 128],
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue