From b0cefffd0097d1a1abc0c553359acbfbf88f9af3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Tue, 5 Jul 2022 19:36:00 +0300 Subject: [PATCH 01/69] implement validation strcuture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins/eth.rs | 5 ++-- mm2src/coins/eth/eth_tests.rs | 37 ++++++++++++++++-------------- mm2src/coins/eth/eth_wasm_tests.rs | 2 +- mm2src/coins/eth/web3_transport.rs | 7 +++++- mm2src/mm2_net/src/transport.rs | 9 ++++++++ 5 files changed, 39 insertions(+), 21 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 89b5862240..9295280a65 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -3409,7 +3409,8 @@ pub async fn eth_coin_from_conf_and_request( for url in urls.iter() { let transport = try_s!(Web3Transport::with_event_handlers( vec![url.clone()], - event_handlers.clone() + event_handlers.clone(), + None )); let web3 = Web3::new(transport); let version = match web3.web3().client_version().compat().await { @@ -3429,7 +3430,7 @@ pub async fn eth_coin_from_conf_and_request( return ERR!("Failed to get client version for all urls"); } - let transport = try_s!(Web3Transport::with_event_handlers(urls, event_handlers)); + let transport = try_s!(Web3Transport::with_event_handlers(urls, event_handlers, None)); let web3 = Web3::new(transport); let (coin_type, decimals) = match protocol { diff --git a/mm2src/coins/eth/eth_tests.rs b/mm2src/coins/eth/eth_tests.rs index 46070326c8..480b38a76d 100644 --- a/mm2src/coins/eth/eth_tests.rs +++ b/mm2src/coins/eth/eth_tests.rs @@ -26,7 +26,7 @@ fn eth_coin_for_test( &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(urls).unwrap(); + let transport = Web3Transport::new(urls, None).unwrap(); let web3 = Web3::new(transport); let conf = json!({ "coins":[ @@ -202,7 +202,7 @@ fn send_and_refund_erc20_payment() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()]).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], None).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -272,7 +272,7 @@ fn send_and_refund_eth_payment() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()]).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], None).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -338,13 +338,14 @@ fn test_nonce_several_urls() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let infura_transport = Web3Transport::new(vec![ - "https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into() - ]) + let infura_transport = Web3Transport::new( + vec!["https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into()], + None, + ) .unwrap(); - let linkpool_transport = Web3Transport::new(vec!["https://ropsten-rpc.linkpool.io".into()]).unwrap(); + let linkpool_transport = Web3Transport::new(vec!["https://ropsten-rpc.linkpool.io".into()], None).unwrap(); // get nonce must succeed if some nodes are down at the moment for some reason - let failing_transport = Web3Transport::new(vec!["http://195.201.0.6:8989".into()]).unwrap(); + let failing_transport = Web3Transport::new(vec!["http://195.201.0.6:8989".into()], None).unwrap(); let web3_infura = Web3::new(infura_transport); let web3_linkpool = Web3::new(linkpool_transport); @@ -406,7 +407,7 @@ fn test_wait_for_payment_spend_timeout() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8555".into()]).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8555".into()], None).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); @@ -464,9 +465,10 @@ fn test_search_for_swap_tx_spend_was_spent() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec![ - "https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into() - ]) + let transport = Web3Transport::new( + vec!["https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into()], + None, + ) .unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); @@ -570,9 +572,10 @@ fn test_search_for_swap_tx_spend_was_refunded() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec![ - "https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into() - ]) + let transport = Web3Transport::new( + vec!["https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into()], + None, + ) .unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); @@ -1263,7 +1266,7 @@ fn test_message_hash() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()]).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], None).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -1304,7 +1307,7 @@ fn test_sign_verify_message() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()]).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], None).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { diff --git a/mm2src/coins/eth/eth_wasm_tests.rs b/mm2src/coins/eth/eth_wasm_tests.rs index ca1f3f8362..5fccf94ffd 100644 --- a/mm2src/coins/eth/eth_wasm_tests.rs +++ b/mm2src/coins/eth/eth_wasm_tests.rs @@ -20,7 +20,7 @@ async fn test_send() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8565".into()]).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8565".into()], None).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index 5b0b229a57..a987dcaa8c 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -3,6 +3,7 @@ use super::{RpcTransportEventHandler, RpcTransportEventHandlerShared}; use futures::TryFutureExt; use futures01::{Future, Poll}; use jsonrpc_core::{Call, Response}; +use mm2_net::transport::GuiAuthValidation; use serde_json::Value as Json; #[cfg(not(target_arch = "wasm32"))] use std::ops::Deref; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -72,11 +73,12 @@ pub struct Web3Transport { id: Arc, uris: Vec, event_handlers: Vec, + gui_auth_validation: Option, } impl Web3Transport { #[allow(dead_code)] - pub fn new(urls: Vec) -> Result { + pub fn new(urls: Vec, gui_auth_validation: Option) -> Result { let mut uris = vec![]; for url in urls.iter() { uris.push(try_s!(url.parse())); @@ -85,12 +87,14 @@ impl Web3Transport { id: Arc::new(AtomicUsize::new(0)), uris, event_handlers: Default::default(), + gui_auth_validation, }) } pub fn with_event_handlers( urls: Vec, event_handlers: Vec, + gui_auth_validation: Option, ) -> Result { let mut uris = vec![]; for url in urls.iter() { @@ -100,6 +104,7 @@ impl Web3Transport { id: Arc::new(AtomicUsize::new(0)), uris, event_handlers, + gui_auth_validation, }) } } diff --git a/mm2src/mm2_net/src/transport.rs b/mm2src/mm2_net/src/transport.rs index a76007b0f4..ebc5946eb9 100644 --- a/mm2src/mm2_net/src/transport.rs +++ b/mm2src/mm2_net/src/transport.rs @@ -48,3 +48,12 @@ where error: e.to_string(), }) } + +/// gui-auth specific data-type that needed in order to perform gui-auth calls +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct GuiAuthValidation { + pub(crate) coin_ticker: String, + pub(crate) address: String, + pub(crate) timestamp_message: u64, + pub(crate) signature: String, +} From cbb30d6662262b9360594ea4639f06a36c0aea55 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 6 Jul 2022 12:09:40 +0300 Subject: [PATCH 02/69] add signed_message to payload if exists Signed-off-by: ozkanonur --- mm2src/coins/eth/web3_transport.rs | 37 +++++++++++++++++++++++------- mm2src/common/common.rs | 8 +++++++ 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index a987dcaa8c..a96e57068f 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -135,15 +135,25 @@ impl Transport for Web3Transport { #[cfg(not(target_arch = "wasm32"))] fn send(&self, _id: RequestId, request: Call) -> Self::Out { Box::new( - send_request(request, self.uris.clone(), self.event_handlers.clone()) - .boxed() - .compat(), + send_request( + request, + self.uris.clone(), + self.event_handlers.clone(), + self.gui_auth_validation.clone(), + ) + .boxed() + .compat(), ) } #[cfg(target_arch = "wasm32")] fn send(&self, _id: RequestId, request: Call) -> Self::Out { - let fut = send_request(request, self.uris.clone(), self.event_handlers.clone()); + let fut = send_request( + request, + self.uris.clone(), + self.event_handlers.clone(), + self.gui_auth_validation, + ); Box::new(SendFuture(Box::pin(fut).compat())) } } @@ -153,6 +163,7 @@ async fn send_request( request: Call, uris: Vec, event_handlers: Vec, + gui_auth_validation: Option, ) -> Result { use common::executor::Timer; use common::log::warn; @@ -164,11 +175,21 @@ async fn send_request( const REQUEST_TIMEOUT_S: f64 = 60.; let mut errors = Vec::new(); - for uri in uris.iter() { - let request = to_string(&request); - event_handlers.on_outgoing_request(request.as_bytes()); - let mut req = http::Request::new(request.clone().into_bytes()); + let mut serialized_request = to_string(&request); + + if let Some(gui_auth_validation) = gui_auth_validation { + let mut json_payload = serde_json::to_value(&serialized_request)?; + json_payload["signed_message"] = json!(gui_auth_validation); + drop_mutability!(json_payload); + serialized_request = json_payload.to_string(); + } + drop_mutability!(serialized_request); + + event_handlers.on_outgoing_request(serialized_request.as_bytes()); + + for uri in uris.iter() { + let mut req = http::Request::new(serialized_request.clone().into_bytes()); *req.method_mut() = http::Method::POST; *req.uri_mut() = uri.clone(); req.headers_mut() diff --git a/mm2src/common/common.rs b/mm2src/common/common.rs index cd50616fb4..8567d321fd 100644 --- a/mm2src/common/common.rs +++ b/mm2src/common/common.rs @@ -84,6 +84,14 @@ macro_rules! try_h { }; } +/// Returns a JSON error HyRes on a failure. +#[macro_export] +macro_rules! drop_mutability { + ($t: ident) => { + let $t = $t; + }; +} + #[macro_use] pub mod jsonrpc_client; #[macro_use] From f5912ae437d84c0d66534e5f884a7ffcb2d8eba9 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 6 Jul 2022 12:11:11 +0300 Subject: [PATCH 03/69] update doc-comment of `drop_mutability` macro Signed-off-by: ozkanonur --- mm2src/common/common.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm2src/common/common.rs b/mm2src/common/common.rs index 8567d321fd..cf8eac4dfe 100644 --- a/mm2src/common/common.rs +++ b/mm2src/common/common.rs @@ -84,7 +84,7 @@ macro_rules! try_h { }; } -/// Returns a JSON error HyRes on a failure. +/// Drops mutability of given variable #[macro_export] macro_rules! drop_mutability { ($t: ident) => { From e366fff85a8d9ee15b6988fa378599b26e7cdaba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Wed, 6 Jul 2022 14:54:39 +0300 Subject: [PATCH 04/69] update `fn sign_message_hash` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins/eth.rs | 19 ++++++++++++++++++- mm2src/coins/eth/web3_transport.rs | 2 +- mm2src/mm2_net/src/transport.rs | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 9295280a65..4031eea905 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -288,6 +288,7 @@ pub struct EthCoinImpl { key_pair: KeyPair, my_address: Address, sign_message_prefix: Option, + gui_auth_message_prefix: Option, swap_contract_address: Address, fallback_swap_contract: Option
, web3: Web3, @@ -1092,7 +1093,20 @@ impl MarketCoinOps for EthCoin { /// Hash message for signature using Ethereum's message signing format. /// keccak256(PREFIX_LENGTH + PREFIX + MESSAGE_LENGTH + MESSAGE) fn sign_message_hash(&self, message: &str) -> Option<[u8; 32]> { - let message_prefix = self.sign_message_prefix.as_ref()?; + let (message, message_prefix) = match self.gui_auth_message_prefix.as_ref() { + Some(prefix) => { + let message = self + .web3 + .transport() + .gui_auth_validation + .as_ref()? + .timestamp_message + .to_string(); + (message, prefix) + }, + None => (String::from(message), self.sign_message_prefix.as_ref()?), + }; + let mut stream = Stream::new(); let prefix_len = CompactInteger::from(message_prefix.len()); prefix_len.serialize(&mut stream); @@ -3460,6 +3474,8 @@ pub async fn eth_coin_from_conf_and_request( } let sign_message_prefix: Option = json::from_value(conf["sign_message_prefix"].clone()).unwrap_or(None); + let gui_auth_message_prefix: Option = + json::from_value(conf["gui_auth_message_prefix"].clone()).unwrap_or(None); let initial_history_state = if req["tx_history"].as_bool().unwrap_or(false) { HistorySyncState::NotStarted @@ -3485,6 +3501,7 @@ pub async fn eth_coin_from_conf_and_request( my_address, coin_type, sign_message_prefix, + gui_auth_message_prefix, swap_contract_address, fallback_swap_contract, decimals, diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index a96e57068f..57ee59da50 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -73,7 +73,7 @@ pub struct Web3Transport { id: Arc, uris: Vec, event_handlers: Vec, - gui_auth_validation: Option, + pub(crate) gui_auth_validation: Option, } impl Web3Transport { diff --git a/mm2src/mm2_net/src/transport.rs b/mm2src/mm2_net/src/transport.rs index ebc5946eb9..7a65bfbed8 100644 --- a/mm2src/mm2_net/src/transport.rs +++ b/mm2src/mm2_net/src/transport.rs @@ -54,6 +54,6 @@ where pub struct GuiAuthValidation { pub(crate) coin_ticker: String, pub(crate) address: String, - pub(crate) timestamp_message: u64, + pub timestamp_message: u64, pub(crate) signature: String, } From 85a640498276718449ed42c9a516191e22256bcd Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 6 Jul 2022 15:28:26 +0300 Subject: [PATCH 05/69] fill `gui_auth_message_prefix` fields for tests Signed-off-by: ozkanonur --- mm2src/coins/eth/eth_tests.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mm2src/coins/eth/eth_tests.rs b/mm2src/coins/eth/eth_tests.rs index 480b38a76d..e47b4e2963 100644 --- a/mm2src/coins/eth/eth_tests.rs +++ b/mm2src/coins/eth/eth_tests.rs @@ -49,6 +49,7 @@ fn eth_coin_for_test( gas_station_policy: GasStationPricePolicy::MeanAverageFast, my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), + gui_auth_message_prefix: None, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract, @@ -213,6 +214,7 @@ fn send_and_refund_erc20_payment() { }, my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), + gui_auth_message_prefix: None, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract: None, @@ -280,6 +282,7 @@ fn send_and_refund_eth_payment() { coin_type: EthCoinType::Eth, my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), + gui_auth_message_prefix: None, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract: None, @@ -357,6 +360,7 @@ fn test_nonce_several_urls() { coin_type: EthCoinType::Eth, my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), + gui_auth_message_prefix: None, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract: None, @@ -420,6 +424,7 @@ fn test_wait_for_payment_spend_timeout() { history_sync_state: Mutex::new(HistorySyncState::NotEnabled), my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), + gui_auth_message_prefix: None, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract: None, @@ -483,6 +488,7 @@ fn test_search_for_swap_tx_spend_was_spent() { history_sync_state: Mutex::new(HistorySyncState::NotEnabled), my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), + gui_auth_message_prefix: None, key_pair, swap_contract_address, fallback_swap_contract: None, @@ -593,6 +599,7 @@ fn test_search_for_swap_tx_spend_was_refunded() { history_sync_state: Mutex::new(HistorySyncState::NotEnabled), my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), + gui_auth_message_prefix: None, key_pair, swap_contract_address, fallback_swap_contract: None, @@ -1274,6 +1281,7 @@ fn test_message_hash() { coin_type: EthCoinType::Eth, my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), + gui_auth_message_prefix: None, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract: None, @@ -1315,6 +1323,7 @@ fn test_sign_verify_message() { coin_type: EthCoinType::Eth, my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), + gui_auth_message_prefix: None, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract: None, From 9efd6bcb26f7602b75fa8e76113e930e53394c5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Wed, 6 Jul 2022 22:40:01 +0300 Subject: [PATCH 06/69] create and implement `trait GuiAuthMessages` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins/eth.rs | 57 +++++++++++++++++++++++++-------- mm2src/mm2_net/src/transport.rs | 6 ++-- 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 4031eea905..f8f80904a7 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -37,7 +37,7 @@ use futures01::Future; use http::StatusCode; use mm2_core::mm_ctx::{MmArc, MmWeak}; use mm2_err_handle::prelude::*; -use mm2_net::transport::{slurp_url, SlurpError}; +use mm2_net::transport::{slurp_url, GuiAuthValidation, SlurpError}; #[cfg(test)] use mocktopus::macros::*; use rand::seq::SliceRandom; use rpc::v1::types::Bytes as BytesJson; @@ -51,6 +51,7 @@ use std::path::PathBuf; use std::str::FromStr; use std::sync::atomic::{AtomicU64, Ordering as AtomicOrdering}; use std::sync::{Arc, Mutex}; +use std::time::{SystemTime, UNIX_EPOCH}; use web3::types::{Action as TraceAction, BlockId, BlockNumber, Bytes, CallRequest, FilterBuilder, Log, Trace, TraceFilterBuilder, Transaction as Web3Transaction, TransactionId}; use web3::{self, Web3}; @@ -1093,19 +1094,7 @@ impl MarketCoinOps for EthCoin { /// Hash message for signature using Ethereum's message signing format. /// keccak256(PREFIX_LENGTH + PREFIX + MESSAGE_LENGTH + MESSAGE) fn sign_message_hash(&self, message: &str) -> Option<[u8; 32]> { - let (message, message_prefix) = match self.gui_auth_message_prefix.as_ref() { - Some(prefix) => { - let message = self - .web3 - .transport() - .gui_auth_validation - .as_ref()? - .timestamp_message - .to_string(); - (message, prefix) - }, - None => (String::from(message), self.sign_message_prefix.as_ref()?), - }; + let message_prefix = self.sign_message_prefix.as_ref()?; let mut stream = Stream::new(); let prefix_len = CompactInteger::from(message_prefix.len()); @@ -3218,6 +3207,46 @@ impl TryToAddress for Option { } } +pub trait GuiAuthMessages { + fn gui_auth_sign_message_hash(&self, message: String) -> Option<[u8; 32]>; + fn generate_gui_auth_signed_validation(&self) -> SignatureResult; +} + +impl GuiAuthMessages for EthCoin { + fn gui_auth_sign_message_hash(&self, message: String) -> Option<[u8; 32]> { + let message_prefix = self.gui_auth_message_prefix.as_ref()?; + let prefix_len = CompactInteger::from(message_prefix.len()); + + let mut stream = Stream::new(); + prefix_len.serialize(&mut stream); + stream.append_slice(message_prefix.as_bytes()); + stream.append_slice(message.len().to_string().as_bytes()); + stream.append_slice(message.as_bytes()); + + Some(keccak256(&stream.out()).take()) + } + + fn generate_gui_auth_signed_validation(&self) -> SignatureResult { + let timestamp_message = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map_err(|e| SignatureError::InternalError(e.to_string()))? + .as_secs(); + + let message_hash = self + .gui_auth_sign_message_hash(timestamp_message.to_string()) + .ok_or(SignatureError::PrefixNotFound)?; + let privkey = &self.key_pair.secret(); + let signature = sign(privkey, &H256::from(message_hash))?; + + Ok(GuiAuthValidation { + coin_ticker: self.ticker.clone(), + address: self.my_address.to_string(), + timestamp_message: timestamp_message + 5 * 60, + signature: format!("0x{}", signature), + }) + } +} + pub fn addr_from_raw_pubkey(pubkey: &[u8]) -> Result { let pubkey = try_s!(PublicKey::from_slice(pubkey).map_err(|e| ERRL!("{:?}", e))); let eth_public = Public::from(&pubkey.serialize_uncompressed()[1..65]); diff --git a/mm2src/mm2_net/src/transport.rs b/mm2src/mm2_net/src/transport.rs index 7a65bfbed8..c44f0d2cb9 100644 --- a/mm2src/mm2_net/src/transport.rs +++ b/mm2src/mm2_net/src/transport.rs @@ -52,8 +52,8 @@ where /// gui-auth specific data-type that needed in order to perform gui-auth calls #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct GuiAuthValidation { - pub(crate) coin_ticker: String, - pub(crate) address: String, + pub coin_ticker: String, + pub address: String, pub timestamp_message: u64, - pub(crate) signature: String, + pub signature: String, } From a59f4bd23c1fecdde4a7042e659abf174cb85f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Wed, 6 Jul 2022 22:53:19 +0300 Subject: [PATCH 07/69] save development state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins/eth/eth_wasm_tests.rs | 1 + mm2src/coins/eth/web3_transport.rs | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/mm2src/coins/eth/eth_wasm_tests.rs b/mm2src/coins/eth/eth_wasm_tests.rs index 5fccf94ffd..b9199fe134 100644 --- a/mm2src/coins/eth/eth_wasm_tests.rs +++ b/mm2src/coins/eth/eth_wasm_tests.rs @@ -28,6 +28,7 @@ async fn test_send() { coin_type: EthCoinType::Eth, my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), + gui_auth_message_prefix: None, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract: None, diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index 57ee59da50..33465091ab 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -152,7 +152,7 @@ impl Transport for Web3Transport { request, self.uris.clone(), self.event_handlers.clone(), - self.gui_auth_validation, + self.gui_auth_validation.clone(), ); Box::new(SendFuture(Box::pin(fut).compat())) } @@ -237,12 +237,21 @@ async fn send_request( request: Call, uris: Vec, event_handlers: Vec, + gui_auth_validation: Option, ) -> Result { - let request_payload = to_string(&request); + let mut serialized_request = to_string(&request); + + if let Some(gui_auth_validation) = gui_auth_validation { + let mut json_payload = serde_json::to_value(&serialized_request)?; + json_payload["signed_message"] = json!(gui_auth_validation); + drop_mutability!(json_payload); + serialized_request = json_payload.to_string(); + } + drop_mutability!(serialized_request); let mut transport_errors = Vec::new(); for uri in uris { - match send_request_once(request_payload.clone(), &uri, &event_handlers).await { + match send_request_once(serialized_request.clone(), &uri, &event_handlers).await { Ok(response_json) => return Ok(response_json), Err(Error(ErrorKind::Transport(e), _)) => { transport_errors.push(e.to_string()); From 6a79d3c5324c2887393e91139099c15b78ce473b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Wed, 6 Jul 2022 23:42:42 +0300 Subject: [PATCH 08/69] save development state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins/eth.rs | 9 +++---- mm2src/coins/eth/eth_tests.rs | 18 ++++++------- mm2src/coins/eth/eth_wasm_tests.rs | 2 +- mm2src/coins/eth/web3_transport.rs | 42 +++++++++++++++++++++--------- 4 files changed, 43 insertions(+), 28 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index f8f80904a7..fddc559731 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -289,7 +289,7 @@ pub struct EthCoinImpl { key_pair: KeyPair, my_address: Address, sign_message_prefix: Option, - gui_auth_message_prefix: Option, + gui_auth: bool, swap_contract_address: Address, fallback_swap_contract: Option
, web3: Web3, @@ -3214,7 +3214,7 @@ pub trait GuiAuthMessages { impl GuiAuthMessages for EthCoin { fn gui_auth_sign_message_hash(&self, message: String) -> Option<[u8; 32]> { - let message_prefix = self.gui_auth_message_prefix.as_ref()?; + let message_prefix = "atomicDEX Auth Ethereum Signed Message:\n"; let prefix_len = CompactInteger::from(message_prefix.len()); let mut stream = Stream::new(); @@ -3503,8 +3503,7 @@ pub async fn eth_coin_from_conf_and_request( } let sign_message_prefix: Option = json::from_value(conf["sign_message_prefix"].clone()).unwrap_or(None); - let gui_auth_message_prefix: Option = - json::from_value(conf["gui_auth_message_prefix"].clone()).unwrap_or(None); + let gui_auth: bool = json::from_value(conf["gui_auth"].clone()).unwrap_or(false); let initial_history_state = if req["tx_history"].as_bool().unwrap_or(false) { HistorySyncState::NotStarted @@ -3530,7 +3529,7 @@ pub async fn eth_coin_from_conf_and_request( my_address, coin_type, sign_message_prefix, - gui_auth_message_prefix, + gui_auth, swap_contract_address, fallback_swap_contract, decimals, diff --git a/mm2src/coins/eth/eth_tests.rs b/mm2src/coins/eth/eth_tests.rs index e47b4e2963..c6407f64c8 100644 --- a/mm2src/coins/eth/eth_tests.rs +++ b/mm2src/coins/eth/eth_tests.rs @@ -49,7 +49,7 @@ fn eth_coin_for_test( gas_station_policy: GasStationPricePolicy::MeanAverageFast, my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), - gui_auth_message_prefix: None, + gui_auth: false, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract, @@ -214,7 +214,7 @@ fn send_and_refund_erc20_payment() { }, my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), - gui_auth_message_prefix: None, + gui_auth: false, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract: None, @@ -282,7 +282,7 @@ fn send_and_refund_eth_payment() { coin_type: EthCoinType::Eth, my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), - gui_auth_message_prefix: None, + gui_auth: false, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract: None, @@ -360,7 +360,7 @@ fn test_nonce_several_urls() { coin_type: EthCoinType::Eth, my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), - gui_auth_message_prefix: None, + gui_auth: false, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract: None, @@ -424,7 +424,7 @@ fn test_wait_for_payment_spend_timeout() { history_sync_state: Mutex::new(HistorySyncState::NotEnabled), my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), - gui_auth_message_prefix: None, + gui_auth: false, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract: None, @@ -488,7 +488,7 @@ fn test_search_for_swap_tx_spend_was_spent() { history_sync_state: Mutex::new(HistorySyncState::NotEnabled), my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), - gui_auth_message_prefix: None, + gui_auth: false, key_pair, swap_contract_address, fallback_swap_contract: None, @@ -599,7 +599,7 @@ fn test_search_for_swap_tx_spend_was_refunded() { history_sync_state: Mutex::new(HistorySyncState::NotEnabled), my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), - gui_auth_message_prefix: None, + gui_auth: false, key_pair, swap_contract_address, fallback_swap_contract: None, @@ -1281,7 +1281,7 @@ fn test_message_hash() { coin_type: EthCoinType::Eth, my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), - gui_auth_message_prefix: None, + gui_auth: false, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract: None, @@ -1323,7 +1323,7 @@ fn test_sign_verify_message() { coin_type: EthCoinType::Eth, my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), - gui_auth_message_prefix: None, + gui_auth: false, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract: None, diff --git a/mm2src/coins/eth/eth_wasm_tests.rs b/mm2src/coins/eth/eth_wasm_tests.rs index b9199fe134..bb1231126c 100644 --- a/mm2src/coins/eth/eth_wasm_tests.rs +++ b/mm2src/coins/eth/eth_wasm_tests.rs @@ -28,7 +28,7 @@ async fn test_send() { coin_type: EthCoinType::Eth, my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), - gui_auth_message_prefix: None, + gui_auth: false, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract: None, diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index 33465091ab..3035150a84 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -73,12 +73,17 @@ pub struct Web3Transport { id: Arc, uris: Vec, event_handlers: Vec, + pub(crate) gui_auth: bool, pub(crate) gui_auth_validation: Option, } impl Web3Transport { #[allow(dead_code)] - pub fn new(urls: Vec, gui_auth_validation: Option) -> Result { + pub fn new( + urls: Vec, + gui_auth: bool, + gui_auth_validation: Option, + ) -> Result { let mut uris = vec![]; for url in urls.iter() { uris.push(try_s!(url.parse())); @@ -87,6 +92,7 @@ impl Web3Transport { id: Arc::new(AtomicUsize::new(0)), uris, event_handlers: Default::default(), + gui_auth, gui_auth_validation, }) } @@ -94,6 +100,7 @@ impl Web3Transport { pub fn with_event_handlers( urls: Vec, event_handlers: Vec, + gui_auth: bool, gui_auth_validation: Option, ) -> Result { let mut uris = vec![]; @@ -104,6 +111,7 @@ impl Web3Transport { id: Arc::new(AtomicUsize::new(0)), uris, event_handlers, + gui_auth, gui_auth_validation, }) } @@ -163,6 +171,7 @@ async fn send_request( request: Call, uris: Vec, event_handlers: Vec, + gui_auth: bool, gui_auth_validation: Option, ) -> Result { use common::executor::Timer; @@ -178,12 +187,15 @@ async fn send_request( let mut serialized_request = to_string(&request); - if let Some(gui_auth_validation) = gui_auth_validation { - let mut json_payload = serde_json::to_value(&serialized_request)?; - json_payload["signed_message"] = json!(gui_auth_validation); - drop_mutability!(json_payload); - serialized_request = json_payload.to_string(); - } + match gui_auth_validation { + Some(gui_auth_validation) if gui_auth => { + let mut json_payload = serde_json::to_value(&serialized_request)?; + json_payload["signed_message"] = json!(gui_auth_validation); + common::drop_mutability!(json_payload); + serialized_request = json_payload.to_string(); + }, + _ => {}, + }; drop_mutability!(serialized_request); event_handlers.on_outgoing_request(serialized_request.as_bytes()); @@ -237,16 +249,20 @@ async fn send_request( request: Call, uris: Vec, event_handlers: Vec, + gui_auth: bool, gui_auth_validation: Option, ) -> Result { let mut serialized_request = to_string(&request); - if let Some(gui_auth_validation) = gui_auth_validation { - let mut json_payload = serde_json::to_value(&serialized_request)?; - json_payload["signed_message"] = json!(gui_auth_validation); - drop_mutability!(json_payload); - serialized_request = json_payload.to_string(); - } + match gui_auth_validation { + Some(gui_auth_validation) if gui_auth => { + let mut json_payload = serde_json::to_value(&serialized_request)?; + json_payload["signed_message"] = json!(gui_auth_validation); + drop_mutability!(json_payload); + serialized_request = json_payload.to_string(); + }, + _ => {}, + }; drop_mutability!(serialized_request); let mut transport_errors = Vec::new(); From 84ec84f14a6c9538bed6e504189edbc5fecd697c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Thu, 7 Jul 2022 00:27:03 +0300 Subject: [PATCH 09/69] save development state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins/eth.rs | 5 +++-- mm2src/coins/eth/eth_tests.rs | 19 +++++++++++-------- mm2src/coins/eth/eth_wasm_tests.rs | 2 +- mm2src/coins/eth/web3_transport.rs | 2 ++ 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index fddc559731..b6651658d3 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -3444,6 +3444,7 @@ pub async fn eth_coin_from_conf_and_request( } } + let gui_auth: bool = json::from_value(conf["gui_auth"].clone()).unwrap_or(false); let key_pair: KeyPair = try_s!(KeyPair::from_secret_slice(priv_key)); let my_address = key_pair.address(); @@ -3453,6 +3454,7 @@ pub async fn eth_coin_from_conf_and_request( let transport = try_s!(Web3Transport::with_event_handlers( vec![url.clone()], event_handlers.clone(), + gui_auth, None )); let web3 = Web3::new(transport); @@ -3473,7 +3475,7 @@ pub async fn eth_coin_from_conf_and_request( return ERR!("Failed to get client version for all urls"); } - let transport = try_s!(Web3Transport::with_event_handlers(urls, event_handlers, None)); + let transport = try_s!(Web3Transport::with_event_handlers(urls, event_handlers, gui_auth, None)); let web3 = Web3::new(transport); let (coin_type, decimals) = match protocol { @@ -3503,7 +3505,6 @@ pub async fn eth_coin_from_conf_and_request( } let sign_message_prefix: Option = json::from_value(conf["sign_message_prefix"].clone()).unwrap_or(None); - let gui_auth: bool = json::from_value(conf["gui_auth"].clone()).unwrap_or(false); let initial_history_state = if req["tx_history"].as_bool().unwrap_or(false) { HistorySyncState::NotStarted diff --git a/mm2src/coins/eth/eth_tests.rs b/mm2src/coins/eth/eth_tests.rs index c6407f64c8..bae4481501 100644 --- a/mm2src/coins/eth/eth_tests.rs +++ b/mm2src/coins/eth/eth_tests.rs @@ -26,7 +26,7 @@ fn eth_coin_for_test( &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(urls, None).unwrap(); + let transport = Web3Transport::new(urls, false, None).unwrap(); let web3 = Web3::new(transport); let conf = json!({ "coins":[ @@ -203,7 +203,7 @@ fn send_and_refund_erc20_payment() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], None).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], false, None).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -274,7 +274,7 @@ fn send_and_refund_eth_payment() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], None).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], false, None).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -343,12 +343,13 @@ fn test_nonce_several_urls() { .unwrap(); let infura_transport = Web3Transport::new( vec!["https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into()], + false, None, ) .unwrap(); - let linkpool_transport = Web3Transport::new(vec!["https://ropsten-rpc.linkpool.io".into()], None).unwrap(); + let linkpool_transport = Web3Transport::new(vec!["https://ropsten-rpc.linkpool.io".into()], false, None).unwrap(); // get nonce must succeed if some nodes are down at the moment for some reason - let failing_transport = Web3Transport::new(vec!["http://195.201.0.6:8989".into()], None).unwrap(); + let failing_transport = Web3Transport::new(vec!["http://195.201.0.6:8989".into()], false, None).unwrap(); let web3_infura = Web3::new(infura_transport); let web3_linkpool = Web3::new(linkpool_transport); @@ -411,7 +412,7 @@ fn test_wait_for_payment_spend_timeout() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8555".into()], None).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8555".into()], false, None).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); @@ -472,6 +473,7 @@ fn test_search_for_swap_tx_spend_was_spent() { .unwrap(); let transport = Web3Transport::new( vec!["https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into()], + false, None, ) .unwrap(); @@ -580,6 +582,7 @@ fn test_search_for_swap_tx_spend_was_refunded() { .unwrap(); let transport = Web3Transport::new( vec!["https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into()], + false, None, ) .unwrap(); @@ -1273,7 +1276,7 @@ fn test_message_hash() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], None).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], false, None).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -1315,7 +1318,7 @@ fn test_sign_verify_message() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], None).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], false, None).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { diff --git a/mm2src/coins/eth/eth_wasm_tests.rs b/mm2src/coins/eth/eth_wasm_tests.rs index bb1231126c..092dbf3e76 100644 --- a/mm2src/coins/eth/eth_wasm_tests.rs +++ b/mm2src/coins/eth/eth_wasm_tests.rs @@ -20,7 +20,7 @@ async fn test_send() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8565".into()], None).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8565".into()], false, None).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index 3035150a84..4bdc5245d4 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -147,6 +147,7 @@ impl Transport for Web3Transport { request, self.uris.clone(), self.event_handlers.clone(), + self.gui_auth, self.gui_auth_validation.clone(), ) .boxed() @@ -160,6 +161,7 @@ impl Transport for Web3Transport { request, self.uris.clone(), self.event_handlers.clone(), + self.gui_auth, self.gui_auth_validation.clone(), ); Box::new(SendFuture(Box::pin(fut).compat())) From 903edf3d42ce119a6c072703d7c06242fd13e31d Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Thu, 7 Jul 2022 13:29:25 +0300 Subject: [PATCH 10/69] save development state Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 6 +---- mm2src/coins/eth/eth_tests.rs | 28 ++++++--------------- mm2src/coins/eth/eth_wasm_tests.rs | 3 +-- mm2src/coins/eth/web3_transport.rs | 40 ++++++++---------------------- 4 files changed, 21 insertions(+), 56 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index b6651658d3..0325de492a 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -289,7 +289,6 @@ pub struct EthCoinImpl { key_pair: KeyPair, my_address: Address, sign_message_prefix: Option, - gui_auth: bool, swap_contract_address: Address, fallback_swap_contract: Option
, web3: Web3, @@ -3444,7 +3443,6 @@ pub async fn eth_coin_from_conf_and_request( } } - let gui_auth: bool = json::from_value(conf["gui_auth"].clone()).unwrap_or(false); let key_pair: KeyPair = try_s!(KeyPair::from_secret_slice(priv_key)); let my_address = key_pair.address(); @@ -3454,7 +3452,6 @@ pub async fn eth_coin_from_conf_and_request( let transport = try_s!(Web3Transport::with_event_handlers( vec![url.clone()], event_handlers.clone(), - gui_auth, None )); let web3 = Web3::new(transport); @@ -3475,7 +3472,7 @@ pub async fn eth_coin_from_conf_and_request( return ERR!("Failed to get client version for all urls"); } - let transport = try_s!(Web3Transport::with_event_handlers(urls, event_handlers, gui_auth, None)); + let transport = try_s!(Web3Transport::with_event_handlers(urls, event_handlers, None)); let web3 = Web3::new(transport); let (coin_type, decimals) = match protocol { @@ -3530,7 +3527,6 @@ pub async fn eth_coin_from_conf_and_request( my_address, coin_type, sign_message_prefix, - gui_auth, swap_contract_address, fallback_swap_contract, decimals, diff --git a/mm2src/coins/eth/eth_tests.rs b/mm2src/coins/eth/eth_tests.rs index bae4481501..480b38a76d 100644 --- a/mm2src/coins/eth/eth_tests.rs +++ b/mm2src/coins/eth/eth_tests.rs @@ -26,7 +26,7 @@ fn eth_coin_for_test( &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(urls, false, None).unwrap(); + let transport = Web3Transport::new(urls, None).unwrap(); let web3 = Web3::new(transport); let conf = json!({ "coins":[ @@ -49,7 +49,6 @@ fn eth_coin_for_test( gas_station_policy: GasStationPricePolicy::MeanAverageFast, my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), - gui_auth: false, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract, @@ -203,7 +202,7 @@ fn send_and_refund_erc20_payment() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], false, None).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], None).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -214,7 +213,6 @@ fn send_and_refund_erc20_payment() { }, my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), - gui_auth: false, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract: None, @@ -274,7 +272,7 @@ fn send_and_refund_eth_payment() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], false, None).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], None).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -282,7 +280,6 @@ fn send_and_refund_eth_payment() { coin_type: EthCoinType::Eth, my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), - gui_auth: false, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract: None, @@ -343,13 +340,12 @@ fn test_nonce_several_urls() { .unwrap(); let infura_transport = Web3Transport::new( vec!["https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into()], - false, None, ) .unwrap(); - let linkpool_transport = Web3Transport::new(vec!["https://ropsten-rpc.linkpool.io".into()], false, None).unwrap(); + let linkpool_transport = Web3Transport::new(vec!["https://ropsten-rpc.linkpool.io".into()], None).unwrap(); // get nonce must succeed if some nodes are down at the moment for some reason - let failing_transport = Web3Transport::new(vec!["http://195.201.0.6:8989".into()], false, None).unwrap(); + let failing_transport = Web3Transport::new(vec!["http://195.201.0.6:8989".into()], None).unwrap(); let web3_infura = Web3::new(infura_transport); let web3_linkpool = Web3::new(linkpool_transport); @@ -361,7 +357,6 @@ fn test_nonce_several_urls() { coin_type: EthCoinType::Eth, my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), - gui_auth: false, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract: None, @@ -412,7 +407,7 @@ fn test_wait_for_payment_spend_timeout() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8555".into()], false, None).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8555".into()], None).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); @@ -425,7 +420,6 @@ fn test_wait_for_payment_spend_timeout() { history_sync_state: Mutex::new(HistorySyncState::NotEnabled), my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), - gui_auth: false, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract: None, @@ -473,7 +467,6 @@ fn test_search_for_swap_tx_spend_was_spent() { .unwrap(); let transport = Web3Transport::new( vec!["https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into()], - false, None, ) .unwrap(); @@ -490,7 +483,6 @@ fn test_search_for_swap_tx_spend_was_spent() { history_sync_state: Mutex::new(HistorySyncState::NotEnabled), my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), - gui_auth: false, key_pair, swap_contract_address, fallback_swap_contract: None, @@ -582,7 +574,6 @@ fn test_search_for_swap_tx_spend_was_refunded() { .unwrap(); let transport = Web3Transport::new( vec!["https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into()], - false, None, ) .unwrap(); @@ -602,7 +593,6 @@ fn test_search_for_swap_tx_spend_was_refunded() { history_sync_state: Mutex::new(HistorySyncState::NotEnabled), my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), - gui_auth: false, key_pair, swap_contract_address, fallback_swap_contract: None, @@ -1276,7 +1266,7 @@ fn test_message_hash() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], false, None).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], None).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -1284,7 +1274,6 @@ fn test_message_hash() { coin_type: EthCoinType::Eth, my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), - gui_auth: false, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract: None, @@ -1318,7 +1307,7 @@ fn test_sign_verify_message() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], false, None).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], None).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -1326,7 +1315,6 @@ fn test_sign_verify_message() { coin_type: EthCoinType::Eth, my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), - gui_auth: false, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract: None, diff --git a/mm2src/coins/eth/eth_wasm_tests.rs b/mm2src/coins/eth/eth_wasm_tests.rs index 092dbf3e76..5fccf94ffd 100644 --- a/mm2src/coins/eth/eth_wasm_tests.rs +++ b/mm2src/coins/eth/eth_wasm_tests.rs @@ -20,7 +20,7 @@ async fn test_send() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8565".into()], false, None).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8565".into()], None).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -28,7 +28,6 @@ async fn test_send() { coin_type: EthCoinType::Eth, my_address: key_pair.address(), sign_message_prefix: Some(String::from("Ethereum Signed Message:\n")), - gui_auth: false, key_pair, swap_contract_address: Address::from("0x7Bc1bBDD6A0a722fC9bffC49c921B685ECB84b94"), fallback_swap_contract: None, diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index 4bdc5245d4..abc9ae805b 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -73,17 +73,12 @@ pub struct Web3Transport { id: Arc, uris: Vec, event_handlers: Vec, - pub(crate) gui_auth: bool, pub(crate) gui_auth_validation: Option, } impl Web3Transport { #[allow(dead_code)] - pub fn new( - urls: Vec, - gui_auth: bool, - gui_auth_validation: Option, - ) -> Result { + pub fn new(urls: Vec, gui_auth_validation: Option) -> Result { let mut uris = vec![]; for url in urls.iter() { uris.push(try_s!(url.parse())); @@ -92,7 +87,6 @@ impl Web3Transport { id: Arc::new(AtomicUsize::new(0)), uris, event_handlers: Default::default(), - gui_auth, gui_auth_validation, }) } @@ -100,7 +94,6 @@ impl Web3Transport { pub fn with_event_handlers( urls: Vec, event_handlers: Vec, - gui_auth: bool, gui_auth_validation: Option, ) -> Result { let mut uris = vec![]; @@ -111,7 +104,6 @@ impl Web3Transport { id: Arc::new(AtomicUsize::new(0)), uris, event_handlers, - gui_auth, gui_auth_validation, }) } @@ -147,7 +139,6 @@ impl Transport for Web3Transport { request, self.uris.clone(), self.event_handlers.clone(), - self.gui_auth, self.gui_auth_validation.clone(), ) .boxed() @@ -161,7 +152,6 @@ impl Transport for Web3Transport { request, self.uris.clone(), self.event_handlers.clone(), - self.gui_auth, self.gui_auth_validation.clone(), ); Box::new(SendFuture(Box::pin(fut).compat())) @@ -173,7 +163,6 @@ async fn send_request( request: Call, uris: Vec, event_handlers: Vec, - gui_auth: bool, gui_auth_validation: Option, ) -> Result { use common::executor::Timer; @@ -189,14 +178,11 @@ async fn send_request( let mut serialized_request = to_string(&request); - match gui_auth_validation { - Some(gui_auth_validation) if gui_auth => { - let mut json_payload = serde_json::to_value(&serialized_request)?; - json_payload["signed_message"] = json!(gui_auth_validation); - common::drop_mutability!(json_payload); - serialized_request = json_payload.to_string(); - }, - _ => {}, + if let Some(gui_auth_validation) = gui_auth_validation { + let mut json_payload = serde_json::to_value(&serialized_request)?; + json_payload["signed_message"] = json!(gui_auth_validation); + common::drop_mutability!(json_payload); + serialized_request = json_payload.to_string(); }; drop_mutability!(serialized_request); @@ -251,19 +237,15 @@ async fn send_request( request: Call, uris: Vec, event_handlers: Vec, - gui_auth: bool, gui_auth_validation: Option, ) -> Result { let mut serialized_request = to_string(&request); - match gui_auth_validation { - Some(gui_auth_validation) if gui_auth => { - let mut json_payload = serde_json::to_value(&serialized_request)?; - json_payload["signed_message"] = json!(gui_auth_validation); - drop_mutability!(json_payload); - serialized_request = json_payload.to_string(); - }, - _ => {}, + if let Some(gui_auth_validation) = gui_auth_validation { + let mut json_payload = serde_json::to_value(&serialized_request)?; + json_payload["signed_message"] = json!(gui_auth_validation); + common::drop_mutability!(json_payload); + serialized_request = json_payload.to_string(); }; drop_mutability!(serialized_request); From 19ffa0955437250e51656e5e5e043092376ee0b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Thu, 7 Jul 2022 16:25:26 +0300 Subject: [PATCH 11/69] save development state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins/eth.rs | 4 +-- mm2src/coins/eth/eth_tests.rs | 22 ++++++------ mm2src/coins/eth/eth_wasm_tests.rs | 2 +- mm2src/coins/eth/web3_transport.rs | 58 ++++++++++++++++++------------ 4 files changed, 49 insertions(+), 37 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 0325de492a..7b2ec1fa02 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -3452,7 +3452,7 @@ pub async fn eth_coin_from_conf_and_request( let transport = try_s!(Web3Transport::with_event_handlers( vec![url.clone()], event_handlers.clone(), - None + false )); let web3 = Web3::new(transport); let version = match web3.web3().client_version().compat().await { @@ -3472,7 +3472,7 @@ pub async fn eth_coin_from_conf_and_request( return ERR!("Failed to get client version for all urls"); } - let transport = try_s!(Web3Transport::with_event_handlers(urls, event_handlers, None)); + let transport = try_s!(Web3Transport::with_event_handlers(urls, event_handlers, false)); let web3 = Web3::new(transport); let (coin_type, decimals) = match protocol { diff --git a/mm2src/coins/eth/eth_tests.rs b/mm2src/coins/eth/eth_tests.rs index 480b38a76d..7e8482f96a 100644 --- a/mm2src/coins/eth/eth_tests.rs +++ b/mm2src/coins/eth/eth_tests.rs @@ -26,7 +26,7 @@ fn eth_coin_for_test( &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(urls, None).unwrap(); + let transport = Web3Transport::new(urls, false).unwrap(); let web3 = Web3::new(transport); let conf = json!({ "coins":[ @@ -202,7 +202,7 @@ fn send_and_refund_erc20_payment() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], None).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], false).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -272,7 +272,7 @@ fn send_and_refund_eth_payment() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], None).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], false).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -340,12 +340,12 @@ fn test_nonce_several_urls() { .unwrap(); let infura_transport = Web3Transport::new( vec!["https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into()], - None, + false, ) .unwrap(); - let linkpool_transport = Web3Transport::new(vec!["https://ropsten-rpc.linkpool.io".into()], None).unwrap(); + let linkpool_transport = Web3Transport::new(vec!["https://ropsten-rpc.linkpool.io".into()], false).unwrap(); // get nonce must succeed if some nodes are down at the moment for some reason - let failing_transport = Web3Transport::new(vec!["http://195.201.0.6:8989".into()], None).unwrap(); + let failing_transport = Web3Transport::new(vec!["http://195.201.0.6:8989".into()], false).unwrap(); let web3_infura = Web3::new(infura_transport); let web3_linkpool = Web3::new(linkpool_transport); @@ -407,7 +407,7 @@ fn test_wait_for_payment_spend_timeout() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8555".into()], None).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8555".into()], false).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); @@ -467,7 +467,7 @@ fn test_search_for_swap_tx_spend_was_spent() { .unwrap(); let transport = Web3Transport::new( vec!["https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into()], - None, + false, ) .unwrap(); let web3 = Web3::new(transport); @@ -574,7 +574,7 @@ fn test_search_for_swap_tx_spend_was_refunded() { .unwrap(); let transport = Web3Transport::new( vec!["https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into()], - None, + false, ) .unwrap(); let web3 = Web3::new(transport); @@ -1266,7 +1266,7 @@ fn test_message_hash() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], None).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], false).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -1307,7 +1307,7 @@ fn test_sign_verify_message() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], None).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], false).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { diff --git a/mm2src/coins/eth/eth_wasm_tests.rs b/mm2src/coins/eth/eth_wasm_tests.rs index 5fccf94ffd..d6e55c13ee 100644 --- a/mm2src/coins/eth/eth_wasm_tests.rs +++ b/mm2src/coins/eth/eth_wasm_tests.rs @@ -20,7 +20,7 @@ async fn test_send() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8565".into()], None).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8565".into()], false).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index abc9ae805b..9063d8b892 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -71,40 +71,48 @@ fn single_response>(response: T, rpc_url: &str) -> Resul #[derive(Clone, Debug)] pub struct Web3Transport { id: Arc, - uris: Vec, + nodes: Vec, event_handlers: Vec, pub(crate) gui_auth_validation: Option, } +#[derive(Clone, Debug)] +pub struct Web3TransportNode { + uri: http::Uri, + gui_auth: bool, +} + impl Web3Transport { #[allow(dead_code)] - pub fn new(urls: Vec, gui_auth_validation: Option) -> Result { - let mut uris = vec![]; + pub fn new(urls: Vec, gui_auth: bool) -> Result { + let mut nodes = vec![]; for url in urls.iter() { - uris.push(try_s!(url.parse())); + let uri = try_s!(url.parse()); + nodes.push(Web3TransportNode { uri, gui_auth }); } Ok(Web3Transport { id: Arc::new(AtomicUsize::new(0)), - uris, + nodes, event_handlers: Default::default(), - gui_auth_validation, + gui_auth_validation: None, }) } pub fn with_event_handlers( urls: Vec, event_handlers: Vec, - gui_auth_validation: Option, + gui_auth: bool, ) -> Result { - let mut uris = vec![]; + let mut nodes = vec![]; for url in urls.iter() { - uris.push(try_s!(url.parse())); + let uri = try_s!(url.parse()); + nodes.push(Web3TransportNode { uri, gui_auth }); } Ok(Web3Transport { id: Arc::new(AtomicUsize::new(0)), - uris, + nodes, event_handlers, - gui_auth_validation, + gui_auth_validation: None, }) } } @@ -137,7 +145,7 @@ impl Transport for Web3Transport { Box::new( send_request( request, - self.uris.clone(), + self.nodes.clone(), self.event_handlers.clone(), self.gui_auth_validation.clone(), ) @@ -150,7 +158,7 @@ impl Transport for Web3Transport { fn send(&self, _id: RequestId, request: Call) -> Self::Out { let fut = send_request( request, - self.uris.clone(), + self.nodes.clone(), self.event_handlers.clone(), self.gui_auth_validation.clone(), ); @@ -161,7 +169,7 @@ impl Transport for Web3Transport { #[cfg(not(target_arch = "wasm32"))] async fn send_request( request: Call, - uris: Vec, + nodes: Vec, event_handlers: Vec, gui_auth_validation: Option, ) -> Result { @@ -188,10 +196,10 @@ async fn send_request( event_handlers.on_outgoing_request(serialized_request.as_bytes()); - for uri in uris.iter() { + for node in nodes.iter() { let mut req = http::Request::new(serialized_request.clone().into_bytes()); *req.method_mut() = http::Method::POST; - *req.uri_mut() = uri.clone(); + *req.uri_mut() = node.uri.clone(); req.headers_mut() .insert(http::header::CONTENT_TYPE, HeaderValue::from_static("application/json")); let timeout = Timer::sleep(REQUEST_TIMEOUT_S); @@ -200,7 +208,11 @@ async fn send_request( let res = match rc { Either::Left((r, _t)) => r, Either::Right((_t, _r)) => { - let error = ERRL!("Error requesting '{}': {}s timeout expired", uri, REQUEST_TIMEOUT_S); + let error = ERRL!( + "Error requesting '{}': {}s timeout expired", + node.uri, + REQUEST_TIMEOUT_S + ); warn!("{}", error); errors.push(error); continue; @@ -219,15 +231,15 @@ async fn send_request( if !status.is_success() { errors.push(ERRL!( - "Server '{}' response !200: {}, {}", - uri, + "Server '{:?}' response !200: {}, {}", + node, status, binprint(&body, b'.') )); continue; } - return single_response(body, &uri.to_string()); + return single_response(body, &node.uri.to_string()); } Err(request_failed_error(&request, &errors)) } @@ -235,7 +247,7 @@ async fn send_request( #[cfg(target_arch = "wasm32")] async fn send_request( request: Call, - uris: Vec, + nodes: Vec, event_handlers: Vec, gui_auth_validation: Option, ) -> Result { @@ -250,8 +262,8 @@ async fn send_request( drop_mutability!(serialized_request); let mut transport_errors = Vec::new(); - for uri in uris { - match send_request_once(serialized_request.clone(), &uri, &event_handlers).await { + for node in nodes { + match send_request_once(serialized_request.clone(), &node.uri, &event_handlers).await { Ok(response_json) => return Ok(response_json), Err(Error(ErrorKind::Transport(e), _)) => { transport_errors.push(e.to_string()); From f83f5b3fd9e5e1483f1f666b8a73d6733c5898c3 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Thu, 7 Jul 2022 19:31:27 +0300 Subject: [PATCH 12/69] save development state Signed-off-by: ozkanonur --- mm2src/coins/eth/web3_transport.rs | 51 +++++++++++++++++++----------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index 9063d8b892..1528ea0897 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -184,19 +184,25 @@ async fn send_request( let mut errors = Vec::new(); - let mut serialized_request = to_string(&request); + let serialized_request = to_string(&request); - if let Some(gui_auth_validation) = gui_auth_validation { - let mut json_payload = serde_json::to_value(&serialized_request)?; - json_payload["signed_message"] = json!(gui_auth_validation); - common::drop_mutability!(json_payload); - serialized_request = json_payload.to_string(); - }; - drop_mutability!(serialized_request); + for node in nodes.iter() { + let mut serialized_request = serialized_request.clone(); + if node.gui_auth { + if let Some(gui_auth_validation) = gui_auth_validation.clone() { + let mut json_payload = serde_json::to_value(&serialized_request)?; + json_payload["signed_message"] = json!(gui_auth_validation); + common::drop_mutability!(json_payload); + serialized_request = json_payload.to_string(); + } else { + errors.push(ERRL!("GuiAuthValidation is not provided for {:?} node", node,)); + continue; + } + } + common::drop_mutability!(serialized_request); - event_handlers.on_outgoing_request(serialized_request.as_bytes()); + event_handlers.on_outgoing_request(serialized_request.as_bytes()); - for node in nodes.iter() { let mut req = http::Request::new(serialized_request.clone().into_bytes()); *req.method_mut() = http::Method::POST; *req.uri_mut() = node.uri.clone(); @@ -241,6 +247,7 @@ async fn send_request( return single_response(body, &node.uri.to_string()); } + Err(request_failed_error(&request, &errors)) } @@ -251,18 +258,24 @@ async fn send_request( event_handlers: Vec, gui_auth_validation: Option, ) -> Result { - let mut serialized_request = to_string(&request); - - if let Some(gui_auth_validation) = gui_auth_validation { - let mut json_payload = serde_json::to_value(&serialized_request)?; - json_payload["signed_message"] = json!(gui_auth_validation); - common::drop_mutability!(json_payload); - serialized_request = json_payload.to_string(); - }; - drop_mutability!(serialized_request); + let serialized_request = to_string(&request); let mut transport_errors = Vec::new(); for node in nodes { + let mut serialized_request = serialized_request.clone(); + if node.gui_auth { + if let Some(gui_auth_validation) = gui_auth_validation.clone() { + let mut json_payload = serde_json::to_value(&serialized_request)?; + json_payload["signed_message"] = json!(gui_auth_validation); + common::drop_mutability!(json_payload); + serialized_request = json_payload.to_string(); + } else { + transport_errors.push(ERRL!("GuiAuthValidation is not provided for {:?} node", node,)); + continue; + } + } + common::drop_mutability!(serialized_request); + match send_request_once(serialized_request.clone(), &node.uri, &event_handlers).await { Ok(response_json) => return Ok(response_json), Err(Error(ErrorKind::Transport(e), _)) => { From 6f36e608721e0755941241111a73ffcf0b8370c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Fri, 8 Jul 2022 11:45:31 +0300 Subject: [PATCH 13/69] save development state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- Cargo.lock | 1 + mm2src/coins/eth.rs | 33 ++++++++++---------- mm2src/coins/eth/web3_transport.rs | 49 +++++++++++++++++++++--------- mm2src/mm2_net/Cargo.toml | 1 + mm2src/mm2_net/src/transport.rs | 9 +++--- 5 files changed, 58 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d511494983..8a2a6be407 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4284,6 +4284,7 @@ dependencies = [ "cfg-if 1.0.0", "common", "derive_more", + "ethkey", "futures 0.3.15", "gstuff", "http 0.2.7", diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 7b2ec1fa02..ba935facac 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -37,7 +37,7 @@ use futures01::Future; use http::StatusCode; use mm2_core::mm_ctx::{MmArc, MmWeak}; use mm2_err_handle::prelude::*; -use mm2_net::transport::{slurp_url, GuiAuthValidation, SlurpError}; +use mm2_net::transport::{slurp_url, GuiAuthValidationGenerator, SlurpError}; #[cfg(test)] use mocktopus::macros::*; use rand::seq::SliceRandom; use rpc::v1::types::Bytes as BytesJson; @@ -3207,12 +3207,13 @@ impl TryToAddress for Option { } pub trait GuiAuthMessages { - fn gui_auth_sign_message_hash(&self, message: String) -> Option<[u8; 32]>; - fn generate_gui_auth_signed_validation(&self) -> SignatureResult; + fn gui_auth_sign_message_hash(message: String) -> Option<[u8; 32]>; + fn generate_gui_auth_signed_validation(generator: GuiAuthValidationGenerator) + -> SignatureResult; } impl GuiAuthMessages for EthCoin { - fn gui_auth_sign_message_hash(&self, message: String) -> Option<[u8; 32]> { + fn gui_auth_sign_message_hash(message: String) -> Option<[u8; 32]> { let message_prefix = "atomicDEX Auth Ethereum Signed Message:\n"; let prefix_len = CompactInteger::from(message_prefix.len()); @@ -3225,24 +3226,24 @@ impl GuiAuthMessages for EthCoin { Some(keccak256(&stream.out()).take()) } - fn generate_gui_auth_signed_validation(&self) -> SignatureResult { + fn generate_gui_auth_signed_validation( + generator: GuiAuthValidationGenerator, + ) -> SignatureResult { let timestamp_message = SystemTime::now() .duration_since(UNIX_EPOCH) .map_err(|e| SignatureError::InternalError(e.to_string()))? .as_secs(); - let message_hash = self - .gui_auth_sign_message_hash(timestamp_message.to_string()) - .ok_or(SignatureError::PrefixNotFound)?; - let privkey = &self.key_pair.secret(); - let signature = sign(privkey, &H256::from(message_hash))?; + let message_hash = + EthCoin::gui_auth_sign_message_hash(timestamp_message.to_string()).ok_or(SignatureError::PrefixNotFound)?; + let signature = sign(&generator.secret, &H256::from(message_hash))?; - Ok(GuiAuthValidation { - coin_ticker: self.ticker.clone(), - address: self.my_address.to_string(), - timestamp_message: timestamp_message + 5 * 60, - signature: format!("0x{}", signature), - }) + Ok(json!({ + "coin_ticker": "ETH", + "address": generator.address, + "timestamp_message": timestamp_message + 90, // 90 seconds to expire + "signature": format!("0x{}", signature), + })) } } diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index 1528ea0897..089e251d8b 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -1,9 +1,10 @@ use super::{RpcTransportEventHandler, RpcTransportEventHandlerShared}; +use crate::eth::{EthCoin, GuiAuthMessages}; #[cfg(not(target_arch = "wasm32"))] use futures::FutureExt; use futures::TryFutureExt; use futures01::{Future, Poll}; use jsonrpc_core::{Call, Response}; -use mm2_net::transport::GuiAuthValidation; +use mm2_net::transport::GuiAuthValidationGenerator; use serde_json::Value as Json; #[cfg(not(target_arch = "wasm32"))] use std::ops::Deref; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -73,7 +74,7 @@ pub struct Web3Transport { id: Arc, nodes: Vec, event_handlers: Vec, - pub(crate) gui_auth_validation: Option, + pub(crate) gui_auth_validation_generator: Option, } #[derive(Clone, Debug)] @@ -94,7 +95,7 @@ impl Web3Transport { id: Arc::new(AtomicUsize::new(0)), nodes, event_handlers: Default::default(), - gui_auth_validation: None, + gui_auth_validation_generator: None, }) } @@ -112,7 +113,7 @@ impl Web3Transport { id: Arc::new(AtomicUsize::new(0)), nodes, event_handlers, - gui_auth_validation: None, + gui_auth_validation_generator: None, }) } } @@ -147,7 +148,7 @@ impl Transport for Web3Transport { request, self.nodes.clone(), self.event_handlers.clone(), - self.gui_auth_validation.clone(), + self.gui_auth_validation_generator.clone(), ) .boxed() .compat(), @@ -160,7 +161,7 @@ impl Transport for Web3Transport { request, self.nodes.clone(), self.event_handlers.clone(), - self.gui_auth_validation.clone(), + self.gui_auth_validation_generator.clone(), ); Box::new(SendFuture(Box::pin(fut).compat())) } @@ -171,7 +172,7 @@ async fn send_request( request: Call, nodes: Vec, event_handlers: Vec, - gui_auth_validation: Option, + gui_auth_validation_generator: Option, ) -> Result { use common::executor::Timer; use common::log::warn; @@ -189,13 +190,23 @@ async fn send_request( for node in nodes.iter() { let mut serialized_request = serialized_request.clone(); if node.gui_auth { - if let Some(gui_auth_validation) = gui_auth_validation.clone() { + if let Some(generator) = gui_auth_validation_generator.clone() { let mut json_payload = serde_json::to_value(&serialized_request)?; - json_payload["signed_message"] = json!(gui_auth_validation); + json_payload["signed_message"] = match EthCoin::generate_gui_auth_signed_validation(generator) { + Ok(t) => t, + Err(e) => { + errors.push(ERRL!( + "GuiAuth signed message generation failed for {:?} node, error: {:?}", + node, + e + )); + continue; + }, + }; common::drop_mutability!(json_payload); serialized_request = json_payload.to_string(); } else { - errors.push(ERRL!("GuiAuthValidation is not provided for {:?} node", node,)); + errors.push(ERRL!("GuiAuthValidationGenerator is not provided for {:?} node", node)); continue; } } @@ -256,7 +267,7 @@ async fn send_request( request: Call, nodes: Vec, event_handlers: Vec, - gui_auth_validation: Option, + gui_auth_validation_generator: Option, ) -> Result { let serialized_request = to_string(&request); @@ -264,13 +275,23 @@ async fn send_request( for node in nodes { let mut serialized_request = serialized_request.clone(); if node.gui_auth { - if let Some(gui_auth_validation) = gui_auth_validation.clone() { + if let Some(generator) = gui_auth_validation_generator.clone() { let mut json_payload = serde_json::to_value(&serialized_request)?; - json_payload["signed_message"] = json!(gui_auth_validation); + json_payload["signed_message"] = match EthCoin::generate_gui_auth_signed_validation(generator) { + Ok(t) => t, + Err(e) => { + transport_errors.push(ERRL!( + "GuiAuth signed message generation failed for {:?} node, error: {:?}", + node, + e + )); + continue; + }, + }; common::drop_mutability!(json_payload); serialized_request = json_payload.to_string(); } else { - transport_errors.push(ERRL!("GuiAuthValidation is not provided for {:?} node", node,)); + transport_errors.push(ERRL!("GuiAuthValidationGenerator is not provided for {:?} node", node,)); continue; } } diff --git a/mm2src/mm2_net/Cargo.toml b/mm2src/mm2_net/Cargo.toml index 1c08ae2282..e188bc985d 100644 --- a/mm2src/mm2_net/Cargo.toml +++ b/mm2src/mm2_net/Cargo.toml @@ -12,6 +12,7 @@ serde_json = { version = "1.0", features = ["preserve_order", "raw_value"] } bytes = "1.1" cfg-if = "1.0" common = { path = "../common" } +ethkey = { git = "https://github.com/artemii235/parity-ethereum.git" } mm2_err_handle = { path = "../mm2_err_handle" } mm2_core = { path = "../mm2_core" } derive_more = "0.99" diff --git a/mm2src/mm2_net/src/transport.rs b/mm2src/mm2_net/src/transport.rs index c44f0d2cb9..2321575fda 100644 --- a/mm2src/mm2_net/src/transport.rs +++ b/mm2src/mm2_net/src/transport.rs @@ -1,4 +1,5 @@ use derive_more::Display; +use ethkey::Secret; use http::{HeaderMap, StatusCode}; use mm2_err_handle::prelude::*; use serde::{Deserialize, Serialize}; @@ -50,10 +51,8 @@ where } /// gui-auth specific data-type that needed in order to perform gui-auth calls -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -pub struct GuiAuthValidation { - pub coin_ticker: String, +#[derive(Clone, Debug)] +pub struct GuiAuthValidationGenerator { + pub secret: Secret, pub address: String, - pub timestamp_message: u64, - pub signature: String, } From 469e0931ef903bbd41b0e4e447ce85b9e1c15464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Fri, 8 Jul 2022 11:59:43 +0300 Subject: [PATCH 14/69] save development state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins/eth.rs | 5 ++-- mm2src/coins/eth/eth_tests.rs | 37 ++++++++++++++---------------- mm2src/coins/eth/eth_wasm_tests.rs | 2 +- mm2src/coins/eth/web3_transport.rs | 9 ++++---- 4 files changed, 24 insertions(+), 29 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index ba935facac..973cc8a95a 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -3452,8 +3452,7 @@ pub async fn eth_coin_from_conf_and_request( for url in urls.iter() { let transport = try_s!(Web3Transport::with_event_handlers( vec![url.clone()], - event_handlers.clone(), - false + event_handlers.clone() )); let web3 = Web3::new(transport); let version = match web3.web3().client_version().compat().await { @@ -3473,7 +3472,7 @@ pub async fn eth_coin_from_conf_and_request( return ERR!("Failed to get client version for all urls"); } - let transport = try_s!(Web3Transport::with_event_handlers(urls, event_handlers, false)); + let transport = try_s!(Web3Transport::with_event_handlers(urls, event_handlers)); let web3 = Web3::new(transport); let (coin_type, decimals) = match protocol { diff --git a/mm2src/coins/eth/eth_tests.rs b/mm2src/coins/eth/eth_tests.rs index 7e8482f96a..46070326c8 100644 --- a/mm2src/coins/eth/eth_tests.rs +++ b/mm2src/coins/eth/eth_tests.rs @@ -26,7 +26,7 @@ fn eth_coin_for_test( &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(urls, false).unwrap(); + let transport = Web3Transport::new(urls).unwrap(); let web3 = Web3::new(transport); let conf = json!({ "coins":[ @@ -202,7 +202,7 @@ fn send_and_refund_erc20_payment() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], false).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()]).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -272,7 +272,7 @@ fn send_and_refund_eth_payment() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], false).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()]).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -338,14 +338,13 @@ fn test_nonce_several_urls() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let infura_transport = Web3Transport::new( - vec!["https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into()], - false, - ) + let infura_transport = Web3Transport::new(vec![ + "https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into() + ]) .unwrap(); - let linkpool_transport = Web3Transport::new(vec!["https://ropsten-rpc.linkpool.io".into()], false).unwrap(); + let linkpool_transport = Web3Transport::new(vec!["https://ropsten-rpc.linkpool.io".into()]).unwrap(); // get nonce must succeed if some nodes are down at the moment for some reason - let failing_transport = Web3Transport::new(vec!["http://195.201.0.6:8989".into()], false).unwrap(); + let failing_transport = Web3Transport::new(vec!["http://195.201.0.6:8989".into()]).unwrap(); let web3_infura = Web3::new(infura_transport); let web3_linkpool = Web3::new(linkpool_transport); @@ -407,7 +406,7 @@ fn test_wait_for_payment_spend_timeout() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8555".into()], false).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8555".into()]).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); @@ -465,10 +464,9 @@ fn test_search_for_swap_tx_spend_was_spent() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new( - vec!["https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into()], - false, - ) + let transport = Web3Transport::new(vec![ + "https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into() + ]) .unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); @@ -572,10 +570,9 @@ fn test_search_for_swap_tx_spend_was_refunded() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new( - vec!["https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into()], - false, - ) + let transport = Web3Transport::new(vec![ + "https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into() + ]) .unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); @@ -1266,7 +1263,7 @@ fn test_message_hash() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], false).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()]).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -1307,7 +1304,7 @@ fn test_sign_verify_message() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()], false).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()]).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { diff --git a/mm2src/coins/eth/eth_wasm_tests.rs b/mm2src/coins/eth/eth_wasm_tests.rs index d6e55c13ee..ca1f3f8362 100644 --- a/mm2src/coins/eth/eth_wasm_tests.rs +++ b/mm2src/coins/eth/eth_wasm_tests.rs @@ -20,7 +20,7 @@ async fn test_send() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8565".into()], false).unwrap(); + let transport = Web3Transport::new(vec!["http://195.201.0.6:8565".into()]).unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index 089e251d8b..8269a026ae 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -85,11 +85,11 @@ pub struct Web3TransportNode { impl Web3Transport { #[allow(dead_code)] - pub fn new(urls: Vec, gui_auth: bool) -> Result { + pub fn new(urls: Vec) -> Result { let mut nodes = vec![]; for url in urls.iter() { let uri = try_s!(url.parse()); - nodes.push(Web3TransportNode { uri, gui_auth }); + nodes.push(Web3TransportNode { uri, gui_auth: false }); } Ok(Web3Transport { id: Arc::new(AtomicUsize::new(0)), @@ -102,12 +102,11 @@ impl Web3Transport { pub fn with_event_handlers( urls: Vec, event_handlers: Vec, - gui_auth: bool, ) -> Result { let mut nodes = vec![]; for url in urls.iter() { let uri = try_s!(url.parse()); - nodes.push(Web3TransportNode { uri, gui_auth }); + nodes.push(Web3TransportNode { uri, gui_auth: false }); } Ok(Web3Transport { id: Arc::new(AtomicUsize::new(0)), @@ -291,7 +290,7 @@ async fn send_request( common::drop_mutability!(json_payload); serialized_request = json_payload.to_string(); } else { - transport_errors.push(ERRL!("GuiAuthValidationGenerator is not provided for {:?} node", node,)); + transport_errors.push(ERRL!("GuiAuthValidationGenerator is not provided for {:?} node", node)); continue; } } From e7bada5337c16b24ebc1bcd9f36e28e62874ed1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Fri, 8 Jul 2022 16:23:53 +0300 Subject: [PATCH 15/69] save development state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- .../mm2_main/src/rpc/dispatcher/dispatcher.rs | 2 + .../src/rpc/lp_commands/lp_commands.rs | 39 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs index 042d412f99..0ecd0ca47d 100644 --- a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs +++ b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs @@ -1,3 +1,4 @@ +use super::lp_commands::enable_v2; use super::{DispatcherError, DispatcherResult, PUBLIC_METHODS}; use crate::mm2::lp_native_dex::init_hw::{init_trezor, init_trezor_status, init_trezor_user_action}; use crate::mm2::lp_ordermatch::{best_orders_rpc_v2, orderbook_rpc_v2, start_simple_market_maker_bot, @@ -123,6 +124,7 @@ async fn dispatcher_v2(request: MmRpcRequest, ctx: MmArc) -> DispatcherResult handle_mmrpc(ctx, request, add_delegation).await, "add_node_to_version_stat" => handle_mmrpc(ctx, request, add_node_to_version_stat).await, "best_orders" => handle_mmrpc(ctx, request, best_orders_rpc_v2).await, + "enable" => handle_mmrpc(ctx, request, enable_v2).await, "enable_bch_with_tokens" => handle_mmrpc(ctx, request, enable_platform_coin_with_tokens::).await, "enable_slp" => handle_mmrpc(ctx, request, enable_token::).await, "get_new_address" => handle_mmrpc(ctx, request, get_new_address).await, diff --git a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs index 6cad4b4dee..199b7dd6d0 100644 --- a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs +++ b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs @@ -46,3 +46,42 @@ pub async fn get_public_key_hash(ctx: MmArc, _req: Json) -> GetPublicKeyRpcResul let public_key_hash = ctx.rmd160().to_owned().into(); Ok(GetPublicKeyHashResponse { public_key_hash }) } + +#[derive(Debug, Display, Serialize, SerializeErrorType)] +#[serde(tag = "error_type", content = "error_data")] +pub enum EnableV2RpcError { + CoinIsNotSupported(String), + InternalError(String), +} + +impl HttpStatusCode for EnableV2RpcError { + fn status_code(&self) -> StatusCode { + match self { + EnableV2RpcError::CoinIsNotSupported(_) => StatusCode::NOT_FOUND, + EnableV2RpcError::InternalError(_) => StatusCode::INTERNAL_SERVER_ERROR, + } + } +} + +#[derive(Serialize)] +pub struct EnableV2RpcResponse { + pub test: bool + // result: &'a str, + // address: String, + // balance: BigDecimal, + // unspendable_balance: BigDecimal, + // coin: &'a str, + // required_confirmations: u64, + // requires_notarization: bool, + // #[serde(skip_serializing_if = "Option::is_none")] + // mature_confirmations: Option, +} + +/// v2 of `fn enable(ctx: MmArc, req: Json)`. +pub async fn enable_v2(ctx: MmArc, req: Json) -> MmResult { + println!("request {:?}", req); + let ticker = req["coin"].as_str().ok_or("No 'coin' field").map_err(|e| EnableV2RpcError::CoinIsNotSupported(e.to_string()))?.to_owned(); + println!("ticker {}", ticker); + + Ok(EnableV2RpcResponse { test: true }) +} From 944a3543b8133f73a5ad5e2506fe8d23d0926808 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Sun, 10 Jul 2022 11:58:25 +0300 Subject: [PATCH 16/69] save development state Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 129 ++++++++++++++++++ mm2src/coins/lp_coins.rs | 2 + .../src/rpc/lp_commands/lp_commands.rs | 59 ++++++-- 3 files changed, 177 insertions(+), 13 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 973cc8a95a..530d9ceb38 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -3417,6 +3417,135 @@ fn rpc_event_handlers_for_eth_transport(ctx: &MmArc, ticker: String) -> Vec Arc> { Arc::new(AsyncMutex::new(())) } +pub async fn eth_coin_from_conf_and_request_v2( + ctx: &MmArc, + ticker: &str, + conf: &Json, + req: &Json, + priv_key: &[u8], + protocol: CoinProtocol, +) -> Result { + let mut urls: Vec = try_s!(json::from_value(req["params"]["nodes"].clone())); + if urls.is_empty() { + return ERR!("Enable request for ETH coin must have at least 1 node URL"); + } + let mut rng = small_rng(); + urls.as_mut_slice().shuffle(&mut rng); + + let swap_contract_address: Address = try_s!(json::from_value(req["swap_contract_address"].clone())); + if swap_contract_address == Address::default() { + return ERR!("swap_contract_address can't be zero address"); + } + + let fallback_swap_contract: Option
= try_s!(json::from_value(req["fallback_swap_contract"].clone())); + if let Some(fallback) = fallback_swap_contract { + if fallback == Address::default() { + return ERR!("fallback_swap_contract can't be zero address"); + } + } + + let key_pair: KeyPair = try_s!(KeyPair::from_secret_slice(priv_key)); + let my_address = key_pair.address(); + + let mut web3_instances = vec![]; + let event_handlers = rpc_event_handlers_for_eth_transport(ctx, ticker.to_string()); + for url in urls.iter() { + let transport = try_s!(Web3Transport::with_event_handlers( + vec![url.clone()], + event_handlers.clone() + )); + let web3 = Web3::new(transport); + let version = match web3.web3().client_version().compat().await { + Ok(v) => v, + Err(e) => { + error!("Couldn't get client version for url {}: {}", url, e); + continue; + }, + }; + web3_instances.push(Web3Instance { + web3, + is_parity: version.contains("Parity") || version.contains("parity"), + }) + } + + if web3_instances.is_empty() { + return ERR!("Failed to get client version for all urls"); + } + + let transport = try_s!(Web3Transport::with_event_handlers(urls, event_handlers)); + let web3 = Web3::new(transport); + + let (coin_type, decimals) = match protocol { + CoinProtocol::ETH => (EthCoinType::Eth, 18), + CoinProtocol::ERC20 { + platform, + contract_address, + } => { + let token_addr = try_s!(valid_addr_from_str(&contract_address)); + let decimals = match conf["decimals"].as_u64() { + None | Some(0) => try_s!(get_token_decimals(&web3, token_addr).await), + Some(d) => d as u8, + }; + (EthCoinType::Erc20 { platform, token_addr }, decimals) + }, + _ => return ERR!("Expect ETH or ERC20 protocol"), + }; + + // param from request should override the config + let required_confirmations = req["required_confirmations"] + .as_u64() + .unwrap_or_else(|| conf["required_confirmations"].as_u64().unwrap_or(1)) + .into(); + + if req["requires_notarization"].as_bool().is_some() { + warn!("requires_notarization doesn't take any effect on ETH/ERC20 coins"); + } + + let sign_message_prefix: Option = json::from_value(conf["sign_message_prefix"].clone()).unwrap_or(None); + + let initial_history_state = if req["tx_history"].as_bool().unwrap_or(false) { + HistorySyncState::NotStarted + } else { + HistorySyncState::NotEnabled + }; + + let gas_station_decimals: Option = try_s!(json::from_value(req["gas_station_decimals"].clone())); + let gas_station_policy: GasStationPricePolicy = + json::from_value(req["gas_station_policy"].clone()).unwrap_or_default(); + + let key_lock = match &coin_type { + EthCoinType::Eth => String::from(ticker), + EthCoinType::Erc20 { ref platform, .. } => String::from(platform), + }; + + let mut map = NONCE_LOCK.lock().unwrap(); + + let nonce_lock = map.entry(key_lock).or_insert_with(new_nonce_lock).clone(); + + let coin = EthCoinImpl { + key_pair, + my_address, + coin_type, + sign_message_prefix, + swap_contract_address, + fallback_swap_contract, + decimals, + ticker: ticker.into(), + gas_station_url: try_s!(json::from_value(req["gas_station_url"].clone())), + gas_station_decimals: gas_station_decimals.unwrap_or(ETH_GAS_STATION_DECIMALS), + gas_station_policy, + web3, + web3_instances, + history_sync_state: Mutex::new(initial_history_state), + ctx: ctx.weak(), + required_confirmations, + chain_id: conf["chain_id"].as_u64(), + logs_block_range: conf["logs_block_range"].as_u64().unwrap_or(DEFAULT_LOGS_BLOCK_RANGE), + nonce_lock, + }; + Ok(EthCoin(Arc::new(coin))) +} + pub async fn eth_coin_from_conf_and_request( ctx: &MmArc, ticker: &str, diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index bc308b1f5a..d1dad69cd3 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -2315,6 +2315,8 @@ pub async fn lp_coininit(ctx: &MmArc, ticker: &str, req: &Json) -> Result { + // TODO + // Check if it's v2, if so call v2, continue as usual otherwise. try_s!(eth_coin_from_conf_and_request(ctx, ticker, &coins_en, req, &secret, protocol).await).into() }, CoinProtocol::QRC20 { diff --git a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs index 199b7dd6d0..1812a3cd98 100644 --- a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs +++ b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs @@ -1,6 +1,7 @@ use common::HttpStatusCode; use crypto::{CryptoCtx, CryptoInitError}; use derive_more::Display; +use ethereum_types::Address; use http::StatusCode; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; @@ -63,25 +64,57 @@ impl HttpStatusCode for EnableV2RpcError { } } +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub enum GasStationPricePolicyV2 { + /// Use mean between average and fast values, default and recommended to use on ETH mainnet due to + /// gas price big spikes. + MeanAverageFast, + /// Use average value only. Useful for non-heavily congested networks (Matic, etc.) + Average, +} + +impl Default for GasStationPricePolicyV2 { + fn default() -> Self { GasStationPricePolicyV2::MeanAverageFast } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct EnableV2RpcRequest { + pub coin: String, + pub nodes: Vec, + pub swap_contract_address: Option, + pub fallback_swap_contract: Option
, + pub gas_station_url: Option, + pub gas_station_decimals: Option, + pub gas_station_policy: GasStationPricePolicyV2, + pub mm2: Option, + pub tx_history: bool, + pub required_confirmations: u64, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct EnableV2NodesRpc { + pub url: String, + pub gui_auth: bool, +} + #[derive(Serialize)] pub struct EnableV2RpcResponse { - pub test: bool - // result: &'a str, - // address: String, - // balance: BigDecimal, - // unspendable_balance: BigDecimal, - // coin: &'a str, - // required_confirmations: u64, - // requires_notarization: bool, - // #[serde(skip_serializing_if = "Option::is_none")] - // mature_confirmations: Option, + pub test: bool, // result: &'a str, + // address: String, + // balance: BigDecimal, + // unspendable_balance: BigDecimal, + // coin: &'a str, + // required_confirmations: u64, + // requires_notarization: bool, + // #[serde(skip_serializing_if = "Option::is_none")] + // mature_confirmations: Option } /// v2 of `fn enable(ctx: MmArc, req: Json)`. -pub async fn enable_v2(ctx: MmArc, req: Json) -> MmResult { +pub async fn enable_v2(ctx: MmArc, req: EnableV2RpcRequest) -> MmResult { println!("request {:?}", req); - let ticker = req["coin"].as_str().ok_or("No 'coin' field").map_err(|e| EnableV2RpcError::CoinIsNotSupported(e.to_string()))?.to_owned(); - println!("ticker {}", ticker); + // let coin: MmCoinEnum = lp_coininit(&ctx, &ticker, &req).await.unwrap(); + // println!("coin {:?}", coin); Ok(EnableV2RpcResponse { test: true }) } From 3bdc56ba7a506d6ee7dfdc71b60fedf550cc32fb Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Mon, 11 Jul 2022 18:10:59 +0300 Subject: [PATCH 17/69] finalize `fn enable_v2` implementation Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 114 ++++++++++++------ mm2src/coins/eth/web3_transport.rs | 30 ++++- mm2src/coins/lp_coins.rs | 17 ++- .../src/rpc/lp_commands/lp_commands.rs | 100 ++++++++------- 4 files changed, 166 insertions(+), 95 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 530d9ceb38..4d537dbe73 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -73,7 +73,7 @@ use common::mm_number::MmNumber; use crypto::privkey::key_pair_from_secret; use ethkey::{sign, verify_address}; use serialization::{CompactInteger, Serializable, Stream}; -use web3_transport::{EthFeeHistoryNamespace, Web3Transport}; +use web3_transport::{EthFeeHistoryNamespace, Web3Transport, Web3TransportNode}; #[cfg(test)] mod eth_tests; #[cfg(target_arch = "wasm32")] mod eth_wasm_tests; @@ -327,6 +327,32 @@ pub enum EthAddressFormat { MixedCase, } +#[derive(Clone, Debug, Deserialize)] +pub struct EnableV2RpcRequest { + pub coin: String, + pub nodes: Vec, + pub swap_contract_address: Address, + pub fallback_swap_contract: Option
, + pub gas_station_url: Option, + pub gas_station_decimals: Option, + #[serde(default)] + pub gas_station_policy: GasStationPricePolicy, + pub mm2: Option, + pub tx_history: Option, + pub required_confirmations: Option, +} + +#[derive(Clone, Debug, Deserialize)] +pub struct EnableV2NodesRpc { + pub url: String, + pub gui_auth: bool, +} + +impl EnableV2RpcRequest { + #[inline(always)] + pub fn from_json_payload(payload: Json) -> Self { serde_json::from_value(payload).unwrap() } +} + #[cfg_attr(test, mockable)] async fn make_gas_station_request(url: &str) -> GasStationResult { let resp = slurp_url(url).await?; @@ -3234,6 +3260,7 @@ impl GuiAuthMessages for EthCoin { .map_err(|e| SignatureError::InternalError(e.to_string()))? .as_secs(); + let timestamp_message = timestamp_message + 90; // 90 seconds to expire let message_hash = EthCoin::gui_auth_sign_message_hash(timestamp_message.to_string()).ok_or(SignatureError::PrefixNotFound)?; let signature = sign(&generator.secret, &H256::from(message_hash))?; @@ -3241,7 +3268,7 @@ impl GuiAuthMessages for EthCoin { Ok(json!({ "coin_ticker": "ETH", "address": generator.address, - "timestamp_message": timestamp_message + 90, // 90 seconds to expire + "timestamp_message": timestamp_message, "signature": format!("0x{}", signature), })) } @@ -3335,7 +3362,7 @@ pub struct GasStationData { /// Using tagged representation to allow adding variants with coefficients, percentage, etc in the future. #[derive(Clone, Copy, Debug, Deserialize)] #[serde(tag = "policy", content = "additional_data")] -enum GasStationPricePolicy { +pub enum GasStationPricePolicy { /// Use mean between average and fast values, default and recommended to use on ETH mainnet due to /// gas price big spikes. MeanAverageFast, @@ -3421,44 +3448,60 @@ pub async fn eth_coin_from_conf_and_request_v2( ctx: &MmArc, ticker: &str, conf: &Json, - req: &Json, + req: EnableV2RpcRequest, priv_key: &[u8], protocol: CoinProtocol, ) -> Result { - let mut urls: Vec = try_s!(json::from_value(req["params"]["nodes"].clone())); - if urls.is_empty() { - return ERR!("Enable request for ETH coin must have at least 1 node URL"); + if req.nodes.is_empty() { + return ERR!("Enable request for ETH coin must have at least 1 node"); } + let mut rng = small_rng(); - urls.as_mut_slice().shuffle(&mut rng); + let mut req = req; + req.nodes.as_mut_slice().shuffle(&mut rng); + drop_mutability!(req); + + let mut nodes = vec![]; + for node in req.nodes.iter() { + let uri: http::Uri = try_s!(node.url.parse()); + nodes.push(Web3TransportNode { + uri, + gui_auth: node.gui_auth, + }); + } + drop_mutability!(nodes); - let swap_contract_address: Address = try_s!(json::from_value(req["swap_contract_address"].clone())); - if swap_contract_address == Address::default() { + if req.swap_contract_address == Address::default() { return ERR!("swap_contract_address can't be zero address"); } - let fallback_swap_contract: Option
= try_s!(json::from_value(req["fallback_swap_contract"].clone())); - if let Some(fallback) = fallback_swap_contract { + if let Some(fallback) = req.fallback_swap_contract { if fallback == Address::default() { return ERR!("fallback_swap_contract can't be zero address"); } } let key_pair: KeyPair = try_s!(KeyPair::from_secret_slice(priv_key)); - let my_address = key_pair.address(); + let my_address = checksum_address(&format!("{:02x}", key_pair.address())); let mut web3_instances = vec![]; let event_handlers = rpc_event_handlers_for_eth_transport(ctx, ticker.to_string()); - for url in urls.iter() { - let transport = try_s!(Web3Transport::with_event_handlers( - vec![url.clone()], + for node in &nodes { + let mut transport = try_s!(Web3Transport::with_event_handlers_and_gui_auth( + vec![node.clone()], event_handlers.clone() )); + transport.gui_auth_validation_generator = Some(GuiAuthValidationGenerator { + secret: key_pair.secret().clone(), + address: my_address.clone(), + }); + drop_mutability!(transport); + let web3 = Web3::new(transport); let version = match web3.web3().client_version().compat().await { Ok(v) => v, Err(e) => { - error!("Couldn't get client version for url {}: {}", url, e); + error!("Couldn't get client version for url {}: {}", node.uri, e); continue; }, }; @@ -3472,7 +3515,14 @@ pub async fn eth_coin_from_conf_and_request_v2( return ERR!("Failed to get client version for all urls"); } - let transport = try_s!(Web3Transport::with_event_handlers(urls, event_handlers)); + let mut transport = try_s!(Web3Transport::with_event_handlers_and_gui_auth(nodes, event_handlers)); + transport.gui_auth_validation_generator = Some(GuiAuthValidationGenerator { + secret: key_pair.secret().clone(), + address: my_address, + }); + + drop_mutability!(transport); + let web3 = Web3::new(transport); let (coin_type, decimals) = match protocol { @@ -3492,27 +3542,19 @@ pub async fn eth_coin_from_conf_and_request_v2( }; // param from request should override the config - let required_confirmations = req["required_confirmations"] - .as_u64() + let required_confirmations = req + .required_confirmations .unwrap_or_else(|| conf["required_confirmations"].as_u64().unwrap_or(1)) .into(); - if req["requires_notarization"].as_bool().is_some() { - warn!("requires_notarization doesn't take any effect on ETH/ERC20 coins"); - } - let sign_message_prefix: Option = json::from_value(conf["sign_message_prefix"].clone()).unwrap_or(None); - let initial_history_state = if req["tx_history"].as_bool().unwrap_or(false) { + let initial_history_state = if req.tx_history.unwrap_or(false) { HistorySyncState::NotStarted } else { HistorySyncState::NotEnabled }; - let gas_station_decimals: Option = try_s!(json::from_value(req["gas_station_decimals"].clone())); - let gas_station_policy: GasStationPricePolicy = - json::from_value(req["gas_station_policy"].clone()).unwrap_or_default(); - let key_lock = match &coin_type { EthCoinType::Eth => String::from(ticker), EthCoinType::Erc20 { ref platform, .. } => String::from(platform), @@ -3523,17 +3565,17 @@ pub async fn eth_coin_from_conf_and_request_v2( let nonce_lock = map.entry(key_lock).or_insert_with(new_nonce_lock).clone(); let coin = EthCoinImpl { - key_pair, - my_address, + key_pair: key_pair.clone(), + my_address: key_pair.address(), coin_type, sign_message_prefix, - swap_contract_address, - fallback_swap_contract, + swap_contract_address: req.swap_contract_address, + fallback_swap_contract: req.fallback_swap_contract, decimals, ticker: ticker.into(), - gas_station_url: try_s!(json::from_value(req["gas_station_url"].clone())), - gas_station_decimals: gas_station_decimals.unwrap_or(ETH_GAS_STATION_DECIMALS), - gas_station_policy, + gas_station_url: req.gas_station_url, + gas_station_decimals: req.gas_station_decimals.unwrap_or(ETH_GAS_STATION_DECIMALS), + gas_station_policy: req.gas_station_policy, web3, web3_instances, history_sync_state: Mutex::new(initial_history_state), diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index 8269a026ae..6b2d6f81c7 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -79,8 +79,8 @@ pub struct Web3Transport { #[derive(Clone, Debug)] pub struct Web3TransportNode { - uri: http::Uri, - gui_auth: bool, + pub(crate) uri: http::Uri, + pub(crate) gui_auth: bool, } impl Web3Transport { @@ -115,6 +115,28 @@ impl Web3Transport { gui_auth_validation_generator: None, }) } + + #[allow(dead_code)] + pub fn new_with_gui_auth(nodes: Vec) -> Result { + Ok(Web3Transport { + id: Arc::new(AtomicUsize::new(0)), + nodes, + event_handlers: Default::default(), + gui_auth_validation_generator: None, + }) + } + + pub fn with_event_handlers_and_gui_auth( + nodes: Vec, + event_handlers: Vec, + ) -> Result { + Ok(Web3Transport { + id: Arc::new(AtomicUsize::new(0)), + nodes, + event_handlers, + gui_auth_validation_generator: None, + }) + } } struct SendFuture(T); @@ -190,7 +212,7 @@ async fn send_request( let mut serialized_request = serialized_request.clone(); if node.gui_auth { if let Some(generator) = gui_auth_validation_generator.clone() { - let mut json_payload = serde_json::to_value(&serialized_request)?; + let mut json_payload: Json = serde_json::from_str(&serialized_request)?; json_payload["signed_message"] = match EthCoin::generate_gui_auth_signed_validation(generator) { Ok(t) => t, Err(e) => { @@ -275,7 +297,7 @@ async fn send_request( let mut serialized_request = serialized_request.clone(); if node.gui_auth { if let Some(generator) = gui_auth_validation_generator.clone() { - let mut json_payload = serde_json::to_value(&serialized_request)?; + let mut json_payload: Json = serde_json::from_str(&serialized_request)?; json_payload["signed_message"] = match EthCoin::generate_gui_auth_signed_validation(generator) { Ok(t) => t, Err(e) => { diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index d1dad69cd3..89adc8b079 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -240,7 +240,8 @@ pub use solana::{solana_coin_from_conf_and_params, SolanaActivationParams, Solan pub mod utxo; #[cfg(not(target_arch = "wasm32"))] pub mod z_coin; -use eth::{eth_coin_from_conf_and_request, EthCoin, EthTxFeeDetails, SignedEthTx}; +use eth::{eth_coin_from_conf_and_request, eth_coin_from_conf_and_request_v2, EnableV2RpcRequest, EthCoin, + EthTxFeeDetails, SignedEthTx}; use hd_wallet::{HDAddress, HDAddressId}; use qrc20::Qrc20ActivationParams; use qrc20::{qrc20_coin_from_conf_and_params, Qrc20Coin, Qrc20FeeDetails}; @@ -2315,9 +2316,17 @@ pub async fn lp_coininit(ctx: &MmArc, ticker: &str, req: &Json) -> Result { - // TODO - // Check if it's v2, if so call v2, continue as usual otherwise. - try_s!(eth_coin_from_conf_and_request(ctx, ticker, &coins_en, req, &secret, protocol).await).into() + let call_version = req["_v"].as_u64().unwrap_or(1); + + if call_version == 1 { + return Ok(try_s!( + eth_coin_from_conf_and_request(ctx, ticker, &coins_en, req, &secret, protocol).await + ) + .into()); + } + + let req = EnableV2RpcRequest::from_json_payload(req.clone()); + try_s!(eth_coin_from_conf_and_request_v2(ctx, ticker, &coins_en, req, &secret, protocol).await).into() }, CoinProtocol::QRC20 { platform, diff --git a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs index 1812a3cd98..cba189c509 100644 --- a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs +++ b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs @@ -1,13 +1,15 @@ -use common::HttpStatusCode; +use coins::lp_coininit; +use common::{mm_number::BigDecimal, Future01CompatExt, HttpStatusCode}; use crypto::{CryptoCtx, CryptoInitError}; use derive_more::Display; -use ethereum_types::Address; use http::StatusCode; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use rpc::v1::types::H160 as H160Json; use serde_json::Value as Json; +use crate::mm2::{lp_network::subscribe_to_topic, lp_swap::tx_helper_topic}; + pub type GetPublicKeyRpcResult = Result>; #[derive(Serialize, Display, SerializeErrorType)] @@ -50,71 +52,67 @@ pub async fn get_public_key_hash(ctx: MmArc, _req: Json) -> GetPublicKeyRpcResul #[derive(Debug, Display, Serialize, SerializeErrorType)] #[serde(tag = "error_type", content = "error_data")] +#[allow(dead_code)] pub enum EnableV2RpcError { - CoinIsNotSupported(String), + InvalidPayload(String), + CoinCouldNotInitialized(String), InternalError(String), } impl HttpStatusCode for EnableV2RpcError { fn status_code(&self) -> StatusCode { match self { - EnableV2RpcError::CoinIsNotSupported(_) => StatusCode::NOT_FOUND, - EnableV2RpcError::InternalError(_) => StatusCode::INTERNAL_SERVER_ERROR, + EnableV2RpcError::InvalidPayload(_) => StatusCode::BAD_REQUEST, + _ => StatusCode::INTERNAL_SERVER_ERROR, } } } -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] -pub enum GasStationPricePolicyV2 { - /// Use mean between average and fast values, default and recommended to use on ETH mainnet due to - /// gas price big spikes. - MeanAverageFast, - /// Use average value only. Useful for non-heavily congested networks (Matic, etc.) - Average, +#[derive(Serialize, Clone)] +pub struct EnableV2RpcResponse { + result: String, + address: String, + balance: BigDecimal, + unspendable_balance: BigDecimal, + coin: String, + required_confirmations: u64, + requires_notarization: bool, + #[serde(skip_serializing_if = "Option::is_none")] + mature_confirmations: Option, } -impl Default for GasStationPricePolicyV2 { - fn default() -> Self { GasStationPricePolicyV2::MeanAverageFast } -} +pub async fn enable_v2(ctx: MmArc, req: Json) -> MmResult { + let mut req = req; + req["_v"] = json!(2_u64); + drop_mutability!(req); -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct EnableV2RpcRequest { - pub coin: String, - pub nodes: Vec, - pub swap_contract_address: Option, - pub fallback_swap_contract: Option
, - pub gas_station_url: Option, - pub gas_station_decimals: Option, - pub gas_station_policy: GasStationPricePolicyV2, - pub mm2: Option, - pub tx_history: bool, - pub required_confirmations: u64, -} + let ticker = req["coin"] + .as_str() + .ok_or_else(|| EnableV2RpcError::InvalidPayload(String::from("No 'coin' field")))? + .to_owned(); -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct EnableV2NodesRpc { - pub url: String, - pub gui_auth: bool, -} + let coin = lp_coininit(&ctx, &ticker, &req) + .await + .map_err(EnableV2RpcError::CoinCouldNotInitialized)?; -#[derive(Serialize)] -pub struct EnableV2RpcResponse { - pub test: bool, // result: &'a str, - // address: String, - // balance: BigDecimal, - // unspendable_balance: BigDecimal, - // coin: &'a str, - // required_confirmations: u64, - // requires_notarization: bool, - // #[serde(skip_serializing_if = "Option::is_none")] - // mature_confirmations: Option -} + let balance = coin + .my_balance() + .compat() + .await + .map_err(|e| EnableV2RpcError::CoinCouldNotInitialized(e.to_string()))?; -/// v2 of `fn enable(ctx: MmArc, req: Json)`. -pub async fn enable_v2(ctx: MmArc, req: EnableV2RpcRequest) -> MmResult { - println!("request {:?}", req); - // let coin: MmCoinEnum = lp_coininit(&ctx, &ticker, &req).await.unwrap(); - // println!("coin {:?}", coin); + if coin.is_utxo_in_native_mode() { + subscribe_to_topic(&ctx, tx_helper_topic(coin.ticker())); + } - Ok(EnableV2RpcResponse { test: true }) + Ok(EnableV2RpcResponse { + result: String::from("success"), + address: coin.my_address().map_err(EnableV2RpcError::InternalError)?, + balance: balance.spendable, + unspendable_balance: balance.unspendable, + coin: coin.ticker().to_string(), + required_confirmations: coin.required_confirmations(), + requires_notarization: coin.requires_notarization(), + mature_confirmations: coin.mature_confirmations(), + }) } From 697e7d5ff43b695640f39ee6f8f3a55d802b3030 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Tue, 12 Jul 2022 13:50:51 +0300 Subject: [PATCH 18/69] force UTC tz for gui-auth signed messages Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 8 ++------ mm2src/common/common.rs | 4 ++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 4d537dbe73..4736c1fea7 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -25,7 +25,7 @@ use bigdecimal::BigDecimal; use bitcrypto::{keccak256, sha256}; use common::executor::Timer; use common::log::{error, info, warn}; -use common::{now_ms, small_rng, DEX_FEE_ADDR_RAW_PUBKEY}; +use common::{get_utc_timestamp, now_ms, small_rng, DEX_FEE_ADDR_RAW_PUBKEY}; use derive_more::Display; use ethabi::{Contract, Token}; use ethcore_transaction::{Action, Transaction as UnSignedEthTx, UnverifiedTransaction}; @@ -51,7 +51,6 @@ use std::path::PathBuf; use std::str::FromStr; use std::sync::atomic::{AtomicU64, Ordering as AtomicOrdering}; use std::sync::{Arc, Mutex}; -use std::time::{SystemTime, UNIX_EPOCH}; use web3::types::{Action as TraceAction, BlockId, BlockNumber, Bytes, CallRequest, FilterBuilder, Log, Trace, TraceFilterBuilder, Transaction as Web3Transaction, TransactionId}; use web3::{self, Web3}; @@ -3255,10 +3254,7 @@ impl GuiAuthMessages for EthCoin { fn generate_gui_auth_signed_validation( generator: GuiAuthValidationGenerator, ) -> SignatureResult { - let timestamp_message = SystemTime::now() - .duration_since(UNIX_EPOCH) - .map_err(|e| SignatureError::InternalError(e.to_string()))? - .as_secs(); + let timestamp_message = get_utc_timestamp(); let timestamp_message = timestamp_message + 90; // 90 seconds to expire let message_hash = diff --git a/mm2src/common/common.rs b/mm2src/common/common.rs index cf8eac4dfe..075fd65f35 100644 --- a/mm2src/common/common.rs +++ b/mm2src/common/common.rs @@ -125,6 +125,7 @@ pub mod executor; #[cfg(target_arch = "wasm32")] pub use wasm::*; use backtrace::SymbolName; +use chrono::Utc; pub use futures::compat::Future01CompatExt; use futures::future::{abortable, AbortHandle, FutureExt}; use futures01::{future, Future}; @@ -950,3 +951,6 @@ pub fn spawn_abortable(fut: impl Future03 + Send + 'static) -> Abor spawn(abortable.then(|_| async {})); AbortOnDropHandle(handle) } + +#[inline(always)] +pub fn get_utc_timestamp() -> i64 { Utc::now().timestamp() } From e02b13c4285cee0b0e7ec56bbb9660ce9fed9d2a Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Tue, 12 Jul 2022 15:22:12 +0300 Subject: [PATCH 19/69] optimize `Web3Transport` initialization Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 29 +++++++---- mm2src/coins/eth/eth_tests.rs | 82 +++++++++++++++++++++++------- mm2src/coins/eth/eth_wasm_tests.rs | 6 ++- mm2src/coins/eth/web3_transport.rs | 34 +------------ 4 files changed, 89 insertions(+), 62 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 4736c1fea7..ba985da4ea 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -3459,9 +3459,8 @@ pub async fn eth_coin_from_conf_and_request_v2( let mut nodes = vec![]; for node in req.nodes.iter() { - let uri: http::Uri = try_s!(node.url.parse()); nodes.push(Web3TransportNode { - uri, + uri: try_s!(node.url.parse()), gui_auth: node.gui_auth, }); } @@ -3483,7 +3482,7 @@ pub async fn eth_coin_from_conf_and_request_v2( let mut web3_instances = vec![]; let event_handlers = rpc_event_handlers_for_eth_transport(ctx, ticker.to_string()); for node in &nodes { - let mut transport = try_s!(Web3Transport::with_event_handlers_and_gui_auth( + let mut transport = try_s!(Web3Transport::with_event_handlers( vec![node.clone()], event_handlers.clone() )); @@ -3508,15 +3507,14 @@ pub async fn eth_coin_from_conf_and_request_v2( } if web3_instances.is_empty() { - return ERR!("Failed to get client version for all urls"); + return ERR!("Failed to get client version for all nodes"); } - let mut transport = try_s!(Web3Transport::with_event_handlers_and_gui_auth(nodes, event_handlers)); + let mut transport = try_s!(Web3Transport::with_event_handlers(nodes, event_handlers)); transport.gui_auth_validation_generator = Some(GuiAuthValidationGenerator { secret: key_pair.secret().clone(), address: my_address, }); - drop_mutability!(transport); let web3 = Web3::new(transport); @@ -3557,7 +3555,6 @@ pub async fn eth_coin_from_conf_and_request_v2( }; let mut map = NONCE_LOCK.lock().unwrap(); - let nonce_lock = map.entry(key_lock).or_insert_with(new_nonce_lock).clone(); let coin = EthCoinImpl { @@ -3581,6 +3578,7 @@ pub async fn eth_coin_from_conf_and_request_v2( logs_block_range: conf["logs_block_range"].as_u64().unwrap_or(DEFAULT_LOGS_BLOCK_RANGE), nonce_lock, }; + Ok(EthCoin(Arc::new(coin))) } @@ -3599,6 +3597,15 @@ pub async fn eth_coin_from_conf_and_request( let mut rng = small_rng(); urls.as_mut_slice().shuffle(&mut rng); + let mut nodes = vec![]; + for url in urls.iter() { + nodes.push(Web3TransportNode { + uri: try_s!(url.parse()), + gui_auth: false, + }); + } + drop_mutability!(nodes); + let swap_contract_address: Address = try_s!(json::from_value(req["swap_contract_address"].clone())); if swap_contract_address == Address::default() { return ERR!("swap_contract_address can't be zero address"); @@ -3616,16 +3623,16 @@ pub async fn eth_coin_from_conf_and_request( let mut web3_instances = vec![]; let event_handlers = rpc_event_handlers_for_eth_transport(ctx, ticker.to_string()); - for url in urls.iter() { + for node in nodes.iter() { let transport = try_s!(Web3Transport::with_event_handlers( - vec![url.clone()], + vec![node.clone()], event_handlers.clone() )); let web3 = Web3::new(transport); let version = match web3.web3().client_version().compat().await { Ok(v) => v, Err(e) => { - error!("Couldn't get client version for url {}: {}", url, e); + error!("Couldn't get client version for url {}: {}", node.uri, e); continue; }, }; @@ -3639,7 +3646,7 @@ pub async fn eth_coin_from_conf_and_request( return ERR!("Failed to get client version for all urls"); } - let transport = try_s!(Web3Transport::with_event_handlers(urls, event_handlers)); + let transport = try_s!(Web3Transport::with_event_handlers(nodes, event_handlers)); let web3 = Web3::new(transport); let (coin_type, decimals) = match protocol { diff --git a/mm2src/coins/eth/eth_tests.rs b/mm2src/coins/eth/eth_tests.rs index 46070326c8..fc8bf27328 100644 --- a/mm2src/coins/eth/eth_tests.rs +++ b/mm2src/coins/eth/eth_tests.rs @@ -26,7 +26,17 @@ fn eth_coin_for_test( &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(urls).unwrap(); + + let mut nodes = vec![]; + for url in urls.iter() { + nodes.push(Web3TransportNode { + uri: url.parse().unwrap(), + gui_auth: false, + }); + } + drop_mutability!(nodes); + + let transport = Web3Transport::new(nodes).unwrap(); let web3 = Web3::new(transport); let conf = json!({ "coins":[ @@ -202,7 +212,11 @@ fn send_and_refund_erc20_payment() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()]).unwrap(); + let transport = Web3Transport::new(vec![Web3TransportNode { + uri: "http://195.201.0.6:8545".parse().unwrap(), + gui_auth: false, + }]) + .unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -272,7 +286,11 @@ fn send_and_refund_eth_payment() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()]).unwrap(); + let transport = Web3Transport::new(vec![Web3TransportNode { + uri: "http://195.201.0.6:8545".parse().unwrap(), + gui_auth: false, + }]) + .unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -338,13 +356,24 @@ fn test_nonce_several_urls() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let infura_transport = Web3Transport::new(vec![ - "https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into() - ]) + let infura_transport = Web3Transport::new(vec![Web3TransportNode { + uri: "https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b" + .parse() + .unwrap(), + gui_auth: false, + }]) + .unwrap(); + let linkpool_transport = Web3Transport::new(vec![Web3TransportNode { + uri: "https://ropsten-rpc.linkpool.io".parse().unwrap(), + gui_auth: false, + }]) .unwrap(); - let linkpool_transport = Web3Transport::new(vec!["https://ropsten-rpc.linkpool.io".into()]).unwrap(); // get nonce must succeed if some nodes are down at the moment for some reason - let failing_transport = Web3Transport::new(vec!["http://195.201.0.6:8989".into()]).unwrap(); + let failing_transport = Web3Transport::new(vec![Web3TransportNode { + uri: "http://195.201.0.6:8989".parse().unwrap(), + gui_auth: false, + }]) + .unwrap(); let web3_infura = Web3::new(infura_transport); let web3_linkpool = Web3::new(linkpool_transport); @@ -406,7 +435,11 @@ fn test_wait_for_payment_spend_timeout() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8555".into()]).unwrap(); + let transport = Web3Transport::new(vec![Web3TransportNode { + uri: "http://194.201.0.6:8555".parse().unwrap(), + gui_auth: false, + }]) + .unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); @@ -464,9 +497,12 @@ fn test_search_for_swap_tx_spend_was_spent() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec![ - "https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into() - ]) + let transport = Web3Transport::new(vec![Web3TransportNode { + uri: "https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b" + .parse() + .unwrap(), + gui_auth: false, + }]) .unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); @@ -570,9 +606,12 @@ fn test_search_for_swap_tx_spend_was_refunded() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec![ - "https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b".into() - ]) + let transport = Web3Transport::new(vec![Web3TransportNode { + uri: "https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b" + .parse() + .unwrap(), + gui_auth: false, + }]) .unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); @@ -1263,7 +1302,11 @@ fn test_message_hash() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()]).unwrap(); + let transport = Web3Transport::new(vec![Web3TransportNode { + uri: "http://195.201.0.6:8545".parse().unwrap(), + gui_auth: false, + }]) + .unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -1304,7 +1347,12 @@ fn test_sign_verify_message() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8545".into()]).unwrap(); + let transport = Web3Transport::new(vec![Web3TransportNode { + uri: "http://195.201.0.6:8545".parse().unwrap(), + gui_auth: false, + }]) + .unwrap(); + let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { diff --git a/mm2src/coins/eth/eth_wasm_tests.rs b/mm2src/coins/eth/eth_wasm_tests.rs index ca1f3f8362..5d3391eb7c 100644 --- a/mm2src/coins/eth/eth_wasm_tests.rs +++ b/mm2src/coins/eth/eth_wasm_tests.rs @@ -20,7 +20,11 @@ async fn test_send() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec!["http://195.201.0.6:8565".into()]).unwrap(); + let transport = Web3Transport::new(vec![Web3TransportNode { + uri: "http://195.201.0.6:8565".parse().unwrap(), + gui_auth: false, + }]) + .unwrap(); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index 6b2d6f81c7..575f4b9a9f 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -85,12 +85,7 @@ pub struct Web3TransportNode { impl Web3Transport { #[allow(dead_code)] - pub fn new(urls: Vec) -> Result { - let mut nodes = vec![]; - for url in urls.iter() { - let uri = try_s!(url.parse()); - nodes.push(Web3TransportNode { uri, gui_auth: false }); - } + pub fn new(nodes: Vec) -> Result { Ok(Web3Transport { id: Arc::new(AtomicUsize::new(0)), nodes, @@ -100,33 +95,6 @@ impl Web3Transport { } pub fn with_event_handlers( - urls: Vec, - event_handlers: Vec, - ) -> Result { - let mut nodes = vec![]; - for url in urls.iter() { - let uri = try_s!(url.parse()); - nodes.push(Web3TransportNode { uri, gui_auth: false }); - } - Ok(Web3Transport { - id: Arc::new(AtomicUsize::new(0)), - nodes, - event_handlers, - gui_auth_validation_generator: None, - }) - } - - #[allow(dead_code)] - pub fn new_with_gui_auth(nodes: Vec) -> Result { - Ok(Web3Transport { - id: Arc::new(AtomicUsize::new(0)), - nodes, - event_handlers: Default::default(), - gui_auth_validation_generator: None, - }) - } - - pub fn with_event_handlers_and_gui_auth( nodes: Vec, event_handlers: Vec, ) -> Result { From 2a5e08447a574121cea9df3ea47fa0e307016e5b Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Tue, 12 Jul 2022 16:01:52 +0300 Subject: [PATCH 20/69] save development state Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 4 +--- mm2src/coins/eth/web3_transport.rs | 3 +-- mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs | 3 +-- mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs | 3 +-- 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 59706b9f37..140034553d 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -57,9 +57,7 @@ use std::sync::{Arc, Mutex}; use web3::types::{Action as TraceAction, BlockId, BlockNumber, Bytes, CallRequest, FilterBuilder, Log, Trace, TraceFilterBuilder, Transaction as Web3Transaction, TransactionId}; use web3::{self, Web3}; -use web3_transport::{EthFeeHistoryNamespace, Web3Transport}; - -use crate::eth::web3_transport::Web3TransportNode; +use web3_transport::{EthFeeHistoryNamespace, Web3Transport, Web3TransportNode}; use super::{AsyncMutex, BalanceError, BalanceFut, CoinBalance, CoinProtocol, CoinTransportMetrics, CoinsContext, FeeApproxStage, FoundSwapTxSpend, HistorySyncState, MarketCoinOps, MmCoin, NegotiateSwapContractAddrErr, diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index 575f4b9a9f..893c46d0a9 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -1,5 +1,4 @@ -use super::{RpcTransportEventHandler, RpcTransportEventHandlerShared}; -use crate::eth::{EthCoin, GuiAuthMessages}; +use super::{EthCoin, GuiAuthMessages, RpcTransportEventHandler, RpcTransportEventHandlerShared}; #[cfg(not(target_arch = "wasm32"))] use futures::FutureExt; use futures::TryFutureExt; use futures01::{Future, Poll}; diff --git a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs index 0ecd0ca47d..bb735de2ec 100644 --- a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs +++ b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs @@ -1,5 +1,4 @@ -use super::lp_commands::enable_v2; -use super::{DispatcherError, DispatcherResult, PUBLIC_METHODS}; +use super::{lp_commands::enable_v2, DispatcherError, DispatcherResult, PUBLIC_METHODS}; use crate::mm2::lp_native_dex::init_hw::{init_trezor, init_trezor_status, init_trezor_user_action}; use crate::mm2::lp_ordermatch::{best_orders_rpc_v2, orderbook_rpc_v2, start_simple_market_maker_bot, stop_simple_market_maker_bot}; diff --git a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs index e04b8ddee7..4a09cb4e25 100644 --- a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs +++ b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs @@ -1,3 +1,4 @@ +use crate::mm2::{lp_network::subscribe_to_topic, lp_swap::tx_helper_topic}; use coins::lp_coininit; use common::{Future01CompatExt, HttpStatusCode}; use crypto::{CryptoCtx, CryptoInitError}; @@ -9,8 +10,6 @@ use mm2_number::BigDecimal; use rpc::v1::types::H160 as H160Json; use serde_json::Value as Json; -use crate::mm2::{lp_network::subscribe_to_topic, lp_swap::tx_helper_topic}; - pub type GetPublicKeyRpcResult = Result>; #[derive(Serialize, Display, SerializeErrorType)] From 423ca6eecbffa22e1ac15f58a1de0f41ca27978d Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Tue, 12 Jul 2022 16:08:50 +0300 Subject: [PATCH 21/69] inline `Web3Transport` initialization functions Signed-off-by: ozkanonur --- mm2src/coins/eth/eth_tests.rs | 2 +- mm2src/coins/eth/web3_transport.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mm2src/coins/eth/eth_tests.rs b/mm2src/coins/eth/eth_tests.rs index fc8bf27328..74f073bd4d 100644 --- a/mm2src/coins/eth/eth_tests.rs +++ b/mm2src/coins/eth/eth_tests.rs @@ -436,7 +436,7 @@ fn test_wait_for_payment_spend_timeout() { ) .unwrap(); let transport = Web3Transport::new(vec![Web3TransportNode { - uri: "http://194.201.0.6:8555".parse().unwrap(), + uri: "http://195.201.0.6:8555".parse().unwrap(), gui_auth: false, }]) .unwrap(); diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index 893c46d0a9..3d630a31bc 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -84,6 +84,7 @@ pub struct Web3TransportNode { impl Web3Transport { #[allow(dead_code)] + #[inline] pub fn new(nodes: Vec) -> Result { Ok(Web3Transport { id: Arc::new(AtomicUsize::new(0)), @@ -93,6 +94,7 @@ impl Web3Transport { }) } + #[inline] pub fn with_event_handlers( nodes: Vec, event_handlers: Vec, From 0466601ff38f55e6e5f4b91cc7c9f786a6ff2b32 Mon Sep 17 00:00:00 2001 From: Onur Date: Tue, 12 Jul 2022 16:25:44 +0300 Subject: [PATCH 22/69] Update Cargo.toml --- mm2src/mm2_rpc/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/mm2src/mm2_rpc/Cargo.toml b/mm2src/mm2_rpc/Cargo.toml index 3053aed302..7abf19ab99 100644 --- a/mm2src/mm2_rpc/Cargo.toml +++ b/mm2src/mm2_rpc/Cargo.toml @@ -11,7 +11,6 @@ mm2_err_handle = { path = "../mm2_err_handle" } derive_more = "0.99" futures = { version = "0.3", package = "futures", features = ["compat", "async-await", "thread-pool"] } http = "0.2" -mm2_number = { path = "../mm2_number" } serde = "1" serde_json = { version = "1.0", features = ["preserve_order", "raw_value"] } ser_error = { path = "../derives/ser_error" } From 4c6453f5beaeea5693cc9ffc6c5e81870e7fc390 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Tue, 12 Jul 2022 22:35:57 +0300 Subject: [PATCH 23/69] update version handling of eth coins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins/lp_coins.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 4b6cfb4abe..8662f15640 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -2316,18 +2316,12 @@ pub async fn lp_coininit(ctx: &MmArc, ticker: &str, req: &Json) -> Result { - let call_version = req["_v"].as_u64().unwrap_or(1); - - if call_version == 1 { - return Ok(try_s!( - eth_coin_from_conf_and_request(ctx, ticker, &coins_en, req, &secret, protocol).await - ) - .into()); - } - - let req = EnableV2RpcRequest::from_json_payload(req.clone()); - try_s!(eth_coin_from_conf_and_request_v2(ctx, ticker, &coins_en, req, &secret, protocol).await).into() + CoinProtocol::ETH | CoinProtocol::ERC20 { .. } => match req["_v"].as_u64() { + Some(2) => { + let req = EnableV2RpcRequest::from_json_payload(req.clone()); + try_s!(eth_coin_from_conf_and_request_v2(ctx, ticker, &coins_en, req, &secret, protocol).await).into() + }, + _ => try_s!(eth_coin_from_conf_and_request(ctx, ticker, &coins_en, req, &secret, protocol).await).into(), }, CoinProtocol::QRC20 { platform, From 74ce30139e0c02af42401bcb7755802c0c2e1c63 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 13 Jul 2022 13:53:51 +0300 Subject: [PATCH 24/69] provide better error handling Signed-off-by: ozkanonur --- Cargo.lock | 1 - mm2src/coins/eth.rs | 45 +++------- mm2src/coins/lp_coins.rs | 10 +-- mm2src/coins/rpc_command/enable_v2.rs | 87 +++++++++++++++++++ mm2src/coins/rpc_command/mod.rs | 1 + .../mm2_main/src/rpc/dispatcher/dispatcher.rs | 4 +- .../src/rpc/lp_commands/lp_commands.rs | 49 +---------- 7 files changed, 108 insertions(+), 89 deletions(-) create mode 100644 mm2src/coins/rpc_command/enable_v2.rs diff --git a/Cargo.lock b/Cargo.lock index 4829270f2a..8f2bd13deb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4321,7 +4321,6 @@ dependencies = [ "gstuff", "http 0.2.7", "mm2_err_handle", - "mm2_number", "ser_error", "ser_error_derive", "serde", diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 140034553d..f6fef4366f 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -59,15 +59,16 @@ use web3::types::{Action as TraceAction, BlockId, BlockNumber, Bytes, CallReques use web3::{self, Web3}; use web3_transport::{EthFeeHistoryNamespace, Web3Transport, Web3TransportNode}; -use super::{AsyncMutex, BalanceError, BalanceFut, CoinBalance, CoinProtocol, CoinTransportMetrics, CoinsContext, - FeeApproxStage, FoundSwapTxSpend, HistorySyncState, MarketCoinOps, MmCoin, NegotiateSwapContractAddrErr, - NumConversError, NumConversResult, RawTransactionError, RawTransactionFut, RawTransactionRequest, - RawTransactionRes, RawTransactionResult, RpcClientType, RpcTransportEventHandler, - RpcTransportEventHandlerShared, SearchForSwapTxSpendInput, SignatureError, SignatureResult, SwapOps, - TradeFee, TradePreimageError, TradePreimageFut, TradePreimageResult, TradePreimageValue, Transaction, - TransactionDetails, TransactionEnum, TransactionErr, TransactionFut, UnexpectedDerivationMethod, - ValidateAddressResult, ValidatePaymentInput, VerificationError, VerificationResult, WithdrawError, - WithdrawFee, WithdrawFut, WithdrawRequest, WithdrawResult}; +use super::{rpc_command::enable_v2::EnableV2RpcRequest, AsyncMutex, BalanceError, BalanceFut, CoinBalance, + CoinProtocol, CoinTransportMetrics, CoinsContext, FeeApproxStage, FoundSwapTxSpend, HistorySyncState, + MarketCoinOps, MmCoin, NegotiateSwapContractAddrErr, NumConversError, NumConversResult, + RawTransactionError, RawTransactionFut, RawTransactionRequest, RawTransactionRes, RawTransactionResult, + RpcClientType, RpcTransportEventHandler, RpcTransportEventHandlerShared, SearchForSwapTxSpendInput, + SignatureError, SignatureResult, SwapOps, TradeFee, TradePreimageError, TradePreimageFut, + TradePreimageResult, TradePreimageValue, Transaction, TransactionDetails, TransactionEnum, TransactionErr, + TransactionFut, UnexpectedDerivationMethod, ValidateAddressResult, ValidatePaymentInput, + VerificationError, VerificationResult, WithdrawError, WithdrawFee, WithdrawFut, WithdrawRequest, + WithdrawResult}; pub use rlp; @@ -324,32 +325,6 @@ pub enum EthAddressFormat { MixedCase, } -#[derive(Clone, Debug, Deserialize)] -pub struct EnableV2RpcRequest { - pub coin: String, - pub nodes: Vec, - pub swap_contract_address: Address, - pub fallback_swap_contract: Option
, - pub gas_station_url: Option, - pub gas_station_decimals: Option, - #[serde(default)] - pub gas_station_policy: GasStationPricePolicy, - pub mm2: Option, - pub tx_history: Option, - pub required_confirmations: Option, -} - -#[derive(Clone, Debug, Deserialize)] -pub struct EnableV2NodesRpc { - pub url: String, - pub gui_auth: bool, -} - -impl EnableV2RpcRequest { - #[inline(always)] - pub fn from_json_payload(payload: Json) -> Self { serde_json::from_value(payload).unwrap() } -} - #[cfg_attr(test, mockable)] async fn make_gas_station_request(url: &str) -> GasStationResult { let resp = slurp_url(url).await?; diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 8662f15640..42b2418d64 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -241,15 +241,15 @@ pub use solana::{solana_coin_from_conf_and_params, SolanaActivationParams, Solan pub mod utxo; #[cfg(not(target_arch = "wasm32"))] pub mod z_coin; -use eth::{eth_coin_from_conf_and_request, eth_coin_from_conf_and_request_v2, EnableV2RpcRequest, EthCoin, - EthTxFeeDetails, SignedEthTx}; +use eth::{eth_coin_from_conf_and_request, eth_coin_from_conf_and_request_v2, EthCoin, EthTxFeeDetails, SignedEthTx}; use hd_wallet::{HDAddress, HDAddressId}; use qrc20::Qrc20ActivationParams; use qrc20::{qrc20_coin_from_conf_and_params, Qrc20Coin, Qrc20FeeDetails}; use qtum::{Qrc20AddressError, ScriptHashTypeNotSupported}; -use rpc_command::init_create_account::{CreateAccountTaskManager, CreateAccountTaskManagerShared}; -use rpc_command::init_scan_for_new_addresses::{ScanAddressesTaskManager, ScanAddressesTaskManagerShared}; -use rpc_command::init_withdraw::{WithdrawTaskManager, WithdrawTaskManagerShared}; +use rpc_command::{enable_v2::EnableV2RpcRequest, + init_create_account::{CreateAccountTaskManager, CreateAccountTaskManagerShared}, + init_scan_for_new_addresses::{ScanAddressesTaskManager, ScanAddressesTaskManagerShared}, + init_withdraw::{WithdrawTaskManager, WithdrawTaskManagerShared}}; use utxo::bch::{bch_coin_from_conf_and_params, BchActivationRequest, BchCoin}; use utxo::qtum::{self, qtum_coin_with_priv_key, QtumCoin}; use utxo::qtum::{QtumDelegationOps, QtumDelegationRequest, QtumStakingInfosDetails}; diff --git a/mm2src/coins/rpc_command/enable_v2.rs b/mm2src/coins/rpc_command/enable_v2.rs new file mode 100644 index 0000000000..50ce500462 --- /dev/null +++ b/mm2src/coins/rpc_command/enable_v2.rs @@ -0,0 +1,87 @@ +use crate::{eth::GasStationPricePolicy, lp_coininit, MmCoinEnum}; +use common::{HttpStatusCode, StatusCode}; +use derive_more::Display; +use ethereum_types::Address; +use mm2_core::mm_ctx::MmArc; +use mm2_err_handle::prelude::MmResult; +use mm2_number::BigDecimal; +use serde_json::Value as Json; + +#[derive(Debug, Display, Serialize, SerializeErrorType)] +#[serde(tag = "error_type", content = "error_data")] +#[allow(dead_code)] +pub enum EnableV2RpcError { + InvalidPayload(String), + CoinCouldNotInitialized(String), + CouldNotFetchBalance(String), + InternalError(String), +} + +impl HttpStatusCode for EnableV2RpcError { + fn status_code(&self) -> StatusCode { + match self { + EnableV2RpcError::InvalidPayload(_) => StatusCode::BAD_REQUEST, + EnableV2RpcError::CoinCouldNotInitialized(_) => StatusCode::BAD_REQUEST, + EnableV2RpcError::CouldNotFetchBalance(_) => StatusCode::SERVICE_UNAVAILABLE, + _ => StatusCode::INTERNAL_SERVER_ERROR, + } + } +} + +#[derive(Clone, Debug, Deserialize)] +pub struct EnableV2RpcRequest { + pub coin: String, + pub nodes: Vec, + pub swap_contract_address: Address, + pub fallback_swap_contract: Option
, + pub gas_station_url: Option, + pub gas_station_decimals: Option, + #[serde(default)] + pub gas_station_policy: GasStationPricePolicy, + pub mm2: Option, + pub tx_history: Option, + pub required_confirmations: Option, +} + +#[derive(Clone, Debug, Deserialize)] +pub struct EnableV2NodesRpc { + pub url: String, + pub gui_auth: bool, +} + +impl EnableV2RpcRequest { + #[inline(always)] + pub fn from_json_payload(payload: Json) -> Self { + serde_json::from_value(payload) + .map_err(|e| EnableV2RpcError::InvalidPayload(e.to_string())) + .unwrap() + } +} + +#[derive(Serialize, Clone)] +pub struct EnableV2RpcResponse { + pub result: String, + pub address: String, + pub balance: BigDecimal, + pub unspendable_balance: BigDecimal, + pub coin: String, + pub required_confirmations: u64, + pub requires_notarization: bool, + #[serde(skip_serializing_if = "Option::is_none")] + pub mature_confirmations: Option, +} + +pub async fn enable_v2(ctx: &MmArc, req: Json) -> MmResult { + let mut req = req; + req["_v"] = json!(2_u64); + drop_mutability!(req); + + let ticker = req["coin"] + .as_str() + .ok_or_else(|| EnableV2RpcError::InvalidPayload(String::from("No 'coin' field")))? + .to_owned(); + + Ok(lp_coininit(ctx, &ticker, &req) + .await + .map_err(EnableV2RpcError::CoinCouldNotInitialized)?) +} diff --git a/mm2src/coins/rpc_command/mod.rs b/mm2src/coins/rpc_command/mod.rs index 7a98d3fc2e..7ed0aa5cd9 100644 --- a/mm2src/coins/rpc_command/mod.rs +++ b/mm2src/coins/rpc_command/mod.rs @@ -1,4 +1,5 @@ pub mod account_balance; +pub mod enable_v2; pub mod hd_account_balance_rpc_error; pub mod init_create_account; pub mod init_scan_for_new_addresses; diff --git a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs index bb735de2ec..ab8606c988 100644 --- a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs +++ b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs @@ -1,4 +1,4 @@ -use super::{lp_commands::enable_v2, DispatcherError, DispatcherResult, PUBLIC_METHODS}; +use super::{lp_commands::enable_v2_wrapper, DispatcherError, DispatcherResult, PUBLIC_METHODS}; use crate::mm2::lp_native_dex::init_hw::{init_trezor, init_trezor_status, init_trezor_user_action}; use crate::mm2::lp_ordermatch::{best_orders_rpc_v2, orderbook_rpc_v2, start_simple_market_maker_bot, stop_simple_market_maker_bot}; @@ -123,7 +123,7 @@ async fn dispatcher_v2(request: MmRpcRequest, ctx: MmArc) -> DispatcherResult handle_mmrpc(ctx, request, add_delegation).await, "add_node_to_version_stat" => handle_mmrpc(ctx, request, add_node_to_version_stat).await, "best_orders" => handle_mmrpc(ctx, request, best_orders_rpc_v2).await, - "enable" => handle_mmrpc(ctx, request, enable_v2).await, + "enable" => handle_mmrpc(ctx, request, enable_v2_wrapper).await, "enable_bch_with_tokens" => handle_mmrpc(ctx, request, enable_platform_coin_with_tokens::).await, "enable_slp" => handle_mmrpc(ctx, request, enable_token::).await, "get_new_address" => handle_mmrpc(ctx, request, get_new_address).await, diff --git a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs index 4a09cb4e25..b0d3d778a9 100644 --- a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs +++ b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs @@ -1,12 +1,11 @@ use crate::mm2::{lp_network::subscribe_to_topic, lp_swap::tx_helper_topic}; -use coins::lp_coininit; +use coins::rpc_command::enable_v2::{enable_v2, EnableV2RpcError, EnableV2RpcResponse}; use common::{Future01CompatExt, HttpStatusCode}; use crypto::{CryptoCtx, CryptoInitError}; use derive_more::Display; use http::StatusCode; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; -use mm2_number::BigDecimal; use rpc::v1::types::H160 as H160Json; use serde_json::Value as Json; @@ -50,50 +49,8 @@ pub async fn get_public_key_hash(ctx: MmArc, _req: Json) -> GetPublicKeyRpcResul Ok(GetPublicKeyHashResponse { public_key_hash }) } -#[derive(Debug, Display, Serialize, SerializeErrorType)] -#[serde(tag = "error_type", content = "error_data")] -#[allow(dead_code)] -pub enum EnableV2RpcError { - InvalidPayload(String), - CoinCouldNotInitialized(String), - InternalError(String), -} - -impl HttpStatusCode for EnableV2RpcError { - fn status_code(&self) -> StatusCode { - match self { - EnableV2RpcError::InvalidPayload(_) => StatusCode::BAD_REQUEST, - _ => StatusCode::INTERNAL_SERVER_ERROR, - } - } -} - -#[derive(Serialize, Clone)] -pub struct EnableV2RpcResponse { - result: String, - address: String, - balance: BigDecimal, - unspendable_balance: BigDecimal, - coin: String, - required_confirmations: u64, - requires_notarization: bool, - #[serde(skip_serializing_if = "Option::is_none")] - mature_confirmations: Option, -} - -pub async fn enable_v2(ctx: MmArc, req: Json) -> MmResult { - let mut req = req; - req["_v"] = json!(2_u64); - drop_mutability!(req); - - let ticker = req["coin"] - .as_str() - .ok_or_else(|| EnableV2RpcError::InvalidPayload(String::from("No 'coin' field")))? - .to_owned(); - - let coin = lp_coininit(&ctx, &ticker, &req) - .await - .map_err(EnableV2RpcError::CoinCouldNotInitialized)?; +pub async fn enable_v2_wrapper(ctx: MmArc, req: Json) -> MmResult { + let coin = enable_v2(&ctx, req).await?; let balance = coin .my_balance() From a75014a1bab0ab7a8acbc4eb9364f99cc0dc6e72 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 13 Jul 2022 13:55:42 +0300 Subject: [PATCH 25/69] simplify `generate_gui_auth_signed_validation` Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index f6fef4366f..fdc5066339 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -3210,9 +3210,8 @@ impl GuiAuthMessages for EthCoin { fn generate_gui_auth_signed_validation( generator: GuiAuthValidationGenerator, ) -> SignatureResult { - let timestamp_message = get_utc_timestamp(); + let timestamp_message = get_utc_timestamp() + 90; // 90 seconds to expire - let timestamp_message = timestamp_message + 90; // 90 seconds to expire let message_hash = EthCoin::gui_auth_sign_message_hash(timestamp_message.to_string()).ok_or(SignatureError::PrefixNotFound)?; let signature = sign(&generator.secret, &H256::from(message_hash))?; From ad5a67d98abaff2bc430b0cf41c0f1d4fd4176f4 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Fri, 15 Jul 2022 17:34:27 +0300 Subject: [PATCH 26/69] save development state Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 89 +++++++++++-------- mm2src/coins/eth/eth_tests.rs | 32 +++---- mm2src/coins/eth/eth_wasm_tests.rs | 3 +- mm2src/coins/eth/web3_transport.rs | 16 ++-- mm2src/coins/lp_coins.rs | 13 +-- .../{enable_v2.rs => activate_eth_coin.rs} | 56 +++++++----- mm2src/coins/rpc_command/mod.rs | 2 +- .../src/eth_with_token_activation.rs | 1 + mm2src/coins_activation/src/lib.rs | 1 + .../mm2_main/src/rpc/dispatcher/dispatcher.rs | 4 +- .../src/rpc/lp_commands/lp_commands.rs | 12 ++- mm2src/mm2_net/src/transport.rs | 10 ++- 12 files changed, 129 insertions(+), 110 deletions(-) rename mm2src/coins/rpc_command/{enable_v2.rs => activate_eth_coin.rs} (54%) create mode 100644 mm2src/coins_activation/src/eth_with_token_activation.rs diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index fdc5066339..86b0a96424 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -39,7 +39,7 @@ use futures01::Future; use http::StatusCode; use mm2_core::mm_ctx::{MmArc, MmWeak}; use mm2_err_handle::prelude::*; -use mm2_net::transport::{slurp_url, GuiAuthValidationGenerator, SlurpError}; +use mm2_net::transport::{slurp_url, GuiAuthValidation, GuiAuthValidationGenerator, SlurpError}; use mm2_number::{BigDecimal, MmNumber}; #[cfg(test)] use mocktopus::macros::*; use rand::seq::SliceRandom; @@ -59,16 +59,16 @@ use web3::types::{Action as TraceAction, BlockId, BlockNumber, Bytes, CallReques use web3::{self, Web3}; use web3_transport::{EthFeeHistoryNamespace, Web3Transport, Web3TransportNode}; -use super::{rpc_command::enable_v2::EnableV2RpcRequest, AsyncMutex, BalanceError, BalanceFut, CoinBalance, - CoinProtocol, CoinTransportMetrics, CoinsContext, FeeApproxStage, FoundSwapTxSpend, HistorySyncState, - MarketCoinOps, MmCoin, NegotiateSwapContractAddrErr, NumConversError, NumConversResult, - RawTransactionError, RawTransactionFut, RawTransactionRequest, RawTransactionRes, RawTransactionResult, - RpcClientType, RpcTransportEventHandler, RpcTransportEventHandlerShared, SearchForSwapTxSpendInput, - SignatureError, SignatureResult, SwapOps, TradeFee, TradePreimageError, TradePreimageFut, - TradePreimageResult, TradePreimageValue, Transaction, TransactionDetails, TransactionEnum, TransactionErr, - TransactionFut, UnexpectedDerivationMethod, ValidateAddressResult, ValidatePaymentInput, - VerificationError, VerificationResult, WithdrawError, WithdrawFee, WithdrawFut, WithdrawRequest, - WithdrawResult}; +use super::{rpc_command::activate_eth_coin::{EnableV2RpcError, EnableV2RpcRequest}, + AsyncMutex, BalanceError, BalanceFut, CoinBalance, CoinProtocol, CoinTransportMetrics, CoinsContext, + FeeApproxStage, FoundSwapTxSpend, HistorySyncState, MarketCoinOps, MmCoin, NegotiateSwapContractAddrErr, + NumConversError, NumConversResult, RawTransactionError, RawTransactionFut, RawTransactionRequest, + RawTransactionRes, RawTransactionResult, RpcClientType, RpcTransportEventHandler, + RpcTransportEventHandlerShared, SearchForSwapTxSpendInput, SignatureError, SignatureResult, SwapOps, + TradeFee, TradePreimageError, TradePreimageFut, TradePreimageResult, TradePreimageValue, Transaction, + TransactionDetails, TransactionEnum, TransactionErr, TransactionFut, UnexpectedDerivationMethod, + ValidateAddressResult, ValidatePaymentInput, VerificationError, VerificationResult, WithdrawError, + WithdrawFee, WithdrawFut, WithdrawRequest, WithdrawResult}; pub use rlp; @@ -3190,7 +3190,7 @@ impl TryToAddress for Option { pub trait GuiAuthMessages { fn gui_auth_sign_message_hash(message: String) -> Option<[u8; 32]>; fn generate_gui_auth_signed_validation(generator: GuiAuthValidationGenerator) - -> SignatureResult; + -> SignatureResult; } impl GuiAuthMessages for EthCoin { @@ -3209,19 +3209,19 @@ impl GuiAuthMessages for EthCoin { fn generate_gui_auth_signed_validation( generator: GuiAuthValidationGenerator, - ) -> SignatureResult { + ) -> SignatureResult { let timestamp_message = get_utc_timestamp() + 90; // 90 seconds to expire let message_hash = EthCoin::gui_auth_sign_message_hash(timestamp_message.to_string()).ok_or(SignatureError::PrefixNotFound)?; let signature = sign(&generator.secret, &H256::from(message_hash))?; - Ok(json!({ - "coin_ticker": "ETH", - "address": generator.address, - "timestamp_message": timestamp_message, - "signature": format!("0x{}", signature), - })) + Ok(GuiAuthValidation { + coin_ticker: String::from("ETH"), + address: generator.address, + timestamp_message, + signature: format!("0x{}", signature), + }) } } @@ -3402,9 +3402,12 @@ pub async fn eth_coin_from_conf_and_request_v2( req: EnableV2RpcRequest, priv_key: &[u8], protocol: CoinProtocol, -) -> Result { +) -> Result> { if req.nodes.is_empty() { - return ERR!("Enable request for ETH coin must have at least 1 node"); + return Err(EnableV2RpcError::AtLeastOneNodeRequired( + "Enable request for ETH coin must have at least 1 node".to_string(), + ) + .into()); } let mut rng = small_rng(); @@ -3414,33 +3417,38 @@ pub async fn eth_coin_from_conf_and_request_v2( let mut nodes = vec![]; for node in req.nodes.iter() { + let uri = node + .url + .parse() + .map_err(|_| EnableV2RpcError::InvalidPayload(format!("{} could not be parsed.", node.url)))?; + nodes.push(Web3TransportNode { - uri: try_s!(node.url.parse()), + uri, gui_auth: node.gui_auth, }); } drop_mutability!(nodes); if req.swap_contract_address == Address::default() { - return ERR!("swap_contract_address can't be zero address"); + return Err(EnableV2RpcError::InvalidPayload("swap_contract_address can't be zero address".to_string()).into()); } if let Some(fallback) = req.fallback_swap_contract { if fallback == Address::default() { - return ERR!("fallback_swap_contract can't be zero address"); + return Err( + EnableV2RpcError::InvalidPayload("fallback_swap_contract can't be zero address".to_string()).into(), + ); } } - let key_pair: KeyPair = try_s!(KeyPair::from_secret_slice(priv_key)); + let key_pair: KeyPair = + KeyPair::from_secret_slice(priv_key).map_err(|e| EnableV2RpcError::InternalError(e.to_string()))?; let my_address = checksum_address(&format!("{:02x}", key_pair.address())); let mut web3_instances = vec![]; let event_handlers = rpc_event_handlers_for_eth_transport(ctx, ticker.to_string()); for node in &nodes { - let mut transport = try_s!(Web3Transport::with_event_handlers( - vec![node.clone()], - event_handlers.clone() - )); + let mut transport = Web3Transport::with_event_handlers(vec![node.clone()], event_handlers.clone()); transport.gui_auth_validation_generator = Some(GuiAuthValidationGenerator { secret: key_pair.secret().clone(), address: my_address.clone(), @@ -3462,10 +3470,12 @@ pub async fn eth_coin_from_conf_and_request_v2( } if web3_instances.is_empty() { - return ERR!("Failed to get client version for all nodes"); + return Err( + EnableV2RpcError::UnreachableNodes("Failed to get client version for all nodes".to_string()).into(), + ); } - let mut transport = try_s!(Web3Transport::with_event_handlers(nodes, event_handlers)); + let mut transport = Web3Transport::with_event_handlers(nodes, event_handlers); transport.gui_auth_validation_generator = Some(GuiAuthValidationGenerator { secret: key_pair.secret().clone(), address: my_address, @@ -3480,14 +3490,18 @@ pub async fn eth_coin_from_conf_and_request_v2( platform, contract_address, } => { - let token_addr = try_s!(valid_addr_from_str(&contract_address)); + let token_addr = valid_addr_from_str(&contract_address).map_err(EnableV2RpcError::InternalError)?; let decimals = match conf["decimals"].as_u64() { - None | Some(0) => try_s!(get_token_decimals(&web3, token_addr).await), + None | Some(0) => get_token_decimals(&web3, token_addr) + .await + .map_err(EnableV2RpcError::InternalError)?, Some(d) => d as u8, }; (EthCoinType::Erc20 { platform, token_addr }, decimals) }, - _ => return ERR!("Expect ETH or ERC20 protocol"), + _ => { + return Err(EnableV2RpcError::InvalidPayload("Expect ETH or ERC20 protocol".to_string()).into()); + }, }; // param from request should override the config @@ -3579,10 +3593,7 @@ pub async fn eth_coin_from_conf_and_request( let mut web3_instances = vec![]; let event_handlers = rpc_event_handlers_for_eth_transport(ctx, ticker.to_string()); for node in nodes.iter() { - let transport = try_s!(Web3Transport::with_event_handlers( - vec![node.clone()], - event_handlers.clone() - )); + let transport = Web3Transport::with_event_handlers(vec![node.clone()], event_handlers.clone()); let web3 = Web3::new(transport); let version = match web3.web3().client_version().compat().await { Ok(v) => v, @@ -3601,7 +3612,7 @@ pub async fn eth_coin_from_conf_and_request( return ERR!("Failed to get client version for all urls"); } - let transport = try_s!(Web3Transport::with_event_handlers(nodes, event_handlers)); + let transport = Web3Transport::with_event_handlers(nodes, event_handlers); let web3 = Web3::new(transport); let (coin_type, decimals) = match protocol { diff --git a/mm2src/coins/eth/eth_tests.rs b/mm2src/coins/eth/eth_tests.rs index 74f073bd4d..de92602384 100644 --- a/mm2src/coins/eth/eth_tests.rs +++ b/mm2src/coins/eth/eth_tests.rs @@ -36,7 +36,7 @@ fn eth_coin_for_test( } drop_mutability!(nodes); - let transport = Web3Transport::new(nodes).unwrap(); + let transport = Web3Transport::new(nodes); let web3 = Web3::new(transport); let conf = json!({ "coins":[ @@ -215,8 +215,7 @@ fn send_and_refund_erc20_payment() { let transport = Web3Transport::new(vec![Web3TransportNode { uri: "http://195.201.0.6:8545".parse().unwrap(), gui_auth: false, - }]) - .unwrap(); + }]); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -289,8 +288,7 @@ fn send_and_refund_eth_payment() { let transport = Web3Transport::new(vec![Web3TransportNode { uri: "http://195.201.0.6:8545".parse().unwrap(), gui_auth: false, - }]) - .unwrap(); + }]); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -361,19 +359,16 @@ fn test_nonce_several_urls() { .parse() .unwrap(), gui_auth: false, - }]) - .unwrap(); + }]); let linkpool_transport = Web3Transport::new(vec![Web3TransportNode { uri: "https://ropsten-rpc.linkpool.io".parse().unwrap(), gui_auth: false, - }]) - .unwrap(); + }]); // get nonce must succeed if some nodes are down at the moment for some reason let failing_transport = Web3Transport::new(vec![Web3TransportNode { uri: "http://195.201.0.6:8989".parse().unwrap(), gui_auth: false, - }]) - .unwrap(); + }]); let web3_infura = Web3::new(infura_transport); let web3_linkpool = Web3::new(linkpool_transport); @@ -438,8 +433,7 @@ fn test_wait_for_payment_spend_timeout() { let transport = Web3Transport::new(vec![Web3TransportNode { uri: "http://195.201.0.6:8555".parse().unwrap(), gui_auth: false, - }]) - .unwrap(); + }]); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); @@ -502,8 +496,7 @@ fn test_search_for_swap_tx_spend_was_spent() { .parse() .unwrap(), gui_auth: false, - }]) - .unwrap(); + }]); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); @@ -611,8 +604,7 @@ fn test_search_for_swap_tx_spend_was_refunded() { .parse() .unwrap(), gui_auth: false, - }]) - .unwrap(); + }]); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); @@ -1305,8 +1297,7 @@ fn test_message_hash() { let transport = Web3Transport::new(vec![Web3TransportNode { uri: "http://195.201.0.6:8545".parse().unwrap(), gui_auth: false, - }]) - .unwrap(); + }]); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -1350,8 +1341,7 @@ fn test_sign_verify_message() { let transport = Web3Transport::new(vec![Web3TransportNode { uri: "http://195.201.0.6:8545".parse().unwrap(), gui_auth: false, - }]) - .unwrap(); + }]); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); diff --git a/mm2src/coins/eth/eth_wasm_tests.rs b/mm2src/coins/eth/eth_wasm_tests.rs index 5d3391eb7c..53c1e88876 100644 --- a/mm2src/coins/eth/eth_wasm_tests.rs +++ b/mm2src/coins/eth/eth_wasm_tests.rs @@ -23,8 +23,7 @@ async fn test_send() { let transport = Web3Transport::new(vec![Web3TransportNode { uri: "http://195.201.0.6:8565".parse().unwrap(), gui_auth: false, - }]) - .unwrap(); + }]); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index 3d630a31bc..4a61df68e9 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -85,26 +85,26 @@ pub struct Web3TransportNode { impl Web3Transport { #[allow(dead_code)] #[inline] - pub fn new(nodes: Vec) -> Result { - Ok(Web3Transport { + pub fn new(nodes: Vec) -> Self { + Web3Transport { id: Arc::new(AtomicUsize::new(0)), nodes, event_handlers: Default::default(), gui_auth_validation_generator: None, - }) + } } #[inline] pub fn with_event_handlers( nodes: Vec, event_handlers: Vec, - ) -> Result { - Ok(Web3Transport { + ) -> Self { + Web3Transport { id: Arc::new(AtomicUsize::new(0)), nodes, event_handlers, gui_auth_validation_generator: None, - }) + } } } @@ -183,7 +183,7 @@ async fn send_request( if let Some(generator) = gui_auth_validation_generator.clone() { let mut json_payload: Json = serde_json::from_str(&serialized_request)?; json_payload["signed_message"] = match EthCoin::generate_gui_auth_signed_validation(generator) { - Ok(t) => t, + Ok(t) => serde_json::to_value(t)?, Err(e) => { errors.push(ERRL!( "GuiAuth signed message generation failed for {:?} node, error: {:?}", @@ -268,7 +268,7 @@ async fn send_request( if let Some(generator) = gui_auth_validation_generator.clone() { let mut json_payload: Json = serde_json::from_str(&serialized_request)?; json_payload["signed_message"] = match EthCoin::generate_gui_auth_signed_validation(generator) { - Ok(t) => t, + Ok(t) => serde_json::to_value(t)?, Err(e) => { transport_errors.push(ERRL!( "GuiAuth signed message generation failed for {:?} node, error: {:?}", diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 42b2418d64..41452a9cfd 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -241,13 +241,12 @@ pub use solana::{solana_coin_from_conf_and_params, SolanaActivationParams, Solan pub mod utxo; #[cfg(not(target_arch = "wasm32"))] pub mod z_coin; -use eth::{eth_coin_from_conf_and_request, eth_coin_from_conf_and_request_v2, EthCoin, EthTxFeeDetails, SignedEthTx}; +use eth::{eth_coin_from_conf_and_request, EthCoin, EthTxFeeDetails, SignedEthTx}; use hd_wallet::{HDAddress, HDAddressId}; use qrc20::Qrc20ActivationParams; use qrc20::{qrc20_coin_from_conf_and_params, Qrc20Coin, Qrc20FeeDetails}; use qtum::{Qrc20AddressError, ScriptHashTypeNotSupported}; -use rpc_command::{enable_v2::EnableV2RpcRequest, - init_create_account::{CreateAccountTaskManager, CreateAccountTaskManagerShared}, +use rpc_command::{init_create_account::{CreateAccountTaskManager, CreateAccountTaskManagerShared}, init_scan_for_new_addresses::{ScanAddressesTaskManager, ScanAddressesTaskManagerShared}, init_withdraw::{WithdrawTaskManager, WithdrawTaskManagerShared}}; use utxo::bch::{bch_coin_from_conf_and_params, BchActivationRequest, BchCoin}; @@ -2316,12 +2315,8 @@ pub async fn lp_coininit(ctx: &MmArc, ticker: &str, req: &Json) -> Result match req["_v"].as_u64() { - Some(2) => { - let req = EnableV2RpcRequest::from_json_payload(req.clone()); - try_s!(eth_coin_from_conf_and_request_v2(ctx, ticker, &coins_en, req, &secret, protocol).await).into() - }, - _ => try_s!(eth_coin_from_conf_and_request(ctx, ticker, &coins_en, req, &secret, protocol).await).into(), + CoinProtocol::ETH | CoinProtocol::ERC20 { .. } => { + try_s!(eth_coin_from_conf_and_request(ctx, ticker, &coins_en, req, &secret, protocol).await).into() }, CoinProtocol::QRC20 { platform, diff --git a/mm2src/coins/rpc_command/enable_v2.rs b/mm2src/coins/rpc_command/activate_eth_coin.rs similarity index 54% rename from mm2src/coins/rpc_command/enable_v2.rs rename to mm2src/coins/rpc_command/activate_eth_coin.rs index 50ce500462..3f906050e8 100644 --- a/mm2src/coins/rpc_command/enable_v2.rs +++ b/mm2src/coins/rpc_command/activate_eth_coin.rs @@ -1,11 +1,13 @@ -use crate::{eth::GasStationPricePolicy, lp_coininit, MmCoinEnum}; +use crate::{coin_conf, + eth::{eth_coin_from_conf_and_request_v2, GasStationPricePolicy}, + lp_register_coin, CoinProtocol, MmCoinEnum, RegisterCoinParams}; use common::{HttpStatusCode, StatusCode}; +use crypto::CryptoCtx; use derive_more::Display; use ethereum_types::Address; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::MmResult; use mm2_number::BigDecimal; -use serde_json::Value as Json; #[derive(Debug, Display, Serialize, SerializeErrorType)] #[serde(tag = "error_type", content = "error_data")] @@ -14,14 +16,18 @@ pub enum EnableV2RpcError { InvalidPayload(String), CoinCouldNotInitialized(String), CouldNotFetchBalance(String), + UnreachableNodes(String), + AtLeastOneNodeRequired(String), InternalError(String), } impl HttpStatusCode for EnableV2RpcError { fn status_code(&self) -> StatusCode { match self { - EnableV2RpcError::InvalidPayload(_) => StatusCode::BAD_REQUEST, - EnableV2RpcError::CoinCouldNotInitialized(_) => StatusCode::BAD_REQUEST, + EnableV2RpcError::InvalidPayload(_) + | EnableV2RpcError::CoinCouldNotInitialized(_) + | EnableV2RpcError::UnreachableNodes(_) + | EnableV2RpcError::AtLeastOneNodeRequired(_) => StatusCode::BAD_REQUEST, EnableV2RpcError::CouldNotFetchBalance(_) => StatusCode::SERVICE_UNAVAILABLE, _ => StatusCode::INTERNAL_SERVER_ERROR, } @@ -49,15 +55,6 @@ pub struct EnableV2NodesRpc { pub gui_auth: bool, } -impl EnableV2RpcRequest { - #[inline(always)] - pub fn from_json_payload(payload: Json) -> Self { - serde_json::from_value(payload) - .map_err(|e| EnableV2RpcError::InvalidPayload(e.to_string())) - .unwrap() - } -} - #[derive(Serialize, Clone)] pub struct EnableV2RpcResponse { pub result: String, @@ -71,17 +68,30 @@ pub struct EnableV2RpcResponse { pub mature_confirmations: Option, } -pub async fn enable_v2(ctx: &MmArc, req: Json) -> MmResult { - let mut req = req; - req["_v"] = json!(2_u64); - drop_mutability!(req); +pub async fn activate_eth_coin(ctx: &MmArc, req: EnableV2RpcRequest) -> MmResult { + let secret = CryptoCtx::from_ctx(ctx) + .map_err(|e| EnableV2RpcError::InternalError(e.to_string()))? + .iguana_ctx() + .secp256k1_privkey_bytes() + .to_vec(); + + let coins_en = coin_conf(ctx, &req.coin); - let ticker = req["coin"] - .as_str() - .ok_or_else(|| EnableV2RpcError::InvalidPayload(String::from("No 'coin' field")))? - .to_owned(); + let protocol: CoinProtocol = serde_json::from_value(coins_en["protocol"].clone()) + .map_err(|e| EnableV2RpcError::CoinCouldNotInitialized(e.to_string()))?; - Ok(lp_coininit(ctx, &ticker, &req) + let coin: MmCoinEnum = eth_coin_from_conf_and_request_v2(ctx, &req.coin, &coins_en, req.clone(), &secret, protocol) + .await? + .into(); + + let register_params = RegisterCoinParams { + ticker: req.coin, + tx_history: req.tx_history.unwrap_or(false), + }; + + lp_register_coin(ctx, coin.clone(), register_params) .await - .map_err(EnableV2RpcError::CoinCouldNotInitialized)?) + .map_err(|e| EnableV2RpcError::CoinCouldNotInitialized(e.to_string()))?; + + Ok(coin) } diff --git a/mm2src/coins/rpc_command/mod.rs b/mm2src/coins/rpc_command/mod.rs index 7ed0aa5cd9..d59b0ea56a 100644 --- a/mm2src/coins/rpc_command/mod.rs +++ b/mm2src/coins/rpc_command/mod.rs @@ -1,5 +1,5 @@ pub mod account_balance; -pub mod enable_v2; +pub mod activate_eth_coin; pub mod hd_account_balance_rpc_error; pub mod init_create_account; pub mod init_scan_for_new_addresses; diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -0,0 +1 @@ + diff --git a/mm2src/coins_activation/src/lib.rs b/mm2src/coins_activation/src/lib.rs index 5b6b9321da..2fd3825a8c 100644 --- a/mm2src/coins_activation/src/lib.rs +++ b/mm2src/coins_activation/src/lib.rs @@ -1,5 +1,6 @@ mod bch_with_tokens_activation; mod context; +mod eth_with_token_activation; mod l2; #[cfg(not(target_arch = "wasm32"))] mod lightning_activation; mod platform_coin_with_tokens; diff --git a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs index ab8606c988..d000f001aa 100644 --- a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs +++ b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs @@ -1,4 +1,4 @@ -use super::{lp_commands::enable_v2_wrapper, DispatcherError, DispatcherResult, PUBLIC_METHODS}; +use super::{lp_commands::activate_eth_coin_wrapper, DispatcherError, DispatcherResult, PUBLIC_METHODS}; use crate::mm2::lp_native_dex::init_hw::{init_trezor, init_trezor_status, init_trezor_user_action}; use crate::mm2::lp_ordermatch::{best_orders_rpc_v2, orderbook_rpc_v2, start_simple_market_maker_bot, stop_simple_market_maker_bot}; @@ -123,7 +123,7 @@ async fn dispatcher_v2(request: MmRpcRequest, ctx: MmArc) -> DispatcherResult handle_mmrpc(ctx, request, add_delegation).await, "add_node_to_version_stat" => handle_mmrpc(ctx, request, add_node_to_version_stat).await, "best_orders" => handle_mmrpc(ctx, request, best_orders_rpc_v2).await, - "enable" => handle_mmrpc(ctx, request, enable_v2_wrapper).await, + "activate_eth_coin" => handle_mmrpc(ctx, request, activate_eth_coin_wrapper).await, "enable_bch_with_tokens" => handle_mmrpc(ctx, request, enable_platform_coin_with_tokens::).await, "enable_slp" => handle_mmrpc(ctx, request, enable_token::).await, "get_new_address" => handle_mmrpc(ctx, request, get_new_address).await, diff --git a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs index b0d3d778a9..e8091e7c03 100644 --- a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs +++ b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs @@ -1,5 +1,6 @@ use crate::mm2::{lp_network::subscribe_to_topic, lp_swap::tx_helper_topic}; -use coins::rpc_command::enable_v2::{enable_v2, EnableV2RpcError, EnableV2RpcResponse}; +use coins::rpc_command::activate_eth_coin::{activate_eth_coin, EnableV2RpcError, EnableV2RpcRequest, + EnableV2RpcResponse}; use common::{Future01CompatExt, HttpStatusCode}; use crypto::{CryptoCtx, CryptoInitError}; use derive_more::Display; @@ -49,14 +50,17 @@ pub async fn get_public_key_hash(ctx: MmArc, _req: Json) -> GetPublicKeyRpcResul Ok(GetPublicKeyHashResponse { public_key_hash }) } -pub async fn enable_v2_wrapper(ctx: MmArc, req: Json) -> MmResult { - let coin = enable_v2(&ctx, req).await?; +pub async fn activate_eth_coin_wrapper( + ctx: MmArc, + req: EnableV2RpcRequest, +) -> MmResult { + let coin = activate_eth_coin(&ctx, req).await?; let balance = coin .my_balance() .compat() .await - .map_err(|e| EnableV2RpcError::CoinCouldNotInitialized(e.to_string()))?; + .map_err(|e| EnableV2RpcError::CouldNotFetchBalance(e.to_string()))?; if coin.is_utxo_in_native_mode() { subscribe_to_topic(&ctx, tx_helper_topic(coin.ticker())); diff --git a/mm2src/mm2_net/src/transport.rs b/mm2src/mm2_net/src/transport.rs index 2321575fda..f3c47f0b6c 100644 --- a/mm2src/mm2_net/src/transport.rs +++ b/mm2src/mm2_net/src/transport.rs @@ -50,9 +50,17 @@ where }) } -/// gui-auth specific data-type that needed in order to perform gui-auth calls #[derive(Clone, Debug)] pub struct GuiAuthValidationGenerator { pub secret: Secret, pub address: String, } + +/// gui-auth specific data-type that needed in order to perform gui-auth calls +#[derive(Serialize)] +pub struct GuiAuthValidation { + pub coin_ticker: String, + pub address: String, + pub timestamp_message: i64, + pub signature: String, +} From 1e013e18fa40484244a3152c7b0c751cabc49528 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Tue, 19 Jul 2022 19:06:35 +0300 Subject: [PATCH 27/69] save development state Signed-off-by: ozkanonur --- Cargo.lock | 1 + mm2src/coins/eth.rs | 83 +++++-- mm2src/coins/eth/erc20.rs | 8 + mm2src/coins/rpc_command/activate_eth_coin.rs | 6 +- mm2src/coins_activation/Cargo.toml | 1 + .../src/erc20_token_activation.rs | 7 + .../src/eth_with_token_activation.rs | 207 ++++++++++++++++++ mm2src/coins_activation/src/lib.rs | 1 + .../src/platform_coin_with_tokens.rs | 2 + .../mm2_main/src/rpc/dispatcher/dispatcher.rs | 2 + .../src/rpc/lp_commands/lp_commands.rs | 8 +- 11 files changed, 303 insertions(+), 23 deletions(-) create mode 100644 mm2src/coins/eth/erc20.rs create mode 100644 mm2src/coins_activation/src/erc20_token_activation.rs diff --git a/Cargo.lock b/Cargo.lock index 8f2bd13deb..de0ffda994 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1136,6 +1136,7 @@ dependencies = [ "common", "crypto", "derive_more", + "ethereum-types 0.4.2", "futures 0.3.15", "hex 0.4.2", "mm2_core", diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 86b0a96424..1c56f324f2 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -24,7 +24,7 @@ use async_trait::async_trait; use bitcrypto::{keccak256, sha256}; use common::executor::Timer; use common::log::{error, info, warn}; -use common::{get_utc_timestamp, now_ms, small_rng, DEX_FEE_ADDR_RAW_PUBKEY}; +use common::{get_utc_timestamp, now_ms, small_rng, HttpStatusCode, DEX_FEE_ADDR_RAW_PUBKEY}; use crypto::privkey::key_pair_from_secret; use derive_more::Display; use ethabi::{Contract, Token}; @@ -72,6 +72,7 @@ use super::{rpc_command::activate_eth_coin::{EnableV2RpcError, EnableV2RpcReques pub use rlp; +pub mod erc20; #[cfg(test)] mod eth_tests; #[cfg(target_arch = "wasm32")] mod eth_wasm_tests; mod web3_transport; @@ -250,6 +251,53 @@ impl From for BalanceError { fn from(e: web3::Error) -> Self { BalanceError::Transport(e.to_string()) } } +#[derive(Debug, Display, Serialize, SerializeErrorType)] +#[serde(tag = "error_type", content = "error_data")] +#[allow(dead_code)] +pub enum EthActivationV2Error { + InvalidPayload(String), + #[display(fmt = "Platform coin {} activation failed. {}", ticker, error)] + ActivationFailed { ticker: String, error: String }, + CouldNotFetchBalance(String), + UnreachableNodes(String), + AtLeastOneNodeRequired(String), + InternalError(String), +} + +impl HttpStatusCode for EthActivationV2Error { + fn status_code(&self) -> StatusCode { + match self { + EthActivationV2Error::InvalidPayload(_) + | EthActivationV2Error::ActivationFailed { .. } + | EthActivationV2Error::UnreachableNodes(_) + | EthActivationV2Error::AtLeastOneNodeRequired(_) => StatusCode::BAD_REQUEST, + EthActivationV2Error::CouldNotFetchBalance(_) => StatusCode::SERVICE_UNAVAILABLE, + _ => StatusCode::INTERNAL_SERVER_ERROR, + } + } +} + +#[derive(Clone, Debug, Deserialize)] +pub struct EthActivationRequest { + pub coin: String, + pub nodes: Vec, + pub swap_contract_address: Address, + pub fallback_swap_contract: Option
, + pub gas_station_url: Option, + pub gas_station_decimals: Option, + #[serde(default)] + pub gas_station_policy: GasStationPricePolicy, + pub mm2: Option, + pub tx_history: Option, + pub required_confirmations: Option, +} + +#[derive(Clone, Debug, Deserialize)] +pub struct EthNode { + pub url: String, + pub gui_auth: bool, +} + #[derive(Debug, Deserialize, Serialize)] struct SavedTraces { /// ETH traces for my_address @@ -271,7 +319,7 @@ struct SavedErc20Events { } #[derive(Debug, PartialEq, Eq)] -enum EthCoinType { +pub enum EthCoinType { /// Ethereum itself or it's forks: ETC/others Eth, /// ERC20 token with smart contract address @@ -3371,7 +3419,7 @@ async fn get_token_decimals(web3: &Web3, token_addr: Address) -> Ok(decimals as u8) } -fn valid_addr_from_str(addr_str: &str) -> Result { +pub fn valid_addr_from_str(addr_str: &str) -> Result { let addr = try_s!(addr_from_str(addr_str)); if !is_valid_checksum_addr(addr_str) { return ERR!("Invalid address checksum"); @@ -3399,12 +3447,12 @@ pub async fn eth_coin_from_conf_and_request_v2( ctx: &MmArc, ticker: &str, conf: &Json, - req: EnableV2RpcRequest, + req: EthActivationRequest, priv_key: &[u8], protocol: CoinProtocol, -) -> Result> { +) -> Result> { if req.nodes.is_empty() { - return Err(EnableV2RpcError::AtLeastOneNodeRequired( + return Err(EthActivationV2Error::AtLeastOneNodeRequired( "Enable request for ETH coin must have at least 1 node".to_string(), ) .into()); @@ -3420,7 +3468,7 @@ pub async fn eth_coin_from_conf_and_request_v2( let uri = node .url .parse() - .map_err(|_| EnableV2RpcError::InvalidPayload(format!("{} could not be parsed.", node.url)))?; + .map_err(|_| EthActivationV2Error::InvalidPayload(format!("{} could not be parsed.", node.url)))?; nodes.push(Web3TransportNode { uri, @@ -3430,19 +3478,22 @@ pub async fn eth_coin_from_conf_and_request_v2( drop_mutability!(nodes); if req.swap_contract_address == Address::default() { - return Err(EnableV2RpcError::InvalidPayload("swap_contract_address can't be zero address".to_string()).into()); + return Err( + EthActivationV2Error::InvalidPayload("swap_contract_address can't be zero address".to_string()).into(), + ); } if let Some(fallback) = req.fallback_swap_contract { if fallback == Address::default() { - return Err( - EnableV2RpcError::InvalidPayload("fallback_swap_contract can't be zero address".to_string()).into(), - ); + return Err(EthActivationV2Error::InvalidPayload( + "fallback_swap_contract can't be zero address".to_string(), + ) + .into()); } } let key_pair: KeyPair = - KeyPair::from_secret_slice(priv_key).map_err(|e| EnableV2RpcError::InternalError(e.to_string()))?; + KeyPair::from_secret_slice(priv_key).map_err(|e| EthActivationV2Error::InternalError(e.to_string()))?; let my_address = checksum_address(&format!("{:02x}", key_pair.address())); let mut web3_instances = vec![]; @@ -3471,7 +3522,7 @@ pub async fn eth_coin_from_conf_and_request_v2( if web3_instances.is_empty() { return Err( - EnableV2RpcError::UnreachableNodes("Failed to get client version for all nodes".to_string()).into(), + EthActivationV2Error::UnreachableNodes("Failed to get client version for all nodes".to_string()).into(), ); } @@ -3490,17 +3541,17 @@ pub async fn eth_coin_from_conf_and_request_v2( platform, contract_address, } => { - let token_addr = valid_addr_from_str(&contract_address).map_err(EnableV2RpcError::InternalError)?; + let token_addr = valid_addr_from_str(&contract_address).map_err(EthActivationV2Error::InternalError)?; let decimals = match conf["decimals"].as_u64() { None | Some(0) => get_token_decimals(&web3, token_addr) .await - .map_err(EnableV2RpcError::InternalError)?, + .map_err(EthActivationV2Error::InternalError)?, Some(d) => d as u8, }; (EthCoinType::Erc20 { platform, token_addr }, decimals) }, _ => { - return Err(EnableV2RpcError::InvalidPayload("Expect ETH or ERC20 protocol".to_string()).into()); + return Err(EthActivationV2Error::InvalidPayload("Expect ETH or ERC20 protocol".to_string()).into()); }, }; diff --git a/mm2src/coins/eth/erc20.rs b/mm2src/coins/eth/erc20.rs new file mode 100644 index 0000000000..2e20a436f4 --- /dev/null +++ b/mm2src/coins/eth/erc20.rs @@ -0,0 +1,8 @@ +use ethereum_types::Address; + +use super::EthCoin; + +pub struct Erc20Token { + pub conf: Arc, + pub platform_coin: EthCoin, +} diff --git a/mm2src/coins/rpc_command/activate_eth_coin.rs b/mm2src/coins/rpc_command/activate_eth_coin.rs index 3f906050e8..5d4440a051 100644 --- a/mm2src/coins/rpc_command/activate_eth_coin.rs +++ b/mm2src/coins/rpc_command/activate_eth_coin.rs @@ -1,5 +1,5 @@ use crate::{coin_conf, - eth::{eth_coin_from_conf_and_request_v2, GasStationPricePolicy}, + eth::{eth_coin_from_conf_and_request_v2, GasStationPricePolicy, EthActivationRequest}, lp_register_coin, CoinProtocol, MmCoinEnum, RegisterCoinParams}; use common::{HttpStatusCode, StatusCode}; use crypto::CryptoCtx; @@ -68,7 +68,7 @@ pub struct EnableV2RpcResponse { pub mature_confirmations: Option, } -pub async fn activate_eth_coin(ctx: &MmArc, req: EnableV2RpcRequest) -> MmResult { +pub async fn activate_eth_coin(ctx: &MmArc, req: EthActivationRequest) -> MmResult { let secret = CryptoCtx::from_ctx(ctx) .map_err(|e| EnableV2RpcError::InternalError(e.to_string()))? .iguana_ctx() @@ -81,7 +81,7 @@ pub async fn activate_eth_coin(ctx: &MmArc, req: EnableV2RpcRequest) -> MmResult .map_err(|e| EnableV2RpcError::CoinCouldNotInitialized(e.to_string()))?; let coin: MmCoinEnum = eth_coin_from_conf_and_request_v2(ctx, &req.coin, &coins_en, req.clone(), &secret, protocol) - .await? + .await.unwrap() .into(); let register_params = RegisterCoinParams { diff --git a/mm2src/coins_activation/Cargo.toml b/mm2src/coins_activation/Cargo.toml index e95895aa99..89f4ac538d 100644 --- a/mm2src/coins_activation/Cargo.toml +++ b/mm2src/coins_activation/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" async-trait = "0.1" coins = { path = "../coins" } common = { path = "../common" } +ethereum-types = { version = "0.4", default-features = false, features = ["std", "serialize"] } mm2_core = { path = "../mm2_core" } mm2_err_handle = { path = "../mm2_err_handle" } mm2_number = { path = "../mm2_number" } diff --git a/mm2src/coins_activation/src/erc20_token_activation.rs b/mm2src/coins_activation/src/erc20_token_activation.rs new file mode 100644 index 0000000000..8b1080f222 --- /dev/null +++ b/mm2src/coins_activation/src/erc20_token_activation.rs @@ -0,0 +1,7 @@ +use serde::Deserialize; + + +#[derive(Clone, Debug, Deserialize)] +pub struct Erc20ActivationRequest { + pub required_confirmations: Option, +} diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 8b13789179..859a3f2ad2 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -1 +1,208 @@ +use std::collections::HashMap; +use async_trait::async_trait; +use coins::{coin_conf, + eth::{eth_coin_from_conf_and_request_v2, valid_addr_from_str, EthActivationRequest, EthActivationV2Error, + EthCoin, EthCoinType}, + my_tx_history_v2::TxHistoryStorage, + CoinBalance, CoinProtocol, MarketCoinOps}; +use common::{log::info, mm_metrics::MetricsArc, Future01CompatExt}; +use futures::future::AbortHandle; +use mm2_core::mm_ctx::MmArc; +use mm2_err_handle::prelude::*; +use mm2_number::BigDecimal; +use serde::{Deserialize, Serialize}; +use serde_json::Value as Json; + +use crate::{platform_coin_with_tokens::{EnablePlatformCoinWithTokensError, GetPlatformBalance, + PlatformWithTokensActivationOps, TokenAsMmCoinInitializer}, + prelude::*}; + +pub struct Erc20Initializer { + platform_coin: EthCoin, +} + +pub struct EthProtocolInfo { + coin_type: EthCoinType, + decimals: u8, +} + +impl TryFromCoinProtocol for EthProtocolInfo { + fn try_from_coin_protocol(proto: CoinProtocol) -> Result> + where + Self: Sized, + { + match proto { + CoinProtocol::ETH => Ok(EthProtocolInfo { + coin_type: EthCoinType::Eth, + decimals: 18, + }), + protocol => MmError::err(protocol), + } + } +} + +impl From for EnablePlatformCoinWithTokensError { + fn from(err: EthActivationV2Error) -> Self { + // match err { + // BchWithTokensActivationError::PlatformCoinCreationError { ticker, error } => { + // EnablePlatformCoinWithTokensError::PlatformCoinCreationError { ticker, error } + // }, + // BchWithTokensActivationError::InvalidSlpPrefix { ticker, prefix, error } => { + // EnablePlatformCoinWithTokensError::Internal(format!( + // "Invalid slp prefix {} configured for {}. Error: {}", + // prefix, ticker, error + // )) + // }, + // BchWithTokensActivationError::PrivKeyNotAllowed(e) => { + // EnablePlatformCoinWithTokensError::PrivKeyNotAllowed(e) + // }, + // BchWithTokensActivationError::UnexpectedDerivationMethod(e) => { + // EnablePlatformCoinWithTokensError::UnexpectedDerivationMethod(e) + // }, + // BchWithTokensActivationError::Transport(e) => EnablePlatformCoinWithTokensError::Transport(e), + // BchWithTokensActivationError::Internal(e) => EnablePlatformCoinWithTokensError::Internal(e), + // } + match err { + EthActivationV2Error::InvalidPayload(e) => EnablePlatformCoinWithTokensError::InvalidPayload(e), + EthActivationV2Error::ActivationFailed { ticker, error } => { + EnablePlatformCoinWithTokensError::PlatformCoinCreationError { ticker, error } + }, + EthActivationV2Error::CouldNotFetchBalance(e) + | EthActivationV2Error::UnreachableNodes(e) + | EthActivationV2Error::AtLeastOneNodeRequired(e) => EnablePlatformCoinWithTokensError::Transport(e), + EthActivationV2Error::InternalError(e) => EnablePlatformCoinWithTokensError::Internal(e), + } + } +} + +#[derive(Clone, Debug, Deserialize)] +pub struct EthWithTokensActivationRequest { + #[serde(flatten)] + platform_request: EthActivationRequest, + erc20_tokens_requests: Vec< + crate::platform_coin_with_tokens::TokenActivationRequest, + >, +} + +impl TxHistory for EthWithTokensActivationRequest { + fn tx_history(&self) -> bool { self.platform_request.tx_history.unwrap_or(false) } +} + +#[derive(Debug, Serialize)] +pub struct EthWithTokensActivationResult { + current_block: u64, + eth_addresses_infos: HashMap>, + erc20_addresses_infos: HashMap>, +} + +impl GetPlatformBalance for EthWithTokensActivationResult { + fn get_platform_balance(&self) -> BigDecimal { + self.eth_addresses_infos + .iter() + .fold(BigDecimal::from(0), |total, (_, addr_info)| { + &total + &addr_info.balances.get_total() + }) + } +} + +impl CurrentBlock for EthWithTokensActivationResult { + fn current_block(&self) -> u64 { self.current_block } +} + +#[async_trait] +impl PlatformWithTokensActivationOps for EthCoin { + type ActivationRequest = EthWithTokensActivationRequest; + type PlatformProtocolInfo = EthProtocolInfo; + type ActivationResult = EthWithTokensActivationResult; + type ActivationError = EthActivationV2Error; + + async fn enable_platform_coin( + ctx: MmArc, + ticker: String, + platform_conf: Json, + activation_request: Self::ActivationRequest, + _protocol_conf: Self::PlatformProtocolInfo, + priv_key: &[u8], + ) -> Result> { + let coins_en = coin_conf(&ctx, &ticker); + + let protocol: CoinProtocol = serde_json::from_value(coins_en["protocol"].clone()).map_err(|e| { + Self::ActivationError::ActivationFailed { + ticker: ticker.clone(), + error: e.to_string(), + } + })?; + + let platform_coin = eth_coin_from_conf_and_request_v2( + &ctx, + &ticker, + &platform_conf, + activation_request.platform_request, + priv_key, + protocol, + ) + .await?; + + Ok(platform_coin) + } + + fn token_initializers( + &self, + ) -> Vec>> { + vec![] + + // vec![Box::new(Erc20Initializer { + // platform_coin: self.clone(), + // })] + } + + async fn get_activation_result(&self) -> Result> { + let my_address = self.my_address().map_err(EthActivationV2Error::InternalError)?; + + let current_block = self + .current_block() + .compat() + .await + .map_err(EthActivationV2Error::InternalError)?; + + // let bch_unspents = self.bch_unspents_for_display(my_address).await?; + // let bch_balance = bch_unspents.platform_balance(self.decimals()); + + // let mut token_balances = HashMap::new(); + // for (token_ticker, info) in self.get_slp_tokens_infos().iter() { + // let token_balance = bch_unspents.slp_token_balance(&info.token_id, info.decimals); + // token_balances.insert(token_ticker.clone(), token_balance); + // } + + let mut result = EthWithTokensActivationResult { + current_block, + eth_addresses_infos: HashMap::new(), + erc20_addresses_infos: HashMap::new(), + }; + + // result + // .bch_addresses_infos + // .insert(my_address.to_string(), CoinAddressInfo { + // derivation_method: DerivationMethod::Iguana, + // pubkey: self.my_public_key()?.to_string(), + // balances: bch_balance, + // }); + + // result.slp_addresses_infos.insert(my_slp_address, CoinAddressInfo { + // derivation_method: DerivationMethod::Iguana, + // pubkey: self.my_public_key()?.to_string(), + // balances: token_balances, + // }); + Ok(result) + } + + fn start_history_background_fetching( + &self, + _metrics: MetricsArc, + _storage: impl TxHistoryStorage + Send + 'static, + _initial_balance: BigDecimal, + ) -> AbortHandle { + todo!() + } +} diff --git a/mm2src/coins_activation/src/lib.rs b/mm2src/coins_activation/src/lib.rs index 2fd3825a8c..02cc0bf714 100644 --- a/mm2src/coins_activation/src/lib.rs +++ b/mm2src/coins_activation/src/lib.rs @@ -1,6 +1,7 @@ mod bch_with_tokens_activation; mod context; mod eth_with_token_activation; +mod erc20_token_activation; mod l2; #[cfg(not(target_arch = "wasm32"))] mod lightning_activation; mod platform_coin_with_tokens; diff --git a/mm2src/coins_activation/src/platform_coin_with_tokens.rs b/mm2src/coins_activation/src/platform_coin_with_tokens.rs index c27a440008..c492932dab 100644 --- a/mm2src/coins_activation/src/platform_coin_with_tokens.rs +++ b/mm2src/coins_activation/src/platform_coin_with_tokens.rs @@ -211,6 +211,7 @@ pub enum EnablePlatformCoinWithTokensError { #[display(fmt = "Unexpected derivation method: {}", _0)] UnexpectedDerivationMethod(String), Transport(String), + InvalidPayload(String), Internal(String), } @@ -272,6 +273,7 @@ impl HttpStatusCode for EnablePlatformCoinWithTokensError { | EnablePlatformCoinWithTokensError::PlatformConfigIsNotFound(_) | EnablePlatformCoinWithTokensError::TokenConfigIsNotFound(_) | EnablePlatformCoinWithTokensError::UnexpectedPlatformProtocol { .. } + | EnablePlatformCoinWithTokensError::InvalidPayload { .. } | EnablePlatformCoinWithTokensError::UnexpectedTokenProtocol { .. } => StatusCode::BAD_REQUEST, } } diff --git a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs index d000f001aa..4f462ab12d 100644 --- a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs +++ b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs @@ -7,6 +7,7 @@ use crate::{mm2::lp_stats::{add_node_to_version_stat, remove_node_from_version_s stop_version_stat_collection, update_version_stat_collection}, mm2::lp_swap::{recreate_swap_data, trade_preimage_rpc}, mm2::rpc::lp_commands::{get_public_key, get_public_key_hash}}; +use coins::eth::EthCoin; use coins::hd_wallet::get_new_address; use coins::my_tx_history_v2::my_tx_history_v2_rpc; use coins::rpc_command::account_balance::account_balance; @@ -125,6 +126,7 @@ async fn dispatcher_v2(request: MmRpcRequest, ctx: MmArc) -> DispatcherResult handle_mmrpc(ctx, request, best_orders_rpc_v2).await, "activate_eth_coin" => handle_mmrpc(ctx, request, activate_eth_coin_wrapper).await, "enable_bch_with_tokens" => handle_mmrpc(ctx, request, enable_platform_coin_with_tokens::).await, + "enable_eth_with_tokens" => handle_mmrpc(ctx, request, enable_platform_coin_with_tokens::).await, "enable_slp" => handle_mmrpc(ctx, request, enable_token::).await, "get_new_address" => handle_mmrpc(ctx, request, get_new_address).await, "get_public_key" => handle_mmrpc(ctx, request, get_public_key).await, diff --git a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs index e8091e7c03..058ad4779b 100644 --- a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs +++ b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs @@ -1,6 +1,6 @@ use crate::mm2::{lp_network::subscribe_to_topic, lp_swap::tx_helper_topic}; -use coins::rpc_command::activate_eth_coin::{activate_eth_coin, EnableV2RpcError, EnableV2RpcRequest, - EnableV2RpcResponse}; +use coins::{rpc_command::activate_eth_coin::{activate_eth_coin, EnableV2RpcError, EnableV2RpcRequest, + EnableV2RpcResponse}, eth::EthActivationRequest}; use common::{Future01CompatExt, HttpStatusCode}; use crypto::{CryptoCtx, CryptoInitError}; use derive_more::Display; @@ -52,9 +52,9 @@ pub async fn get_public_key_hash(ctx: MmArc, _req: Json) -> GetPublicKeyRpcResul pub async fn activate_eth_coin_wrapper( ctx: MmArc, - req: EnableV2RpcRequest, + req: EthActivationRequest, ) -> MmResult { - let coin = activate_eth_coin(&ctx, req).await?; + let coin = activate_eth_coin(&ctx, req).await.unwrap(); let balance = coin .my_balance() From a8de7e6b9edff7ccdb6aa81c4815c9923a381fb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Tue, 19 Jul 2022 22:14:05 +0300 Subject: [PATCH 28/69] save development state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins/eth.rs | 5 +- mm2src/coins/eth/erc20.rs | 269 +++++++++++++++++- mm2src/coins/lp_coins.rs | 7 + mm2src/coins/rpc_command/activate_eth_coin.rs | 5 +- .../src/erc20_token_activation.rs | 1 - mm2src/coins_activation/src/lib.rs | 2 +- .../src/rpc/lp_commands/lp_commands.rs | 5 +- 7 files changed, 285 insertions(+), 9 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 1c56f324f2..2ffb22e0c9 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -257,7 +257,10 @@ impl From for BalanceError { pub enum EthActivationV2Error { InvalidPayload(String), #[display(fmt = "Platform coin {} activation failed. {}", ticker, error)] - ActivationFailed { ticker: String, error: String }, + ActivationFailed { + ticker: String, + error: String, + }, CouldNotFetchBalance(String), UnreachableNodes(String), AtLeastOneNodeRequired(String), diff --git a/mm2src/coins/eth/erc20.rs b/mm2src/coins/eth/erc20.rs index 2e20a436f4..0b4d43a89e 100644 --- a/mm2src/coins/eth/erc20.rs +++ b/mm2src/coins/eth/erc20.rs @@ -1,8 +1,273 @@ +use super::EthCoin; +use crate::{BalanceFut, CoinBalance, FeeApproxStage, FoundSwapTxSpend, HistorySyncState, MarketCoinOps, MmCoin, + NegotiateSwapContractAddrErr, RawTransactionFut, RawTransactionRequest, SearchForSwapTxSpendInput, + SignatureResult, SwapOps, TradeFee, TradePreimageFut, TradePreimageResult, TradePreimageValue, + TransactionEnum, TransactionFut, UnexpectedDerivationMethod, ValidateAddressResult, ValidatePaymentInput, + VerificationResult, WithdrawFut, WithdrawRequest}; +use async_trait::async_trait; use ethereum_types::Address; +use futures01::Future; +use mm2_core::mm_ctx::MmArc; +use mm2_err_handle::prelude::*; +use mm2_number::{BigDecimal, MmNumber}; +use rpc::v1::types::Bytes as BytesJson; +use serde_json::Value as Json; +use std::sync::Arc; -use super::EthCoin; +#[derive(Clone, Debug)] +pub struct Erc20TokenConf { + pub decimals: u8, + pub ticker: String, + pub token_contract_address: Address, +} +#[derive(Clone, Debug)] pub struct Erc20Token { - pub conf: Arc, + pub conf: Arc, pub platform_coin: EthCoin, } + +#[async_trait] +impl MmCoin for Erc20Token { + fn is_asset_chain(&self) -> bool { todo!() } + + fn get_raw_transaction(&self, req: RawTransactionRequest) -> RawTransactionFut { todo!() } + + fn withdraw(&self, req: WithdrawRequest) -> WithdrawFut { todo!() } + + fn decimals(&self) -> u8 { todo!() } + + fn convert_to_address(&self, from: &str, to_address_format: Json) -> Result { todo!() } + + fn validate_address(&self, address: &str) -> ValidateAddressResult { todo!() } + + fn process_history_loop(&self, ctx: MmArc) -> Box + Send> { todo!() } + + fn history_sync_status(&self) -> HistorySyncState { todo!() } + + fn get_trade_fee(&self) -> Box + Send> { todo!() } + + async fn get_sender_trade_fee( + &self, + value: TradePreimageValue, + stage: FeeApproxStage, + ) -> TradePreimageResult { + todo!() + } + + fn get_receiver_trade_fee(&self, stage: FeeApproxStage) -> TradePreimageFut { todo!() } + + async fn get_fee_to_send_taker_fee( + &self, + dex_fee_amount: BigDecimal, + stage: FeeApproxStage, + ) -> TradePreimageResult { + todo!() + } + + fn required_confirmations(&self) -> u64 { todo!() } + + fn requires_notarization(&self) -> bool { todo!() } + + fn set_required_confirmations(&self, confirmations: u64) { todo!() } + + fn set_requires_notarization(&self, _requires_nota: bool) { todo!() } + + fn swap_contract_address(&self) -> Option { todo!() } + + fn mature_confirmations(&self) -> Option { todo!() } + + fn coin_protocol_info(&self) -> Vec { todo!() } + + fn is_coin_protocol_supported(&self, _info: &Option>) -> bool { todo!() } +} + +#[async_trait] +impl SwapOps for Erc20Token { + fn send_taker_fee(&self, fee_addr: &[u8], amount: BigDecimal, _uuid: &[u8]) -> TransactionFut { todo!() } + + fn send_maker_payment( + &self, + time_lock: u32, + taker_pub: &[u8], + secret_hash: &[u8], + amount: BigDecimal, + swap_contract_address: &Option, + _swap_unique_data: &[u8], + ) -> TransactionFut { + todo!() + } + + fn send_taker_payment( + &self, + time_lock: u32, + maker_pub: &[u8], + secret_hash: &[u8], + amount: BigDecimal, + swap_contract_address: &Option, + _swap_unique_data: &[u8], + ) -> TransactionFut { + todo!() + } + + fn send_maker_spends_taker_payment( + &self, + taker_payment_tx: &[u8], + _time_lock: u32, + _taker_pub: &[u8], + secret: &[u8], + swap_contract_address: &Option, + _swap_unique_data: &[u8], + ) -> TransactionFut { + todo!() + } + + fn send_taker_spends_maker_payment( + &self, + maker_payment_tx: &[u8], + _time_lock: u32, + _maker_pub: &[u8], + secret: &[u8], + swap_contract_address: &Option, + _swap_unique_data: &[u8], + ) -> TransactionFut { + todo!() + } + + fn send_taker_refunds_payment( + &self, + taker_payment_tx: &[u8], + _time_lock: u32, + _maker_pub: &[u8], + _secret_hash: &[u8], + swap_contract_address: &Option, + _swap_unique_data: &[u8], + ) -> TransactionFut { + todo!() + } + + fn send_maker_refunds_payment( + &self, + maker_payment_tx: &[u8], + _time_lock: u32, + _taker_pub: &[u8], + _secret_hash: &[u8], + swap_contract_address: &Option, + _swap_unique_data: &[u8], + ) -> TransactionFut { + todo!() + } + + fn validate_fee( + &self, + fee_tx: &TransactionEnum, + expected_sender: &[u8], + fee_addr: &[u8], + amount: &BigDecimal, + min_block_number: u64, + _uuid: &[u8], + ) -> Box + Send> { + todo!() + } + + fn validate_maker_payment(&self, input: ValidatePaymentInput) -> Box + Send> { + todo!() + } + + fn validate_taker_payment(&self, input: ValidatePaymentInput) -> Box + Send> { + todo!() + } + + fn check_if_my_payment_sent( + &self, + time_lock: u32, + _other_pub: &[u8], + secret_hash: &[u8], + from_block: u64, + swap_contract_address: &Option, + _swap_unique_data: &[u8], + ) -> Box, Error = String> + Send> { + todo!() + } + + async fn search_for_swap_tx_spend_my( + &self, + input: SearchForSwapTxSpendInput<'_>, + ) -> Result, String> { + todo!() + } + + async fn search_for_swap_tx_spend_other( + &self, + input: SearchForSwapTxSpendInput<'_>, + ) -> Result, String> { + todo!() + } + + fn extract_secret(&self, _secret_hash: &[u8], spend_tx: &[u8]) -> Result, String> { todo!() } + + fn negotiate_swap_contract_addr( + &self, + other_side_address: Option<&[u8]>, + ) -> Result, MmError> { + todo!() + } + + fn derive_htlc_key_pair(&self, _swap_unique_data: &[u8]) -> keys::KeyPair { todo!() } +} + +#[cfg_attr(test, mocktopus::macros::mockable)] +impl MarketCoinOps for Erc20Token { + fn ticker(&self) -> &str { todo!() } + + fn my_address(&self) -> Result { todo!() } + + fn get_public_key(&self) -> Result> { todo!() } + + fn sign_message_hash(&self, message: &str) -> Option<[u8; 32]> { todo!() } + + fn sign_message(&self, message: &str) -> SignatureResult { todo!() } + + fn verify_message(&self, signature: &str, message: &str, address: &str) -> VerificationResult { todo!() } + + fn my_balance(&self) -> BalanceFut { todo!() } + + fn base_coin_balance(&self) -> BalanceFut { todo!() } + + fn platform_ticker(&self) -> &str { todo!() } + + fn send_raw_tx(&self, mut tx: &str) -> Box + Send> { todo!() } + + fn send_raw_tx_bytes(&self, tx: &[u8]) -> Box + Send> { todo!() } + + fn wait_for_confirmations( + &self, + tx: &[u8], + confirmations: u64, + _requires_nota: bool, + wait_until: u64, + check_every: u64, + ) -> Box + Send> { + todo!() + } + + fn wait_for_tx_spend( + &self, + tx_bytes: &[u8], + wait_until: u64, + from_block: u64, + swap_contract_address: &Option, + ) -> TransactionFut { + todo!() + } + + fn tx_enum_from_bytes(&self, bytes: &[u8]) -> Result { todo!() } + + fn current_block(&self) -> Box + Send> { todo!() } + + fn display_priv_key(&self) -> Result { todo!() } + + fn min_tx_amount(&self) -> BigDecimal { todo!() } + + fn min_trading_vol(&self) -> MmNumber { todo!() } +} diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 41452a9cfd..72d523d1ad 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -38,6 +38,7 @@ use common::mm_metrics::MetricsWeak; use common::{calc_total_pages, now_ms, ten, HttpStatusCode}; use crypto::{Bip32Error, CryptoCtx, DerivationPath}; use derive_more::Display; +use eth::erc20::Erc20Token; use futures::compat::Future01CompatExt; use futures::lock::Mutex as AsyncMutex; use futures::{FutureExt, TryFutureExt}; @@ -1787,6 +1788,7 @@ pub enum MmCoinEnum { QtumCoin(QtumCoin), Qrc20Coin(Qrc20Coin), EthCoin(EthCoin), + Erc20Token(Erc20Token), #[cfg(not(target_arch = "wasm32"))] ZCoin(ZCoin), Bch(BchCoin), @@ -1808,6 +1810,10 @@ impl From for MmCoinEnum { fn from(c: EthCoin) -> MmCoinEnum { MmCoinEnum::EthCoin(c) } } +impl From for MmCoinEnum { + fn from(c: Erc20Token) -> MmCoinEnum { MmCoinEnum::Erc20Token(c) } +} + impl From for MmCoinEnum { fn from(c: TestCoin) -> MmCoinEnum { MmCoinEnum::Test(c) } } @@ -1868,6 +1874,7 @@ impl Deref for MmCoinEnum { MmCoinEnum::SolanaCoin(ref c) => c, #[cfg(not(target_arch = "wasm32"))] MmCoinEnum::SplToken(ref c) => c, + MmCoinEnum::Erc20Token(ref c) => c, } } } diff --git a/mm2src/coins/rpc_command/activate_eth_coin.rs b/mm2src/coins/rpc_command/activate_eth_coin.rs index 5d4440a051..983d306ec4 100644 --- a/mm2src/coins/rpc_command/activate_eth_coin.rs +++ b/mm2src/coins/rpc_command/activate_eth_coin.rs @@ -1,5 +1,5 @@ use crate::{coin_conf, - eth::{eth_coin_from_conf_and_request_v2, GasStationPricePolicy, EthActivationRequest}, + eth::{eth_coin_from_conf_and_request_v2, EthActivationRequest, GasStationPricePolicy}, lp_register_coin, CoinProtocol, MmCoinEnum, RegisterCoinParams}; use common::{HttpStatusCode, StatusCode}; use crypto::CryptoCtx; @@ -81,7 +81,8 @@ pub async fn activate_eth_coin(ctx: &MmArc, req: EthActivationRequest) -> MmResu .map_err(|e| EnableV2RpcError::CoinCouldNotInitialized(e.to_string()))?; let coin: MmCoinEnum = eth_coin_from_conf_and_request_v2(ctx, &req.coin, &coins_en, req.clone(), &secret, protocol) - .await.unwrap() + .await + .unwrap() .into(); let register_params = RegisterCoinParams { diff --git a/mm2src/coins_activation/src/erc20_token_activation.rs b/mm2src/coins_activation/src/erc20_token_activation.rs index 8b1080f222..9ef55c7022 100644 --- a/mm2src/coins_activation/src/erc20_token_activation.rs +++ b/mm2src/coins_activation/src/erc20_token_activation.rs @@ -1,6 +1,5 @@ use serde::Deserialize; - #[derive(Clone, Debug, Deserialize)] pub struct Erc20ActivationRequest { pub required_confirmations: Option, diff --git a/mm2src/coins_activation/src/lib.rs b/mm2src/coins_activation/src/lib.rs index 02cc0bf714..d6af0ae421 100644 --- a/mm2src/coins_activation/src/lib.rs +++ b/mm2src/coins_activation/src/lib.rs @@ -1,7 +1,7 @@ mod bch_with_tokens_activation; mod context; -mod eth_with_token_activation; mod erc20_token_activation; +mod eth_with_token_activation; mod l2; #[cfg(not(target_arch = "wasm32"))] mod lightning_activation; mod platform_coin_with_tokens; diff --git a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs index 058ad4779b..0825f253c7 100644 --- a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs +++ b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs @@ -1,6 +1,7 @@ use crate::mm2::{lp_network::subscribe_to_topic, lp_swap::tx_helper_topic}; -use coins::{rpc_command::activate_eth_coin::{activate_eth_coin, EnableV2RpcError, EnableV2RpcRequest, - EnableV2RpcResponse}, eth::EthActivationRequest}; +use coins::{eth::EthActivationRequest, + rpc_command::activate_eth_coin::{activate_eth_coin, EnableV2RpcError, EnableV2RpcRequest, + EnableV2RpcResponse}}; use common::{Future01CompatExt, HttpStatusCode}; use crypto::{CryptoCtx, CryptoInitError}; use derive_more::Display; From 38430a95036234738c23ada8d73ff0e0fc555783 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 20 Jul 2022 00:54:55 +0300 Subject: [PATCH 29/69] save p.o.c state Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 2 +- .../src/eth_with_token_activation.rs | 104 +++++++++++++++--- 2 files changed, 91 insertions(+), 15 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 2ffb22e0c9..2a00f58345 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -351,7 +351,7 @@ pub struct EthCoinImpl { required_confirmations: AtomicU64, /// Coin needs access to the context in order to reuse the logging and shutdown facilities. /// Using a weak reference by default in order to avoid circular references and leaks. - ctx: MmWeak, + pub ctx: MmWeak, chain_id: Option, /// the block range used for eth_getLogs logs_block_range: u64, diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 859a3f2ad2..a2a4c3434c 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -1,23 +1,26 @@ use std::collections::HashMap; +use crate::{erc20_token_activation::Erc20ActivationRequest, + platform_coin_with_tokens::{EnablePlatformCoinWithTokensError, GetPlatformBalance, + PlatformWithTokensActivationOps, RegisterTokenInfo, TokenActivationParams, + TokenActivationRequest, TokenAsMmCoinInitializer, TokenInitializer, TokenOf}, + prelude::*}; use async_trait::async_trait; use coins::{coin_conf, eth::{eth_coin_from_conf_and_request_v2, valid_addr_from_str, EthActivationRequest, EthActivationV2Error, EthCoin, EthCoinType}, + lp_register_coin, my_tx_history_v2::TxHistoryStorage, - CoinBalance, CoinProtocol, MarketCoinOps}; + CoinBalance, CoinProtocol, MarketCoinOps, MmCoin, MmCoinEnum, RegisterCoinParams}; use common::{log::info, mm_metrics::MetricsArc, Future01CompatExt}; +use crypto::CryptoCtx; use futures::future::AbortHandle; -use mm2_core::mm_ctx::MmArc; +use mm2_core::mm_ctx::{MmArc, MmCtxBuilder}; use mm2_err_handle::prelude::*; use mm2_number::BigDecimal; use serde::{Deserialize, Serialize}; use serde_json::Value as Json; -use crate::{platform_coin_with_tokens::{EnablePlatformCoinWithTokensError, GetPlatformBalance, - PlatformWithTokensActivationOps, TokenAsMmCoinInitializer}, - prelude::*}; - pub struct Erc20Initializer { platform_coin: EthCoin, } @@ -26,6 +29,73 @@ pub struct EthProtocolInfo { coin_type: EthCoinType, decimals: u8, } +impl TokenOf for EthCoin { + type PlatformCoin = EthCoin; +} + +impl RegisterTokenInfo for EthCoin { + fn register_token_info(&self, token: &EthCoin) { + // self.add_slp_token_info(token.ticker().into(), token.get_info()) + } +} + +#[async_trait] +impl TokenInitializer for Erc20Initializer { + type Token = EthCoin; + type TokenActivationRequest = EthActivationRequest; + type TokenProtocol = EthProtocolInfo; + type InitTokensError = std::convert::Infallible; + + fn tokens_requests_from_platform_request( + platform_params: &EthWithTokensActivationRequest, + ) -> Vec> { + platform_params.erc20_tokens_requests.clone() + } + + async fn enable_tokens( + &self, + activation_params: Vec>, + ) -> Result, MmError> { + let ctx = MmArc::from_weak(&self.platform_coin.ctx).clone().unwrap(); + let secret = CryptoCtx::from_ctx(&ctx) + .unwrap() + .iguana_ctx() + .secp256k1_privkey_bytes() + .to_vec(); + + let mut tokens = vec![]; + for param in activation_params { + let coins_en = coin_conf(&ctx, ¶m.activation_request.coin); + let protocol: CoinProtocol = serde_json::from_value(coins_en["protocol"].clone()).unwrap(); + let coin: EthCoin = eth_coin_from_conf_and_request_v2( + &ctx, + ¶m.activation_request.coin, + &coins_en, + param.activation_request.clone(), + &secret, + protocol, + ) + .await + .unwrap() + .into(); + + let register_params = RegisterCoinParams { + ticker: param.activation_request.coin, + tx_history: param.activation_request.tx_history.unwrap_or(false), + }; + + lp_register_coin(&ctx, MmCoinEnum::EthCoin(coin.clone()), register_params) + .await + .unwrap(); + + tokens.push(coin); + } + + Ok(tokens) + } + + fn platform_coin(&self) -> &EthCoin { &self.platform_coin } +} impl TryFromCoinProtocol for EthProtocolInfo { fn try_from_coin_protocol(proto: CoinProtocol) -> Result> @@ -37,6 +107,16 @@ impl TryFromCoinProtocol for EthProtocolInfo { coin_type: EthCoinType::Eth, decimals: 18, }), + CoinProtocol::ERC20 { + platform, + contract_address, + } => { + let token_addr = valid_addr_from_str(&contract_address).unwrap(); + Ok(EthProtocolInfo { + coin_type: EthCoinType::Erc20 { platform, token_addr }, + decimals: 18, + }) + }, protocol => MmError::err(protocol), } } @@ -80,9 +160,7 @@ impl From for EnablePlatformCoinWithTokensError { pub struct EthWithTokensActivationRequest { #[serde(flatten)] platform_request: EthActivationRequest, - erc20_tokens_requests: Vec< - crate::platform_coin_with_tokens::TokenActivationRequest, - >, + erc20_tokens_requests: Vec>, } impl TxHistory for EthWithTokensActivationRequest { @@ -150,11 +228,9 @@ impl PlatformWithTokensActivationOps for EthCoin { fn token_initializers( &self, ) -> Vec>> { - vec![] - - // vec![Box::new(Erc20Initializer { - // platform_coin: self.clone(), - // })] + vec![Box::new(Erc20Initializer { + platform_coin: self.clone(), + })] } async fn get_activation_result(&self) -> Result> { From 8eed30b4d3243fe2ef013b26b9ffb41e12481f55 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 20 Jul 2022 14:04:53 +0300 Subject: [PATCH 30/69] save development state Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 65 ++++++++++++++- .../src/eth_with_token_activation.rs | 81 +++++++++---------- 2 files changed, 100 insertions(+), 46 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 2a00f58345..6cbd896514 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -53,7 +53,7 @@ use std::ops::Deref; use std::path::PathBuf; use std::str::FromStr; use std::sync::atomic::{AtomicU64, Ordering as AtomicOrdering}; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, MutexGuard}; use web3::types::{Action as TraceAction, BlockId, BlockNumber, Bytes, CallRequest, FilterBuilder, Log, Trace, TraceFilterBuilder, Transaction as Web3Transaction, TransactionId}; use web3::{self, Web3}; @@ -336,9 +336,9 @@ pub struct EthCoinImpl { ticker: String, coin_type: EthCoinType, key_pair: KeyPair, - my_address: Address, + pub my_address: Address, sign_message_prefix: Option, - swap_contract_address: Address, + pub swap_contract_address: Address, fallback_swap_contract: Option
, web3: Web3, /// The separate web3 instances kept to get nonce, will replace the web3 completely soon @@ -356,6 +356,7 @@ pub struct EthCoinImpl { /// the block range used for eth_getLogs logs_block_range: u64, nonce_lock: Arc>, + erc20_tokens_infos: Arc>>, } #[derive(Clone, Debug)] @@ -364,6 +365,12 @@ pub struct Web3Instance { is_parity: bool, } +#[derive(Clone, Debug)] +pub struct Erc20TokenInfo { + pub token_address: Address, + pub decimals: u8, +} + #[derive(Deserialize, Serialize)] #[serde(tag = "format")] pub enum EthAddressFormat { @@ -582,6 +589,14 @@ impl EthCoinImpl { pub fn address_from_str(&self, address: &str) -> Result { Ok(try_s!(valid_addr_from_str(address))) } + + pub async fn add_erc_token_info(&self, ticker: String, info: Erc20TokenInfo) { + self.erc20_tokens_infos.lock().await.insert(ticker, info); + } + + pub async fn get_erc_tokens_infos(&self) -> tokio::sync::MutexGuard<'_, HashMap> { + self.erc20_tokens_infos.lock().await + } } async fn get_raw_transaction_impl(coin: EthCoin, req: RawTransactionRequest) -> RawTransactionResult { @@ -2517,6 +2532,48 @@ impl EthCoin { Box::new(fut.boxed().compat()) } + pub async fn get_tokens_balance_list(&self) -> HashMap { + let coin = self.clone(); + let mut token_balances = HashMap::new(); + for (token_ticker, info) in self.get_erc_tokens_infos().await.iter() { + let balance: CoinBalance = coin + .get_token_balance_by_address(info.clone()) + .and_then(move |result| Ok(u256_to_big_decimal(result, info.decimals)?)) + .map(|spendable| CoinBalance { + spendable, + unspendable: BigDecimal::from(0), + }) + .compat() + .await + .unwrap(); + token_balances.insert(token_ticker.clone(), balance); + } + + token_balances + } + + pub fn get_token_balance_by_address(&self, token: Erc20TokenInfo) -> BalanceFut { + let coin = self.clone(); + let fut = async move { + let function = ERC20_CONTRACT.function("balanceOf")?; + let data = function.encode_input(&[Token::Address(coin.my_address)])?; + let res = coin + .call_request(token.token_address, None, Some(data.into())) + .compat() + .await?; + let decoded = function.decode_output(&res.0)?; + match decoded[0] { + Token::Uint(number) => Ok(number), + _ => { + let error = format!("Expected U256 as balanceOf result but got {:?}", decoded); + MmError::err(BalanceError::InvalidResponse(error)) + }, + } + }; + + Box::new(fut.boxed().compat()) + } + /// Estimates how much gas is necessary to allow the contract call to complete. /// `contract_addr` can be a ERC20 token address or any other contract address. /// @@ -3600,6 +3657,7 @@ pub async fn eth_coin_from_conf_and_request_v2( chain_id: conf["chain_id"].as_u64(), logs_block_range: conf["logs_block_range"].as_u64().unwrap_or(DEFAULT_LOGS_BLOCK_RANGE), nonce_lock, + erc20_tokens_infos: Default::default(), }; Ok(EthCoin(Arc::new(coin))) @@ -3736,6 +3794,7 @@ pub async fn eth_coin_from_conf_and_request( chain_id: conf["chain_id"].as_u64(), logs_block_range: conf["logs_block_range"].as_u64().unwrap_or(DEFAULT_LOGS_BLOCK_RANGE), nonce_lock, + erc20_tokens_infos: Default::default(), }; Ok(EthCoin(Arc::new(coin))) } diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index a2a4c3434c..93f29069f5 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -7,10 +7,11 @@ use crate::{erc20_token_activation::Erc20ActivationRequest, prelude::*}; use async_trait::async_trait; use coins::{coin_conf, - eth::{eth_coin_from_conf_and_request_v2, valid_addr_from_str, EthActivationRequest, EthActivationV2Error, - EthCoin, EthCoinType}, + eth::{eth_coin_from_conf_and_request_v2, valid_addr_from_str, Erc20TokenInfo, EthActivationRequest, + EthActivationV2Error, EthCoin, EthCoinType}, lp_register_coin, my_tx_history_v2::TxHistoryStorage, + rpc_command::activate_eth_coin::activate_eth_coin, CoinBalance, CoinProtocol, MarketCoinOps, MmCoin, MmCoinEnum, RegisterCoinParams}; use common::{log::info, mm_metrics::MetricsArc, Future01CompatExt}; use crypto::CryptoCtx; @@ -35,7 +36,11 @@ impl TokenOf for EthCoin { impl RegisterTokenInfo for EthCoin { fn register_token_info(&self, token: &EthCoin) { - // self.add_slp_token_info(token.ticker().into(), token.get_info()) + // self.add_erc_token_info(Erc20TokenInfo { + // token_address: token.my_address, + // decimals: token.decimals(), + // }) + // .await; } } @@ -56,7 +61,11 @@ impl TokenInitializer for Erc20Initializer { &self, activation_params: Vec>, ) -> Result, MmError> { - let ctx = MmArc::from_weak(&self.platform_coin.ctx).clone().unwrap(); + let ctx = MmArc::from_weak(&self.platform_coin.ctx) + .clone() + .ok_or("No context") + .unwrap(); + let secret = CryptoCtx::from_ctx(&ctx) .unwrap() .iguana_ctx() @@ -79,14 +88,21 @@ impl TokenInitializer for Erc20Initializer { .unwrap() .into(); - let register_params = RegisterCoinParams { - ticker: param.activation_request.coin, - tx_history: param.activation_request.tx_history.unwrap_or(false), - }; + self.platform_coin() + .add_erc_token_info(coin.ticker().to_string(), Erc20TokenInfo { + token_address: coin.swap_contract_address, + decimals: coin.decimals(), + }) + .await; - lp_register_coin(&ctx, MmCoinEnum::EthCoin(coin.clone()), register_params) - .await - .unwrap(); + // let register_params = RegisterCoinParams { + // ticker: param.activation_request.coin, + // tx_history: param.activation_request.tx_history.unwrap_or(false), + // }; + // + // lp_register_coin(&ctx, MmCoinEnum::EthCoin(coin.clone()), register_params) + // .await + // .unwrap(); tokens.push(coin); } @@ -114,7 +130,7 @@ impl TryFromCoinProtocol for EthProtocolInfo { let token_addr = valid_addr_from_str(&contract_address).unwrap(); Ok(EthProtocolInfo { coin_type: EthCoinType::Erc20 { platform, token_addr }, - decimals: 18, + decimals: 6, }) }, protocol => MmError::err(protocol), @@ -124,25 +140,6 @@ impl TryFromCoinProtocol for EthProtocolInfo { impl From for EnablePlatformCoinWithTokensError { fn from(err: EthActivationV2Error) -> Self { - // match err { - // BchWithTokensActivationError::PlatformCoinCreationError { ticker, error } => { - // EnablePlatformCoinWithTokensError::PlatformCoinCreationError { ticker, error } - // }, - // BchWithTokensActivationError::InvalidSlpPrefix { ticker, prefix, error } => { - // EnablePlatformCoinWithTokensError::Internal(format!( - // "Invalid slp prefix {} configured for {}. Error: {}", - // prefix, ticker, error - // )) - // }, - // BchWithTokensActivationError::PrivKeyNotAllowed(e) => { - // EnablePlatformCoinWithTokensError::PrivKeyNotAllowed(e) - // }, - // BchWithTokensActivationError::UnexpectedDerivationMethod(e) => { - // EnablePlatformCoinWithTokensError::UnexpectedDerivationMethod(e) - // }, - // BchWithTokensActivationError::Transport(e) => EnablePlatformCoinWithTokensError::Transport(e), - // BchWithTokensActivationError::Internal(e) => EnablePlatformCoinWithTokensError::Internal(e), - // } match err { EthActivationV2Error::InvalidPayload(e) => EnablePlatformCoinWithTokensError::InvalidPayload(e), EthActivationV2Error::ActivationFailed { ticker, error } => { @@ -245,11 +242,9 @@ impl PlatformWithTokensActivationOps for EthCoin { // let bch_unspents = self.bch_unspents_for_display(my_address).await?; // let bch_balance = bch_unspents.platform_balance(self.decimals()); - // let mut token_balances = HashMap::new(); - // for (token_ticker, info) in self.get_slp_tokens_infos().iter() { - // let token_balance = bch_unspents.slp_token_balance(&info.token_id, info.decimals); - // token_balances.insert(token_ticker.clone(), token_balance); - // } + //let balance = self.my_balance().compat().await.unwrap(); + + let token_balances = self.get_tokens_balance_list().await; let mut result = EthWithTokensActivationResult { current_block, @@ -257,13 +252,13 @@ impl PlatformWithTokensActivationOps for EthCoin { erc20_addresses_infos: HashMap::new(), }; - // result - // .bch_addresses_infos - // .insert(my_address.to_string(), CoinAddressInfo { - // derivation_method: DerivationMethod::Iguana, - // pubkey: self.my_public_key()?.to_string(), - // balances: bch_balance, - // }); + result + .erc20_addresses_infos + .insert(my_address.to_string(), CoinAddressInfo { + derivation_method: DerivationMethod::Iguana, + pubkey: my_address, + balances: token_balances, + }); // result.slp_addresses_infos.insert(my_slp_address, CoinAddressInfo { // derivation_method: DerivationMethod::Iguana, From 0f77653f359fba271f6991c367e9f171efecca60 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 20 Jul 2022 14:20:32 +0300 Subject: [PATCH 31/69] exclude `activate_eth_coin` Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 3 +- mm2src/coins/rpc_command/activate_eth_coin.rs | 98 ------------------- mm2src/coins/rpc_command/mod.rs | 1 - .../src/eth_with_token_activation.rs | 1 - .../mm2_main/src/rpc/dispatcher/dispatcher.rs | 3 +- .../src/rpc/lp_commands/lp_commands.rs | 32 +----- 6 files changed, 3 insertions(+), 135 deletions(-) delete mode 100644 mm2src/coins/rpc_command/activate_eth_coin.rs diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 6cbd896514..a13f3e488b 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -59,8 +59,7 @@ use web3::types::{Action as TraceAction, BlockId, BlockNumber, Bytes, CallReques use web3::{self, Web3}; use web3_transport::{EthFeeHistoryNamespace, Web3Transport, Web3TransportNode}; -use super::{rpc_command::activate_eth_coin::{EnableV2RpcError, EnableV2RpcRequest}, - AsyncMutex, BalanceError, BalanceFut, CoinBalance, CoinProtocol, CoinTransportMetrics, CoinsContext, +use super::{AsyncMutex, BalanceError, BalanceFut, CoinBalance, CoinProtocol, CoinTransportMetrics, CoinsContext, FeeApproxStage, FoundSwapTxSpend, HistorySyncState, MarketCoinOps, MmCoin, NegotiateSwapContractAddrErr, NumConversError, NumConversResult, RawTransactionError, RawTransactionFut, RawTransactionRequest, RawTransactionRes, RawTransactionResult, RpcClientType, RpcTransportEventHandler, diff --git a/mm2src/coins/rpc_command/activate_eth_coin.rs b/mm2src/coins/rpc_command/activate_eth_coin.rs deleted file mode 100644 index 983d306ec4..0000000000 --- a/mm2src/coins/rpc_command/activate_eth_coin.rs +++ /dev/null @@ -1,98 +0,0 @@ -use crate::{coin_conf, - eth::{eth_coin_from_conf_and_request_v2, EthActivationRequest, GasStationPricePolicy}, - lp_register_coin, CoinProtocol, MmCoinEnum, RegisterCoinParams}; -use common::{HttpStatusCode, StatusCode}; -use crypto::CryptoCtx; -use derive_more::Display; -use ethereum_types::Address; -use mm2_core::mm_ctx::MmArc; -use mm2_err_handle::prelude::MmResult; -use mm2_number::BigDecimal; - -#[derive(Debug, Display, Serialize, SerializeErrorType)] -#[serde(tag = "error_type", content = "error_data")] -#[allow(dead_code)] -pub enum EnableV2RpcError { - InvalidPayload(String), - CoinCouldNotInitialized(String), - CouldNotFetchBalance(String), - UnreachableNodes(String), - AtLeastOneNodeRequired(String), - InternalError(String), -} - -impl HttpStatusCode for EnableV2RpcError { - fn status_code(&self) -> StatusCode { - match self { - EnableV2RpcError::InvalidPayload(_) - | EnableV2RpcError::CoinCouldNotInitialized(_) - | EnableV2RpcError::UnreachableNodes(_) - | EnableV2RpcError::AtLeastOneNodeRequired(_) => StatusCode::BAD_REQUEST, - EnableV2RpcError::CouldNotFetchBalance(_) => StatusCode::SERVICE_UNAVAILABLE, - _ => StatusCode::INTERNAL_SERVER_ERROR, - } - } -} - -#[derive(Clone, Debug, Deserialize)] -pub struct EnableV2RpcRequest { - pub coin: String, - pub nodes: Vec, - pub swap_contract_address: Address, - pub fallback_swap_contract: Option
, - pub gas_station_url: Option, - pub gas_station_decimals: Option, - #[serde(default)] - pub gas_station_policy: GasStationPricePolicy, - pub mm2: Option, - pub tx_history: Option, - pub required_confirmations: Option, -} - -#[derive(Clone, Debug, Deserialize)] -pub struct EnableV2NodesRpc { - pub url: String, - pub gui_auth: bool, -} - -#[derive(Serialize, Clone)] -pub struct EnableV2RpcResponse { - pub result: String, - pub address: String, - pub balance: BigDecimal, - pub unspendable_balance: BigDecimal, - pub coin: String, - pub required_confirmations: u64, - pub requires_notarization: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub mature_confirmations: Option, -} - -pub async fn activate_eth_coin(ctx: &MmArc, req: EthActivationRequest) -> MmResult { - let secret = CryptoCtx::from_ctx(ctx) - .map_err(|e| EnableV2RpcError::InternalError(e.to_string()))? - .iguana_ctx() - .secp256k1_privkey_bytes() - .to_vec(); - - let coins_en = coin_conf(ctx, &req.coin); - - let protocol: CoinProtocol = serde_json::from_value(coins_en["protocol"].clone()) - .map_err(|e| EnableV2RpcError::CoinCouldNotInitialized(e.to_string()))?; - - let coin: MmCoinEnum = eth_coin_from_conf_and_request_v2(ctx, &req.coin, &coins_en, req.clone(), &secret, protocol) - .await - .unwrap() - .into(); - - let register_params = RegisterCoinParams { - ticker: req.coin, - tx_history: req.tx_history.unwrap_or(false), - }; - - lp_register_coin(ctx, coin.clone(), register_params) - .await - .map_err(|e| EnableV2RpcError::CoinCouldNotInitialized(e.to_string()))?; - - Ok(coin) -} diff --git a/mm2src/coins/rpc_command/mod.rs b/mm2src/coins/rpc_command/mod.rs index d59b0ea56a..7a98d3fc2e 100644 --- a/mm2src/coins/rpc_command/mod.rs +++ b/mm2src/coins/rpc_command/mod.rs @@ -1,5 +1,4 @@ pub mod account_balance; -pub mod activate_eth_coin; pub mod hd_account_balance_rpc_error; pub mod init_create_account; pub mod init_scan_for_new_addresses; diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 93f29069f5..a679090f4a 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -11,7 +11,6 @@ use coins::{coin_conf, EthActivationV2Error, EthCoin, EthCoinType}, lp_register_coin, my_tx_history_v2::TxHistoryStorage, - rpc_command::activate_eth_coin::activate_eth_coin, CoinBalance, CoinProtocol, MarketCoinOps, MmCoin, MmCoinEnum, RegisterCoinParams}; use common::{log::info, mm_metrics::MetricsArc, Future01CompatExt}; use crypto::CryptoCtx; diff --git a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs index 4f462ab12d..9e867188b7 100644 --- a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs +++ b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs @@ -1,4 +1,4 @@ -use super::{lp_commands::activate_eth_coin_wrapper, DispatcherError, DispatcherResult, PUBLIC_METHODS}; +use super::{DispatcherError, DispatcherResult, PUBLIC_METHODS}; use crate::mm2::lp_native_dex::init_hw::{init_trezor, init_trezor_status, init_trezor_user_action}; use crate::mm2::lp_ordermatch::{best_orders_rpc_v2, orderbook_rpc_v2, start_simple_market_maker_bot, stop_simple_market_maker_bot}; @@ -124,7 +124,6 @@ async fn dispatcher_v2(request: MmRpcRequest, ctx: MmArc) -> DispatcherResult handle_mmrpc(ctx, request, add_delegation).await, "add_node_to_version_stat" => handle_mmrpc(ctx, request, add_node_to_version_stat).await, "best_orders" => handle_mmrpc(ctx, request, best_orders_rpc_v2).await, - "activate_eth_coin" => handle_mmrpc(ctx, request, activate_eth_coin_wrapper).await, "enable_bch_with_tokens" => handle_mmrpc(ctx, request, enable_platform_coin_with_tokens::).await, "enable_eth_with_tokens" => handle_mmrpc(ctx, request, enable_platform_coin_with_tokens::).await, "enable_slp" => handle_mmrpc(ctx, request, enable_token::).await, diff --git a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs index 0825f253c7..dc692bef28 100644 --- a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs +++ b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs @@ -1,7 +1,5 @@ use crate::mm2::{lp_network::subscribe_to_topic, lp_swap::tx_helper_topic}; -use coins::{eth::EthActivationRequest, - rpc_command::activate_eth_coin::{activate_eth_coin, EnableV2RpcError, EnableV2RpcRequest, - EnableV2RpcResponse}}; +use coins::eth::EthActivationRequest; use common::{Future01CompatExt, HttpStatusCode}; use crypto::{CryptoCtx, CryptoInitError}; use derive_more::Display; @@ -50,31 +48,3 @@ pub async fn get_public_key_hash(ctx: MmArc, _req: Json) -> GetPublicKeyRpcResul let public_key_hash = ctx.rmd160().to_owned().into(); Ok(GetPublicKeyHashResponse { public_key_hash }) } - -pub async fn activate_eth_coin_wrapper( - ctx: MmArc, - req: EthActivationRequest, -) -> MmResult { - let coin = activate_eth_coin(&ctx, req).await.unwrap(); - - let balance = coin - .my_balance() - .compat() - .await - .map_err(|e| EnableV2RpcError::CouldNotFetchBalance(e.to_string()))?; - - if coin.is_utxo_in_native_mode() { - subscribe_to_topic(&ctx, tx_helper_topic(coin.ticker())); - } - - Ok(EnableV2RpcResponse { - result: String::from("success"), - address: coin.my_address().map_err(EnableV2RpcError::InternalError)?, - balance: balance.spendable, - unspendable_balance: balance.unspendable, - coin: coin.ticker().to_string(), - required_confirmations: coin.required_confirmations(), - requires_notarization: coin.requires_notarization(), - mature_confirmations: coin.mature_confirmations(), - }) -} From 4e995785700d903ba73aede6eb7348515d43aa39 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 20 Jul 2022 14:28:00 +0300 Subject: [PATCH 32/69] finalize `eth_and_erc20_activations` functionality Signed-off-by: ozkanonur --- .../src/eth_with_token_activation.rs | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index a679090f4a..888604f430 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -1,7 +1,4 @@ -use std::collections::HashMap; - -use crate::{erc20_token_activation::Erc20ActivationRequest, - platform_coin_with_tokens::{EnablePlatformCoinWithTokensError, GetPlatformBalance, +use crate::{platform_coin_with_tokens::{EnablePlatformCoinWithTokensError, GetPlatformBalance, PlatformWithTokensActivationOps, RegisterTokenInfo, TokenActivationParams, TokenActivationRequest, TokenAsMmCoinInitializer, TokenInitializer, TokenOf}, prelude::*}; @@ -12,14 +9,15 @@ use coins::{coin_conf, lp_register_coin, my_tx_history_v2::TxHistoryStorage, CoinBalance, CoinProtocol, MarketCoinOps, MmCoin, MmCoinEnum, RegisterCoinParams}; -use common::{log::info, mm_metrics::MetricsArc, Future01CompatExt}; +use common::{mm_metrics::MetricsArc, Future01CompatExt}; use crypto::CryptoCtx; use futures::future::AbortHandle; -use mm2_core::mm_ctx::{MmArc, MmCtxBuilder}; +use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use mm2_number::BigDecimal; use serde::{Deserialize, Serialize}; use serde_json::Value as Json; +use std::collections::HashMap; pub struct Erc20Initializer { platform_coin: EthCoin, @@ -34,7 +32,7 @@ impl TokenOf for EthCoin { } impl RegisterTokenInfo for EthCoin { - fn register_token_info(&self, token: &EthCoin) { + fn register_token_info(&self, _token: &EthCoin) { // self.add_erc_token_info(Erc20TokenInfo { // token_address: token.my_address, // decimals: token.decimals(), @@ -94,14 +92,14 @@ impl TokenInitializer for Erc20Initializer { }) .await; - // let register_params = RegisterCoinParams { - // ticker: param.activation_request.coin, - // tx_history: param.activation_request.tx_history.unwrap_or(false), - // }; - // - // lp_register_coin(&ctx, MmCoinEnum::EthCoin(coin.clone()), register_params) - // .await - // .unwrap(); + let register_params = RegisterCoinParams { + ticker: param.activation_request.coin, + tx_history: param.activation_request.tx_history.unwrap_or(false), + }; + + lp_register_coin(&ctx, MmCoinEnum::EthCoin(coin.clone()), register_params) + .await + .unwrap(); tokens.push(coin); } @@ -241,7 +239,7 @@ impl PlatformWithTokensActivationOps for EthCoin { // let bch_unspents = self.bch_unspents_for_display(my_address).await?; // let bch_balance = bch_unspents.platform_balance(self.decimals()); - //let balance = self.my_balance().compat().await.unwrap(); + let eth_balance = self.my_balance().compat().await.unwrap(); let token_balances = self.get_tokens_balance_list().await; @@ -251,6 +249,14 @@ impl PlatformWithTokensActivationOps for EthCoin { erc20_addresses_infos: HashMap::new(), }; + result + .eth_addresses_infos + .insert(my_address.to_string(), CoinAddressInfo { + derivation_method: DerivationMethod::Iguana, + pubkey: my_address.clone(), + balances: eth_balance, + }); + result .erc20_addresses_infos .insert(my_address.to_string(), CoinAddressInfo { @@ -259,11 +265,6 @@ impl PlatformWithTokensActivationOps for EthCoin { balances: token_balances, }); - // result.slp_addresses_infos.insert(my_slp_address, CoinAddressInfo { - // derivation_method: DerivationMethod::Iguana, - // pubkey: self.my_public_key()?.to_string(), - // balances: token_balances, - // }); Ok(result) } From 933e4397a236bef2bb86018557af6621ef681b67 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 20 Jul 2022 18:54:01 +0300 Subject: [PATCH 33/69] save development state Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 4 +- mm2src/coins/eth/erc20.rs | 273 ------------------ mm2src/coins/lp_coins.rs | 7 - .../src/eth_with_token_activation.rs | 118 ++++---- 4 files changed, 55 insertions(+), 347 deletions(-) delete mode 100644 mm2src/coins/eth/erc20.rs diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index a13f3e488b..f751bd5358 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -53,7 +53,7 @@ use std::ops::Deref; use std::path::PathBuf; use std::str::FromStr; use std::sync::atomic::{AtomicU64, Ordering as AtomicOrdering}; -use std::sync::{Arc, Mutex, MutexGuard}; +use std::sync::{Arc, Mutex}; use web3::types::{Action as TraceAction, BlockId, BlockNumber, Bytes, CallRequest, FilterBuilder, Log, Trace, TraceFilterBuilder, Transaction as Web3Transaction, TransactionId}; use web3::{self, Web3}; @@ -71,7 +71,6 @@ use super::{AsyncMutex, BalanceError, BalanceFut, CoinBalance, CoinProtocol, Coi pub use rlp; -pub mod erc20; #[cfg(test)] mod eth_tests; #[cfg(target_arch = "wasm32")] mod eth_wasm_tests; mod web3_transport; @@ -281,7 +280,6 @@ impl HttpStatusCode for EthActivationV2Error { #[derive(Clone, Debug, Deserialize)] pub struct EthActivationRequest { - pub coin: String, pub nodes: Vec, pub swap_contract_address: Address, pub fallback_swap_contract: Option
, diff --git a/mm2src/coins/eth/erc20.rs b/mm2src/coins/eth/erc20.rs deleted file mode 100644 index 0b4d43a89e..0000000000 --- a/mm2src/coins/eth/erc20.rs +++ /dev/null @@ -1,273 +0,0 @@ -use super::EthCoin; -use crate::{BalanceFut, CoinBalance, FeeApproxStage, FoundSwapTxSpend, HistorySyncState, MarketCoinOps, MmCoin, - NegotiateSwapContractAddrErr, RawTransactionFut, RawTransactionRequest, SearchForSwapTxSpendInput, - SignatureResult, SwapOps, TradeFee, TradePreimageFut, TradePreimageResult, TradePreimageValue, - TransactionEnum, TransactionFut, UnexpectedDerivationMethod, ValidateAddressResult, ValidatePaymentInput, - VerificationResult, WithdrawFut, WithdrawRequest}; -use async_trait::async_trait; -use ethereum_types::Address; -use futures01::Future; -use mm2_core::mm_ctx::MmArc; -use mm2_err_handle::prelude::*; -use mm2_number::{BigDecimal, MmNumber}; -use rpc::v1::types::Bytes as BytesJson; -use serde_json::Value as Json; -use std::sync::Arc; - -#[derive(Clone, Debug)] -pub struct Erc20TokenConf { - pub decimals: u8, - pub ticker: String, - pub token_contract_address: Address, -} - -#[derive(Clone, Debug)] -pub struct Erc20Token { - pub conf: Arc, - pub platform_coin: EthCoin, -} - -#[async_trait] -impl MmCoin for Erc20Token { - fn is_asset_chain(&self) -> bool { todo!() } - - fn get_raw_transaction(&self, req: RawTransactionRequest) -> RawTransactionFut { todo!() } - - fn withdraw(&self, req: WithdrawRequest) -> WithdrawFut { todo!() } - - fn decimals(&self) -> u8 { todo!() } - - fn convert_to_address(&self, from: &str, to_address_format: Json) -> Result { todo!() } - - fn validate_address(&self, address: &str) -> ValidateAddressResult { todo!() } - - fn process_history_loop(&self, ctx: MmArc) -> Box + Send> { todo!() } - - fn history_sync_status(&self) -> HistorySyncState { todo!() } - - fn get_trade_fee(&self) -> Box + Send> { todo!() } - - async fn get_sender_trade_fee( - &self, - value: TradePreimageValue, - stage: FeeApproxStage, - ) -> TradePreimageResult { - todo!() - } - - fn get_receiver_trade_fee(&self, stage: FeeApproxStage) -> TradePreimageFut { todo!() } - - async fn get_fee_to_send_taker_fee( - &self, - dex_fee_amount: BigDecimal, - stage: FeeApproxStage, - ) -> TradePreimageResult { - todo!() - } - - fn required_confirmations(&self) -> u64 { todo!() } - - fn requires_notarization(&self) -> bool { todo!() } - - fn set_required_confirmations(&self, confirmations: u64) { todo!() } - - fn set_requires_notarization(&self, _requires_nota: bool) { todo!() } - - fn swap_contract_address(&self) -> Option { todo!() } - - fn mature_confirmations(&self) -> Option { todo!() } - - fn coin_protocol_info(&self) -> Vec { todo!() } - - fn is_coin_protocol_supported(&self, _info: &Option>) -> bool { todo!() } -} - -#[async_trait] -impl SwapOps for Erc20Token { - fn send_taker_fee(&self, fee_addr: &[u8], amount: BigDecimal, _uuid: &[u8]) -> TransactionFut { todo!() } - - fn send_maker_payment( - &self, - time_lock: u32, - taker_pub: &[u8], - secret_hash: &[u8], - amount: BigDecimal, - swap_contract_address: &Option, - _swap_unique_data: &[u8], - ) -> TransactionFut { - todo!() - } - - fn send_taker_payment( - &self, - time_lock: u32, - maker_pub: &[u8], - secret_hash: &[u8], - amount: BigDecimal, - swap_contract_address: &Option, - _swap_unique_data: &[u8], - ) -> TransactionFut { - todo!() - } - - fn send_maker_spends_taker_payment( - &self, - taker_payment_tx: &[u8], - _time_lock: u32, - _taker_pub: &[u8], - secret: &[u8], - swap_contract_address: &Option, - _swap_unique_data: &[u8], - ) -> TransactionFut { - todo!() - } - - fn send_taker_spends_maker_payment( - &self, - maker_payment_tx: &[u8], - _time_lock: u32, - _maker_pub: &[u8], - secret: &[u8], - swap_contract_address: &Option, - _swap_unique_data: &[u8], - ) -> TransactionFut { - todo!() - } - - fn send_taker_refunds_payment( - &self, - taker_payment_tx: &[u8], - _time_lock: u32, - _maker_pub: &[u8], - _secret_hash: &[u8], - swap_contract_address: &Option, - _swap_unique_data: &[u8], - ) -> TransactionFut { - todo!() - } - - fn send_maker_refunds_payment( - &self, - maker_payment_tx: &[u8], - _time_lock: u32, - _taker_pub: &[u8], - _secret_hash: &[u8], - swap_contract_address: &Option, - _swap_unique_data: &[u8], - ) -> TransactionFut { - todo!() - } - - fn validate_fee( - &self, - fee_tx: &TransactionEnum, - expected_sender: &[u8], - fee_addr: &[u8], - amount: &BigDecimal, - min_block_number: u64, - _uuid: &[u8], - ) -> Box + Send> { - todo!() - } - - fn validate_maker_payment(&self, input: ValidatePaymentInput) -> Box + Send> { - todo!() - } - - fn validate_taker_payment(&self, input: ValidatePaymentInput) -> Box + Send> { - todo!() - } - - fn check_if_my_payment_sent( - &self, - time_lock: u32, - _other_pub: &[u8], - secret_hash: &[u8], - from_block: u64, - swap_contract_address: &Option, - _swap_unique_data: &[u8], - ) -> Box, Error = String> + Send> { - todo!() - } - - async fn search_for_swap_tx_spend_my( - &self, - input: SearchForSwapTxSpendInput<'_>, - ) -> Result, String> { - todo!() - } - - async fn search_for_swap_tx_spend_other( - &self, - input: SearchForSwapTxSpendInput<'_>, - ) -> Result, String> { - todo!() - } - - fn extract_secret(&self, _secret_hash: &[u8], spend_tx: &[u8]) -> Result, String> { todo!() } - - fn negotiate_swap_contract_addr( - &self, - other_side_address: Option<&[u8]>, - ) -> Result, MmError> { - todo!() - } - - fn derive_htlc_key_pair(&self, _swap_unique_data: &[u8]) -> keys::KeyPair { todo!() } -} - -#[cfg_attr(test, mocktopus::macros::mockable)] -impl MarketCoinOps for Erc20Token { - fn ticker(&self) -> &str { todo!() } - - fn my_address(&self) -> Result { todo!() } - - fn get_public_key(&self) -> Result> { todo!() } - - fn sign_message_hash(&self, message: &str) -> Option<[u8; 32]> { todo!() } - - fn sign_message(&self, message: &str) -> SignatureResult { todo!() } - - fn verify_message(&self, signature: &str, message: &str, address: &str) -> VerificationResult { todo!() } - - fn my_balance(&self) -> BalanceFut { todo!() } - - fn base_coin_balance(&self) -> BalanceFut { todo!() } - - fn platform_ticker(&self) -> &str { todo!() } - - fn send_raw_tx(&self, mut tx: &str) -> Box + Send> { todo!() } - - fn send_raw_tx_bytes(&self, tx: &[u8]) -> Box + Send> { todo!() } - - fn wait_for_confirmations( - &self, - tx: &[u8], - confirmations: u64, - _requires_nota: bool, - wait_until: u64, - check_every: u64, - ) -> Box + Send> { - todo!() - } - - fn wait_for_tx_spend( - &self, - tx_bytes: &[u8], - wait_until: u64, - from_block: u64, - swap_contract_address: &Option, - ) -> TransactionFut { - todo!() - } - - fn tx_enum_from_bytes(&self, bytes: &[u8]) -> Result { todo!() } - - fn current_block(&self) -> Box + Send> { todo!() } - - fn display_priv_key(&self) -> Result { todo!() } - - fn min_tx_amount(&self) -> BigDecimal { todo!() } - - fn min_trading_vol(&self) -> MmNumber { todo!() } -} diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 72d523d1ad..41452a9cfd 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -38,7 +38,6 @@ use common::mm_metrics::MetricsWeak; use common::{calc_total_pages, now_ms, ten, HttpStatusCode}; use crypto::{Bip32Error, CryptoCtx, DerivationPath}; use derive_more::Display; -use eth::erc20::Erc20Token; use futures::compat::Future01CompatExt; use futures::lock::Mutex as AsyncMutex; use futures::{FutureExt, TryFutureExt}; @@ -1788,7 +1787,6 @@ pub enum MmCoinEnum { QtumCoin(QtumCoin), Qrc20Coin(Qrc20Coin), EthCoin(EthCoin), - Erc20Token(Erc20Token), #[cfg(not(target_arch = "wasm32"))] ZCoin(ZCoin), Bch(BchCoin), @@ -1810,10 +1808,6 @@ impl From for MmCoinEnum { fn from(c: EthCoin) -> MmCoinEnum { MmCoinEnum::EthCoin(c) } } -impl From for MmCoinEnum { - fn from(c: Erc20Token) -> MmCoinEnum { MmCoinEnum::Erc20Token(c) } -} - impl From for MmCoinEnum { fn from(c: TestCoin) -> MmCoinEnum { MmCoinEnum::Test(c) } } @@ -1874,7 +1868,6 @@ impl Deref for MmCoinEnum { MmCoinEnum::SolanaCoin(ref c) => c, #[cfg(not(target_arch = "wasm32"))] MmCoinEnum::SplToken(ref c) => c, - MmCoinEnum::Erc20Token(ref c) => c, } } } diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 888604f430..d2000c7615 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -19,28 +19,55 @@ use serde::{Deserialize, Serialize}; use serde_json::Value as Json; use std::collections::HashMap; -pub struct Erc20Initializer { - platform_coin: EthCoin, +impl From for EnablePlatformCoinWithTokensError { + fn from(err: EthActivationV2Error) -> Self { + match err { + EthActivationV2Error::InvalidPayload(e) => EnablePlatformCoinWithTokensError::InvalidPayload(e), + EthActivationV2Error::ActivationFailed { ticker, error } => { + EnablePlatformCoinWithTokensError::PlatformCoinCreationError { ticker, error } + }, + EthActivationV2Error::CouldNotFetchBalance(e) + | EthActivationV2Error::UnreachableNodes(e) + | EthActivationV2Error::AtLeastOneNodeRequired(e) => EnablePlatformCoinWithTokensError::Transport(e), + EthActivationV2Error::InternalError(e) => EnablePlatformCoinWithTokensError::Internal(e), + } + } } pub struct EthProtocolInfo { coin_type: EthCoinType, decimals: u8, } -impl TokenOf for EthCoin { - type PlatformCoin = EthCoin; -} -impl RegisterTokenInfo for EthCoin { - fn register_token_info(&self, _token: &EthCoin) { - // self.add_erc_token_info(Erc20TokenInfo { - // token_address: token.my_address, - // decimals: token.decimals(), - // }) - // .await; +impl TryFromCoinProtocol for EthProtocolInfo { + fn try_from_coin_protocol(proto: CoinProtocol) -> Result> + where + Self: Sized, + { + match proto { + CoinProtocol::ETH => Ok(EthProtocolInfo { + coin_type: EthCoinType::Eth, + decimals: 18, + }), + CoinProtocol::ERC20 { + platform, + contract_address, + } => { + let token_addr = valid_addr_from_str(&contract_address).unwrap(); + Ok(EthProtocolInfo { + coin_type: EthCoinType::Erc20 { platform, token_addr }, + decimals: 6, + }) + }, + protocol => MmError::err(protocol), + } } } +pub struct Erc20Initializer { + platform_coin: EthCoin, +} + #[async_trait] impl TokenInitializer for Erc20Initializer { type Token = EthCoin; @@ -58,10 +85,7 @@ impl TokenInitializer for Erc20Initializer { &self, activation_params: Vec>, ) -> Result, MmError> { - let ctx = MmArc::from_weak(&self.platform_coin.ctx) - .clone() - .ok_or("No context") - .unwrap(); + let ctx = MmArc::from_weak(&self.platform_coin.ctx).ok_or("No context").unwrap(); let secret = CryptoCtx::from_ctx(&ctx) .unwrap() @@ -71,19 +95,18 @@ impl TokenInitializer for Erc20Initializer { let mut tokens = vec![]; for param in activation_params { - let coins_en = coin_conf(&ctx, ¶m.activation_request.coin); + let coins_en = coin_conf(&ctx, ¶m.ticker); let protocol: CoinProtocol = serde_json::from_value(coins_en["protocol"].clone()).unwrap(); let coin: EthCoin = eth_coin_from_conf_and_request_v2( &ctx, - ¶m.activation_request.coin, + ¶m.ticker, &coins_en, param.activation_request.clone(), &secret, protocol, ) .await - .unwrap() - .into(); + .unwrap(); self.platform_coin() .add_erc_token_info(coin.ticker().to_string(), Erc20TokenInfo { @@ -93,7 +116,7 @@ impl TokenInitializer for Erc20Initializer { .await; let register_params = RegisterCoinParams { - ticker: param.activation_request.coin, + ticker: param.ticker, tx_history: param.activation_request.tx_history.unwrap_or(false), }; @@ -110,46 +133,6 @@ impl TokenInitializer for Erc20Initializer { fn platform_coin(&self) -> &EthCoin { &self.platform_coin } } -impl TryFromCoinProtocol for EthProtocolInfo { - fn try_from_coin_protocol(proto: CoinProtocol) -> Result> - where - Self: Sized, - { - match proto { - CoinProtocol::ETH => Ok(EthProtocolInfo { - coin_type: EthCoinType::Eth, - decimals: 18, - }), - CoinProtocol::ERC20 { - platform, - contract_address, - } => { - let token_addr = valid_addr_from_str(&contract_address).unwrap(); - Ok(EthProtocolInfo { - coin_type: EthCoinType::Erc20 { platform, token_addr }, - decimals: 6, - }) - }, - protocol => MmError::err(protocol), - } - } -} - -impl From for EnablePlatformCoinWithTokensError { - fn from(err: EthActivationV2Error) -> Self { - match err { - EthActivationV2Error::InvalidPayload(e) => EnablePlatformCoinWithTokensError::InvalidPayload(e), - EthActivationV2Error::ActivationFailed { ticker, error } => { - EnablePlatformCoinWithTokensError::PlatformCoinCreationError { ticker, error } - }, - EthActivationV2Error::CouldNotFetchBalance(e) - | EthActivationV2Error::UnreachableNodes(e) - | EthActivationV2Error::AtLeastOneNodeRequired(e) => EnablePlatformCoinWithTokensError::Transport(e), - EthActivationV2Error::InternalError(e) => EnablePlatformCoinWithTokensError::Internal(e), - } - } -} - #[derive(Clone, Debug, Deserialize)] pub struct EthWithTokensActivationRequest { #[serde(flatten)] @@ -161,6 +144,16 @@ impl TxHistory for EthWithTokensActivationRequest { fn tx_history(&self) -> bool { self.platform_request.tx_history.unwrap_or(false) } } +impl TokenOf for EthCoin { + type PlatformCoin = EthCoin; +} + +impl RegisterTokenInfo for EthCoin { + fn register_token_info(&self, _token: &EthCoin) { + // handled in enable_tokens for now because of concurrent thread safety reasons + } +} + #[derive(Debug, Serialize)] pub struct EthWithTokensActivationResult { current_block: u64, @@ -236,9 +229,6 @@ impl PlatformWithTokensActivationOps for EthCoin { .await .map_err(EthActivationV2Error::InternalError)?; - // let bch_unspents = self.bch_unspents_for_display(my_address).await?; - // let bch_balance = bch_unspents.platform_balance(self.decimals()); - let eth_balance = self.my_balance().compat().await.unwrap(); let token_balances = self.get_tokens_balance_list().await; From e0d797e72782ab71787d413086004f3969fb8e75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Wed, 20 Jul 2022 21:14:41 +0300 Subject: [PATCH 34/69] save development state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins/eth.rs | 7 ++- .../src/eth_with_token_activation.rs | 52 ++++--------------- .../src/rpc/lp_commands/lp_commands.rs | 4 +- 3 files changed, 14 insertions(+), 49 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index f751bd5358..0ecbe0268b 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -2529,7 +2529,7 @@ impl EthCoin { Box::new(fut.boxed().compat()) } - pub async fn get_tokens_balance_list(&self) -> HashMap { + pub async fn get_tokens_balance_list(&self) -> Result, MmError> { let coin = self.clone(); let mut token_balances = HashMap::new(); for (token_ticker, info) in self.get_erc_tokens_infos().await.iter() { @@ -2541,12 +2541,11 @@ impl EthCoin { unspendable: BigDecimal::from(0), }) .compat() - .await - .unwrap(); + .await?; token_balances.insert(token_ticker.clone(), balance); } - token_balances + Ok(token_balances) } pub fn get_token_balance_by_address(&self, token: Erc20TokenInfo) -> BalanceFut { diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index d2000c7615..54340c4b7e 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -4,8 +4,8 @@ use crate::{platform_coin_with_tokens::{EnablePlatformCoinWithTokensError, GetPl prelude::*}; use async_trait::async_trait; use coins::{coin_conf, - eth::{eth_coin_from_conf_and_request_v2, valid_addr_from_str, Erc20TokenInfo, EthActivationRequest, - EthActivationV2Error, EthCoin, EthCoinType}, + eth::{eth_coin_from_conf_and_request_v2, Erc20TokenInfo, EthActivationRequest, EthActivationV2Error, + EthCoin}, lp_register_coin, my_tx_history_v2::TxHistoryStorage, CoinBalance, CoinProtocol, MarketCoinOps, MmCoin, MmCoinEnum, RegisterCoinParams}; @@ -34,33 +34,12 @@ impl From for EnablePlatformCoinWithTokensError { } } -pub struct EthProtocolInfo { - coin_type: EthCoinType, - decimals: u8, -} - -impl TryFromCoinProtocol for EthProtocolInfo { +impl TryFromCoinProtocol for CoinProtocol { fn try_from_coin_protocol(proto: CoinProtocol) -> Result> where Self: Sized, { - match proto { - CoinProtocol::ETH => Ok(EthProtocolInfo { - coin_type: EthCoinType::Eth, - decimals: 18, - }), - CoinProtocol::ERC20 { - platform, - contract_address, - } => { - let token_addr = valid_addr_from_str(&contract_address).unwrap(); - Ok(EthProtocolInfo { - coin_type: EthCoinType::Erc20 { platform, token_addr }, - decimals: 6, - }) - }, - protocol => MmError::err(protocol), - } + Ok(proto) } } @@ -72,7 +51,7 @@ pub struct Erc20Initializer { impl TokenInitializer for Erc20Initializer { type Token = EthCoin; type TokenActivationRequest = EthActivationRequest; - type TokenProtocol = EthProtocolInfo; + type TokenProtocol = CoinProtocol; type InitTokensError = std::convert::Infallible; fn tokens_requests_from_platform_request( @@ -83,7 +62,7 @@ impl TokenInitializer for Erc20Initializer { async fn enable_tokens( &self, - activation_params: Vec>, + activation_params: Vec>, ) -> Result, MmError> { let ctx = MmArc::from_weak(&self.platform_coin.ctx).ok_or("No context").unwrap(); @@ -96,14 +75,13 @@ impl TokenInitializer for Erc20Initializer { let mut tokens = vec![]; for param in activation_params { let coins_en = coin_conf(&ctx, ¶m.ticker); - let protocol: CoinProtocol = serde_json::from_value(coins_en["protocol"].clone()).unwrap(); let coin: EthCoin = eth_coin_from_conf_and_request_v2( &ctx, ¶m.ticker, &coins_en, param.activation_request.clone(), &secret, - protocol, + param.protocol, ) .await .unwrap(); @@ -178,7 +156,7 @@ impl CurrentBlock for EthWithTokensActivationResult { #[async_trait] impl PlatformWithTokensActivationOps for EthCoin { type ActivationRequest = EthWithTokensActivationRequest; - type PlatformProtocolInfo = EthProtocolInfo; + type PlatformProtocolInfo = CoinProtocol; type ActivationResult = EthWithTokensActivationResult; type ActivationError = EthActivationV2Error; @@ -187,18 +165,9 @@ impl PlatformWithTokensActivationOps for EthCoin { ticker: String, platform_conf: Json, activation_request: Self::ActivationRequest, - _protocol_conf: Self::PlatformProtocolInfo, + protocol: Self::PlatformProtocolInfo, priv_key: &[u8], ) -> Result> { - let coins_en = coin_conf(&ctx, &ticker); - - let protocol: CoinProtocol = serde_json::from_value(coins_en["protocol"].clone()).map_err(|e| { - Self::ActivationError::ActivationFailed { - ticker: ticker.clone(), - error: e.to_string(), - } - })?; - let platform_coin = eth_coin_from_conf_and_request_v2( &ctx, &ticker, @@ -230,8 +199,7 @@ impl PlatformWithTokensActivationOps for EthCoin { .map_err(EthActivationV2Error::InternalError)?; let eth_balance = self.my_balance().compat().await.unwrap(); - - let token_balances = self.get_tokens_balance_list().await; + let token_balances = self.get_tokens_balance_list().await.unwrap(); let mut result = EthWithTokensActivationResult { current_block, diff --git a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs index dc692bef28..6cad4b4dee 100644 --- a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs +++ b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs @@ -1,6 +1,4 @@ -use crate::mm2::{lp_network::subscribe_to_topic, lp_swap::tx_helper_topic}; -use coins::eth::EthActivationRequest; -use common::{Future01CompatExt, HttpStatusCode}; +use common::HttpStatusCode; use crypto::{CryptoCtx, CryptoInitError}; use derive_more::Display; use http::StatusCode; From 38be8058207bdf7309d86610c02589c6816f0aee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Wed, 20 Jul 2022 21:23:29 +0300 Subject: [PATCH 35/69] fix `check --tests` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins/eth/eth_tests.rs | 9 +++++++++ mm2src/coins/eth/eth_wasm_tests.rs | 1 + 2 files changed, 10 insertions(+) diff --git a/mm2src/coins/eth/eth_tests.rs b/mm2src/coins/eth/eth_tests.rs index de92602384..c527cd6e25 100644 --- a/mm2src/coins/eth/eth_tests.rs +++ b/mm2src/coins/eth/eth_tests.rs @@ -73,6 +73,7 @@ fn eth_coin_for_test( chain_id: None, logs_block_range: DEFAULT_LOGS_BLOCK_RANGE, nonce_lock: new_nonce_lock(), + erc20_tokens_infos: Default::default(), })); (ctx, eth_coin) } @@ -244,6 +245,7 @@ fn send_and_refund_erc20_payment() { chain_id: None, logs_block_range: DEFAULT_LOGS_BLOCK_RANGE, nonce_lock: new_nonce_lock(), + erc20_tokens_infos: Default::default(), })); let payment = coin @@ -314,6 +316,7 @@ fn send_and_refund_eth_payment() { chain_id: None, logs_block_range: DEFAULT_LOGS_BLOCK_RANGE, nonce_lock: new_nonce_lock(), + erc20_tokens_infos: Default::default(), })); let payment = coin @@ -408,6 +411,7 @@ fn test_nonce_several_urls() { chain_id: None, logs_block_range: DEFAULT_LOGS_BLOCK_RANGE, nonce_lock: new_nonce_lock(), + erc20_tokens_infos: Default::default(), })); log!("My address {:?}", coin.my_address); @@ -460,6 +464,7 @@ fn test_wait_for_payment_spend_timeout() { chain_id: None, logs_block_range: DEFAULT_LOGS_BLOCK_RANGE, nonce_lock: new_nonce_lock(), + erc20_tokens_infos: Default::default(), }; let coin = EthCoin(Arc::new(coin)); @@ -524,6 +529,7 @@ fn test_search_for_swap_tx_spend_was_spent() { chain_id: None, logs_block_range: DEFAULT_LOGS_BLOCK_RANGE, nonce_lock: new_nonce_lock(), + erc20_tokens_infos: Default::default(), })); // raw transaction bytes of https://ropsten.etherscan.io/tx/0xb1c987e2ac79581bb8718267b5cb49a18274890494299239d1d0dfdb58d6d76a @@ -635,6 +641,7 @@ fn test_search_for_swap_tx_spend_was_refunded() { chain_id: None, logs_block_range: DEFAULT_LOGS_BLOCK_RANGE, nonce_lock: new_nonce_lock(), + erc20_tokens_infos: Default::default(), })); // raw transaction bytes of https://ropsten.etherscan.io/tx/0xe18bbca69dea9a4624e1f5b0b2021d5fe4c8daa03f36084a8ba011b08e5cd938 @@ -1323,6 +1330,7 @@ fn test_message_hash() { chain_id: None, logs_block_range: DEFAULT_LOGS_BLOCK_RANGE, nonce_lock: new_nonce_lock(), + erc20_tokens_infos: Default::default(), })); let message_hash = coin.sign_message_hash("test").unwrap(); @@ -1368,6 +1376,7 @@ fn test_sign_verify_message() { chain_id: None, logs_block_range: DEFAULT_LOGS_BLOCK_RANGE, nonce_lock: new_nonce_lock(), + erc20_tokens_infos: Default::default(), })); let message = "test"; diff --git a/mm2src/coins/eth/eth_wasm_tests.rs b/mm2src/coins/eth/eth_wasm_tests.rs index 53c1e88876..bad5a97e02 100644 --- a/mm2src/coins/eth/eth_wasm_tests.rs +++ b/mm2src/coins/eth/eth_wasm_tests.rs @@ -49,6 +49,7 @@ async fn test_send() { chain_id: None, logs_block_range: DEFAULT_LOGS_BLOCK_RANGE, nonce_lock: new_nonce_lock(), + erc20_tokens_infos: Default::default(), })); let tx = coin .send_maker_payment( From c588ecd9b6733c6c57e7b20ce7f86da41a66c166 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 20 Jul 2022 22:59:31 +0300 Subject: [PATCH 36/69] finish `register_token_info` fn Signed-off-by: ozkanonur --- Cargo.lock | 1 + mm2src/coins_activation/Cargo.toml | 3 +- .../src/erc20_token_activation.rs | 5 --- .../src/eth_with_token_activation.rs | 31 ++++++++++++------- 4 files changed, 22 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index de0ffda994..90188cced3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1149,6 +1149,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", + "tokio", ] [[package]] diff --git a/mm2src/coins_activation/Cargo.toml b/mm2src/coins_activation/Cargo.toml index 89f4ac538d..9c7291f90e 100644 --- a/mm2src/coins_activation/Cargo.toml +++ b/mm2src/coins_activation/Cargo.toml @@ -23,4 +23,5 @@ ser_error = { path = "../derives/ser_error" } ser_error_derive = { path = "../derives/ser_error_derive" } serde = "1.0" serde_derive = "1.0" -serde_json = { version = "1.0", features = ["preserve_order", "raw_value"] } \ No newline at end of file +serde_json = { version = "1.0", features = ["preserve_order", "raw_value"] } +tokio = { version = "1.7" } \ No newline at end of file diff --git a/mm2src/coins_activation/src/erc20_token_activation.rs b/mm2src/coins_activation/src/erc20_token_activation.rs index 9ef55c7022..8b13789179 100644 --- a/mm2src/coins_activation/src/erc20_token_activation.rs +++ b/mm2src/coins_activation/src/erc20_token_activation.rs @@ -1,6 +1 @@ -use serde::Deserialize; -#[derive(Clone, Debug, Deserialize)] -pub struct Erc20ActivationRequest { - pub required_confirmations: Option, -} diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 54340c4b7e..a42349e4b1 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -9,7 +9,7 @@ use coins::{coin_conf, lp_register_coin, my_tx_history_v2::TxHistoryStorage, CoinBalance, CoinProtocol, MarketCoinOps, MmCoin, MmCoinEnum, RegisterCoinParams}; -use common::{mm_metrics::MetricsArc, Future01CompatExt}; +use common::{block_on, mm_metrics::MetricsArc, Future01CompatExt}; use crypto::CryptoCtx; use futures::future::AbortHandle; use mm2_core::mm_ctx::MmArc; @@ -18,6 +18,7 @@ use mm2_number::BigDecimal; use serde::{Deserialize, Serialize}; use serde_json::Value as Json; use std::collections::HashMap; +use tokio::task::block_in_place; impl From for EnablePlatformCoinWithTokensError { fn from(err: EthActivationV2Error) -> Self { @@ -86,13 +87,6 @@ impl TokenInitializer for Erc20Initializer { .await .unwrap(); - self.platform_coin() - .add_erc_token_info(coin.ticker().to_string(), Erc20TokenInfo { - token_address: coin.swap_contract_address, - decimals: coin.decimals(), - }) - .await; - let register_params = RegisterCoinParams { ticker: param.ticker, tx_history: param.activation_request.tx_history.unwrap_or(false), @@ -127,8 +121,14 @@ impl TokenOf for EthCoin { } impl RegisterTokenInfo for EthCoin { - fn register_token_info(&self, _token: &EthCoin) { - // handled in enable_tokens for now because of concurrent thread safety reasons + fn register_token_info(&self, token: &EthCoin) { + block_in_place(|| { + let fut = self.add_erc_token_info(token.ticker().to_string(), Erc20TokenInfo { + token_address: token.swap_contract_address, + decimals: token.decimals(), + }); + block_on(fut); + }); } } @@ -198,8 +198,15 @@ impl PlatformWithTokensActivationOps for EthCoin { .await .map_err(EthActivationV2Error::InternalError)?; - let eth_balance = self.my_balance().compat().await.unwrap(); - let token_balances = self.get_tokens_balance_list().await.unwrap(); + let eth_balance = self + .my_balance() + .compat() + .await + .map_err(|e| EthActivationV2Error::CouldNotFetchBalance(e.to_string()))?; + let token_balances = self + .get_tokens_balance_list() + .await + .map_err(|e| EthActivationV2Error::CouldNotFetchBalance(e.to_string()))?; let mut result = EthWithTokensActivationResult { current_block, From e314ba3a703abe370afa6a5c5601bdb27673bf3b Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Thu, 21 Jul 2022 00:46:43 +0300 Subject: [PATCH 37/69] implement `erc20_token_activation` rpc Signed-off-by: ozkanonur --- .../src/erc20_token_activation.rs | 110 ++++++++++++++++++ mm2src/coins_activation/src/token.rs | 3 + .../mm2_main/src/rpc/dispatcher/dispatcher.rs | 3 +- 3 files changed, 115 insertions(+), 1 deletion(-) diff --git a/mm2src/coins_activation/src/erc20_token_activation.rs b/mm2src/coins_activation/src/erc20_token_activation.rs index 8b13789179..1cc7da516c 100644 --- a/mm2src/coins_activation/src/erc20_token_activation.rs +++ b/mm2src/coins_activation/src/erc20_token_activation.rs @@ -1 +1,111 @@ +use crate::{prelude::TryPlatformCoinFromMmCoinEnum, + token::{EnableTokenError, TokenActivationOps, TokenProtocolParams}}; +use async_trait::async_trait; +use coins::{coin_conf, + eth::{eth_coin_from_conf_and_request_v2, EthActivationRequest, EthActivationV2Error, EthCoin}, + CoinBalance, CoinProtocol, MarketCoinOps, MmCoinEnum}; +use common::Future01CompatExt; +use crypto::CryptoCtx; +use mm2_core::mm_ctx::MmArc; +use mm2_err_handle::prelude::MmError; +use serde::Serialize; +use std::collections::HashMap; +#[derive(Debug, Serialize)] +pub struct Erc20InitResult { + balances: HashMap, + pubkey: String, + platform_coin: String, +} + +impl TokenProtocolParams for CoinProtocol { + fn platform_coin_ticker(&self) -> &str { + match self { + CoinProtocol::ERC20 { platform, .. } => platform, + _ => "ETH", + } + } +} + +impl TryPlatformCoinFromMmCoinEnum for EthCoin { + fn try_from_mm_coin(coin: MmCoinEnum) -> Option + where + Self: Sized, + { + match coin { + MmCoinEnum::EthCoin(coin) => Some(coin), + _ => None, + } + } +} + +impl From for EnableTokenError { + fn from(err: EthActivationV2Error) -> Self { + match err { + EthActivationV2Error::InvalidPayload(e) => EnableTokenError::InvalidPayload(e), + EthActivationV2Error::ActivationFailed { ticker, error } => { + EnableTokenError::Internal(format!("{} activation is failed. {}", ticker, error)) + }, + EthActivationV2Error::AtLeastOneNodeRequired(e) + | EthActivationV2Error::UnreachableNodes(e) + | EthActivationV2Error::CouldNotFetchBalance(e) => EnableTokenError::Transport(e), + EthActivationV2Error::InternalError(e) => EnableTokenError::Internal(e), + } + } +} + +#[async_trait] +impl TokenActivationOps for EthCoin { + type PlatformCoin = EthCoin; + type ActivationParams = EthActivationRequest; + type ProtocolInfo = CoinProtocol; + type ActivationResult = Erc20InitResult; + type ActivationError = EthActivationV2Error; + + async fn enable_token( + ticker: String, + platform_coin: Self::PlatformCoin, + activation_params: Self::ActivationParams, + protocol_conf: Self::ProtocolInfo, + ) -> Result<(Self, Self::ActivationResult), MmError> { + let ctx = MmArc::from_weak(&platform_coin.ctx) + .ok_or("No context") + .map_err(|e| EthActivationV2Error::InternalError(e.to_string()))?; + + let secret = CryptoCtx::from_ctx(&ctx) + .map_err(|e| EthActivationV2Error::InternalError(e.to_string()))? + .iguana_ctx() + .secp256k1_privkey_bytes() + .to_vec(); + + let coins_en = coin_conf(&ctx, &ticker); + let token: EthCoin = eth_coin_from_conf_and_request_v2( + &ctx, + &ticker, + &coins_en, + activation_params.clone(), + &secret, + protocol_conf, + ) + .await?; + + let my_address = token.my_address().map_err(EthActivationV2Error::InternalError)?; + + let balance = token + .my_balance() + .compat() + .await + .map_err(|e| EthActivationV2Error::CouldNotFetchBalance(e.to_string()))?; + + let mut balances = HashMap::new(); + balances.insert(my_address.clone(), balance); + + let init_result = Erc20InitResult { + balances, + pubkey: my_address, + platform_coin: token.platform_ticker().to_owned(), + }; + + Ok((token, init_result)) + } +} diff --git a/mm2src/coins_activation/src/token.rs b/mm2src/coins_activation/src/token.rs index 544c1e0b9b..eb8ad7200f 100644 --- a/mm2src/coins_activation/src/token.rs +++ b/mm2src/coins_activation/src/token.rs @@ -58,6 +58,8 @@ pub enum EnableTokenError { }, #[display(fmt = "{}", _0)] UnexpectedDerivationMethod(UnexpectedDerivationMethod), + #[display(fmt = "{} is not valid payload.", _0)] + InvalidPayload(String), Transport(String), Internal(String), } @@ -151,6 +153,7 @@ impl HttpStatusCode for EnableTokenError { EnableTokenError::TokenIsAlreadyActivated(_) | EnableTokenError::PlatformCoinIsNotActivated(_) | EnableTokenError::TokenConfigIsNotFound { .. } + | EnableTokenError::InvalidPayload { .. } | EnableTokenError::UnexpectedTokenProtocol { .. } => StatusCode::BAD_REQUEST, EnableTokenError::TokenProtocolParseError { .. } | EnableTokenError::UnsupportedPlatformCoin { .. } diff --git a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs index 9e867188b7..32912afd34 100644 --- a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs +++ b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs @@ -125,8 +125,9 @@ async fn dispatcher_v2(request: MmRpcRequest, ctx: MmArc) -> DispatcherResult handle_mmrpc(ctx, request, add_node_to_version_stat).await, "best_orders" => handle_mmrpc(ctx, request, best_orders_rpc_v2).await, "enable_bch_with_tokens" => handle_mmrpc(ctx, request, enable_platform_coin_with_tokens::).await, - "enable_eth_with_tokens" => handle_mmrpc(ctx, request, enable_platform_coin_with_tokens::).await, "enable_slp" => handle_mmrpc(ctx, request, enable_token::).await, + "enable_eth_with_tokens" => handle_mmrpc(ctx, request, enable_platform_coin_with_tokens::).await, + "enable_erc20" => handle_mmrpc(ctx, request, enable_token::).await, "get_new_address" => handle_mmrpc(ctx, request, get_new_address).await, "get_public_key" => handle_mmrpc(ctx, request, get_public_key).await, "get_public_key_hash" => handle_mmrpc(ctx, request, get_public_key_hash).await, From 92c9a71e3015251279c3eff2effd843eb3da843a Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Thu, 21 Jul 2022 10:30:00 +0300 Subject: [PATCH 38/69] map errors for eth/erc20 activation Signed-off-by: ozkanonur --- .../src/eth_with_token_activation.rs | 42 ++++++++++++++----- .../src/platform_coin_with_tokens.rs | 17 +++++++- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index a42349e4b1..391c368af9 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -1,6 +1,7 @@ use crate::{platform_coin_with_tokens::{EnablePlatformCoinWithTokensError, GetPlatformBalance, - PlatformWithTokensActivationOps, RegisterTokenInfo, TokenActivationParams, - TokenActivationRequest, TokenAsMmCoinInitializer, TokenInitializer, TokenOf}, + InitTokensAsMmCoinsError, PlatformWithTokensActivationOps, RegisterTokenInfo, + TokenActivationParams, TokenActivationRequest, TokenAsMmCoinInitializer, + TokenInitializer, TokenOf}, prelude::*}; use async_trait::async_trait; use coins::{coin_conf, @@ -48,12 +49,27 @@ pub struct Erc20Initializer { platform_coin: EthCoin, } +impl From for InitTokensAsMmCoinsError { + fn from(error: EthActivationV2Error) -> Self { + match error { + EthActivationV2Error::InvalidPayload(e) => InitTokensAsMmCoinsError::InvalidPayload(e), + EthActivationV2Error::ActivationFailed { ticker, error } => { + InitTokensAsMmCoinsError::InitializationFailed { ticker, error } + }, + EthActivationV2Error::CouldNotFetchBalance(e) + | EthActivationV2Error::UnreachableNodes(e) + | EthActivationV2Error::AtLeastOneNodeRequired(e) + | EthActivationV2Error::InternalError(e) => InitTokensAsMmCoinsError::Internal(e), + } + } +} + #[async_trait] impl TokenInitializer for Erc20Initializer { type Token = EthCoin; type TokenActivationRequest = EthActivationRequest; type TokenProtocol = CoinProtocol; - type InitTokensError = std::convert::Infallible; + type InitTokensError = EthActivationV2Error; fn tokens_requests_from_platform_request( platform_params: &EthWithTokensActivationRequest, @@ -64,11 +80,13 @@ impl TokenInitializer for Erc20Initializer { async fn enable_tokens( &self, activation_params: Vec>, - ) -> Result, MmError> { - let ctx = MmArc::from_weak(&self.platform_coin.ctx).ok_or("No context").unwrap(); + ) -> Result, MmError> { + let ctx = MmArc::from_weak(&self.platform_coin.ctx) + .ok_or("No context") + .map_err(|e| EthActivationV2Error::InternalError(e.to_string()))?; let secret = CryptoCtx::from_ctx(&ctx) - .unwrap() + .map_err(|e| EthActivationV2Error::InternalError(e.to_string()))? .iguana_ctx() .secp256k1_privkey_bytes() .to_vec(); @@ -82,19 +100,21 @@ impl TokenInitializer for Erc20Initializer { &coins_en, param.activation_request.clone(), &secret, - param.protocol, + param.protocol.clone(), ) - .await - .unwrap(); + .await?; let register_params = RegisterCoinParams { - ticker: param.ticker, + ticker: param.ticker.clone(), tx_history: param.activation_request.tx_history.unwrap_or(false), }; lp_register_coin(&ctx, MmCoinEnum::EthCoin(coin.clone()), register_params) .await - .unwrap(); + .map_err(|e| EthActivationV2Error::ActivationFailed { + ticker: param.ticker, + error: e.to_string(), + })?; tokens.push(coin); } diff --git a/mm2src/coins_activation/src/platform_coin_with_tokens.rs b/mm2src/coins_activation/src/platform_coin_with_tokens.rs index c492932dab..2e29df0552 100644 --- a/mm2src/coins_activation/src/platform_coin_with_tokens.rs +++ b/mm2src/coins_activation/src/platform_coin_with_tokens.rs @@ -66,6 +66,9 @@ pub trait TokenAsMmCoinInitializer: Send + Sync { pub enum InitTokensAsMmCoinsError { TokenConfigIsNotFound(String), InvalidPubkey(String), + InvalidPayload(String), + Internal(String), + InitializationFailed { ticker: String, error: String }, TokenProtocolParseError { ticker: String, error: String }, UnexpectedTokenProtocol { ticker: String, protocol: CoinProtocol }, } @@ -206,6 +209,11 @@ pub enum EnablePlatformCoinWithTokensError { ticker: String, error: String, }, + #[display(fmt = "Error on {} token initialization: {}", ticker, error)] + TokenCreationError { + ticker: String, + error: String, + }, #[display(fmt = "Private key is not allowed: {}", _0)] PrivKeyNotAllowed(String), #[display(fmt = "Unexpected derivation method: {}", _0)] @@ -246,7 +254,13 @@ impl From for EnablePlatformCoinWithTokensError { InitTokensAsMmCoinsError::UnexpectedTokenProtocol { ticker, protocol } => { EnablePlatformCoinWithTokensError::UnexpectedTokenProtocol { ticker, protocol } }, - InitTokensAsMmCoinsError::InvalidPubkey(e) => EnablePlatformCoinWithTokensError::Internal(e), + InitTokensAsMmCoinsError::InvalidPayload(e) => EnablePlatformCoinWithTokensError::InvalidPayload(e), + InitTokensAsMmCoinsError::InvalidPubkey(e) | InitTokensAsMmCoinsError::Internal(e) => { + EnablePlatformCoinWithTokensError::Internal(e) + }, + InitTokensAsMmCoinsError::InitializationFailed { ticker, error } => { + EnablePlatformCoinWithTokensError::TokenCreationError { ticker, error } + }, } } } @@ -265,6 +279,7 @@ impl HttpStatusCode for EnablePlatformCoinWithTokensError { EnablePlatformCoinWithTokensError::CoinProtocolParseError { .. } | EnablePlatformCoinWithTokensError::TokenProtocolParseError { .. } | EnablePlatformCoinWithTokensError::PlatformCoinCreationError { .. } + | EnablePlatformCoinWithTokensError::TokenCreationError { .. } | EnablePlatformCoinWithTokensError::PrivKeyNotAllowed(_) | EnablePlatformCoinWithTokensError::UnexpectedDerivationMethod(_) | EnablePlatformCoinWithTokensError::Transport(_) From b453c15c308b3c5f85775b04304a104d440051c6 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Thu, 21 Jul 2022 11:05:27 +0300 Subject: [PATCH 39/69] fix wasm build failure Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 4 ++-- mm2src/coins_activation/Cargo.toml | 2 ++ .../src/eth_with_token_activation.rs | 23 +++++++++++++++---- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 0ecbe0268b..e115869691 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -353,7 +353,7 @@ pub struct EthCoinImpl { /// the block range used for eth_getLogs logs_block_range: u64, nonce_lock: Arc>, - erc20_tokens_infos: Arc>>, + erc20_tokens_infos: Arc>>, } #[derive(Clone, Debug)] @@ -591,7 +591,7 @@ impl EthCoinImpl { self.erc20_tokens_infos.lock().await.insert(ticker, info); } - pub async fn get_erc_tokens_infos(&self) -> tokio::sync::MutexGuard<'_, HashMap> { + pub async fn get_erc_tokens_infos(&self) -> futures::lock::MutexGuard< '_,HashMap > { self.erc20_tokens_infos.lock().await } } diff --git a/mm2src/coins_activation/Cargo.toml b/mm2src/coins_activation/Cargo.toml index 9c7291f90e..1ad8ed1371 100644 --- a/mm2src/coins_activation/Cargo.toml +++ b/mm2src/coins_activation/Cargo.toml @@ -24,4 +24,6 @@ ser_error_derive = { path = "../derives/ser_error_derive" } serde = "1.0" serde_derive = "1.0" serde_json = { version = "1.0", features = ["preserve_order", "raw_value"] } + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] tokio = { version = "1.7" } \ No newline at end of file diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 391c368af9..9837efd275 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -5,12 +5,11 @@ use crate::{platform_coin_with_tokens::{EnablePlatformCoinWithTokensError, GetPl prelude::*}; use async_trait::async_trait; use coins::{coin_conf, - eth::{eth_coin_from_conf_and_request_v2, Erc20TokenInfo, EthActivationRequest, EthActivationV2Error, - EthCoin}, + eth::{eth_coin_from_conf_and_request_v2, EthActivationRequest, EthActivationV2Error, EthCoin}, lp_register_coin, my_tx_history_v2::TxHistoryStorage, - CoinBalance, CoinProtocol, MarketCoinOps, MmCoin, MmCoinEnum, RegisterCoinParams}; -use common::{block_on, mm_metrics::MetricsArc, Future01CompatExt}; + CoinBalance, CoinProtocol, MarketCoinOps, MmCoinEnum, RegisterCoinParams}; +use common::{mm_metrics::MetricsArc, Future01CompatExt}; use crypto::CryptoCtx; use futures::future::AbortHandle; use mm2_core::mm_ctx::MmArc; @@ -19,6 +18,12 @@ use mm2_number::BigDecimal; use serde::{Deserialize, Serialize}; use serde_json::Value as Json; use std::collections::HashMap; + +#[cfg(not(target_arch = "wasm32"))] +use coins::eth::Erc20TokenInfo; +#[cfg(not(target_arch = "wasm32"))] use coins::MmCoin; +#[cfg(not(target_arch = "wasm32"))] use common::block_on; +#[cfg(not(target_arch = "wasm32"))] use tokio::task::block_in_place; impl From for EnablePlatformCoinWithTokensError { @@ -141,8 +146,9 @@ impl TokenOf for EthCoin { } impl RegisterTokenInfo for EthCoin { + #[cfg(not(target_arch = "wasm32"))] fn register_token_info(&self, token: &EthCoin) { - block_in_place(|| { + block_in_place(move || { let fut = self.add_erc_token_info(token.ticker().to_string(), Erc20TokenInfo { token_address: token.swap_contract_address, decimals: token.decimals(), @@ -150,6 +156,13 @@ impl RegisterTokenInfo for EthCoin { block_on(fut); }); } + + #[cfg(target_arch = "wasm32")] + fn register_token_info(&self, _token: &EthCoin) { + // TODO + common::panic_w("'register_token_info' is not implemented in WASM yet."); + unimplemented!() + } } #[derive(Debug, Serialize)] From 78942e1fb2b21bddc46bf13e74b61acdfb723ec4 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Thu, 21 Jul 2022 11:11:59 +0300 Subject: [PATCH 40/69] fix fmt Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index e115869691..975661969e 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -591,7 +591,7 @@ impl EthCoinImpl { self.erc20_tokens_infos.lock().await.insert(ticker, info); } - pub async fn get_erc_tokens_infos(&self) -> futures::lock::MutexGuard< '_,HashMap > { + pub async fn get_erc_tokens_infos(&self) -> futures::lock::MutexGuard<'_, HashMap> { self.erc20_tokens_infos.lock().await } } From e89a9ec8b9c813c8ae6a84394ee8059ccc4a2877 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Thu, 21 Jul 2022 11:34:09 +0300 Subject: [PATCH 41/69] rename `EthActivationRequest` to `EthActivationV2Request` Signed-off-by: ozkanonur --- Cargo.lock | 1 - mm2src/coins/eth.rs | 4 +- mm2src/coins_activation/Cargo.toml | 5 +-- .../src/erc20_token_activation.rs | 4 +- .../src/eth_with_token_activation.rs | 38 ++++++------------- 5 files changed, 16 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 90188cced3..de0ffda994 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1149,7 +1149,6 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "tokio", ] [[package]] diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 975661969e..9895637848 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -279,7 +279,7 @@ impl HttpStatusCode for EthActivationV2Error { } #[derive(Clone, Debug, Deserialize)] -pub struct EthActivationRequest { +pub struct EthActivationV2Request { pub nodes: Vec, pub swap_contract_address: Address, pub fallback_swap_contract: Option
, @@ -3503,7 +3503,7 @@ pub async fn eth_coin_from_conf_and_request_v2( ctx: &MmArc, ticker: &str, conf: &Json, - req: EthActivationRequest, + req: EthActivationV2Request, priv_key: &[u8], protocol: CoinProtocol, ) -> Result> { diff --git a/mm2src/coins_activation/Cargo.toml b/mm2src/coins_activation/Cargo.toml index 1ad8ed1371..89f4ac538d 100644 --- a/mm2src/coins_activation/Cargo.toml +++ b/mm2src/coins_activation/Cargo.toml @@ -23,7 +23,4 @@ ser_error = { path = "../derives/ser_error" } ser_error_derive = { path = "../derives/ser_error_derive" } serde = "1.0" serde_derive = "1.0" -serde_json = { version = "1.0", features = ["preserve_order", "raw_value"] } - -[target.'cfg(not(target_arch = "wasm32"))'.dependencies] -tokio = { version = "1.7" } \ No newline at end of file +serde_json = { version = "1.0", features = ["preserve_order", "raw_value"] } \ No newline at end of file diff --git a/mm2src/coins_activation/src/erc20_token_activation.rs b/mm2src/coins_activation/src/erc20_token_activation.rs index 1cc7da516c..4490e0a947 100644 --- a/mm2src/coins_activation/src/erc20_token_activation.rs +++ b/mm2src/coins_activation/src/erc20_token_activation.rs @@ -2,7 +2,7 @@ use crate::{prelude::TryPlatformCoinFromMmCoinEnum, token::{EnableTokenError, TokenActivationOps, TokenProtocolParams}}; use async_trait::async_trait; use coins::{coin_conf, - eth::{eth_coin_from_conf_and_request_v2, EthActivationRequest, EthActivationV2Error, EthCoin}, + eth::{eth_coin_from_conf_and_request_v2, EthActivationV2Error, EthActivationV2Request, EthCoin}, CoinBalance, CoinProtocol, MarketCoinOps, MmCoinEnum}; use common::Future01CompatExt; use crypto::CryptoCtx; @@ -57,7 +57,7 @@ impl From for EnableTokenError { #[async_trait] impl TokenActivationOps for EthCoin { type PlatformCoin = EthCoin; - type ActivationParams = EthActivationRequest; + type ActivationParams = EthActivationV2Request; type ProtocolInfo = CoinProtocol; type ActivationResult = Erc20InitResult; type ActivationError = EthActivationV2Error; diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 9837efd275..c18caf086e 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -5,10 +5,11 @@ use crate::{platform_coin_with_tokens::{EnablePlatformCoinWithTokensError, GetPl prelude::*}; use async_trait::async_trait; use coins::{coin_conf, - eth::{eth_coin_from_conf_and_request_v2, EthActivationRequest, EthActivationV2Error, EthCoin}, + eth::{eth_coin_from_conf_and_request_v2, Erc20TokenInfo, EthActivationV2Error, EthActivationV2Request, + EthCoin}, lp_register_coin, my_tx_history_v2::TxHistoryStorage, - CoinBalance, CoinProtocol, MarketCoinOps, MmCoinEnum, RegisterCoinParams}; + CoinBalance, CoinProtocol, MarketCoinOps, MmCoin, MmCoinEnum, RegisterCoinParams}; use common::{mm_metrics::MetricsArc, Future01CompatExt}; use crypto::CryptoCtx; use futures::future::AbortHandle; @@ -19,13 +20,6 @@ use serde::{Deserialize, Serialize}; use serde_json::Value as Json; use std::collections::HashMap; -#[cfg(not(target_arch = "wasm32"))] -use coins::eth::Erc20TokenInfo; -#[cfg(not(target_arch = "wasm32"))] use coins::MmCoin; -#[cfg(not(target_arch = "wasm32"))] use common::block_on; -#[cfg(not(target_arch = "wasm32"))] -use tokio::task::block_in_place; - impl From for EnablePlatformCoinWithTokensError { fn from(err: EthActivationV2Error) -> Self { match err { @@ -72,7 +66,7 @@ impl From for InitTokensAsMmCoinsError { #[async_trait] impl TokenInitializer for Erc20Initializer { type Token = EthCoin; - type TokenActivationRequest = EthActivationRequest; + type TokenActivationRequest = EthActivationV2Request; type TokenProtocol = CoinProtocol; type InitTokensError = EthActivationV2Error; @@ -84,7 +78,7 @@ impl TokenInitializer for Erc20Initializer { async fn enable_tokens( &self, - activation_params: Vec>, + activation_params: Vec>, ) -> Result, MmError> { let ctx = MmArc::from_weak(&self.platform_coin.ctx) .ok_or("No context") @@ -133,8 +127,8 @@ impl TokenInitializer for Erc20Initializer { #[derive(Clone, Debug, Deserialize)] pub struct EthWithTokensActivationRequest { #[serde(flatten)] - platform_request: EthActivationRequest, - erc20_tokens_requests: Vec>, + platform_request: EthActivationV2Request, + erc20_tokens_requests: Vec>, } impl TxHistory for EthWithTokensActivationRequest { @@ -146,22 +140,12 @@ impl TokenOf for EthCoin { } impl RegisterTokenInfo for EthCoin { - #[cfg(not(target_arch = "wasm32"))] fn register_token_info(&self, token: &EthCoin) { - block_in_place(move || { - let fut = self.add_erc_token_info(token.ticker().to_string(), Erc20TokenInfo { - token_address: token.swap_contract_address, - decimals: token.decimals(), - }); - block_on(fut); + let fut = self.add_erc_token_info(token.ticker().to_string(), Erc20TokenInfo { + token_address: token.swap_contract_address, + decimals: token.decimals(), }); - } - - #[cfg(target_arch = "wasm32")] - fn register_token_info(&self, _token: &EthCoin) { - // TODO - common::panic_w("'register_token_info' is not implemented in WASM yet."); - unimplemented!() + futures::executor::block_on(fut); } } From 5be5b83b69634ba03d233b138046def4f031a1de Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Thu, 21 Jul 2022 11:59:16 +0300 Subject: [PATCH 42/69] optimize implementation Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 25 ++++++------------- .../src/erc20_token_activation.rs | 2 +- .../src/eth_with_token_activation.rs | 4 +-- 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 9895637848..922876db14 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -24,7 +24,7 @@ use async_trait::async_trait; use bitcrypto::{keccak256, sha256}; use common::executor::Timer; use common::log::{error, info, warn}; -use common::{get_utc_timestamp, now_ms, small_rng, HttpStatusCode, DEX_FEE_ADDR_RAW_PUBKEY}; +use common::{get_utc_timestamp, now_ms, small_rng, DEX_FEE_ADDR_RAW_PUBKEY}; use crypto::privkey::key_pair_from_secret; use derive_more::Display; use ethabi::{Contract, Token}; @@ -265,19 +265,6 @@ pub enum EthActivationV2Error { InternalError(String), } -impl HttpStatusCode for EthActivationV2Error { - fn status_code(&self) -> StatusCode { - match self { - EthActivationV2Error::InvalidPayload(_) - | EthActivationV2Error::ActivationFailed { .. } - | EthActivationV2Error::UnreachableNodes(_) - | EthActivationV2Error::AtLeastOneNodeRequired(_) => StatusCode::BAD_REQUEST, - EthActivationV2Error::CouldNotFetchBalance(_) => StatusCode::SERVICE_UNAVAILABLE, - _ => StatusCode::INTERNAL_SERVER_ERROR, - } - } -} - #[derive(Clone, Debug, Deserialize)] pub struct EthActivationV2Request { pub nodes: Vec, @@ -333,9 +320,9 @@ pub struct EthCoinImpl { ticker: String, coin_type: EthCoinType, key_pair: KeyPair, - pub my_address: Address, + my_address: Address, sign_message_prefix: Option, - pub swap_contract_address: Address, + swap_contract_address: Address, fallback_swap_contract: Option
, web3: Web3, /// The separate web3 instances kept to get nonce, will replace the web3 completely soon @@ -348,7 +335,7 @@ pub struct EthCoinImpl { required_confirmations: AtomicU64, /// Coin needs access to the context in order to reuse the logging and shutdown facilities. /// Using a weak reference by default in order to avoid circular references and leaks. - pub ctx: MmWeak, + ctx: MmWeak, chain_id: Option, /// the block range used for eth_getLogs logs_block_range: u64, @@ -587,6 +574,10 @@ impl EthCoinImpl { Ok(try_s!(valid_addr_from_str(address))) } + pub fn swap_contract_address_as_h160(&self) -> Address { self.swap_contract_address } + + pub fn ctx(&self) -> MmWeak { self.ctx.clone() } + pub async fn add_erc_token_info(&self, ticker: String, info: Erc20TokenInfo) { self.erc20_tokens_infos.lock().await.insert(ticker, info); } diff --git a/mm2src/coins_activation/src/erc20_token_activation.rs b/mm2src/coins_activation/src/erc20_token_activation.rs index 4490e0a947..d692ac2eda 100644 --- a/mm2src/coins_activation/src/erc20_token_activation.rs +++ b/mm2src/coins_activation/src/erc20_token_activation.rs @@ -68,7 +68,7 @@ impl TokenActivationOps for EthCoin { activation_params: Self::ActivationParams, protocol_conf: Self::ProtocolInfo, ) -> Result<(Self, Self::ActivationResult), MmError> { - let ctx = MmArc::from_weak(&platform_coin.ctx) + let ctx = MmArc::from_weak(&platform_coin.ctx()) .ok_or("No context") .map_err(|e| EthActivationV2Error::InternalError(e.to_string()))?; diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index c18caf086e..7fa453d1fa 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -80,7 +80,7 @@ impl TokenInitializer for Erc20Initializer { &self, activation_params: Vec>, ) -> Result, MmError> { - let ctx = MmArc::from_weak(&self.platform_coin.ctx) + let ctx = MmArc::from_weak(&self.platform_coin.ctx()) .ok_or("No context") .map_err(|e| EthActivationV2Error::InternalError(e.to_string()))?; @@ -142,7 +142,7 @@ impl TokenOf for EthCoin { impl RegisterTokenInfo for EthCoin { fn register_token_info(&self, token: &EthCoin) { let fut = self.add_erc_token_info(token.ticker().to_string(), Erc20TokenInfo { - token_address: token.swap_contract_address, + token_address: token.swap_contract_address_as_h160(), decimals: token.decimals(), }); futures::executor::block_on(fut); From 0b3a42b4b2e11a309372e7fb009a8544a0777750 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Thu, 21 Jul 2022 13:03:54 +0300 Subject: [PATCH 43/69] drop mutability after updates Signed-off-by: ozkanonur --- mm2src/coins_activation/src/erc20_token_activation.rs | 3 +-- mm2src/coins_activation/src/eth_with_token_activation.rs | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mm2src/coins_activation/src/erc20_token_activation.rs b/mm2src/coins_activation/src/erc20_token_activation.rs index d692ac2eda..94a3deb583 100644 --- a/mm2src/coins_activation/src/erc20_token_activation.rs +++ b/mm2src/coins_activation/src/erc20_token_activation.rs @@ -97,8 +97,7 @@ impl TokenActivationOps for EthCoin { .await .map_err(|e| EthActivationV2Error::CouldNotFetchBalance(e.to_string()))?; - let mut balances = HashMap::new(); - balances.insert(my_address.clone(), balance); + let balances = HashMap::from([(my_address.clone(), balance)]); let init_result = Erc20InitResult { balances, diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 7fa453d1fa..18e0abfb7a 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -10,7 +10,7 @@ use coins::{coin_conf, lp_register_coin, my_tx_history_v2::TxHistoryStorage, CoinBalance, CoinProtocol, MarketCoinOps, MmCoin, MmCoinEnum, RegisterCoinParams}; -use common::{mm_metrics::MetricsArc, Future01CompatExt}; +use common::{drop_mutability, mm_metrics::MetricsArc, Future01CompatExt}; use crypto::CryptoCtx; use futures::future::AbortHandle; use mm2_core::mm_ctx::MmArc; @@ -117,6 +117,7 @@ impl TokenInitializer for Erc20Initializer { tokens.push(coin); } + drop_mutability!(tokens); Ok(tokens) } @@ -246,6 +247,7 @@ impl PlatformWithTokensActivationOps for EthCoin { pubkey: my_address, balances: token_balances, }); + drop_mutability!(result); Ok(result) } From fd860b571db3649c4f24f5f4744618dffd672b5f Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Fri, 22 Jul 2022 01:20:23 +0300 Subject: [PATCH 44/69] save development state Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 13 ++++++------- .../src/erc20_token_activation.rs | 9 ++++++--- .../src/eth_with_token_activation.rs | 15 +++++++++------ 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 922876db14..2c69b97fe6 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -261,7 +261,8 @@ pub enum EthActivationV2Error { }, CouldNotFetchBalance(String), UnreachableNodes(String), - AtLeastOneNodeRequired(String), + #[display(fmt = "Enable request for ETH coin must have at least 1 node")] + AtLeastOneNodeRequired, InternalError(String), } @@ -275,7 +276,8 @@ pub struct EthActivationV2Request { #[serde(default)] pub gas_station_policy: GasStationPricePolicy, pub mm2: Option, - pub tx_history: Option, + #[serde(default)] + pub tx_history: bool, pub required_confirmations: Option, } @@ -3499,10 +3501,7 @@ pub async fn eth_coin_from_conf_and_request_v2( protocol: CoinProtocol, ) -> Result> { if req.nodes.is_empty() { - return Err(EthActivationV2Error::AtLeastOneNodeRequired( - "Enable request for ETH coin must have at least 1 node".to_string(), - ) - .into()); + return Err(EthActivationV2Error::AtLeastOneNodeRequired.into()); } let mut rng = small_rng(); @@ -3610,7 +3609,7 @@ pub async fn eth_coin_from_conf_and_request_v2( let sign_message_prefix: Option = json::from_value(conf["sign_message_prefix"].clone()).unwrap_or(None); - let initial_history_state = if req.tx_history.unwrap_or(false) { + let initial_history_state = if req.tx_history { HistorySyncState::NotStarted } else { HistorySyncState::NotEnabled diff --git a/mm2src/coins_activation/src/erc20_token_activation.rs b/mm2src/coins_activation/src/erc20_token_activation.rs index 94a3deb583..5e8e2e705e 100644 --- a/mm2src/coins_activation/src/erc20_token_activation.rs +++ b/mm2src/coins_activation/src/erc20_token_activation.rs @@ -46,9 +46,12 @@ impl From for EnableTokenError { EthActivationV2Error::ActivationFailed { ticker, error } => { EnableTokenError::Internal(format!("{} activation is failed. {}", ticker, error)) }, - EthActivationV2Error::AtLeastOneNodeRequired(e) - | EthActivationV2Error::UnreachableNodes(e) - | EthActivationV2Error::CouldNotFetchBalance(e) => EnableTokenError::Transport(e), + EthActivationV2Error::AtLeastOneNodeRequired => { + EnableTokenError::Transport("Enable request for ETH coin must have at least 1 node".to_string()) + }, + EthActivationV2Error::UnreachableNodes(e) | EthActivationV2Error::CouldNotFetchBalance(e) => { + EnableTokenError::Transport(e) + }, EthActivationV2Error::InternalError(e) => EnableTokenError::Internal(e), } } diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 18e0abfb7a..0e57657358 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -27,9 +27,12 @@ impl From for EnablePlatformCoinWithTokensError { EthActivationV2Error::ActivationFailed { ticker, error } => { EnablePlatformCoinWithTokensError::PlatformCoinCreationError { ticker, error } }, - EthActivationV2Error::CouldNotFetchBalance(e) - | EthActivationV2Error::UnreachableNodes(e) - | EthActivationV2Error::AtLeastOneNodeRequired(e) => EnablePlatformCoinWithTokensError::Transport(e), + EthActivationV2Error::AtLeastOneNodeRequired => EnablePlatformCoinWithTokensError::Transport( + "Enable request for ETH coin must have at least 1 node".to_string(), + ), + EthActivationV2Error::CouldNotFetchBalance(e) | EthActivationV2Error::UnreachableNodes(e) => { + EnablePlatformCoinWithTokensError::Transport(e) + }, EthActivationV2Error::InternalError(e) => EnablePlatformCoinWithTokensError::Internal(e), } } @@ -57,8 +60,8 @@ impl From for InitTokensAsMmCoinsError { }, EthActivationV2Error::CouldNotFetchBalance(e) | EthActivationV2Error::UnreachableNodes(e) - | EthActivationV2Error::AtLeastOneNodeRequired(e) | EthActivationV2Error::InternalError(e) => InitTokensAsMmCoinsError::Internal(e), + e => InitTokensAsMmCoinsError::Internal(e.to_string()), } } } @@ -105,7 +108,7 @@ impl TokenInitializer for Erc20Initializer { let register_params = RegisterCoinParams { ticker: param.ticker.clone(), - tx_history: param.activation_request.tx_history.unwrap_or(false), + tx_history: param.activation_request.tx_history, }; lp_register_coin(&ctx, MmCoinEnum::EthCoin(coin.clone()), register_params) @@ -133,7 +136,7 @@ pub struct EthWithTokensActivationRequest { } impl TxHistory for EthWithTokensActivationRequest { - fn tx_history(&self) -> bool { self.platform_request.tx_history.unwrap_or(false) } + fn tx_history(&self) -> bool { self.platform_request.tx_history } } impl TokenOf for EthCoin { From e19e07267f084d0113077427641e52d247af2aae Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Fri, 22 Jul 2022 15:09:25 +0300 Subject: [PATCH 45/69] make `fn enable_token` less bloat Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 73 +++++++++++++++- .../src/erc20_token_activation.rs | 87 +++++++++---------- 2 files changed, 111 insertions(+), 49 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 2c69b97fe6..abbdc35a07 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -59,6 +59,8 @@ use web3::types::{Action as TraceAction, BlockId, BlockNumber, Bytes, CallReques use web3::{self, Web3}; use web3_transport::{EthFeeHistoryNamespace, Web3Transport, Web3TransportNode}; +use crate::coin_conf; + use super::{AsyncMutex, BalanceError, BalanceFut, CoinBalance, CoinProtocol, CoinTransportMetrics, CoinsContext, FeeApproxStage, FoundSwapTxSpend, HistorySyncState, MarketCoinOps, MmCoin, NegotiateSwapContractAddrErr, NumConversError, NumConversResult, RawTransactionError, RawTransactionFut, RawTransactionRequest, @@ -281,12 +283,22 @@ pub struct EthActivationV2Request { pub required_confirmations: Option, } +#[derive(Clone, Debug, Deserialize)] +pub struct Erc20TokenRequest { + pub required_confirmations: Option, +} + #[derive(Clone, Debug, Deserialize)] pub struct EthNode { pub url: String, pub gui_auth: bool, } +pub struct Erc20Protocol { + pub platform: String, + pub token_addr: Address, +} + #[derive(Debug, Deserialize, Serialize)] struct SavedTraces { /// ETH traces for my_address @@ -307,7 +319,7 @@ struct SavedErc20Events { latest_block: U256, } -#[derive(Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum EthCoinType { /// Ethereum itself or it's forks: ETC/others Eth, @@ -319,12 +331,12 @@ pub enum EthCoinType { /// pImpl idiom. #[derive(Debug)] pub struct EthCoinImpl { - ticker: String, + pub ticker: String, coin_type: EthCoinType, key_pair: KeyPair, my_address: Address, sign_message_prefix: Option, - swap_contract_address: Address, + pub swap_contract_address: Address, fallback_swap_contract: Option
, web3: Web3, /// The separate web3 instances kept to get nonce, will replace the web3 completely soon @@ -728,7 +740,7 @@ async fn withdraw_impl(coin: EthCoin, req: WithdrawRequest) -> WithdrawResult { } #[derive(Clone, Debug)] -pub struct EthCoin(Arc); +pub struct EthCoin(pub Arc); impl Deref for EthCoin { type Target = EthCoinImpl; fn deref(&self) -> &EthCoinImpl { &*self.0 } @@ -2563,6 +2575,59 @@ impl EthCoin { Box::new(fut.boxed().compat()) } + pub async fn initialize_erc20_token( + &self, + activation_params: Erc20TokenRequest, + protocol: Erc20Protocol, + ticker: String, + ) -> Result> { + let ctx = MmArc::from_weak(&self.ctx) + .ok_or_else(|| String::from("No context")) + .map_err(EthActivationV2Error::InternalError)?; + + let conf = coin_conf(&ctx, &ticker); + + let decimals = match conf["decimals"].as_u64() { + None | Some(0) => get_token_decimals(&self.web3, protocol.token_addr) + .await + .map_err(EthActivationV2Error::InternalError)?, + Some(d) => d as u8, + }; + + let required_confirmations = activation_params + .required_confirmations + .unwrap_or_else(|| conf["required_confirmations"].as_u64().unwrap_or(1)) + .into(); + + let token = EthCoinImpl { + key_pair: self.key_pair.clone(), + my_address: self.my_address, + coin_type: EthCoinType::Erc20 { + platform: protocol.platform, + token_addr: protocol.token_addr, + }, + sign_message_prefix: self.sign_message_prefix.clone(), + swap_contract_address: self.swap_contract_address, + fallback_swap_contract: self.fallback_swap_contract, + decimals, + ticker, + gas_station_url: self.gas_station_url.clone(), + gas_station_decimals: self.gas_station_decimals, + gas_station_policy: self.gas_station_policy, + web3: self.web3.clone(), + web3_instances: self.web3_instances.clone(), + history_sync_state: Mutex::new(self.history_sync_state.lock().unwrap().clone()), + ctx: self.ctx.clone(), + required_confirmations, + chain_id: self.chain_id, + logs_block_range: self.logs_block_range, + nonce_lock: self.nonce_lock.clone(), + erc20_tokens_infos: Default::default(), + }; + + Ok(EthCoin(Arc::new(token))) + } + /// Estimates how much gas is necessary to allow the contract call to complete. /// `contract_addr` can be a ERC20 token address or any other contract address. /// diff --git a/mm2src/coins_activation/src/erc20_token_activation.rs b/mm2src/coins_activation/src/erc20_token_activation.rs index 5e8e2e705e..3c887e8c7a 100644 --- a/mm2src/coins_activation/src/erc20_token_activation.rs +++ b/mm2src/coins_activation/src/erc20_token_activation.rs @@ -1,12 +1,9 @@ -use crate::{prelude::TryPlatformCoinFromMmCoinEnum, +use crate::{prelude::{TryFromCoinProtocol, TryPlatformCoinFromMmCoinEnum}, token::{EnableTokenError, TokenActivationOps, TokenProtocolParams}}; use async_trait::async_trait; -use coins::{coin_conf, - eth::{eth_coin_from_conf_and_request_v2, EthActivationV2Error, EthActivationV2Request, EthCoin}, +use coins::{eth::{valid_addr_from_str, Erc20Protocol, Erc20TokenRequest, EthActivationV2Error, EthCoin}, CoinBalance, CoinProtocol, MarketCoinOps, MmCoinEnum}; use common::Future01CompatExt; -use crypto::CryptoCtx; -use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::MmError; use serde::Serialize; use std::collections::HashMap; @@ -18,11 +15,20 @@ pub struct Erc20InitResult { platform_coin: String, } -impl TokenProtocolParams for CoinProtocol { - fn platform_coin_ticker(&self) -> &str { - match self { - CoinProtocol::ERC20 { platform, .. } => platform, - _ => "ETH", +impl From for EnableTokenError { + fn from(err: EthActivationV2Error) -> Self { + match err { + EthActivationV2Error::InvalidPayload(e) => EnableTokenError::InvalidPayload(e), + EthActivationV2Error::ActivationFailed { ticker, error } => { + EnableTokenError::Internal(format!("{} activation is failed. {}", ticker, error)) + }, + EthActivationV2Error::AtLeastOneNodeRequired => { + EnableTokenError::Transport("Enable request for ETH coin must have at least 1 node".to_string()) + }, + EthActivationV2Error::UnreachableNodes(e) | EthActivationV2Error::CouldNotFetchBalance(e) => { + EnableTokenError::Transport(e) + }, + EthActivationV2Error::InternalError(e) => EnableTokenError::Internal(e), } } } @@ -39,29 +45,37 @@ impl TryPlatformCoinFromMmCoinEnum for EthCoin { } } -impl From for EnableTokenError { - fn from(err: EthActivationV2Error) -> Self { - match err { - EthActivationV2Error::InvalidPayload(e) => EnableTokenError::InvalidPayload(e), - EthActivationV2Error::ActivationFailed { ticker, error } => { - EnableTokenError::Internal(format!("{} activation is failed. {}", ticker, error)) - }, - EthActivationV2Error::AtLeastOneNodeRequired => { - EnableTokenError::Transport("Enable request for ETH coin must have at least 1 node".to_string()) - }, - EthActivationV2Error::UnreachableNodes(e) | EthActivationV2Error::CouldNotFetchBalance(e) => { - EnableTokenError::Transport(e) +impl TryFromCoinProtocol for Erc20Protocol { + fn try_from_coin_protocol(proto: CoinProtocol) -> Result> + where + Self: Sized, + { + match proto { + CoinProtocol::ERC20 { + platform, + contract_address, + } => { + let token_addr = valid_addr_from_str(&contract_address).map_err(|_| CoinProtocol::ERC20 { + platform: platform.clone(), + contract_address, + })?; + + Ok(Erc20Protocol { platform, token_addr }) }, - EthActivationV2Error::InternalError(e) => EnableTokenError::Internal(e), + proto => MmError::err(proto), } } } +impl TokenProtocolParams for Erc20Protocol { + fn platform_coin_ticker(&self) -> &str { &self.platform } +} + #[async_trait] impl TokenActivationOps for EthCoin { type PlatformCoin = EthCoin; - type ActivationParams = EthActivationV2Request; - type ProtocolInfo = CoinProtocol; + type ActivationParams = Erc20TokenRequest; + type ProtocolInfo = Erc20Protocol; type ActivationResult = Erc20InitResult; type ActivationError = EthActivationV2Error; @@ -71,26 +85,9 @@ impl TokenActivationOps for EthCoin { activation_params: Self::ActivationParams, protocol_conf: Self::ProtocolInfo, ) -> Result<(Self, Self::ActivationResult), MmError> { - let ctx = MmArc::from_weak(&platform_coin.ctx()) - .ok_or("No context") - .map_err(|e| EthActivationV2Error::InternalError(e.to_string()))?; - - let secret = CryptoCtx::from_ctx(&ctx) - .map_err(|e| EthActivationV2Error::InternalError(e.to_string()))? - .iguana_ctx() - .secp256k1_privkey_bytes() - .to_vec(); - - let coins_en = coin_conf(&ctx, &ticker); - let token: EthCoin = eth_coin_from_conf_and_request_v2( - &ctx, - &ticker, - &coins_en, - activation_params.clone(), - &secret, - protocol_conf, - ) - .await?; + let token = platform_coin + .initialize_erc20_token(activation_params, protocol_conf, ticker) + .await?; let my_address = token.my_address().map_err(EthActivationV2Error::InternalError)?; From 254a72e19e11093119a59569c6ecdd5cb661294c Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Fri, 22 Jul 2022 15:48:37 +0300 Subject: [PATCH 46/69] make `enable_tokens` less bloat Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 7 ++- .../src/eth_with_token_activation.rs | 58 +++++-------------- 2 files changed, 19 insertions(+), 46 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index abbdc35a07..3eb265878c 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -588,7 +588,12 @@ impl EthCoinImpl { Ok(try_s!(valid_addr_from_str(address))) } - pub fn swap_contract_address_as_h160(&self) -> Address { self.swap_contract_address } + pub fn erc20_token_address(&self) -> Option
{ + match self.coin_type { + EthCoinType::Erc20 { token_addr, .. } => Some(token_addr), + EthCoinType::Eth => None, + } + } pub fn ctx(&self) -> MmWeak { self.ctx.clone() } diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 0e57657358..83c39a0f9c 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -4,14 +4,11 @@ use crate::{platform_coin_with_tokens::{EnablePlatformCoinWithTokensError, GetPl TokenInitializer, TokenOf}, prelude::*}; use async_trait::async_trait; -use coins::{coin_conf, - eth::{eth_coin_from_conf_and_request_v2, Erc20TokenInfo, EthActivationV2Error, EthActivationV2Request, - EthCoin}, - lp_register_coin, +use coins::{eth::{eth_coin_from_conf_and_request_v2, Erc20Protocol, Erc20TokenInfo, Erc20TokenRequest, + EthActivationV2Error, EthActivationV2Request, EthCoin}, my_tx_history_v2::TxHistoryStorage, - CoinBalance, CoinProtocol, MarketCoinOps, MmCoin, MmCoinEnum, RegisterCoinParams}; + CoinBalance, CoinProtocol, MarketCoinOps, MmCoin}; use common::{drop_mutability, mm_metrics::MetricsArc, Future01CompatExt}; -use crypto::CryptoCtx; use futures::future::AbortHandle; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; @@ -69,8 +66,8 @@ impl From for InitTokensAsMmCoinsError { #[async_trait] impl TokenInitializer for Erc20Initializer { type Token = EthCoin; - type TokenActivationRequest = EthActivationV2Request; - type TokenProtocol = CoinProtocol; + type TokenActivationRequest = Erc20TokenRequest; + type TokenProtocol = Erc20Protocol; type InitTokensError = EthActivationV2Error; fn tokens_requests_from_platform_request( @@ -81,44 +78,15 @@ impl TokenInitializer for Erc20Initializer { async fn enable_tokens( &self, - activation_params: Vec>, + activation_params: Vec>, ) -> Result, MmError> { - let ctx = MmArc::from_weak(&self.platform_coin.ctx()) - .ok_or("No context") - .map_err(|e| EthActivationV2Error::InternalError(e.to_string()))?; - - let secret = CryptoCtx::from_ctx(&ctx) - .map_err(|e| EthActivationV2Error::InternalError(e.to_string()))? - .iguana_ctx() - .secp256k1_privkey_bytes() - .to_vec(); - let mut tokens = vec![]; for param in activation_params { - let coins_en = coin_conf(&ctx, ¶m.ticker); - let coin: EthCoin = eth_coin_from_conf_and_request_v2( - &ctx, - ¶m.ticker, - &coins_en, - param.activation_request.clone(), - &secret, - param.protocol.clone(), - ) - .await?; - - let register_params = RegisterCoinParams { - ticker: param.ticker.clone(), - tx_history: param.activation_request.tx_history, - }; - - lp_register_coin(&ctx, MmCoinEnum::EthCoin(coin.clone()), register_params) - .await - .map_err(|e| EthActivationV2Error::ActivationFailed { - ticker: param.ticker, - error: e.to_string(), - })?; - - tokens.push(coin); + let token: EthCoin = self + .platform_coin + .initialize_erc20_token(param.activation_request.clone(), param.protocol, param.ticker) + .await?; + tokens.push(token); } drop_mutability!(tokens); @@ -132,7 +100,7 @@ impl TokenInitializer for Erc20Initializer { pub struct EthWithTokensActivationRequest { #[serde(flatten)] platform_request: EthActivationV2Request, - erc20_tokens_requests: Vec>, + erc20_tokens_requests: Vec>, } impl TxHistory for EthWithTokensActivationRequest { @@ -146,7 +114,7 @@ impl TokenOf for EthCoin { impl RegisterTokenInfo for EthCoin { fn register_token_info(&self, token: &EthCoin) { let fut = self.add_erc_token_info(token.ticker().to_string(), Erc20TokenInfo { - token_address: token.swap_contract_address_as_h160(), + token_address: token.erc20_token_address().unwrap(), decimals: token.decimals(), }); futures::executor::block_on(fut); From 9004d58e34891246a3b5a5da25bca546bcd21395 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Fri, 22 Jul 2022 16:31:51 +0300 Subject: [PATCH 47/69] finalize review fixes Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 43 ++++++++++++------- .../src/erc20_token_activation.rs | 27 ++++-------- .../src/eth_with_token_activation.rs | 42 +++++++++--------- .../src/platform_coin_with_tokens.rs | 16 +++++++ mm2src/coins_activation/src/token.rs | 2 - 5 files changed, 73 insertions(+), 57 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 3eb265878c..fcb06b2ec1 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -251,11 +251,13 @@ impl From for BalanceError { fn from(e: web3::Error) -> Self { BalanceError::Transport(e.to_string()) } } -#[derive(Debug, Display, Serialize, SerializeErrorType)] +#[derive(Display, Serialize, SerializeErrorType)] #[serde(tag = "error_type", content = "error_data")] #[allow(dead_code)] pub enum EthActivationV2Error { InvalidPayload(String), + InvalidSwapContractAddr(String), + InvalidFallbackSwapContract(String), #[display(fmt = "Platform coin {} activation failed. {}", ticker, error)] ActivationFailed { ticker: String, @@ -268,7 +270,7 @@ pub enum EthActivationV2Error { InternalError(String), } -#[derive(Clone, Debug, Deserialize)] +#[derive(Clone, Deserialize)] pub struct EthActivationV2Request { pub nodes: Vec, pub swap_contract_address: Address, @@ -283,17 +285,25 @@ pub struct EthActivationV2Request { pub required_confirmations: Option, } -#[derive(Clone, Debug, Deserialize)] -pub struct Erc20TokenRequest { - pub required_confirmations: Option, -} - -#[derive(Clone, Debug, Deserialize)] +#[derive(Clone, Deserialize)] pub struct EthNode { pub url: String, pub gui_auth: bool, } +#[derive(Serialize, SerializeErrorType)] +#[serde(tag = "error_type", content = "error_data")] +#[allow(dead_code)] +pub enum Erc20TokenActivationError { + InternalError(String), + CouldNotFetchBalance(String), +} + +#[derive(Clone, Deserialize)] +pub struct Erc20TokenActivationRequest { + pub required_confirmations: Option, +} + pub struct Erc20Protocol { pub platform: String, pub token_addr: Address, @@ -2582,20 +2592,20 @@ impl EthCoin { pub async fn initialize_erc20_token( &self, - activation_params: Erc20TokenRequest, + activation_params: Erc20TokenActivationRequest, protocol: Erc20Protocol, ticker: String, - ) -> Result> { + ) -> Result> { let ctx = MmArc::from_weak(&self.ctx) .ok_or_else(|| String::from("No context")) - .map_err(EthActivationV2Error::InternalError)?; + .map_err(Erc20TokenActivationError::InternalError)?; let conf = coin_conf(&ctx, &ticker); let decimals = match conf["decimals"].as_u64() { None | Some(0) => get_token_decimals(&self.web3, protocol.token_addr) .await - .map_err(EthActivationV2Error::InternalError)?, + .map_err(Erc20TokenActivationError::InternalError)?, Some(d) => d as u8, }; @@ -3594,14 +3604,15 @@ pub async fn eth_coin_from_conf_and_request_v2( drop_mutability!(nodes); if req.swap_contract_address == Address::default() { - return Err( - EthActivationV2Error::InvalidPayload("swap_contract_address can't be zero address".to_string()).into(), - ); + return Err(EthActivationV2Error::InvalidSwapContractAddr( + "swap_contract_address can't be zero address".to_string(), + ) + .into()); } if let Some(fallback) = req.fallback_swap_contract { if fallback == Address::default() { - return Err(EthActivationV2Error::InvalidPayload( + return Err(EthActivationV2Error::InvalidFallbackSwapContract( "fallback_swap_contract can't be zero address".to_string(), ) .into()); diff --git a/mm2src/coins_activation/src/erc20_token_activation.rs b/mm2src/coins_activation/src/erc20_token_activation.rs index 3c887e8c7a..8253ac96f3 100644 --- a/mm2src/coins_activation/src/erc20_token_activation.rs +++ b/mm2src/coins_activation/src/erc20_token_activation.rs @@ -1,7 +1,7 @@ use crate::{prelude::{TryFromCoinProtocol, TryPlatformCoinFromMmCoinEnum}, token::{EnableTokenError, TokenActivationOps, TokenProtocolParams}}; use async_trait::async_trait; -use coins::{eth::{valid_addr_from_str, Erc20Protocol, Erc20TokenRequest, EthActivationV2Error, EthCoin}, +use coins::{eth::{valid_addr_from_str, Erc20Protocol, Erc20TokenActivationError, Erc20TokenActivationRequest, EthCoin}, CoinBalance, CoinProtocol, MarketCoinOps, MmCoinEnum}; use common::Future01CompatExt; use mm2_err_handle::prelude::MmError; @@ -15,20 +15,11 @@ pub struct Erc20InitResult { platform_coin: String, } -impl From for EnableTokenError { - fn from(err: EthActivationV2Error) -> Self { +impl From for EnableTokenError { + fn from(err: Erc20TokenActivationError) -> Self { match err { - EthActivationV2Error::InvalidPayload(e) => EnableTokenError::InvalidPayload(e), - EthActivationV2Error::ActivationFailed { ticker, error } => { - EnableTokenError::Internal(format!("{} activation is failed. {}", ticker, error)) - }, - EthActivationV2Error::AtLeastOneNodeRequired => { - EnableTokenError::Transport("Enable request for ETH coin must have at least 1 node".to_string()) - }, - EthActivationV2Error::UnreachableNodes(e) | EthActivationV2Error::CouldNotFetchBalance(e) => { - EnableTokenError::Transport(e) - }, - EthActivationV2Error::InternalError(e) => EnableTokenError::Internal(e), + Erc20TokenActivationError::InternalError(e) => EnableTokenError::Internal(e), + Erc20TokenActivationError::CouldNotFetchBalance(e) => EnableTokenError::Transport(e), } } } @@ -74,10 +65,10 @@ impl TokenProtocolParams for Erc20Protocol { #[async_trait] impl TokenActivationOps for EthCoin { type PlatformCoin = EthCoin; - type ActivationParams = Erc20TokenRequest; + type ActivationParams = Erc20TokenActivationRequest; type ProtocolInfo = Erc20Protocol; type ActivationResult = Erc20InitResult; - type ActivationError = EthActivationV2Error; + type ActivationError = Erc20TokenActivationError; async fn enable_token( ticker: String, @@ -89,13 +80,13 @@ impl TokenActivationOps for EthCoin { .initialize_erc20_token(activation_params, protocol_conf, ticker) .await?; - let my_address = token.my_address().map_err(EthActivationV2Error::InternalError)?; + let my_address = token.my_address().map_err(Erc20TokenActivationError::InternalError)?; let balance = token .my_balance() .compat() .await - .map_err(|e| EthActivationV2Error::CouldNotFetchBalance(e.to_string()))?; + .map_err(|e| Erc20TokenActivationError::CouldNotFetchBalance(e.to_string()))?; let balances = HashMap::from([(my_address.clone(), balance)]); diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 83c39a0f9c..a9bfbbf9a0 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -4,8 +4,8 @@ use crate::{platform_coin_with_tokens::{EnablePlatformCoinWithTokensError, GetPl TokenInitializer, TokenOf}, prelude::*}; use async_trait::async_trait; -use coins::{eth::{eth_coin_from_conf_and_request_v2, Erc20Protocol, Erc20TokenInfo, Erc20TokenRequest, - EthActivationV2Error, EthActivationV2Request, EthCoin}, +use coins::{eth::{eth_coin_from_conf_and_request_v2, Erc20Protocol, Erc20TokenActivationError, + Erc20TokenActivationRequest, Erc20TokenInfo, EthActivationV2Error, EthActivationV2Request, EthCoin}, my_tx_history_v2::TxHistoryStorage, CoinBalance, CoinProtocol, MarketCoinOps, MmCoin}; use common::{drop_mutability, mm_metrics::MetricsArc, Future01CompatExt}; @@ -24,13 +24,19 @@ impl From for EnablePlatformCoinWithTokensError { EthActivationV2Error::ActivationFailed { ticker, error } => { EnablePlatformCoinWithTokensError::PlatformCoinCreationError { ticker, error } }, - EthActivationV2Error::AtLeastOneNodeRequired => EnablePlatformCoinWithTokensError::Transport( + EthActivationV2Error::AtLeastOneNodeRequired => EnablePlatformCoinWithTokensError::AtLeastOneNodeRequired( "Enable request for ETH coin must have at least 1 node".to_string(), ), EthActivationV2Error::CouldNotFetchBalance(e) | EthActivationV2Error::UnreachableNodes(e) => { EnablePlatformCoinWithTokensError::Transport(e) }, EthActivationV2Error::InternalError(e) => EnablePlatformCoinWithTokensError::Internal(e), + EthActivationV2Error::InvalidSwapContractAddr(e) => { + EnablePlatformCoinWithTokensError::InvalidSwapContractAddr(e) + }, + EthActivationV2Error::InvalidFallbackSwapContract(e) => { + EnablePlatformCoinWithTokensError::InvalidFallbackSwapContract(e) + }, } } } @@ -48,17 +54,11 @@ pub struct Erc20Initializer { platform_coin: EthCoin, } -impl From for InitTokensAsMmCoinsError { - fn from(error: EthActivationV2Error) -> Self { +impl From for InitTokensAsMmCoinsError { + fn from(error: Erc20TokenActivationError) -> Self { match error { - EthActivationV2Error::InvalidPayload(e) => InitTokensAsMmCoinsError::InvalidPayload(e), - EthActivationV2Error::ActivationFailed { ticker, error } => { - InitTokensAsMmCoinsError::InitializationFailed { ticker, error } - }, - EthActivationV2Error::CouldNotFetchBalance(e) - | EthActivationV2Error::UnreachableNodes(e) - | EthActivationV2Error::InternalError(e) => InitTokensAsMmCoinsError::Internal(e), - e => InitTokensAsMmCoinsError::Internal(e.to_string()), + Erc20TokenActivationError::InternalError(e) => InitTokensAsMmCoinsError::Internal(e), + Erc20TokenActivationError::CouldNotFetchBalance(e) => InitTokensAsMmCoinsError::CouldNotFetchBalance(e), } } } @@ -66,9 +66,9 @@ impl From for InitTokensAsMmCoinsError { #[async_trait] impl TokenInitializer for Erc20Initializer { type Token = EthCoin; - type TokenActivationRequest = Erc20TokenRequest; + type TokenActivationRequest = Erc20TokenActivationRequest; type TokenProtocol = Erc20Protocol; - type InitTokensError = EthActivationV2Error; + type InitTokensError = Erc20TokenActivationError; fn tokens_requests_from_platform_request( platform_params: &EthWithTokensActivationRequest, @@ -78,13 +78,13 @@ impl TokenInitializer for Erc20Initializer { async fn enable_tokens( &self, - activation_params: Vec>, - ) -> Result, MmError> { + activation_params: Vec>, + ) -> Result, MmError> { let mut tokens = vec![]; for param in activation_params { let token: EthCoin = self .platform_coin - .initialize_erc20_token(param.activation_request.clone(), param.protocol, param.ticker) + .initialize_erc20_token(param.activation_request, param.protocol, param.ticker) .await?; tokens.push(token); } @@ -96,11 +96,11 @@ impl TokenInitializer for Erc20Initializer { fn platform_coin(&self) -> &EthCoin { &self.platform_coin } } -#[derive(Clone, Debug, Deserialize)] +#[derive(Clone, Deserialize)] pub struct EthWithTokensActivationRequest { #[serde(flatten)] platform_request: EthActivationV2Request, - erc20_tokens_requests: Vec>, + erc20_tokens_requests: Vec>, } impl TxHistory for EthWithTokensActivationRequest { @@ -121,7 +121,7 @@ impl RegisterTokenInfo for EthCoin { } } -#[derive(Debug, Serialize)] +#[derive(Serialize)] pub struct EthWithTokensActivationResult { current_block: u64, eth_addresses_infos: HashMap>, diff --git a/mm2src/coins_activation/src/platform_coin_with_tokens.rs b/mm2src/coins_activation/src/platform_coin_with_tokens.rs index 2e29df0552..c0a0682601 100644 --- a/mm2src/coins_activation/src/platform_coin_with_tokens.rs +++ b/mm2src/coins_activation/src/platform_coin_with_tokens.rs @@ -66,7 +66,10 @@ pub trait TokenAsMmCoinInitializer: Send + Sync { pub enum InitTokensAsMmCoinsError { TokenConfigIsNotFound(String), InvalidPubkey(String), + InvalidSwapContractAddr(String), + InvalidFallbackSwapContract(String), InvalidPayload(String), + CouldNotFetchBalance(String), Internal(String), InitializationFailed { ticker: String, error: String }, TokenProtocolParseError { ticker: String, error: String }, @@ -219,7 +222,10 @@ pub enum EnablePlatformCoinWithTokensError { #[display(fmt = "Unexpected derivation method: {}", _0)] UnexpectedDerivationMethod(String), Transport(String), + AtLeastOneNodeRequired(String), InvalidPayload(String), + InvalidSwapContractAddr(String), + InvalidFallbackSwapContract(String), Internal(String), } @@ -261,6 +267,13 @@ impl From for EnablePlatformCoinWithTokensError { InitTokensAsMmCoinsError::InitializationFailed { ticker, error } => { EnablePlatformCoinWithTokensError::TokenCreationError { ticker, error } }, + InitTokensAsMmCoinsError::InvalidSwapContractAddr(e) => { + EnablePlatformCoinWithTokensError::InvalidSwapContractAddr(e) + }, + InitTokensAsMmCoinsError::InvalidFallbackSwapContract(e) => { + EnablePlatformCoinWithTokensError::InvalidFallbackSwapContract(e) + }, + InitTokensAsMmCoinsError::CouldNotFetchBalance(e) => EnablePlatformCoinWithTokensError::Transport(e), } } } @@ -289,6 +302,9 @@ impl HttpStatusCode for EnablePlatformCoinWithTokensError { | EnablePlatformCoinWithTokensError::TokenConfigIsNotFound(_) | EnablePlatformCoinWithTokensError::UnexpectedPlatformProtocol { .. } | EnablePlatformCoinWithTokensError::InvalidPayload { .. } + | EnablePlatformCoinWithTokensError::InvalidSwapContractAddr(_) + | EnablePlatformCoinWithTokensError::InvalidFallbackSwapContract(_) + | EnablePlatformCoinWithTokensError::AtLeastOneNodeRequired(_) | EnablePlatformCoinWithTokensError::UnexpectedTokenProtocol { .. } => StatusCode::BAD_REQUEST, } } diff --git a/mm2src/coins_activation/src/token.rs b/mm2src/coins_activation/src/token.rs index eb8ad7200f..2437b02a42 100644 --- a/mm2src/coins_activation/src/token.rs +++ b/mm2src/coins_activation/src/token.rs @@ -59,7 +59,6 @@ pub enum EnableTokenError { #[display(fmt = "{}", _0)] UnexpectedDerivationMethod(UnexpectedDerivationMethod), #[display(fmt = "{} is not valid payload.", _0)] - InvalidPayload(String), Transport(String), Internal(String), } @@ -153,7 +152,6 @@ impl HttpStatusCode for EnableTokenError { EnableTokenError::TokenIsAlreadyActivated(_) | EnableTokenError::PlatformCoinIsNotActivated(_) | EnableTokenError::TokenConfigIsNotFound { .. } - | EnableTokenError::InvalidPayload { .. } | EnableTokenError::UnexpectedTokenProtocol { .. } => StatusCode::BAD_REQUEST, EnableTokenError::TokenProtocolParseError { .. } | EnableTokenError::UnsupportedPlatformCoin { .. } From c903a29bc659424c6949a952ba7b1e757d2b738d Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Fri, 22 Jul 2022 16:40:06 +0300 Subject: [PATCH 48/69] update errors Signed-off-by: ozkanonur --- .../src/platform_coin_with_tokens.rs | 12 ------------ mm2src/coins_activation/src/token.rs | 3 ++- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/mm2src/coins_activation/src/platform_coin_with_tokens.rs b/mm2src/coins_activation/src/platform_coin_with_tokens.rs index c0a0682601..337c6084d0 100644 --- a/mm2src/coins_activation/src/platform_coin_with_tokens.rs +++ b/mm2src/coins_activation/src/platform_coin_with_tokens.rs @@ -68,10 +68,8 @@ pub enum InitTokensAsMmCoinsError { InvalidPubkey(String), InvalidSwapContractAddr(String), InvalidFallbackSwapContract(String), - InvalidPayload(String), CouldNotFetchBalance(String), Internal(String), - InitializationFailed { ticker: String, error: String }, TokenProtocolParseError { ticker: String, error: String }, UnexpectedTokenProtocol { ticker: String, protocol: CoinProtocol }, } @@ -212,11 +210,6 @@ pub enum EnablePlatformCoinWithTokensError { ticker: String, error: String, }, - #[display(fmt = "Error on {} token initialization: {}", ticker, error)] - TokenCreationError { - ticker: String, - error: String, - }, #[display(fmt = "Private key is not allowed: {}", _0)] PrivKeyNotAllowed(String), #[display(fmt = "Unexpected derivation method: {}", _0)] @@ -260,13 +253,9 @@ impl From for EnablePlatformCoinWithTokensError { InitTokensAsMmCoinsError::UnexpectedTokenProtocol { ticker, protocol } => { EnablePlatformCoinWithTokensError::UnexpectedTokenProtocol { ticker, protocol } }, - InitTokensAsMmCoinsError::InvalidPayload(e) => EnablePlatformCoinWithTokensError::InvalidPayload(e), InitTokensAsMmCoinsError::InvalidPubkey(e) | InitTokensAsMmCoinsError::Internal(e) => { EnablePlatformCoinWithTokensError::Internal(e) }, - InitTokensAsMmCoinsError::InitializationFailed { ticker, error } => { - EnablePlatformCoinWithTokensError::TokenCreationError { ticker, error } - }, InitTokensAsMmCoinsError::InvalidSwapContractAddr(e) => { EnablePlatformCoinWithTokensError::InvalidSwapContractAddr(e) }, @@ -292,7 +281,6 @@ impl HttpStatusCode for EnablePlatformCoinWithTokensError { EnablePlatformCoinWithTokensError::CoinProtocolParseError { .. } | EnablePlatformCoinWithTokensError::TokenProtocolParseError { .. } | EnablePlatformCoinWithTokensError::PlatformCoinCreationError { .. } - | EnablePlatformCoinWithTokensError::TokenCreationError { .. } | EnablePlatformCoinWithTokensError::PrivKeyNotAllowed(_) | EnablePlatformCoinWithTokensError::UnexpectedDerivationMethod(_) | EnablePlatformCoinWithTokensError::Transport(_) diff --git a/mm2src/coins_activation/src/token.rs b/mm2src/coins_activation/src/token.rs index 2437b02a42..9e27a9c079 100644 --- a/mm2src/coins_activation/src/token.rs +++ b/mm2src/coins_activation/src/token.rs @@ -58,7 +58,7 @@ pub enum EnableTokenError { }, #[display(fmt = "{}", _0)] UnexpectedDerivationMethod(UnexpectedDerivationMethod), - #[display(fmt = "{} is not valid payload.", _0)] + CouldNotFetchBalance(String), Transport(String), Internal(String), } @@ -157,6 +157,7 @@ impl HttpStatusCode for EnableTokenError { | EnableTokenError::UnsupportedPlatformCoin { .. } | EnableTokenError::UnexpectedDerivationMethod(_) | EnableTokenError::Transport(_) + | EnableTokenError::CouldNotFetchBalance(_) | EnableTokenError::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR, } } From ece5bdd31a8a1bff32ad25b126a34c94873a690f Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Fri, 22 Jul 2022 21:46:28 +0300 Subject: [PATCH 49/69] update visibility & privacy modifiers in `eth.rs` Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index fcb06b2ec1..caec7855d4 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -59,12 +59,10 @@ use web3::types::{Action as TraceAction, BlockId, BlockNumber, Bytes, CallReques use web3::{self, Web3}; use web3_transport::{EthFeeHistoryNamespace, Web3Transport, Web3TransportNode}; -use crate::coin_conf; - -use super::{AsyncMutex, BalanceError, BalanceFut, CoinBalance, CoinProtocol, CoinTransportMetrics, CoinsContext, - FeeApproxStage, FoundSwapTxSpend, HistorySyncState, MarketCoinOps, MmCoin, NegotiateSwapContractAddrErr, - NumConversError, NumConversResult, RawTransactionError, RawTransactionFut, RawTransactionRequest, - RawTransactionRes, RawTransactionResult, RpcClientType, RpcTransportEventHandler, +use super::{coin_conf, AsyncMutex, BalanceError, BalanceFut, CoinBalance, CoinProtocol, CoinTransportMetrics, + CoinsContext, FeeApproxStage, FoundSwapTxSpend, HistorySyncState, MarketCoinOps, MmCoin, + NegotiateSwapContractAddrErr, NumConversError, NumConversResult, RawTransactionError, RawTransactionFut, + RawTransactionRequest, RawTransactionRes, RawTransactionResult, RpcClientType, RpcTransportEventHandler, RpcTransportEventHandlerShared, SearchForSwapTxSpendInput, SignatureError, SignatureResult, SwapOps, TradeFee, TradePreimageError, TradePreimageFut, TradePreimageResult, TradePreimageValue, Transaction, TransactionDetails, TransactionEnum, TransactionErr, TransactionFut, UnexpectedDerivationMethod, @@ -329,8 +327,8 @@ struct SavedErc20Events { latest_block: U256, } -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum EthCoinType { +#[derive(Debug, PartialEq, Eq)] +enum EthCoinType { /// Ethereum itself or it's forks: ETC/others Eth, /// ERC20 token with smart contract address @@ -341,12 +339,12 @@ pub enum EthCoinType { /// pImpl idiom. #[derive(Debug)] pub struct EthCoinImpl { - pub ticker: String, + ticker: String, coin_type: EthCoinType, key_pair: KeyPair, my_address: Address, sign_message_prefix: Option, - pub swap_contract_address: Address, + swap_contract_address: Address, fallback_swap_contract: Option
, web3: Web3, /// The separate web3 instances kept to get nonce, will replace the web3 completely soon @@ -373,7 +371,7 @@ pub struct Web3Instance { is_parity: bool, } -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct Erc20TokenInfo { pub token_address: Address, pub decimals: u8, @@ -2568,7 +2566,7 @@ impl EthCoin { Ok(token_balances) } - pub fn get_token_balance_by_address(&self, token: Erc20TokenInfo) -> BalanceFut { + fn get_token_balance_by_address(&self, token: Erc20TokenInfo) -> BalanceFut { let coin = self.clone(); let fut = async move { let function = ERC20_CONTRACT.function("balanceOf")?; From d3ee87413a49b2b49a4eb94f7e98d945523b7263 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Fri, 22 Jul 2022 22:14:00 +0300 Subject: [PATCH 50/69] make `get_token_balance_by_address` async fn Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 54 +++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index caec7855d4..3c1a82c97e 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -603,8 +603,6 @@ impl EthCoinImpl { } } - pub fn ctx(&self) -> MmWeak { self.ctx.clone() } - pub async fn add_erc_token_info(&self, ticker: String, info: Erc20TokenInfo) { self.erc20_tokens_infos.lock().await.insert(ticker, info); } @@ -753,7 +751,7 @@ async fn withdraw_impl(coin: EthCoin, req: WithdrawRequest) -> WithdrawResult { } #[derive(Clone, Debug)] -pub struct EthCoin(pub Arc); +pub struct EthCoin(Arc); impl Deref for EthCoin { type Target = EthCoinImpl; fn deref(&self) -> &EthCoinImpl { &*self.0 } @@ -2551,41 +2549,35 @@ impl EthCoin { let coin = self.clone(); let mut token_balances = HashMap::new(); for (token_ticker, info) in self.get_erc_tokens_infos().await.iter() { - let balance: CoinBalance = coin - .get_token_balance_by_address(info.clone()) - .and_then(move |result| Ok(u256_to_big_decimal(result, info.decimals)?)) - .map(|spendable| CoinBalance { - spendable, - unspendable: BigDecimal::from(0), - }) - .compat() - .await?; + let balance_as_u256 = coin.get_token_balance_by_address(info.clone()).await?; + let balance_as_big_decimal = u256_to_big_decimal(balance_as_u256, info.decimals)?; + let balance = CoinBalance { + spendable: balance_as_big_decimal, + unspendable: BigDecimal::from(0), + }; token_balances.insert(token_ticker.clone(), balance); } Ok(token_balances) } - fn get_token_balance_by_address(&self, token: Erc20TokenInfo) -> BalanceFut { + async fn get_token_balance_by_address(&self, token: Erc20TokenInfo) -> Result> { let coin = self.clone(); - let fut = async move { - let function = ERC20_CONTRACT.function("balanceOf")?; - let data = function.encode_input(&[Token::Address(coin.my_address)])?; - let res = coin - .call_request(token.token_address, None, Some(data.into())) - .compat() - .await?; - let decoded = function.decode_output(&res.0)?; - match decoded[0] { - Token::Uint(number) => Ok(number), - _ => { - let error = format!("Expected U256 as balanceOf result but got {:?}", decoded); - MmError::err(BalanceError::InvalidResponse(error)) - }, - } - }; - - Box::new(fut.boxed().compat()) + let function = ERC20_CONTRACT.function("balanceOf")?; + let data = function.encode_input(&[Token::Address(coin.my_address)])?; + let res = coin + .call_request(token.token_address, None, Some(data.into())) + .compat() + .await?; + let decoded = function.decode_output(&res.0)?; + + match decoded[0] { + Token::Uint(number) => Ok(number), + _ => { + let error = format!("Expected U256 as balanceOf result but got {:?}", decoded); + MmError::err(BalanceError::InvalidResponse(error)) + }, + } } pub async fn initialize_erc20_token( From ec3373863b79bd0c1324157abc436d2dd8ce0925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Tue, 26 Jul 2022 00:43:14 +0300 Subject: [PATCH 51/69] avoid using hard-coded ticker for gui-auth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins/eth.rs | 4 +++- mm2src/coins_activation/src/eth_with_token_activation.rs | 4 +--- mm2src/mm2_net/src/transport.rs | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 3c1a82c97e..aaf7306e6c 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -3384,7 +3384,7 @@ impl GuiAuthMessages for EthCoin { let signature = sign(&generator.secret, &H256::from(message_hash))?; Ok(GuiAuthValidation { - coin_ticker: String::from("ETH"), + coin_ticker: generator.coin_ticker, address: generator.address, timestamp_message, signature: format!("0x{}", signature), @@ -3618,6 +3618,7 @@ pub async fn eth_coin_from_conf_and_request_v2( for node in &nodes { let mut transport = Web3Transport::with_event_handlers(vec![node.clone()], event_handlers.clone()); transport.gui_auth_validation_generator = Some(GuiAuthValidationGenerator { + coin_ticker: ticker.to_string(), secret: key_pair.secret().clone(), address: my_address.clone(), }); @@ -3645,6 +3646,7 @@ pub async fn eth_coin_from_conf_and_request_v2( let mut transport = Web3Transport::with_event_handlers(nodes, event_handlers); transport.gui_auth_validation_generator = Some(GuiAuthValidationGenerator { + coin_ticker: ticker.to_string(), secret: key_pair.secret().clone(), address: my_address, }); diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index a9bfbbf9a0..f63e0eed15 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -8,7 +8,7 @@ use coins::{eth::{eth_coin_from_conf_and_request_v2, Erc20Protocol, Erc20TokenAc Erc20TokenActivationRequest, Erc20TokenInfo, EthActivationV2Error, EthActivationV2Request, EthCoin}, my_tx_history_v2::TxHistoryStorage, CoinBalance, CoinProtocol, MarketCoinOps, MmCoin}; -use common::{drop_mutability, mm_metrics::MetricsArc, Future01CompatExt}; +use common::{mm_metrics::MetricsArc, Future01CompatExt}; use futures::future::AbortHandle; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; @@ -88,7 +88,6 @@ impl TokenInitializer for Erc20Initializer { .await?; tokens.push(token); } - drop_mutability!(tokens); Ok(tokens) } @@ -218,7 +217,6 @@ impl PlatformWithTokensActivationOps for EthCoin { pubkey: my_address, balances: token_balances, }); - drop_mutability!(result); Ok(result) } diff --git a/mm2src/mm2_net/src/transport.rs b/mm2src/mm2_net/src/transport.rs index f3c47f0b6c..d9ad4b7ab6 100644 --- a/mm2src/mm2_net/src/transport.rs +++ b/mm2src/mm2_net/src/transport.rs @@ -52,6 +52,7 @@ where #[derive(Clone, Debug)] pub struct GuiAuthValidationGenerator { + pub coin_ticker: String, pub secret: Secret, pub address: String, } From 619487a2b78626f11fdc043c0549027025e05d18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Tue, 26 Jul 2022 23:08:30 +0300 Subject: [PATCH 52/69] fix review note MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins/eth/web3_transport.rs | 23 +++++++++++++++++------ mm2src/mm2_net/src/transport.rs | 2 +- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index 4a61df68e9..a1ab4e6a03 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -3,7 +3,7 @@ use super::{EthCoin, GuiAuthMessages, RpcTransportEventHandler, RpcTransportEven use futures::TryFutureExt; use futures01::{Future, Poll}; use jsonrpc_core::{Call, Response}; -use mm2_net::transport::GuiAuthValidationGenerator; +use mm2_net::transport::{GuiAuthValidation, GuiAuthValidationGenerator}; use serde_json::Value as Json; #[cfg(not(target_arch = "wasm32"))] use std::ops::Deref; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -21,6 +21,13 @@ pub struct EthFeeHistoryNamespace { transport: T, } +#[derive(Serialize, Clone)] +pub struct AuthPayload<'a> { + #[serde(flatten)] + pub request: &'a Call, + pub signed_message: GuiAuthValidation, +} + impl Namespace for EthFeeHistoryNamespace { fn new(transport: T) -> Self where @@ -181,9 +188,8 @@ async fn send_request( let mut serialized_request = serialized_request.clone(); if node.gui_auth { if let Some(generator) = gui_auth_validation_generator.clone() { - let mut json_payload: Json = serde_json::from_str(&serialized_request)?; - json_payload["signed_message"] = match EthCoin::generate_gui_auth_signed_validation(generator) { - Ok(t) => serde_json::to_value(t)?, + let signed_message = match EthCoin::generate_gui_auth_signed_validation(generator) { + Ok(t) => t, Err(e) => { errors.push(ERRL!( "GuiAuth signed message generation failed for {:?} node, error: {:?}", @@ -193,8 +199,13 @@ async fn send_request( continue; }, }; - common::drop_mutability!(json_payload); - serialized_request = json_payload.to_string(); + + let auth_request = AuthPayload { + request: &request, + signed_message, + }; + + serialized_request = to_string(&auth_request); } else { errors.push(ERRL!("GuiAuthValidationGenerator is not provided for {:?} node", node)); continue; diff --git a/mm2src/mm2_net/src/transport.rs b/mm2src/mm2_net/src/transport.rs index d9ad4b7ab6..f829e730d5 100644 --- a/mm2src/mm2_net/src/transport.rs +++ b/mm2src/mm2_net/src/transport.rs @@ -58,7 +58,7 @@ pub struct GuiAuthValidationGenerator { } /// gui-auth specific data-type that needed in order to perform gui-auth calls -#[derive(Serialize)] +#[derive(Serialize, Clone)] pub struct GuiAuthValidation { pub coin_ticker: String, pub address: String, From 214df5c95368d0c39a24b51f9bcab6f2532f5c74 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 27 Jul 2022 01:55:20 +0300 Subject: [PATCH 53/69] optimize pr stage Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 8 +++++++- .../src/erc20_token_activation.rs | 15 ++++++++++----- .../src/eth_with_token_activation.rs | 7 +++++-- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index aaf7306e6c..b0546ce385 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -1165,7 +1165,13 @@ impl MarketCoinOps for EthCoin { fn my_address(&self) -> Result { Ok(checksum_address(&format!("{:#02x}", self.my_address))) } - fn get_public_key(&self) -> Result> { unimplemented!() } + fn get_public_key(&self) -> Result> { + let mut raw_pubkey = [0; 65]; + raw_pubkey[0] = 0x04; + raw_pubkey[1..].copy_from_slice(self.key_pair.public()); + let secp_public = PublicKey::from_slice(&raw_pubkey).unwrap(); + Ok(secp_public.to_string()) + } /// Hash message for signature using Ethereum's message signing format. /// keccak256(PREFIX_LENGTH + PREFIX + MESSAGE_LENGTH + MESSAGE) diff --git a/mm2src/coins_activation/src/erc20_token_activation.rs b/mm2src/coins_activation/src/erc20_token_activation.rs index 8253ac96f3..7585dcba0e 100644 --- a/mm2src/coins_activation/src/erc20_token_activation.rs +++ b/mm2src/coins_activation/src/erc20_token_activation.rs @@ -2,7 +2,7 @@ use crate::{prelude::{TryFromCoinProtocol, TryPlatformCoinFromMmCoinEnum}, token::{EnableTokenError, TokenActivationOps, TokenProtocolParams}}; use async_trait::async_trait; use coins::{eth::{valid_addr_from_str, Erc20Protocol, Erc20TokenActivationError, Erc20TokenActivationRequest, EthCoin}, - CoinBalance, CoinProtocol, MarketCoinOps, MmCoinEnum}; + CoinBalance, CoinProtocol, MarketCoinOps, MmCoin, MmCoinEnum}; use common::Future01CompatExt; use mm2_err_handle::prelude::MmError; use serde::Serialize; @@ -11,8 +11,9 @@ use std::collections::HashMap; #[derive(Debug, Serialize)] pub struct Erc20InitResult { balances: HashMap, - pubkey: String, platform_coin: String, + token_contract_address: String, + required_confirmations: u64, } impl From for EnableTokenError { @@ -80,7 +81,10 @@ impl TokenActivationOps for EthCoin { .initialize_erc20_token(activation_params, protocol_conf, ticker) .await?; - let my_address = token.my_address().map_err(Erc20TokenActivationError::InternalError)?; + let address = token.my_address().map_err(Erc20TokenActivationError::InternalError)?; + let token_contract_address = token + .erc20_token_address() + .ok_or_else(|| Erc20TokenActivationError::InternalError("Token contract address is missing".to_string()))?; let balance = token .my_balance() @@ -88,12 +92,13 @@ impl TokenActivationOps for EthCoin { .await .map_err(|e| Erc20TokenActivationError::CouldNotFetchBalance(e.to_string()))?; - let balances = HashMap::from([(my_address.clone(), balance)]); + let balances = HashMap::from([(address, balance)]); let init_result = Erc20InitResult { balances, - pubkey: my_address, platform_coin: token.platform_ticker().to_owned(), + required_confirmations: token.required_confirmations(), + token_contract_address: format!("{:#02x}", token_contract_address), }; Ok((token, init_result)) diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index f63e0eed15..55737ae9af 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -179,6 +179,9 @@ impl PlatformWithTokensActivationOps for EthCoin { async fn get_activation_result(&self) -> Result> { let my_address = self.my_address().map_err(EthActivationV2Error::InternalError)?; + let pubkey = self + .get_public_key() + .map_err(|e| EthActivationV2Error::InternalError(e.to_string()))?; let current_block = self .current_block() @@ -206,7 +209,7 @@ impl PlatformWithTokensActivationOps for EthCoin { .eth_addresses_infos .insert(my_address.to_string(), CoinAddressInfo { derivation_method: DerivationMethod::Iguana, - pubkey: my_address.clone(), + pubkey: pubkey.clone(), balances: eth_balance, }); @@ -214,7 +217,7 @@ impl PlatformWithTokensActivationOps for EthCoin { .erc20_addresses_infos .insert(my_address.to_string(), CoinAddressInfo { derivation_method: DerivationMethod::Iguana, - pubkey: my_address, + pubkey, balances: token_balances, }); From d9de507fe70901a500b38d5887a05bb3149d4af2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Wed, 27 Jul 2022 02:14:27 +0300 Subject: [PATCH 54/69] optimize `send_request` of wasm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins/eth/web3_transport.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index a1ab4e6a03..f13ae65b40 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -277,8 +277,7 @@ async fn send_request( let mut serialized_request = serialized_request.clone(); if node.gui_auth { if let Some(generator) = gui_auth_validation_generator.clone() { - let mut json_payload: Json = serde_json::from_str(&serialized_request)?; - json_payload["signed_message"] = match EthCoin::generate_gui_auth_signed_validation(generator) { + let signed_message = match EthCoin::generate_gui_auth_signed_validation(generator) { Ok(t) => serde_json::to_value(t)?, Err(e) => { transport_errors.push(ERRL!( @@ -289,8 +288,13 @@ async fn send_request( continue; }, }; - common::drop_mutability!(json_payload); - serialized_request = json_payload.to_string(); + + let auth_request = AuthPayload { + request: &request, + signed_message, + }; + + serialized_request = to_string(&auth_request); } else { transport_errors.push(ERRL!("GuiAuthValidationGenerator is not provided for {:?} node", node)); continue; From 4e00a1f2a4c9af5ec3d9e191caa893b0bc7238f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Wed, 27 Jul 2022 12:34:23 +0300 Subject: [PATCH 55/69] fix wasm compilation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins/eth/web3_transport.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index f13ae65b40..5fe66c57a5 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -278,7 +278,7 @@ async fn send_request( if node.gui_auth { if let Some(generator) = gui_auth_validation_generator.clone() { let signed_message = match EthCoin::generate_gui_auth_signed_validation(generator) { - Ok(t) => serde_json::to_value(t)?, + Ok(t) => t, Err(e) => { transport_errors.push(ERRL!( "GuiAuth signed message generation failed for {:?} node, error: {:?}", From 81c67c646ccf9c589d5f00c5f6dcf6421686e0c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Wed, 27 Jul 2022 16:50:25 +0300 Subject: [PATCH 56/69] fix pr notes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins/eth.rs | 5 +++-- .../src/eth_with_token_activation.rs | 4 ++-- .../src/platform_coin_with_tokens.rs | 12 ------------ 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index b0546ce385..4b39c072fd 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -251,7 +251,6 @@ impl From for BalanceError { #[derive(Display, Serialize, SerializeErrorType)] #[serde(tag = "error_type", content = "error_data")] -#[allow(dead_code)] pub enum EthActivationV2Error { InvalidPayload(String), InvalidSwapContractAddr(String), @@ -291,7 +290,6 @@ pub struct EthNode { #[derive(Serialize, SerializeErrorType)] #[serde(tag = "error_type", content = "error_data")] -#[allow(dead_code)] pub enum Erc20TokenActivationError { InternalError(String), CouldNotFetchBalance(String), @@ -2592,6 +2590,9 @@ impl EthCoin { protocol: Erc20Protocol, ticker: String, ) -> Result> { + // TODO + // Check if ctx is required. + // Remove it to avoid circular references if possible let ctx = MmArc::from_weak(&self.ctx) .ok_or_else(|| String::from("No context")) .map_err(Erc20TokenActivationError::InternalError)?; diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 55737ae9af..141fab1456 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -32,10 +32,10 @@ impl From for EnablePlatformCoinWithTokensError { }, EthActivationV2Error::InternalError(e) => EnablePlatformCoinWithTokensError::Internal(e), EthActivationV2Error::InvalidSwapContractAddr(e) => { - EnablePlatformCoinWithTokensError::InvalidSwapContractAddr(e) + EnablePlatformCoinWithTokensError::Internal(e) }, EthActivationV2Error::InvalidFallbackSwapContract(e) => { - EnablePlatformCoinWithTokensError::InvalidFallbackSwapContract(e) + EnablePlatformCoinWithTokensError::Internal(e) }, } } diff --git a/mm2src/coins_activation/src/platform_coin_with_tokens.rs b/mm2src/coins_activation/src/platform_coin_with_tokens.rs index 337c6084d0..ecd1dac377 100644 --- a/mm2src/coins_activation/src/platform_coin_with_tokens.rs +++ b/mm2src/coins_activation/src/platform_coin_with_tokens.rs @@ -66,8 +66,6 @@ pub trait TokenAsMmCoinInitializer: Send + Sync { pub enum InitTokensAsMmCoinsError { TokenConfigIsNotFound(String), InvalidPubkey(String), - InvalidSwapContractAddr(String), - InvalidFallbackSwapContract(String), CouldNotFetchBalance(String), Internal(String), TokenProtocolParseError { ticker: String, error: String }, @@ -217,8 +215,6 @@ pub enum EnablePlatformCoinWithTokensError { Transport(String), AtLeastOneNodeRequired(String), InvalidPayload(String), - InvalidSwapContractAddr(String), - InvalidFallbackSwapContract(String), Internal(String), } @@ -256,12 +252,6 @@ impl From for EnablePlatformCoinWithTokensError { InitTokensAsMmCoinsError::InvalidPubkey(e) | InitTokensAsMmCoinsError::Internal(e) => { EnablePlatformCoinWithTokensError::Internal(e) }, - InitTokensAsMmCoinsError::InvalidSwapContractAddr(e) => { - EnablePlatformCoinWithTokensError::InvalidSwapContractAddr(e) - }, - InitTokensAsMmCoinsError::InvalidFallbackSwapContract(e) => { - EnablePlatformCoinWithTokensError::InvalidFallbackSwapContract(e) - }, InitTokensAsMmCoinsError::CouldNotFetchBalance(e) => EnablePlatformCoinWithTokensError::Transport(e), } } @@ -290,8 +280,6 @@ impl HttpStatusCode for EnablePlatformCoinWithTokensError { | EnablePlatformCoinWithTokensError::TokenConfigIsNotFound(_) | EnablePlatformCoinWithTokensError::UnexpectedPlatformProtocol { .. } | EnablePlatformCoinWithTokensError::InvalidPayload { .. } - | EnablePlatformCoinWithTokensError::InvalidSwapContractAddr(_) - | EnablePlatformCoinWithTokensError::InvalidFallbackSwapContract(_) | EnablePlatformCoinWithTokensError::AtLeastOneNodeRequired(_) | EnablePlatformCoinWithTokensError::UnexpectedTokenProtocol { .. } => StatusCode::BAD_REQUEST, } From c038188bf8884ae94dca92f19f8eadd7049bf527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Wed, 27 Jul 2022 17:58:00 +0300 Subject: [PATCH 57/69] fix formatting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins_activation/src/eth_with_token_activation.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 141fab1456..79ad6973a6 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -31,12 +31,8 @@ impl From for EnablePlatformCoinWithTokensError { EnablePlatformCoinWithTokensError::Transport(e) }, EthActivationV2Error::InternalError(e) => EnablePlatformCoinWithTokensError::Internal(e), - EthActivationV2Error::InvalidSwapContractAddr(e) => { - EnablePlatformCoinWithTokensError::Internal(e) - }, - EthActivationV2Error::InvalidFallbackSwapContract(e) => { - EnablePlatformCoinWithTokensError::Internal(e) - }, + EthActivationV2Error::InvalidSwapContractAddr(e) => EnablePlatformCoinWithTokensError::Internal(e), + EthActivationV2Error::InvalidFallbackSwapContract(e) => EnablePlatformCoinWithTokensError::Internal(e), } } } From be591297f39950347f870289067c6b5577da656f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Thu, 28 Jul 2022 14:06:02 +0300 Subject: [PATCH 58/69] update `get_public_address` to uncompress format for ethereum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins/eth.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 4b39c072fd..52827c1eb0 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -1164,11 +1164,8 @@ impl MarketCoinOps for EthCoin { fn my_address(&self) -> Result { Ok(checksum_address(&format!("{:#02x}", self.my_address))) } fn get_public_key(&self) -> Result> { - let mut raw_pubkey = [0; 65]; - raw_pubkey[0] = 0x04; - raw_pubkey[1..].copy_from_slice(self.key_pair.public()); - let secp_public = PublicKey::from_slice(&raw_pubkey).unwrap(); - Ok(secp_public.to_string()) + let uncompressed_without_prefix = hex::encode(self.key_pair.public()); + Ok(format!("04{}", uncompressed_without_prefix)) } /// Hash message for signature using Ethereum's message signing format. From 300791e927e3e4e6c60e4ae19d605ab70dc13c7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Thu, 28 Jul 2022 15:32:39 +0300 Subject: [PATCH 59/69] no need to clone Erc20TokenInfo for `get_token_balance_by_address` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins/eth.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 52827c1eb0..f91e212814 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -2550,7 +2550,7 @@ impl EthCoin { let coin = self.clone(); let mut token_balances = HashMap::new(); for (token_ticker, info) in self.get_erc_tokens_infos().await.iter() { - let balance_as_u256 = coin.get_token_balance_by_address(info.clone()).await?; + let balance_as_u256 = coin.get_token_balance_by_address(info.token_address).await?; let balance_as_big_decimal = u256_to_big_decimal(balance_as_u256, info.decimals)?; let balance = CoinBalance { spendable: balance_as_big_decimal, @@ -2562,12 +2562,12 @@ impl EthCoin { Ok(token_balances) } - async fn get_token_balance_by_address(&self, token: Erc20TokenInfo) -> Result> { + async fn get_token_balance_by_address(&self, token_address: Address) -> Result> { let coin = self.clone(); let function = ERC20_CONTRACT.function("balanceOf")?; let data = function.encode_input(&[Token::Address(coin.my_address)])?; let res = coin - .call_request(token.token_address, None, Some(data.into())) + .call_request(token_address, None, Some(data.into())) .compat() .await?; let decoded = function.decode_output(&res.0)?; From 7bf4e5728470a29e8f9cc85d72d3c6c795eb1a2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Thu, 28 Jul 2022 17:50:18 +0300 Subject: [PATCH 60/69] update `InvalidSwapContractAddr` and `InvalidFallbackSwapContract` mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins_activation/src/eth_with_token_activation.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 79ad6973a6..4a75ee4280 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -20,7 +20,11 @@ use std::collections::HashMap; impl From for EnablePlatformCoinWithTokensError { fn from(err: EthActivationV2Error) -> Self { match err { - EthActivationV2Error::InvalidPayload(e) => EnablePlatformCoinWithTokensError::InvalidPayload(e), + EthActivationV2Error::InvalidPayload(e) + | EthActivationV2Error::InvalidSwapContractAddr(e) + | EthActivationV2Error::InvalidFallbackSwapContract(e) => { + EnablePlatformCoinWithTokensError::InvalidPayload(e) + }, EthActivationV2Error::ActivationFailed { ticker, error } => { EnablePlatformCoinWithTokensError::PlatformCoinCreationError { ticker, error } }, @@ -31,8 +35,6 @@ impl From for EnablePlatformCoinWithTokensError { EnablePlatformCoinWithTokensError::Transport(e) }, EthActivationV2Error::InternalError(e) => EnablePlatformCoinWithTokensError::Internal(e), - EthActivationV2Error::InvalidSwapContractAddr(e) => EnablePlatformCoinWithTokensError::Internal(e), - EthActivationV2Error::InvalidFallbackSwapContract(e) => EnablePlatformCoinWithTokensError::Internal(e), } } } From af3ed5060c98266648bd720adaa4479104927990 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Fri, 29 Jul 2022 23:41:36 +0300 Subject: [PATCH 61/69] refactor `AsyncMutex` to std one for `eth20_tokens_infos` of `EthCoinImpl` Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 18 +++++++++++------- mm2src/coins/solana.rs | 3 +++ .../src/eth_with_token_activation.rs | 3 +-- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index f91e212814..fc8aa55726 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -360,7 +360,7 @@ pub struct EthCoinImpl { /// the block range used for eth_getLogs logs_block_range: u64, nonce_lock: Arc>, - erc20_tokens_infos: Arc>>, + erc20_tokens_infos: Arc>>, } #[derive(Clone, Debug)] @@ -369,7 +369,7 @@ pub struct Web3Instance { is_parity: bool, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Erc20TokenInfo { pub token_address: Address, pub decimals: u8, @@ -601,12 +601,16 @@ impl EthCoinImpl { } } - pub async fn add_erc_token_info(&self, ticker: String, info: Erc20TokenInfo) { - self.erc20_tokens_infos.lock().await.insert(ticker, info); + pub fn add_erc_token_info(&self, ticker: String, info: Erc20TokenInfo) { + self.erc20_tokens_infos.lock().unwrap().insert(ticker, info); } - pub async fn get_erc_tokens_infos(&self) -> futures::lock::MutexGuard<'_, HashMap> { - self.erc20_tokens_infos.lock().await + /// WARNING + /// Be very careful using this function since it returns dereferenced clone + /// of value behind the MutexGuard and makes it non-thread-safe. + pub fn get_erc_tokens_infos(&self) -> HashMap { + let guard = self.erc20_tokens_infos.lock().unwrap(); + (*guard).clone() } } @@ -2549,7 +2553,7 @@ impl EthCoin { pub async fn get_tokens_balance_list(&self) -> Result, MmError> { let coin = self.clone(); let mut token_balances = HashMap::new(); - for (token_ticker, info) in self.get_erc_tokens_infos().await.iter() { + for (token_ticker, info) in self.get_erc_tokens_infos().iter() { let balance_as_u256 = coin.get_token_balance_by_address(info.token_address).await?; let balance_as_big_decimal = u256_to_big_decimal(balance_as_u256, info.decimals)?; let balance = CoinBalance { diff --git a/mm2src/coins/solana.rs b/mm2src/coins/solana.rs index 6bf3c7049c..c1671e7112 100644 --- a/mm2src/coins/solana.rs +++ b/mm2src/coins/solana.rs @@ -343,6 +343,9 @@ impl SolanaCoin { self.spl_tokens_infos.lock().unwrap().insert(ticker, info); } + /// WARNING + /// Be very careful using this function since it returns dereferenced clone + /// of value behind the MutexGuard and makes it non-thread-safe. pub fn get_spl_tokens_infos(&self) -> HashMap { let guard = self.spl_tokens_infos.lock().unwrap(); (*guard).clone() diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 4a75ee4280..57c854a1a2 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -110,11 +110,10 @@ impl TokenOf for EthCoin { impl RegisterTokenInfo for EthCoin { fn register_token_info(&self, token: &EthCoin) { - let fut = self.add_erc_token_info(token.ticker().to_string(), Erc20TokenInfo { + self.add_erc_token_info(token.ticker().to_string(), Erc20TokenInfo { token_address: token.erc20_token_address().unwrap(), decimals: token.decimals(), }); - futures::executor::block_on(fut); } } From 31605e5d53f387100619112fe0a2eeb5f891bdd9 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Tue, 2 Aug 2022 14:35:06 +0300 Subject: [PATCH 62/69] fix pr notes Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 279 +----------------- mm2src/coins/eth/v2_activation.rs | 276 +++++++++++++++++ mm2src/coins/eth/web3_transport.rs | 112 +++---- .../src/erc20_token_activation.rs | 3 +- .../src/eth_with_token_activation.rs | 5 +- 5 files changed, 344 insertions(+), 331 deletions(-) create mode 100644 mm2src/coins/eth/v2_activation.rs diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index fc8aa55726..9dde1b7489 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -75,6 +75,8 @@ pub use rlp; #[cfg(target_arch = "wasm32")] mod eth_wasm_tests; mod web3_transport; +#[path = "eth/v2_activation.rs"] pub mod v2_activation; + /// https://github.com/artemii235/etomic-swap/blob/master/contracts/EtomicSwap.sol /// Dev chain (195.201.0.6:8565) contract address: 0xa09ad3cd7e96586ebd05a2607ee56b56fb2db8fd /// Ropsten: https://ropsten.etherscan.io/address/0x7bc1bbdd6a0a722fc9bffc49c921b685ecb84b94 @@ -107,6 +109,9 @@ const GAS_PRICE_APPROXIMATION_PERCENT_ON_ORDER_ISSUE: u64 = 5; /// - it may increase by 3% during the swap. const GAS_PRICE_APPROXIMATION_PERCENT_ON_TRADE_PREIMAGE: u64 = 7; +/// Lifetime of generated signed message for gui-auth requests +const GUI_AUTH_SIGNED_MESSAGE_LIFETIME_SEC: i64 = 90; + lazy_static! { pub static ref SWAP_CONTRACT: Contract = Contract::load(SWAP_CONTRACT_ABI.as_bytes()).unwrap(); pub static ref ERC20_CONTRACT: Contract = Contract::load(ERC20_ABI.as_bytes()).unwrap(); @@ -249,62 +254,6 @@ impl From for BalanceError { fn from(e: web3::Error) -> Self { BalanceError::Transport(e.to_string()) } } -#[derive(Display, Serialize, SerializeErrorType)] -#[serde(tag = "error_type", content = "error_data")] -pub enum EthActivationV2Error { - InvalidPayload(String), - InvalidSwapContractAddr(String), - InvalidFallbackSwapContract(String), - #[display(fmt = "Platform coin {} activation failed. {}", ticker, error)] - ActivationFailed { - ticker: String, - error: String, - }, - CouldNotFetchBalance(String), - UnreachableNodes(String), - #[display(fmt = "Enable request for ETH coin must have at least 1 node")] - AtLeastOneNodeRequired, - InternalError(String), -} - -#[derive(Clone, Deserialize)] -pub struct EthActivationV2Request { - pub nodes: Vec, - pub swap_contract_address: Address, - pub fallback_swap_contract: Option
, - pub gas_station_url: Option, - pub gas_station_decimals: Option, - #[serde(default)] - pub gas_station_policy: GasStationPricePolicy, - pub mm2: Option, - #[serde(default)] - pub tx_history: bool, - pub required_confirmations: Option, -} - -#[derive(Clone, Deserialize)] -pub struct EthNode { - pub url: String, - pub gui_auth: bool, -} - -#[derive(Serialize, SerializeErrorType)] -#[serde(tag = "error_type", content = "error_data")] -pub enum Erc20TokenActivationError { - InternalError(String), - CouldNotFetchBalance(String), -} - -#[derive(Clone, Deserialize)] -pub struct Erc20TokenActivationRequest { - pub required_confirmations: Option, -} - -pub struct Erc20Protocol { - pub platform: String, - pub token_addr: Address, -} - #[derive(Debug, Deserialize, Serialize)] struct SavedTraces { /// ETH traces for my_address @@ -2585,62 +2534,6 @@ impl EthCoin { } } - pub async fn initialize_erc20_token( - &self, - activation_params: Erc20TokenActivationRequest, - protocol: Erc20Protocol, - ticker: String, - ) -> Result> { - // TODO - // Check if ctx is required. - // Remove it to avoid circular references if possible - let ctx = MmArc::from_weak(&self.ctx) - .ok_or_else(|| String::from("No context")) - .map_err(Erc20TokenActivationError::InternalError)?; - - let conf = coin_conf(&ctx, &ticker); - - let decimals = match conf["decimals"].as_u64() { - None | Some(0) => get_token_decimals(&self.web3, protocol.token_addr) - .await - .map_err(Erc20TokenActivationError::InternalError)?, - Some(d) => d as u8, - }; - - let required_confirmations = activation_params - .required_confirmations - .unwrap_or_else(|| conf["required_confirmations"].as_u64().unwrap_or(1)) - .into(); - - let token = EthCoinImpl { - key_pair: self.key_pair.clone(), - my_address: self.my_address, - coin_type: EthCoinType::Erc20 { - platform: protocol.platform, - token_addr: protocol.token_addr, - }, - sign_message_prefix: self.sign_message_prefix.clone(), - swap_contract_address: self.swap_contract_address, - fallback_swap_contract: self.fallback_swap_contract, - decimals, - ticker, - gas_station_url: self.gas_station_url.clone(), - gas_station_decimals: self.gas_station_decimals, - gas_station_policy: self.gas_station_policy, - web3: self.web3.clone(), - web3_instances: self.web3_instances.clone(), - history_sync_state: Mutex::new(self.history_sync_state.lock().unwrap().clone()), - ctx: self.ctx.clone(), - required_confirmations, - chain_id: self.chain_id, - logs_block_range: self.logs_block_range, - nonce_lock: self.nonce_lock.clone(), - erc20_tokens_infos: Default::default(), - }; - - Ok(EthCoin(Arc::new(token))) - } - /// Estimates how much gas is necessary to allow the contract call to complete. /// `contract_addr` can be a ERC20 token address or any other contract address. /// @@ -3385,7 +3278,7 @@ impl GuiAuthMessages for EthCoin { fn generate_gui_auth_signed_validation( generator: GuiAuthValidationGenerator, ) -> SignatureResult { - let timestamp_message = get_utc_timestamp() + 90; // 90 seconds to expire + let timestamp_message = get_utc_timestamp() + GUI_AUTH_SIGNED_MESSAGE_LIFETIME_SEC; let message_hash = EthCoin::gui_auth_sign_message_hash(timestamp_message.to_string()).ok_or(SignatureError::PrefixNotFound)?; @@ -3570,166 +3463,6 @@ fn rpc_event_handlers_for_eth_transport(ctx: &MmArc, ticker: String) -> Vec Arc> { Arc::new(AsyncMutex::new(())) } -pub async fn eth_coin_from_conf_and_request_v2( - ctx: &MmArc, - ticker: &str, - conf: &Json, - req: EthActivationV2Request, - priv_key: &[u8], - protocol: CoinProtocol, -) -> Result> { - if req.nodes.is_empty() { - return Err(EthActivationV2Error::AtLeastOneNodeRequired.into()); - } - - let mut rng = small_rng(); - let mut req = req; - req.nodes.as_mut_slice().shuffle(&mut rng); - drop_mutability!(req); - - let mut nodes = vec![]; - for node in req.nodes.iter() { - let uri = node - .url - .parse() - .map_err(|_| EthActivationV2Error::InvalidPayload(format!("{} could not be parsed.", node.url)))?; - - nodes.push(Web3TransportNode { - uri, - gui_auth: node.gui_auth, - }); - } - drop_mutability!(nodes); - - if req.swap_contract_address == Address::default() { - return Err(EthActivationV2Error::InvalidSwapContractAddr( - "swap_contract_address can't be zero address".to_string(), - ) - .into()); - } - - if let Some(fallback) = req.fallback_swap_contract { - if fallback == Address::default() { - return Err(EthActivationV2Error::InvalidFallbackSwapContract( - "fallback_swap_contract can't be zero address".to_string(), - ) - .into()); - } - } - - let key_pair: KeyPair = - KeyPair::from_secret_slice(priv_key).map_err(|e| EthActivationV2Error::InternalError(e.to_string()))?; - let my_address = checksum_address(&format!("{:02x}", key_pair.address())); - - let mut web3_instances = vec![]; - let event_handlers = rpc_event_handlers_for_eth_transport(ctx, ticker.to_string()); - for node in &nodes { - let mut transport = Web3Transport::with_event_handlers(vec![node.clone()], event_handlers.clone()); - transport.gui_auth_validation_generator = Some(GuiAuthValidationGenerator { - coin_ticker: ticker.to_string(), - secret: key_pair.secret().clone(), - address: my_address.clone(), - }); - drop_mutability!(transport); - - let web3 = Web3::new(transport); - let version = match web3.web3().client_version().compat().await { - Ok(v) => v, - Err(e) => { - error!("Couldn't get client version for url {}: {}", node.uri, e); - continue; - }, - }; - web3_instances.push(Web3Instance { - web3, - is_parity: version.contains("Parity") || version.contains("parity"), - }) - } - - if web3_instances.is_empty() { - return Err( - EthActivationV2Error::UnreachableNodes("Failed to get client version for all nodes".to_string()).into(), - ); - } - - let mut transport = Web3Transport::with_event_handlers(nodes, event_handlers); - transport.gui_auth_validation_generator = Some(GuiAuthValidationGenerator { - coin_ticker: ticker.to_string(), - secret: key_pair.secret().clone(), - address: my_address, - }); - drop_mutability!(transport); - - let web3 = Web3::new(transport); - - let (coin_type, decimals) = match protocol { - CoinProtocol::ETH => (EthCoinType::Eth, 18), - CoinProtocol::ERC20 { - platform, - contract_address, - } => { - let token_addr = valid_addr_from_str(&contract_address).map_err(EthActivationV2Error::InternalError)?; - let decimals = match conf["decimals"].as_u64() { - None | Some(0) => get_token_decimals(&web3, token_addr) - .await - .map_err(EthActivationV2Error::InternalError)?, - Some(d) => d as u8, - }; - (EthCoinType::Erc20 { platform, token_addr }, decimals) - }, - _ => { - return Err(EthActivationV2Error::InvalidPayload("Expect ETH or ERC20 protocol".to_string()).into()); - }, - }; - - // param from request should override the config - let required_confirmations = req - .required_confirmations - .unwrap_or_else(|| conf["required_confirmations"].as_u64().unwrap_or(1)) - .into(); - - let sign_message_prefix: Option = json::from_value(conf["sign_message_prefix"].clone()).unwrap_or(None); - - let initial_history_state = if req.tx_history { - HistorySyncState::NotStarted - } else { - HistorySyncState::NotEnabled - }; - - let key_lock = match &coin_type { - EthCoinType::Eth => String::from(ticker), - EthCoinType::Erc20 { ref platform, .. } => String::from(platform), - }; - - let mut map = NONCE_LOCK.lock().unwrap(); - let nonce_lock = map.entry(key_lock).or_insert_with(new_nonce_lock).clone(); - - let coin = EthCoinImpl { - key_pair: key_pair.clone(), - my_address: key_pair.address(), - coin_type, - sign_message_prefix, - swap_contract_address: req.swap_contract_address, - fallback_swap_contract: req.fallback_swap_contract, - decimals, - ticker: ticker.into(), - gas_station_url: req.gas_station_url, - gas_station_decimals: req.gas_station_decimals.unwrap_or(ETH_GAS_STATION_DECIMALS), - gas_station_policy: req.gas_station_policy, - web3, - web3_instances, - history_sync_state: Mutex::new(initial_history_state), - ctx: ctx.weak(), - required_confirmations, - chain_id: conf["chain_id"].as_u64(), - logs_block_range: conf["logs_block_range"].as_u64().unwrap_or(DEFAULT_LOGS_BLOCK_RANGE), - nonce_lock, - erc20_tokens_infos: Default::default(), - }; - - Ok(EthCoin(Arc::new(coin))) -} - pub async fn eth_coin_from_conf_and_request( ctx: &MmArc, ticker: &str, diff --git a/mm2src/coins/eth/v2_activation.rs b/mm2src/coins/eth/v2_activation.rs new file mode 100644 index 0000000000..39c0d30e51 --- /dev/null +++ b/mm2src/coins/eth/v2_activation.rs @@ -0,0 +1,276 @@ +use super::*; + +#[derive(Display, Serialize, SerializeErrorType)] +#[serde(tag = "error_type", content = "error_data")] +pub enum EthActivationV2Error { + InvalidPayload(String), + InvalidSwapContractAddr(String), + InvalidFallbackSwapContract(String), + #[display(fmt = "Platform coin {} activation failed. {}", ticker, error)] + ActivationFailed { + ticker: String, + error: String, + }, + CouldNotFetchBalance(String), + UnreachableNodes(String), + #[display(fmt = "Enable request for ETH coin must have at least 1 node")] + AtLeastOneNodeRequired, + InternalError(String), +} + +#[derive(Clone, Deserialize)] +pub struct EthActivationV2Request { + pub nodes: Vec, + pub swap_contract_address: Address, + pub fallback_swap_contract: Option
, + pub gas_station_url: Option, + pub gas_station_decimals: Option, + #[serde(default)] + pub gas_station_policy: GasStationPricePolicy, + pub mm2: Option, + #[serde(default)] + pub tx_history: bool, + pub required_confirmations: Option, +} + +#[derive(Clone, Deserialize)] +pub struct EthNode { + pub url: String, + pub gui_auth: bool, +} + +#[derive(Serialize, SerializeErrorType)] +#[serde(tag = "error_type", content = "error_data")] +pub enum Erc20TokenActivationError { + InternalError(String), + CouldNotFetchBalance(String), +} + +#[derive(Clone, Deserialize)] +pub struct Erc20TokenActivationRequest { + pub required_confirmations: Option, +} + +pub struct Erc20Protocol { + pub platform: String, + pub token_addr: Address, +} + +#[cfg_attr(test, mockable)] +impl EthCoin { + pub async fn initialize_erc20_token( + &self, + activation_params: Erc20TokenActivationRequest, + protocol: Erc20Protocol, + ticker: String, + ) -> Result> { + // TODO + // Check if ctx is required. + // Remove it to avoid circular references if possible + let ctx = MmArc::from_weak(&self.ctx) + .ok_or_else(|| String::from("No context")) + .map_err(Erc20TokenActivationError::InternalError)?; + + let conf = coin_conf(&ctx, &ticker); + + let decimals = match conf["decimals"].as_u64() { + None | Some(0) => get_token_decimals(&self.web3, protocol.token_addr) + .await + .map_err(Erc20TokenActivationError::InternalError)?, + Some(d) => d as u8, + }; + + let required_confirmations = activation_params + .required_confirmations + .unwrap_or_else(|| conf["required_confirmations"].as_u64().unwrap_or(1)) + .into(); + + let token = EthCoinImpl { + key_pair: self.key_pair.clone(), + my_address: self.my_address, + coin_type: EthCoinType::Erc20 { + platform: protocol.platform, + token_addr: protocol.token_addr, + }, + sign_message_prefix: self.sign_message_prefix.clone(), + swap_contract_address: self.swap_contract_address, + fallback_swap_contract: self.fallback_swap_contract, + decimals, + ticker, + gas_station_url: self.gas_station_url.clone(), + gas_station_decimals: self.gas_station_decimals, + gas_station_policy: self.gas_station_policy, + web3: self.web3.clone(), + web3_instances: self.web3_instances.clone(), + history_sync_state: Mutex::new(self.history_sync_state.lock().unwrap().clone()), + ctx: self.ctx.clone(), + required_confirmations, + chain_id: self.chain_id, + logs_block_range: self.logs_block_range, + nonce_lock: self.nonce_lock.clone(), + erc20_tokens_infos: Default::default(), + }; + + Ok(EthCoin(Arc::new(token))) + } +} + +pub async fn eth_coin_from_conf_and_request_v2( + ctx: &MmArc, + ticker: &str, + conf: &Json, + req: EthActivationV2Request, + priv_key: &[u8], + protocol: CoinProtocol, +) -> Result> { + if req.nodes.is_empty() { + return Err(EthActivationV2Error::AtLeastOneNodeRequired.into()); + } + + let mut rng = small_rng(); + let mut req = req; + req.nodes.as_mut_slice().shuffle(&mut rng); + drop_mutability!(req); + + let mut nodes = vec![]; + for node in req.nodes.iter() { + let uri = node + .url + .parse() + .map_err(|_| EthActivationV2Error::InvalidPayload(format!("{} could not be parsed.", node.url)))?; + + nodes.push(Web3TransportNode { + uri, + gui_auth: node.gui_auth, + }); + } + drop_mutability!(nodes); + + if req.swap_contract_address == Address::default() { + return Err(EthActivationV2Error::InvalidSwapContractAddr( + "swap_contract_address can't be zero address".to_string(), + ) + .into()); + } + + if let Some(fallback) = req.fallback_swap_contract { + if fallback == Address::default() { + return Err(EthActivationV2Error::InvalidFallbackSwapContract( + "fallback_swap_contract can't be zero address".to_string(), + ) + .into()); + } + } + + let key_pair: KeyPair = + KeyPair::from_secret_slice(priv_key).map_err(|e| EthActivationV2Error::InternalError(e.to_string()))?; + let my_address = checksum_address(&format!("{:02x}", key_pair.address())); + + let mut web3_instances = vec![]; + let event_handlers = rpc_event_handlers_for_eth_transport(ctx, ticker.to_string()); + for node in &nodes { + let mut transport = Web3Transport::with_event_handlers(vec![node.clone()], event_handlers.clone()); + transport.gui_auth_validation_generator = Some(GuiAuthValidationGenerator { + coin_ticker: ticker.to_string(), + secret: key_pair.secret().clone(), + address: my_address.clone(), + }); + drop_mutability!(transport); + + let web3 = Web3::new(transport); + let version = match web3.web3().client_version().compat().await { + Ok(v) => v, + Err(e) => { + error!("Couldn't get client version for url {}: {}", node.uri, e); + continue; + }, + }; + web3_instances.push(Web3Instance { + web3, + is_parity: version.contains("Parity") || version.contains("parity"), + }) + } + + if web3_instances.is_empty() { + return Err( + EthActivationV2Error::UnreachableNodes("Failed to get client version for all nodes".to_string()).into(), + ); + } + + let mut transport = Web3Transport::with_event_handlers(nodes, event_handlers); + transport.gui_auth_validation_generator = Some(GuiAuthValidationGenerator { + coin_ticker: ticker.to_string(), + secret: key_pair.secret().clone(), + address: my_address, + }); + drop_mutability!(transport); + + let web3 = Web3::new(transport); + + let (coin_type, decimals) = match protocol { + CoinProtocol::ETH => (EthCoinType::Eth, 18), + CoinProtocol::ERC20 { + platform, + contract_address, + } => { + let token_addr = valid_addr_from_str(&contract_address).map_err(EthActivationV2Error::InternalError)?; + let decimals = match conf["decimals"].as_u64() { + None | Some(0) => get_token_decimals(&web3, token_addr) + .await + .map_err(EthActivationV2Error::InternalError)?, + Some(d) => d as u8, + }; + (EthCoinType::Erc20 { platform, token_addr }, decimals) + }, + _ => { + return Err(EthActivationV2Error::InvalidPayload("Expect ETH or ERC20 protocol".to_string()).into()); + }, + }; + + // param from request should override the config + let required_confirmations = req + .required_confirmations + .unwrap_or_else(|| conf["required_confirmations"].as_u64().unwrap_or(1)) + .into(); + + let sign_message_prefix: Option = json::from_value(conf["sign_message_prefix"].clone()).unwrap_or(None); + + let initial_history_state = if req.tx_history { + HistorySyncState::NotStarted + } else { + HistorySyncState::NotEnabled + }; + + let key_lock = match &coin_type { + EthCoinType::Eth => String::from(ticker), + EthCoinType::Erc20 { ref platform, .. } => String::from(platform), + }; + + let mut map = NONCE_LOCK.lock().unwrap(); + let nonce_lock = map.entry(key_lock).or_insert_with(new_nonce_lock).clone(); + + let coin = EthCoinImpl { + key_pair: key_pair.clone(), + my_address: key_pair.address(), + coin_type, + sign_message_prefix, + swap_contract_address: req.swap_contract_address, + fallback_swap_contract: req.fallback_swap_contract, + decimals, + ticker: ticker.into(), + gas_station_url: req.gas_station_url, + gas_station_decimals: req.gas_station_decimals.unwrap_or(ETH_GAS_STATION_DECIMALS), + gas_station_policy: req.gas_station_policy, + web3, + web3_instances, + history_sync_state: Mutex::new(initial_history_state), + ctx: ctx.weak(), + required_confirmations, + chain_id: conf["chain_id"].as_u64(), + logs_block_range: conf["logs_block_range"].as_u64().unwrap_or(DEFAULT_LOGS_BLOCK_RANGE), + nonce_lock, + erc20_tokens_infos: Default::default(), + }; + + Ok(EthCoin(Arc::new(coin))) +} diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index 5fe66c57a5..3f2912aeec 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -164,6 +164,46 @@ impl Transport for Web3Transport { } } +/// Generates a signed message and inserts it into request +/// payload if gui_auth is activated. Returns false on errors. +fn handle_gui_auth_payload_if_activated( + gui_auth_validation_generator: &Option, + node: &Web3TransportNode, + request: &Call, + errors: &mut Vec, +) -> Result { + if !node.gui_auth { + return Err(true); + } + + let generator = match gui_auth_validation_generator.clone() { + Some(gen) => gen, + None => { + errors.push(ERRL!("GuiAuthValidationGenerator is not provided for {:?} node", node)); + return Err(false); + }, + }; + + let signed_message = match EthCoin::generate_gui_auth_signed_validation(generator) { + Ok(t) => t, + Err(e) => { + errors.push(ERRL!( + "GuiAuth signed message generation failed for {:?} node, error: {:?}", + node, + e + )); + return Err(false); + }, + }; + + let auth_request = AuthPayload { + request, + signed_message, + }; + + Ok(to_string(&auth_request)) +} + #[cfg(not(target_arch = "wasm32"))] async fn send_request( request: Call, @@ -185,33 +225,12 @@ async fn send_request( let serialized_request = to_string(&request); for node in nodes.iter() { - let mut serialized_request = serialized_request.clone(); - if node.gui_auth { - if let Some(generator) = gui_auth_validation_generator.clone() { - let signed_message = match EthCoin::generate_gui_auth_signed_validation(generator) { - Ok(t) => t, - Err(e) => { - errors.push(ERRL!( - "GuiAuth signed message generation failed for {:?} node, error: {:?}", - node, - e - )); - continue; - }, - }; - - let auth_request = AuthPayload { - request: &request, - signed_message, - }; - - serialized_request = to_string(&auth_request); - } else { - errors.push(ERRL!("GuiAuthValidationGenerator is not provided for {:?} node", node)); - continue; - } - } - common::drop_mutability!(serialized_request); + let serialized_request = + match handle_gui_auth_payload_if_activated(&gui_auth_validation_generator, node, &request, &mut errors) { + Ok(r) => r, + Err(true) => serialized_request.clone(), + Err(false) => continue, + }; event_handlers.on_outgoing_request(serialized_request.as_bytes()); @@ -273,34 +292,17 @@ async fn send_request( let serialized_request = to_string(&request); let mut transport_errors = Vec::new(); - for node in nodes { - let mut serialized_request = serialized_request.clone(); - if node.gui_auth { - if let Some(generator) = gui_auth_validation_generator.clone() { - let signed_message = match EthCoin::generate_gui_auth_signed_validation(generator) { - Ok(t) => t, - Err(e) => { - transport_errors.push(ERRL!( - "GuiAuth signed message generation failed for {:?} node, error: {:?}", - node, - e - )); - continue; - }, - }; - - let auth_request = AuthPayload { - request: &request, - signed_message, - }; - - serialized_request = to_string(&auth_request); - } else { - transport_errors.push(ERRL!("GuiAuthValidationGenerator is not provided for {:?} node", node)); - continue; - } - } - common::drop_mutability!(serialized_request); + for node in nodes.iter() { + let serialized_request = match handle_gui_auth_payload_if_activated( + &gui_auth_validation_generator, + node, + &request, + &mut transport_errors, + ) { + Ok(r) => r, + Err(true) => serialized_request.clone(), + Err(false) => continue, + }; match send_request_once(serialized_request.clone(), &node.uri, &event_handlers).await { Ok(response_json) => return Ok(response_json), diff --git a/mm2src/coins_activation/src/erc20_token_activation.rs b/mm2src/coins_activation/src/erc20_token_activation.rs index 7585dcba0e..1869fb046d 100644 --- a/mm2src/coins_activation/src/erc20_token_activation.rs +++ b/mm2src/coins_activation/src/erc20_token_activation.rs @@ -1,7 +1,8 @@ use crate::{prelude::{TryFromCoinProtocol, TryPlatformCoinFromMmCoinEnum}, token::{EnableTokenError, TokenActivationOps, TokenProtocolParams}}; use async_trait::async_trait; -use coins::{eth::{valid_addr_from_str, Erc20Protocol, Erc20TokenActivationError, Erc20TokenActivationRequest, EthCoin}, +use coins::{eth::{v2_activation::{Erc20Protocol, Erc20TokenActivationError, Erc20TokenActivationRequest}, + valid_addr_from_str, EthCoin}, CoinBalance, CoinProtocol, MarketCoinOps, MmCoin, MmCoinEnum}; use common::Future01CompatExt; use mm2_err_handle::prelude::MmError; diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 57c854a1a2..2db2c24926 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -4,8 +4,9 @@ use crate::{platform_coin_with_tokens::{EnablePlatformCoinWithTokensError, GetPl TokenInitializer, TokenOf}, prelude::*}; use async_trait::async_trait; -use coins::{eth::{eth_coin_from_conf_and_request_v2, Erc20Protocol, Erc20TokenActivationError, - Erc20TokenActivationRequest, Erc20TokenInfo, EthActivationV2Error, EthActivationV2Request, EthCoin}, +use coins::{eth::{v2_activation::{eth_coin_from_conf_and_request_v2, Erc20Protocol, Erc20TokenActivationError, + Erc20TokenActivationRequest, EthActivationV2Error, EthActivationV2Request}, + Erc20TokenInfo, EthCoin}, my_tx_history_v2::TxHistoryStorage, CoinBalance, CoinProtocol, MarketCoinOps, MmCoin}; use common::{mm_metrics::MetricsArc, Future01CompatExt}; From 8c37c203d4ada6b8ef33c58d0892e127eafc6dd8 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 3 Aug 2022 15:05:28 +0300 Subject: [PATCH 63/69] fix pr reviews Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 10 ++- mm2src/coins/eth/v2_activation.rs | 8 ++- mm2src/coins/eth/web3_transport.rs | 72 +++++++++---------- .../src/eth_with_token_activation.rs | 11 ++- 4 files changed, 58 insertions(+), 43 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 9dde1b7489..6cf5a6a152 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -97,6 +97,8 @@ const GAS_PRICE_PERCENT: u64 = 10; const BASE_BLOCK_FEE_DIFF_PCT: u64 = 13; const DEFAULT_LOGS_BLOCK_RANGE: u64 = 1000; +const DEFAULT_REQUIRED_CONFIRMATIONS: u8 = 1; + /// Take into account that the dynamic fee may increase by 3% during the swap. const GAS_PRICE_APPROXIMATION_PERCENT_ON_START_SWAP: u64 = 3; /// Take into account that the dynamic fee may increase at each of the following stages: @@ -304,7 +306,7 @@ pub struct EthCoinImpl { required_confirmations: AtomicU64, /// Coin needs access to the context in order to reuse the logging and shutdown facilities. /// Using a weak reference by default in order to avoid circular references and leaks. - ctx: MmWeak, + pub ctx: MmWeak, chain_id: Option, /// the block range used for eth_getLogs logs_block_range: u64, @@ -3546,7 +3548,11 @@ pub async fn eth_coin_from_conf_and_request( // param from request should override the config let required_confirmations = req["required_confirmations"] .as_u64() - .unwrap_or_else(|| conf["required_confirmations"].as_u64().unwrap_or(1)) + .unwrap_or_else(|| { + conf["required_confirmations"] + .as_u64() + .unwrap_or(DEFAULT_REQUIRED_CONFIRMATIONS as u64) + }) .into(); if req["requires_notarization"].as_bool().is_some() { diff --git a/mm2src/coins/eth/v2_activation.rs b/mm2src/coins/eth/v2_activation.rs index 39c0d30e51..55ac99de63 100644 --- a/mm2src/coins/eth/v2_activation.rs +++ b/mm2src/coins/eth/v2_activation.rs @@ -230,10 +230,14 @@ pub async fn eth_coin_from_conf_and_request_v2( // param from request should override the config let required_confirmations = req .required_confirmations - .unwrap_or_else(|| conf["required_confirmations"].as_u64().unwrap_or(1)) + .unwrap_or_else(|| { + conf["required_confirmations"] + .as_u64() + .unwrap_or(DEFAULT_REQUIRED_CONFIRMATIONS as u64) + }) .into(); - let sign_message_prefix: Option = json::from_value(conf["sign_message_prefix"].clone()).unwrap_or(None); + let sign_message_prefix: Option = json::from_value(conf["sign_message_prefix"].clone()).ok(); let initial_history_state = if req.tx_history { HistorySyncState::NotStarted diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index 3f2912aeec..a0632c5082 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -1,4 +1,4 @@ -use super::{EthCoin, GuiAuthMessages, RpcTransportEventHandler, RpcTransportEventHandlerShared}; +use super::{EthCoin, GuiAuthMessages, RpcTransportEventHandler, RpcTransportEventHandlerShared, Web3RpcError}; #[cfg(not(target_arch = "wasm32"))] use futures::FutureExt; use futures::TryFutureExt; use futures01::{Future, Poll}; @@ -170,29 +170,28 @@ fn handle_gui_auth_payload_if_activated( gui_auth_validation_generator: &Option, node: &Web3TransportNode, request: &Call, - errors: &mut Vec, -) -> Result { +) -> Result, Web3RpcError> { if !node.gui_auth { - return Err(true); + return Ok(None); } let generator = match gui_auth_validation_generator.clone() { Some(gen) => gen, None => { - errors.push(ERRL!("GuiAuthValidationGenerator is not provided for {:?} node", node)); - return Err(false); + return Err(Web3RpcError::Internal(format!( + "GuiAuthValidationGenerator is not provided for {:?} node", + node + ))); }, }; let signed_message = match EthCoin::generate_gui_auth_signed_validation(generator) { Ok(t) => t, Err(e) => { - errors.push(ERRL!( + return Err(Web3RpcError::Internal(format!( "GuiAuth signed message generation failed for {:?} node, error: {:?}", - node, - e - )); - return Err(false); + node, e + ))); }, }; @@ -201,7 +200,7 @@ fn handle_gui_auth_payload_if_activated( signed_message, }; - Ok(to_string(&auth_request)) + Ok(Some(to_string(&auth_request))) } #[cfg(not(target_arch = "wasm32"))] @@ -226,10 +225,13 @@ async fn send_request( for node in nodes.iter() { let serialized_request = - match handle_gui_auth_payload_if_activated(&gui_auth_validation_generator, node, &request, &mut errors) { - Ok(r) => r, - Err(true) => serialized_request.clone(), - Err(false) => continue, + match handle_gui_auth_payload_if_activated(&gui_auth_validation_generator, node, &request) { + Ok(Some(r)) => r, + Ok(None) => serialized_request.clone(), + Err(e) => { + errors.push(e); + continue; + }, }; event_handlers.on_outgoing_request(serialized_request.as_bytes()); @@ -245,13 +247,12 @@ async fn send_request( let res = match rc { Either::Left((r, _t)) => r, Either::Right((_t, _r)) => { - let error = ERRL!( + let error = format!( "Error requesting '{}': {}s timeout expired", - node.uri, - REQUEST_TIMEOUT_S + node.uri, REQUEST_TIMEOUT_S ); warn!("{}", error); - errors.push(error); + errors.push(Web3RpcError::Transport(error)); continue; }, }; @@ -259,7 +260,7 @@ async fn send_request( let (status, _headers, body) = match res { Ok(r) => r, Err(err) => { - errors.push(err.to_string()); + errors.push(Web3RpcError::Transport(err.to_string())); continue; }, }; @@ -267,12 +268,12 @@ async fn send_request( event_handlers.on_incoming_response(&body); if !status.is_success() { - errors.push(ERRL!( + errors.push(Web3RpcError::Transport(format!( "Server '{:?}' response !200: {}, {}", node, status, binprint(&body, b'.') - )); + ))); continue; } @@ -293,21 +294,20 @@ async fn send_request( let mut transport_errors = Vec::new(); for node in nodes.iter() { - let serialized_request = match handle_gui_auth_payload_if_activated( - &gui_auth_validation_generator, - node, - &request, - &mut transport_errors, - ) { - Ok(r) => r, - Err(true) => serialized_request.clone(), - Err(false) => continue, - }; + let serialized_request = + match handle_gui_auth_payload_if_activated(&gui_auth_validation_generator, node, &request) { + Ok(Some(r)) => r, + Ok(None) => serialized_request.clone(), + Err(e) => { + transport_errors.push(e); + continue; + }, + }; match send_request_once(serialized_request.clone(), &node.uri, &event_handlers).await { Ok(response_json) => return Ok(response_json), Err(Error(ErrorKind::Transport(e), _)) => { - transport_errors.push(e.to_string()); + transport_errors.push(Web3RpcError::Transport(e)); }, Err(e) => return Err(e), } @@ -364,8 +364,8 @@ async fn send_request_once( } } -fn request_failed_error(request: &Call, errors: &[String]) -> Error { - let errors = errors.join("; "); +fn request_failed_error(request: &Call, errors: &[Web3RpcError]) -> Error { + let errors: String = errors.iter().map(|e| format!("{:?}; ", e)).collect(); let error = format!("request {:?} failed: {}", request, errors); Error::from(ErrorKind::Transport(error)) } diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 2db2c24926..da5289b563 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -9,8 +9,8 @@ use coins::{eth::{v2_activation::{eth_coin_from_conf_and_request_v2, Erc20Protoc Erc20TokenInfo, EthCoin}, my_tx_history_v2::TxHistoryStorage, CoinBalance, CoinProtocol, MarketCoinOps, MmCoin}; -use common::{mm_metrics::MetricsArc, Future01CompatExt}; -use futures::future::AbortHandle; +use common::{log::error, mm_metrics::MetricsArc, Future01CompatExt}; +use futures::future::{abortable, AbortHandle}; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use mm2_number::BigDecimal; @@ -228,6 +228,11 @@ impl PlatformWithTokensActivationOps for EthCoin { _storage: impl TxHistoryStorage + Send + 'static, _initial_balance: BigDecimal, ) -> AbortHandle { - todo!() + error!( + "tx_history is not allowed for {}. It works very slowly and requires a lot of disk space.", + self.ticker() + ); + let (_, abort_handle) = abortable(async {}); + abort_handle } } From 528bdb39c893a572bcdc1de2498652ad30163edd Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 3 Aug 2022 15:22:26 +0300 Subject: [PATCH 64/69] fix pr reviews Signed-off-by: ozkanonur --- mm2src/coins/eth.rs | 22 +++++++------ mm2src/coins/eth/v2_activation.rs | 32 ++----------------- .../src/eth_with_token_activation.rs | 14 ++++---- 3 files changed, 23 insertions(+), 45 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 6cf5a6a152..619df9b7a5 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -99,6 +99,8 @@ const DEFAULT_LOGS_BLOCK_RANGE: u64 = 1000; const DEFAULT_REQUIRED_CONFIRMATIONS: u8 = 1; +const ETH_DECIMALS: u8 = 18; + /// Take into account that the dynamic fee may increase by 3% during the swap. const GAS_PRICE_APPROXIMATION_PERCENT_ON_START_SWAP: u64 = 3; /// Take into account that the dynamic fee may increase at each of the following stages: @@ -277,7 +279,7 @@ struct SavedErc20Events { } #[derive(Debug, PartialEq, Eq)] -enum EthCoinType { +pub enum EthCoinType { /// Ethereum itself or it's forks: ETC/others Eth, /// ERC20 token with smart contract address @@ -1171,7 +1173,7 @@ impl MarketCoinOps for EthCoin { fn base_coin_balance(&self) -> BalanceFut { Box::new( self.eth_balance() - .and_then(move |result| Ok(u256_to_big_decimal(result, 18)?)), + .and_then(move |result| Ok(u256_to_big_decimal(result, ETH_DECIMALS)?)), ) } @@ -1759,7 +1761,7 @@ impl EthCoin { None => None, }; - let total_amount: BigDecimal = u256_to_big_decimal(call_data.value, 18).unwrap(); + let total_amount: BigDecimal = u256_to_big_decimal(call_data.value, ETH_DECIMALS).unwrap(); let mut received_by_me = 0.into(); let mut spent_by_me = 0.into(); @@ -3009,8 +3011,8 @@ impl EthTxFeeDetails { fn new(gas: U256, gas_price: U256, coin: &str) -> NumConversResult { let total_fee = gas * gas_price; // Fees are always paid in ETH, can use 18 decimals by default - let total_fee = u256_to_big_decimal(total_fee, 18)?; - let gas_price = u256_to_big_decimal(gas_price, 18)?; + let total_fee = u256_to_big_decimal(total_fee, ETH_DECIMALS)?; + let gas_price = u256_to_big_decimal(gas_price, ETH_DECIMALS)?; Ok(EthTxFeeDetails { coin: coin.to_owned(), @@ -3092,7 +3094,7 @@ impl MmCoin for EthCoin { }; Ok(TradeFee { coin: fee_coin.into(), - amount: try_s!(u256_to_big_decimal(fee, 18)).into(), + amount: try_s!(u256_to_big_decimal(fee, ETH_DECIMALS)).into(), paid_from_trading_vol: false, }) }), @@ -3140,7 +3142,7 @@ impl MmCoin for EthCoin { }; let total_fee = gas_limit * gas_price; - let amount = u256_to_big_decimal(total_fee, 18)?; + let amount = u256_to_big_decimal(total_fee, ETH_DECIMALS)?; let fee_coin = match &self.coin_type { EthCoinType::Eth => &self.ticker, EthCoinType::Erc20 { platform, .. } => platform, @@ -3158,7 +3160,7 @@ impl MmCoin for EthCoin { let gas_price = coin.get_gas_price().compat().await?; let gas_price = increase_gas_price_by_stage(gas_price, &stage); let total_fee = gas_price * U256::from(150_000); - let amount = u256_to_big_decimal(total_fee, 18)?; + let amount = u256_to_big_decimal(total_fee, ETH_DECIMALS)?; let fee_coin = match &coin.coin_type { EthCoinType::Eth => &coin.ticker, EthCoinType::Erc20 { platform, .. } => platform, @@ -3208,7 +3210,7 @@ impl MmCoin for EthCoin { // Ideally we should determine the case when we have the insufficient balance and return `TradePreimageError::NotSufficientBalance` error. let gas_limit = self.estimate_gas(estimate_gas_req).compat().await?; let total_fee = gas_limit * gas_price; - let amount = u256_to_big_decimal(total_fee, 18)?; + let amount = u256_to_big_decimal(total_fee, ETH_DECIMALS)?; Ok(TradeFee { coin: fee_coin.into(), amount: amount.into(), @@ -3530,7 +3532,7 @@ pub async fn eth_coin_from_conf_and_request( let web3 = Web3::new(transport); let (coin_type, decimals) = match protocol { - CoinProtocol::ETH => (EthCoinType::Eth, 18), + CoinProtocol::ETH => (EthCoinType::Eth, ETH_DECIMALS), CoinProtocol::ERC20 { platform, contract_address, diff --git a/mm2src/coins/eth/v2_activation.rs b/mm2src/coins/eth/v2_activation.rs index 55ac99de63..2211b1bd7a 100644 --- a/mm2src/coins/eth/v2_activation.rs +++ b/mm2src/coins/eth/v2_activation.rs @@ -121,7 +121,6 @@ pub async fn eth_coin_from_conf_and_request_v2( conf: &Json, req: EthActivationV2Request, priv_key: &[u8], - protocol: CoinProtocol, ) -> Result> { if req.nodes.is_empty() { return Err(EthActivationV2Error::AtLeastOneNodeRequired.into()); @@ -207,26 +206,6 @@ pub async fn eth_coin_from_conf_and_request_v2( let web3 = Web3::new(transport); - let (coin_type, decimals) = match protocol { - CoinProtocol::ETH => (EthCoinType::Eth, 18), - CoinProtocol::ERC20 { - platform, - contract_address, - } => { - let token_addr = valid_addr_from_str(&contract_address).map_err(EthActivationV2Error::InternalError)?; - let decimals = match conf["decimals"].as_u64() { - None | Some(0) => get_token_decimals(&web3, token_addr) - .await - .map_err(EthActivationV2Error::InternalError)?, - Some(d) => d as u8, - }; - (EthCoinType::Erc20 { platform, token_addr }, decimals) - }, - _ => { - return Err(EthActivationV2Error::InvalidPayload("Expect ETH or ERC20 protocol".to_string()).into()); - }, - }; - // param from request should override the config let required_confirmations = req .required_confirmations @@ -245,22 +224,17 @@ pub async fn eth_coin_from_conf_and_request_v2( HistorySyncState::NotEnabled }; - let key_lock = match &coin_type { - EthCoinType::Eth => String::from(ticker), - EthCoinType::Erc20 { ref platform, .. } => String::from(platform), - }; - let mut map = NONCE_LOCK.lock().unwrap(); - let nonce_lock = map.entry(key_lock).or_insert_with(new_nonce_lock).clone(); + let nonce_lock = map.entry(ticker.to_string()).or_insert_with(new_nonce_lock).clone(); let coin = EthCoinImpl { key_pair: key_pair.clone(), my_address: key_pair.address(), - coin_type, + coin_type: EthCoinType::Eth, sign_message_prefix, swap_contract_address: req.swap_contract_address, fallback_swap_contract: req.fallback_swap_contract, - decimals, + decimals: ETH_DECIMALS, ticker: ticker.into(), gas_station_url: req.gas_station_url, gas_station_decimals: req.gas_station_decimals.unwrap_or(ETH_GAS_STATION_DECIMALS), diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index da5289b563..38f53314b4 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -6,7 +6,7 @@ use crate::{platform_coin_with_tokens::{EnablePlatformCoinWithTokensError, GetPl use async_trait::async_trait; use coins::{eth::{v2_activation::{eth_coin_from_conf_and_request_v2, Erc20Protocol, Erc20TokenActivationError, Erc20TokenActivationRequest, EthActivationV2Error, EthActivationV2Request}, - Erc20TokenInfo, EthCoin}, + Erc20TokenInfo, EthCoin, EthCoinType}, my_tx_history_v2::TxHistoryStorage, CoinBalance, CoinProtocol, MarketCoinOps, MmCoin}; use common::{log::error, mm_metrics::MetricsArc, Future01CompatExt}; @@ -40,12 +40,15 @@ impl From for EnablePlatformCoinWithTokensError { } } -impl TryFromCoinProtocol for CoinProtocol { +impl TryFromCoinProtocol for EthCoinType { fn try_from_coin_protocol(proto: CoinProtocol) -> Result> where Self: Sized, { - Ok(proto) + match proto { + CoinProtocol::ETH => Ok(EthCoinType::Eth), + protocol => MmError::err(protocol), + } } } @@ -142,7 +145,7 @@ impl CurrentBlock for EthWithTokensActivationResult { #[async_trait] impl PlatformWithTokensActivationOps for EthCoin { type ActivationRequest = EthWithTokensActivationRequest; - type PlatformProtocolInfo = CoinProtocol; + type PlatformProtocolInfo = EthCoinType; type ActivationResult = EthWithTokensActivationResult; type ActivationError = EthActivationV2Error; @@ -151,7 +154,7 @@ impl PlatformWithTokensActivationOps for EthCoin { ticker: String, platform_conf: Json, activation_request: Self::ActivationRequest, - protocol: Self::PlatformProtocolInfo, + _protocol: Self::PlatformProtocolInfo, priv_key: &[u8], ) -> Result> { let platform_coin = eth_coin_from_conf_and_request_v2( @@ -160,7 +163,6 @@ impl PlatformWithTokensActivationOps for EthCoin { &platform_conf, activation_request.platform_request, priv_key, - protocol, ) .await?; From bc60c20bf69e1d9d0e20e37a081c13f911ef77c8 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 3 Aug 2022 21:00:19 +0300 Subject: [PATCH 65/69] create `Web3Transport::single_node` fn Signed-off-by: ozkanonur --- mm2src/coins/eth/eth_tests.rs | 57 ++++++------------------------ mm2src/coins/eth/eth_wasm_tests.rs | 5 +-- mm2src/coins/eth/web3_transport.rs | 15 ++++++++ 3 files changed, 27 insertions(+), 50 deletions(-) diff --git a/mm2src/coins/eth/eth_tests.rs b/mm2src/coins/eth/eth_tests.rs index c527cd6e25..b3ba38129c 100644 --- a/mm2src/coins/eth/eth_tests.rs +++ b/mm2src/coins/eth/eth_tests.rs @@ -213,10 +213,7 @@ fn send_and_refund_erc20_payment() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec![Web3TransportNode { - uri: "http://195.201.0.6:8545".parse().unwrap(), - gui_auth: false, - }]); + let transport = Web3Transport::single_node("http://195.201.0.6:8545", false); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -287,10 +284,7 @@ fn send_and_refund_eth_payment() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec![Web3TransportNode { - uri: "http://195.201.0.6:8545".parse().unwrap(), - gui_auth: false, - }]); + let transport = Web3Transport::single_node("http://195.201.0.6:8545", false); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -357,21 +351,11 @@ fn test_nonce_several_urls() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let infura_transport = Web3Transport::new(vec![Web3TransportNode { - uri: "https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b" - .parse() - .unwrap(), - gui_auth: false, - }]); - let linkpool_transport = Web3Transport::new(vec![Web3TransportNode { - uri: "https://ropsten-rpc.linkpool.io".parse().unwrap(), - gui_auth: false, - }]); + let infura_transport = + Web3Transport::single_node("https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b", false); + let linkpool_transport = Web3Transport::single_node("https://ropsten-rpc.linkpool.io", false); // get nonce must succeed if some nodes are down at the moment for some reason - let failing_transport = Web3Transport::new(vec![Web3TransportNode { - uri: "http://195.201.0.6:8989".parse().unwrap(), - gui_auth: false, - }]); + let failing_transport = Web3Transport::single_node("http://195.201.0.6:8989", false); let web3_infura = Web3::new(infura_transport); let web3_linkpool = Web3::new(linkpool_transport); @@ -434,10 +418,7 @@ fn test_wait_for_payment_spend_timeout() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec![Web3TransportNode { - uri: "http://195.201.0.6:8555".parse().unwrap(), - gui_auth: false, - }]); + let transport = Web3Transport::single_node("http://195.201.0.6:8555", false); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); @@ -496,12 +477,7 @@ fn test_search_for_swap_tx_spend_was_spent() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec![Web3TransportNode { - uri: "https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b" - .parse() - .unwrap(), - gui_auth: false, - }]); + let transport = Web3Transport::single_node("https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b", false); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); @@ -605,12 +581,7 @@ fn test_search_for_swap_tx_spend_was_refunded() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec![Web3TransportNode { - uri: "https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b" - .parse() - .unwrap(), - gui_auth: false, - }]); + let transport = Web3Transport::single_node("https://ropsten.infura.io/v3/c01c1b4cf66642528547624e1d6d9d6b", false); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); @@ -1301,10 +1272,7 @@ fn test_message_hash() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec![Web3TransportNode { - uri: "http://195.201.0.6:8545".parse().unwrap(), - gui_auth: false, - }]); + let transport = Web3Transport::single_node("http://195.201.0.6:8545", false); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { @@ -1346,10 +1314,7 @@ fn test_sign_verify_message() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec![Web3TransportNode { - uri: "http://195.201.0.6:8545".parse().unwrap(), - gui_auth: false, - }]); + let transport = Web3Transport::single_node("http://195.201.0.6:8545", false); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); diff --git a/mm2src/coins/eth/eth_wasm_tests.rs b/mm2src/coins/eth/eth_wasm_tests.rs index bad5a97e02..55d02ce462 100644 --- a/mm2src/coins/eth/eth_wasm_tests.rs +++ b/mm2src/coins/eth/eth_wasm_tests.rs @@ -20,10 +20,7 @@ async fn test_send() { &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); - let transport = Web3Transport::new(vec![Web3TransportNode { - uri: "http://195.201.0.6:8565".parse().unwrap(), - gui_auth: false, - }]); + let transport = Web3Transport::single_node("http://195.201.0.6:8565", false); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); let coin = EthCoin(Arc::new(EthCoinImpl { diff --git a/mm2src/coins/eth/web3_transport.rs b/mm2src/coins/eth/web3_transport.rs index a0632c5082..fb5ea2846b 100644 --- a/mm2src/coins/eth/web3_transport.rs +++ b/mm2src/coins/eth/web3_transport.rs @@ -113,6 +113,21 @@ impl Web3Transport { gui_auth_validation_generator: None, } } + + #[allow(dead_code)] + pub fn single_node(url: &'static str, gui_auth: bool) -> Self { + let nodes = vec![Web3TransportNode { + uri: url.parse().unwrap(), + gui_auth, + }]; + + Web3Transport { + id: Arc::new(AtomicUsize::new(0)), + nodes, + event_handlers: Default::default(), + gui_auth_validation_generator: None, + } + } } struct SendFuture(T); From 5975d6a94b70fabac9875ed00cbebc78ccca99c9 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 3 Aug 2022 21:38:39 +0300 Subject: [PATCH 66/69] update `start_history_background_fetching` return type Signed-off-by: ozkanonur --- mm2src/coins/eth/v2_activation.rs | 1 + .../src/bch_with_tokens_activation.rs | 5 +++-- .../src/eth_with_token_activation.rs | 17 ++++++++--------- .../src/platform_coin_with_tokens.rs | 6 ++++-- .../src/solana_with_tokens_activation.rs | 11 +++++++++-- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/mm2src/coins/eth/v2_activation.rs b/mm2src/coins/eth/v2_activation.rs index 2211b1bd7a..b01bdbac49 100644 --- a/mm2src/coins/eth/v2_activation.rs +++ b/mm2src/coins/eth/v2_activation.rs @@ -16,6 +16,7 @@ pub enum EthActivationV2Error { #[display(fmt = "Enable request for ETH coin must have at least 1 node")] AtLeastOneNodeRequired, InternalError(String), + TxHistoryNotAllowed(String), } #[derive(Clone, Deserialize)] diff --git a/mm2src/coins_activation/src/bch_with_tokens_activation.rs b/mm2src/coins_activation/src/bch_with_tokens_activation.rs index e0f3102b47..606d8042a4 100644 --- a/mm2src/coins_activation/src/bch_with_tokens_activation.rs +++ b/mm2src/coins_activation/src/bch_with_tokens_activation.rs @@ -273,7 +273,7 @@ impl PlatformWithTokensActivationOps for BchCoin { metrics: MetricsArc, storage: impl TxHistoryStorage + Send + 'static, initial_balance: BigDecimal, - ) -> AbortHandle { + ) -> Result> { let ticker = self.ticker().to_owned(); let (fut, abort_handle) = abortable(bch_and_slp_history_loop( self.clone(), @@ -286,6 +286,7 @@ impl PlatformWithTokensActivationOps for BchCoin { info!("bch_and_slp_history_loop stopped for {}, reason {}", ticker, e); } }); - abort_handle + + Ok(abort_handle) } } diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 38f53314b4..ff7751c613 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -9,8 +9,8 @@ use coins::{eth::{v2_activation::{eth_coin_from_conf_and_request_v2, Erc20Protoc Erc20TokenInfo, EthCoin, EthCoinType}, my_tx_history_v2::TxHistoryStorage, CoinBalance, CoinProtocol, MarketCoinOps, MmCoin}; -use common::{log::error, mm_metrics::MetricsArc, Future01CompatExt}; -use futures::future::{abortable, AbortHandle}; +use common::{mm_metrics::MetricsArc, Future01CompatExt}; +use futures::future::AbortHandle; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use mm2_number::BigDecimal; @@ -36,6 +36,7 @@ impl From for EnablePlatformCoinWithTokensError { EnablePlatformCoinWithTokensError::Transport(e) }, EthActivationV2Error::InternalError(e) => EnablePlatformCoinWithTokensError::Internal(e), + EthActivationV2Error::TxHistoryNotAllowed(e) => EnablePlatformCoinWithTokensError::TxHistoryNotAllowed(e), } } } @@ -81,7 +82,7 @@ impl TokenInitializer for Erc20Initializer { async fn enable_tokens( &self, activation_params: Vec>, - ) -> Result, MmError> { + ) -> Result, MmError> { let mut tokens = vec![]; for param in activation_params { let token: EthCoin = self @@ -177,7 +178,7 @@ impl PlatformWithTokensActivationOps for EthCoin { })] } - async fn get_activation_result(&self) -> Result> { + async fn get_activation_result(&self) -> Result> { let my_address = self.my_address().map_err(EthActivationV2Error::InternalError)?; let pubkey = self .get_public_key() @@ -229,12 +230,10 @@ impl PlatformWithTokensActivationOps for EthCoin { _metrics: MetricsArc, _storage: impl TxHistoryStorage + Send + 'static, _initial_balance: BigDecimal, - ) -> AbortHandle { - error!( + ) -> Result> { + return MmError::err(EthActivationV2Error::TxHistoryNotAllowed(format!( "tx_history is not allowed for {}. It works very slowly and requires a lot of disk space.", self.ticker() - ); - let (_, abort_handle) = abortable(async {}); - abort_handle + ))); } } diff --git a/mm2src/coins_activation/src/platform_coin_with_tokens.rs b/mm2src/coins_activation/src/platform_coin_with_tokens.rs index ecd1dac377..babf8a8af8 100644 --- a/mm2src/coins_activation/src/platform_coin_with_tokens.rs +++ b/mm2src/coins_activation/src/platform_coin_with_tokens.rs @@ -165,7 +165,7 @@ pub trait PlatformWithTokensActivationOps: Into { metrics: MetricsArc, storage: impl TxHistoryStorage, initial_balance: BigDecimal, - ) -> AbortHandle; + ) -> Result>; } #[derive(Debug, Deserialize)] @@ -216,6 +216,7 @@ pub enum EnablePlatformCoinWithTokensError { AtLeastOneNodeRequired(String), InvalidPayload(String), Internal(String), + TxHistoryNotAllowed(String), } impl From for EnablePlatformCoinWithTokensError { @@ -281,6 +282,7 @@ impl HttpStatusCode for EnablePlatformCoinWithTokensError { | EnablePlatformCoinWithTokensError::UnexpectedPlatformProtocol { .. } | EnablePlatformCoinWithTokensError::InvalidPayload { .. } | EnablePlatformCoinWithTokensError::AtLeastOneNodeRequired(_) + | EnablePlatformCoinWithTokensError::TxHistoryNotAllowed(_) | EnablePlatformCoinWithTokensError::UnexpectedTokenProtocol { .. } => StatusCode::BAD_REQUEST, } } @@ -328,7 +330,7 @@ where ctx.metrics.clone(), TxHistoryStorageBuilder::new(&ctx).build()?, activation_result.get_platform_balance(), - ); + )?; ctx.abort_handlers.lock().unwrap().push(abort_handler); } diff --git a/mm2src/coins_activation/src/solana_with_tokens_activation.rs b/mm2src/coins_activation/src/solana_with_tokens_activation.rs index 71fdcf4027..593f60b964 100644 --- a/mm2src/coins_activation/src/solana_with_tokens_activation.rs +++ b/mm2src/coins_activation/src/solana_with_tokens_activation.rs @@ -105,6 +105,7 @@ pub enum SolanaWithTokensActivationError { GetBalanceError(BalanceError), Transport(String), Internal(String), + TxHistoryNotAllowed(String), } impl From for EnablePlatformCoinWithTokensError { @@ -121,6 +122,9 @@ impl From for EnablePlatformCoinWithTokensError }, SolanaWithTokensActivationError::Transport(e) => EnablePlatformCoinWithTokensError::Transport(e), SolanaWithTokensActivationError::Internal(e) => EnablePlatformCoinWithTokensError::Internal(e), + SolanaWithTokensActivationError::TxHistoryNotAllowed(e) => { + EnablePlatformCoinWithTokensError::TxHistoryNotAllowed(e) + }, } } } @@ -227,7 +231,10 @@ impl PlatformWithTokensActivationOps for SolanaCoin { _metrics: MetricsArc, _storage: impl TxHistoryStorage + Send + 'static, _initial_balance: BigDecimal, - ) -> AbortHandle { - todo!() + ) -> Result> { + return MmError::err(SolanaWithTokensActivationError::TxHistoryNotAllowed(format!( + "tx_history is not allowed for {}.", + self.ticker() + ))); } } From a691c940f4618129b52fdb23e268ae5b249c2296 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Thu, 4 Aug 2022 13:21:18 +0300 Subject: [PATCH 67/69] Revert "update `start_history_background_fetching` return type" This reverts commit 5975d6a94b70fabac9875ed00cbebc78ccca99c9. --- mm2src/coins/eth/v2_activation.rs | 1 - .../src/bch_with_tokens_activation.rs | 5 ++--- .../src/eth_with_token_activation.rs | 17 +++++++++-------- .../src/platform_coin_with_tokens.rs | 6 ++---- .../src/solana_with_tokens_activation.rs | 11 ++--------- 5 files changed, 15 insertions(+), 25 deletions(-) diff --git a/mm2src/coins/eth/v2_activation.rs b/mm2src/coins/eth/v2_activation.rs index b01bdbac49..2211b1bd7a 100644 --- a/mm2src/coins/eth/v2_activation.rs +++ b/mm2src/coins/eth/v2_activation.rs @@ -16,7 +16,6 @@ pub enum EthActivationV2Error { #[display(fmt = "Enable request for ETH coin must have at least 1 node")] AtLeastOneNodeRequired, InternalError(String), - TxHistoryNotAllowed(String), } #[derive(Clone, Deserialize)] diff --git a/mm2src/coins_activation/src/bch_with_tokens_activation.rs b/mm2src/coins_activation/src/bch_with_tokens_activation.rs index 606d8042a4..e0f3102b47 100644 --- a/mm2src/coins_activation/src/bch_with_tokens_activation.rs +++ b/mm2src/coins_activation/src/bch_with_tokens_activation.rs @@ -273,7 +273,7 @@ impl PlatformWithTokensActivationOps for BchCoin { metrics: MetricsArc, storage: impl TxHistoryStorage + Send + 'static, initial_balance: BigDecimal, - ) -> Result> { + ) -> AbortHandle { let ticker = self.ticker().to_owned(); let (fut, abort_handle) = abortable(bch_and_slp_history_loop( self.clone(), @@ -286,7 +286,6 @@ impl PlatformWithTokensActivationOps for BchCoin { info!("bch_and_slp_history_loop stopped for {}, reason {}", ticker, e); } }); - - Ok(abort_handle) + abort_handle } } diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index ff7751c613..38f53314b4 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -9,8 +9,8 @@ use coins::{eth::{v2_activation::{eth_coin_from_conf_and_request_v2, Erc20Protoc Erc20TokenInfo, EthCoin, EthCoinType}, my_tx_history_v2::TxHistoryStorage, CoinBalance, CoinProtocol, MarketCoinOps, MmCoin}; -use common::{mm_metrics::MetricsArc, Future01CompatExt}; -use futures::future::AbortHandle; +use common::{log::error, mm_metrics::MetricsArc, Future01CompatExt}; +use futures::future::{abortable, AbortHandle}; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use mm2_number::BigDecimal; @@ -36,7 +36,6 @@ impl From for EnablePlatformCoinWithTokensError { EnablePlatformCoinWithTokensError::Transport(e) }, EthActivationV2Error::InternalError(e) => EnablePlatformCoinWithTokensError::Internal(e), - EthActivationV2Error::TxHistoryNotAllowed(e) => EnablePlatformCoinWithTokensError::TxHistoryNotAllowed(e), } } } @@ -82,7 +81,7 @@ impl TokenInitializer for Erc20Initializer { async fn enable_tokens( &self, activation_params: Vec>, - ) -> Result, MmError> { + ) -> Result, MmError> { let mut tokens = vec![]; for param in activation_params { let token: EthCoin = self @@ -178,7 +177,7 @@ impl PlatformWithTokensActivationOps for EthCoin { })] } - async fn get_activation_result(&self) -> Result> { + async fn get_activation_result(&self) -> Result> { let my_address = self.my_address().map_err(EthActivationV2Error::InternalError)?; let pubkey = self .get_public_key() @@ -230,10 +229,12 @@ impl PlatformWithTokensActivationOps for EthCoin { _metrics: MetricsArc, _storage: impl TxHistoryStorage + Send + 'static, _initial_balance: BigDecimal, - ) -> Result> { - return MmError::err(EthActivationV2Error::TxHistoryNotAllowed(format!( + ) -> AbortHandle { + error!( "tx_history is not allowed for {}. It works very slowly and requires a lot of disk space.", self.ticker() - ))); + ); + let (_, abort_handle) = abortable(async {}); + abort_handle } } diff --git a/mm2src/coins_activation/src/platform_coin_with_tokens.rs b/mm2src/coins_activation/src/platform_coin_with_tokens.rs index babf8a8af8..ecd1dac377 100644 --- a/mm2src/coins_activation/src/platform_coin_with_tokens.rs +++ b/mm2src/coins_activation/src/platform_coin_with_tokens.rs @@ -165,7 +165,7 @@ pub trait PlatformWithTokensActivationOps: Into { metrics: MetricsArc, storage: impl TxHistoryStorage, initial_balance: BigDecimal, - ) -> Result>; + ) -> AbortHandle; } #[derive(Debug, Deserialize)] @@ -216,7 +216,6 @@ pub enum EnablePlatformCoinWithTokensError { AtLeastOneNodeRequired(String), InvalidPayload(String), Internal(String), - TxHistoryNotAllowed(String), } impl From for EnablePlatformCoinWithTokensError { @@ -282,7 +281,6 @@ impl HttpStatusCode for EnablePlatformCoinWithTokensError { | EnablePlatformCoinWithTokensError::UnexpectedPlatformProtocol { .. } | EnablePlatformCoinWithTokensError::InvalidPayload { .. } | EnablePlatformCoinWithTokensError::AtLeastOneNodeRequired(_) - | EnablePlatformCoinWithTokensError::TxHistoryNotAllowed(_) | EnablePlatformCoinWithTokensError::UnexpectedTokenProtocol { .. } => StatusCode::BAD_REQUEST, } } @@ -330,7 +328,7 @@ where ctx.metrics.clone(), TxHistoryStorageBuilder::new(&ctx).build()?, activation_result.get_platform_balance(), - )?; + ); ctx.abort_handlers.lock().unwrap().push(abort_handler); } diff --git a/mm2src/coins_activation/src/solana_with_tokens_activation.rs b/mm2src/coins_activation/src/solana_with_tokens_activation.rs index 593f60b964..71fdcf4027 100644 --- a/mm2src/coins_activation/src/solana_with_tokens_activation.rs +++ b/mm2src/coins_activation/src/solana_with_tokens_activation.rs @@ -105,7 +105,6 @@ pub enum SolanaWithTokensActivationError { GetBalanceError(BalanceError), Transport(String), Internal(String), - TxHistoryNotAllowed(String), } impl From for EnablePlatformCoinWithTokensError { @@ -122,9 +121,6 @@ impl From for EnablePlatformCoinWithTokensError }, SolanaWithTokensActivationError::Transport(e) => EnablePlatformCoinWithTokensError::Transport(e), SolanaWithTokensActivationError::Internal(e) => EnablePlatformCoinWithTokensError::Internal(e), - SolanaWithTokensActivationError::TxHistoryNotAllowed(e) => { - EnablePlatformCoinWithTokensError::TxHistoryNotAllowed(e) - }, } } } @@ -231,10 +227,7 @@ impl PlatformWithTokensActivationOps for SolanaCoin { _metrics: MetricsArc, _storage: impl TxHistoryStorage + Send + 'static, _initial_balance: BigDecimal, - ) -> Result> { - return MmError::err(SolanaWithTokensActivationError::TxHistoryNotAllowed(format!( - "tx_history is not allowed for {}.", - self.ticker() - ))); + ) -> AbortHandle { + todo!() } } From a67c162660950b58e74588026ca09b592921a6de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Thu, 4 Aug 2022 13:53:46 +0300 Subject: [PATCH 68/69] remove `tx_history` for eth v2 activation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins/eth/v2_activation.rs | 9 +-------- .../src/eth_with_token_activation.rs | 13 ++++--------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/mm2src/coins/eth/v2_activation.rs b/mm2src/coins/eth/v2_activation.rs index 2211b1bd7a..aee317f5cb 100644 --- a/mm2src/coins/eth/v2_activation.rs +++ b/mm2src/coins/eth/v2_activation.rs @@ -29,7 +29,6 @@ pub struct EthActivationV2Request { pub gas_station_policy: GasStationPricePolicy, pub mm2: Option, #[serde(default)] - pub tx_history: bool, pub required_confirmations: Option, } @@ -218,12 +217,6 @@ pub async fn eth_coin_from_conf_and_request_v2( let sign_message_prefix: Option = json::from_value(conf["sign_message_prefix"].clone()).ok(); - let initial_history_state = if req.tx_history { - HistorySyncState::NotStarted - } else { - HistorySyncState::NotEnabled - }; - let mut map = NONCE_LOCK.lock().unwrap(); let nonce_lock = map.entry(ticker.to_string()).or_insert_with(new_nonce_lock).clone(); @@ -241,7 +234,7 @@ pub async fn eth_coin_from_conf_and_request_v2( gas_station_policy: req.gas_station_policy, web3, web3_instances, - history_sync_state: Mutex::new(initial_history_state), + history_sync_state: Mutex::new(HistorySyncState::NotEnabled), ctx: ctx.weak(), required_confirmations, chain_id: conf["chain_id"].as_u64(), diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 38f53314b4..8e75488d53 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -9,8 +9,8 @@ use coins::{eth::{v2_activation::{eth_coin_from_conf_and_request_v2, Erc20Protoc Erc20TokenInfo, EthCoin, EthCoinType}, my_tx_history_v2::TxHistoryStorage, CoinBalance, CoinProtocol, MarketCoinOps, MmCoin}; -use common::{log::error, mm_metrics::MetricsArc, Future01CompatExt}; -use futures::future::{abortable, AbortHandle}; +use common::{mm_metrics::MetricsArc, Future01CompatExt}; +use futures::future::AbortHandle; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use mm2_number::BigDecimal; @@ -105,7 +105,7 @@ pub struct EthWithTokensActivationRequest { } impl TxHistory for EthWithTokensActivationRequest { - fn tx_history(&self) -> bool { self.platform_request.tx_history } + fn tx_history(&self) -> bool { false } } impl TokenOf for EthCoin { @@ -230,11 +230,6 @@ impl PlatformWithTokensActivationOps for EthCoin { _storage: impl TxHistoryStorage + Send + 'static, _initial_balance: BigDecimal, ) -> AbortHandle { - error!( - "tx_history is not allowed for {}. It works very slowly and requires a lot of disk space.", - self.ticker() - ); - let (_, abort_handle) = abortable(async {}); - abort_handle + unimplemented!() } } From 9c011f2253f59dc0397a4c399cb070f035459111 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Thu, 4 Aug 2022 15:15:45 +0300 Subject: [PATCH 69/69] fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- mm2src/coins/eth/v2_activation.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/mm2src/coins/eth/v2_activation.rs b/mm2src/coins/eth/v2_activation.rs index aee317f5cb..0f9c59ceea 100644 --- a/mm2src/coins/eth/v2_activation.rs +++ b/mm2src/coins/eth/v2_activation.rs @@ -28,7 +28,6 @@ pub struct EthActivationV2Request { #[serde(default)] pub gas_station_policy: GasStationPricePolicy, pub mm2: Option, - #[serde(default)] pub required_confirmations: Option, }