Skip to content

Commit c4b635a

Browse files
committed
Simplify stuff
1 parent 7b4be89 commit c4b635a

17 files changed

+191
-70
lines changed

Cargo.lock

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

token-lending/program/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ spl-token = { version = "3.2.0", features=["no-entrypoint"] }
2121
switchboard-program = "0.2.0"
2222
thiserror = "1.0"
2323
uint = "=0.9.0"
24+
serde = "1.0"
25+
serde_derive = "1.0"
26+
serde_json = "1.0"
27+
arrform = "0.1.1"
2428

2529
[dev-dependencies]
2630
assert_matches = "1.5.0"

token-lending/program/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ pub mod state;
1414
// Export current sdk types for downstream users building with a different sdk version
1515
pub use solana_program;
1616

17+
#[macro_use]
18+
extern crate serde_derive;
19+
1720
solana_program::declare_id!("So1endDq2YkqhipRh3WViPa8hdiSpxWy6z3Z6tMCpAo");
1821

1922
/// Canonical null pubkey. Prints out as "nu11111111111111111111111111111111111111111"

token-lending/program/src/logs.rs

Lines changed: 77 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
#![allow(missing_docs)]
22
use crate::math::Decimal;
3-
use solana_program::{msg, pubkey::Pubkey};
3+
use solana_program::pubkey::Pubkey;
44
use std::fmt;
55

6-
#[derive(Debug)]
7-
enum LogEventType {
8-
PythOraclePriceUpdateType,
9-
SwitchboardV1OraclePriceUpdateType,
6+
extern crate serde;
7+
extern crate serde_json;
8+
9+
#[derive(Debug, Serialize)]
10+
pub enum LogEventType {
11+
ProgramVersion,
12+
PythError,
13+
PythOraclePriceUpdate,
14+
SwitchboardError,
15+
SwitchboardV1OraclePriceUpdate,
16+
ReserveStateUpdate,
1017
}
1118

1219
impl fmt::Display for LogEventType {
@@ -15,49 +22,85 @@ impl fmt::Display for LogEventType {
1522
}
1623
}
1724

18-
pub fn emit_log_event(e: &dyn LogEvent) {
19-
msg!("Solend Log Event");
20-
msg!(&e.to_string());
21-
}
22-
23-
pub trait LogEvent {
24-
fn to_string(&self) -> String;
25+
#[macro_export]
26+
macro_rules! emit_log_event {
27+
($e:expr) => {
28+
msg!("solend-event-log:");
29+
msg!(&serde_json::to_string($e).unwrap());
30+
};
2531
}
2632

33+
#[derive(Serialize)]
2734
pub struct PythOraclePriceUpdate {
35+
pub event_type: LogEventType,
2836
pub oracle_pubkey: Pubkey,
2937
pub price: Decimal,
30-
pub conf: u64,
38+
pub confidence: u64,
3139
pub published_slot: u64,
3240
}
3341

34-
impl LogEvent for PythOraclePriceUpdate {
35-
fn to_string(&self) -> String {
36-
return format!(
37-
"{},{},{},{},{}",
38-
LogEventType::PythOraclePriceUpdateType.to_string(),
39-
self.oracle_pubkey.to_string(),
40-
self.price.to_string(),
41-
self.conf.to_string(),
42-
self.published_slot,
43-
);
44-
}
42+
#[derive(Serialize)]
43+
pub struct PythError {
44+
pub event_type: LogEventType,
45+
pub oracle_pubkey: Pubkey,
46+
pub error_message: String,
4547
}
4648

49+
#[derive(Serialize)]
4750
pub struct SwitchboardV1OraclePriceUpdate {
51+
pub event_type: LogEventType,
4852
pub oracle_pubkey: Pubkey,
4953
pub price: Decimal,
5054
pub published_slot: u64,
5155
}
5256

53-
impl LogEvent for SwitchboardV1OraclePriceUpdate {
54-
fn to_string(&self) -> String {
55-
return format!(
56-
"{},{},{},{}",
57-
LogEventType::SwitchboardV1OraclePriceUpdateType.to_string(),
58-
self.oracle_pubkey.to_string(),
59-
self.price.to_string(),
60-
self.published_slot,
61-
);
62-
}
57+
#[derive(Serialize)]
58+
pub struct SwitchboardError {
59+
pub event_type: LogEventType,
60+
pub oracle_pubkey: Pubkey,
61+
pub error_message: String,
62+
}
63+
64+
#[derive(Serialize)]
65+
pub struct ProgramVersion {
66+
pub event_type: LogEventType,
67+
pub version: u8,
68+
}
69+
70+
#[derive(Serialize)]
71+
pub struct ReserveStateUpdate {
72+
pub event_type: LogEventType,
73+
pub reserve_id: Pubkey,
74+
pub available_amount: u64,
75+
pub borrowed_amount_wads: Decimal,
76+
pub cumulative_borrow_rate_wads: Decimal,
77+
pub collateral_mint_total_supply: u64,
78+
pub collateral_exchange_rate: String,
79+
}
80+
81+
#[derive(Serialize)]
82+
pub struct ObligationStateUpdate {
83+
pub event_type: LogEventType,
84+
pub obligation_id: Pubkey,
85+
pub deposited_value: Decimal,
86+
pub borrowed_value: Decimal,
87+
pub allowed_borrow_value: Decimal,
88+
pub unhealthy_borrow_value: Decimal,
89+
pub deposits: Vec<DepositLog>,
90+
pub borrows: Vec<BorrowLog>,
91+
}
92+
93+
#[derive(Serialize)]
94+
pub struct DepositLog {
95+
pub reserve_id: Pubkey,
96+
pub deposited_amount: u64,
97+
pub market_value: Decimal,
98+
}
99+
100+
#[derive(Serialize)]
101+
pub struct BorrowLog {
102+
pub reserve_id: Pubkey,
103+
pub cumulative_borrow_rate_wads: Decimal,
104+
pub borrowed_amount_wads: Decimal,
105+
pub market_value: Decimal,
63106
}

token-lending/program/src/math/decimal.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,12 @@ use uint::construct_uint;
2222

2323
// U192 with 192 bits consisting of 3 x 64-bit words
2424
construct_uint! {
25+
#[derive(Serialize)]
2526
pub struct U192(3);
2627
}
2728

2829
/// Large decimal values, precise to 18 digits
29-
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd, Eq, Ord)]
30+
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd, Eq, Ord, Serialize)]
3031
pub struct Decimal(pub U192);
3132

3233
impl Decimal {

token-lending/program/src/processor.rs

Lines changed: 68 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
//! Program state processor
22
33
use 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
};
1720
use 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

Comments
 (0)