From 4bede306a9f4bc52a5121cf0f39bd60aa3a716f1 Mon Sep 17 00:00:00 2001 From: shamardy Date: Sat, 22 Apr 2023 00:30:59 +0200 Subject: [PATCH 01/11] add `get_balances` param to enable with tokens methods, request tokens balances from rpcs concurrently --- mm2src/coins/eth.rs | 26 ++++---- mm2src/coins/solana.rs | 3 +- mm2src/coins/solana/spl.rs | 2 +- mm2src/coins/tendermint/tendermint_coin.rs | 24 +++++--- .../src/bch_with_tokens_activation.rs | 43 ++++++++------ .../src/eth_with_token_activation.rs | 58 ++++++++++-------- .../src/platform_coin_with_tokens.rs | 7 ++- .../src/solana_with_tokens_activation.rs | 59 ++++++++++++------- .../src/tendermint_with_assets_activation.rs | 53 ++++++++++------- 9 files changed, 166 insertions(+), 109 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index f610b91845..de34f09981 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -43,7 +43,7 @@ use ethereum_types::{Address, H160, H256, U256}; use ethkey::{public_to_address, KeyPair, Public, Signature}; use ethkey::{sign, verify_address}; use futures::compat::Future01CompatExt; -use futures::future::{join_all, select_ok, Either, FutureExt, TryFutureExt}; +use futures::future::{join_all, select_ok, try_join_all, Either, FutureExt, TryFutureExt}; use futures01::Future; use http::StatusCode; use mm2_core::mm_ctx::{MmArc, MmWeak}; @@ -3430,19 +3430,23 @@ 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().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 { - spendable: balance_as_big_decimal, - unspendable: BigDecimal::from(0), + let selfi = self.clone(); + let mut requests = Vec::new(); + for (token_ticker, info) in self.get_erc_tokens_infos() { + let coin = selfi.clone(); + let fut = async move { + 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, + unspendable: BigDecimal::from(0), + }; + Ok::<_, MmError>((token_ticker.clone(), balance)) }; - token_balances.insert(token_ticker.clone(), balance); + requests.push(fut); } - Ok(token_balances) + try_join_all(requests).await.map(|res| res.into_iter().collect()) } async fn get_token_balance_by_address(&self, token_address: Address) -> Result> { diff --git a/mm2src/coins/solana.rs b/mm2src/coins/solana.rs index ef3cc38c49..d8f7037f81 100644 --- a/mm2src/coins/solana.rs +++ b/mm2src/coins/solana.rs @@ -320,10 +320,9 @@ impl SolanaCoin { Ok((hash, fees)) } - pub async fn my_balance_spl(&self, infos: &SplTokenInfo) -> Result> { + pub async fn my_balance_spl(&self, infos: SplTokenInfo) -> Result> { let token_accounts = async_blocking({ let coin = self.clone(); - let infos = infos.clone(); move || { coin.rpc().get_token_accounts_by_owner( &coin.key_pair.pubkey(), diff --git a/mm2src/coins/solana/spl.rs b/mm2src/coins/solana/spl.rs index 8aa917aed0..c01e7c367f 100644 --- a/mm2src/coins/solana/spl.rs +++ b/mm2src/coins/solana/spl.rs @@ -219,7 +219,7 @@ impl SplToken { let coin = self.clone(); let fut = async move { coin.platform_coin - .my_balance_spl(&SplTokenInfo { + .my_balance_spl(SplTokenInfo { token_contract_address: coin.conf.token_contract_address, decimals: coin.conf.decimals, }) diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 594508a3af..bb7ccce167 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -49,6 +49,7 @@ use cosmrs::tx::{self, Fee, Msg, Raw, SignDoc, SignerInfo}; use cosmrs::{AccountId, Any, Coin, Denom, ErrorReport}; use crypto::{privkey::key_pair_from_secret, Secp256k1Secret, StandardHDPathToCoin}; use derive_more::Display; +use futures::future::try_join_all; use futures::lock::Mutex as AsyncMutex; use futures::{FutureExt, TryFutureExt}; use futures01::Future; @@ -422,17 +423,24 @@ impl TendermintCommons for TendermintCoin { let platform_balance = big_decimal_from_sat_unsigned(platform_balance_denom, self.decimals); let ibc_assets_info = self.tokens_info.lock().clone(); - let mut result = AllBalancesResult { - platform_balance, - tokens_balances: HashMap::new(), - }; + let mut requests = Vec::new(); for (ticker, info) in ibc_assets_info { - let balance_denom = self.balance_for_denom(info.denom.to_string()).await?; - let balance_decimal = big_decimal_from_sat_unsigned(balance_denom, info.decimals); - result.tokens_balances.insert(ticker, balance_decimal); + let fut = async move { + let balance_denom = self + .balance_for_denom(info.denom.to_string()) + .await + .map_err(|e| e.into_inner())?; + let balance_decimal = big_decimal_from_sat_unsigned(balance_denom, info.decimals); + Ok::<_, TendermintCoinRpcError>((ticker.clone(), balance_decimal)) + }; + requests.push(fut); } + let tokens_balances = try_join_all(requests).await?.into_iter().collect(); - Ok(result) + Ok(AllBalancesResult { + platform_balance, + tokens_balances, + }) } #[inline(always)] diff --git a/mm2src/coins_activation/src/bch_with_tokens_activation.rs b/mm2src/coins_activation/src/bch_with_tokens_activation.rs index 97fca2acca..1fadda67de 100644 --- a/mm2src/coins_activation/src/bch_with_tokens_activation.rs +++ b/mm2src/coins_activation/src/bch_with_tokens_activation.rs @@ -11,6 +11,7 @@ use coins::utxo::UtxoCommonOps; use coins::{CoinBalance, CoinProtocol, MarketCoinOps, MmCoin, PrivKeyBuildPolicy, PrivKeyPolicyNotAllowed, UnexpectedDerivationMethod}; use common::executor::{AbortSettings, SpawnAbortable}; +use common::true_f; use common::Future01CompatExt; use crypto::CryptoCtxError; use mm2_core::mm_ctx::MmArc; @@ -119,6 +120,8 @@ pub struct BchWithTokensActivationRequest { #[serde(flatten)] platform_request: BchActivationRequest, slp_tokens_requests: Vec>, + #[serde(default = "true_f")] + pub get_balances: bool, } impl TxHistory for BchWithTokensActivationRequest { @@ -244,6 +247,7 @@ impl PlatformWithTokensActivationOps for BchCoin { async fn get_activation_result( &self, + activation_request: &Self::ActivationRequest, ) -> Result> { let my_address = self.as_ref().derivation_method.single_addr_or_err()?; let my_slp_address = self @@ -254,34 +258,37 @@ impl PlatformWithTokensActivationOps for BchCoin { let current_block = self.as_ref().rpc_client.get_block_count().compat().await?; - 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 = BchWithTokensActivationResult { current_block, bch_addresses_infos: HashMap::new(), slp_addresses_infos: HashMap::new(), }; - result - .bch_addresses_infos - .insert(my_address.to_string(), CoinAddressInfo { + if activation_request.get_balances { + 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); + } + + 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: bch_balance, + 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) } diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 7b5d099ba5..2cd0f9f355 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -11,6 +11,7 @@ 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::true_f; use common::Future01CompatExt; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; @@ -122,6 +123,8 @@ pub struct EthWithTokensActivationRequest { #[serde(flatten)] platform_request: EthActivationV2Request, erc20_tokens_requests: Vec>, + #[serde(default = "true_f")] + pub get_balances: bool, } impl TxHistory for EthWithTokensActivationRequest { @@ -198,7 +201,10 @@ impl PlatformWithTokensActivationOps for EthCoin { })] } - async fn get_activation_result(&self) -> Result> { + async fn get_activation_result( + &self, + activation_request: &Self::ActivationRequest, + ) -> Result> { let my_address = self.my_address()?; let pubkey = self.get_public_key()?; @@ -208,37 +214,39 @@ impl PlatformWithTokensActivationOps for EthCoin { .await .map_err(EthActivationV2Error::InternalError)?; - 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, eth_addresses_infos: HashMap::new(), erc20_addresses_infos: HashMap::new(), }; - result - .eth_addresses_infos - .insert(my_address.to_string(), CoinAddressInfo { - derivation_method: DerivationMethod::Iguana, - pubkey: pubkey.clone(), - balances: eth_balance, - }); + if activation_request.get_balances { + 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()))?; + + result + .eth_addresses_infos + .insert(my_address.to_string(), CoinAddressInfo { + derivation_method: DerivationMethod::Iguana, + pubkey: pubkey.clone(), + balances: eth_balance, + }); - result - .erc20_addresses_infos - .insert(my_address.to_string(), CoinAddressInfo { - derivation_method: DerivationMethod::Iguana, - pubkey, - balances: token_balances, - }); + result + .erc20_addresses_infos + .insert(my_address.to_string(), CoinAddressInfo { + derivation_method: DerivationMethod::Iguana, + pubkey, + balances: token_balances, + }); + } Ok(result) } diff --git a/mm2src/coins_activation/src/platform_coin_with_tokens.rs b/mm2src/coins_activation/src/platform_coin_with_tokens.rs index e6e3f1b9f3..29949d47a9 100644 --- a/mm2src/coins_activation/src/platform_coin_with_tokens.rs +++ b/mm2src/coins_activation/src/platform_coin_with_tokens.rs @@ -150,7 +150,10 @@ pub trait PlatformWithTokensActivationOps: Into { &self, ) -> Vec>>; - async fn get_activation_result(&self) -> Result>; + async fn get_activation_result( + &self, + activation_request: &Self::ActivationRequest, + ) -> Result>; fn start_history_background_fetching( &self, @@ -311,7 +314,7 @@ where mm_tokens.extend(tokens); } - let activation_result = platform_coin.get_activation_result().await?; + let activation_result = platform_coin.get_activation_result(&req.request).await?; log::info!("{} current block {}", req.ticker, activation_result.current_block()); if req.request.tx_history() { diff --git a/mm2src/coins_activation/src/solana_with_tokens_activation.rs b/mm2src/coins_activation/src/solana_with_tokens_activation.rs index 9bdc014691..ea1900d162 100644 --- a/mm2src/coins_activation/src/solana_with_tokens_activation.rs +++ b/mm2src/coins_activation/src/solana_with_tokens_activation.rs @@ -12,8 +12,10 @@ use coins::solana::solana_coin_with_policy; use coins::solana::spl::{SplProtocolConf, SplTokenCreationError}; use coins::{BalanceError, CoinBalance, CoinProtocol, MarketCoinOps, PrivKeyBuildPolicy, SolanaActivationParams, SolanaCoin, SplToken}; +use common::true_f; use common::Future01CompatExt; use crypto::CryptoCtxError; +use futures::future::try_join_all; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use mm2_number::BigDecimal; @@ -79,6 +81,8 @@ pub struct SolanaWithTokensActivationRequest { #[serde(flatten)] platform_request: SolanaActivationParams, spl_tokens_requests: Vec>, + #[serde(default = "true_f")] + pub get_balances: bool, } impl TxHistory for SolanaWithTokensActivationRequest { @@ -205,42 +209,53 @@ impl PlatformWithTokensActivationOps for SolanaCoin { })] } - async fn get_activation_result(&self) -> Result> { + async fn get_activation_result( + &self, + activation_request: &Self::ActivationRequest, + ) -> Result> { let my_address = self.my_address()?; + let current_block = self .current_block() .compat() .await .map_to_mm(Self::ActivationError::Internal)?; - let solana_balance = self - .my_balance() - .compat() - .await - .map_err(|e| Self::ActivationError::GetBalanceError(e.into_inner()))?; - let mut token_balances = HashMap::new(); - let token_infos = self.get_spl_tokens_infos(); - for (token_ticker, info) in token_infos.into_iter() { - let balance = self.my_balance_spl(&info.clone()).await?; - token_balances.insert(token_ticker.to_owned(), balance); - } + let mut result = SolanaWithTokensActivationResult { current_block, solana_addresses_infos: HashMap::new(), spl_addresses_infos: HashMap::new(), }; - result - .solana_addresses_infos - .insert(my_address.clone(), CoinAddressInfo { + + if activation_request.get_balances { + let solana_balance = self + .my_balance() + .compat() + .await + .map_err(|e| Self::ActivationError::GetBalanceError(e.into_inner()))?; + + let (token_tickers, requests): (Vec<_>, Vec<_>) = self + .get_spl_tokens_infos() + .into_iter() + .map(|(ticker, info)| (ticker, self.my_balance_spl(info))) + .unzip(); + let token_balances = token_tickers.into_iter().zip(try_join_all(requests).await?).collect(); + + result + .solana_addresses_infos + .insert(my_address.clone(), CoinAddressInfo { + derivation_method: DerivationMethod::Iguana, + pubkey: my_address.clone(), + balances: solana_balance, + }); + + result.spl_addresses_infos.insert(my_address.clone(), CoinAddressInfo { derivation_method: DerivationMethod::Iguana, - pubkey: my_address.clone(), - balances: solana_balance, + pubkey: my_address, + balances: token_balances, }); + } - result.spl_addresses_infos.insert(my_address.clone(), CoinAddressInfo { - derivation_method: DerivationMethod::Iguana, - pubkey: my_address, - balances: token_balances, - }); Ok(result) } diff --git a/mm2src/coins_activation/src/tendermint_with_assets_activation.rs b/mm2src/coins_activation/src/tendermint_with_assets_activation.rs index 3c477cfdd3..823247554d 100644 --- a/mm2src/coins_activation/src/tendermint_with_assets_activation.rs +++ b/mm2src/coins_activation/src/tendermint_with_assets_activation.rs @@ -11,7 +11,7 @@ use coins::tendermint::{TendermintCoin, TendermintCommons, TendermintConf, Tende TendermintTokenActivationParams, TendermintTokenInitError, TendermintTokenProtocolInfo}; use coins::{CoinBalance, CoinProtocol, MarketCoinOps, MmCoin, PrivKeyBuildPolicy}; use common::executor::{AbortSettings, SpawnAbortable}; -use common::Future01CompatExt; +use common::{true_f, Future01CompatExt}; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use mm2_number::BigDecimal; @@ -35,6 +35,8 @@ pub struct TendermintActivationParams { pub tokens_params: Vec>, #[serde(default)] tx_history: bool, + #[serde(default = "true_f")] + pub get_balances: bool, } impl TxHistory for TendermintActivationParams { @@ -187,34 +189,45 @@ impl PlatformWithTokensActivationOps for TendermintCoin { })] } - async fn get_activation_result(&self) -> Result> { + async fn get_activation_result( + &self, + activation_request: &Self::ActivationRequest, + ) -> Result> { let current_block = self.current_block().compat().await.map_to_mm(|e| TendermintInitError { ticker: self.ticker().to_owned(), kind: TendermintInitErrorKind::RpcError(e), })?; - let balances = self.all_balances().await.mm_err(|e| TendermintInitError { - ticker: self.ticker().to_owned(), - kind: TendermintInitErrorKind::RpcError(e.to_string()), - })?; + let (balance, tokens_balances) = if activation_request.get_balances { + let balances = self.all_balances().await.mm_err(|e| TendermintInitError { + ticker: self.ticker().to_owned(), + kind: TendermintInitErrorKind::RpcError(e.to_string()), + })?; + ( + CoinBalance { + spendable: balances.platform_balance, + unspendable: BigDecimal::default(), + }, + balances + .tokens_balances + .into_iter() + .map(|(ticker, balance)| { + (ticker, CoinBalance { + spendable: balance, + unspendable: BigDecimal::default(), + }) + }) + .collect(), + ) + } else { + (CoinBalance::default(), HashMap::default()) + }; Ok(TendermintActivationResult { address: self.account_id.to_string(), current_block, - balance: CoinBalance { - spendable: balances.platform_balance, - unspendable: BigDecimal::default(), - }, - tokens_balances: balances - .tokens_balances - .into_iter() - .map(|(ticker, balance)| { - (ticker, CoinBalance { - spendable: balance, - unspendable: BigDecimal::default(), - }) - }) - .collect(), + balance, + tokens_balances, ticker: self.ticker().to_owned(), }) } From 150d928d2aa6bfefa9400ce257a491d115c98a5c Mon Sep 17 00:00:00 2001 From: shamardy Date: Tue, 25 Apr 2023 19:28:23 +0200 Subject: [PATCH 02/11] make balance reponse fields optional, early return on get_balances check, integration tests for get_balances --- .../src/bch_with_tokens_activation.rs | 76 +++++++++-------- .../src/eth_with_token_activation.rs | 83 ++++++++++--------- .../src/platform_coin_with_tokens.rs | 22 +++-- .../src/solana_with_tokens_activation.rs | 80 +++++++++--------- .../src/tendermint_with_assets_activation.rs | 50 ++++++----- .../mm2_main/tests/docker_tests/slp_tests.rs | 25 +++++- .../tests/mm2_tests/bch_and_slp_tests.rs | 4 + mm2src/mm2_main/tests/mm2_tests/eth_tests.rs | 63 +++++++++++++- .../mm2_tests/tendermint_ibc_asset_tests.rs | 5 +- .../tests/mm2_tests/tendermint_tests.rs | 30 ++++++- mm2src/mm2_test_helpers/src/for_tests.rs | 72 ++++++++++++++++ mm2src/mm2_test_helpers/src/structs.rs | 20 +++-- 12 files changed, 374 insertions(+), 156 deletions(-) diff --git a/mm2src/coins_activation/src/bch_with_tokens_activation.rs b/mm2src/coins_activation/src/bch_with_tokens_activation.rs index 1fadda67de..382fbb2799 100644 --- a/mm2src/coins_activation/src/bch_with_tokens_activation.rs +++ b/mm2src/coins_activation/src/bch_with_tokens_activation.rs @@ -147,17 +147,19 @@ impl TryFromCoinProtocol for BchProtocolInfo { #[derive(Debug, Serialize)] pub struct BchWithTokensActivationResult { current_block: u64, - bch_addresses_infos: HashMap>, - slp_addresses_infos: HashMap>, + #[serde(skip_serializing_if = "Option::is_none")] + bch_addresses_infos: Option>>, + #[serde(skip_serializing_if = "Option::is_none")] + slp_addresses_infos: Option>>, } impl GetPlatformBalance for BchWithTokensActivationResult { - fn get_platform_balance(&self) -> BigDecimal { - self.bch_addresses_infos - .iter() - .fold(BigDecimal::from(0), |total, (_, addr_info)| { + fn get_platform_balance(&self) -> Option { + self.bch_addresses_infos.as_ref().map(|infos| { + infos.iter().fold(BigDecimal::from(0), |total, (_, addr_info)| { &total + &addr_info.balances.get_total() }) + }) } } @@ -249,6 +251,16 @@ impl PlatformWithTokensActivationOps for BchCoin { &self, activation_request: &Self::ActivationRequest, ) -> Result> { + let current_block = self.as_ref().rpc_client.get_block_count().compat().await?; + + if !activation_request.get_balances { + return Ok(BchWithTokensActivationResult { + current_block, + bch_addresses_infos: None, + slp_addresses_infos: None, + }); + } + let my_address = self.as_ref().derivation_method.single_addr_or_err()?; let my_slp_address = self .get_my_slp_address() @@ -256,40 +268,32 @@ impl PlatformWithTokensActivationOps for BchCoin { .encode() .map_to_mm(BchWithTokensActivationError::Internal)?; - let current_block = self.as_ref().rpc_client.get_block_count().compat().await?; + let bch_unspents = self.bch_unspents_for_display(my_address).await?; + let bch_balance = bch_unspents.platform_balance(self.decimals()); - let mut result = BchWithTokensActivationResult { - current_block, - bch_addresses_infos: HashMap::new(), - slp_addresses_infos: HashMap::new(), - }; - - if activation_request.get_balances { - 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 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); + } - result - .bch_addresses_infos - .insert(my_address.to_string(), CoinAddressInfo { - derivation_method: DerivationMethod::Iguana, - pubkey: self.my_public_key()?.to_string(), - balances: bch_balance, - }); + let bch_addresses_infos = HashMap::from([(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, - }); - } + let slp_addresses_infos = HashMap::from([(my_slp_address, CoinAddressInfo { + derivation_method: DerivationMethod::Iguana, + pubkey: self.my_public_key()?.to_string(), + balances: token_balances, + })]); - Ok(result) + Ok(BchWithTokensActivationResult { + current_block, + bch_addresses_infos: Some(bch_addresses_infos), + slp_addresses_infos: Some(slp_addresses_infos), + }) } fn start_history_background_fetching( diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 2cd0f9f355..89b6e41864 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -147,17 +147,19 @@ impl RegisterTokenInfo for EthCoin { #[derive(Serialize)] pub struct EthWithTokensActivationResult { current_block: u64, - eth_addresses_infos: HashMap>, - erc20_addresses_infos: HashMap>, + #[serde(skip_serializing_if = "Option::is_none")] + eth_addresses_infos: Option>>, + #[serde(skip_serializing_if = "Option::is_none")] + erc20_addresses_infos: Option>>, } impl GetPlatformBalance for EthWithTokensActivationResult { - fn get_platform_balance(&self) -> BigDecimal { - self.eth_addresses_infos - .iter() - .fold(BigDecimal::from(0), |total, (_, addr_info)| { + fn get_platform_balance(&self) -> Option { + self.eth_addresses_infos.as_ref().map(|infos| { + infos.iter().fold(BigDecimal::from(0), |total, (_, addr_info)| { &total + &addr_info.balances.get_total() }) + }) } } @@ -205,50 +207,51 @@ impl PlatformWithTokensActivationOps for EthCoin { &self, activation_request: &Self::ActivationRequest, ) -> Result> { - let my_address = self.my_address()?; - let pubkey = self.get_public_key()?; - let current_block = self .current_block() .compat() .await .map_err(EthActivationV2Error::InternalError)?; - let mut result = EthWithTokensActivationResult { - current_block, - eth_addresses_infos: HashMap::new(), - erc20_addresses_infos: HashMap::new(), - }; + if !activation_request.get_balances { + return Ok(EthWithTokensActivationResult { + current_block, + eth_addresses_infos: None, + erc20_addresses_infos: None, + }); + } + + let my_address = self.my_address()?; + let pubkey = self.get_public_key()?; - if activation_request.get_balances { - 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 eth_balance = self + .my_balance() + .compat() + .await + .map_err(|e| EthActivationV2Error::CouldNotFetchBalance(e.to_string()))?; - result - .eth_addresses_infos - .insert(my_address.to_string(), CoinAddressInfo { - derivation_method: DerivationMethod::Iguana, - pubkey: pubkey.clone(), - balances: eth_balance, - }); + let token_balances = self + .get_tokens_balance_list() + .await + .map_err(|e| EthActivationV2Error::CouldNotFetchBalance(e.to_string()))?; - result - .erc20_addresses_infos - .insert(my_address.to_string(), CoinAddressInfo { - derivation_method: DerivationMethod::Iguana, - pubkey, - balances: token_balances, - }); - } + let eth_addresses_infos = HashMap::from([(my_address.to_string(), CoinAddressInfo { + derivation_method: DerivationMethod::Iguana, + pubkey: pubkey.clone(), + balances: eth_balance, + })]); + + let erc20_addresses_infos = HashMap::from([(my_address.to_string(), CoinAddressInfo { + derivation_method: DerivationMethod::Iguana, + pubkey, + balances: token_balances, + })]); - Ok(result) + Ok(EthWithTokensActivationResult { + current_block, + eth_addresses_infos: Some(eth_addresses_infos), + erc20_addresses_infos: Some(erc20_addresses_infos), + }) } fn start_history_background_fetching( diff --git a/mm2src/coins_activation/src/platform_coin_with_tokens.rs b/mm2src/coins_activation/src/platform_coin_with_tokens.rs index 29949d47a9..c7b134105c 100644 --- a/mm2src/coins_activation/src/platform_coin_with_tokens.rs +++ b/mm2src/coins_activation/src/platform_coin_with_tokens.rs @@ -127,7 +127,7 @@ where } pub trait GetPlatformBalance { - fn get_platform_balance(&self) -> BigDecimal; + fn get_platform_balance(&self) -> Option; } #[async_trait] @@ -207,6 +207,8 @@ pub enum EnablePlatformCoinWithTokensError { PrivKeyPolicyNotAllowed(PrivKeyPolicyNotAllowed), #[display(fmt = "Unexpected derivation method: {}", _0)] UnexpectedDerivationMethod(String), + #[display(fmt = "Activation request error: {}", _0)] + ActivationRequestError(String), Transport(String), AtLeastOneNodeRequired(String), InvalidPayload(String), @@ -277,6 +279,7 @@ impl HttpStatusCode for EnablePlatformCoinWithTokensError { | EnablePlatformCoinWithTokensError::TokenConfigIsNotFound(_) | EnablePlatformCoinWithTokensError::UnexpectedPlatformProtocol { .. } | EnablePlatformCoinWithTokensError::InvalidPayload { .. } + | EnablePlatformCoinWithTokensError::ActivationRequestError(_) | EnablePlatformCoinWithTokensError::AtLeastOneNodeRequired(_) | EnablePlatformCoinWithTokensError::UnexpectedTokenProtocol { .. } => StatusCode::BAD_REQUEST, } @@ -318,11 +321,18 @@ where log::info!("{} current block {}", req.ticker, activation_result.current_block()); if req.request.tx_history() { - platform_coin.start_history_background_fetching( - ctx.clone(), - TxHistoryStorageBuilder::new(&ctx).build()?, - activation_result.get_platform_balance(), - ); + match activation_result.get_platform_balance() { + Some(initial_balance) => + platform_coin.start_history_background_fetching( + ctx.clone(), + TxHistoryStorageBuilder::new(&ctx).build()?, + initial_balance, + ), + None => return MmError::err(EnablePlatformCoinWithTokensError::ActivationRequestError( + "Tx history fetching requires getting balances on activation, current request parameters: `tx_history`=true, `get_balances`=false" + .to_string(), + )), + } } let coins_ctx = CoinsContext::from_ctx(&ctx).unwrap(); diff --git a/mm2src/coins_activation/src/solana_with_tokens_activation.rs b/mm2src/coins_activation/src/solana_with_tokens_activation.rs index ea1900d162..bb650456c6 100644 --- a/mm2src/coins_activation/src/solana_with_tokens_activation.rs +++ b/mm2src/coins_activation/src/solana_with_tokens_activation.rs @@ -92,12 +92,14 @@ impl TxHistory for SolanaWithTokensActivationRequest { #[derive(Debug, Serialize)] pub struct SolanaWithTokensActivationResult { current_block: u64, - solana_addresses_infos: HashMap>, - spl_addresses_infos: HashMap>, + #[serde(skip_serializing_if = "Option::is_none")] + solana_addresses_infos: Option>>, + #[serde(skip_serializing_if = "Option::is_none")] + spl_addresses_infos: Option>>, } impl GetPlatformBalance for SolanaWithTokensActivationResult { - fn get_platform_balance(&self) -> BigDecimal { + fn get_platform_balance(&self) -> Option { self.solana_addresses_infos .iter() .fold(BigDecimal::from(0), |total, (_, addr_info)| { @@ -213,50 +215,52 @@ impl PlatformWithTokensActivationOps for SolanaCoin { &self, activation_request: &Self::ActivationRequest, ) -> Result> { - let my_address = self.my_address()?; - let current_block = self .current_block() .compat() .await .map_to_mm(Self::ActivationError::Internal)?; - let mut result = SolanaWithTokensActivationResult { - current_block, - solana_addresses_infos: HashMap::new(), - spl_addresses_infos: HashMap::new(), - }; - - if activation_request.get_balances { - let solana_balance = self - .my_balance() - .compat() - .await - .map_err(|e| Self::ActivationError::GetBalanceError(e.into_inner()))?; - - let (token_tickers, requests): (Vec<_>, Vec<_>) = self - .get_spl_tokens_infos() - .into_iter() - .map(|(ticker, info)| (ticker, self.my_balance_spl(info))) - .unzip(); - let token_balances = token_tickers.into_iter().zip(try_join_all(requests).await?).collect(); - - result - .solana_addresses_infos - .insert(my_address.clone(), CoinAddressInfo { - derivation_method: DerivationMethod::Iguana, - pubkey: my_address.clone(), - balances: solana_balance, - }); - - result.spl_addresses_infos.insert(my_address.clone(), CoinAddressInfo { - derivation_method: DerivationMethod::Iguana, - pubkey: my_address, - balances: token_balances, + if !activation_request.get_balances { + return Ok(SolanaWithTokensActivationResult { + current_block, + solana_addresses_infos: None, + spl_addresses_infos: None, }); } - Ok(result) + let my_address = self.my_address()?; + + let solana_balance = self + .my_balance() + .compat() + .await + .map_err(|e| Self::ActivationError::GetBalanceError(e.into_inner()))?; + + let (token_tickers, requests): (Vec<_>, Vec<_>) = self + .get_spl_tokens_infos() + .into_iter() + .map(|(ticker, info)| (ticker, self.my_balance_spl(info))) + .unzip(); + let token_balances = token_tickers.into_iter().zip(try_join_all(requests).await?).collect(); + + let solana_addresses_infos = HashMap::from([(my_address.clone(), CoinAddressInfo { + derivation_method: DerivationMethod::Iguana, + pubkey: my_address.clone(), + balances: solana_balance, + })]); + + let spl_addresses_infos = HashMap::from([(my_address.clone(), CoinAddressInfo { + derivation_method: DerivationMethod::Iguana, + pubkey: my_address.clone(), + balances: token_balances, + })]); + + Ok(SolanaWithTokensActivationResult { + current_block, + solana_addresses_infos: Some(solana_addresses_infos), + spl_addresses_infos: Some(spl_addresses_infos), + }) } fn start_history_background_fetching( diff --git a/mm2src/coins_activation/src/tendermint_with_assets_activation.rs b/mm2src/coins_activation/src/tendermint_with_assets_activation.rs index 823247554d..0d3ddd03ec 100644 --- a/mm2src/coins_activation/src/tendermint_with_assets_activation.rs +++ b/mm2src/coins_activation/src/tendermint_with_assets_activation.rs @@ -127,8 +127,10 @@ pub struct TendermintActivationResult { ticker: String, address: String, current_block: u64, - balance: CoinBalance, - tokens_balances: HashMap, + #[serde(skip_serializing_if = "Option::is_none")] + balance: Option, + #[serde(skip_serializing_if = "Option::is_none")] + tokens_balances: Option>, } impl CurrentBlock for TendermintActivationResult { @@ -136,7 +138,7 @@ impl CurrentBlock for TendermintActivationResult { } impl GetPlatformBalance for TendermintActivationResult { - fn get_platform_balance(&self) -> BigDecimal { self.balance.spendable.clone() } + fn get_platform_balance(&self) -> Option { self.balance.as_ref().map(|b| b.spendable.clone()) } } impl From for EnablePlatformCoinWithTokensError { @@ -198,16 +200,29 @@ impl PlatformWithTokensActivationOps for TendermintCoin { kind: TendermintInitErrorKind::RpcError(e), })?; - let (balance, tokens_balances) = if activation_request.get_balances { - let balances = self.all_balances().await.mm_err(|e| TendermintInitError { + if !activation_request.get_balances { + return Ok(TendermintActivationResult { ticker: self.ticker().to_owned(), - kind: TendermintInitErrorKind::RpcError(e.to_string()), - })?; - ( - CoinBalance { - spendable: balances.platform_balance, - unspendable: BigDecimal::default(), - }, + address: self.account_id.to_string(), + current_block, + balance: None, + tokens_balances: None, + }); + } + + let balances = self.all_balances().await.mm_err(|e| TendermintInitError { + ticker: self.ticker().to_owned(), + kind: TendermintInitErrorKind::RpcError(e.to_string()), + })?; + + Ok(TendermintActivationResult { + address: self.account_id.to_string(), + current_block, + balance: Some(CoinBalance { + spendable: balances.platform_balance, + unspendable: BigDecimal::default(), + }), + tokens_balances: Some( balances .tokens_balances .into_iter() @@ -218,16 +233,7 @@ impl PlatformWithTokensActivationOps for TendermintCoin { }) }) .collect(), - ) - } else { - (CoinBalance::default(), HashMap::default()) - }; - - Ok(TendermintActivationResult { - address: self.account_id.to_string(), - current_block, - balance, - tokens_balances, + ), ticker: self.ticker().to_owned(), }) } diff --git a/mm2src/mm2_main/tests/docker_tests/slp_tests.rs b/mm2src/mm2_main/tests/docker_tests/slp_tests.rs index b1e889cc22..1d9818c802 100644 --- a/mm2src/mm2_main/tests/docker_tests/slp_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/slp_tests.rs @@ -2,7 +2,8 @@ use crate::docker_tests::docker_tests_common::*; use crate::integration_tests_common::enable_native; use mm2_number::BigDecimal; use mm2_test_helpers::for_tests::{assert_coin_not_found_on_balance, disable_coin, disable_coin_err, - enable_bch_with_tokens, enable_slp, my_balance, UtxoRpcMode}; + enable_bch_with_tokens, enable_bch_with_tokens_without_balance, enable_slp, + my_balance, UtxoRpcMode}; use mm2_test_helpers::structs::{EnableBchWithTokensResponse, EnableElectrumResponse, EnableSlpResponse, RpcV2Response}; use serde_json::{self as json}; use std::time::Duration; @@ -104,6 +105,7 @@ fn test_bch_and_slp_balance_enable_bch_with_tokens_v2() { let (_, bch_balance) = enable_bch_with_tokens .result .bch_addresses_infos + .unwrap() .into_iter() .next() .unwrap(); @@ -114,6 +116,7 @@ fn test_bch_and_slp_balance_enable_bch_with_tokens_v2() { let (_, slp_balances) = enable_bch_with_tokens .result .slp_addresses_infos + .unwrap() .into_iter() .next() .unwrap(); @@ -126,6 +129,26 @@ fn test_bch_and_slp_balance_enable_bch_with_tokens_v2() { assert_eq!(expected_slp_unspendable, actual_slp.unspendable); } +#[test] +fn test_enable_bch_with_tokens_v2_without_balance() { + let mm = slp_supplied_node(); + + let tx_history = false; + let enable_bch_with_tokens = block_on(enable_bch_with_tokens_without_balance( + &mm, + "FORSLP", + &["ADEXSLP"], + UtxoRpcMode::Native, + tx_history, + )); + + let enable_bch_with_tokens: RpcV2Response = + json::from_value(enable_bch_with_tokens).unwrap(); + + assert!(enable_bch_with_tokens.result.bch_addresses_infos.is_none()); + assert!(enable_bch_with_tokens.result.slp_addresses_infos.is_none()); +} + #[test] fn test_withdraw_bch_max_must_not_spend_slp() { let mm = slp_supplied_node(); diff --git a/mm2src/mm2_main/tests/mm2_tests/bch_and_slp_tests.rs b/mm2src/mm2_main/tests/mm2_tests/bch_and_slp_tests.rs index 38830e6d24..b059cad70a 100644 --- a/mm2src/mm2_main/tests/mm2_tests/bch_and_slp_tests.rs +++ b/mm2src/mm2_main/tests/mm2_tests/bch_and_slp_tests.rs @@ -650,6 +650,7 @@ fn test_bch_and_slp_with_hd_account_id() { let (bch_addr, _) = activation_result .result .bch_addresses_infos + .unwrap() .into_iter() .exactly_one() .unwrap(); @@ -658,6 +659,7 @@ fn test_bch_and_slp_with_hd_account_id() { let (slp_addr, _) = activation_result .result .slp_addresses_infos + .unwrap() .into_iter() .exactly_one() .unwrap(); @@ -682,6 +684,7 @@ fn test_bch_and_slp_with_hd_account_id() { let (bch_addr, _) = activation_result .result .bch_addresses_infos + .unwrap() .into_iter() .exactly_one() .unwrap(); @@ -690,6 +693,7 @@ fn test_bch_and_slp_with_hd_account_id() { let (slp_addr, _) = activation_result .result .slp_addresses_infos + .unwrap() .into_iter() .exactly_one() .unwrap(); diff --git a/mm2src/mm2_main/tests/mm2_tests/eth_tests.rs b/mm2src/mm2_main/tests/mm2_tests/eth_tests.rs index d1ae803d03..d37dd9b258 100644 --- a/mm2src/mm2_main/tests/mm2_tests/eth_tests.rs +++ b/mm2src/mm2_main/tests/mm2_tests/eth_tests.rs @@ -2,7 +2,8 @@ use common::block_on; use http::StatusCode; use mm2_test_helpers::for_tests::{disable_coin, disable_coin_err, get_passphrase, MarketMakerIt, Mm2TestConf, ETH_DEV_NODES}; -use serde_json::{json, Value as Json}; +use mm2_test_helpers::structs::{EnableEthWithTokensResponse, RpcV2Response}; +use serde_json::{self as json, json, Value as Json}; use std::str::FromStr; #[cfg(not(target_arch = "wasm32"))] @@ -35,6 +36,42 @@ async fn enable_eth_with_tokens(mm: &MarketMakerIt, platform_coin: &str, tokens: Json::from_str(&enable.1).unwrap() } +#[cfg(not(target_arch = "wasm32"))] +async fn enable_eth_with_tokens_without_balance( + mm: &MarketMakerIt, + platform_coin: &str, + tokens: &[&str], + nodes: &[&str], +) -> Json { + let erc20_tokens_requests: Vec<_> = tokens.iter().map(|ticker| json!({ "ticker": ticker })).collect(); + let nodes: Vec<_> = nodes.iter().map(|url| json!({ "url": url })).collect(); + + let enable = mm + .rpc(&json!({ + "userpass": mm.userpass, + "method": "enable_eth_with_tokens", + "mmrpc": "2.0", + "params": { + "ticker": platform_coin, + "swap_contract_address":"0x2b294F029Fde858b2c62184e8390591755521d8E", + "fallback_swap_contract":"0x8500AFc0bc5214728082163326C2FF0C73f4a871", + "nodes": nodes, + "tx_history": true, + "erc20_tokens_requests": erc20_tokens_requests, + "get_balances": false, + } + })) + .await + .unwrap(); + assert_eq!( + enable.0, + StatusCode::OK, + "'enable_eth_with_tokens' failed: {}", + enable.1 + ); + Json::from_str(&enable.1).unwrap() +} + #[test] #[cfg(not(target_arch = "wasm32"))] fn test_disable_eth_coin_with_token() { @@ -77,3 +114,27 @@ fn test_disable_eth_coin_with_token() { // Then try to disable ETH platform coin. block_on(disable_coin(&mm, "ETH")); } + +#[test] +#[cfg(not(target_arch = "wasm32"))] +fn test_disable_eth_coin_with_token_without_balance() { + let passphrase = get_passphrase(&".env.client", "BOB_PASSPHRASE").unwrap(); + let coins = json! ([ + {"coin":"ETH","name":"ethereum","protocol":{"type":"ETH"},"rpcport":80,"mm2":1}, + {"coin":"JST","name":"jst","rpcport":80,"mm2":1,"protocol":{"type":"ERC20","protocol_data":{"platform":"ETH","contract_address":"0x2b294F029Fde858b2c62184e8390591755521d8E"}}} + ]); + let conf = Mm2TestConf::seednode(&passphrase, &coins); + let mm = block_on(MarketMakerIt::start_async(conf.conf, conf.rpc_password, None)).unwrap(); + let enable_eth_with_tokens = block_on(enable_eth_with_tokens_without_balance( + &mm, + "ETH", + &["JST"], + ETH_DEV_NODES, + )); + + let enable_eth_with_tokens: RpcV2Response = + json::from_value(enable_eth_with_tokens).unwrap(); + + assert!(enable_eth_with_tokens.result.eth_addresses_infos.is_none()); + assert!(enable_eth_with_tokens.result.erc20_addresses_infos.is_none()); +} diff --git a/mm2src/mm2_main/tests/mm2_tests/tendermint_ibc_asset_tests.rs b/mm2src/mm2_main/tests/mm2_tests/tendermint_ibc_asset_tests.rs index 19b5d99a2a..6e150f25f5 100644 --- a/mm2src/mm2_main/tests/mm2_tests/tendermint_ibc_asset_tests.rs +++ b/mm2src/mm2_main/tests/mm2_tests/tendermint_ibc_asset_tests.rs @@ -32,11 +32,12 @@ fn test_iris_with_usdc_activation_balance_orderbook() { assert_eq!(response.result.address, expected_address); let expected_iris_balance = BigDecimal::from(100); - assert_eq!(response.result.balance.spendable, expected_iris_balance); + assert_eq!(response.result.balance.unwrap().spendable, expected_iris_balance); let expected_usdc_balance: BigDecimal = "0.683142".parse().unwrap(); - let actual_usdc_balance = response.result.tokens_balances.get(USDC_IBC_TICKER).unwrap(); + let tokens_balances = response.result.tokens_balances.unwrap(); + let actual_usdc_balance = tokens_balances.get(USDC_IBC_TICKER).unwrap(); assert_eq!(actual_usdc_balance.spendable, expected_usdc_balance); let actual_usdc_balance = block_on(my_balance(&mm, USDC_IBC_TICKER)).balance; diff --git a/mm2src/mm2_main/tests/mm2_tests/tendermint_tests.rs b/mm2src/mm2_main/tests/mm2_tests/tendermint_tests.rs index 660e60c4e5..dd5f6f9939 100644 --- a/mm2src/mm2_main/tests/mm2_tests/tendermint_tests.rs +++ b/mm2src/mm2_main/tests/mm2_tests/tendermint_tests.rs @@ -1,9 +1,10 @@ use common::block_on; use mm2_number::BigDecimal; use mm2_test_helpers::for_tests::{atom_testnet_conf, disable_coin, disable_coin_err, enable_tendermint, - enable_tendermint_token, get_tendermint_my_tx_history, ibc_withdraw, - iris_nimda_testnet_conf, iris_testnet_conf, my_balance, send_raw_transaction, - withdraw_v1, MarketMakerIt, Mm2TestConf}; + enable_tendermint_token, enable_tendermint_without_balance, + get_tendermint_my_tx_history, ibc_withdraw, iris_nimda_testnet_conf, + iris_testnet_conf, my_balance, send_raw_transaction, withdraw_v1, MarketMakerIt, + Mm2TestConf}; use mm2_test_helpers::structs::{RpcV2Response, TendermintActivationResult, TransactionDetails}; use serde_json::{self as json, json}; @@ -34,7 +35,7 @@ fn test_tendermint_activation_and_balance() { let result: RpcV2Response = json::from_value(activation_result).unwrap(); assert_eq!(result.result.address, expected_address); let expected_balance: BigDecimal = "8.0959".parse().unwrap(); - assert_eq!(result.result.balance.spendable, expected_balance); + assert_eq!(result.result.balance.unwrap().spendable, expected_balance); let my_balance = block_on(my_balance(&mm, ATOM_TICKER)); assert_eq!(my_balance.balance, expected_balance); @@ -43,6 +44,27 @@ fn test_tendermint_activation_and_balance() { assert_eq!(my_balance.coin, ATOM_TICKER); } +#[test] +fn test_tendermint_activation_without_balance() { + let coins = json!([atom_testnet_conf()]); + + let conf = Mm2TestConf::seednode(ATOM_TEST_BALANCE_SEED, &coins); + let mm = MarketMakerIt::start(conf.conf, conf.rpc_password, None).unwrap(); + + let activation_result = block_on(enable_tendermint_without_balance( + &mm, + ATOM_TICKER, + &[], + ATOM_TENDERMINT_RPC_URLS, + false, + )); + + let result: RpcV2Response = json::from_value(activation_result).unwrap(); + + assert!(result.result.balance.is_none()); + assert!(result.result.tokens_balances.is_none()); +} + #[test] fn test_tendermint_withdraw() { let coins = json!([atom_testnet_conf()]); diff --git a/mm2src/mm2_test_helpers/src/for_tests.rs b/mm2src/mm2_test_helpers/src/for_tests.rs index 910837c666..a12bfd59d7 100644 --- a/mm2src/mm2_test_helpers/src/for_tests.rs +++ b/mm2src/mm2_test_helpers/src/for_tests.rs @@ -1736,6 +1736,41 @@ pub async fn enable_bch_with_tokens( json::from_str(&enable.1).unwrap() } +pub async fn enable_bch_with_tokens_without_balance( + mm: &MarketMakerIt, + platform_coin: &str, + tokens: &[&str], + mode: UtxoRpcMode, + tx_history: bool, +) -> Json { + let slp_requests: Vec<_> = tokens.iter().map(|ticker| json!({ "ticker": ticker })).collect(); + + let enable = mm + .rpc(&json!({ + "userpass": mm.userpass, + "method": "enable_bch_with_tokens", + "mmrpc": "2.0", + "params": { + "ticker": platform_coin, + "allow_slp_unsafe_conf": true, + "bchd_urls": [], + "mode": mode, + "tx_history": tx_history, + "slp_tokens_requests": slp_requests, + "get_balances": false, + } + })) + .await + .unwrap(); + assert_eq!( + enable.0, + StatusCode::OK, + "'enable_bch_with_tokens' failed: {}", + enable.1 + ); + json::from_str(&enable.1).unwrap() +} + pub async fn enable_solana_with_tokens( mm: &MarketMakerIt, platform_coin: &str, @@ -2511,6 +2546,43 @@ pub async fn enable_tendermint( json::from_str(&request.1).unwrap() } +pub async fn enable_tendermint_without_balance( + mm: &MarketMakerIt, + coin: &str, + ibc_assets: &[&str], + rpc_urls: &[&str], + tx_history: bool, +) -> Json { + let ibc_requests: Vec<_> = ibc_assets.iter().map(|ticker| json!({ "ticker": ticker })).collect(); + + let request = json!({ + "userpass": mm.userpass, + "method": "enable_tendermint_with_assets", + "mmrpc": "2.0", + "params": { + "ticker": coin, + "tokens_params": ibc_requests, + "rpc_urls": rpc_urls, + "tx_history": tx_history, + "get_balances": false + } + }); + println!( + "enable_tendermint_with_assets request {}", + json::to_string(&request).unwrap() + ); + + let request = mm.rpc(&request).await.unwrap(); + assert_eq!( + request.0, + StatusCode::OK, + "'enable_tendermint_with_assets' failed: {}", + request.1 + ); + println!("enable_tendermint_with_assets response {}", request.1); + json::from_str(&request.1).unwrap() +} + pub async fn get_tendermint_my_tx_history(mm: &MarketMakerIt, coin: &str, limit: usize, page_number: usize) -> Json { let request = json!({ "userpass": mm.userpass, diff --git a/mm2src/mm2_test_helpers/src/structs.rs b/mm2src/mm2_test_helpers/src/structs.rs index d26dc9b77b..875072f5c1 100644 --- a/mm2src/mm2_test_helpers/src/structs.rs +++ b/mm2src/mm2_test_helpers/src/structs.rs @@ -904,20 +904,28 @@ pub struct CoinAddressInfo { pub type TokenBalances = HashMap; +#[derive(Debug, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct EnableEthWithTokensResponse { + pub current_block: u64, + pub eth_addresses_infos: Option>>, + pub erc20_addresses_infos: Option>>, +} + #[derive(Debug, Deserialize)] #[serde(deny_unknown_fields)] pub struct EnableBchWithTokensResponse { pub current_block: u64, - pub bch_addresses_infos: HashMap>, - pub slp_addresses_infos: HashMap>, + pub bch_addresses_infos: Option>>, + pub slp_addresses_infos: Option>>, } #[derive(Debug, Deserialize)] #[serde(deny_unknown_fields)] pub struct EnableSolanaWithTokensResponse { pub current_block: u64, - pub solana_addresses_infos: HashMap>, - pub spl_addresses_infos: HashMap>, + pub solana_addresses_infos: Option>>, + pub spl_addresses_infos: Option>>, } #[derive(Debug, Deserialize)] @@ -1093,8 +1101,8 @@ pub struct WithdrawResult {} pub struct TendermintActivationResult { pub address: String, pub current_block: u64, - pub balance: CoinBalance, - pub tokens_balances: HashMap, + pub balance: Option, + pub tokens_balances: Option>, pub ticker: String, } From 19fd34e3bfff91ab1fb9bd395a5df68b71f306ae Mon Sep 17 00:00:00 2001 From: shamardy Date: Wed, 26 Apr 2023 18:49:29 +0200 Subject: [PATCH 03/11] request bch balance at the start of bch_and_slp_history_loop if get_balances is false --- .../tendermint/tendermint_tx_history_v2.rs | 2 +- mm2src/coins/utxo/utxo_tx_history_v2.rs | 37 ++++++++++++++----- .../src/bch_with_tokens_activation.rs | 2 +- .../src/eth_with_token_activation.rs | 2 +- .../src/platform_coin_with_tokens.rs | 22 +++-------- .../src/solana_with_tokens_activation.rs | 2 +- .../src/tendermint_with_assets_activation.rs | 2 +- 7 files changed, 39 insertions(+), 30 deletions(-) diff --git a/mm2src/coins/tendermint/tendermint_tx_history_v2.rs b/mm2src/coins/tendermint/tendermint_tx_history_v2.rs index fa637e858a..e4851a626a 100644 --- a/mm2src/coins/tendermint/tendermint_tx_history_v2.rs +++ b/mm2src/coins/tendermint/tendermint_tx_history_v2.rs @@ -877,7 +877,7 @@ pub async fn tendermint_history_loop( coin: TendermintCoin, storage: impl TxHistoryStorage, _ctx: MmArc, - _current_balance: BigDecimal, + _current_balance: Option, ) { let balances = match coin.all_balances().await { Ok(balances) => balances, diff --git a/mm2src/coins/utxo/utxo_tx_history_v2.rs b/mm2src/coins/utxo/utxo_tx_history_v2.rs index f822a285b5..8a3e47c100 100644 --- a/mm2src/coins/utxo/utxo_tx_history_v2.rs +++ b/mm2src/coins/utxo/utxo_tx_history_v2.rs @@ -679,18 +679,37 @@ pub async fn bch_and_slp_history_loop( coin: BchCoin, storage: impl TxHistoryStorage, metrics: MetricsArc, - current_balance: BigDecimal, + current_balance: Option, ) { - let my_address = match coin.my_address() { - Ok(my_address) => my_address, - Err(e) => { - error!("{}", e); - return; + let balances = match current_balance { + Some(current_balance) => { + let my_address = match coin.my_address() { + Ok(my_address) => my_address, + Err(e) => { + error!("{}", e); + return; + }, + }; + HashMap::from([(my_address, current_balance)]) + }, + None => { + let ticker = coin.ticker().to_string(); + match retry_on_err!(async { coin.my_addresses_balances().await }) + .until_ready() + .repeat_every_secs(30.) + .inspect_err(move |e| { + error!("Error {e:?} on balance fetching for the coin {}", ticker); + }) + .await + { + Ok(addresses_balances) => addresses_balances, + Err(e) => { + error!("{}", e); + return; + }, + } }, }; - let mut balances = HashMap::new(); - balances.insert(my_address, current_balance); - drop_mutability!(balances); let ctx = UtxoTxHistoryCtx { coin, diff --git a/mm2src/coins_activation/src/bch_with_tokens_activation.rs b/mm2src/coins_activation/src/bch_with_tokens_activation.rs index 382fbb2799..0c815df7be 100644 --- a/mm2src/coins_activation/src/bch_with_tokens_activation.rs +++ b/mm2src/coins_activation/src/bch_with_tokens_activation.rs @@ -300,7 +300,7 @@ impl PlatformWithTokensActivationOps for BchCoin { &self, ctx: MmArc, storage: impl TxHistoryStorage + Send + 'static, - initial_balance: BigDecimal, + initial_balance: Option, ) { let fut = bch_and_slp_history_loop(self.clone(), storage, ctx.metrics.clone(), initial_balance); diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 89b6e41864..eca2f797f1 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -258,7 +258,7 @@ impl PlatformWithTokensActivationOps for EthCoin { &self, _ctx: MmArc, _storage: impl TxHistoryStorage + Send + 'static, - _initial_balance: BigDecimal, + _initial_balance: Option, ) { } } diff --git a/mm2src/coins_activation/src/platform_coin_with_tokens.rs b/mm2src/coins_activation/src/platform_coin_with_tokens.rs index c7b134105c..2a1b19c513 100644 --- a/mm2src/coins_activation/src/platform_coin_with_tokens.rs +++ b/mm2src/coins_activation/src/platform_coin_with_tokens.rs @@ -159,7 +159,7 @@ pub trait PlatformWithTokensActivationOps: Into { &self, ctx: MmArc, storage: impl TxHistoryStorage, - initial_balance: BigDecimal, + initial_balance: Option, ); } @@ -207,8 +207,6 @@ pub enum EnablePlatformCoinWithTokensError { PrivKeyPolicyNotAllowed(PrivKeyPolicyNotAllowed), #[display(fmt = "Unexpected derivation method: {}", _0)] UnexpectedDerivationMethod(String), - #[display(fmt = "Activation request error: {}", _0)] - ActivationRequestError(String), Transport(String), AtLeastOneNodeRequired(String), InvalidPayload(String), @@ -279,7 +277,6 @@ impl HttpStatusCode for EnablePlatformCoinWithTokensError { | EnablePlatformCoinWithTokensError::TokenConfigIsNotFound(_) | EnablePlatformCoinWithTokensError::UnexpectedPlatformProtocol { .. } | EnablePlatformCoinWithTokensError::InvalidPayload { .. } - | EnablePlatformCoinWithTokensError::ActivationRequestError(_) | EnablePlatformCoinWithTokensError::AtLeastOneNodeRequired(_) | EnablePlatformCoinWithTokensError::UnexpectedTokenProtocol { .. } => StatusCode::BAD_REQUEST, } @@ -321,18 +318,11 @@ where log::info!("{} current block {}", req.ticker, activation_result.current_block()); if req.request.tx_history() { - match activation_result.get_platform_balance() { - Some(initial_balance) => - platform_coin.start_history_background_fetching( - ctx.clone(), - TxHistoryStorageBuilder::new(&ctx).build()?, - initial_balance, - ), - None => return MmError::err(EnablePlatformCoinWithTokensError::ActivationRequestError( - "Tx history fetching requires getting balances on activation, current request parameters: `tx_history`=true, `get_balances`=false" - .to_string(), - )), - } + platform_coin.start_history_background_fetching( + ctx.clone(), + TxHistoryStorageBuilder::new(&ctx).build()?, + activation_result.get_platform_balance(), + ); } let coins_ctx = CoinsContext::from_ctx(&ctx).unwrap(); diff --git a/mm2src/coins_activation/src/solana_with_tokens_activation.rs b/mm2src/coins_activation/src/solana_with_tokens_activation.rs index bb650456c6..b8b37ce9c2 100644 --- a/mm2src/coins_activation/src/solana_with_tokens_activation.rs +++ b/mm2src/coins_activation/src/solana_with_tokens_activation.rs @@ -267,7 +267,7 @@ impl PlatformWithTokensActivationOps for SolanaCoin { &self, _ctx: MmArc, _storage: impl TxHistoryStorage + Send + 'static, - _initial_balance: BigDecimal, + _initial_balance: Option, ) { } } diff --git a/mm2src/coins_activation/src/tendermint_with_assets_activation.rs b/mm2src/coins_activation/src/tendermint_with_assets_activation.rs index 0d3ddd03ec..39ccbe8349 100644 --- a/mm2src/coins_activation/src/tendermint_with_assets_activation.rs +++ b/mm2src/coins_activation/src/tendermint_with_assets_activation.rs @@ -242,7 +242,7 @@ impl PlatformWithTokensActivationOps for TendermintCoin { &self, ctx: MmArc, storage: impl TxHistoryStorage, - initial_balance: BigDecimal, + initial_balance: Option, ) { let fut = tendermint_history_loop(self.clone(), storage, ctx, initial_balance); From d8da3c42a7dfa585a97fd58790f773ae54adbadc Mon Sep 17 00:00:00 2001 From: shamardy Date: Wed, 26 Apr 2023 19:21:14 +0200 Subject: [PATCH 04/11] fix solana compilation --- .../coins_activation/src/solana_with_tokens_activation.rs | 6 +++--- mm2src/mm2_main/tests/docker_tests/solana_tests.rs | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mm2src/coins_activation/src/solana_with_tokens_activation.rs b/mm2src/coins_activation/src/solana_with_tokens_activation.rs index b8b37ce9c2..8f790c2fc1 100644 --- a/mm2src/coins_activation/src/solana_with_tokens_activation.rs +++ b/mm2src/coins_activation/src/solana_with_tokens_activation.rs @@ -100,11 +100,11 @@ pub struct SolanaWithTokensActivationResult { impl GetPlatformBalance for SolanaWithTokensActivationResult { fn get_platform_balance(&self) -> Option { - self.solana_addresses_infos - .iter() - .fold(BigDecimal::from(0), |total, (_, addr_info)| { + self.solana_addresses_infos.as_ref().map(|infos| { + infos.iter().fold(BigDecimal::from(0), |total, (_, addr_info)| { &total + &addr_info.balances.get_total() }) + }) } } diff --git a/mm2src/mm2_main/tests/docker_tests/solana_tests.rs b/mm2src/mm2_main/tests/docker_tests/solana_tests.rs index 1164c20c95..e46035c1b2 100644 --- a/mm2src/mm2_main/tests/docker_tests/solana_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/solana_tests.rs @@ -23,6 +23,7 @@ fn test_solana_and_spl_balance_enable_spl_v2() { let (_, solana_balance) = enable_solana_with_tokens .result .solana_addresses_infos + .unwrap() .into_iter() .next() .unwrap(); @@ -31,6 +32,7 @@ fn test_solana_and_spl_balance_enable_spl_v2() { let (_, spl_balances) = enable_solana_with_tokens .result .spl_addresses_infos + .unwrap() .into_iter() .next() .unwrap(); From abfe1bead2c7c0e557213021542a06e69f13e52e Mon Sep 17 00:00:00 2001 From: shamardy Date: Thu, 27 Apr 2023 00:29:21 +0200 Subject: [PATCH 05/11] fix enable with tokens responses to remove only the balance field from response if get_balances is false --- .../src/bch_with_tokens_activation.rs | 58 +++++++++--------- .../src/eth_with_token_activation.rs | 58 +++++++++--------- mm2src/coins_activation/src/prelude.rs | 3 +- .../src/solana_with_tokens_activation.rs | 61 +++++++++---------- .../mm2_main/tests/docker_tests/slp_tests.rs | 35 ++++++++--- .../tests/docker_tests/solana_tests.rs | 11 ++-- .../tests/mm2_tests/bch_and_slp_tests.rs | 4 -- mm2src/mm2_main/tests/mm2_tests/eth_tests.rs | 17 +++++- mm2src/mm2_test_helpers/src/structs.rs | 14 ++--- 9 files changed, 144 insertions(+), 117 deletions(-) diff --git a/mm2src/coins_activation/src/bch_with_tokens_activation.rs b/mm2src/coins_activation/src/bch_with_tokens_activation.rs index 0c815df7be..37f03f434d 100644 --- a/mm2src/coins_activation/src/bch_with_tokens_activation.rs +++ b/mm2src/coins_activation/src/bch_with_tokens_activation.rs @@ -147,19 +147,17 @@ impl TryFromCoinProtocol for BchProtocolInfo { #[derive(Debug, Serialize)] pub struct BchWithTokensActivationResult { current_block: u64, - #[serde(skip_serializing_if = "Option::is_none")] - bch_addresses_infos: Option>>, - #[serde(skip_serializing_if = "Option::is_none")] - slp_addresses_infos: Option>>, + bch_addresses_infos: HashMap>, + slp_addresses_infos: HashMap>, } impl GetPlatformBalance for BchWithTokensActivationResult { fn get_platform_balance(&self) -> Option { - self.bch_addresses_infos.as_ref().map(|infos| { - infos.iter().fold(BigDecimal::from(0), |total, (_, addr_info)| { - &total + &addr_info.balances.get_total() + self.bch_addresses_infos + .iter() + .fold(Some(BigDecimal::from(0)), |total, (_, addr_info)| { + total.and_then(|t| addr_info.balances.as_ref().map(|b| t + b.get_total())) }) - }) } } @@ -253,46 +251,48 @@ impl PlatformWithTokensActivationOps for BchCoin { ) -> Result> { let current_block = self.as_ref().rpc_client.get_block_count().compat().await?; - if !activation_request.get_balances { - return Ok(BchWithTokensActivationResult { - current_block, - bch_addresses_infos: None, - slp_addresses_infos: None, - }); - } - let my_address = self.as_ref().derivation_method.single_addr_or_err()?; let my_slp_address = self .get_my_slp_address() .map_to_mm(BchWithTokensActivationError::Internal)? .encode() .map_to_mm(BchWithTokensActivationError::Internal)?; - - 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 pubkey = self.my_public_key()?.to_string(); + + let (bch_balance, token_balances) = if activation_request.get_balances { + let bch_unspents = self.bch_unspents_for_display(my_address).await?; + let token_balances = self + .get_slp_tokens_infos() + .iter() + .map(|(token_ticker, info)| { + let token_balance = bch_unspents.slp_token_balance(&info.token_id, info.decimals); + (token_ticker.clone(), token_balance) + }) + .collect(); + ( + Some(bch_unspents.platform_balance(self.decimals())), + Some(token_balances), + ) + } else { + (None, None) + }; let bch_addresses_infos = HashMap::from([(my_address.to_string(), CoinAddressInfo { derivation_method: DerivationMethod::Iguana, - pubkey: self.my_public_key()?.to_string(), + pubkey: pubkey.clone(), balances: bch_balance, })]); let slp_addresses_infos = HashMap::from([(my_slp_address, CoinAddressInfo { derivation_method: DerivationMethod::Iguana, - pubkey: self.my_public_key()?.to_string(), + pubkey, balances: token_balances, })]); Ok(BchWithTokensActivationResult { current_block, - bch_addresses_infos: Some(bch_addresses_infos), - slp_addresses_infos: Some(slp_addresses_infos), + bch_addresses_infos, + slp_addresses_infos, }) } diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index eca2f797f1..9f37d89ed0 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -147,19 +147,17 @@ impl RegisterTokenInfo for EthCoin { #[derive(Serialize)] pub struct EthWithTokensActivationResult { current_block: u64, - #[serde(skip_serializing_if = "Option::is_none")] - eth_addresses_infos: Option>>, - #[serde(skip_serializing_if = "Option::is_none")] - erc20_addresses_infos: Option>>, + eth_addresses_infos: HashMap>, + erc20_addresses_infos: HashMap>, } impl GetPlatformBalance for EthWithTokensActivationResult { fn get_platform_balance(&self) -> Option { - self.eth_addresses_infos.as_ref().map(|infos| { - infos.iter().fold(BigDecimal::from(0), |total, (_, addr_info)| { - &total + &addr_info.balances.get_total() + self.eth_addresses_infos + .iter() + .fold(Some(BigDecimal::from(0)), |total, (_, addr_info)| { + total.and_then(|t| addr_info.balances.as_ref().map(|b| t + b.get_total())) }) - }) } } @@ -213,35 +211,37 @@ impl PlatformWithTokensActivationOps for EthCoin { .await .map_err(EthActivationV2Error::InternalError)?; - if !activation_request.get_balances { - return Ok(EthWithTokensActivationResult { - current_block, - eth_addresses_infos: None, - erc20_addresses_infos: None, - }); - } - let my_address = self.my_address()?; let pubkey = self.get_public_key()?; - let eth_balance = self - .my_balance() - .compat() - .await - .map_err(|e| EthActivationV2Error::CouldNotFetchBalance(e.to_string()))?; + let eth_balance = if activation_request.get_balances { + Some( + self.my_balance() + .compat() + .await + .map_err(|e| EthActivationV2Error::CouldNotFetchBalance(e.to_string()))?, + ) + } else { + None + }; - let token_balances = self - .get_tokens_balance_list() - .await - .map_err(|e| EthActivationV2Error::CouldNotFetchBalance(e.to_string()))?; + let token_balances = if activation_request.get_balances { + Some( + self.get_tokens_balance_list() + .await + .map_err(|e| EthActivationV2Error::CouldNotFetchBalance(e.to_string()))?, + ) + } else { + None + }; - let eth_addresses_infos = HashMap::from([(my_address.to_string(), CoinAddressInfo { + let eth_addresses_infos = HashMap::from([(my_address.clone(), CoinAddressInfo { derivation_method: DerivationMethod::Iguana, pubkey: pubkey.clone(), balances: eth_balance, })]); - let erc20_addresses_infos = HashMap::from([(my_address.to_string(), CoinAddressInfo { + let erc20_addresses_infos = HashMap::from([(my_address, CoinAddressInfo { derivation_method: DerivationMethod::Iguana, pubkey, balances: token_balances, @@ -249,8 +249,8 @@ impl PlatformWithTokensActivationOps for EthCoin { Ok(EthWithTokensActivationResult { current_block, - eth_addresses_infos: Some(eth_addresses_infos), - erc20_addresses_infos: Some(erc20_addresses_infos), + eth_addresses_infos, + erc20_addresses_infos, }) } diff --git a/mm2src/coins_activation/src/prelude.rs b/mm2src/coins_activation/src/prelude.rs index 55e1d03aba..f110e8ead6 100644 --- a/mm2src/coins_activation/src/prelude.rs +++ b/mm2src/coins_activation/src/prelude.rs @@ -44,7 +44,8 @@ pub enum DerivationMethod { pub struct CoinAddressInfo { pub(crate) derivation_method: DerivationMethod, pub(crate) pubkey: String, - pub(crate) balances: Balance, + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) balances: Option, } pub type TokenBalances = HashMap; diff --git a/mm2src/coins_activation/src/solana_with_tokens_activation.rs b/mm2src/coins_activation/src/solana_with_tokens_activation.rs index 8f790c2fc1..3ad87ecaba 100644 --- a/mm2src/coins_activation/src/solana_with_tokens_activation.rs +++ b/mm2src/coins_activation/src/solana_with_tokens_activation.rs @@ -92,19 +92,17 @@ impl TxHistory for SolanaWithTokensActivationRequest { #[derive(Debug, Serialize)] pub struct SolanaWithTokensActivationResult { current_block: u64, - #[serde(skip_serializing_if = "Option::is_none")] - solana_addresses_infos: Option>>, - #[serde(skip_serializing_if = "Option::is_none")] - spl_addresses_infos: Option>>, + solana_addresses_infos: HashMap>, + spl_addresses_infos: HashMap>, } impl GetPlatformBalance for SolanaWithTokensActivationResult { fn get_platform_balance(&self) -> Option { - self.solana_addresses_infos.as_ref().map(|infos| { - infos.iter().fold(BigDecimal::from(0), |total, (_, addr_info)| { - &total + &addr_info.balances.get_total() + self.solana_addresses_infos + .iter() + .fold(Some(BigDecimal::from(0)), |total, (_, addr_info)| { + total.and_then(|t| addr_info.balances.as_ref().map(|b| t + b.get_total())) }) - }) } } @@ -221,28 +219,29 @@ impl PlatformWithTokensActivationOps for SolanaCoin { .await .map_to_mm(Self::ActivationError::Internal)?; - if !activation_request.get_balances { - return Ok(SolanaWithTokensActivationResult { - current_block, - solana_addresses_infos: None, - spl_addresses_infos: None, - }); - } - let my_address = self.my_address()?; - let solana_balance = self - .my_balance() - .compat() - .await - .map_err(|e| Self::ActivationError::GetBalanceError(e.into_inner()))?; - - let (token_tickers, requests): (Vec<_>, Vec<_>) = self - .get_spl_tokens_infos() - .into_iter() - .map(|(ticker, info)| (ticker, self.my_balance_spl(info))) - .unzip(); - let token_balances = token_tickers.into_iter().zip(try_join_all(requests).await?).collect(); + let solana_balance = if activation_request.get_balances { + Some( + self.my_balance() + .compat() + .await + .map_err(|e| Self::ActivationError::GetBalanceError(e.into_inner()))?, + ) + } else { + None + }; + + let token_balances = if activation_request.get_balances { + let (token_tickers, requests): (Vec<_>, Vec<_>) = self + .get_spl_tokens_infos() + .into_iter() + .map(|(ticker, info)| (ticker, self.my_balance_spl(info))) + .unzip(); + Some(token_tickers.into_iter().zip(try_join_all(requests).await?).collect()) + } else { + None + }; let solana_addresses_infos = HashMap::from([(my_address.clone(), CoinAddressInfo { derivation_method: DerivationMethod::Iguana, @@ -252,14 +251,14 @@ impl PlatformWithTokensActivationOps for SolanaCoin { let spl_addresses_infos = HashMap::from([(my_address.clone(), CoinAddressInfo { derivation_method: DerivationMethod::Iguana, - pubkey: my_address.clone(), + pubkey: my_address, balances: token_balances, })]); Ok(SolanaWithTokensActivationResult { current_block, - solana_addresses_infos: Some(solana_addresses_infos), - spl_addresses_infos: Some(spl_addresses_infos), + solana_addresses_infos, + spl_addresses_infos, }) } diff --git a/mm2src/mm2_main/tests/docker_tests/slp_tests.rs b/mm2src/mm2_main/tests/docker_tests/slp_tests.rs index 1d9818c802..d3839c4d90 100644 --- a/mm2src/mm2_main/tests/docker_tests/slp_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/slp_tests.rs @@ -102,29 +102,33 @@ fn test_bch_and_slp_balance_enable_bch_with_tokens_v2() { let expected_bch_spendable = BigDecimal::from(1000); let expected_bch_unspendable: BigDecimal = "0.00001".parse().unwrap(); - let (_, bch_balance) = enable_bch_with_tokens + let bch_balance = enable_bch_with_tokens .result .bch_addresses_infos - .unwrap() .into_iter() .next() + .unwrap() + .1 + .balances .unwrap(); - assert_eq!(expected_bch_spendable, bch_balance.balances.spendable); - assert_eq!(expected_bch_unspendable, bch_balance.balances.unspendable); + assert_eq!(expected_bch_spendable, bch_balance.spendable); + assert_eq!(expected_bch_unspendable, bch_balance.unspendable); - let (_, slp_balances) = enable_bch_with_tokens + let slp_balances = enable_bch_with_tokens .result .slp_addresses_infos - .unwrap() .into_iter() .next() + .unwrap() + .1 + .balances .unwrap(); let expected_slp_spendable = BigDecimal::from(1000); let expected_slp_unspendable: BigDecimal = 0.into(); - let actual_slp = slp_balances.balances.get("ADEXSLP").unwrap(); + let actual_slp = slp_balances.get("ADEXSLP").unwrap(); assert_eq!(expected_slp_spendable, actual_slp.spendable); assert_eq!(expected_slp_unspendable, actual_slp.unspendable); } @@ -145,8 +149,21 @@ fn test_enable_bch_with_tokens_v2_without_balance() { let enable_bch_with_tokens: RpcV2Response = json::from_value(enable_bch_with_tokens).unwrap(); - assert!(enable_bch_with_tokens.result.bch_addresses_infos.is_none()); - assert!(enable_bch_with_tokens.result.slp_addresses_infos.is_none()); + let (_, bch_balance) = enable_bch_with_tokens + .result + .bch_addresses_infos + .into_iter() + .next() + .unwrap(); + assert!(bch_balance.balances.is_none()); + + let (_, slp_balances) = enable_bch_with_tokens + .result + .slp_addresses_infos + .into_iter() + .next() + .unwrap(); + assert!(slp_balances.balances.is_none()); } #[test] diff --git a/mm2src/mm2_main/tests/docker_tests/solana_tests.rs b/mm2src/mm2_main/tests/docker_tests/solana_tests.rs index e46035c1b2..85e3591b7a 100644 --- a/mm2src/mm2_main/tests/docker_tests/solana_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/solana_tests.rs @@ -23,20 +23,21 @@ fn test_solana_and_spl_balance_enable_spl_v2() { let (_, solana_balance) = enable_solana_with_tokens .result .solana_addresses_infos - .unwrap() .into_iter() .next() .unwrap(); - assert!(solana_balance.balances.spendable > 0.into()); + assert!(solana_balance.balances.unwrap().spendable > 0.into()); - let (_, spl_balances) = enable_solana_with_tokens + let spl_balances = enable_solana_with_tokens .result .spl_addresses_infos - .unwrap() .into_iter() .next() + .unwrap() + .1 + .balances .unwrap(); - let usdc_spl = spl_balances.balances.get("USDC-SOL-DEVNET").unwrap(); + let usdc_spl = spl_balances.get("USDC-SOL-DEVNET").unwrap(); assert!(usdc_spl.spendable.is_zero()); let enable_spl = block_on(enable_spl(&mm, "ADEX-SOL-DEVNET")); diff --git a/mm2src/mm2_main/tests/mm2_tests/bch_and_slp_tests.rs b/mm2src/mm2_main/tests/mm2_tests/bch_and_slp_tests.rs index b059cad70a..38830e6d24 100644 --- a/mm2src/mm2_main/tests/mm2_tests/bch_and_slp_tests.rs +++ b/mm2src/mm2_main/tests/mm2_tests/bch_and_slp_tests.rs @@ -650,7 +650,6 @@ fn test_bch_and_slp_with_hd_account_id() { let (bch_addr, _) = activation_result .result .bch_addresses_infos - .unwrap() .into_iter() .exactly_one() .unwrap(); @@ -659,7 +658,6 @@ fn test_bch_and_slp_with_hd_account_id() { let (slp_addr, _) = activation_result .result .slp_addresses_infos - .unwrap() .into_iter() .exactly_one() .unwrap(); @@ -684,7 +682,6 @@ fn test_bch_and_slp_with_hd_account_id() { let (bch_addr, _) = activation_result .result .bch_addresses_infos - .unwrap() .into_iter() .exactly_one() .unwrap(); @@ -693,7 +690,6 @@ fn test_bch_and_slp_with_hd_account_id() { let (slp_addr, _) = activation_result .result .slp_addresses_infos - .unwrap() .into_iter() .exactly_one() .unwrap(); diff --git a/mm2src/mm2_main/tests/mm2_tests/eth_tests.rs b/mm2src/mm2_main/tests/mm2_tests/eth_tests.rs index d37dd9b258..04d3365dc8 100644 --- a/mm2src/mm2_main/tests/mm2_tests/eth_tests.rs +++ b/mm2src/mm2_main/tests/mm2_tests/eth_tests.rs @@ -135,6 +135,19 @@ fn test_disable_eth_coin_with_token_without_balance() { let enable_eth_with_tokens: RpcV2Response = json::from_value(enable_eth_with_tokens).unwrap(); - assert!(enable_eth_with_tokens.result.eth_addresses_infos.is_none()); - assert!(enable_eth_with_tokens.result.erc20_addresses_infos.is_none()); + let (_, eth_balance) = enable_eth_with_tokens + .result + .eth_addresses_infos + .into_iter() + .next() + .unwrap(); + assert!(eth_balance.balances.is_none()); + + let (_, erc20_balances) = enable_eth_with_tokens + .result + .erc20_addresses_infos + .into_iter() + .next() + .unwrap(); + assert!(erc20_balances.balances.is_none()); } diff --git a/mm2src/mm2_test_helpers/src/structs.rs b/mm2src/mm2_test_helpers/src/structs.rs index 875072f5c1..61ad1a706f 100644 --- a/mm2src/mm2_test_helpers/src/structs.rs +++ b/mm2src/mm2_test_helpers/src/structs.rs @@ -899,7 +899,7 @@ pub enum DerivationMethod { pub struct CoinAddressInfo { pub derivation_method: DerivationMethod, pub pubkey: String, - pub balances: Balance, + pub balances: Option, } pub type TokenBalances = HashMap; @@ -908,24 +908,24 @@ pub type TokenBalances = HashMap; #[serde(deny_unknown_fields)] pub struct EnableEthWithTokensResponse { pub current_block: u64, - pub eth_addresses_infos: Option>>, - pub erc20_addresses_infos: Option>>, + pub eth_addresses_infos: HashMap>, + pub erc20_addresses_infos: HashMap>, } #[derive(Debug, Deserialize)] #[serde(deny_unknown_fields)] pub struct EnableBchWithTokensResponse { pub current_block: u64, - pub bch_addresses_infos: Option>>, - pub slp_addresses_infos: Option>>, + pub bch_addresses_infos: HashMap>, + pub slp_addresses_infos: HashMap>, } #[derive(Debug, Deserialize)] #[serde(deny_unknown_fields)] pub struct EnableSolanaWithTokensResponse { pub current_block: u64, - pub solana_addresses_infos: Option>>, - pub spl_addresses_infos: Option>>, + pub solana_addresses_infos: HashMap>, + pub spl_addresses_infos: HashMap>, } #[derive(Debug, Deserialize)] From 445d3b65de1551956cb788e52262d630b55723ea Mon Sep 17 00:00:00 2001 From: shamardy Date: Thu, 27 Apr 2023 16:44:00 +0200 Subject: [PATCH 06/11] capture self of get_tokens_balance_list by reference using a closure to be used in the loop without cloning --- mm2src/coins/eth.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 3c924aab13..e2453a2667 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -3430,12 +3430,11 @@ impl EthCoin { } pub async fn get_tokens_balance_list(&self) -> Result, MmError> { - let selfi = self.clone(); + let coin = || self; let mut requests = Vec::new(); for (token_ticker, info) in self.get_erc_tokens_infos() { - let coin = selfi.clone(); let fut = async move { - let balance_as_u256 = coin.get_token_balance_by_address(info.token_address).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, From 5b27255c40cd207b873fde8afcd708b213b0a959 Mon Sep 17 00:00:00 2001 From: shamardy Date: Thu, 27 Apr 2023 21:10:25 +0200 Subject: [PATCH 07/11] move enable_tendermint_without_balance/enable_bch_with_tokens_without_balance to where it's used --- .../mm2_main/tests/docker_tests/slp_tests.rs | 41 ++++++++++- .../tests/mm2_tests/tendermint_tests.rs | 47 ++++++++++-- mm2src/mm2_test_helpers/src/for_tests.rs | 72 ------------------- 3 files changed, 80 insertions(+), 80 deletions(-) diff --git a/mm2src/mm2_main/tests/docker_tests/slp_tests.rs b/mm2src/mm2_main/tests/docker_tests/slp_tests.rs index d3839c4d90..e210160e64 100644 --- a/mm2src/mm2_main/tests/docker_tests/slp_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/slp_tests.rs @@ -1,13 +1,48 @@ use crate::docker_tests::docker_tests_common::*; use crate::integration_tests_common::enable_native; +use http::StatusCode; use mm2_number::BigDecimal; use mm2_test_helpers::for_tests::{assert_coin_not_found_on_balance, disable_coin, disable_coin_err, - enable_bch_with_tokens, enable_bch_with_tokens_without_balance, enable_slp, - my_balance, UtxoRpcMode}; + enable_bch_with_tokens, enable_slp, my_balance, UtxoRpcMode}; use mm2_test_helpers::structs::{EnableBchWithTokensResponse, EnableElectrumResponse, EnableSlpResponse, RpcV2Response}; -use serde_json::{self as json}; +use serde_json::{self as json, json, Value as Json}; use std::time::Duration; +async fn enable_bch_with_tokens_without_balance( + mm: &MarketMakerIt, + platform_coin: &str, + tokens: &[&str], + mode: UtxoRpcMode, + tx_history: bool, +) -> Json { + let slp_requests: Vec<_> = tokens.iter().map(|ticker| json!({ "ticker": ticker })).collect(); + + let enable = mm + .rpc(&json!({ + "userpass": mm.userpass, + "method": "enable_bch_with_tokens", + "mmrpc": "2.0", + "params": { + "ticker": platform_coin, + "allow_slp_unsafe_conf": true, + "bchd_urls": [], + "mode": mode, + "tx_history": tx_history, + "slp_tokens_requests": slp_requests, + "get_balances": false, + } + })) + .await + .unwrap(); + assert_eq!( + enable.0, + StatusCode::OK, + "'enable_bch_with_tokens' failed: {}", + enable.1 + ); + json::from_str(&enable.1).unwrap() +} + #[test] fn trade_test_with_maker_slp() { trade_base_rel(("ADEXSLP", "FORSLP")); } diff --git a/mm2src/mm2_main/tests/mm2_tests/tendermint_tests.rs b/mm2src/mm2_main/tests/mm2_tests/tendermint_tests.rs index dd5f6f9939..70905bbd49 100644 --- a/mm2src/mm2_main/tests/mm2_tests/tendermint_tests.rs +++ b/mm2src/mm2_main/tests/mm2_tests/tendermint_tests.rs @@ -1,12 +1,12 @@ use common::block_on; +use http::StatusCode; use mm2_number::BigDecimal; use mm2_test_helpers::for_tests::{atom_testnet_conf, disable_coin, disable_coin_err, enable_tendermint, - enable_tendermint_token, enable_tendermint_without_balance, - get_tendermint_my_tx_history, ibc_withdraw, iris_nimda_testnet_conf, - iris_testnet_conf, my_balance, send_raw_transaction, withdraw_v1, MarketMakerIt, - Mm2TestConf}; + enable_tendermint_token, get_tendermint_my_tx_history, ibc_withdraw, + iris_nimda_testnet_conf, iris_testnet_conf, my_balance, send_raw_transaction, + withdraw_v1, MarketMakerIt, Mm2TestConf}; use mm2_test_helpers::structs::{RpcV2Response, TendermintActivationResult, TransactionDetails}; -use serde_json::{self as json, json}; +use serde_json::{self as json, json, Value as Json}; const IRIS_TEST_SEED: &str = "iris test seed"; const ATOM_TEST_BALANCE_SEED: &str = "atom test seed"; @@ -16,6 +16,43 @@ const ATOM_TENDERMINT_RPC_URLS: &[&str] = &["https://rpc.sentry-02.theta-testnet const IRIS_TESTNET_RPC_URLS: &[&str] = &["http://34.80.202.172:26657"]; +async fn enable_tendermint_without_balance( + mm: &MarketMakerIt, + coin: &str, + ibc_assets: &[&str], + rpc_urls: &[&str], + tx_history: bool, +) -> Json { + let ibc_requests: Vec<_> = ibc_assets.iter().map(|ticker| json!({ "ticker": ticker })).collect(); + + let request = json!({ + "userpass": mm.userpass, + "method": "enable_tendermint_with_assets", + "mmrpc": "2.0", + "params": { + "ticker": coin, + "tokens_params": ibc_requests, + "rpc_urls": rpc_urls, + "tx_history": tx_history, + "get_balances": false + } + }); + println!( + "enable_tendermint_with_assets request {}", + json::to_string(&request).unwrap() + ); + + let request = mm.rpc(&request).await.unwrap(); + assert_eq!( + request.0, + StatusCode::OK, + "'enable_tendermint_with_assets' failed: {}", + request.1 + ); + println!("enable_tendermint_with_assets response {}", request.1); + json::from_str(&request.1).unwrap() +} + #[test] fn test_tendermint_activation_and_balance() { let coins = json!([atom_testnet_conf()]); diff --git a/mm2src/mm2_test_helpers/src/for_tests.rs b/mm2src/mm2_test_helpers/src/for_tests.rs index 96a3434e1c..68c3ba4eaf 100644 --- a/mm2src/mm2_test_helpers/src/for_tests.rs +++ b/mm2src/mm2_test_helpers/src/for_tests.rs @@ -1736,41 +1736,6 @@ pub async fn enable_bch_with_tokens( json::from_str(&enable.1).unwrap() } -pub async fn enable_bch_with_tokens_without_balance( - mm: &MarketMakerIt, - platform_coin: &str, - tokens: &[&str], - mode: UtxoRpcMode, - tx_history: bool, -) -> Json { - let slp_requests: Vec<_> = tokens.iter().map(|ticker| json!({ "ticker": ticker })).collect(); - - let enable = mm - .rpc(&json!({ - "userpass": mm.userpass, - "method": "enable_bch_with_tokens", - "mmrpc": "2.0", - "params": { - "ticker": platform_coin, - "allow_slp_unsafe_conf": true, - "bchd_urls": [], - "mode": mode, - "tx_history": tx_history, - "slp_tokens_requests": slp_requests, - "get_balances": false, - } - })) - .await - .unwrap(); - assert_eq!( - enable.0, - StatusCode::OK, - "'enable_bch_with_tokens' failed: {}", - enable.1 - ); - json::from_str(&enable.1).unwrap() -} - pub async fn enable_solana_with_tokens( mm: &MarketMakerIt, platform_coin: &str, @@ -2546,43 +2511,6 @@ pub async fn enable_tendermint( json::from_str(&request.1).unwrap() } -pub async fn enable_tendermint_without_balance( - mm: &MarketMakerIt, - coin: &str, - ibc_assets: &[&str], - rpc_urls: &[&str], - tx_history: bool, -) -> Json { - let ibc_requests: Vec<_> = ibc_assets.iter().map(|ticker| json!({ "ticker": ticker })).collect(); - - let request = json!({ - "userpass": mm.userpass, - "method": "enable_tendermint_with_assets", - "mmrpc": "2.0", - "params": { - "ticker": coin, - "tokens_params": ibc_requests, - "rpc_urls": rpc_urls, - "tx_history": tx_history, - "get_balances": false - } - }); - println!( - "enable_tendermint_with_assets request {}", - json::to_string(&request).unwrap() - ); - - let request = mm.rpc(&request).await.unwrap(); - assert_eq!( - request.0, - StatusCode::OK, - "'enable_tendermint_with_assets' failed: {}", - request.1 - ); - println!("enable_tendermint_with_assets response {}", request.1); - json::from_str(&request.1).unwrap() -} - pub async fn get_tendermint_my_tx_history(mm: &MarketMakerIt, coin: &str, limit: usize, page_number: usize) -> Json { let request = json!({ "userpass": mm.userpass, From 914e9568f31387c53f4a79a932bf94e23794cc2f Mon Sep 17 00:00:00 2001 From: shamardy Date: Fri, 28 Apr 2023 13:03:48 +0300 Subject: [PATCH 08/11] make get_tokens_balance_list code better --- 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 e2453a2667..2944315728 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -3436,11 +3436,8 @@ impl EthCoin { let fut = async move { 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, - unspendable: BigDecimal::from(0), - }; - Ok::<_, MmError>((token_ticker.clone(), balance)) + let balance = CoinBalance::new(balance_as_big_decimal); + Ok((token_ticker, balance)) }; requests.push(fut); } From 8dfbed1700213ec78b4d9df1a16b943eb868f698 Mon Sep 17 00:00:00 2001 From: shamardy Date: Fri, 28 Apr 2023 18:48:41 +0300 Subject: [PATCH 09/11] add enhance enable with tokens methods changelog --- CHANGELOG.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a563426fd..65003cfcc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,14 +5,17 @@ **Enhancements/Fixes:** - cosmos/iris ethermint account compatibility implemented [#1765](https://github.com/KomodoPlatform/atomicDEX-API/pull/1765) - p2p stack is improved [#1755](https://github.com/KomodoPlatform/atomicDEX-API/pull/1755) -- - Validate topics if they are mixed or not. -- - Do early return if the message data is not valid (since no point to iterate over and over on the invalid message) -- - Break the loop right after processing any of `SWAP_PREFIX`, `WATCHER_PREFIX`, `TX_HELPER_PREFIX` topic. + - Validate topics if they are mixed or not. + - Do early return if the message data is not valid (since no point to iterate over and over on the invalid message) + - Break the loop right after processing any of `SWAP_PREFIX`, `WATCHER_PREFIX`, `TX_HELPER_PREFIX` topic. - An issue was fixed where we don't have to wait for all EVM nodes to sync the latest account nonce [#1757](https://github.com/KomodoPlatform/atomicDEX-API/pull/1757) - optimized dev and release compilation profiles and removed ci [#1759](https://github.com/KomodoPlatform/atomicDEX-API/pull/1759) - fix receiver trade fee for cosmos swaps [#1767](https://github.com/KomodoPlatform/atomicDEX-API/pull/1767) - All features were enabled to be checked under x86-64 code lint CI step with `--all-features` option [#1760](https://github.com/KomodoPlatform/atomicDEX-API/pull/1760) - use OS generated secrets for cryptographically secure randomness in `maker_swap` and `tendermint_coin::get_sender_trade_fee_for_denom` [#1753](https://github.com/KomodoPlatform/atomicDEX-API/pull/1753) +- Some enhancements were done for `enable_bch_with_tokens`,`enable_eth_with_tokens`,`enable_tendermint_with_assets` RPCs in [#1762](https://github.com/KomodoPlatform/atomicDEX-API/pull/1762) + - A new parameter `get_balances` was added to the above methods requests, when this parameter is set to `false`, balances will not be returned in the response. The default value for this parameter is `true` to ensure backward compatibility. + - Token balances requests are now performed concurrently for the above methods. ## v1.0.2-beta - 2023-04-11 From 644433600e9da33e237cbacfd03b63b24c71a15c Mon Sep 17 00:00:00 2001 From: shamardy Date: Mon, 1 May 2023 22:25:14 +0300 Subject: [PATCH 10/11] return token tickers if get_balances is false --- mm2src/coins/tendermint/tendermint_coin.rs | 2 +- .../src/bch_with_tokens_activation.rs | 68 ++++++++++-------- .../src/eth_with_token_activation.rs | 71 +++++++++++-------- mm2src/coins_activation/src/prelude.rs | 4 +- .../src/solana_with_tokens_activation.rs | 71 +++++++++++-------- .../src/tendermint_with_assets_activation.rs | 6 +- .../mm2_main/tests/docker_tests/slp_tests.rs | 3 + mm2src/mm2_main/tests/mm2_tests/eth_tests.rs | 7 ++ .../mm2_tests/tendermint_ibc_asset_tests.rs | 32 ++++++++- .../tests/mm2_tests/tendermint_tests.rs | 48 ++----------- mm2src/mm2_test_helpers/src/for_tests.rs | 37 ++++++++++ mm2src/mm2_test_helpers/src/structs.rs | 2 + 12 files changed, 214 insertions(+), 137 deletions(-) diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 106e2a9c3a..f8efaad1cd 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -225,7 +225,7 @@ pub struct TendermintCoinImpl { pub(super) denom: Denom, chain_id: ChainId, gas_price: Option, - pub(crate) tokens_info: PaMutex>, + pub tokens_info: PaMutex>, /// This spawner is used to spawn coin's related futures that should be aborted on coin deactivation /// or on [`MmArc::stop`]. pub(super) abortable_system: AbortableQueue, diff --git a/mm2src/coins_activation/src/bch_with_tokens_activation.rs b/mm2src/coins_activation/src/bch_with_tokens_activation.rs index 37f03f434d..e70b0901c1 100644 --- a/mm2src/coins_activation/src/bch_with_tokens_activation.rs +++ b/mm2src/coins_activation/src/bch_with_tokens_activation.rs @@ -11,15 +11,15 @@ use coins::utxo::UtxoCommonOps; use coins::{CoinBalance, CoinProtocol, MarketCoinOps, MmCoin, PrivKeyBuildPolicy, PrivKeyPolicyNotAllowed, UnexpectedDerivationMethod}; use common::executor::{AbortSettings, SpawnAbortable}; -use common::true_f; use common::Future01CompatExt; +use common::{drop_mutability, true_f}; use crypto::CryptoCtxError; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use mm2_number::BigDecimal; use serde_derive::{Deserialize, Serialize}; use serde_json::Value as Json; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::str::FromStr; impl From for InitTokensAsMmCoinsError { @@ -259,40 +259,52 @@ impl PlatformWithTokensActivationOps for BchCoin { .map_to_mm(BchWithTokensActivationError::Internal)?; let pubkey = self.my_public_key()?.to_string(); - let (bch_balance, token_balances) = if activation_request.get_balances { - let bch_unspents = self.bch_unspents_for_display(my_address).await?; - let token_balances = self - .get_slp_tokens_infos() - .iter() - .map(|(token_ticker, info)| { - let token_balance = bch_unspents.slp_token_balance(&info.token_id, info.decimals); - (token_ticker.clone(), token_balance) - }) - .collect(); - ( - Some(bch_unspents.platform_balance(self.decimals())), - Some(token_balances), - ) - } else { - (None, None) + let mut bch_address_info = CoinAddressInfo { + derivation_method: DerivationMethod::Iguana, + pubkey: pubkey.clone(), + balances: None, + tickers: None, }; - let bch_addresses_infos = HashMap::from([(my_address.to_string(), CoinAddressInfo { + let mut slp_address_info = CoinAddressInfo { derivation_method: DerivationMethod::Iguana, pubkey: pubkey.clone(), - balances: bch_balance, - })]); + balances: None, + tickers: None, + }; - let slp_addresses_infos = HashMap::from([(my_slp_address, CoinAddressInfo { - derivation_method: DerivationMethod::Iguana, - pubkey, - balances: token_balances, - })]); + if !activation_request.get_balances { + drop_mutability!(bch_address_info); + let tickers: HashSet<_> = self.get_slp_tokens_infos().keys().cloned().collect(); + slp_address_info.tickers = Some(tickers); + drop_mutability!(slp_address_info); + + return Ok(BchWithTokensActivationResult { + current_block, + bch_addresses_infos: HashMap::from([(my_address.to_string(), bch_address_info)]), + slp_addresses_infos: HashMap::from([(my_slp_address, slp_address_info)]), + }); + } + + let bch_unspents = self.bch_unspents_for_display(my_address).await?; + bch_address_info.balances = Some(bch_unspents.platform_balance(self.decimals())); + drop_mutability!(bch_address_info); + + let token_balances: HashMap<_, _> = self + .get_slp_tokens_infos() + .iter() + .map(|(token_ticker, info)| { + let token_balance = bch_unspents.slp_token_balance(&info.token_id, info.decimals); + (token_ticker.clone(), token_balance) + }) + .collect(); + slp_address_info.balances = Some(token_balances); + drop_mutability!(slp_address_info); Ok(BchWithTokensActivationResult { current_block, - bch_addresses_infos, - slp_addresses_infos, + bch_addresses_infos: HashMap::from([(my_address.to_string(), bch_address_info)]), + slp_addresses_infos: HashMap::from([(my_slp_address, slp_address_info)]), }) } diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 9f37d89ed0..0f5774f7e2 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -11,8 +11,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::true_f; use common::Future01CompatExt; +use common::{drop_mutability, true_f}; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; #[cfg(target_arch = "wasm32")] @@ -20,7 +20,7 @@ use mm2_metamask::MetamaskRpcError; use mm2_number::BigDecimal; use serde::{Deserialize, Serialize}; use serde_json::Value as Json; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; impl From for EnablePlatformCoinWithTokensError { fn from(err: EthActivationV2Error) -> Self { @@ -214,43 +214,52 @@ impl PlatformWithTokensActivationOps for EthCoin { let my_address = self.my_address()?; let pubkey = self.get_public_key()?; - let eth_balance = if activation_request.get_balances { - Some( - self.my_balance() - .compat() - .await - .map_err(|e| EthActivationV2Error::CouldNotFetchBalance(e.to_string()))?, - ) - } else { - None - }; - - let token_balances = if activation_request.get_balances { - Some( - self.get_tokens_balance_list() - .await - .map_err(|e| EthActivationV2Error::CouldNotFetchBalance(e.to_string()))?, - ) - } else { - None - }; - - let eth_addresses_infos = HashMap::from([(my_address.clone(), CoinAddressInfo { + let mut eth_address_info = CoinAddressInfo { derivation_method: DerivationMethod::Iguana, pubkey: pubkey.clone(), - balances: eth_balance, - })]); + balances: None, + tickers: None, + }; - let erc20_addresses_infos = HashMap::from([(my_address, CoinAddressInfo { + let mut erc20_address_info = CoinAddressInfo { derivation_method: DerivationMethod::Iguana, pubkey, - balances: token_balances, - })]); + balances: None, + tickers: None, + }; + + if !activation_request.get_balances { + drop_mutability!(eth_address_info); + let tickers: HashSet<_> = self.get_erc_tokens_infos().into_keys().collect(); + erc20_address_info.tickers = Some(tickers); + drop_mutability!(erc20_address_info); + + return Ok(EthWithTokensActivationResult { + current_block, + eth_addresses_infos: HashMap::from([(my_address.clone(), eth_address_info)]), + erc20_addresses_infos: HashMap::from([(my_address, erc20_address_info)]), + }); + } + + let eth_balance = self + .my_balance() + .compat() + .await + .map_err(|e| EthActivationV2Error::CouldNotFetchBalance(e.to_string()))?; + eth_address_info.balances = Some(eth_balance); + drop_mutability!(eth_address_info); + + let token_balances = self + .get_tokens_balance_list() + .await + .map_err(|e| EthActivationV2Error::CouldNotFetchBalance(e.to_string()))?; + erc20_address_info.balances = Some(token_balances); + drop_mutability!(erc20_address_info); Ok(EthWithTokensActivationResult { current_block, - eth_addresses_infos, - erc20_addresses_infos, + eth_addresses_infos: HashMap::from([(my_address.clone(), eth_address_info)]), + erc20_addresses_infos: HashMap::from([(my_address, erc20_address_info)]), }) } diff --git a/mm2src/coins_activation/src/prelude.rs b/mm2src/coins_activation/src/prelude.rs index f110e8ead6..2126d8bc06 100644 --- a/mm2src/coins_activation/src/prelude.rs +++ b/mm2src/coins_activation/src/prelude.rs @@ -7,7 +7,7 @@ use mm2_err_handle::prelude::*; use mm2_number::BigDecimal; use serde_derive::Serialize; use serde_json::{self as json, Value as Json}; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; pub trait CurrentBlock { fn current_block(&self) -> u64; @@ -46,6 +46,8 @@ pub struct CoinAddressInfo { pub(crate) pubkey: String, #[serde(skip_serializing_if = "Option::is_none")] pub(crate) balances: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) tickers: Option>, } pub type TokenBalances = HashMap; diff --git a/mm2src/coins_activation/src/solana_with_tokens_activation.rs b/mm2src/coins_activation/src/solana_with_tokens_activation.rs index 3ad87ecaba..835eb37fd8 100644 --- a/mm2src/coins_activation/src/solana_with_tokens_activation.rs +++ b/mm2src/coins_activation/src/solana_with_tokens_activation.rs @@ -12,8 +12,8 @@ use coins::solana::solana_coin_with_policy; use coins::solana::spl::{SplProtocolConf, SplTokenCreationError}; use coins::{BalanceError, CoinBalance, CoinProtocol, MarketCoinOps, PrivKeyBuildPolicy, SolanaActivationParams, SolanaCoin, SplToken}; -use common::true_f; use common::Future01CompatExt; +use common::{drop_mutability, true_f}; use crypto::CryptoCtxError; use futures::future::try_join_all; use mm2_core::mm_ctx::MmArc; @@ -221,44 +221,53 @@ impl PlatformWithTokensActivationOps for SolanaCoin { let my_address = self.my_address()?; - let solana_balance = if activation_request.get_balances { - Some( - self.my_balance() - .compat() - .await - .map_err(|e| Self::ActivationError::GetBalanceError(e.into_inner()))?, - ) - } else { - None - }; - - let token_balances = if activation_request.get_balances { - let (token_tickers, requests): (Vec<_>, Vec<_>) = self - .get_spl_tokens_infos() - .into_iter() - .map(|(ticker, info)| (ticker, self.my_balance_spl(info))) - .unzip(); - Some(token_tickers.into_iter().zip(try_join_all(requests).await?).collect()) - } else { - None + let mut solana_address_info = CoinAddressInfo { + derivation_method: DerivationMethod::Iguana, + pubkey: my_address.clone(), + balances: None, + tickers: None, }; - let solana_addresses_infos = HashMap::from([(my_address.clone(), CoinAddressInfo { + let mut spl_address_info = CoinAddressInfo { derivation_method: DerivationMethod::Iguana, pubkey: my_address.clone(), - balances: solana_balance, - })]); + balances: None, + tickers: None, + }; - let spl_addresses_infos = HashMap::from([(my_address.clone(), CoinAddressInfo { - derivation_method: DerivationMethod::Iguana, - pubkey: my_address, - balances: token_balances, - })]); + if !activation_request.get_balances { + drop_mutability!(solana_address_info); + let tickers = self.get_spl_tokens_infos().into_keys().collect(); + spl_address_info.tickers = Some(tickers); + drop_mutability!(spl_address_info); + + return Ok(SolanaWithTokensActivationResult { + current_block, + solana_addresses_infos: HashMap::from([(my_address.clone(), solana_address_info)]), + spl_addresses_infos: HashMap::from([(my_address, spl_address_info)]), + }); + } + + let solana_balance = self + .my_balance() + .compat() + .await + .map_err(|e| Self::ActivationError::GetBalanceError(e.into_inner()))?; + solana_address_info.balances = Some(solana_balance); + drop_mutability!(solana_address_info); + + let (token_tickers, requests): (Vec<_>, Vec<_>) = self + .get_spl_tokens_infos() + .into_iter() + .map(|(ticker, info)| (ticker, self.my_balance_spl(info))) + .unzip(); + spl_address_info.balances = Some(token_tickers.into_iter().zip(try_join_all(requests).await?).collect()); + drop_mutability!(spl_address_info); Ok(SolanaWithTokensActivationResult { current_block, - solana_addresses_infos, - spl_addresses_infos, + solana_addresses_infos: HashMap::from([(my_address.clone(), solana_address_info)]), + spl_addresses_infos: HashMap::from([(my_address, spl_address_info)]), }) } diff --git a/mm2src/coins_activation/src/tendermint_with_assets_activation.rs b/mm2src/coins_activation/src/tendermint_with_assets_activation.rs index 39ccbe8349..7c9d663540 100644 --- a/mm2src/coins_activation/src/tendermint_with_assets_activation.rs +++ b/mm2src/coins_activation/src/tendermint_with_assets_activation.rs @@ -17,7 +17,7 @@ use mm2_err_handle::prelude::*; use mm2_number::BigDecimal; use serde::{Deserialize, Serialize}; use serde_json::Value as Json; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; impl TokenOf for TendermintToken { type PlatformCoin = TendermintCoin; @@ -131,6 +131,8 @@ pub struct TendermintActivationResult { balance: Option, #[serde(skip_serializing_if = "Option::is_none")] tokens_balances: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + tokens_tickers: Option>, } impl CurrentBlock for TendermintActivationResult { @@ -207,6 +209,7 @@ impl PlatformWithTokensActivationOps for TendermintCoin { current_block, balance: None, tokens_balances: None, + tokens_tickers: Some(self.tokens_info.lock().clone().into_keys().collect()), }); } @@ -235,6 +238,7 @@ impl PlatformWithTokensActivationOps for TendermintCoin { .collect(), ), ticker: self.ticker().to_owned(), + tokens_tickers: None, }) } diff --git a/mm2src/mm2_main/tests/docker_tests/slp_tests.rs b/mm2src/mm2_main/tests/docker_tests/slp_tests.rs index e210160e64..61cd95bc0a 100644 --- a/mm2src/mm2_main/tests/docker_tests/slp_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/slp_tests.rs @@ -6,6 +6,7 @@ use mm2_test_helpers::for_tests::{assert_coin_not_found_on_balance, disable_coin enable_bch_with_tokens, enable_slp, my_balance, UtxoRpcMode}; use mm2_test_helpers::structs::{EnableBchWithTokensResponse, EnableElectrumResponse, EnableSlpResponse, RpcV2Response}; use serde_json::{self as json, json, Value as Json}; +use std::collections::HashSet; use std::time::Duration; async fn enable_bch_with_tokens_without_balance( @@ -191,6 +192,7 @@ fn test_enable_bch_with_tokens_v2_without_balance() { .next() .unwrap(); assert!(bch_balance.balances.is_none()); + assert!(bch_balance.tickers.is_none()); let (_, slp_balances) = enable_bch_with_tokens .result @@ -199,6 +201,7 @@ fn test_enable_bch_with_tokens_v2_without_balance() { .next() .unwrap(); assert!(slp_balances.balances.is_none()); + assert_eq!(slp_balances.tickers.unwrap(), HashSet::from(["ADEXSLP".to_string()])); } #[test] diff --git a/mm2src/mm2_main/tests/mm2_tests/eth_tests.rs b/mm2src/mm2_main/tests/mm2_tests/eth_tests.rs index 04d3365dc8..fb96a1e29e 100644 --- a/mm2src/mm2_main/tests/mm2_tests/eth_tests.rs +++ b/mm2src/mm2_main/tests/mm2_tests/eth_tests.rs @@ -4,6 +4,8 @@ use mm2_test_helpers::for_tests::{disable_coin, disable_coin_err, get_passphrase ETH_DEV_NODES}; use mm2_test_helpers::structs::{EnableEthWithTokensResponse, RpcV2Response}; use serde_json::{self as json, json, Value as Json}; +use std::collections::HashSet; +use std::iter::FromIterator; use std::str::FromStr; #[cfg(not(target_arch = "wasm32"))] @@ -142,6 +144,7 @@ fn test_disable_eth_coin_with_token_without_balance() { .next() .unwrap(); assert!(eth_balance.balances.is_none()); + assert!(eth_balance.tickers.is_none()); let (_, erc20_balances) = enable_eth_with_tokens .result @@ -150,4 +153,8 @@ fn test_disable_eth_coin_with_token_without_balance() { .next() .unwrap(); assert!(erc20_balances.balances.is_none()); + assert_eq!( + erc20_balances.tickers.unwrap(), + HashSet::from_iter(vec!["JST".to_string()]) + ); } diff --git a/mm2src/mm2_main/tests/mm2_tests/tendermint_ibc_asset_tests.rs b/mm2src/mm2_main/tests/mm2_tests/tendermint_ibc_asset_tests.rs index 6e150f25f5..4cd0712aad 100644 --- a/mm2src/mm2_main/tests/mm2_tests/tendermint_ibc_asset_tests.rs +++ b/mm2src/mm2_main/tests/mm2_tests/tendermint_ibc_asset_tests.rs @@ -1,10 +1,13 @@ use common::block_on; use mm2_number::BigDecimal; -use mm2_test_helpers::for_tests::{enable_tendermint, iris_testnet_conf, my_balance, orderbook, orderbook_v2, - set_price, usdc_ibc_iris_testnet_conf, MarketMakerIt, Mm2TestConf}; +use mm2_test_helpers::for_tests::{enable_tendermint, enable_tendermint_without_balance, iris_testnet_conf, my_balance, + orderbook, orderbook_v2, set_price, usdc_ibc_iris_testnet_conf, MarketMakerIt, + Mm2TestConf}; use mm2_test_helpers::structs::{OrderbookAddress, OrderbookResponse, OrderbookV2Response, RpcV2Response, TendermintActivationResult}; use serde_json::{self, json}; +use std::collections::HashSet; +use std::iter::FromIterator; const IRIS_TESTNET_RPCS: &[&str] = &["http://34.80.202.172:26657"]; const IRIS_TICKER: &str = "IRIS-TEST"; @@ -68,3 +71,28 @@ fn test_iris_with_usdc_activation_balance_orderbook() { let first_bid = orderbook_v2.result.bids.first().unwrap(); assert_eq!(first_bid.entry.address, expected_address); } + +#[test] +fn test_iris_with_usdc_activation_without_balance() { + let coins = json!([iris_testnet_conf(), usdc_ibc_iris_testnet_conf()]); + + let conf = Mm2TestConf::seednode(IRIS_USDC_ACTIVATION_SEED, &coins); + let mm = MarketMakerIt::start(conf.conf, conf.rpc_password, None).unwrap(); + + let activation_result = block_on(enable_tendermint_without_balance( + &mm, + IRIS_TICKER, + &[USDC_IBC_TICKER], + IRIS_TESTNET_RPCS, + false, + )); + + let result: RpcV2Response = serde_json::from_value(activation_result).unwrap(); + + assert!(result.result.balance.is_none()); + assert!(result.result.tokens_balances.is_none()); + assert_eq!( + result.result.tokens_tickers.unwrap(), + HashSet::from_iter(vec![USDC_IBC_TICKER.to_string()]) + ); +} diff --git a/mm2src/mm2_main/tests/mm2_tests/tendermint_tests.rs b/mm2src/mm2_main/tests/mm2_tests/tendermint_tests.rs index 70905bbd49..24218546e0 100644 --- a/mm2src/mm2_main/tests/mm2_tests/tendermint_tests.rs +++ b/mm2src/mm2_main/tests/mm2_tests/tendermint_tests.rs @@ -1,12 +1,12 @@ use common::block_on; -use http::StatusCode; use mm2_number::BigDecimal; use mm2_test_helpers::for_tests::{atom_testnet_conf, disable_coin, disable_coin_err, enable_tendermint, - enable_tendermint_token, get_tendermint_my_tx_history, ibc_withdraw, - iris_nimda_testnet_conf, iris_testnet_conf, my_balance, send_raw_transaction, - withdraw_v1, MarketMakerIt, Mm2TestConf}; + enable_tendermint_token, enable_tendermint_without_balance, + get_tendermint_my_tx_history, ibc_withdraw, iris_nimda_testnet_conf, + iris_testnet_conf, my_balance, send_raw_transaction, withdraw_v1, MarketMakerIt, + Mm2TestConf}; use mm2_test_helpers::structs::{RpcV2Response, TendermintActivationResult, TransactionDetails}; -use serde_json::{self as json, json, Value as Json}; +use serde_json::{self as json, json}; const IRIS_TEST_SEED: &str = "iris test seed"; const ATOM_TEST_BALANCE_SEED: &str = "atom test seed"; @@ -16,43 +16,6 @@ const ATOM_TENDERMINT_RPC_URLS: &[&str] = &["https://rpc.sentry-02.theta-testnet const IRIS_TESTNET_RPC_URLS: &[&str] = &["http://34.80.202.172:26657"]; -async fn enable_tendermint_without_balance( - mm: &MarketMakerIt, - coin: &str, - ibc_assets: &[&str], - rpc_urls: &[&str], - tx_history: bool, -) -> Json { - let ibc_requests: Vec<_> = ibc_assets.iter().map(|ticker| json!({ "ticker": ticker })).collect(); - - let request = json!({ - "userpass": mm.userpass, - "method": "enable_tendermint_with_assets", - "mmrpc": "2.0", - "params": { - "ticker": coin, - "tokens_params": ibc_requests, - "rpc_urls": rpc_urls, - "tx_history": tx_history, - "get_balances": false - } - }); - println!( - "enable_tendermint_with_assets request {}", - json::to_string(&request).unwrap() - ); - - let request = mm.rpc(&request).await.unwrap(); - assert_eq!( - request.0, - StatusCode::OK, - "'enable_tendermint_with_assets' failed: {}", - request.1 - ); - println!("enable_tendermint_with_assets response {}", request.1); - json::from_str(&request.1).unwrap() -} - #[test] fn test_tendermint_activation_and_balance() { let coins = json!([atom_testnet_conf()]); @@ -100,6 +63,7 @@ fn test_tendermint_activation_without_balance() { assert!(result.result.balance.is_none()); assert!(result.result.tokens_balances.is_none()); + assert!(result.result.tokens_tickers.unwrap().is_empty()); } #[test] diff --git a/mm2src/mm2_test_helpers/src/for_tests.rs b/mm2src/mm2_test_helpers/src/for_tests.rs index 9dbe21145c..30d16ee98a 100644 --- a/mm2src/mm2_test_helpers/src/for_tests.rs +++ b/mm2src/mm2_test_helpers/src/for_tests.rs @@ -2511,6 +2511,43 @@ pub async fn enable_tendermint( json::from_str(&request.1).unwrap() } +pub async fn enable_tendermint_without_balance( + mm: &MarketMakerIt, + coin: &str, + ibc_assets: &[&str], + rpc_urls: &[&str], + tx_history: bool, +) -> Json { + let ibc_requests: Vec<_> = ibc_assets.iter().map(|ticker| json!({ "ticker": ticker })).collect(); + + let request = json!({ + "userpass": mm.userpass, + "method": "enable_tendermint_with_assets", + "mmrpc": "2.0", + "params": { + "ticker": coin, + "tokens_params": ibc_requests, + "rpc_urls": rpc_urls, + "tx_history": tx_history, + "get_balances": false + } + }); + println!( + "enable_tendermint_with_assets request {}", + serde_json::to_string(&request).unwrap() + ); + + let request = mm.rpc(&request).await.unwrap(); + assert_eq!( + request.0, + StatusCode::OK, + "'enable_tendermint_with_assets' failed: {}", + request.1 + ); + println!("enable_tendermint_with_assets response {}", request.1); + serde_json::from_str(&request.1).unwrap() +} + pub async fn get_tendermint_my_tx_history(mm: &MarketMakerIt, coin: &str, limit: usize, page_number: usize) -> Json { let request = json!({ "userpass": mm.userpass, diff --git a/mm2src/mm2_test_helpers/src/structs.rs b/mm2src/mm2_test_helpers/src/structs.rs index 61ad1a706f..2c18b09276 100644 --- a/mm2src/mm2_test_helpers/src/structs.rs +++ b/mm2src/mm2_test_helpers/src/structs.rs @@ -900,6 +900,7 @@ pub struct CoinAddressInfo { pub derivation_method: DerivationMethod, pub pubkey: String, pub balances: Option, + pub tickers: Option>, } pub type TokenBalances = HashMap; @@ -1104,6 +1105,7 @@ pub struct TendermintActivationResult { pub balance: Option, pub tokens_balances: Option>, pub ticker: String, + pub tokens_tickers: Option>, } #[derive(Debug, Deserialize)] From c308987c818bd541b9de6234125f4806f26bdfb2 Mon Sep 17 00:00:00 2001 From: shamardy Date: Tue, 2 May 2023 14:16:19 +0300 Subject: [PATCH 11/11] update CHANGELOG.md --- CHANGELOG.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65003cfcc1..26e6c1e600 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## v1.0.4-beta - 2023-05-12 + +**Features:** + +**Enhancements/Fixes:** +- Some enhancements were done for `enable_bch_with_tokens`,`enable_eth_with_tokens`,`enable_tendermint_with_assets` RPCs in [#1762](https://github.com/KomodoPlatform/atomicDEX-API/pull/1762) + - A new parameter `get_balances` was added to the above methods requests, when this parameter is set to `false`, balances will not be returned in the response. The default value for this parameter is `true` to ensure backward compatibility. + - Token balances requests are now performed concurrently for the above methods. + + ## v1.0.3-beta - 2023-04-28 **Features:** @@ -13,9 +23,6 @@ - fix receiver trade fee for cosmos swaps [#1767](https://github.com/KomodoPlatform/atomicDEX-API/pull/1767) - All features were enabled to be checked under x86-64 code lint CI step with `--all-features` option [#1760](https://github.com/KomodoPlatform/atomicDEX-API/pull/1760) - use OS generated secrets for cryptographically secure randomness in `maker_swap` and `tendermint_coin::get_sender_trade_fee_for_denom` [#1753](https://github.com/KomodoPlatform/atomicDEX-API/pull/1753) -- Some enhancements were done for `enable_bch_with_tokens`,`enable_eth_with_tokens`,`enable_tendermint_with_assets` RPCs in [#1762](https://github.com/KomodoPlatform/atomicDEX-API/pull/1762) - - A new parameter `get_balances` was added to the above methods requests, when this parameter is set to `false`, balances will not be returned in the response. The default value for this parameter is `true` to ensure backward compatibility. - - Token balances requests are now performed concurrently for the above methods. ## v1.0.2-beta - 2023-04-11