sol.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. use crate::rpc::{jsonrpc, jsonrpc::JsonResult};
  2. use crate::serial::{deserialize, serialize, Decodable, Encodable};
  3. use crate::{Error, Result};
  4. use super::bridge::{TokenClient, TokenNotification, TokenSubscribtion};
  5. use async_trait::async_trait;
  6. use async_executor::Executor;
  7. use futures::{SinkExt, StreamExt};
  8. use log::*;
  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. pubkey::Pubkey, signature::Signer, signer::keypair::Keypair, system_instruction,
  15. transaction::Transaction,
  16. };
  17. use tokio_tungstenite::{connect_async, tungstenite, tungstenite::protocol::Message};
  18. use async_std::sync::{Arc, Mutex};
  19. use std::collections::HashMap;
  20. use std::convert::TryFrom;
  21. use std::str::FromStr;
  22. //const RPC_SERVER: &str = "https://api.mainnet-beta.solana.com";
  23. //const WSS_SERVER: &str = "wss://api.mainnet-beta.solana.com";
  24. const RPC_SERVER: &str = "https://api.devnet.solana.com";
  25. const WSS_SERVER: &str = "wss://api.devnet.solana.com";
  26. //const RPC_SERVER: &str = "http://localhost:8899";
  27. //const WSS_SERVER: &str = "ws://localhost:8900";
  28. #[derive(Serialize)]
  29. struct SubscribeParams {
  30. encoding: Value,
  31. commitment: Value,
  32. }
  33. pub struct SolClient {
  34. keypair: Keypair,
  35. // subscriptions hashmap using pubkey as an index and a value of (keypair, amount)
  36. subscriptions: Arc<Mutex<HashMap<Pubkey, (Keypair, u64)>>>,
  37. notify_channel: (
  38. async_channel::Sender<TokenNotification>,
  39. async_channel::Receiver<TokenNotification>,
  40. ),
  41. subscribe_channel: (
  42. async_channel::Sender<jsonrpc::JsonRequest>,
  43. async_channel::Receiver<jsonrpc::JsonRequest>,
  44. ),
  45. }
  46. impl SolClient {
  47. pub async fn new(keypair: Vec<u8>) -> Result<Arc<Self>> {
  48. let keypair: Keypair = deserialize(&keypair)?;
  49. let notify_channel = async_channel::unbounded();
  50. let subscribe_channel = async_channel::unbounded();
  51. Ok(Arc::new(Self {
  52. keypair,
  53. subscriptions: Arc::new(Mutex::new(HashMap::new())),
  54. notify_channel,
  55. subscribe_channel,
  56. }))
  57. }
  58. pub async fn run(self: Arc<Self>, executor: Arc<Executor<'_>>) -> SolResult<()> {
  59. // WebSocket handshake/connect
  60. let (ws_stream, _) = connect_async(WSS_SERVER).await?;
  61. let (mut write, read) = ws_stream.split();
  62. let self2 = self.clone();
  63. let _: async_executor::Task<Result<()>> = executor.spawn(async move {
  64. loop {
  65. // recv a request for websocket
  66. let sub_msg = self2.subscribe_channel.1.recv().await?;
  67. // write the request to websocket
  68. write
  69. .send(Message::Text(serde_json::to_string(&sub_msg)?))
  70. .await
  71. .map_err(|err| SolFailed::from(err))?;
  72. }
  73. });
  74. read.for_each(|message| async {
  75. // read ws msg
  76. self.clone()
  77. .read_ws_msg(message)
  78. .await
  79. .expect("read from websocket");
  80. })
  81. .await;
  82. Ok(())
  83. }
  84. async fn read_ws_msg(
  85. self: Arc<Self>,
  86. message: std::result::Result<Message, tungstenite::Error>,
  87. ) -> SolResult<()> {
  88. let data = message?.into_text()?;
  89. let v: JsonResult = serde_json::from_str(&data).map_err(|err| Error::from(err))?;
  90. match v {
  91. JsonResult::Resp(r) => {
  92. // receive a response with subscription id
  93. let sub_id = r.result.as_i64().ok_or(Error::ParseIntError)?;
  94. debug!(
  95. target: "SOL BRIDGE",
  96. "Successfully get response : {:?}",
  97. sub_id
  98. );
  99. }
  100. JsonResult::Err(e) => {
  101. // receive an error
  102. debug!(
  103. target: "SOL BRIDGE",
  104. "Error on subscription: {:?}", e.error.message.to_string());
  105. }
  106. JsonResult::Notif(n) => {
  107. // receive notification once an account get updated
  108. // get values from the notification
  109. let new_bal = n.params["result"]["value"]["lamports"]
  110. .as_u64()
  111. .ok_or(Error::ParseIntError)?;
  112. let owner_pubkey = n.params["result"]["value"]["owner"]
  113. .as_str()
  114. .ok_or(Error::ParseFailed("Error Parse serde_json Value to &str"))?;
  115. let owner_pubkey: Pubkey = Pubkey::from_str(&owner_pubkey)?;
  116. let sub_id = n.params["subscription"]
  117. .as_u64()
  118. .ok_or(Error::ParseIntError)?;
  119. // get the keypair and old_balance from the subscriptions list
  120. let (keypair, old_balance) = &self.subscriptions.lock().await[&owner_pubkey];
  121. match new_bal > *old_balance {
  122. true => {
  123. let received_balance = new_bal - old_balance;
  124. self.send_to_main_account(&keypair)?;
  125. self.notify_channel
  126. .0
  127. .send(TokenNotification {
  128. secret_key: serialize(keypair),
  129. received_balance,
  130. })
  131. .await
  132. .map_err(|err| Error::from(err))?;
  133. self.unsubscribe(sub_id, &owner_pubkey).await?;
  134. debug!(
  135. target: "SOL BRIDGE",
  136. "Received {} lamports, to the pubkey: {} ",
  137. received_balance, owner_pubkey.to_string(),
  138. );
  139. }
  140. false => {
  141. self.unsubscribe(sub_id, &owner_pubkey).await?;
  142. }
  143. }
  144. }
  145. }
  146. Ok(())
  147. }
  148. fn send_to_main_account(&self, keypair: &Keypair) -> SolResult<()> {
  149. let rpc = RpcClient::new(RPC_SERVER.to_string());
  150. let amount = rpc.get_balance(&keypair.pubkey())?;
  151. let instruction =
  152. system_instruction::transfer(&keypair.pubkey(), &self.keypair.pubkey(), amount);
  153. let mut tx = Transaction::new_with_payer(&[instruction], Some(&keypair.pubkey()));
  154. let bhq = BlockhashQuery::default();
  155. match bhq.get_blockhash_and_fee_calculator(&rpc, rpc.commitment()) {
  156. Err(_) => panic!("Couldn't connect to RPC"),
  157. Ok(v) => tx.sign(&[keypair], v.0),
  158. }
  159. let _signature = rpc.send_and_confirm_transaction(&tx)?;
  160. Ok(())
  161. }
  162. async fn unsubscribe(&self, sub_id: u64, pubkey: &Pubkey) -> Result<()> {
  163. let sub_msg = jsonrpc::request(json!("accountUnsubscribe"), json!([json!(sub_id)]));
  164. self.subscribe_channel.0.send(sub_msg).await?;
  165. self.subscriptions.lock().await.remove(pubkey);
  166. Ok(())
  167. }
  168. }
  169. #[async_trait]
  170. impl TokenClient for SolClient {
  171. async fn subscribe(&self) -> Result<TokenSubscribtion> {
  172. let keypair = Keypair::generate(&mut OsRng);
  173. // Parameters for subscription to events related to `pubkey`.
  174. let sub_params = SubscribeParams {
  175. encoding: json!("jsonParsed"),
  176. // XXX: Use "finalized" for 100% certainty.
  177. commitment: json!("confirmed"),
  178. };
  179. let sub_msg = jsonrpc::request(
  180. json!("accountSubscribe"),
  181. json!([json!(keypair.pubkey().to_string()), json!(sub_params)]),
  182. );
  183. let rpc = RpcClient::new(RPC_SERVER.to_string());
  184. let balance = rpc
  185. .get_balance(&keypair.pubkey())
  186. .map_err(|err| SolFailed::from(err))?;
  187. let public_key = keypair.pubkey().to_string();
  188. // NOTE we send keypair for sol as secret_key
  189. let secret_key = serialize(&keypair);
  190. // add to subscriptions list
  191. self.subscriptions
  192. .lock()
  193. .await
  194. .insert(keypair.pubkey(), (keypair, balance));
  195. // send
  196. self.subscribe_channel.0.send(sub_msg).await?;
  197. Ok(TokenSubscribtion {
  198. secret_key,
  199. public_key,
  200. })
  201. }
  202. async fn get_notifier(&self) -> Result<async_channel::Receiver<TokenNotification>> {
  203. Ok(self.notify_channel.1.clone())
  204. }
  205. async fn send(&self, address: Vec<u8>, amount: u64) -> Result<()> {
  206. let rpc = RpcClient::new(RPC_SERVER.to_string());
  207. let address: Pubkey = deserialize(&address)?;
  208. let instruction = system_instruction::transfer(&self.keypair.pubkey(), &address, amount);
  209. let mut tx = Transaction::new_with_payer(&[instruction], Some(&self.keypair.pubkey()));
  210. let bhq = BlockhashQuery::default();
  211. match bhq.get_blockhash_and_fee_calculator(&rpc, rpc.commitment()) {
  212. Err(_) => panic!("Couldn't connect to RPC"),
  213. Ok(v) => tx.sign(&[&self.keypair], v.0),
  214. }
  215. let _signature = rpc
  216. .send_and_confirm_transaction(&tx)
  217. .map_err(|err| SolFailed::from(err))?;
  218. Ok(())
  219. }
  220. }
  221. impl Encodable for Keypair {
  222. fn encode<S: std::io::Write>(&self, s: S) -> Result<usize> {
  223. let key = self.to_bytes();
  224. let len = key.encode(s)?;
  225. Ok(len)
  226. }
  227. }
  228. impl Decodable for Keypair {
  229. fn decode<D: std::io::Read>(mut d: D) -> Result<Self> {
  230. let key: Vec<u8> = Decodable::decode(&mut d)?;
  231. let key = Keypair::from_bytes(key.as_slice()).map_err(|_| {
  232. crate::Error::from(SolFailed::DecodeAndEncodeError(
  233. "load keypair from slice".into(),
  234. ))
  235. })?;
  236. Ok(key)
  237. }
  238. }
  239. impl Encodable for Pubkey {
  240. fn encode<S: std::io::Write>(&self, s: S) -> Result<usize> {
  241. let key = self.to_string();
  242. let len = key.encode(s)?;
  243. Ok(len)
  244. }
  245. }
  246. impl Decodable for Pubkey {
  247. fn decode<D: std::io::Read>(mut d: D) -> Result<Self> {
  248. let key: String = Decodable::decode(&mut d)?;
  249. let key = Pubkey::try_from(key.as_str()).map_err(|_| {
  250. crate::Error::from(SolFailed::DecodeAndEncodeError(
  251. "load public key from slice".into(),
  252. ))
  253. })?;
  254. Ok(key)
  255. }
  256. }
  257. #[derive(Debug)]
  258. pub enum SolFailed {
  259. NotEnoughValue(u64),
  260. BadSolAddress(String),
  261. DecodeAndEncodeError(String),
  262. WebSocketError(String),
  263. SolClientError(String),
  264. ParseError(String),
  265. SolError(String),
  266. }
  267. impl std::error::Error for SolFailed {}
  268. impl std::fmt::Display for SolFailed {
  269. fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
  270. match self {
  271. SolFailed::NotEnoughValue(i) => {
  272. write!(f, "There is no enough value {}", i)
  273. }
  274. SolFailed::BadSolAddress(ref err) => {
  275. write!(f, "Bad Sol Address: {}", err)
  276. }
  277. SolFailed::DecodeAndEncodeError(ref err) => {
  278. write!(f, "Decode and decode keys error: {}", err)
  279. }
  280. SolFailed::WebSocketError(i) => {
  281. write!(f, "WebSocket Error: {}", i)
  282. }
  283. SolFailed::ParseError(i) => {
  284. write!(f, "Parse Error: {}", i)
  285. }
  286. SolFailed::SolClientError(i) => {
  287. write!(f, "Solana Client Error: {}", i)
  288. }
  289. SolFailed::SolError(i) => {
  290. write!(f, "SolFailed: {}", i)
  291. }
  292. }
  293. }
  294. }
  295. impl From<solana_sdk::pubkey::ParsePubkeyError> for SolFailed {
  296. fn from(err: solana_sdk::pubkey::ParsePubkeyError) -> SolFailed {
  297. SolFailed::ParseError(err.to_string())
  298. }
  299. }
  300. impl From<tungstenite::Error> for SolFailed {
  301. fn from(err: tungstenite::Error) -> SolFailed {
  302. SolFailed::WebSocketError(err.to_string())
  303. }
  304. }
  305. impl From<solana_client::client_error::ClientError> for SolFailed {
  306. fn from(err: solana_client::client_error::ClientError) -> SolFailed {
  307. SolFailed::SolError(err.to_string())
  308. }
  309. }
  310. impl From<crate::error::Error> for SolFailed {
  311. fn from(err: crate::error::Error) -> SolFailed {
  312. SolFailed::SolError(err.to_string())
  313. }
  314. }
  315. pub type SolResult<T> = std::result::Result<T, SolFailed>;
  316. /// Derive an associated token address from given owner and mint
  317. fn get_associated_token_account(owner: &Pubkey, mint: &Pubkey) -> (Pubkey, u8) {
  318. let associated_token =
  319. Pubkey::from_str("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL").unwrap();
  320. Pubkey::find_program_address(
  321. &[
  322. &owner.to_bytes(),
  323. &spl_token::id().to_bytes(),
  324. &mint.to_bytes(),
  325. ],
  326. &associated_token,
  327. )
  328. }
  329. /// Check if given account is a valid token mint
  330. fn account_is_initialized_mint(mint: &Pubkey) -> bool {
  331. let rpc = RpcClient::new(RPC_SERVER.to_string());
  332. match rpc.get_token_supply(mint) {
  333. Ok(_) => return true,
  334. Err(_) => return false,
  335. }
  336. }