solana_trader_client_rust/provider/
utils.rs
1use std::{collections::HashMap, str::FromStr};
2
3use anyhow::Result;
4use base64::{engine::general_purpose, Engine};
5use serde_json::{json, Value};
6use solana_sdk::{
7 address_lookup_table::AddressLookupTableAccount,
8 instruction::{AccountMeta, Instruction},
9 pubkey::Pubkey,
10 transaction::Transaction,
11};
12use solana_trader_proto::api::{self, Project, TransactionMessage, TransactionMessageV2};
13
14pub trait IntoTransactionMessage {
15 fn into_transaction_message(self) -> TransactionMessage;
16}
17
18impl IntoTransactionMessage for TransactionMessage {
19 fn into_transaction_message(self) -> TransactionMessage {
20 self
21 }
22}
23
24impl IntoTransactionMessage for TransactionMessageV2 {
25 fn into_transaction_message(self) -> TransactionMessage {
26 TransactionMessage {
27 content: self.content,
28 is_cleanup: false,
29 }
30 }
31}
32
33pub fn convert_address_lookup_table(
34 address_lookup_table: &HashMap<String, api::PublicKeys>,
35) -> Result<Vec<AddressLookupTableAccount>> {
36 let mut result = Vec::new();
37
38 for (key, accounts) in address_lookup_table {
39 let lookup_table_address = Pubkey::from_str(key)?;
40 let addresses: Vec<Pubkey> = accounts
41 .pks
42 .iter()
43 .map(|pk| Pubkey::from_str(pk))
44 .collect::<Result<_, _>>()?;
45
46 let lookup_table = AddressLookupTableAccount {
47 key: lookup_table_address,
48 addresses,
49 };
50
51 result.push(lookup_table);
52 }
53
54 Ok(result)
55}
56
57pub fn convert_jupiter_instructions(
58 instructions: &[api::InstructionJupiter],
59) -> Result<Vec<Instruction>> {
60 let mut solana_instructions = Vec::new();
61
62 for inst in instructions {
63 let program_id = Pubkey::from_str(&inst.program_id)?;
64
65 let accounts: Vec<AccountMeta> = inst
66 .accounts
67 .iter()
68 .map(|acc| {
69 let pubkey = Pubkey::from_str(&acc.program_id)?;
70 Ok(AccountMeta {
71 pubkey,
72 is_signer: acc.is_signer,
73 is_writable: acc.is_writable,
74 })
75 })
76 .collect::<Result<Vec<_>>>()?;
77
78 solana_instructions.push(Instruction {
79 program_id,
80 accounts,
81 data: inst.data.clone(),
82 });
83 }
84
85 Ok(solana_instructions)
86}
87
88pub fn convert_raydium_instructions(
89 instructions: &[api::InstructionRaydium],
90) -> Result<Vec<Instruction>> {
91 let mut solana_instructions = Vec::new();
92
93 for inst in instructions {
94 let program_id = Pubkey::from_str(&inst.program_id)?;
95
96 let accounts: Vec<AccountMeta> = inst
97 .accounts
98 .iter()
99 .map(|acc| {
100 let pubkey = Pubkey::from_str(&acc.program_id)?;
101 Ok(AccountMeta {
102 pubkey,
103 is_signer: acc.is_signer,
104 is_writable: acc.is_writable,
105 })
106 })
107 .collect::<Result<Vec<_>>>()?;
108
109 solana_instructions.push(Instruction {
110 program_id,
111 accounts,
112 data: inst.data.clone(),
113 });
114 }
115
116 Ok(solana_instructions)
117}
118
119pub fn create_transaction_message(
120 instructions: Vec<Instruction>,
121 recent_blockhash: &str,
122) -> Result<api::TransactionMessage> {
123 let mut transaction = Transaction::new_with_payer(&instructions, None);
124 transaction.message.recent_blockhash = recent_blockhash.parse()?;
125
126 let serialized = bincode::serialize(&transaction)?;
127 let content = general_purpose::STANDARD.encode(serialized);
128
129 Ok(api::TransactionMessage {
130 content,
131 is_cleanup: false,
132 })
133}
134
135pub fn convert_string_enums(value: &mut Value) {
136 match value {
137 Value::Object(map) => {
138 for (key, val) in map {
139 match (key.as_str(), &val) {
140 ("project", Value::String(s)) => {
141 if let Some(project_enum) = Project::from_str_name(s) {
142 *val = json!(project_enum as i32);
143 }
144 }
145
146 ("infinity", Value::String(s)) => {
147 let mapped = match s.as_str() {
148 "INF_NOT" => 0,
149 "INF" => 1,
150 "INF_NEG" => 2,
151 _ => return,
152 };
153 *val = json!(mapped);
154 }
155
156 _ => convert_string_enums(val),
157 }
158 }
159 }
160 Value::Array(arr) => arr.iter_mut().for_each(convert_string_enums),
161 _ => {}
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 #[test]
170 fn test_conversions() {
171 let mut value = json!({
172 "project": "P_JUPITER",
173 "tradeFeeRate": "1000",
174 "nested": {
175 "project": "P_RAYDIUM",
176 "priceImpactPercent": {
177 "infinity": "INF_NOT"
178 }
179 },
180 "array": [
181 {"project": "P_OPENBOOK"}
182 ]
183 });
184
185 convert_string_enums(&mut value);
186
187 assert_eq!(value["project"], 2);
188 assert_eq!(value["nested"]["project"], 3);
189 assert_eq!(value["nested"]["priceImpactPercent"]["infinity"], 0);
190 assert_eq!(value["array"][0]["project"], 5);
191 }
192}