Skip to main content

usdc_plus_exchange/drift/
components.rs

1use anchor_lang::prelude::*;
2use borsh::{BorshDeserialize, BorshSerialize};
3use bytemuck::Pod;
4use num_traits::{One, Zero};
5use solana_program::msg;
6use std::{cell::{Ref, RefMut}, marker::PhantomData, panic::Location};
7use crate::errors::ReflectErrorCodes;
8
9pub trait Size {
10    const SIZE: usize;
11}
12
13pub trait SpotBalance {
14    fn market_index(&self) -> u16;
15    fn balance(&self) -> u128;
16    fn balance_type(&self) -> &SpotBalanceType;
17}
18
19impl SpotBalance for PoolBalance {
20    fn market_index(&self) -> u16 {
21        self.market_index
22    }
23
24    fn balance_type(&self) -> &SpotBalanceType {
25        &SpotBalanceType::Deposit
26    }
27
28    fn balance(&self) -> u128 {
29        self.scaled_balance
30    }
31}
32
33#[zero_copy(unsafe)]
34#[derive(Default, Eq, PartialEq, Debug, AnchorSerialize, AnchorDeserialize,)]
35#[repr(C)]
36pub struct InsuranceFund {
37    pub vault: Pubkey,
38    pub total_shares: u128,
39    pub user_shares: u128,
40    pub shares_base: u128,     // exponent for lp shares (for rebasing)
41    pub unstaking_period: i64, // if_unstaking_period
42    pub last_revenue_settle_ts: i64,
43    pub revenue_settle_period: i64,
44    pub total_factor: u32, // percentage of interest for total insurance
45    pub user_factor: u32,  // percentage of interest for user staked insurance
46}
47
48#[zero_copy(unsafe)]
49#[derive(Default, Eq, PartialEq, Debug, AnchorDeserialize, AnchorSerialize)]
50#[repr(C)]
51pub struct SpotPosition {
52    /// The scaled balance of the position. To get the token amount, multiply by the cumulative deposit/borrow
53    /// interest of corresponding market.
54    /// precision: SPOT_BALANCE_PRECISION
55    pub scaled_balance: u64,
56    /// How many spot bids the user has open
57    /// precision: token mint precision
58    pub open_bids: i64,
59    /// How many spot asks the user has open
60    /// precision: token mint precision
61    pub open_asks: i64,
62    /// The cumulative deposits/borrows a user has made into a market
63    /// precision: token mint precision
64    pub cumulative_deposits: i64,
65    /// The market index of the corresponding spot market
66    pub market_index: u16,
67    /// Whether the position is deposit or borrow
68    pub balance_type: SpotBalanceType,
69    /// Number of open orders
70    pub open_orders: u8,
71    pub padding: [u8; 4],
72}
73
74#[derive(Clone, Copy, BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Default)]
75pub enum SpotBalanceType {
76    #[default]
77    Deposit,
78    Borrow,
79}
80
81#[derive(Default, Clone, Copy, BorshSerialize, BorshDeserialize, PartialEq, Debug, Eq, PartialOrd, Ord)]
82pub enum AssetTier {
83    /// full priviledge
84    Collateral,
85    /// collateral, but no borrow
86    Protected,
87    /// not collateral, allow multi-borrow
88    Cross,
89    /// not collateral, only single borrow
90    Isolated,
91    /// no privilege
92    #[default]
93    Unlisted,
94}
95
96#[derive(Default, AnchorSerialize, AnchorDeserialize, Clone, Copy, Eq, PartialEq, Debug)]
97#[repr(C)]
98pub struct HistoricalIndexData {
99    /// precision: PRICE_PRECISION
100    pub last_index_bid_price: u64,
101    /// precision: PRICE_PRECISION
102    pub last_index_ask_price: u64,
103    /// precision: PRICE_PRECISION
104    pub last_index_price_twap: u64,
105    /// precision: PRICE_PRECISION
106    pub last_index_price_twap_5min: u64,
107    /// unix_timestamp of last snapshot
108    pub last_index_price_twap_ts: i64,
109}
110
111pub const SPOT_MARKET_ACCOUNT_DISCM: [u8; 8] = [100, 177, 8, 107, 168, 65, 65, 39];
112
113#[zero_copy(unsafe)]
114#[derive(PartialEq, Eq, Debug)]
115#[repr(C)]
116pub struct SpotMarket {
117    /// The address of the spot market. It is a pda of the market index
118    pub pubkey: Pubkey,
119    /// The oracle used to price the markets deposits/borrows
120    pub oracle: Pubkey,
121    /// The token mint of the market
122    pub mint: Pubkey,
123    /// The vault used to store the market's deposits
124    /// The amount in the vault should be equal to or greater than deposits - borrows
125    pub vault: Pubkey,
126    /// The encoded display name for the market e.g. SOL
127    pub name: [u8; 32],
128    pub historical_oracle_data: HistoricalOracleData,
129    pub historical_index_data: HistoricalIndexData,
130    /// Revenue the protocol has collected in this markets token
131    /// e.g. for SOL-PERP, funds can be settled in usdc and will flow into the USDC revenue pool
132    pub revenue_pool: PoolBalance, // in base asset
133    /// The fees collected from swaps between this market and the quote market
134    /// Is settled to the quote markets revenue pool
135    pub spot_fee_pool: PoolBalance,
136    /// Details on the insurance fund covering bankruptcies in this markets token
137    /// Covers bankruptcies for borrows with this markets token and perps settling in this markets token
138    pub insurance_fund: InsuranceFund,
139    /// The total spot fees collected for this market
140    /// precision: QUOTE_PRECISION
141    pub total_spot_fee: u128,
142    /// The sum of the scaled balances for deposits across users and pool balances
143    /// To convert to the deposit token amount, multiply by the cumulative deposit interest
144    /// precision: SPOT_BALANCE_PRECISION
145    pub deposit_balance: u128,
146    /// The sum of the scaled balances for borrows across users and pool balances
147    /// To convert to the borrow token amount, multiply by the cumulative borrow interest
148    /// precision: SPOT_BALANCE_PRECISION
149    pub borrow_balance: u128,
150    /// The cumulative interest earned by depositors
151    /// Used to calculate the deposit token amount from the deposit balance
152    /// precision: SPOT_CUMULATIVE_INTEREST_PRECISION
153    pub cumulative_deposit_interest: u128,
154    /// The cumulative interest earned by borrowers
155    /// Used to calculate the borrow token amount from the borrow balance
156    /// precision: SPOT_CUMULATIVE_INTEREST_PRECISION
157    pub cumulative_borrow_interest: u128,
158    /// The total socialized loss from borrows, in the mint's token
159    /// precision: token mint precision
160    pub total_social_loss: u128,
161    /// The total socialized loss from borrows, in the quote market's token
162    /// preicision: QUOTE_PRECISION
163    pub total_quote_social_loss: u128,
164    /// no withdraw limits/guards when deposits below this threshold
165    /// precision: token mint precision
166    pub withdraw_guard_threshold: u64,
167    /// The max amount of token deposits in this market
168    /// 0 if there is no limit
169    /// precision: token mint precision
170    pub max_token_deposits: u64,
171    /// 24hr average of deposit token amount
172    /// precision: token mint precision
173    pub deposit_token_twap: u64,
174    /// 24hr average of borrow token amount
175    /// precision: token mint precision
176    pub borrow_token_twap: u64,
177    /// 24hr average of utilization
178    /// which is borrow amount over token amount
179    /// precision: SPOT_UTILIZATION_PRECISION
180    pub utilization_twap: u64,
181    /// Last time the cumulative deposit and borrow interest was updated
182    pub last_interest_ts: u64,
183    /// Last time the deposit/borrow/utilization averages were updated
184    pub last_twap_ts: u64,
185    /// The time the market is set to expire. Only set if market is in reduce only mode
186    pub expiry_ts: i64,
187    /// Spot orders must be a multiple of the step size
188    /// precision: token mint precision
189    pub order_step_size: u64,
190    /// Spot orders must be a multiple of the tick size
191    /// precision: PRICE_PRECISION
192    pub order_tick_size: u64,
193    /// The minimum order size
194    /// precision: token mint precision
195    pub min_order_size: u64,
196    /// The maximum spot position size
197    /// if the limit is 0, there is no limit
198    /// precision: token mint precision
199    pub max_position_size: u64,
200    /// Every spot trade has a fill record id. This is the next id to use
201    pub next_fill_record_id: u64,
202    /// Every deposit has a deposit record id. This is the next id to use
203    pub next_deposit_record_id: u64,
204    /// The initial asset weight used to calculate a deposits contribution to a users initial total collateral
205    /// e.g. if the asset weight is .8, $100 of deposits contributes $80 to the users initial total collateral
206    /// precision: SPOT_WEIGHT_PRECISION
207    pub initial_asset_weight: u32,
208    /// The maintenance asset weight used to calculate a deposits contribution to a users maintenance total collateral
209    /// e.g. if the asset weight is .9, $100 of deposits contributes $90 to the users maintenance total collateral
210    /// precision: SPOT_WEIGHT_PRECISION
211    pub maintenance_asset_weight: u32,
212    /// The initial liability weight used to calculate a borrows contribution to a users initial margin requirement
213    /// e.g. if the liability weight is .9, $100 of borrows contributes $90 to the users initial margin requirement
214    /// precision: SPOT_WEIGHT_PRECISION
215    pub initial_liability_weight: u32,
216    /// The maintenance liability weight used to calculate a borrows contribution to a users maintenance margin requirement
217    /// e.g. if the liability weight is .8, $100 of borrows contributes $80 to the users maintenance margin requirement
218    /// precision: SPOT_WEIGHT_PRECISION
219    pub maintenance_liability_weight: u32,
220    /// The initial margin fraction factor. Used to increase liability weight/decrease asset weight for large positions
221    /// precision: MARGIN_PRECISION
222    pub imf_factor: u32,
223    /// The fee the liquidator is paid for taking over borrow/deposit
224    /// precision: LIQUIDATOR_FEE_PRECISION
225    pub liquidator_fee: u32,
226    /// The fee the insurance fund receives from liquidation
227    /// precision: LIQUIDATOR_FEE_PRECISION
228    pub if_liquidation_fee: u32,
229    /// The optimal utilization rate for this market.
230    /// Used to determine the markets borrow rate
231    /// precision: SPOT_UTILIZATION_PRECISION
232    pub optimal_utilization: u32,
233    /// The borrow rate for this market when the market has optimal utilization
234    /// precision: SPOT_RATE_PRECISION
235    pub optimal_borrow_rate: u32,
236    /// The borrow rate for this market when the market has 1000 utilization
237    /// precision: SPOT_RATE_PRECISION
238    pub max_borrow_rate: u32,
239    /// The market's token mint's decimals. To from decimals to a precision, 10^decimals
240    pub decimals: u32,
241    pub market_index: u16,
242    /// Whether or not spot trading is enabled
243    pub orders_enabled: bool,
244    pub oracle_source: OracleSource,
245    pub status: MarketStatus,
246    /// The asset tier affects how a deposit can be used as collateral and the priority for a borrow being liquidated
247    pub asset_tier: AssetTier,
248    pub paused_operations: u8,
249    pub if_paused_operations: u8,
250    pub fee_adjustment: i16,
251    /// What fraction of max_token_deposits
252    /// disabled when 0, 1 => 1/10000 => .01% of max_token_deposits
253    /// precision: X/10000
254    pub max_token_borrows_fraction: u16,
255    /// For swaps, the amount of token loaned out in the begin_swap ix
256    /// precision: token mint precision
257    pub flash_loan_amount: u64,
258    /// For swaps, the amount in the users token account in the begin_swap ix
259    /// Used to calculate how much of the token left the system in end_swap ix
260    /// precision: token mint precision
261    pub flash_loan_initial_token_amount: u64,
262    /// The total fees received from swaps
263    /// precision: token mint precision
264    pub total_swap_fee: u64,
265    /// When to begin scaling down the initial asset weight
266    /// disabled when 0
267    /// precision: QUOTE_PRECISION
268    pub scale_initial_asset_weight_start: u64,
269    /// The min borrow rate for this market when the market regardless of utilization
270    /// 1 => 1/200 => .5%
271    /// precision: X/200
272    pub min_borrow_rate: u8,
273    /// fuel multiplier for spot deposits
274    /// precision: 10
275    pub fuel_boost_deposits: u8,
276    /// fuel multiplier for spot borrows
277    /// precision: 10
278    pub fuel_boost_borrows: u8,
279    /// fuel multiplier for spot taker
280    /// precision: 10
281    pub fuel_boost_taker: u8,
282    /// fuel multiplier for spot maker
283    /// precision: 10
284    pub fuel_boost_maker: u8,
285    /// fuel multiplier for spot insurance stake
286    /// precision: 10
287    pub fuel_boost_insurance: u8,
288    pub token_program_flag: u8,
289    pub pool_id: u8,
290    pub padding: [u8; 40],
291}
292
293impl SpotMarket {
294    pub fn deserialize(buf: &mut &[u8]) -> Result<Self> {
295        use std::io::Read;
296        
297        let mut spot_market = SpotMarket::default();        
298         
299        // Read Pubkeys (32 bytes each)
300        let mut pubkey_bytes = [0u8; 32];
301        buf.read_exact(&mut pubkey_bytes)?;
302        spot_market.pubkey = Pubkey::from(pubkey_bytes);
303        
304        let mut oracle_bytes = [0u8; 32];
305        buf.read_exact(&mut oracle_bytes)?;
306        spot_market.oracle = Pubkey::from(oracle_bytes);
307        
308        let mut mint_bytes = [0u8; 32];
309        buf.read_exact(&mut mint_bytes)?;
310        spot_market.mint = Pubkey::from(mint_bytes);
311        
312        let mut vault_bytes = [0u8; 32];
313        buf.read_exact(&mut vault_bytes)?;
314        spot_market.vault = Pubkey::from(vault_bytes);
315        
316        buf.read_exact(&mut spot_market.name)?;
317        
318        
319        spot_market.historical_oracle_data = HistoricalOracleData::deserialize(buf)?;
320        spot_market.historical_index_data = HistoricalIndexData::deserialize(buf)?;
321        spot_market.revenue_pool = PoolBalance::deserialize(buf)?;
322        spot_market.spot_fee_pool = PoolBalance::deserialize(buf)?;
323        spot_market.insurance_fund = InsuranceFund::deserialize(buf)?;
324        
325        spot_market.total_spot_fee = u128::deserialize(buf)?;
326        spot_market.deposit_balance = u128::deserialize(buf)?;
327        spot_market.borrow_balance = u128::deserialize(buf)?;
328        spot_market.cumulative_deposit_interest = u128::deserialize(buf)?;
329        spot_market.cumulative_borrow_interest = u128::deserialize(buf)?;
330        spot_market.total_social_loss = u128::deserialize(buf)?;
331        spot_market.total_quote_social_loss = u128::deserialize(buf)?;
332        
333        spot_market.withdraw_guard_threshold = u64::deserialize(buf)?;
334        spot_market.max_token_deposits = u64::deserialize(buf)?;
335        spot_market.deposit_token_twap = u64::deserialize(buf)?;
336        spot_market.borrow_token_twap = u64::deserialize(buf)?;
337        spot_market.utilization_twap = u64::deserialize(buf)?;
338        spot_market.last_interest_ts = u64::deserialize(buf)?;
339        spot_market.last_twap_ts = u64::deserialize(buf)?;
340        spot_market.expiry_ts = i64::deserialize(buf)?;
341        spot_market.order_step_size = u64::deserialize(buf)?;
342        spot_market.order_tick_size = u64::deserialize(buf)?;
343        spot_market.min_order_size = u64::deserialize(buf)?;
344        spot_market.max_position_size = u64::deserialize(buf)?;
345        spot_market.next_fill_record_id = u64::deserialize(buf)?;
346        spot_market.next_deposit_record_id = u64::deserialize(buf)?;
347        
348        spot_market.initial_asset_weight = u32::deserialize(buf)?;
349        spot_market.maintenance_asset_weight = u32::deserialize(buf)?;
350        spot_market.initial_liability_weight = u32::deserialize(buf)?;
351        spot_market.maintenance_liability_weight = u32::deserialize(buf)?;
352        spot_market.imf_factor = u32::deserialize(buf)?;
353        spot_market.liquidator_fee = u32::deserialize(buf)?;
354        spot_market.if_liquidation_fee = u32::deserialize(buf)?;
355        spot_market.optimal_utilization = u32::deserialize(buf)?;
356        spot_market.optimal_borrow_rate = u32::deserialize(buf)?;
357        spot_market.max_borrow_rate = u32::deserialize(buf)?;
358        spot_market.decimals = u32::deserialize(buf)?;
359        
360        spot_market.market_index = u16::deserialize(buf)?;
361        spot_market.orders_enabled = bool::deserialize(buf)?;
362        spot_market.oracle_source = OracleSource::deserialize(buf)?;
363        spot_market.status = MarketStatus::deserialize(buf)?;
364        spot_market.asset_tier = AssetTier::deserialize(buf)?;
365        spot_market.paused_operations = u8::deserialize(buf)?;
366        spot_market.if_paused_operations = u8::deserialize(buf)?;
367        spot_market.fee_adjustment = i16::deserialize(buf)?;
368        spot_market.max_token_borrows_fraction = u16::deserialize(buf)?;
369        
370        spot_market.flash_loan_amount = u64::deserialize(buf)?;
371        spot_market.flash_loan_initial_token_amount = u64::deserialize(buf)?;
372        spot_market.total_swap_fee = u64::deserialize(buf)?;
373        spot_market.scale_initial_asset_weight_start = u64::deserialize(buf)?;
374        
375        spot_market.min_borrow_rate = u8::deserialize(buf)?;
376        spot_market.fuel_boost_deposits = u8::deserialize(buf)?;
377        spot_market.fuel_boost_borrows = u8::deserialize(buf)?;
378        spot_market.fuel_boost_taker = u8::deserialize(buf)?;
379        spot_market.fuel_boost_maker = u8::deserialize(buf)?;
380        spot_market.fuel_boost_insurance = u8::deserialize(buf)?;
381        spot_market.token_program_flag = u8::deserialize(buf)?;
382        spot_market.pool_id = u8::deserialize(buf)?;
383        
384        buf.read_exact(&mut spot_market.padding)?;
385        
386        Ok(spot_market)
387    }
388}
389
390impl Size for SpotMarket {
391    const SIZE: usize = 776;
392}
393
394impl Default for SpotMarket {
395    fn default() -> Self {
396        SpotMarket {
397            pubkey: Pubkey::default(),
398            oracle: Pubkey::default(),
399            mint: Pubkey::default(),
400            vault: Pubkey::default(),
401            name: [0; 32],
402            historical_oracle_data: HistoricalOracleData::default(),
403            historical_index_data: HistoricalIndexData::default(),
404            revenue_pool: PoolBalance::default(),
405            spot_fee_pool: PoolBalance::default(),
406            insurance_fund: InsuranceFund::default(),
407            total_spot_fee: 0,
408            deposit_balance: 0,
409            borrow_balance: 0,
410            cumulative_deposit_interest: 0,
411            cumulative_borrow_interest: 0,
412            total_social_loss: 0,
413            total_quote_social_loss: 0,
414            withdraw_guard_threshold: 0,
415            max_token_deposits: 0,
416            deposit_token_twap: 0,
417            borrow_token_twap: 0,
418            utilization_twap: 0,
419            last_interest_ts: 0,
420            last_twap_ts: 0,
421            expiry_ts: 0,
422            order_step_size: 1,
423            order_tick_size: 0,
424            min_order_size: 0,
425            max_position_size: 0,
426            next_fill_record_id: 0,
427            next_deposit_record_id: 0,
428            initial_asset_weight: 0,
429            maintenance_asset_weight: 0,
430            initial_liability_weight: 0,
431            maintenance_liability_weight: 0,
432            imf_factor: 0,
433            liquidator_fee: 0,
434            if_liquidation_fee: 0,
435            optimal_utilization: 0,
436            optimal_borrow_rate: 0,
437            max_borrow_rate: 0,
438            decimals: 0,
439            market_index: 0,
440            orders_enabled: false,
441            oracle_source: OracleSource::default(),
442            status: MarketStatus::default(),
443            asset_tier: AssetTier::default(),
444            paused_operations: 0,
445            if_paused_operations: 0,
446            fee_adjustment: 0,
447            max_token_borrows_fraction: 0,
448            flash_loan_amount: 0,
449            flash_loan_initial_token_amount: 0,
450            total_swap_fee: 0,
451            scale_initial_asset_weight_start: 0,
452            min_borrow_rate: 0,
453            fuel_boost_deposits: 0,
454            fuel_boost_borrows: 0,
455            fuel_boost_taker: 0,
456            fuel_boost_maker: 0,
457            fuel_boost_insurance: 0,
458            token_program_flag: 0,
459            pool_id: 0,
460            padding: [0; 40],
461        }
462    }
463}
464
465#[derive(Default, Clone, Copy, BorshSerialize, BorshDeserialize, PartialEq, Debug, Eq)]
466pub enum MarketStatus {
467    /// warm up period for initialization, fills are paused
468    #[default]
469    Initialized,
470    /// all operations allowed
471    Active,
472    /// Deprecated in favor of PausedOperations
473    FundingPaused,
474    /// Deprecated in favor of PausedOperations
475    AmmPaused,
476    /// Deprecated in favor of PausedOperations
477    FillPaused,
478    /// Deprecated in favor of PausedOperations
479    WithdrawPaused,
480    /// fills only able to reduce liability
481    ReduceOnly,
482    /// market has determined settlement price and positions are expired must be settled
483    Settlement,
484    /// market has no remaining participants
485    Delisted,
486}
487
488#[zero_copy(unsafe)]
489#[derive(Default, Eq, PartialEq, Debug, AnchorSerialize, AnchorDeserialize,)]
490#[repr(C)] 
491pub struct PoolBalance {
492    /// To get the pool's token amount, you must multiply the scaled balance by the market's cumulative
493    /// deposit interest
494    /// precision: SPOT_BALANCE_PRECISION
495    pub scaled_balance: u128,
496    /// The spot market the pool is for
497    pub market_index: u16,
498    pub padding: [u8; 6],
499}
500
501// #[assert_no_slop]
502#[zero_copy(unsafe)]
503#[derive(Debug, PartialEq, Eq)]
504#[repr(C)]
505pub struct AMM {
506    /// oracle price data public key
507    pub oracle: Pubkey,
508    /// stores historically witnessed oracle data
509    pub historical_oracle_data: HistoricalOracleData,
510    /// accumulated base asset amount since inception per lp share
511    /// precision: QUOTE_PRECISION
512    pub base_asset_amount_per_lp: i128,
513    /// accumulated quote asset amount since inception per lp share
514    /// precision: QUOTE_PRECISION
515    pub quote_asset_amount_per_lp: i128,
516    /// partition of fees from perp market trading moved from pnl settlements
517    pub fee_pool: PoolBalance,
518    /// `x` reserves for constant product mm formula (x * y = k)
519    /// precision: AMM_RESERVE_PRECISION
520    pub base_asset_reserve: u128,
521    /// `y` reserves for constant product mm formula (x * y = k)
522    /// precision: AMM_RESERVE_PRECISION
523    pub quote_asset_reserve: u128,
524    /// determines how close the min/max base asset reserve sit vs base reserves
525    /// allow for decreasing slippage without increasing liquidity and v.v.
526    /// precision: PERCENTAGE_PRECISION
527    pub concentration_coef: u128,
528    /// minimum base_asset_reserve allowed before AMM is unavailable
529    /// precision: AMM_RESERVE_PRECISION
530    pub min_base_asset_reserve: u128,
531    /// maximum base_asset_reserve allowed before AMM is unavailable
532    /// precision: AMM_RESERVE_PRECISION
533    pub max_base_asset_reserve: u128,
534    /// `sqrt(k)` in constant product mm formula (x * y = k). stored to avoid drift caused by integer math issues
535    /// precision: AMM_RESERVE_PRECISION
536    pub sqrt_k: u128,
537    /// normalizing numerical factor for y, its use offers lowest slippage in cp-curve when market is balanced
538    /// precision: PEG_PRECISION
539    pub peg_multiplier: u128,
540    /// y when market is balanced. stored to save computation
541    /// precision: AMM_RESERVE_PRECISION
542    pub terminal_quote_asset_reserve: u128,
543    /// always non-negative. tracks number of total longs in market (regardless of counterparty)
544    /// precision: BASE_PRECISION
545    pub base_asset_amount_long: i128,
546    /// always non-positive. tracks number of total shorts in market (regardless of counterparty)
547    /// precision: BASE_PRECISION
548    pub base_asset_amount_short: i128,
549    /// tracks net position (longs-shorts) in market with AMM as counterparty
550    /// precision: BASE_PRECISION
551    pub base_asset_amount_with_amm: i128,
552    /// tracks net position (longs-shorts) in market with LPs as counterparty
553    /// precision: BASE_PRECISION
554    pub base_asset_amount_with_unsettled_lp: i128,
555    /// max allowed open interest, blocks trades that breach this value
556    /// precision: BASE_PRECISION
557    pub max_open_interest: u128,
558    /// sum of all user's perp quote_asset_amount in market
559    /// precision: QUOTE_PRECISION
560    pub quote_asset_amount: i128,
561    /// sum of all long user's quote_entry_amount in market
562    /// precision: QUOTE_PRECISION
563    pub quote_entry_amount_long: i128,
564    /// sum of all short user's quote_entry_amount in market
565    /// precision: QUOTE_PRECISION
566    pub quote_entry_amount_short: i128,
567    /// sum of all long user's quote_break_even_amount in market
568    /// precision: QUOTE_PRECISION
569    pub quote_break_even_amount_long: i128,
570    /// sum of all short user's quote_break_even_amount in market
571    /// precision: QUOTE_PRECISION
572    pub quote_break_even_amount_short: i128,
573    /// total user lp shares of sqrt_k (protocol owned liquidity = sqrt_k - last_funding_rate)
574    /// precision: AMM_RESERVE_PRECISION
575    pub user_lp_shares: u128,
576    /// last funding rate in this perp market (unit is quote per base)
577    /// precision: QUOTE_PRECISION
578    pub last_funding_rate: i64,
579    /// last funding rate for longs in this perp market (unit is quote per base)
580    /// precision: QUOTE_PRECISION
581    pub last_funding_rate_long: i64,
582    /// last funding rate for shorts in this perp market (unit is quote per base)
583    /// precision: QUOTE_PRECISION
584    pub last_funding_rate_short: i64,
585    /// estimate of last 24h of funding rate perp market (unit is quote per base)
586    /// precision: QUOTE_PRECISION
587    pub last_24h_avg_funding_rate: i64,
588    /// total fees collected by this perp market
589    /// precision: QUOTE_PRECISION
590    pub total_fee: i128,
591    /// total fees collected by the vAMM's bid/ask spread
592    /// precision: QUOTE_PRECISION
593    pub total_mm_fee: i128,
594    /// total fees collected by exchange fee schedule
595    /// precision: QUOTE_PRECISION
596    pub total_exchange_fee: u128,
597    /// total fees minus any recognized upnl and pool withdraws
598    /// precision: QUOTE_PRECISION
599    pub total_fee_minus_distributions: i128,
600    /// sum of all fees from fee pool withdrawn to revenue pool
601    /// precision: QUOTE_PRECISION
602    pub total_fee_withdrawn: u128,
603    /// all fees collected by market for liquidations
604    /// precision: QUOTE_PRECISION
605    pub total_liquidation_fee: u128,
606    /// accumulated funding rate for longs since inception in market
607    pub cumulative_funding_rate_long: i128,
608    /// accumulated funding rate for shorts since inception in market
609    pub cumulative_funding_rate_short: i128,
610    /// accumulated social loss paid by users since inception in market
611    pub total_social_loss: u128,
612    /// transformed base_asset_reserve for users going long
613    /// precision: AMM_RESERVE_PRECISION
614    pub ask_base_asset_reserve: u128,
615    /// transformed quote_asset_reserve for users going long
616    /// precision: AMM_RESERVE_PRECISION
617    pub ask_quote_asset_reserve: u128,
618    /// transformed base_asset_reserve for users going short
619    /// precision: AMM_RESERVE_PRECISION
620    pub bid_base_asset_reserve: u128,
621    /// transformed quote_asset_reserve for users going short
622    /// precision: AMM_RESERVE_PRECISION
623    pub bid_quote_asset_reserve: u128,
624    /// the last seen oracle price partially shrunk toward the amm reserve price
625    /// precision: PRICE_PRECISION
626    pub last_oracle_normalised_price: i64,
627    /// the gap between the oracle price and the reserve price = y * peg_multiplier / x
628    pub last_oracle_reserve_price_spread_pct: i64,
629    /// average estimate of bid price over funding_period
630    /// precision: PRICE_PRECISION
631    pub last_bid_price_twap: u64,
632    /// average estimate of ask price over funding_period
633    /// precision: PRICE_PRECISION
634    pub last_ask_price_twap: u64,
635    /// average estimate of (bid+ask)/2 price over funding_period
636    /// precision: PRICE_PRECISION
637    pub last_mark_price_twap: u64,
638    /// average estimate of (bid+ask)/2 price over FIVE_MINUTES
639    pub last_mark_price_twap_5min: u64,
640    /// the last blockchain slot the amm was updated
641    pub last_update_slot: u64,
642    /// the pct size of the oracle confidence interval
643    /// precision: PERCENTAGE_PRECISION
644    pub last_oracle_conf_pct: u64,
645    /// the total_fee_minus_distribution change since the last funding update
646    /// precision: QUOTE_PRECISION
647    pub net_revenue_since_last_funding: i64,
648    /// the last funding rate update unix_timestamp
649    pub last_funding_rate_ts: i64,
650    /// the peridocity of the funding rate updates
651    pub funding_period: i64,
652    /// the base step size (increment) of orders
653    /// precision: BASE_PRECISION
654    pub order_step_size: u64,
655    /// the price tick size of orders
656    /// precision: PRICE_PRECISION
657    pub order_tick_size: u64,
658    /// the minimum base size of an order
659    /// precision: BASE_PRECISION
660    pub min_order_size: u64,
661    /// the max base size a single user can have
662    /// precision: BASE_PRECISION
663    pub max_position_size: u64,
664    /// estimated total of volume in market
665    /// QUOTE_PRECISION
666    pub volume_24h: u64,
667    /// the volume intensity of long fills against AMM
668    pub long_intensity_volume: u64,
669    /// the volume intensity of short fills against AMM
670    pub short_intensity_volume: u64,
671    /// the blockchain unix timestamp at the time of the last trade
672    pub last_trade_ts: i64,
673    /// estimate of standard deviation of the fill (mark) prices
674    /// precision: PRICE_PRECISION
675    pub mark_std: u64,
676    /// estimate of standard deviation of the oracle price at each update
677    /// precision: PRICE_PRECISION
678    pub oracle_std: u64,
679    /// the last unix_timestamp the mark twap was updated
680    pub last_mark_price_twap_ts: i64,
681    /// the minimum spread the AMM can quote. also used as step size for some spread logic increases.
682    pub base_spread: u32,
683    /// the maximum spread the AMM can quote
684    pub max_spread: u32,
685    /// the spread for asks vs the reserve price
686    pub long_spread: u32,
687    /// the spread for bids vs the reserve price
688    pub short_spread: u32,
689    /// the count intensity of long fills against AMM
690    pub long_intensity_count: u32,
691    /// the count intensity of short fills against AMM
692    pub short_intensity_count: u32,
693    /// the fraction of total available liquidity a single fill on the AMM can consume
694    pub max_fill_reserve_fraction: u16,
695    /// the maximum slippage a single fill on the AMM can push
696    pub max_slippage_ratio: u16,
697    /// the update intensity of AMM formulaic updates (adjusting k). 0-100
698    pub curve_update_intensity: u8,
699    /// the jit intensity of AMM. larger intensity means larger participation in jit. 0 means no jit participation.
700    /// (0, 100] is intensity for protocol-owned AMM. (100, 200] is intensity for user LP-owned AMM.
701    pub amm_jit_intensity: u8,
702    /// the oracle provider information. used to decode/scale the oracle public key
703    pub oracle_source: OracleSource,
704    /// tracks whether the oracle was considered valid at the last AMM update
705    pub last_oracle_valid: bool,
706    /// the target value for `base_asset_amount_per_lp`, used during AMM JIT with LP split
707    /// precision: BASE_PRECISION
708    pub target_base_asset_amount_per_lp: i32,
709    /// expo for unit of per_lp, base 10 (if per_lp_base=X, then per_lp unit is 10^X)
710    pub per_lp_base: i8,
711    pub padding1: u8,
712    pub padding2: u16,
713    pub total_fee_earned_per_lp: u64,
714    pub net_unsettled_funding_pnl: i64,
715    pub quote_asset_amount_with_unsettled_lp: i64,
716    pub reference_price_offset: i32,
717    pub padding: [u8; 12],
718}
719
720#[derive(Default, AnchorSerialize, AnchorDeserialize, Clone, Copy, Eq, PartialEq, Debug)]
721#[repr(C)]
722pub struct HistoricalOracleData {
723    /// precision: PRICE_PRECISION
724    pub last_oracle_price: i64,
725    /// precision: PRICE_PRECISION
726    pub last_oracle_conf: u64,
727    /// number of slots since last update
728    pub last_oracle_delay: i64,
729    /// precision: PRICE_PRECISION
730    pub last_oracle_price_twap: i64,
731    /// precision: PRICE_PRECISION
732    pub last_oracle_price_twap_5min: i64,
733    /// unix_timestamp of last snapshot
734    pub last_oracle_price_twap_ts: i64,
735}
736
737impl Default for AMM {
738    fn default() -> Self {
739        AMM {
740            oracle: Pubkey::default(),
741            historical_oracle_data: HistoricalOracleData::default(),
742            base_asset_amount_per_lp: 0,
743            quote_asset_amount_per_lp: 0,
744            fee_pool: PoolBalance::default(),
745            base_asset_reserve: 0,
746            quote_asset_reserve: 0,
747            concentration_coef: 0,
748            min_base_asset_reserve: 0,
749            max_base_asset_reserve: 0,
750            sqrt_k: 0,
751            peg_multiplier: 0,
752            terminal_quote_asset_reserve: 0,
753            base_asset_amount_long: 0,
754            base_asset_amount_short: 0,
755            base_asset_amount_with_amm: 0,
756            base_asset_amount_with_unsettled_lp: 0,
757            max_open_interest: 0,
758            quote_asset_amount: 0,
759            quote_entry_amount_long: 0,
760            quote_entry_amount_short: 0,
761            quote_break_even_amount_long: 0,
762            quote_break_even_amount_short: 0,
763            user_lp_shares: 0,
764            last_funding_rate: 0,
765            last_funding_rate_long: 0,
766            last_funding_rate_short: 0,
767            last_24h_avg_funding_rate: 0,
768            total_fee: 0,
769            total_mm_fee: 0,
770            total_exchange_fee: 0,
771            total_fee_minus_distributions: 0,
772            total_fee_withdrawn: 0,
773            total_liquidation_fee: 0,
774            cumulative_funding_rate_long: 0,
775            cumulative_funding_rate_short: 0,
776            total_social_loss: 0,
777            ask_base_asset_reserve: 0,
778            ask_quote_asset_reserve: 0,
779            bid_base_asset_reserve: 0,
780            bid_quote_asset_reserve: 0,
781            last_oracle_normalised_price: 0,
782            last_oracle_reserve_price_spread_pct: 0,
783            last_bid_price_twap: 0,
784            last_ask_price_twap: 0,
785            last_mark_price_twap: 0,
786            last_mark_price_twap_5min: 0,
787            last_update_slot: 0,
788            last_oracle_conf_pct: 0,
789            net_revenue_since_last_funding: 0,
790            last_funding_rate_ts: 0,
791            funding_period: 0,
792            order_step_size: 0,
793            order_tick_size: 0,
794            min_order_size: 1,
795            max_position_size: 0,
796            volume_24h: 0,
797            long_intensity_volume: 0,
798            short_intensity_volume: 0,
799            last_trade_ts: 0,
800            mark_std: 0,
801            oracle_std: 0,
802            last_mark_price_twap_ts: 0,
803            base_spread: 0,
804            max_spread: 0,
805            long_spread: 0,
806            short_spread: 0,
807            long_intensity_count: 0,
808            short_intensity_count: 0,
809            max_fill_reserve_fraction: 0,
810            max_slippage_ratio: 0,
811            curve_update_intensity: 0,
812            amm_jit_intensity: 0,
813            oracle_source: OracleSource::default(),
814            last_oracle_valid: false,
815            target_base_asset_amount_per_lp: 0,
816            per_lp_base: 0,
817            padding1: 0,
818            padding2: 0,
819            total_fee_earned_per_lp: 0,
820            net_unsettled_funding_pnl: 0,
821            quote_asset_amount_with_unsettled_lp: 0,
822            reference_price_offset: 0,
823            padding: [0; 12],
824        }
825    }
826}
827
828pub trait SafeUnwrap {
829    type Item;
830    fn safe_unwrap(self) -> std::result::Result<Self::Item, ReflectErrorCodes>;
831}
832
833impl<T> SafeUnwrap for Option<T> {
834    type Item = T;
835
836    #[track_caller]
837    #[inline(always)]
838    fn safe_unwrap(self) -> std::result::Result<T, ReflectErrorCodes> {
839        match self {
840            Some(v) => Ok(v),
841            None => {
842                let caller = Location::caller();
843                msg!("Unwrap error thrown at {}:{}", caller.file(), caller.line());
844                Err(ReflectErrorCodes::FailedUnwrap) // Removed .into() since we're returning ReflectErrorCodes directly
845            }
846        }
847    }
848}
849
850impl<T> SafeUnwrap for std::result::Result<T, ReflectErrorCodes> {
851    type Item = T;
852
853    #[track_caller]
854    #[inline(always)]
855    fn safe_unwrap(self) -> std::result::Result<T, ReflectErrorCodes> {
856        match self {
857            Ok(v) => Ok(v),
858            Err(_) => {
859                let caller = Location::caller();
860                msg!("Unwrap error thrown at {}:{}", caller.file(), caller.line());
861                Err(ReflectErrorCodes::FailedUnwrap) // Removed .into() since we're returning ReflectErrorCodes directly
862            }
863        }
864    }
865}
866
867#[macro_export]
868macro_rules! validate {
869    ($assert:expr, $err:expr) => {
870        {
871            if ($assert) {
872                Ok(())
873            } else {
874                let error_code: ReflectErrorCodes = $err;
875                msg!("Error {} thrown at {}:{}", error_code, file!(), line!());
876                Err(error_code)
877            }
878        }
879    };
880    (
881        $assert:expr,
882        $err:expr,
883        $($arg:tt)+
884    ) => {
885        {
886        if ($assert) {
887            Ok(())
888        } else {
889            let error_code: ReflectErrorCodes = $err;
890            msg!("Error {} thrown at {}:{}", error_code, file!(), line!());
891            msg!($($arg)*);
892            Err(error_code)
893        }
894        }
895    };
896}
897
898
899#[derive(AnchorSerialize, AnchorDeserialize, Clone, Copy, Eq, PartialEq, Debug, Default, Ord, PartialOrd,)]
900pub enum OracleSource {
901    #[default]
902    Pyth,
903    Switchboard,
904    QuoteAsset,
905    Pyth1K,
906    Pyth1M,
907    PythStableCoin,
908    Prelaunch,
909    PythPull,
910    Pyth1KPull,
911    Pyth1MPull,
912    PythStableCoinPull,
913    SwitchboardOnDemand,
914    PythLazer,
915    PythLazer1K,
916    PythLazer1M,
917    PythLazerStableCoin,
918}
919
920pub trait SafeMath: Sized {
921    fn safe_add(self, rhs: Self) -> Result<Self>;
922    fn safe_sub(self, rhs: Self) -> Result<Self>;
923    fn safe_mul(self, rhs: Self) -> Result<Self>;
924    fn safe_div(self, rhs: Self) -> Result<Self>;
925    fn safe_div_ceil(self, rhs: Self) -> Result<Self>;
926}
927
928impl From<Error> for ReflectErrorCodes {
929    fn from(err: Error) -> Self {
930        ReflectErrorCodes::MathError // or whatever error code makes most sense as default
931    }
932}
933
934pub trait Cast: Sized {
935    #[track_caller]
936    #[inline(always)]
937    fn cast<T: std::convert::TryFrom<Self>>(self) -> Result<T> {
938        match self.try_into() {
939            Ok(result) => Ok(result),
940            Err(_) => {
941                let caller = Location::caller();
942                msg!(
943                    "Casting error thrown at {}:{}",
944                    caller.file(),
945                    caller.line()
946                );
947                Err(ReflectErrorCodes::ConversionFailed.into())
948            }
949        }
950    }
951}
952
953impl Cast for u128 {}
954impl Cast for u64 {}
955impl Cast for u32 {}
956impl Cast for u16 {}
957impl Cast for u8 {}
958impl Cast for i128 {}
959impl Cast for i64 {}
960impl Cast for i32 {}
961impl Cast for i16 {}
962impl Cast for i8 {}
963impl Cast for bool {}
964
965macro_rules! checked_impl {
966    ($t:ty) => {
967        impl SafeMath for $t {
968            #[track_caller]
969            #[inline(always)]
970            fn safe_add(self, v: $t) -> Result<$t> {
971                match self.checked_add(v) {
972                    Some(result) => Ok(result),
973                    None => {
974                        let caller = Location::caller();
975                        msg!("Math error thrown at {}:{}", caller.file(), caller.line());
976                        Err(ReflectErrorCodes::MathError.into())
977                    }
978                }
979            }
980
981            #[track_caller]
982            #[inline(always)]
983            fn safe_sub(self, v: $t) -> Result<$t> {
984                match self.checked_sub(v) {
985                    Some(result) => Ok(result),
986                    None => {
987                        let caller = Location::caller();
988                        msg!("Math error thrown at {}:{}", caller.file(), caller.line());
989                        Err(ReflectErrorCodes::MathError.into())
990                    }
991                }
992            }
993
994            #[track_caller]
995            #[inline(always)]
996            fn safe_mul(self, v: $t) -> Result<$t> {
997                match self.checked_mul(v) {
998                    Some(result) => Ok(result),
999                    None => {
1000                        let caller = Location::caller();
1001                        msg!("Math error thrown at {}:{}", caller.file(), caller.line());
1002                        Err(ReflectErrorCodes::MathError.into())
1003                    }
1004                }
1005            }
1006
1007            #[track_caller]
1008            #[inline(always)]
1009            fn safe_div(self, v: $t) -> Result<$t> {
1010                match self.checked_div(v) {
1011                    Some(result) => Ok(result),
1012                    None => {
1013                        let caller = Location::caller();
1014                        msg!("Math error thrown at {}:{}", caller.file(), caller.line());
1015                        Err(ReflectErrorCodes::MathError.into())
1016                    }
1017                }
1018            }
1019
1020            #[track_caller]
1021            #[inline(always)]
1022            fn safe_div_ceil(self, v: $t) -> Result<$t> {
1023                match self.checked_ceil_div(v) {
1024                    Some(result) => Ok(result),
1025                    None => {
1026                        let caller = Location::caller();
1027                        msg!("Math error thrown at {}:{}", caller.file(), caller.line());
1028                        Err(ReflectErrorCodes::MathError.into())
1029                    }
1030                }
1031            }
1032        }
1033    };
1034}
1035checked_impl!(u128);
1036checked_impl!(u64);
1037checked_impl!(u32);
1038checked_impl!(u16);
1039checked_impl!(u8);
1040checked_impl!(i128);
1041checked_impl!(i64);
1042checked_impl!(i32);
1043checked_impl!(i16);
1044checked_impl!(i8);
1045
1046pub trait SafeDivFloor: Sized {
1047    /// Perform floor division
1048    fn safe_div_floor(self, rhs: Self) -> Result<Self>;
1049}
1050
1051pub trait CheckedFloorDiv: Sized {
1052    /// Perform floor division
1053    fn checked_floor_div(&self, rhs: Self) -> Option<Self>;
1054}
1055
1056macro_rules! checked_impl {
1057    ($t:ty) => {
1058        impl CheckedFloorDiv for $t {
1059            #[track_caller]
1060            #[inline]
1061            fn checked_floor_div(&self, rhs: $t) -> Option<$t> {
1062                let quotient = self.checked_div(rhs)?;
1063
1064                let remainder = self.checked_rem(rhs)?;
1065
1066                if remainder != <$t>::zero() {
1067                    quotient.checked_sub(<$t>::one())
1068                } else {
1069                    Some(quotient)
1070                }
1071            }
1072        }
1073    };
1074}
1075
1076macro_rules! div_floor_impl {
1077    ($t:ty) => {
1078        impl SafeDivFloor for $t {
1079            #[track_caller]
1080            #[inline(always)]
1081            fn safe_div_floor(self, v: $t) -> Result<$t> {
1082                match self.checked_floor_div(v) {
1083                    Some(result) => Ok(result),
1084                    None => {
1085                        let caller = Location::caller();
1086                        msg!("Math error thrown at {}:{}", caller.file(), caller.line());
1087                        Err(ReflectErrorCodes::MathError.into())
1088                    }
1089                }
1090            }
1091        }
1092    };
1093}
1094
1095div_floor_impl!(i128);
1096div_floor_impl!(i64);
1097div_floor_impl!(i32);
1098div_floor_impl!(i16);
1099div_floor_impl!(i8);
1100
1101checked_impl!(u128);
1102checked_impl!(u64);
1103checked_impl!(u32);
1104checked_impl!(u16);
1105checked_impl!(u8);
1106checked_impl!(i128);
1107checked_impl!(i64);
1108checked_impl!(i32);
1109checked_impl!(i16);
1110checked_impl!(i8);
1111
1112pub trait CheckedCeilDiv: Sized {
1113    /// Perform ceiling division
1114    fn checked_ceil_div(&self, rhs: Self) -> Option<Self>;
1115}
1116
1117macro_rules! checked_impl {
1118    ($t:ty) => {
1119        impl CheckedCeilDiv for $t {
1120            #[track_caller]
1121            #[inline]
1122            fn checked_ceil_div(&self, rhs: $t) -> Option<$t> {
1123                let quotient = self.checked_div(rhs)?;
1124
1125                let remainder = self.checked_rem(rhs)?;
1126
1127                if remainder > <$t>::zero() {
1128                    quotient.checked_add(<$t>::one())
1129                } else {
1130                    Some(quotient)
1131                }
1132            }
1133        }
1134    };
1135}
1136
1137checked_impl!(u128);
1138checked_impl!(u64);
1139checked_impl!(u32);
1140checked_impl!(u16);
1141checked_impl!(u8);
1142checked_impl!(i128);
1143checked_impl!(i64);
1144checked_impl!(i32);
1145checked_impl!(i16);
1146checked_impl!(i8);
1147
1148
1149#[derive(Clone, PartialEq, Debug, Eq, Default)]
1150pub struct UserSpots {
1151    pub spot_positions: [SpotPosition; SPOT_POSITION_COUNT], 
1152}
1153
1154#[inline(never)]
1155pub fn get_token_amount(
1156    balance: u128,
1157    spot_market: &SpotMarket,
1158    balance_type: &SpotBalanceType,
1159) -> Result<u128> {
1160
1161    // Hardcoded because of reasons.
1162    let precision_decrease = (10_u128).pow((19_u32).safe_sub(6)?);
1163
1164    let cumulative_interest = match balance_type {
1165        SpotBalanceType::Deposit => spot_market.cumulative_deposit_interest,
1166        SpotBalanceType::Borrow => spot_market.cumulative_borrow_interest,
1167    };
1168
1169    let token_amount = match balance_type {
1170        SpotBalanceType::Deposit => balance
1171            .safe_mul(cumulative_interest)?
1172            .safe_div(precision_decrease)?,
1173        SpotBalanceType::Borrow => balance
1174            .safe_mul(cumulative_interest)?
1175            .safe_div_ceil(precision_decrease)?,
1176    };
1177
1178    Ok(token_amount)
1179}
1180
1181pub const PUBKEY_LENGTH: usize = 32;
1182pub const NAME_LENGTH: usize = 32;
1183pub const SPOT_POSITION_COUNT: usize = 8;
1184pub const ANCHOR_DISCRIMINATOR_SIZE: usize = 8;
1185
1186// Calculate the offset of spot_positions
1187pub const SPOT_POSITIONS_OFFSET: usize =  
1188    PUBKEY_LENGTH + // authority
1189    PUBKEY_LENGTH + // delegate
1190    NAME_LENGTH;
1191
1192// Calculate the offset of perp_positions.
1193pub const PERP_POSITIONS_OFFSET: usize = ANCHOR_DISCRIMINATOR_SIZE +
1194    PUBKEY_LENGTH * 2 + // authority and delegate
1195    NAME_LENGTH +
1196    std::mem::size_of::<SpotPosition>() * SPOT_POSITION_COUNT;
1197
1198
1199pub struct ForeignAccountLoader<'info, T: Pod> {
1200    acc_info: &'info AccountInfo<'info>,
1201    phantom: PhantomData<T>,
1202}
1203
1204impl<'info, T: Pod> ForeignAccountLoader<'info, T> {
1205    pub fn try_from_unchecked(
1206        acc_info: &'info AccountInfo<'info>
1207    ) -> std::result::Result<Self, Error> {
1208        Ok(Self {
1209            acc_info,
1210            phantom: PhantomData,
1211        })
1212    }
1213
1214    pub fn load(&self) -> std::result::Result<Ref<T>, Error> {
1215        let data = self.acc_info.try_borrow_data()?;
1216        Ok(Ref::map(data, |data| bytemuck::from_bytes(&data[8..])))
1217    }
1218
1219    pub fn load_mut(&self) -> std::result::Result<RefMut<T>, Error> {
1220        let data = self.acc_info.try_borrow_mut_data()?;
1221        Ok(RefMut::map(data, |data| bytemuck::from_bytes_mut(&mut data[8..])))
1222    }
1223}