sol.rs 20 KB

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