eth.rs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. use async_std::sync::{Arc, Mutex};
  2. use std::convert::TryInto;
  3. use std::time::Duration;
  4. use async_executor::Executor;
  5. use async_trait::async_trait;
  6. use hash_db::Hasher;
  7. use keccak_hasher::KeccakHasher;
  8. use lazy_static::lazy_static;
  9. use log::{debug, error};
  10. use num_bigint::{BigUint, RandBigInt};
  11. use serde::{Deserialize, Serialize};
  12. use serde_json::{json, Value};
  13. use super::bridge::{NetworkClient, TokenNotification, TokenSubscribtion};
  14. use crate::{
  15. rpc::jsonrpc,
  16. rpc::jsonrpc::JsonResult,
  17. serial::{deserialize, serialize, Decodable, Encodable},
  18. util::{generate_id, parse::truncate, NetworkName},
  19. Error, Result,
  20. };
  21. pub const ETH_NATIVE_TOKEN_ID: &str = "0x0000000000000000000000000000000000000000";
  22. #[derive(Clone, Debug)]
  23. pub struct Keypair {
  24. pub private_key: String,
  25. pub public_key: String,
  26. }
  27. // An ERC-20 token transfer transaction's data is as follows:
  28. //
  29. // 1. The first 4 bytes of the keccak256 hash of "transfer(address,uint256)".
  30. // 2. The address of the recipient, left-zero-padded to be 32 bytes.
  31. // 3. The amount to be transferred: amount * 10^decimals
  32. // This is the entire ERC20 ABI
  33. lazy_static! {
  34. static ref ERC20_NAME_METHOD: [u8; 4] = {
  35. let method = b"name()";
  36. KeccakHasher::hash(method)[0..4].try_into().expect("nope")
  37. };
  38. static ref ERC20_APPROVE_METHOD: [u8; 4] = {
  39. let method = b"approve(address,uint256)";
  40. KeccakHasher::hash(method)[0..4].try_into().expect("nope")
  41. };
  42. static ref ERC20_TOTALSUPPLY_METHOD: [u8; 4] = {
  43. let method = b"totalSupply()";
  44. KeccakHasher::hash(method)[0..4].try_into().expect("nope")
  45. };
  46. static ref ERC20_TRANSFERFROM_METHOD: [u8; 4] = {
  47. let method = b"transferFrom(address,address,uint256)";
  48. KeccakHasher::hash(method)[0..4].try_into().expect("nope")
  49. };
  50. static ref ERC20_DECIMALS_METHOD: [u8; 4] = {
  51. let method = b"decimals()";
  52. KeccakHasher::hash(method)[0..4].try_into().expect("nope")
  53. };
  54. static ref ERC20_VERSION_METHOD: [u8; 4] = {
  55. let method = b"version()";
  56. KeccakHasher::hash(method)[0..4].try_into().expect("nope")
  57. };
  58. static ref ERC20_BALANCEOF_METHOD: [u8; 4] = {
  59. let method = b"balanceOf(address)";
  60. KeccakHasher::hash(method)[0..4].try_into().expect("nope")
  61. };
  62. static ref ERC20_SYMBOL_METHOD: [u8; 4] = {
  63. let method = b"symbol()";
  64. KeccakHasher::hash(method)[0..4].try_into().expect("nope")
  65. };
  66. static ref ERC20_TRANSFER_METHOD: [u8; 4] = {
  67. let method = b"transfer(address,uint256)";
  68. KeccakHasher::hash(method)[0..4].try_into().expect("nope")
  69. };
  70. static ref ERC20_APPROVEANDCALL_METHOD: [u8; 4] = {
  71. let method = b"approveAndCall(address,uint256,bytes)";
  72. KeccakHasher::hash(method)[0..4].try_into().expect("nope")
  73. };
  74. static ref ERC20_ALLOWANCE_METHOD: [u8; 4] = {
  75. let method = b"allowance(address,address)";
  76. KeccakHasher::hash(method)[0..4].try_into().expect("nope")
  77. };
  78. }
  79. pub fn erc20_transfer_data(recipient: &str, amount: BigUint) -> String {
  80. let rec = recipient.trim_start_matches("0x");
  81. let rec_padded = format!("{:0>64}", rec);
  82. let amnt_bytes = amount.to_bytes_be();
  83. let amnt_hex = hex::encode(amnt_bytes);
  84. let amnt_hex_padded = format!("{:0>64}", amnt_hex);
  85. format!(
  86. "0x{}{}{}",
  87. hex::encode(*ERC20_TRANSFER_METHOD),
  88. rec_padded,
  89. amnt_hex_padded
  90. )
  91. }
  92. pub fn erc20_balanceof_data(account: &str) -> String {
  93. let acc = account.trim_start_matches("0x");
  94. let acc_padded = format!("{:0>64}", acc);
  95. format!("0x{}{}", hex::encode(*ERC20_BALANCEOF_METHOD), acc_padded)
  96. }
  97. fn to_eth_hex(val: BigUint) -> String {
  98. let bytes = val.to_bytes_be();
  99. let h = hex::encode(bytes);
  100. format!("0x{}", h.trim_start_matches('0'))
  101. }
  102. /// Generate a 256-bit ETH private key.
  103. pub fn generate_privkey() -> String {
  104. let mut rng = rand::thread_rng();
  105. let token = rng.gen_bigint(256);
  106. let token_bytes = token.to_bytes_le().1;
  107. let key = KeccakHasher::hash(&token_bytes);
  108. hex::encode(key)
  109. }
  110. #[allow(non_snake_case)]
  111. #[derive(Serialize, Deserialize, Debug, Clone)]
  112. pub struct EthTx {
  113. pub from: String,
  114. pub to: String,
  115. #[serde(skip_serializing_if = "Option::is_none")]
  116. pub gas: Option<String>,
  117. #[serde(skip_serializing_if = "Option::is_none")]
  118. pub gasPrice: Option<String>,
  119. #[serde(skip_serializing_if = "Option::is_none")]
  120. pub value: Option<String>,
  121. #[serde(skip_serializing_if = "Option::is_none")]
  122. pub data: Option<String>,
  123. #[serde(skip_serializing_if = "Option::is_none")]
  124. pub nonce: Option<String>,
  125. }
  126. impl EthTx {
  127. pub fn new(
  128. from: &str,
  129. to: &str,
  130. gas: Option<BigUint>,
  131. gas_price: Option<BigUint>,
  132. value: Option<BigUint>,
  133. data: Option<String>,
  134. nonce: Option<String>,
  135. ) -> Self {
  136. let gas_hex = gas.map(to_eth_hex);
  137. let gasprice_hex = gas_price.map(to_eth_hex);
  138. let value_hex = value.map(to_eth_hex);
  139. EthTx {
  140. from: from.to_string(),
  141. to: to.to_string(),
  142. gas: gas_hex,
  143. gasPrice: gasprice_hex,
  144. value: value_hex,
  145. data,
  146. nonce,
  147. }
  148. }
  149. }
  150. // JSON-RPC interface to Geth.
  151. // https://eth.wiki/json-rpc/API
  152. // https://geth.ethereum.org/docs/rpc/
  153. //
  154. // geth can be started with: $ geth --ropsten --syncmode light
  155. // It should then show an Unix socket endpoint like so:
  156. // INFO [10-25|19:47:32.845] IPC endpoint opened: url=/home/x/.ethereum/ropsten/geth.ipc
  157. //
  158. pub struct EthClient {
  159. // main_keypair (private, public)
  160. main_keypair: Keypair,
  161. passphrase: String,
  162. socket_path: String,
  163. subscriptions: Arc<Mutex<Vec<String>>>,
  164. notify_channel: (
  165. async_channel::Sender<TokenNotification>,
  166. async_channel::Receiver<TokenNotification>,
  167. ),
  168. }
  169. impl EthClient {
  170. pub fn new(socket_path: String, passphrase: String) -> Self {
  171. let notify_channel = async_channel::unbounded();
  172. let subscriptions = Arc::new(Mutex::new(Vec::new()));
  173. Self {
  174. // this must set by the cashier
  175. main_keypair: Keypair {
  176. private_key: String::new(),
  177. public_key: String::new(),
  178. },
  179. passphrase,
  180. socket_path,
  181. subscriptions,
  182. notify_channel,
  183. }
  184. }
  185. pub fn set_main_keypair(&mut self, keypair: &Keypair) {
  186. self.main_keypair = keypair.clone();
  187. }
  188. async fn send_eth_to_main_wallet(&self, acc: &str, amount: BigUint) -> Result<()> {
  189. debug!(target: "ETH BRIDGE", "Send eth to main wallet");
  190. let tx = EthTx::new(
  191. acc,
  192. &self.main_keypair.public_key,
  193. None,
  194. None,
  195. Some(amount),
  196. None,
  197. None,
  198. );
  199. self.send_transaction(&tx, &self.passphrase).await?;
  200. Ok(())
  201. }
  202. async fn handle_subscribe_request(
  203. self: Arc<Self>,
  204. addr: String,
  205. drk_pub_key: jubjub::SubgroupPoint,
  206. ) -> Result<()> {
  207. if self.subscriptions.lock().await.contains(&addr) {
  208. return Ok(());
  209. }
  210. let decimals = 18;
  211. let prev_balance = self.get_current_balance(&addr, None).await?;
  212. let mut current_balance;
  213. let iter_interval = 1;
  214. let mut sub_iter = 0;
  215. loop {
  216. if sub_iter > 60 * 10 {
  217. // 10 minutes
  218. self.unsubscribe(&addr).await;
  219. return Err(crate::Error::ClientFailed("Deposit for expired".into()));
  220. }
  221. sub_iter += iter_interval;
  222. async_std::task::sleep(Duration::from_secs(iter_interval)).await;
  223. current_balance = self.get_current_balance(&addr, None).await?;
  224. if current_balance != prev_balance {
  225. break;
  226. }
  227. }
  228. let send_notification = self.notify_channel.0.clone();
  229. self.unsubscribe(&addr).await;
  230. if current_balance < prev_balance {
  231. return Err(crate::Error::ClientFailed(
  232. "New balance is less than previous balance".into(),
  233. ));
  234. }
  235. let received_balance = current_balance - prev_balance;
  236. let received_balance_ui = received_balance.clone() / u64::pow(10, decimals as u32);
  237. send_notification
  238. .send(TokenNotification {
  239. network: NetworkName::Ethereum,
  240. token_id: generate_id(ETH_NATIVE_TOKEN_ID, &NetworkName::Ethereum)?,
  241. drk_pub_key,
  242. // TODO FIX
  243. received_balance: received_balance.to_u64_digits()[0],
  244. decimals: decimals as u16,
  245. })
  246. .await
  247. .map_err(Error::from)?;
  248. self.send_eth_to_main_wallet(&addr, received_balance)
  249. .await?;
  250. debug!(target: "ETH BRIDGE", "Received {} eth", received_balance_ui );
  251. Ok(())
  252. }
  253. async fn unsubscribe(&self, pubkey: &str) {
  254. let mut subscriptions = self.subscriptions.lock().await;
  255. let index = subscriptions.iter().position(|p| p == pubkey);
  256. if let Some(ind) = index {
  257. debug!(target: "ETH BRIDGE", "Removing subscription from list");
  258. subscriptions.remove(ind);
  259. }
  260. }
  261. async fn request(&self, r: jsonrpc::JsonRequest) -> EthResult<Value> {
  262. debug!(target: "ETH RPC", "--> {}", serde_json::to_string(&r)?);
  263. let reply: JsonResult = match jsonrpc::send_unix_request(&self.socket_path, json!(r))
  264. .await
  265. .map_err(EthFailed::from)
  266. {
  267. Ok(v) => v,
  268. Err(e) => return Err(e),
  269. };
  270. match reply {
  271. JsonResult::Resp(r) => {
  272. debug!(target: "ETH RPC", "<-- {}", serde_json::to_string(&r)?);
  273. Ok(r.result)
  274. }
  275. JsonResult::Err(e) => {
  276. debug!(target: "ETH RPC", "<-- {}", serde_json::to_string(&e)?);
  277. Err(EthFailed::RpcError(e.error.message.to_string()))
  278. }
  279. JsonResult::Notif(n) => {
  280. debug!(target: "ETH RPC", "<-- {}", serde_json::to_string(&n)?);
  281. Err(EthFailed::RpcError("Unexpected reply".to_string()))
  282. }
  283. }
  284. }
  285. pub async fn import_privkey(&self, key: &str, passphrase: &str) -> EthResult<Value> {
  286. let req = jsonrpc::request(json!("personal_importRawKey"), json!([key, passphrase]));
  287. Ok(self.request(req).await?)
  288. }
  289. /*
  290. pub async fn estimate_gas(&self, tx: &EthTx) -> Result<Value> {
  291. let req = jsonrpc::request(json!("eth_estimateGas"), json!([tx]));
  292. Ok(self.request(req).await?)
  293. }
  294. */
  295. pub async fn block_number(&self) -> EthResult<Value> {
  296. let req = jsonrpc::request(json!("eth_blockNumber"), json!([]));
  297. Ok(self.request(req).await?)
  298. }
  299. pub async fn get_eth_balance(&self, acc: &str, block: &str) -> EthResult<Value> {
  300. let req = jsonrpc::request(json!("eth_getBalance"), json!([acc, block]));
  301. Ok(self.request(req).await?)
  302. }
  303. pub async fn get_erc20_balance(&self, acc: &str, mint: &str) -> EthResult<Value> {
  304. let tx = EthTx::new(
  305. acc,
  306. mint,
  307. None,
  308. None,
  309. None,
  310. Some(erc20_balanceof_data(acc)),
  311. None,
  312. );
  313. let req = jsonrpc::request(json!("eth_call"), json!([tx, "latest"]));
  314. Ok(self.request(req).await?)
  315. }
  316. pub async fn get_current_balance(&self, acc: &str, _mint: Option<&str>) -> EthResult<BigUint> {
  317. // Latest known block, used to calculate present balance.
  318. let block = self.block_number().await?;
  319. let block = block.as_str().unwrap();
  320. // Native ETH balance
  321. let hexbalance = self.get_eth_balance(acc, block).await?;
  322. let hexbalance = hexbalance.as_str().unwrap().trim_start_matches("0x");
  323. let balance = BigUint::parse_bytes(hexbalance.as_bytes(), 16).unwrap();
  324. Ok(balance)
  325. }
  326. pub async fn send_transaction(&self, tx: &EthTx, passphrase: &str) -> EthResult<Value> {
  327. let req = jsonrpc::request(json!("personal_sendTransaction"), json!([tx, passphrase]));
  328. Ok(self.request(req).await?)
  329. }
  330. }
  331. #[async_trait]
  332. impl NetworkClient for EthClient {
  333. async fn subscribe(
  334. self: Arc<Self>,
  335. drk_pub_key: jubjub::SubgroupPoint,
  336. _mint_address: Option<String>,
  337. executor: Arc<Executor<'_>>,
  338. ) -> Result<TokenSubscribtion> {
  339. let private_key = generate_privkey();
  340. let addr = self.import_privkey(&private_key, &self.passphrase).await?;
  341. let address: String = if addr.as_str().is_some() {
  342. addr.as_str().unwrap().to_string()
  343. } else {
  344. return Err(Error::from(EthFailed::ImportPrivateError));
  345. };
  346. let addr_cloned = address.clone();
  347. executor
  348. .spawn(async move {
  349. let result = self
  350. .handle_subscribe_request(addr_cloned, drk_pub_key)
  351. .await;
  352. if let Err(e) = result {
  353. error!(target: "ETH BRIDGE SUBSCRIPTION","{}", e.to_string());
  354. }
  355. })
  356. .detach();
  357. let private_key: Vec<u8> = serialize(&private_key);
  358. Ok(TokenSubscribtion {
  359. private_key,
  360. public_key: address,
  361. })
  362. }
  363. async fn subscribe_with_keypair(
  364. self: Arc<Self>,
  365. _private_key: Vec<u8>,
  366. public_key: Vec<u8>,
  367. drk_pub_key: jubjub::SubgroupPoint,
  368. _mint_address: Option<String>,
  369. executor: Arc<Executor<'_>>,
  370. ) -> Result<String> {
  371. let public_key: String = deserialize(&public_key)?;
  372. let address = public_key.clone();
  373. executor
  374. .spawn(async move {
  375. let result = self.handle_subscribe_request(address, drk_pub_key).await;
  376. if let Err(e) = result {
  377. error!(target: "ETH BRIDGE SUBSCRIPTION","{}", e.to_string());
  378. }
  379. })
  380. .detach();
  381. Ok(public_key)
  382. }
  383. async fn get_notifier(self: Arc<Self>) -> Result<async_channel::Receiver<TokenNotification>> {
  384. Ok(self.notify_channel.1.clone())
  385. }
  386. async fn send(
  387. self: Arc<Self>,
  388. address: Vec<u8>,
  389. _mint: Option<String>,
  390. amount: u64,
  391. ) -> Result<()> {
  392. // Recipient address
  393. let dest: String = deserialize(&address)?;
  394. let decimals = 18;
  395. // reverse truncate
  396. let amount = truncate(amount, decimals as u16, 8)?;
  397. let tx = EthTx::new(
  398. &self.main_keypair.public_key,
  399. &dest,
  400. None,
  401. None,
  402. Some(BigUint::from(amount)),
  403. None,
  404. None,
  405. );
  406. self.send_transaction(&tx, &self.passphrase).await?;
  407. Ok(())
  408. }
  409. }
  410. impl Encodable for Keypair {
  411. fn encode<S: std::io::Write>(&self, mut s: S) -> Result<usize> {
  412. let mut len = 0;
  413. len += self.private_key.encode(&mut s)?;
  414. len += self.public_key.encode(&mut s)?;
  415. Ok(len)
  416. }
  417. }
  418. impl Decodable for Keypair {
  419. fn decode<D: std::io::Read>(mut d: D) -> Result<Self> {
  420. Ok(Self {
  421. private_key: Decodable::decode(&mut d)?,
  422. public_key: Decodable::decode(&mut d)?,
  423. })
  424. }
  425. }
  426. #[derive(Debug)]
  427. pub enum EthFailed {
  428. NotEnoughValue(u64),
  429. MainAccountNotEnoughValue,
  430. BadEthAddress(String),
  431. DecodeAndEncodeError(String),
  432. RpcError(String),
  433. EthClientError(String),
  434. MintIsNotValid(String),
  435. JsonError(String),
  436. ParseError(String),
  437. ImportPrivateError,
  438. }
  439. impl std::error::Error for EthFailed {}
  440. impl std::fmt::Display for EthFailed {
  441. fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
  442. match self {
  443. EthFailed::NotEnoughValue(i) => {
  444. write!(f, "There is no enough value {}", i)
  445. }
  446. EthFailed::MainAccountNotEnoughValue => {
  447. write!(f, "Main Account Has no enough value")
  448. }
  449. EthFailed::BadEthAddress(ref err) => {
  450. write!(f, "Bad Eth Address: {}", err)
  451. }
  452. EthFailed::DecodeAndEncodeError(ref err) => {
  453. write!(f, "Decode and decode keys error: {}", err)
  454. }
  455. EthFailed::RpcError(i) => {
  456. write!(f, "Rpc Error: {}", i)
  457. }
  458. EthFailed::ParseError(i) => {
  459. write!(f, "Parse Error: {}", i)
  460. }
  461. EthFailed::MintIsNotValid(i) => {
  462. write!(f, "Given mint is not valid: {}", i)
  463. }
  464. EthFailed::JsonError(i) => {
  465. write!(f, "JsonError: {}", i)
  466. }
  467. EthFailed::ImportPrivateError => {
  468. write!(f, "Unable to derive address from private key")
  469. }
  470. EthFailed::EthClientError(i) => {
  471. write!(f, "Eth client error: {}", i)
  472. }
  473. }
  474. }
  475. }
  476. impl From<crate::error::Error> for EthFailed {
  477. fn from(err: crate::error::Error) -> EthFailed {
  478. EthFailed::EthClientError(err.to_string())
  479. }
  480. }
  481. impl From<serde_json::Error> for EthFailed {
  482. fn from(err: serde_json::Error) -> EthFailed {
  483. EthFailed::JsonError(err.to_string())
  484. }
  485. }
  486. pub type EthResult<T> = std::result::Result<T, EthFailed>;
  487. #[allow(unused_imports)]
  488. mod tests {
  489. use super::*;
  490. use num_bigint::ToBigUint;
  491. use std::str::FromStr;
  492. #[test]
  493. fn test_erc20_transfer_data() {
  494. let recipient = "0x5b7b3b499fb69c40c365343cb0dc842fe8c23887";
  495. let amnt = BigUint::from_str("34765403556934000640").unwrap();
  496. assert_eq!(erc20_transfer_data(recipient, amnt), "0xa9059cbb0000000000000000000000005b7b3b499fb69c40c365343cb0dc842fe8c23887000000000000000000000000000000000000000000000001e27786570c272000");
  497. }
  498. }