sol.rs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. use async_std::sync::{Arc, Mutex};
  2. use std::convert::TryFrom;
  3. use std::str::FromStr;
  4. use std::time::Duration;
  5. use async_native_tls::TlsConnector;
  6. use async_trait::async_trait;
  7. use futures::{SinkExt, StreamExt};
  8. use log::{debug, error, info, warn};
  9. use rand::rngs::OsRng;
  10. use serde::Serialize;
  11. use serde_json::{json, Value};
  12. use solana_client::{blockhash_query::BlockhashQuery, rpc_client::RpcClient};
  13. use solana_sdk::{
  14. native_token::lamports_to_sol,
  15. program_pack::Pack,
  16. pubkey::Pubkey,
  17. signature::{Signature, Signer},
  18. signer::keypair::Keypair,
  19. system_instruction,
  20. transaction::Transaction,
  21. };
  22. use spl_associated_token_account::{create_associated_token_account, get_associated_token_address};
  23. use tungstenite::Message;
  24. use super::bridge::{NetworkClient, TokenNotification, TokenSubscribtion};
  25. use crate::rpc::{jsonrpc, jsonrpc::JsonResult, websockets, websockets::WsStream};
  26. use crate::serial::{deserialize, serialize, Decodable, Encodable};
  27. use crate::util::{generate_id, parse::truncate, NetworkName};
  28. use crate::{Error, Result};
  29. pub const SOL_NATIVE_TOKEN_ID: &str = "So11111111111111111111111111111111111111112";
  30. #[derive(Serialize)]
  31. struct SubscribeParams {
  32. encoding: Value,
  33. commitment: Value,
  34. }
  35. pub struct SolClient {
  36. main_keypair: Keypair,
  37. // Subscriptions vector of pubkey
  38. subscriptions: Arc<Mutex<Vec<Pubkey>>>,
  39. notify_channel: (
  40. async_channel::Sender<TokenNotification>,
  41. async_channel::Receiver<TokenNotification>,
  42. ),
  43. rpc_server: &'static str,
  44. wss_server: &'static str,
  45. }
  46. impl SolClient {
  47. pub async fn new(main_keypair: Vec<u8>, network: &str) -> Result<Arc<Self>> {
  48. let main_keypair: Keypair = deserialize(&main_keypair)?;
  49. let notify_channel = async_channel::unbounded();
  50. info!(target: "SOL BRIDGE", "Main SOL wallet pubkey: {:?}", &main_keypair.pubkey());
  51. let (rpc_server, wss_server) = match network {
  52. "mainnet" => (
  53. "https://api.mainnet-beta.solana.com",
  54. "wss://api.devnet.solana.com",
  55. ),
  56. "devnet" => (
  57. "https://api.devnet.solana.com",
  58. "wss://api.devnet.solana.com",
  59. ),
  60. "testnet" => (
  61. "https://api.testnet.solana.com",
  62. "wss://api.testnet.solana.com",
  63. ),
  64. "localhost" => ("http://localhost:8899", "ws://localhost:8900"),
  65. _ => return Err(Error::NotSupportedNetwork),
  66. };
  67. Ok(Arc::new(Self {
  68. main_keypair,
  69. subscriptions: Arc::new(Mutex::new(Vec::new())),
  70. notify_channel,
  71. rpc_server,
  72. wss_server,
  73. }))
  74. }
  75. fn check_main_account_balance(&self, rpc: &RpcClient) -> SolResult<bool> {
  76. let main_sol_balance = rpc
  77. .get_balance(&self.main_keypair.pubkey())
  78. .map_err(SolFailed::from)?;
  79. let fees = rpc.get_fees()?;
  80. let lamports_per_signature = fees.fee_calculator.lamports_per_signature;
  81. let required_funds = lamports_per_signature * 3;
  82. Ok(main_sol_balance > required_funds)
  83. }
  84. async fn handle_subscribe_request(
  85. self: Arc<Self>,
  86. keypair: Keypair,
  87. drk_pub_key: jubjub::SubgroupPoint,
  88. mint: Option<Pubkey>,
  89. ) -> SolResult<()> {
  90. debug!(target: "SOL BRIDGE", "handle_subscribe_request()");
  91. // Derive token pubkey if mint was provided.
  92. let pubkey = if mint.is_some() {
  93. get_associated_token_address(&keypair.pubkey(), &mint.unwrap())
  94. } else {
  95. keypair.pubkey()
  96. };
  97. // Check if we're already subscribed
  98. if self.subscriptions.lock().await.contains(&pubkey) {
  99. return Ok(());
  100. }
  101. let rpc = RpcClient::new(self.rpc_server.to_string());
  102. // Fetch the current balance.
  103. let (prev_balance, decimals) = if mint.is_none() {
  104. (rpc.get_balance(&pubkey).map_err(SolFailed::from)?, 9)
  105. } else {
  106. let mint = mint.unwrap();
  107. match get_account_token_balance(&rpc, &pubkey, &mint) {
  108. Ok(v) => v,
  109. Err(_) => {
  110. let (exists, decimals) = account_is_initialized_mint(&rpc, &mint);
  111. if !exists {
  112. debug!("Could not figure out the number of decimals in SPL token");
  113. return Err(SolFailed::MintIsNotValid(mint.to_string()));
  114. }
  115. (0, decimals)
  116. }
  117. }
  118. };
  119. // WebSocket connection
  120. let builder = native_tls::TlsConnector::builder();
  121. let tls = TlsConnector::from(builder);
  122. let (stream, _) = websockets::connect(self.wss_server, tls).await?;
  123. let (mut write, mut read) = stream.split();
  124. // Subscription request build
  125. let sub_params = SubscribeParams {
  126. encoding: json!("jsonParsed"),
  127. commitment: json!("finalized"),
  128. };
  129. let subscription = jsonrpc::request(
  130. json!("accountSubscribe"),
  131. json!([json!(pubkey.to_string()), json!(sub_params)]),
  132. );
  133. debug!(target: "SOLANA RPC", "--> {}", serde_json::to_string(&subscription)?);
  134. write
  135. .send(Message::text(serde_json::to_string(&subscription)?))
  136. .await?;
  137. // Subscription ID used for unsubscribing later.
  138. let mut sub_id: i64 = 0;
  139. // The balance we are going to receive from the JSONRPC notification
  140. let cur_balance: u64;
  141. let ping_payload: Vec<u8> = vec![42, 33, 31, 42];
  142. loop {
  143. let message = read.next().await.ok_or(Error::TungsteniteError)?;
  144. let message = message?;
  145. if let Message::Pong(_) = message.clone() {
  146. async_std::task::sleep(Duration::from_secs(1)).await;
  147. write.send(Message::Ping(ping_payload.clone())).await?;
  148. continue;
  149. };
  150. match serde_json::from_slice(&message.into_data())? {
  151. JsonResult::Resp(r) => {
  152. // ACK
  153. debug!(target: "SOLANA RPC", "<-- {}", serde_json::to_string(&r)?);
  154. self.subscriptions.lock().await.push(pubkey);
  155. sub_id = r.result.as_i64().unwrap();
  156. // Start sending pings
  157. write.send(Message::Ping(ping_payload.clone())).await?;
  158. }
  159. JsonResult::Err(e) => {
  160. debug!(target: "SOLANA RPC", "<-- {}", serde_json::to_string(&e)?);
  161. self.unsubscribe(&mut write, &pubkey, &sub_id).await?;
  162. return Err(SolFailed::RpcError(e.error.message.to_string()));
  163. }
  164. JsonResult::Notif(n) => {
  165. // Account updated
  166. debug!(target: "SOLANA RPC", "Got WebSocket notification");
  167. let params = n.params["result"]["value"].clone();
  168. if mint.is_some() {
  169. cur_balance = params["data"]["parsed"]["info"]["tokenAmount"]["amount"]
  170. .as_str()
  171. .unwrap()
  172. .parse()
  173. .map_err(Error::from)?;
  174. } else {
  175. cur_balance = params["lamports"].as_u64().unwrap();
  176. }
  177. break;
  178. }
  179. }
  180. }
  181. let send_notification = self.notify_channel.0.clone();
  182. let self2 = self.clone();
  183. self2.unsubscribe(&mut write, &pubkey, &sub_id).await?;
  184. if cur_balance < prev_balance {
  185. return Err(SolFailed::Notification(
  186. "New balance is less than previous balance".into(),
  187. ));
  188. }
  189. if mint.is_some() {
  190. let amnt = cur_balance - prev_balance;
  191. let ui_amnt = amnt / u64::pow(10, decimals as u32);
  192. send_notification
  193. .send(TokenNotification {
  194. network: NetworkName::Solana,
  195. token_id: generate_id(&mint.unwrap().to_string(), &NetworkName::Solana)?,
  196. drk_pub_key,
  197. received_balance: amnt,
  198. decimals: decimals as u16,
  199. })
  200. .await
  201. .map_err(Error::from)?;
  202. debug!(target: "SOL BRIDGE", "Received {} {:?} tokens", ui_amnt, mint.unwrap());
  203. let _ = self.send_tok_to_main_wallet(&rpc, &mint.unwrap(), amnt, decimals, &keypair)?;
  204. } else {
  205. let amnt = cur_balance - prev_balance;
  206. let ui_amnt = lamports_to_sol(amnt);
  207. send_notification
  208. .send(TokenNotification {
  209. network: NetworkName::Solana,
  210. token_id: generate_id(SOL_NATIVE_TOKEN_ID, &NetworkName::Solana)?,
  211. drk_pub_key,
  212. received_balance: amnt,
  213. decimals: decimals as u16,
  214. })
  215. .await
  216. .map_err(Error::from)?;
  217. debug!(target: "SOL BRIDGE", "Received {} SOL", ui_amnt);
  218. let _ = self.send_sol_to_main_wallet(&rpc, amnt, &keypair)?;
  219. }
  220. Ok(())
  221. }
  222. async fn unsubscribe(
  223. self: Arc<Self>,
  224. write: &mut futures::stream::SplitSink<WsStream, tungstenite::Message>,
  225. pubkey: &Pubkey,
  226. sub_id: &i64,
  227. ) -> Result<()> {
  228. {
  229. let mut subscriptions = self.subscriptions.lock().await;
  230. let index = subscriptions.iter().position(|p| p == pubkey);
  231. if let Some(ind) = index {
  232. debug!("Removing subscription from list");
  233. subscriptions.remove(ind);
  234. }
  235. }
  236. let unsubscription = jsonrpc::request(json!("accountUnsubscribe"), json!([sub_id]));
  237. write
  238. .send(Message::text(serde_json::to_string(&unsubscription)?))
  239. .await?;
  240. Ok(())
  241. }
  242. fn send_tok_to_main_wallet(
  243. self: Arc<Self>,
  244. rpc: &RpcClient,
  245. mint: &Pubkey,
  246. amount: u64,
  247. decimals: u64,
  248. keypair: &Keypair,
  249. ) -> SolResult<Signature> {
  250. debug!(target: "SOL BRIDGE", "Sending {} {:?} tokens to main wallet",
  251. amount / u64::pow(10, decimals as u32), mint);
  252. // The token account from our main wallet
  253. let main_tok_pk = get_associated_token_address(&self.main_keypair.pubkey(), mint);
  254. // The token account from the deposit wallet
  255. let temp_tok_pk = get_associated_token_address(&keypair.pubkey(), mint);
  256. let mut instructions = vec![];
  257. match rpc.get_account_data(&main_tok_pk) {
  258. Ok(v) => {
  259. match spl_token::state::Account::unpack_from_slice(&v) {
  260. // It's valid token data, and we consider account initialized.
  261. Ok(_) => {}
  262. // Some other unexpected data.
  263. Err(_) => {
  264. return Err(SolFailed::SolClientError(
  265. "Invalid data on derived account".into(),
  266. ));
  267. }
  268. }
  269. }
  270. Err(_) => {
  271. // Unitinialized, so we add a creation instruction
  272. debug!("Main wallet token account is uninitialized. Adding init instruction.");
  273. let init_ix = create_associated_token_account(
  274. &self.main_keypair.pubkey(), // fee payer
  275. &self.main_keypair.pubkey(), // wallet
  276. mint,
  277. );
  278. instructions.push(init_ix);
  279. }
  280. }
  281. // Transfer tokens from the deposit wallet to the main wallet
  282. let transfer_ix = spl_token::instruction::transfer_checked(
  283. &spl_token::id(),
  284. &temp_tok_pk,
  285. mint,
  286. &main_tok_pk,
  287. &keypair.pubkey(),
  288. &[],
  289. amount,
  290. decimals as u8,
  291. )?;
  292. instructions.push(transfer_ix);
  293. // Close the account and reap the rent if there's no more tokens on it.
  294. let (tok_balance, _) = get_account_token_balance(&rpc, &temp_tok_pk, mint)?;
  295. if tok_balance - amount == 0 {
  296. debug!(target: "SOL BRIDGE", "Adding account close instruction because resulting balance is 0");
  297. let close_ix = spl_token::instruction::close_account(
  298. &spl_token::id(),
  299. &temp_tok_pk,
  300. &self.main_keypair.pubkey(),
  301. &keypair.pubkey(),
  302. &[],
  303. )?;
  304. instructions.push(close_ix);
  305. }
  306. let tx = Transaction::new_with_payer(&instructions, Some(&self.main_keypair.pubkey()));
  307. let signature = sign_and_send_transaction(&rpc, tx, vec![&self.main_keypair, keypair])?;
  308. debug!(target: "SOL BRIDGE", "Sent tokens to main wallet: {}", signature);
  309. Ok(signature)
  310. }
  311. fn send_sol_to_main_wallet(
  312. self: Arc<Self>,
  313. rpc: &RpcClient,
  314. amount: u64,
  315. keypair: &Keypair,
  316. ) -> SolResult<Signature> {
  317. debug!(target: "SOL BRIDGE", "Sending {} SOL to main wallet", lamports_to_sol(amount));
  318. let ix =
  319. system_instruction::transfer(&keypair.pubkey(), &self.main_keypair.pubkey(), amount);
  320. let tx = Transaction::new_with_payer(&[ix], Some(&self.main_keypair.pubkey()));
  321. let signature = sign_and_send_transaction(&rpc, tx, vec![&self.main_keypair, keypair])?;
  322. debug!(target: "SOL BRIDGE", "Sent {} SOL to main wallet: {}", lamports_to_sol(amount), signature);
  323. Ok(signature)
  324. }
  325. fn check_mint_address(&self, mint_address: Option<String>) -> SolResult<Option<Pubkey>> {
  326. if let Some(mint_addr) = mint_address {
  327. let pubkey = match Pubkey::from_str(&mint_addr) {
  328. Ok(v) => v,
  329. Err(e) => return Err(SolFailed::BadSolAddress(e.to_string())),
  330. };
  331. let rpc = RpcClient::new(self.rpc_server.to_string());
  332. if !account_is_initialized_mint(&rpc, &pubkey).0 {
  333. return Err(SolFailed::MintIsNotValid(mint_addr));
  334. }
  335. Ok(Some(pubkey))
  336. } else {
  337. Ok(None)
  338. }
  339. }
  340. }
  341. #[async_trait]
  342. impl NetworkClient for SolClient {
  343. async fn subscribe(
  344. self: Arc<Self>,
  345. drk_pub_key: jubjub::SubgroupPoint,
  346. mint_address: Option<String>,
  347. ) -> Result<TokenSubscribtion> {
  348. let keypair = Keypair::generate(&mut OsRng);
  349. let public_key = keypair.pubkey().to_string();
  350. let secret_key = serialize(&keypair);
  351. let mint = self.check_mint_address(mint_address)?;
  352. let rpc = RpcClient::new(self.rpc_server.to_string());
  353. if !self.check_main_account_balance(&rpc)? {
  354. warn!(target: "SOL BRIDGE", "Main account has no enough funds");
  355. return Err(Error::from(SolFailed::MainAccountNotEnoughValue));
  356. }
  357. smol::spawn(async move {
  358. let result = self
  359. .handle_subscribe_request(keypair, drk_pub_key, mint)
  360. .await;
  361. if let Err(e) = result {
  362. error!(target: "SOL BRIDGE SUBSCRIPTION","{}", e.to_string());
  363. }
  364. })
  365. .detach();
  366. Ok(TokenSubscribtion {
  367. secret_key,
  368. public_key,
  369. })
  370. }
  371. // in solana case private key it's the same as keypair
  372. async fn subscribe_with_keypair(
  373. self: Arc<Self>,
  374. private_key: Vec<u8>,
  375. _public_key: Vec<u8>,
  376. drk_pub_key: jubjub::SubgroupPoint,
  377. mint_address: Option<String>,
  378. ) -> Result<String> {
  379. let keypair: Keypair = deserialize(&private_key)?;
  380. let public_key = keypair.pubkey().to_string();
  381. let mint = self.check_mint_address(mint_address)?;
  382. let rpc = RpcClient::new(self.rpc_server.to_string());
  383. if !self.check_main_account_balance(&rpc)? {
  384. return Err(Error::from(SolFailed::MainAccountNotEnoughValue));
  385. }
  386. smol::spawn(async move {
  387. let result = self
  388. .handle_subscribe_request(keypair, drk_pub_key, mint)
  389. .await;
  390. if let Err(e) = result {
  391. error!(target: "SOL BRIDGE SUBSCRIPTION","{}", e.to_string());
  392. }
  393. })
  394. .detach();
  395. Ok(public_key)
  396. }
  397. async fn get_notifier(self: Arc<Self>) -> Result<async_channel::Receiver<TokenNotification>> {
  398. Ok(self.notify_channel.1.clone())
  399. }
  400. async fn send(
  401. self: Arc<Self>,
  402. address: Vec<u8>,
  403. mint: Option<String>,
  404. amount: u64,
  405. ) -> Result<()> {
  406. let rpc = RpcClient::new(self.rpc_server.to_string());
  407. let address: Pubkey = deserialize(&address)?;
  408. let mut decimals = 9;
  409. if mint.is_some() {
  410. let mint_address: Option<Pubkey> = self.check_mint_address(mint)?;
  411. if let Some(mint_addr) = mint_address {
  412. let tkn = rpc.get_token_supply(&mint_addr).map_err(SolFailed::from)?;
  413. decimals = tkn.decimals;
  414. };
  415. }
  416. // reverse truncate
  417. truncate(amount, decimals as u16, 8)?;
  418. let instruction =
  419. system_instruction::transfer(&self.main_keypair.pubkey(), &address, amount);
  420. let mut tx = Transaction::new_with_payer(&[instruction], Some(&self.main_keypair.pubkey()));
  421. let bhq = BlockhashQuery::default();
  422. match bhq.get_blockhash_and_fee_calculator(&rpc, rpc.commitment()) {
  423. Err(_) => panic!("Couldn't connect to RPC"),
  424. Ok(v) => tx.sign(&[&self.main_keypair], v.0),
  425. }
  426. let _signature = rpc
  427. .send_and_confirm_transaction(&tx)
  428. .map_err(SolFailed::from)?;
  429. Ok(())
  430. }
  431. }
  432. /// Gets account token balance for given mint.
  433. /// Returns: (amount, decimals)
  434. pub fn get_account_token_balance(
  435. rpc: &RpcClient,
  436. address: &Pubkey,
  437. mint: &Pubkey,
  438. ) -> SolResult<(u64, u64)> {
  439. let mint_account = rpc.get_account(mint)?;
  440. let token_account = rpc.get_account(address)?;
  441. let mint_data = spl_token::state::Mint::unpack_from_slice(&mint_account.data)?;
  442. let token_data = spl_token::state::Account::unpack_from_slice(&token_account.data)?;
  443. Ok((token_data.amount, mint_data.decimals as u64))
  444. }
  445. /// Check if given account is a valid token mint
  446. pub fn account_is_initialized_mint(rpc: &RpcClient, mint: &Pubkey) -> (bool, u64) {
  447. match rpc.get_token_supply(mint) {
  448. Ok(v) => (true, v.decimals as u64),
  449. Err(_) => (false, 0),
  450. }
  451. }
  452. pub fn sign_and_send_transaction(
  453. rpc: &RpcClient,
  454. mut tx: Transaction,
  455. signers: Vec<&Keypair>,
  456. ) -> SolResult<Signature> {
  457. let bhq = BlockhashQuery::default();
  458. match bhq.get_blockhash_and_fee_calculator(rpc, rpc.commitment()) {
  459. Err(_) => return Err(SolFailed::RpcError("Couldn't connect to RPC".into())),
  460. Ok(v) => tx.sign(&signers, v.0),
  461. }
  462. match rpc.send_and_confirm_transaction(&tx) {
  463. Ok(s) => Ok(s),
  464. Err(_) => Err(SolFailed::RpcError("Failed to send transaction".into())),
  465. }
  466. }
  467. impl Encodable for Keypair {
  468. fn encode<S: std::io::Write>(&self, s: S) -> Result<usize> {
  469. let key: Vec<u8> = self.to_bytes().to_vec();
  470. let len = key.encode(s)?;
  471. Ok(len)
  472. }
  473. }
  474. impl Decodable for Keypair {
  475. fn decode<D: std::io::Read>(mut d: D) -> Result<Self> {
  476. let key: Vec<u8> = Decodable::decode(&mut d)?;
  477. let key = Keypair::from_bytes(key.as_slice()).map_err(|_| {
  478. crate::Error::from(SolFailed::DecodeAndEncodeError(
  479. "load keypair from slice".into(),
  480. ))
  481. })?;
  482. Ok(key)
  483. }
  484. }
  485. impl Encodable for Pubkey {
  486. fn encode<S: std::io::Write>(&self, s: S) -> Result<usize> {
  487. let key = self.to_string();
  488. let len = key.encode(s)?;
  489. Ok(len)
  490. }
  491. }
  492. impl Decodable for Pubkey {
  493. fn decode<D: std::io::Read>(mut d: D) -> Result<Self> {
  494. let key: String = Decodable::decode(&mut d)?;
  495. let key = Pubkey::try_from(key.as_str()).map_err(|_| {
  496. crate::Error::from(SolFailed::DecodeAndEncodeError(
  497. "load public key from slice".into(),
  498. ))
  499. })?;
  500. Ok(key)
  501. }
  502. }
  503. #[derive(Debug)]
  504. pub enum SolFailed {
  505. NotEnoughValue(u64),
  506. MainAccountNotEnoughValue,
  507. BadSolAddress(String),
  508. DecodeAndEncodeError(String),
  509. WebSocketError(String),
  510. RpcError(String),
  511. SolClientError(String),
  512. Notification(String),
  513. ProgramError(String),
  514. MintIsNotValid(String),
  515. JsonError(String),
  516. ParseError(String),
  517. SolError(String),
  518. }
  519. impl std::error::Error for SolFailed {}
  520. impl std::fmt::Display for SolFailed {
  521. fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
  522. match self {
  523. SolFailed::NotEnoughValue(i) => {
  524. write!(f, "There is no enough value {}", i)
  525. }
  526. SolFailed::MainAccountNotEnoughValue => {
  527. write!(f, "Main Account Has no enough value")
  528. }
  529. SolFailed::BadSolAddress(ref err) => {
  530. write!(f, "Bad Sol Address: {}", err)
  531. }
  532. SolFailed::DecodeAndEncodeError(ref err) => {
  533. write!(f, "Decode and decode keys error: {}", err)
  534. }
  535. SolFailed::WebSocketError(i) => {
  536. write!(f, "WebSocket Error: {}", i)
  537. }
  538. SolFailed::RpcError(i) => {
  539. write!(f, "Rpc Error: {}", i)
  540. }
  541. SolFailed::ParseError(i) => {
  542. write!(f, "Parse Error: {}", i)
  543. }
  544. SolFailed::SolClientError(i) => {
  545. write!(f, "Solana Client Error: {}", i)
  546. }
  547. SolFailed::Notification(i) => {
  548. write!(f, "Received Notification Error: {}", i)
  549. }
  550. SolFailed::ProgramError(i) => {
  551. write!(f, "ProgramError Error: {}", i)
  552. }
  553. SolFailed::MintIsNotValid(i) => {
  554. write!(f, "Given mint is not valid: {}", i)
  555. }
  556. SolFailed::JsonError(i) => {
  557. write!(f, "JsonError: {}", i)
  558. }
  559. SolFailed::SolError(i) => {
  560. write!(f, "SolFailed: {}", i)
  561. }
  562. }
  563. }
  564. }
  565. impl From<solana_sdk::pubkey::ParsePubkeyError> for SolFailed {
  566. fn from(err: solana_sdk::pubkey::ParsePubkeyError) -> SolFailed {
  567. SolFailed::ParseError(err.to_string())
  568. }
  569. }
  570. impl From<tungstenite::Error> for SolFailed {
  571. fn from(err: tungstenite::Error) -> SolFailed {
  572. SolFailed::WebSocketError(err.to_string())
  573. }
  574. }
  575. impl From<solana_client::client_error::ClientError> for SolFailed {
  576. fn from(err: solana_client::client_error::ClientError) -> SolFailed {
  577. SolFailed::SolError(err.to_string())
  578. }
  579. }
  580. impl From<solana_sdk::program_error::ProgramError> for SolFailed {
  581. fn from(err: solana_sdk::program_error::ProgramError) -> SolFailed {
  582. SolFailed::ProgramError(err.to_string())
  583. }
  584. }
  585. impl From<crate::error::Error> for SolFailed {
  586. fn from(err: crate::error::Error) -> SolFailed {
  587. SolFailed::SolError(err.to_string())
  588. }
  589. }
  590. impl From<serde_json::Error> for SolFailed {
  591. fn from(err: serde_json::Error) -> SolFailed {
  592. SolFailed::JsonError(err.to_string())
  593. }
  594. }
  595. pub type SolResult<T> = std::result::Result<T, SolFailed>;