Skip to content

Adds derive_priv_key v2 RPC for HD wallets#2541

Closed
smk762 wants to merge 9 commits intodevfrom
test-multi-privkey
Closed

Adds derive_priv_key v2 RPC for HD wallets#2541
smk762 wants to merge 9 commits intodevfrom
test-multi-privkey

Conversation

@smk762
Copy link
Copy Markdown

@smk762 smk762 commented Jul 21, 2025

The legacy show_priv_key method did not take input for account/address id, and would only return the zero index WIF for HD wallets, so I've added a v2 derive_priv_key method which accepts these inputs.

Request:

{
    "userpass": "{{userpass}}",
    "mmrpc": "2.0",
    "method": "derive_priv_key",
    "params": {
        "coin": "MATIC",
        "account_id": 0,
        "address_id": 3
    }
}

Response:

{
    "mmrpc": "2.0",
    "result": {
        "coin": "MATIC",
        "address": "0x1e8B4aA6a8B8a376E0357504cF2ebC11Bc02288b",
        "derivation_path": "m/44'/60'/0'/0/3",
        "priv_key": "0x932ec93805200317394d6f63216791cf6052e6bb7412153f799c0b0660086e24",
        "pub_key": "0x036b521bb1f9e845301f8bcb1f025151784ac2ea54b95fa50b9c491aced4a34c04"
    },
    "id": null
}

To test:

  • Use the seed in the test function to launch in HD mode
  • Activate some coins, and create some addresses, then query these coins and addresses via derive_priv_key.
  • Confirm the responses match the values returned at https://iancoleman.io/bip39/ with the same seed and selected coin.

Copy link
Copy Markdown

@onur-ozkan onur-ozkan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Some notes from the first review from my end:

Comment on lines +2157 to +2160
/// Returns the WIF prefix for the coin.
fn wif_prefix(&self) -> Option<u8> { None }

fn is_utxo(&self) -> bool { false }
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These shouldn't be defined in MarketCoinOps. I don't think we need to define them anywhere at all; we can simply derive the UTXO coin from MmCoinEnum.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done in 5641673

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

superceded by 236f9d0

Comment on lines +33 to +40
#[display(fmt = "No such coin: {}", _0)]
NoSuchCoin(String),
#[display(fmt = "Coin {} doesn't support HD wallet derivation", _0)]
CoinDoesntSupportDerivation(String),
#[display(fmt = "Hardware/remote wallet doesn't allow exporting private keys")]
HwWalletNotAllowed,
#[display(fmt = "Internal error: {}", _0)]
Internal(String),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be more clear to use struct-like errors instead if tuple-like ones, e.g.,:

    NoSuchCoin {
        ticker: String,
    },
    Internal {
        reason: String,
    }

so we can know what are the inner values are about without having to look use-cases.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done in 221b9fe

Comment on lines +2008 to +2010
"myipaddr": env::var ("BOB_TRADE_IP") .ok(),
"rpcip": env::var ("BOB_TRADE_IP") .ok(),
"canbind": env::var ("BOB_TRADE_PORT") .ok().map (|s| s.parse::<i64>().unwrap()),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove white spaces?

We should also unwrap instead of calling ok to fail the test when BOB_TRADE_IP and BOB_TRADE_PORT isn't present.

Copy link
Copy Markdown
Author

@smk762 smk762 Jul 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 79e632c

FWIW, the rest of the file uses .ok() and similar white spacing throughout. Should I fix up those also while I'm here?

Comment on lines +54 to +63
#[async_trait]
pub trait DerivePrivKeyV2: MmCoin + CoinWithPrivKeyPolicy + CoinWithDerivationMethod + Sized {
async fn derive_priv_key(&self, req: &DerivePrivKeyReq) -> Result<DerivedPrivKey, MmError<DerivePrivKeyError>>;
}

#[async_trait]
impl<Coin> DerivePrivKeyV2 for Coin
where
Coin: MmCoin + CoinWithPrivKeyPolicy + CoinWithDerivationMethod + MarketCoinOps + Sync,
{
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If derive_priv_key can take MmCoinEnum as a parameter, that would greatly simplify the implementation so we don't have to do all the generic-dances here (also in priv_key::derive_priv_key).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done in 236f9d0

@mariocynicys
Copy link
Copy Markdown
Collaborator

is this impl-ed so to

  • output the private key to the user (do we really need that for hd wallets?)
  • or is the result used within KW to do some computation (what would that be?)

@gcharang
Copy link
Copy Markdown

gcharang commented Jul 22, 2025

@mariocynicys

output the private key to the user (do we really need that for hd wallets?)

yes, this was implemented to let users export privkeys for HD wallet. we do need to do it as users will need the privkeys in case they need to do anything komodo wallet doesn't do. or if they need to access their coins in case the electrum servers we have are down. Even if there are no active electrum servers, users can import their privkey in native wallets with full blockchain history to move their coins

@mariocynicys
Copy link
Copy Markdown
Collaborator

i mean if we already have a way to expose the wallet seed, we then dont need to expose individual private keys. i dont know of a wallet that can work with a single private key (if there is, it will probably even consider it as legacy address, so no segwit coins etc... will be visible)

@gcharang
Copy link
Copy Markdown

you can import a single private key in komodo ocean wallet for KMD. in any native full node wallet for most other utxo coins. even for ethereum, you can do it in trust wallet or meta mask

@smk762 smk762 requested a review from onur-ozkan July 22, 2025 16:39
})?;

let private = Private {
prefix: 0, // ETH doesn't use WIF format
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the only difference compare to UTXO implementation?

@smk762
Copy link
Copy Markdown
Author

smk762 commented Jul 23, 2025

closing in favor of #2542

@smk762 smk762 closed this Jul 23, 2025
@shamardy shamardy deleted the test-multi-privkey branch July 23, 2025 12:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants