11//! Program state processor
22
33use crate :: {
4- self as spl_token_lending,
4+ self as spl_token_lending, emit_log_event ,
55 error:: LendingError ,
66 instruction:: LendingInstruction ,
7- logs:: { emit_log_event, PythOraclePriceUpdate , SwitchboardV1OraclePriceUpdate } ,
7+ logs:: {
8+ LogEventType , ProgramVersion , PythError , PythOraclePriceUpdate , ReserveStateUpdate ,
9+ SwitchboardError , SwitchboardV1OraclePriceUpdate ,
10+ } ,
811 math:: { Decimal , Rate , TryAdd , TryDiv , TryMul , TrySub , WAD } ,
912 pyth,
1013 state:: {
1114 CalculateBorrowResult , CalculateLiquidationResult , CalculateRepayResult ,
1215 InitLendingMarketParams , InitObligationParams , InitReserveParams , LendingMarket ,
1316 NewReserveCollateralParams , NewReserveLiquidityParams , Obligation , Reserve ,
14- ReserveCollateral , ReserveConfig , ReserveLiquidity ,
17+ ReserveCollateral , ReserveConfig , ReserveLiquidity , PROGRAM_VERSION ,
1518 } ,
1619} ;
1720use num_traits:: FromPrimitive ;
@@ -40,6 +43,11 @@ pub fn process_instruction(
4043 accounts : & [ AccountInfo ] ,
4144 input : & [ u8 ] ,
4245) -> ProgramResult {
46+ emit_log_event ! ( & ProgramVersion {
47+ event_type: LogEventType :: ProgramVersion ,
48+ version: PROGRAM_VERSION ,
49+ } ) ;
50+
4351 let instruction = LendingInstruction :: unpack ( input) ?;
4452 match instruction {
4553 LendingInstruction :: InitLendingMarket {
@@ -432,6 +440,15 @@ fn _refresh_reserve_interest<'a>(
432440
433441 reserve. accrue_interest ( clock. slot ) ?;
434442 reserve. last_update . update_slot ( clock. slot ) ;
443+ emit_log_event ! ( & ReserveStateUpdate {
444+ event_type: LogEventType :: ReserveStateUpdate ,
445+ reserve_id: * reserve_info. key,
446+ available_amount: reserve. liquidity. available_amount,
447+ borrowed_amount_wads: reserve. liquidity. borrowed_amount_wads,
448+ cumulative_borrow_rate_wads: reserve. liquidity. cumulative_borrow_rate_wads,
449+ collateral_mint_total_supply: reserve. collateral. mint_total_supply,
450+ collateral_exchange_rate: reserve. collateral_exchange_rate( ) ?. to_string( ) ,
451+ } ) ;
435452 Reserve :: pack ( reserve, & mut reserve_info. data . borrow_mut ( ) ) ?;
436453
437454 Ok ( ( ) )
@@ -807,7 +824,6 @@ fn process_refresh_obligation(program_id: &Pubkey, accounts: &[AccountInfo]) ->
807824 let decimals = 10u64
808825 . checked_pow ( deposit_reserve. liquidity . mint_decimals as u32 )
809826 . ok_or ( LendingError :: MathOverflow ) ?;
810-
811827 let market_value = deposit_reserve
812828 . collateral_exchange_rate ( ) ?
813829 . decimal_collateral_to_liquidity ( collateral. deposited_amount . into ( ) ) ?
@@ -2153,15 +2169,24 @@ fn get_pyth_price(pyth_price_info: &AccountInfo, clock: &Clock) -> Result<Decima
21532169 . map_err ( |_| ProgramError :: InvalidAccountData ) ?;
21542170
21552171 if pyth_price. ptype != pyth:: PriceType :: Price {
2156- msg ! ( "Oracle price type is invalid {}" , pyth_price. ptype as u8 ) ;
2172+ emit_log_event ! ( & PythError {
2173+ event_type: LogEventType :: PythError ,
2174+ oracle_pubkey: * pyth_price_info. key,
2175+ error_message: format!( "Oracle price type is invalid: {}" , pyth_price. ptype as u8 ) ,
2176+ } ) ;
2177+
21572178 return Err ( LendingError :: InvalidOracleConfig . into ( ) ) ;
21582179 }
21592180
21602181 if pyth_price. agg . status != pyth:: PriceStatus :: Trading {
2161- msg ! (
2162- "Oracle price status is invalid: {}" ,
2163- pyth_price. agg. status as u8
2164- ) ;
2182+ emit_log_event ! ( & PythError {
2183+ event_type: LogEventType :: PythError ,
2184+ oracle_pubkey: * pyth_price_info. key,
2185+ error_message: format!(
2186+ "Oracle price status is invalid: {}" ,
2187+ pyth_price. agg. status as u8
2188+ ) ,
2189+ } ) ;
21652190 return Err ( LendingError :: InvalidOracleConfig . into ( ) ) ;
21662191 }
21672192
@@ -2170,12 +2195,20 @@ fn get_pyth_price(pyth_price_info: &AccountInfo, clock: &Clock) -> Result<Decima
21702195 . checked_sub ( pyth_price. valid_slot )
21712196 . ok_or ( LendingError :: MathOverflow ) ?;
21722197 if slots_elapsed >= STALE_AFTER_SLOTS_ELAPSED {
2173- msg ! ( "Pyth oracle price is stale" ) ;
2198+ emit_log_event ! ( & PythError {
2199+ event_type: LogEventType :: PythError ,
2200+ oracle_pubkey: * pyth_price_info. key,
2201+ error_message: format!( "Pyth oracle price is stale: {} slots old." , slots_elapsed) ,
2202+ } ) ;
21742203 return Err ( LendingError :: InvalidOracleConfig . into ( ) ) ;
21752204 }
21762205
21772206 let price: u64 = pyth_price. agg . price . try_into ( ) . map_err ( |_| {
2178- msg ! ( "Oracle price cannot be negative" ) ;
2207+ emit_log_event ! ( & PythError {
2208+ event_type: LogEventType :: PythError ,
2209+ oracle_pubkey: * pyth_price_info. key,
2210+ error_message: "Oracle price cannot be negative" . to_string( ) ,
2211+ } ) ;
21792212 LendingError :: InvalidOracleConfig
21802213 } ) ?;
21812214
@@ -2186,11 +2219,15 @@ fn get_pyth_price(pyth_price_info: &AccountInfo, clock: &Clock) -> Result<Decima
21862219 // 100/confidence_ratio = maximum size of confidence range as a percent of price
21872220 // confidence_ratio of 10 filters out pyth prices with conf > 10% of price
21882221 if conf. checked_mul ( confidence_ratio) . unwrap ( ) > price {
2189- msg ! (
2190- "Oracle price confidence is too wide. price: {}, conf: {}" ,
2191- price,
2192- conf,
2193- ) ;
2222+ emit_log_event ! ( & PythError {
2223+ event_type: LogEventType :: PythError ,
2224+ oracle_pubkey: * pyth_price_info. key,
2225+ error_message: format!(
2226+ "Oracle price confidence is too wide. price: {}, conf: {}" ,
2227+ price, conf
2228+ ) ,
2229+ } ) ;
2230+
21942231 return Err ( LendingError :: InvalidOracleConfig . into ( ) ) ;
21952232 }
21962233
@@ -2215,10 +2252,11 @@ fn get_pyth_price(pyth_price_info: &AccountInfo, clock: &Clock) -> Result<Decima
22152252 . ok_or ( LendingError :: MathOverflow ) ?;
22162253 Decimal :: from ( price) . try_div ( decimals) ?
22172254 } ;
2218- emit_log_event ( & PythOraclePriceUpdate {
2255+ emit_log_event ! ( & PythOraclePriceUpdate {
2256+ event_type: LogEventType :: PythOraclePriceUpdate ,
22192257 oracle_pubkey: * pyth_price_info. key,
22202258 price: market_price,
2221- conf : conf,
2259+ confidence : conf,
22222260 published_slot: pyth_price. valid_slot,
22232261 } ) ;
22242262
@@ -2238,7 +2276,11 @@ fn get_switchboard_price(
22382276 let account_buf = switchboard_feed_info. try_borrow_data ( ) ?;
22392277 // first byte type discriminator
22402278 if account_buf[ 0 ] != SwitchboardAccountType :: TYPE_AGGREGATOR as u8 {
2241- msg ! ( "switchboard address not of type aggregator" ) ;
2279+ emit_log_event ! ( & SwitchboardError {
2280+ event_type: LogEventType :: SwitchboardError ,
2281+ oracle_pubkey: * switchboard_feed_info. key,
2282+ error_message: "Switchboard feed is not of type aggregator" . to_string( ) ,
2283+ } ) ;
22422284 return Err ( LendingError :: InvalidAccountInput . into ( ) ) ;
22432285 }
22442286
@@ -2254,7 +2296,11 @@ fn get_switchboard_price(
22542296 . checked_sub ( open_slot)
22552297 . ok_or ( LendingError :: MathOverflow ) ?;
22562298 if slots_elapsed >= STALE_AFTER_SLOTS_ELAPSED {
2257- msg ! ( "Switchboard oracle price is stale" ) ;
2299+ emit_log_event ! ( & SwitchboardError {
2300+ event_type: LogEventType :: SwitchboardError ,
2301+ oracle_pubkey: * switchboard_feed_info. key,
2302+ error_message: format!( "Oracle price is stale by {} slots" , slots_elapsed) ,
2303+ } ) ;
22582304 return Err ( LendingError :: InvalidOracleConfig . into ( ) ) ;
22592305 }
22602306
@@ -2266,7 +2312,8 @@ fn get_switchboard_price(
22662312 let price = ( ( price_quotient as f64 ) * price_float) as u128 ;
22672313
22682314 let market_price = Decimal :: from ( price) . try_div ( price_quotient) ?;
2269- emit_log_event ( & SwitchboardV1OraclePriceUpdate {
2315+ emit_log_event ! ( & SwitchboardV1OraclePriceUpdate {
2316+ event_type: LogEventType :: SwitchboardV1OraclePriceUpdate ,
22702317 oracle_pubkey: * switchboard_feed_info. key,
22712318 price: market_price,
22722319 published_slot: open_slot,
0 commit comments