Skip to content

Commit

Permalink
make balance reponse fields optional, early return on get_balances ch…
Browse files Browse the repository at this point in the history
…eck, integration tests for get_balances
  • Loading branch information
shamardy committed Apr 25, 2023
1 parent 4bede30 commit 150d928
Show file tree
Hide file tree
Showing 12 changed files with 374 additions and 156 deletions.
76 changes: 40 additions & 36 deletions mm2src/coins_activation/src/bch_with_tokens_activation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,17 +147,19 @@ impl TryFromCoinProtocol for BchProtocolInfo {
#[derive(Debug, Serialize)]
pub struct BchWithTokensActivationResult {
current_block: u64,
bch_addresses_infos: HashMap<String, CoinAddressInfo<CoinBalance>>,
slp_addresses_infos: HashMap<String, CoinAddressInfo<TokenBalances>>,
#[serde(skip_serializing_if = "Option::is_none")]
bch_addresses_infos: Option<HashMap<String, CoinAddressInfo<CoinBalance>>>,
#[serde(skip_serializing_if = "Option::is_none")]
slp_addresses_infos: Option<HashMap<String, CoinAddressInfo<TokenBalances>>>,
}

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<BigDecimal> {
self.bch_addresses_infos.as_ref().map(|infos| {
infos.iter().fold(BigDecimal::from(0), |total, (_, addr_info)| {
&total + &addr_info.balances.get_total()
})
})
}
}

Expand Down Expand Up @@ -249,47 +251,49 @@ impl PlatformWithTokensActivationOps for BchCoin {
&self,
activation_request: &Self::ActivationRequest,
) -> Result<BchWithTokensActivationResult, MmError<BchWithTokensActivationError>> {
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 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(
Expand Down
83 changes: 43 additions & 40 deletions mm2src/coins_activation/src/eth_with_token_activation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,17 +147,19 @@ impl RegisterTokenInfo<EthCoin> for EthCoin {
#[derive(Serialize)]
pub struct EthWithTokensActivationResult {
current_block: u64,
eth_addresses_infos: HashMap<String, CoinAddressInfo<CoinBalance>>,
erc20_addresses_infos: HashMap<String, CoinAddressInfo<TokenBalances>>,
#[serde(skip_serializing_if = "Option::is_none")]
eth_addresses_infos: Option<HashMap<String, CoinAddressInfo<CoinBalance>>>,
#[serde(skip_serializing_if = "Option::is_none")]
erc20_addresses_infos: Option<HashMap<String, CoinAddressInfo<TokenBalances>>>,
}

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<BigDecimal> {
self.eth_addresses_infos.as_ref().map(|infos| {
infos.iter().fold(BigDecimal::from(0), |total, (_, addr_info)| {
&total + &addr_info.balances.get_total()
})
})
}
}

Expand Down Expand Up @@ -205,50 +207,51 @@ impl PlatformWithTokensActivationOps for EthCoin {
&self,
activation_request: &Self::ActivationRequest,
) -> Result<EthWithTokensActivationResult, MmError<EthActivationV2Error>> {
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(
Expand Down
22 changes: 16 additions & 6 deletions mm2src/coins_activation/src/platform_coin_with_tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ where
}

pub trait GetPlatformBalance {
fn get_platform_balance(&self) -> BigDecimal;
fn get_platform_balance(&self) -> Option<BigDecimal>;
}

#[async_trait]
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -277,6 +279,7 @@ impl HttpStatusCode for EnablePlatformCoinWithTokensError {
| EnablePlatformCoinWithTokensError::TokenConfigIsNotFound(_)
| EnablePlatformCoinWithTokensError::UnexpectedPlatformProtocol { .. }
| EnablePlatformCoinWithTokensError::InvalidPayload { .. }
| EnablePlatformCoinWithTokensError::ActivationRequestError(_)
| EnablePlatformCoinWithTokensError::AtLeastOneNodeRequired(_)
| EnablePlatformCoinWithTokensError::UnexpectedTokenProtocol { .. } => StatusCode::BAD_REQUEST,
}
Expand Down Expand Up @@ -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();
Expand Down
80 changes: 42 additions & 38 deletions mm2src/coins_activation/src/solana_with_tokens_activation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,14 @@ impl TxHistory for SolanaWithTokensActivationRequest {
#[derive(Debug, Serialize)]
pub struct SolanaWithTokensActivationResult {
current_block: u64,
solana_addresses_infos: HashMap<String, CoinAddressInfo<CoinBalance>>,
spl_addresses_infos: HashMap<String, CoinAddressInfo<TokenBalances>>,
#[serde(skip_serializing_if = "Option::is_none")]
solana_addresses_infos: Option<HashMap<String, CoinAddressInfo<CoinBalance>>>,
#[serde(skip_serializing_if = "Option::is_none")]
spl_addresses_infos: Option<HashMap<String, CoinAddressInfo<TokenBalances>>>,
}

impl GetPlatformBalance for SolanaWithTokensActivationResult {
fn get_platform_balance(&self) -> BigDecimal {
fn get_platform_balance(&self) -> Option<BigDecimal> {
self.solana_addresses_infos
.iter()
.fold(BigDecimal::from(0), |total, (_, addr_info)| {
Expand Down Expand Up @@ -213,50 +215,52 @@ impl PlatformWithTokensActivationOps for SolanaCoin {
&self,
activation_request: &Self::ActivationRequest,
) -> Result<Self::ActivationResult, MmError<Self::ActivationError>> {
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(
Expand Down
Loading

0 comments on commit 150d928

Please sign in to comment.