sol.rs 24 KB

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