Skip to content

Commit

Permalink
Merge pull request #1672 from sergei-boiko/shared-db
Browse files Browse the repository at this point in the history
[r2r] Hardware Wallet enhancements
  • Loading branch information
ca333 authored Feb 25, 2023
2 parents bf43cc8 + 99954a7 commit 5549d69
Show file tree
Hide file tree
Showing 51 changed files with 1,312 additions and 459 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ deny = [
# The goal is to reduce this list as much as possible
skip = [
{ name = "aes", version = "*" },
{ name = "adler", version = "*" },
{ name = "ahash", version = "*" },
{ name = "arrayvec", version = "*" },
{ name = "autocfg", version = "*" },
Expand Down Expand Up @@ -282,13 +283,15 @@ skip = [
{ name = "subtle", version = "*" },
{ name = "syn", version = "*" },
{ name = "time", version = "*" },
{ name = "time-macros", version = "*" },
{ name = "tiny-keccak", version = "*" },
{ name = "tokio-util", version = "*" },
{ name = "trie-root", version = "*" },
{ name = "uint", version = "*" },
{ name = "unicode-xid", version = "*" },
{ name = "unsigned-varint", version = "*" },
{ name = "url", version = "*" },
{ name = "uuid", version = "*" },
{ name = "wasi", version = "*" },
{ name = "webpki", version = "*" },
{ name = "wyz", version = "*" },
Expand Down
8 changes: 4 additions & 4 deletions mm2src/coins/coin_balance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ pub trait EnableCoinBalanceOps {
params: EnabledCoinBalanceParams,
) -> MmResult<CoinBalanceReport, EnableCoinBalanceError>
where
XPubExtractor: HDXPubExtractor + Sync;
XPubExtractor: HDXPubExtractor;
}

#[async_trait]
Expand All @@ -173,7 +173,7 @@ where
params: EnabledCoinBalanceParams,
) -> MmResult<CoinBalanceReport, EnableCoinBalanceError>
where
XPubExtractor: HDXPubExtractor + Sync,
XPubExtractor: HDXPubExtractor,
{
match self.derivation_method() {
DerivationMethod::SingleAddress(my_address) => self
Expand Down Expand Up @@ -211,7 +211,7 @@ pub trait HDWalletBalanceOps: HDWalletCoinOps {
params: EnabledCoinBalanceParams,
) -> MmResult<HDWalletBalance, EnableCoinBalanceError>
where
XPubExtractor: HDXPubExtractor + Sync;
XPubExtractor: HDXPubExtractor;

/// Scans for the new addresses of the specified `hd_account` using the given `address_scanner`.
/// Returns balances of the new addresses.
Expand Down Expand Up @@ -387,7 +387,7 @@ pub mod common_impl {
where
Coin: HDWalletBalanceOps + MarketCoinOps + Sync,
Coin::Address: fmt::Display,
XPubExtractor: HDXPubExtractor + Sync,
XPubExtractor: HDXPubExtractor,
{
let mut accounts = hd_wallet.get_accounts_mut().await;
let address_scanner = coin.produce_hd_address_scanner().await?;
Expand Down
6 changes: 3 additions & 3 deletions mm2src/coins/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ use sha3::{Digest, Keccak256};
use std::collections::HashMap;
use std::convert::TryFrom;
use std::ops::Deref;
use std::path::PathBuf;
#[cfg(not(target_arch = "wasm32"))] use std::path::PathBuf;
use std::str::FromStr;
use std::sync::atomic::{AtomicU64, Ordering as AtomicOrdering};
use std::sync::{Arc, Mutex};
Expand Down Expand Up @@ -484,7 +484,7 @@ impl EthCoinImpl {
Box::new(self.web3.trace().filter(filter.build()).map_err(|e| ERRL!("{}", e)))
}

#[cfg_attr(target_arch = "wasm32", allow(dead_code))]
#[cfg(not(target_arch = "wasm32"))]
fn eth_traces_path(&self, ctx: &MmArc) -> PathBuf {
ctx.dbdir()
.join("TRANSACTIONS")
Expand Down Expand Up @@ -528,7 +528,7 @@ impl EthCoinImpl {
unreachable!()
}

#[cfg_attr(target_arch = "wasm32", allow(dead_code))]
#[cfg(not(target_arch = "wasm32"))]
fn erc20_events_path(&self, ctx: &MmArc) -> PathBuf {
ctx.dbdir()
.join("TRANSACTIONS")
Expand Down
184 changes: 184 additions & 0 deletions mm2src/coins/hd_confirm_address.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
use async_trait::async_trait;
use bip32::DerivationPath;
use crypto::hw_rpc_task::HwConnectStatuses;
use crypto::trezor::trezor_rpc_task::{TrezorRequestStatuses, TrezorRpcTaskProcessor, TryIntoUserAction};
use crypto::trezor::{ProcessTrezorResponse, TrezorError, TrezorProcessingError};
use crypto::{CryptoCtx, CryptoCtxError, HardwareWalletArc, HwError, HwProcessingError};
use enum_from::{EnumFromInner, EnumFromStringify};
use mm2_core::mm_ctx::MmArc;
use mm2_err_handle::prelude::*;
use rpc_task::{RpcTask, RpcTaskError, RpcTaskHandle};

const SHOW_ADDRESS_ON_DISPLAY: bool = true;

#[derive(EnumFromInner, EnumFromStringify)]
pub enum HDConfirmAddressError {
HwContextNotInitialized,
RpcTaskError(RpcTaskError),
#[from_inner]
HardwareWalletError(HwError),
InvalidAddress {
expected: String,
found: String,
},
#[from_stringify("CryptoCtxError")]
Internal(String),
}

impl From<TrezorError> for HDConfirmAddressError {
fn from(e: TrezorError) -> Self { HDConfirmAddressError::HardwareWalletError(HwError::from(e)) }
}

impl From<TrezorProcessingError<RpcTaskError>> for HDConfirmAddressError {
fn from(e: TrezorProcessingError<RpcTaskError>) -> Self {
match e {
TrezorProcessingError::TrezorError(trezor) => HDConfirmAddressError::from(HwError::from(trezor)),
TrezorProcessingError::ProcessorError(rpc) => HDConfirmAddressError::RpcTaskError(rpc),
}
}
}

impl From<HwProcessingError<RpcTaskError>> for HDConfirmAddressError {
fn from(e: HwProcessingError<RpcTaskError>) -> Self {
match e {
HwProcessingError::HwError(hw) => HDConfirmAddressError::from(hw),
HwProcessingError::ProcessorError(rpc) => HDConfirmAddressError::RpcTaskError(rpc),
}
}
}

/// An `InProgress` status constructor.
pub trait ConfirmAddressStatus: Sized {
/// Returns an `InProgress` RPC status that will be used to ask the user
/// to confirm an `address` on his HW device.
fn confirm_addr_status(address: String) -> Self;
}

/// An address confirmation interface.
#[async_trait]
pub trait HDConfirmAddress: Sync {
/// Asks the user to confirm if the given `expected_address` is the same as on the HW display.
async fn confirm_utxo_address(
&self,
trezor_utxo_coin: String,
derivation_path: DerivationPath,
expected_address: String,
) -> MmResult<(), HDConfirmAddressError>;
}

pub enum RpcTaskConfirmAddress<'task, Task: RpcTask> {
Trezor {
hw_ctx: HardwareWalletArc,
task_handle: &'task RpcTaskHandle<Task>,
statuses: HwConnectStatuses<Task::InProgressStatus, Task::AwaitingStatus>,
},
}

#[async_trait]
impl<'task, Task> HDConfirmAddress for RpcTaskConfirmAddress<'task, Task>
where
Task: RpcTask,
Task::InProgressStatus: ConfirmAddressStatus,
Task::UserAction: TryIntoUserAction + Send,
{
async fn confirm_utxo_address(
&self,
trezor_utxo_coin: String,
derivation_path: DerivationPath,
expected_address: String,
) -> MmResult<(), HDConfirmAddressError> {
match self {
RpcTaskConfirmAddress::Trezor {
hw_ctx,
task_handle,
statuses,
} => {
Self::confirm_utxo_address_with_trezor(
hw_ctx,
task_handle,
statuses,
trezor_utxo_coin,
derivation_path,
expected_address,
)
.await
},
}
}
}

impl<'task, Task> RpcTaskConfirmAddress<'task, Task>
where
Task: RpcTask,
Task::InProgressStatus: ConfirmAddressStatus,
Task::UserAction: TryIntoUserAction + Send,
{
pub fn new(
ctx: &MmArc,
task_handle: &'task RpcTaskHandle<Task>,
statuses: HwConnectStatuses<Task::InProgressStatus, Task::AwaitingStatus>,
) -> MmResult<RpcTaskConfirmAddress<'task, Task>, HDConfirmAddressError> {
let crypto_ctx = CryptoCtx::from_ctx(ctx)?;
let hw_ctx = crypto_ctx
.hw_ctx()
.or_mm_err(|| HDConfirmAddressError::HwContextNotInitialized)?;
Ok(RpcTaskConfirmAddress::Trezor {
hw_ctx,
task_handle,
statuses,
})
}

async fn confirm_utxo_address_with_trezor(
hw_ctx: &HardwareWalletArc,
task_handle: &RpcTaskHandle<Task>,
connect_statuses: &HwConnectStatuses<Task::InProgressStatus, Task::AwaitingStatus>,
trezor_coin: String,
derivation_path: DerivationPath,
expected_address: String,
) -> MmResult<(), HDConfirmAddressError> {
let mut trezor_session = hw_ctx.trezor().await?;

let confirm_statuses = TrezorRequestStatuses {
on_button_request: Task::InProgressStatus::confirm_addr_status(expected_address.clone()),
..connect_statuses.to_trezor_request_statuses()
};

let pubkey_processor = TrezorRpcTaskProcessor::new(task_handle, confirm_statuses);
let address = trezor_session
.get_utxo_address(derivation_path, trezor_coin, SHOW_ADDRESS_ON_DISPLAY)
.await?
.process(&pubkey_processor)
.await?;

if address != expected_address {
return MmError::err(HDConfirmAddressError::InvalidAddress {
expected: expected_address,
found: address,
});
}
Ok(())
}
}

#[cfg(test)]
pub(crate) mod for_tests {
use super::*;
use mocktopus::macros::mockable;

#[derive(Default)]
pub struct MockableConfirmAddress;

#[async_trait]
#[mockable]
impl HDConfirmAddress for MockableConfirmAddress {
async fn confirm_utxo_address(
&self,
_trezor_utxo_coin: String,
_derivation_path: DerivationPath,
_expected_address: String,
) -> MmResult<(), HDConfirmAddressError> {
unimplemented!()
}
}
}
10 changes: 4 additions & 6 deletions mm2src/coins/hd_pubkey.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::hd_wallet::NewAccountCreatingError;
use async_trait::async_trait;
use crypto::hw_rpc_task::{HwConnectStatuses, TrezorRpcTaskConnectProcessor};
use crypto::hw_rpc_task::HwConnectStatuses;
use crypto::trezor::trezor_rpc_task::{TrezorRpcTaskProcessor, TryIntoUserAction};
use crypto::trezor::utxo::IGNORE_XPUB_MAGIC;
use crypto::trezor::{ProcessTrezorResponse, TrezorError, TrezorProcessingError};
Expand Down Expand Up @@ -81,11 +81,11 @@ pub trait ExtractExtendedPubkey {
derivation_path: DerivationPath,
) -> MmResult<Self::ExtendedPublicKey, HDExtractPubkeyError>
where
XPubExtractor: HDXPubExtractor + Sync;
XPubExtractor: HDXPubExtractor;
}

#[async_trait]
pub trait HDXPubExtractor {
pub trait HDXPubExtractor: Sync {
async fn extract_utxo_xpub(
&self,
trezor_utxo_coin: String,
Expand Down Expand Up @@ -162,9 +162,7 @@ where
trezor_coin: String,
derivation_path: DerivationPath,
) -> MmResult<XPub, HDExtractPubkeyError> {
let connect_processor = TrezorRpcTaskConnectProcessor::new(task_handle, statuses.clone());
let trezor = hw_ctx.trezor(&connect_processor).await?;
let mut trezor_session = trezor.session().await?;
let mut trezor_session = hw_ctx.trezor().await?;

let pubkey_processor = TrezorRpcTaskProcessor::new(task_handle, statuses.to_trezor_request_statuses());
let xpub = trezor_session
Expand Down
Loading

0 comments on commit 5549d69

Please sign in to comment.