sol.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. use crate::rpc::{jsonrpc, jsonrpc::JsonResult};
  2. use crate::serial::{deserialize, serialize, Decodable, Encodable};
  3. use crate::{Error, Result};
  4. use super::bridge::{ TokenSubscribtion, TokenNotification, TokenClient};
  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: &'static str = "https://api.mainnet-beta.solana.com";
  23. //const WSS_SERVER: &'static str = "wss://api.mainnet-beta.solana.com";
  24. const RPC_SERVER: &'static str = "https://api.devnet.solana.com";
  25. const WSS_SERVER: &'static str = "wss://api.devnet.solana.com";
  26. //const RPC_SERVER: &'static str = "http://localhost:8899";
  27. //const WSS_SERVER: &'static 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. if new_bal > old_balance.to_owned() {
  122. let received_balance = new_bal - old_balance;
  123. self.send_to_main_account(&keypair)?;
  124. self.notify_channel
  125. .0
  126. .send(TokenNotification {
  127. secret_key: serialize(keypair),
  128. received_balance,
  129. })
  130. .await
  131. .map_err(|err| Error::from(err))?;
  132. self.unsubscribe(sub_id, &owner_pubkey).await?;
  133. debug!(
  134. target: "SOL BRIDGE",
  135. "Received {} lamports, to the pubkey: {} ",
  136. received_balance, owner_pubkey.to_string(),
  137. );
  138. } else if new_bal < old_balance.to_owned() {
  139. self.unsubscribe(sub_id, &owner_pubkey).await?;
  140. }
  141. }
  142. }
  143. Ok(())
  144. }
  145. fn send_to_main_account(&self, keypair: &Keypair) -> SolResult<()> {
  146. let rpc = RpcClient::new(RPC_SERVER.to_string());
  147. let amount = rpc.get_balance(&keypair.pubkey())?;
  148. let instruction =
  149. system_instruction::transfer(&keypair.pubkey(), &self.keypair.pubkey(), amount);
  150. let mut tx = Transaction::new_with_payer(&[instruction], Some(&keypair.pubkey()));
  151. let bhq = BlockhashQuery::default();
  152. match bhq.get_blockhash_and_fee_calculator(&rpc, rpc.commitment()) {
  153. Err(_) => panic!("Couldn't connect to RPC"),
  154. Ok(v) => tx.sign(&[keypair], v.0),
  155. }
  156. let _signature = rpc.send_and_confirm_transaction(&tx)?;
  157. Ok(())
  158. }
  159. async fn unsubscribe(&self, sub_id: u64, pubkey: &Pubkey) -> Result<()> {
  160. let sub_msg = jsonrpc::request(json!("accountUnsubscribe"), json!([json!(sub_id)]));
  161. self.subscribe_channel.0.send(sub_msg).await?;
  162. self.subscriptions.lock().await.remove(pubkey);
  163. Ok(())
  164. }
  165. }
  166. #[async_trait]
  167. impl TokenClient for SolClient {
  168. async fn subscribe(&self) -> Result<TokenSubscribtion> {
  169. let keypair = Keypair::generate(&mut OsRng);
  170. // Parameters for subscription to events related to `pubkey`.
  171. let sub_params = SubscribeParams {
  172. encoding: json!("jsonParsed"),
  173. // XXX: Use "finalized" for 100% certainty.
  174. commitment: json!("confirmed"),
  175. };
  176. let sub_msg = jsonrpc::request(
  177. json!("accountSubscribe"),
  178. json!([json!(keypair.pubkey().to_string()), json!(sub_params)]),
  179. );
  180. let rpc = RpcClient::new(RPC_SERVER.to_string());
  181. let balance = rpc
  182. .get_balance(&keypair.pubkey())
  183. .map_err(|err| SolFailed::from(err))?;
  184. let public_key = serialize(&keypair.pubkey());
  185. // NOTE we send keypair for sol as secret_key
  186. let secret_key = serialize(&keypair);
  187. // add to subscriptions list
  188. self.subscriptions
  189. .lock()
  190. .await
  191. .insert(keypair.pubkey(), (keypair, balance));
  192. // send
  193. self.subscribe_channel.0.send(sub_msg).await?;
  194. Ok(TokenSubscribtion { secret_key, public_key})
  195. }
  196. async fn get_notifier(&self) -> Result<async_channel::Receiver<TokenNotification>>{
  197. Ok(self.notify_channel.1.clone())
  198. }
  199. async fn send(&self, address: Vec<u8>, amount: u64) -> Result<()> {
  200. let rpc = RpcClient::new(RPC_SERVER.to_string());
  201. let address: Pubkey = deserialize(&address)?;
  202. let instruction = system_instruction::transfer(&self.keypair.pubkey(), &address, amount);
  203. let mut tx = Transaction::new_with_payer(&[instruction], Some(&self.keypair.pubkey()));
  204. let bhq = BlockhashQuery::default();
  205. match bhq.get_blockhash_and_fee_calculator(&rpc, rpc.commitment()) {
  206. Err(_) => panic!("Couldn't connect to RPC"),
  207. Ok(v) => tx.sign(&[&self.keypair], v.0),
  208. }
  209. let _signature = rpc
  210. .send_and_confirm_transaction(&tx)
  211. .map_err(|err| SolFailed::from(err))?;
  212. Ok(())
  213. }
  214. }
  215. impl Encodable for Keypair {
  216. fn encode<S: std::io::Write>(&self, s: S) -> Result<usize> {
  217. let key = self.to_bytes();
  218. let len = key.encode(s)?;
  219. Ok(len)
  220. }
  221. }
  222. impl Decodable for Keypair {
  223. fn decode<D: std::io::Read>(mut d: D) -> Result<Self> {
  224. let key: Vec<u8> = Decodable::decode(&mut d)?;
  225. let key = Keypair::from_bytes(key.as_slice()).map_err(|_| {
  226. crate::Error::from(SolFailed::DecodeAndEncodeError(
  227. "load keypair from slice".into(),
  228. ))
  229. })?;
  230. Ok(key)
  231. }
  232. }
  233. impl Encodable for Pubkey {
  234. fn encode<S: std::io::Write>(&self, s: S) -> Result<usize> {
  235. let key = self.to_string();
  236. let len = key.encode(s)?;
  237. Ok(len)
  238. }
  239. }
  240. impl Decodable for Pubkey {
  241. fn decode<D: std::io::Read>(mut d: D) -> Result<Self> {
  242. let key: String = Decodable::decode(&mut d)?;
  243. let key = Pubkey::try_from(key.as_str()).map_err(|_| {
  244. crate::Error::from(SolFailed::DecodeAndEncodeError(
  245. "load public key from slice".into(),
  246. ))
  247. })?;
  248. Ok(key)
  249. }
  250. }
  251. #[derive(Debug)]
  252. pub enum SolFailed {
  253. NotEnoughValue(u64),
  254. BadSolAddress(String),
  255. DecodeAndEncodeError(String),
  256. WebSocketError(String),
  257. SolClientError(String),
  258. ParseError(String),
  259. SolError(String),
  260. }
  261. impl std::error::Error for SolFailed {}
  262. impl std::fmt::Display for SolFailed {
  263. fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
  264. match self {
  265. SolFailed::NotEnoughValue(i) => {
  266. write!(f, "There is no enough value {}", i)
  267. }
  268. SolFailed::BadSolAddress(ref err) => {
  269. write!(f, "Bad Sol Address: {}", err)
  270. }
  271. SolFailed::DecodeAndEncodeError(ref err) => {
  272. write!(f, "Decode and decode keys error: {}", err)
  273. }
  274. SolFailed::WebSocketError(i) => {
  275. write!(f, "WebSocket Error: {}", i)
  276. }
  277. SolFailed::ParseError(i) => {
  278. write!(f, "Parse Error: {}", i)
  279. }
  280. SolFailed::SolClientError(i) => {
  281. write!(f, "Solana Client Error: {}", i)
  282. }
  283. SolFailed::SolError(i) => {
  284. write!(f, "SolFailed: {}", i)
  285. }
  286. }
  287. }
  288. }
  289. impl From<solana_sdk::pubkey::ParsePubkeyError> for SolFailed {
  290. fn from(err: solana_sdk::pubkey::ParsePubkeyError) -> SolFailed {
  291. SolFailed::ParseError(err.to_string())
  292. }
  293. }
  294. impl From<tungstenite::Error> for SolFailed {
  295. fn from(err: tungstenite::Error) -> SolFailed {
  296. SolFailed::WebSocketError(err.to_string())
  297. }
  298. }
  299. impl From<solana_client::client_error::ClientError> for SolFailed {
  300. fn from(err: solana_client::client_error::ClientError) -> SolFailed {
  301. SolFailed::SolError(err.to_string())
  302. }
  303. }
  304. impl From<crate::error::Error> for SolFailed {
  305. fn from(err: crate::error::Error) -> SolFailed {
  306. SolFailed::SolError(err.to_string())
  307. }
  308. }
  309. pub type SolResult<T> = std::result::Result<T, SolFailed>;