dexter_storage_proto/
lib.rs

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            // Deprecated bincode serialized status metadata doesn't support
238            // loaded addresses.
239            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}