feat(wallet): implement HD multi-address support for message signing#2432
feat(wallet): implement HD multi-address support for message signing#2432
Conversation
…r HDwallet, completed eth impl
| sepolia-taker-swap-v2-tests = [] | ||
| test-ext-api = ["trading_api/test-ext-api"] | ||
| new-db-arch = [] # A temporary feature to integrate the new db architecture incrementally | ||
| new-db-arch = ["mm2_core/new-db-arch"] # A temporary feature to integrate the new db architecture incrementally |
There was a problem hiding this comment.
nit: this change is up #2398. you could omit it here if u want (to avoid conflicts)
mm2src/coins/lp_coins.rs
Outdated
| HdWallet { | ||
| coin: String, | ||
| message: String, | ||
| derivation_path: RpcDerivationPath, |
There was a problem hiding this comment.
there is part of the derivation path which should be static per coin (and defined in the coins file).
we might wanna get the derivation path this way: https://github.com/KomodoPlatform/komodo-defi-framework/blob/d323812a5100b3a96f152bfcbc7ac38e86b828bc/mm2src/coins/rpc_command/account_balance.rs#L19-L20
There was a problem hiding this comment.
I might disagree with this. KDF already returns full derivation path for every addresses which GUI can just pass to this param. Moreover, if I go with your suggestion, I will also need to make sign_message into an asynchronous function(no big deal tho) and make the fn do more work.
If I see a better reason not to require the full derivation_path I will rework it ofc.
There was a problem hiding this comment.
if we wanna keep it like this, we at least wanna perform a check (e.g.) to make sure we are not signing from a private key that isn't standard to this coin. people make mistakes.
mm2src/coins/lp_coins.rs
Outdated
| #[serde(tag = "derivation_method", rename_all = "snake_case")] | ||
| pub enum SignatureRequest { | ||
| Iguana { | ||
| coin: String, | ||
| message: String, | ||
| }, | ||
| HdWallet { | ||
| coin: String, | ||
| message: String, | ||
| derivation_path: RpcDerivationPath, | ||
| }, | ||
| } |
There was a problem hiding this comment.
does it make sense to tell the caller to state whether they want the signing with iguana or HD wallet given that KDF was initialized exclusively with either iguana or HD wallet?
i mean, if i initialized KDF with enable_hd: true, signing requests should implicitly be HD based (as signing with iguana should error anyway and vice versa), or let's say, signing should depend on the activated coin (assuming we can have one coin activated in HD mode while another activated in another mode (e.g. pubkey-only)).
what im saying is, the derivation_method field shouldn't exist.
mm2src/coins/eth.rs
Outdated
|
|
||
| let signature = match derivation_path { | ||
| Some(derivation_path) => { | ||
| let expected_coin_type = self.priv_key_policy.path_to_coin_or_err()?.coin_type(); |
There was a problem hiding this comment.
could we check the whole path to coin instead of just the coin type?
There was a problem hiding this comment.
thanks
what about this tho:
let expected_path = self.priv_key_policy.path_to_coin_or_err()?;
let rpc_path = HDPathToCoin::try_from(derivation_path.clone())?;
if expected_path != &rpc_path {
let error = format!(
"Derivation path '{:?}' must be equal to '{:?}'",
derivation_path, expected_path
);
return MmError::err(SignatureError::InvalidRequest(error));
};There was a problem hiding this comment.
but looks like the tail applies a strict length check: https://github.com/KomodoPlatform/komodo-defi-framework/blob/187284d0b1e07ef7d9c243cb35dba210063c2b4d/mm2src/crypto/src/bip32_child.rs#L233
we can trim the derivation path before HDPathToCoin::try_from or use StandardHDPath but add a method to it that gets the HDPathToCoin from self.
shamardy
left a comment
There was a problem hiding this comment.
One comment at this stage that will change things a bit. Will review more once this is addressed.
smk762
left a comment
There was a problem hiding this comment.
Confirmed working for LTC, LTC-segwit, and ETH. Confirmed param omission defaults to 0 index address. Confirmed param inclusion validates with related index address.
Prior segwit issues determined to be a result of derivation path data in MM2.db not being updated to match the coins file when it was updated. Issue unlikely to affect non-dev users.
shamardy
left a comment
There was a problem hiding this comment.
Thanks for the fixes! Only nits left, will merge once fixed.
| fn sign_message_hash(&self, _message: &str) -> Option<[u8; 32]> { None } | ||
|
|
||
| fn sign_message(&self, _message: &str) -> SignatureResult<String> { unimplemented!() } | ||
| fn sign_message(&self, _message: &str, _account: Option<HDAddressSelector>) -> SignatureResult<String> { | ||
| MmError::err(SignatureError::InternalError("Not implemented".into())) | ||
| } | ||
|
|
||
| fn verify_message(&self, _signature: &str, _message: &str, _address: &str) -> VerificationResult<bool> { | ||
| unimplemented!() | ||
| MmError::err(VerificationError::InternalError("Not implemented".into())) |
There was a problem hiding this comment.
I guess we will need those once SIA implementation is completed. Can you please open an issue for both this and tendermint and any other missing implementation @borngraced
48a64cf to
860c208
Compare
|
@smk762 |
dimxy
left a comment
There was a problem hiding this comment.
LGTM.
Couple of notes for future:
I'd suggest we try to avoid optional params like in this fn
fn sign_message(&self, message: &str, address: Option<HDAddressSelector>)
in favour of explicit params, to avoid hidden behaviour what make the whole api less transparent IMO. So in this case params could be enum { Iguana, HDWallet {address: HDAddressSelector }
Also let's avoid general purpose errors with attached lengthy descriptions like: SignatureError::InvalidRequest("You need to enable kdf with enable_hd to sign messages with a specific account/address".to_string()) in favour of error codes, for e.g. SignatureError::HDWalletNotEnabled
Totally agree on both |
|
@borngraced please fix this opening comment #2432 (comment) even post merge |
updated. thanks! |
fixes two tests that were introduced in #2432. 1- fixes `test_sign_verify_message_eth_with_derivation_path` by including a json parameter that was missing. 2- fixes `test_hd_address_conflict_across_derivation_paths` as it was not functioning correctly because it never re-used the same DB path, which is a critical step to show that the bug exists. this makes it so we reuse the same DB path for the second mm2 instance. the test was also simplified to omit message signing as it was not critical part of the test.
* dev: feat(walletconnect): add WalletConnect v2 support for EVM and Cosmos (#2223) feat(ibc-routing-part-1): supporting entire Cosmos network for swaps (#2459) fix(test): fix HD Wallet message signing tests (#2474) improvement(builds): enable static CRT linking for MSVC builds (#2464) feat(wallet): implement HD multi-address support for message signing (#2432)
* lr-swap-wip: (37 commits) fix custom token error name fix getting chain_id from protocol_data refactor (review): use dedicated large error cfg, add new fn to FromApiValueError, fix TODO, use experimental namespace for lr rpc, more Ticker alias feat(walletconnect): add WalletConnect v2 support for EVM and Cosmos (GLEECBTC#2223) feat(ibc-routing-part-1): supporting entire Cosmos network for swaps (GLEECBTC#2459) fix(test): fix HD Wallet message signing tests (GLEECBTC#2474) improvement(builds): enable static CRT linking for MSVC builds (GLEECBTC#2464) feat(wallet): implement HD multi-address support for message signing (GLEECBTC#2432) fix(p2pk): validate expected pubkey correctly for p2pk inputs (GLEECBTC#2408) chore(docs): update old urls referencing atomicdex or old docs pages (GLEECBTC#2428) improvement(p2p): remove hardcoded seeds (GLEECBTC#2439) fix(evm-api): find enabled erc20 token using platform ticker (GLEECBTC#2445) chore(docs): add DeepWiki badge to README (GLEECBTC#2463) chore(core): organize deps using workspace.dependencies (GLEECBTC#2449) feat(db-arch): more dbdir to address_dir replacements (GLEECBTC#2398) chore(build-artifacts): remove duplicated mm2 build artifacts (GLEECBTC#2448) feat(pubkey-banning): expirable bans (GLEECBTC#2455) fix(eth-balance-events): serialize eth address using AddrToString (GLEECBTC#2440) chore(deps): remove base58 and replace it completely with bs58 (GLEECBTC#2427) feat(tron): initial groundwork for full TRON integration (GLEECBTC#2425) ...
* dev: (30 commits) chore(core): replace hash_raw_entry with stable entry() API (GLEECBTC#2473) chore(core): adapt `MmError` and usages for compatibility with new rustc versions (GLEECBTC#2443) feat(wallet): add `delete_wallet` RPC (GLEECBTC#2497) chore(release): add changelog entries for v2.5.0-beta (GLEECBTC#2494) chore(release): bump kdf version to 2.5.0-beta (GLEECBTC#2492) feat(tests): zcoin unit test to validate dex fee (GLEECBTC#2460) fix(zcoin): correctly track unconfirmed z-coin notes (GLEECBTC#2331) improvement(orders): remove BTC specific volume from min_trading_vol logic (GLEECBTC#2483) feat(ibc-routing-part-2): supporting entire Cosmos network for swaps (GLEECBTC#2476) fix(startup): don't initialize WalletConnect during startup (GLEECBTC#2485) fix(dns): better ip resolution (GLEECBTC#2487) improvement(event-streaming): strong type streamer IDs (GLEECBTC#2441) bump timed-map to `1.4.1` (GLEECBTC#2481) improvement(RPC): unified interface for legacy and current RPC interfaces (GLEECBTC#2450) improvement(tendermint): `tendermint_tx_internal_id` helper (GLEECBTC#2438) feat(walletconnect): add WalletConnect v2 support for EVM and Cosmos (GLEECBTC#2223) feat(ibc-routing-part-1): supporting entire Cosmos network for swaps (GLEECBTC#2459) fix(test): fix HD Wallet message signing tests (GLEECBTC#2474) improvement(builds): enable static CRT linking for MSVC builds (GLEECBTC#2464) feat(wallet): implement HD multi-address support for message signing (GLEECBTC#2432) ... # Conflicts: # mm2src/coins/qrc20.rs # mm2src/mm2_main/src/lp_swap/maker_swap.rs
#2406
This PR allows users with HD wallet to sign messages from any derived address using
derivation_pathsign_messagerpc response paramsExample before
{ "coin": "ETH", "message": "hello world", }Example New
{ "coin": "ETH", "message": "hello world" }Example New(HD account)
{ "coin": "ETH", "message": "hello world", "address": { "derivation_path": "m/44'/0'/0'/0/2" } }OR
{ "coin": "ETH", "message": "hello world", "address": { "account_id": 0, "chain": "External", "address_id": 1 } }