1use {
2 serde::{Deserialize, Serialize},
3 solana_account_decoder::{
4 parse_token::{real_number_string_trimmed, UiTokenAmount},
5 StringAmount,
6 },
7 solana_sdk::{
8 deserialize_utils::default_on_eof, message::v0::LoadedAddresses, transaction::Result,
9 transaction_context::TransactionReturnData,
10 },
11 solana_transaction_status::{
12 InnerInstructions, Reward, RewardType, TransactionStatusMeta, TransactionTokenBalance,
13 },
14 std::str::FromStr,
15};
16
17pub mod convert;
18
19pub type StoredExtendedRewards = Vec<StoredExtendedReward>;
20
21#[derive(Serialize, Deserialize)]
22pub struct StoredExtendedReward {
23 pubkey: String,
24 lamports: i64,
25 #[serde(deserialize_with = "default_on_eof")]
26 post_balance: u64,
27 #[serde(deserialize_with = "default_on_eof")]
28 reward_type: Option<RewardType>,
29 #[serde(deserialize_with = "default_on_eof")]
30 commission: Option<u8>,
31}
32
33impl From<StoredExtendedReward> for Reward {
34 fn from(value: StoredExtendedReward) -> Self {
35 let StoredExtendedReward {
36 pubkey,
37 lamports,
38 post_balance,
39 reward_type,
40 commission,
41 } = value;
42 Self {
43 pubkey,
44 lamports,
45 post_balance,
46 reward_type,
47 commission,
48 }
49 }
50}
51
52impl From<Reward> for StoredExtendedReward {
53 fn from(value: Reward) -> Self {
54 let Reward {
55 pubkey,
56 lamports,
57 post_balance,
58 reward_type,
59 commission,
60 } = value;
61 Self {
62 pubkey,
63 lamports,
64 post_balance,
65 reward_type,
66 commission,
67 }
68 }
69}
70
71#[derive(Serialize, Deserialize)]
72pub struct StoredTokenAmount {
73 pub ui_amount: f64,
74 pub decimals: u8,
75 pub amount: StringAmount,
76}
77
78impl From<StoredTokenAmount> for UiTokenAmount {
79 fn from(value: StoredTokenAmount) -> Self {
80 let StoredTokenAmount {
81 ui_amount,
82 decimals,
83 amount,
84 } = value;
85 let ui_amount_string =
86 real_number_string_trimmed(u64::from_str(&amount).unwrap_or(0), decimals);
87 Self {
88 ui_amount: Some(ui_amount),
89 decimals,
90 amount,
91 ui_amount_string,
92 }
93 }
94}
95
96impl From<UiTokenAmount> for StoredTokenAmount {
97 fn from(value: UiTokenAmount) -> Self {
98 let UiTokenAmount {
99 ui_amount,
100 decimals,
101 amount,
102 ..
103 } = value;
104 Self {
105 ui_amount: ui_amount.unwrap_or(0.0),
106 decimals,
107 amount,
108 }
109 }
110}
111
112#[derive(Serialize, Deserialize)]
113pub struct StoredTransactionTokenBalance {
114 pub account_index: u8,
115 pub mint: String,
116 pub ui_token_amount: StoredTokenAmount,
117 #[serde(deserialize_with = "default_on_eof")]
118 pub owner: String,
119 #[serde(deserialize_with = "default_on_eof")]
120 pub program_id: String,
121}
122
123impl From<StoredTransactionTokenBalance> for TransactionTokenBalance {
124 fn from(value: StoredTransactionTokenBalance) -> Self {
125 let StoredTransactionTokenBalance {
126 account_index,
127 mint,
128 ui_token_amount,
129 owner,
130 program_id,
131 } = value;
132 Self {
133 account_index,
134 mint,
135 ui_token_amount: ui_token_amount.into(),
136 owner,
137 program_id,
138 }
139 }
140}
141
142impl From<TransactionTokenBalance> for StoredTransactionTokenBalance {
143 fn from(value: TransactionTokenBalance) -> Self {
144 let TransactionTokenBalance {
145 account_index,
146 mint,
147 ui_token_amount,
148 owner,
149 program_id,
150 } = value;
151 Self {
152 account_index,
153 mint,
154 ui_token_amount: ui_token_amount.into(),
155 owner,
156 program_id,
157 }
158 }
159}
160
161#[derive(Serialize, Deserialize)]
162pub struct StoredTransactionStatusMeta {
163 pub status: Result<()>,
164 pub fee: u64,
165 pub pre_balances: Vec<u64>,
166 pub post_balances: Vec<u64>,
167 #[serde(deserialize_with = "default_on_eof")]
168 pub inner_instructions: Option<Vec<InnerInstructions>>,
169 #[serde(deserialize_with = "default_on_eof")]
170 pub log_messages: Option<Vec<String>>,
171 #[serde(deserialize_with = "default_on_eof")]
172 pub pre_token_balances: Option<Vec<StoredTransactionTokenBalance>>,
173 #[serde(deserialize_with = "default_on_eof")]
174 pub post_token_balances: Option<Vec<StoredTransactionTokenBalance>>,
175 #[serde(deserialize_with = "default_on_eof")]
176 pub rewards: Option<Vec<StoredExtendedReward>>,
177 #[serde(deserialize_with = "default_on_eof")]
178 pub return_data: Option<TransactionReturnData>,
179 #[serde(deserialize_with = "default_on_eof")]
180 pub compute_units_consumed: Option<u64>,
181}
182
183impl From<StoredTransactionStatusMeta> for TransactionStatusMeta {
184 fn from(value: StoredTransactionStatusMeta) -> Self {
185 let StoredTransactionStatusMeta {
186 status,
187 fee,
188 pre_balances,
189 post_balances,
190 inner_instructions,
191 log_messages,
192 pre_token_balances,
193 post_token_balances,
194 rewards,
195 return_data,
196 compute_units_consumed,
197 } = value;
198 Self {
199 status,
200 fee,
201 pre_balances,
202 post_balances,
203 inner_instructions,
204 log_messages,
205 pre_token_balances: pre_token_balances
206 .map(|balances| balances.into_iter().map(|balance| balance.into()).collect()),
207 post_token_balances: post_token_balances
208 .map(|balances| balances.into_iter().map(|balance| balance.into()).collect()),
209 rewards: rewards
210 .map(|rewards| rewards.into_iter().map(|reward| reward.into()).collect()),
211 loaded_addresses: LoadedAddresses::default(),
212 return_data,
213 compute_units_consumed,
214 }
215 }
216}
217
218impl TryFrom<TransactionStatusMeta> for StoredTransactionStatusMeta {
219 type Error = bincode::Error;
220 fn try_from(value: TransactionStatusMeta) -> std::result::Result<Self, Self::Error> {
221 let TransactionStatusMeta {
222 status,
223 fee,
224 pre_balances,
225 post_balances,
226 inner_instructions,
227 log_messages,
228 pre_token_balances,
229 post_token_balances,
230 rewards,
231 loaded_addresses,
232 return_data,
233 compute_units_consumed,
234 } = value;
235
236 if !loaded_addresses.is_empty() {
237 return Err(
240 bincode::ErrorKind::Custom("Bincode serialization is deprecated".into()).into(),
241 );
242 }
243
244 Ok(Self {
245 status,
246 fee,
247 pre_balances,
248 post_balances,
249 inner_instructions,
250 log_messages,
251 pre_token_balances: pre_token_balances
252 .map(|balances| balances.into_iter().map(|balance| balance.into()).collect()),
253 post_token_balances: post_token_balances
254 .map(|balances| balances.into_iter().map(|balance| balance.into()).collect()),
255 rewards: rewards
256 .map(|rewards| rewards.into_iter().map(|reward| reward.into()).collect()),
257 return_data,
258 compute_units_consumed,
259 })
260 }
261}