sol.rs 24 KB

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