Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(hd_wallet): evm hd wallet and trezor #1979

Merged
merged 140 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from 119 commits
Commits
Show all changes
140 commits
Select commit Hold shift + click to select a range
921e281
wip: move hd_wallet.rs into a mod along with storage
shamardy Sep 22, 2023
83ade83
move hd_confirm_address.rs to hd_wallet mod
shamardy Sep 22, 2023
64932d9
move hd_pubkey.rs to hd_wallet mod
shamardy Sep 22, 2023
edfc928
remove hd prefix from file names in hd_wallet mod
shamardy Sep 26, 2023
bd5cfd4
wip: create hd_wallet mod to separate hd wallet functionalities from …
shamardy Sep 29, 2023
73b8b84
make set_known_addresses_number to have a default implementation acro…
shamardy Oct 2, 2023
aadf904
rename NewAccountCreatingError to NewAccountCreationError
shamardy Oct 4, 2023
975c6fa
return Self::Address instead of reference from HDAddressOps::address …
shamardy Oct 5, 2023
4d6e468
derive copy for HDAccountAddressId + other refactors
shamardy Oct 6, 2023
5114cc1
convert create_new_account to a generic function
shamardy Oct 11, 2023
731b27c
remove address_format field from generic HDWallet impl
shamardy Oct 16, 2023
8d7cf6d
move UtxoHDWallet and it's impl to utxo_hd_wallet.rs
shamardy Oct 16, 2023
038e0bd
create HDCoinWithdrawOps and move get_withdraw_hd_sender to it and ma…
shamardy Oct 17, 2023
1672197
wip: Add HDWallet derivation and implement HD coin ops for ETHCoin
shamardy Oct 18, 2023
2d42b3e
refactor is_address_used impl for ETHAddressScanner
shamardy Oct 19, 2023
7658417
move scan_for_new_addresses_impl to lp_coins.rs for now
shamardy Oct 19, 2023
e6b686e
enable account_balance, get_new_address, create_account, scan_for_new…
shamardy Oct 21, 2023
e8add69
create eth_hd_wallet.rs and move eth hd wallet types and implementati…
shamardy Oct 25, 2023
30080bb
make extract_extended_pubkey function common for all coins
shamardy Oct 25, 2023
e842165
do concurrent call for addresses balances
shamardy Oct 26, 2023
dd1d4c0
remove address EthCoinImpl since it's included in derivation_method, …
shamardy Oct 27, 2023
ad18db8
Merge remote-tracking branch 'origin/dev' into evm-hd-wallet
shamardy Oct 27, 2023
3ff7e3e
wip: enable eth hd wallet on coin initialization
shamardy Oct 27, 2023
ce4a337
Merge remote-tracking branch 'hd-account-balance' into evm-hd-wallet
shamardy Nov 28, 2023
f30842b
Original source for UDP transport to connect to Trezor emulator
dimxy Oct 10, 2023
76c8cc9
added modifications to udp.rs to integrate it
dimxy Oct 29, 2023
d47a43f
add tests for withdraw from witness and p2pkh with trezor, add trezor…
dimxy Oct 29, 2023
a76b189
refactor trezor ConnectableDeviceWrapper (use borrow instead of consu…
dimxy Oct 18, 2023
8e56aa9
add support for trezor evm initialisation with rpc task manager and w…
dimxy Nov 12, 2023
2d2894a
fix fmt
dimxy Nov 13, 2023
599e60a
remove unused commented code
dimxy Nov 13, 2023
9a39110
add Result to pubkey_from_xpub_str
dimxy Nov 13, 2023
1d8df3c
dispose extra chain_id replay protection, fix trimming zeros for trez…
dimxy Nov 15, 2023
aed8ef8
change amount in trezor test
dimxy Nov 15, 2023
da9c6a5
add error check of signature v created by trezor
dimxy Nov 15, 2023
719bff0
fix chunk length calc for trezor eth tx request
dimxy Nov 16, 2023
1b7993a
fix target all for bip32 lib for trezor
dimxy Nov 16, 2023
b0e2f58
add trezor eth network definitions structs
dimxy Nov 17, 2023
b4ccf3f
fix deadcode clippy
dimxy Nov 26, 2023
c9a6f5c
fix clippy errors
dimxy Nov 26, 2023
1c9fa22
add pin input in test trezor init loop, remove unsupported trezor tests
dimxy Nov 26, 2023
d17e605
move trezor tests in a module
dimxy Nov 27, 2023
7cbc46e
fix wasm build
dimxy Nov 27, 2023
958617c
added: init_enable_eth rpc set, check to disable init eth trezor in n…
dimxy Dec 8, 2023
e0a4565
fix fmt
dimxy Dec 10, 2023
da421b4
remove unused comments
dimxy Dec 13, 2023
bd4ec47
refactor xpub extraction by checking coin type
dimxy Dec 13, 2023
00aa339
add test code to try create new eth acc with trezor
dimxy Dec 13, 2023
10bfef1
fix eth gap_limit
dimxy Jan 18, 2024
4988565
fix getting address for derivation_path in eth withdraw for trezor
dimxy Jan 18, 2024
56fba06
allow eth withdraw from default account (no 'from' set) for trezor
dimxy Jan 18, 2024
3004711
fix clippy warnings
dimxy Jan 18, 2024
134c2e9
fix fmt
dimxy Jan 18, 2024
ddcb180
change get_enabled_address() to return HDAddress
dimxy Jan 21, 2024
1569184
change eth withdraw build to use cached from address (instead getting…
dimxy Jan 21, 2024
c7e5971
fix eth withdraw wasm build of refactored code
dimxy Jan 21, 2024
ff45c04
fix fmt
dimxy Jan 21, 2024
3925fe5
fix eth withdraw test mock
dimxy Jan 21, 2024
ad4cec8
fix fmt
dimxy Jan 21, 2024
6e664a9
fix eth withdraw test mock
dimxy Jan 22, 2024
055f9be
reorg imports
dimxy Feb 14, 2024
0e845bb
remove extra pub
dimxy Feb 14, 2024
bfe7a29
eliminate activated_pubkey in Trezor privkey policy; fix address for …
dimxy Feb 14, 2024
29b7835
mark unused trezor proto impl function as reserved for future
dimxy Feb 14, 2024
75c75a6
fix fmt
dimxy Feb 14, 2024
b98d380
fix default privkey policy in test helper activation request
dimxy Feb 14, 2024
fc6ec8d
Merge remote-tracking branch 'hd-account-balance' into evm-hd-wallet
shamardy Feb 14, 2024
52f9d91
Fix HDAddressOps::Address trait bounds
shamardy Feb 14, 2024
a1a0a43
Fix todo comments
shamardy Feb 14, 2024
63def73
Merge remote-tracking branch 'hd-account-balance' into evm-hd-wallet
shamardy Feb 14, 2024
5896b77
Merge branch 'evm-hd-wallet' into evm-hd-wallet-trezor
dimxy Feb 18, 2024
7d55c88
fix review notes: update signing status, get_public_key() return, sig…
dimxy Feb 20, 2024
950e349
fix fmt
dimxy Feb 22, 2024
049f025
refactor old DerivationMethod struct
dimxy Feb 22, 2024
1f897d7
new and refactor eth tests:
dimxy Feb 22, 2024
75ecef0
Merge remote-tracking branch 'hd-account-balance' into evm-hd-wallet
shamardy Mar 1, 2024
7f50a64
Merge remote-tracking branch 'evm-hd-wallet' into evm-hd-wallet-trezor
shamardy Mar 1, 2024
31295f3
Refactor EthPrivKeyBuildPolicy conversion and error handling in eth.rs
shamardy Mar 2, 2024
a4ac2ca
move eth on_generating_transaction after to and from address are checked
shamardy Mar 2, 2024
50e7933
add todo to add trezor to detect_priv_key_policy
shamardy Mar 2, 2024
58ca5f7
Remove JST distributor and related functions from eth/for_tests.rs
shamardy Mar 4, 2024
b520897
fix and remove some attributes
shamardy Mar 4, 2024
df2fa11
minor refactors
shamardy Mar 4, 2024
7481338
Removed the UnexpectedDerivationMethod variant from WithdrawError enu…
shamardy Mar 4, 2024
a0c33fd
Updated the to_response method in DerivationMethod enum in mm2src/coi…
shamardy Mar 4, 2024
c90489d
use for-tests feature for test_create_new_account_init_loop
shamardy Mar 4, 2024
504bd5e
Refactor coin activation statuses names
shamardy Mar 4, 2024
3dad3bf
fix `ETH_NETWORK_DEFS` typo and minor refactors
shamardy Mar 5, 2024
28bbba7
fix task_handle in re enable platform coin
dimxy Mar 5, 2024
097ba56
fix trezor tests for updated rpc_mode param
dimxy Mar 5, 2024
faa15e9
Merge remote-tracking branch 'hd-account-balance' into evm-hd-wallet
shamardy Mar 8, 2024
efb9c31
update todo comment about CoinAssocTypes::my_addr for HD wallet
shamardy Mar 8, 2024
185dbb0
Merge remote-tracking branch 'evm-hd-wallet' into evm-hd-wallet-trezor
shamardy Mar 8, 2024
4ca5491
Merge pull request #2005 from KomodoPlatform/evm-hd-wallet-trezor
shamardy Mar 8, 2024
95675c1
fix HDAddressBalanceScanner to use transaction count and balance
shamardy Mar 12, 2024
c538bb5
EVM HD Wallet balance streaming
shamardy Mar 13, 2024
d085af1
* implement CoinAssocTypes::my_addr for utxo hd wallet
shamardy Mar 14, 2024
d28042d
add init_token and implement it for EthCoin
shamardy Mar 16, 2024
49f2805
fix is_address_used for evm to check for both platform and tokens bal…
shamardy Mar 19, 2024
b35b7fb
use task_handle to update init erc20 task status
shamardy Mar 19, 2024
3233549
Fix eth_with_tokens response without creating a new trait for init_pl…
shamardy Mar 20, 2024
cf83e9b
fix backward compatibility issues
shamardy Mar 21, 2024
318c39c
Remove todos that are not needed anymore
shamardy Mar 21, 2024
be0acb0
make nonce lock per address
shamardy Mar 22, 2024
160dcda
Include token contract address, platform_coin, required_confirmations…
shamardy Mar 22, 2024
ef359ca
Better handle EnableCoinBalanceError
shamardy Mar 23, 2024
6b3fb5f
wip: doc comments
shamardy Mar 23, 2024
ffd0c96
complete doc comments
shamardy Mar 23, 2024
37e2b71
fix: insert platform ticker as a token only once for balance events
shamardy Mar 26, 2024
8660392
fix: make evm balance streaming error per address, add BalanceData an…
shamardy Mar 26, 2024
d2eaa17
fix: doc comments
shamardy Mar 26, 2024
846c22a
fix: use my addresses outside get_all_balance_results_concurrently to…
shamardy Mar 27, 2024
3c2e77d
fix: rename eth xpub ectractor status function and move to a common file
shamardy Mar 27, 2024
2a9e790
fix: doc comment of InitTokenActivationOps
shamardy Mar 27, 2024
7b81206
fix: rename erc20 xpub extractor status function and move to a common…
shamardy Mar 27, 2024
d9777af
fix: make confirm_address works for ethereum
shamardy Mar 27, 2024
dc6ef2a
fix: add some comments to explain why Address::default() is used for …
shamardy Mar 28, 2024
ee8ecf3
fix: Remove unused comment on get_eth_address and add doc comment for…
shamardy Apr 1, 2024
503aafb
fix: remove parameters from doc comments
shamardy Apr 1, 2024
09c1260
fix: rename all instances of BalanceMap to BalanceObject
shamardy Apr 1, 2024
def7e33
fix: make `chain_id` non-optional in `EthCoinImpl`
shamardy Apr 1, 2024
a0650d2
fix: fix failing eth tests due to chain_id not found:
shamardy Apr 2, 2024
681d5e4
fix: set proper chain id for some hardcoded configs in tests
shamardy Apr 2, 2024
afffe8b
Merge remote-tracking branch 'origin/hd-account-balance' into evm-hd-…
shamardy Apr 2, 2024
9de56f0
post-merge fix: fix z_balance_streaming.rs imports
shamardy Apr 2, 2024
fb1ccd7
fix: Rename common fn `extract_extended_pubkey` to `extract_extended_…
shamardy Apr 3, 2024
faaae10
fix: document `ExtractExtendedPubkey` trait
shamardy Apr 4, 2024
26cca4b
fix: rename `my_addresses` to `all_addresses` add it to `CoinWithDeri…
shamardy Apr 4, 2024
2201300
fix: map `EthActivationV2Error::ChainIdNotSet` to `EnablePlatformCoin…
shamardy Apr 5, 2024
2d8b0e2
fix: create a common registry for events and error events of the stre…
shamardy Apr 6, 2024
9462346
Merge remote-tracking branch 'origin/hd-account-balance' into evm-hd-…
shamardy Apr 16, 2024
b1d6d62
post-merge fixes: reduce arguments in sign_and_send_transaction
shamardy Apr 16, 2024
2017c22
post-merge test fixes: fix test_buy_conf_settings by adding chain_id …
shamardy Apr 16, 2024
031add3
post-merge fixes:
shamardy Apr 17, 2024
8e59228
post-merge test fixes: fix docker tests
shamardy Apr 17, 2024
8c41e55
post-merge test fixes:
shamardy Apr 17, 2024
66673b7
post-merge test fixes: fix fmt
shamardy Apr 17, 2024
b9890e6
post-merge test fixes: unignore swap_usdc_ibc_with_nimda test after t…
shamardy Apr 17, 2024
862476c
post-merge test fixes: increase WASM_BINDGEN_TEST_TIMEOUT to 420 and …
shamardy Apr 18, 2024
ff28b4b
post-merge test fixes: fix some issues in swap watcher test, some tes…
shamardy Apr 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions mm2src/coins/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ enable-solana = [
]
default = []
run-docker-tests = []
for-tests = []

[lib]
name = "coins"
Expand Down
260 changes: 167 additions & 93 deletions mm2src/coins/coin_balance.rs

Large diffs are not rendered by default.

1,244 changes: 678 additions & 566 deletions mm2src/coins/eth.rs

Large diffs are not rendered by default.

150 changes: 110 additions & 40 deletions mm2src/coins/eth/eth_balance_events.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use async_trait::async_trait;
use common::{executor::{AbortSettings, SpawnAbortable, Timer},
log, Future01CompatExt};
use ethereum_types::Address;
use futures::{channel::oneshot::{self, Receiver, Sender},
stream::FuturesUnordered,
StreamExt};
Expand All @@ -10,65 +11,104 @@ use mm2_err_handle::prelude::MmError;
use mm2_event_stream::{behaviour::{EventBehaviour, EventInitStatus},
Event, EventStreamConfiguration};
use mm2_number::BigDecimal;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};

use super::EthCoin;
use crate::{eth::{u256_to_big_decimal, Erc20TokenInfo},
BalanceError, MmCoin};
struct BalanceData {
laruh marked this conversation as resolved.
Show resolved Hide resolved
ticker: String,
address: String,
balance: BigDecimal,
}

struct BalanceFetchError {
ticker: String,
address: String,
error: MmError<BalanceError>,
}

type BalanceResult = Result<BalanceData, BalanceFetchError>;

/// This implementation differs from others, as they immediately return
/// an error if any of the requests fails. This one completes all futures
/// and returns their results individually.
async fn get_all_balance_results_concurrently(
coin: &EthCoin,
) -> Vec<Result<(String, BigDecimal), (String, MmError<BalanceError>)>> {
async fn get_all_balance_results_concurrently(coin: &EthCoin, addresses: HashSet<Address>) -> Vec<BalanceResult> {
let mut tokens = coin.get_erc_tokens_infos();

// Workaround for performance purposes.
//
// Unlike tokens, the platform coin length is constant (=1). Instead of creating a generic
// type and mapping the platform coin and the entire token list (which can grow at any time), we map
// the platform coin to Erc20TokenInfo so that we can use the token list right away without
// additional mapping.
tokens.insert(coin.ticker.clone(), Erc20TokenInfo {
token_address: coin.my_address,
// This is a dummy value, since there is no token address for the platform coin.
// In the fetch_balance function, we check if the token_ticker is equal to this
// coin's ticker to avoid using token_address to fetch the balance
// and to use address_balance instead.
token_address: Address::default(),
onur-ozkan marked this conversation as resolved.
Show resolved Hide resolved
decimals: coin.decimals,
});
drop_mutability!(tokens);

let mut all_jobs = FuturesUnordered::new();

let jobs = tokens
.into_iter()
.map(|(token_ticker, info)| async move { fetch_balance(coin, token_ticker, &info).await })
.collect::<FuturesUnordered<_>>();
for address in addresses {
let jobs = tokens.iter().map(|(token_ticker, info)| {
let coin = coin.clone();
let token_ticker = token_ticker.clone();
let info = info.clone();
async move { fetch_balance(&coin, address, token_ticker, &info).await }
});

jobs.collect().await
all_jobs.extend(jobs);
}

all_jobs.collect().await
}

async fn fetch_balance(
coin: &EthCoin,
address: Address,
token_ticker: String,
info: &Erc20TokenInfo,
) -> Result<(String, BigDecimal), (String, MmError<BalanceError>)> {
) -> Result<BalanceData, BalanceFetchError> {
let (balance_as_u256, decimals) = if token_ticker == coin.ticker {
(
coin.address_balance(coin.my_address)
coin.address_balance(address)
.compat()
.await
.map_err(|e| (token_ticker.clone(), e))?,
.map_err(|error| BalanceFetchError {
ticker: token_ticker.clone(),
address: address.to_string(),
error,
})?,
coin.decimals,
)
} else {
(
coin.get_token_balance_by_address(info.token_address)
coin.get_token_balance(info.token_address)
.await
.map_err(|e| (token_ticker.clone(), e))?,
.map_err(|error| BalanceFetchError {
ticker: token_ticker.clone(),
address: address.to_string(),
error,
})?,
info.decimals,
)
};

let balance_as_big_decimal =
u256_to_big_decimal(balance_as_u256, decimals).map_err(|e| (token_ticker.clone(), e.into()))?;

Ok((token_ticker, balance_as_big_decimal))
let balance_as_big_decimal = u256_to_big_decimal(balance_as_u256, decimals).map_err(|e| BalanceFetchError {
ticker: token_ticker.clone(),
address: address.to_string(),
error: e.into(),
})?;

Ok(BalanceData {
ticker: token_ticker,
address: address.to_string(),
balance: balance_as_big_decimal,
})
}

#[async_trait]
Expand All @@ -80,31 +120,69 @@ impl EventBehaviour for EthCoin {
const RECEIVER_DROPPED_MSG: &str = "Receiver is dropped, which should never happen.";

async fn start_polling(coin: EthCoin, ctx: MmArc, interval: f64) {
let mut cache: HashMap<String, BigDecimal> = HashMap::new();
async fn sleep_remaining_time(interval: f64, now: Instant) {
// If the interval is x seconds,
// our goal is to broadcast changed balances every x seconds.
// To achieve this, we need to subtract the time complexity of each iteration.
// Given that an iteration already takes 80% of the interval,
// this will lead to inconsistency in the events.
let remaining_time = interval - now.elapsed().as_secs_f64();
// Not worth to make a call for less than `0.1` durations
if remaining_time >= 0.1 {
Timer::sleep(remaining_time).await;
}
}

let mut cache: HashMap<String, HashMap<String, BigDecimal>> = HashMap::new();

loop {
let now = Instant::now();

let addresses = match coin.my_addresses().await {
Ok(addresses) => addresses,
Err(e) => {
log::error!("Failed getting addresses for {}. Error: {}", coin.ticker, e);
let e = serde_json::to_value(e).expect("Serialization shouldn't fail.");
ctx.stream_channel_controller
.broadcast(Event::new(
format!("{}:{}", EthCoin::ERROR_EVENT_NAME, coin.ticker),
e.to_string(),
))
.await;
sleep_remaining_time(interval, now).await;
continue;
},
};

let mut balance_updates = vec![];
for result in get_all_balance_results_concurrently(&coin).await {
for result in get_all_balance_results_concurrently(&coin, addresses).await {
match result {
Ok((ticker, balance)) => {
if Some(&balance) == cache.get(&ticker) {
Ok(res) => {
if Some(&res.balance) == cache.get(&res.ticker).and_then(|map| map.get(&res.address)) {
continue;
}

balance_updates.push(json!({
"ticker": ticker,
"balance": { "spendable": balance, "unspendable": BigDecimal::default() }
"ticker": res.ticker,
"address": res.address,
"balance": { "spendable": res.balance, "unspendable": BigDecimal::default() }
}));
cache.insert(ticker.to_owned(), balance);
cache
.entry(res.ticker.clone())
.or_insert_with(HashMap::new)
.insert(res.address, res.balance);
},
Err((ticker, e)) => {
log::error!("Failed getting balance for '{ticker}' with {interval} interval. Error: {e}");
let e = serde_json::to_value(e).expect("Serialization should't fail.");
Err(err) => {
log::error!(
"Failed getting balance for '{}:{}' with {interval} interval. Error: {}",
err.ticker,
err.address,
err.error
);
let e = serde_json::to_value(err.error).expect("Serialization shouldn't fail.");
ctx.stream_channel_controller
.broadcast(Event::new(
format!("{}:{}", EthCoin::ERROR_EVENT_NAME, ticker),
format!("{}:{}:{}", EthCoin::ERROR_EVENT_NAME, err.ticker, err.address),
dimxy marked this conversation as resolved.
Show resolved Hide resolved
e.to_string(),
))
.await;
Expand All @@ -121,15 +199,7 @@ impl EventBehaviour for EthCoin {
.await;
}

// If the interval is x seconds, our goal is to broadcast changed balances every x seconds.
// To achieve this, we need to subtract the time complexity of each iteration.
// Given that an iteration already takes 80% of the interval, this will lead to inconsistency
// in the events.
let remaining_time = interval - now.elapsed().as_secs_f64();
// Not worth to make a call for less than `0.1` durations
if remaining_time >= 0.1 {
Timer::sleep(remaining_time).await;
}
sleep_remaining_time(interval, now).await;
}
}

Expand Down
Loading
Loading