Skip to content

feat(wallet): implement unified offline private key export API#2542

Merged
shamardy merged 28 commits intomainfrom
offline_key_export
Jul 28, 2025
Merged

feat(wallet): implement unified offline private key export API#2542
shamardy merged 28 commits intomainfrom
offline_key_export

Conversation

@devin-ai-integration
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration bot commented Jul 23, 2025

feat: implement unified offline private key export API

Summary

This PR implements a unified offline private key export API that allows exporting private keys for coins that are not currently activated/enabled in MM2. The implementation consolidates three export modes (Standard, HD, Iguana) into a single get_private_keys RPC method and maintains backwards compatibility by updating the existing show_priv_key method with offline fallback functionality.

Key Changes:

  • New get_private_keys RPC method supporting offline key export for inactive coins
  • Enhanced show_priv_key method with offline fallback when coins aren't activated
  • Support for UTXO and ETH-based protocols with proper address prefix handling
  • Three export modes: Standard (WIF), HD (with derivation paths), and Iguana (legacy format)

Review & Testing Checklist for Human

⚠️ CRITICAL - 5 items requiring thorough verification:

  • Test get_private_keys RPC method with all three modes (Standard, HD, Iguana) using different coin types (BTC, ETH, tokens) and verify exported private keys are cryptographically correct
  • Verify backwards compatibility of show_priv_key method - ensure it still works normally for activated coins without any behavioral changes
  • Test offline fallback functionality - verify show_priv_key now works for non-activated coins by calling it with coins that aren't currently enabled
  • Validate key derivation accuracy - cross-check exported private keys against known good implementations or by importing into wallets to ensure they control the expected addresses
  • Test protocol-specific handling - verify prefix value extraction and address derivation works correctly for various coin types, especially Komodo SmartChains and ERC20 tokens

Recommended Test Plan:

  1. Enable a few coins normally, test show_priv_key works as before
  2. Disable those coins, test show_priv_key now uses offline fallback
  3. Test get_private_keys with various coin configurations in all three modes
  4. Import exported keys into external wallets to verify they control expected addresses

Diagram

%%{ init : { "theme" : "default" }}%%
graph TD
    Client[/"HTTP Client<br/>(curl/app)"/] --> Dispatcher["mm2_main/src/rpc/<br/>dispatcher/dispatcher.rs"]:::minor-edit
    
    Dispatcher -->|"get_private_keys"| OfflineKeys["coins/rpc_command/<br/>offline_keys.rs<br/>(NEW FILE)"]:::major-edit
    Dispatcher -->|"show_priv_key"| LpCoins["coins/lp_coins.rs<br/>show_priv_key()"]:::major-edit
    
    LpCoins -->|"fallback when<br/>coin not activated"| OfflineKeys
    LpCoins -->|"normal path when<br/>coin activated"| CoinInstance[/"Activated Coin<br/>Instance"/]:::context
    
    OfflineKeys --> CoinsConfig[/"coins.json<br/>Configuration"/]:::context
    OfflineKeys --> CryptoUtils[/"Key Derivation<br/>& Crypto Utils"/]:::context
    
    ModRs["coins/rpc_command/<br/>mod.rs"]:::minor-edit -->|"module<br/>registration"| OfflineKeys
    
    subgraph Legend
        L1[Major Edit]:::major-edit
        L2[Minor Edit]:::minor-edit  
        L3[Context/No Edit]:::context
    end
    
    classDef major-edit fill:#90EE90
    classDef minor-edit fill:#87CEEB
    classDef context fill:#FFFFFF
Loading

Notes

  • Cryptographic Risk: This PR handles private key derivation and export - any bugs could result in incorrect keys being generated, which is extremely dangerous for users' funds
  • Testing Limitation: The implementation was not fully tested with a running MM2 instance due to environment constraints - thorough manual testing is essential
  • Protocol Support: Handles various protocols including UTXO-based coins (Bitcoin, Komodo, etc.), Ethereum-based tokens, etc. with appropriate address prefix handling
  • Backwards Compatibility: The show_priv_key method maintains existing behavior for activated coins while adding new offline capability

Session Details:

@devin-ai-integration
Copy link
Copy Markdown
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@ca333
Copy link
Copy Markdown

ca333 commented Jul 23, 2025

Offline Private Key Export API Documentation

Overview

The get_private_keys API allows you to export private keys for coins that are not currently activated/enabled in KDF and/or while being offline (no network connection). This is particularly useful for offline key management and backup scenarios.

Supported Export Modes

1. Standard Mode

Exports the standard private key for each specified coin.

2. HD (Hierarchical Deterministic) Mode

Exports multiple HD-derived addresses for each coin within a specified index range.

3. Iguana Mode

Exports keys using the Iguana derivation method (legacy compatibility).

API Endpoint

Method: get_private_keys
URL: http://localhost:7783

Request Parameters

Parameter Type Required Description
coins Array[String] Yes List of coin tickers to export keys for
mode String No Export mode: "standard" (default), "hd", or "iguana"
start_index Number No Starting index for HD mode (default: 0)
end_index Number No Ending index for HD mode (default: 0)

cURL Examples

Standard Mode

curl --url http://127.0.0.1:7783 --data \
'{
    "userpass": "USERPASS",
    "mmrpc": "2.0",
    "method": "get_private_keys",
    "params": {
      "coins": ["BTC", "LTC", "DOGE", "KMD"],
      "mode": "standard"
    }
  }'

HD Mode

curl --url http://127.0.0.1:7783 --data \
'{
    "userpass": "USERPASS",
    "mmrpc": "2.0",
    "method": "get_private_keys",
    "params": {
      "coins": ["BTC", "LTC", "DOGE", "KMD"],
      "mode": "hd",
      "start_index": 0,
      "end_index": 5
    }
  }'

Iguana Mode

curl --url http://127.0.0.1:7783 --data \
'{
    "userpass": "USERPASS",
    "mmrpc": "2.0",
    "method": "get_private_keys",
    "params": {
      "coins": ["BTC", "LTC", "DOGE", "KMD"],
      "mode": "iguana"
    }
  }'

Response Format

Standard Mode Response

{
  "mmrpc": "2.0",
  "result": [
    {
      "coin": "BTC",
      "pubkey": "03...",
      "address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
      "priv_key": "L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1"
    }
  ],
  "id": null
}

HD Mode Response

{
  "mmrpc": "2.0",
  "result": [
    {
      "coin": "BTC",
      "addresses": [
        {
          "index": 0,
          "pubkey": "03...",
          "address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
          "priv_key": "L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1"
        },
        {
          "index": 1,
          "pubkey": "02...",
          "address": "1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2",
          "priv_key": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
        }
      ]
    }
  ],
  "id": null
}

Error Handling

The API may return errors in the following format:

{
  "mmrpc": "2.0",
  "error": "Error message description",
  "error_path": "offline_keys",
  "error_trace": "offline_keys:227]",
  "error_type": "Internal",
  "error_data": "Additional error details",
  "id": null
}

Common error scenarios:

  • Missing coin configuration: Coin not found in coins file
  • Invalid protocol: Unsupported coin protocol
  • Missing prefix values: Required address prefix bytes not configured
  • Invalid parameters: Malformed request parameters

Backwards Compatibility

The existing show_priv_key method has been enhanced with offline fallback functionality. If a coin is not currently activated, it will automatically attempt to derive the private key using the offline export functionality.

Legacy show_priv_key Usage

curl --url "http://127.0.0.1:7783" --data '{"userpass":"USERPASS","method":"show_priv_key","coin":"KMD"}'

This will work for both activated and non-activated coins with or without internet connection, maintaining full backwards compatibility.

@smk762
Copy link
Copy Markdown

smk762 commented Jul 23, 2025

can we please also add input for account_index?

Update: resolved ✔️

@smk762
Copy link
Copy Markdown

smk762 commented Jul 23, 2025

Table in prior comment indicates start_index and end_index default to zero.
In testing, this was found not to be the case.

  • omitting both params outputs for the addresses from index 0 to 10 (11 items).
  • setting start_index only outputs for the addresses from index start_index to start_index + 10 (11 items).
  • setting end_index only outputs for the addresses from index 0 to end_index (end_index + 1 items).

@smk762
Copy link
Copy Markdown

smk762 commented Jul 23, 2025

No errors returned when using start_index or end_index params in mode: standard, mode: iguana or when mode is not set (defaulting to standard). It would be good to return an "invalidParams" error (or similar) in these cases.

Update: resolved ✔️

@smk762
Copy link
Copy Markdown

smk762 commented Jul 23, 2025

I noticed that in mode: hd, a coin such as BBK which do not have a derivation_path value set will still return a response:

            {
                "coin": "BBK",
                "addresses": [
                    {
                        "index": 0,
                        "pubkey": "034ba1a9d6d275eb0749f17005e944d17bbe0d1eb3eed03960cc4d454e8797af23",
                        "address": "BLr7Axhbmz5B8oVZ6HXo81nhiF2CTH6CbM",
                        "priv_key": "GqbDKxbKEgcsP4tCcz15czd67ABzD1dYPh6fVgEvzcySNmeYKhYP"
                    },
                    {
                        "index": 1,
                        "pubkey": "03dcb8565e389b6aa04e00470e10b4dc6ddc2e2ce7189983d4da342f685402074e",
                        "address": "BBmrEwNgMfzXA2hpCSuiE42Tjr4BUsd9yX",
                        "priv_key": "Gy6mtEFi1evnTizY3QqEHDkqY6JyWkRwsU9Vd9EVRv6RyNdESULM"
                    },
                    {
                        "index": 2,
                        "pubkey": "03a7bfe05927de5e7f0959effc10d165d8009ae78c9b7553c3a9e14be8cf7519a9",
                        "address": "B5CrqcW7TLSesceTT3jH35RdL8vSPDn6pu",
                        "priv_key": "Gwn1ZcBfCvLG954Js2d6womB8wsv6UDvMYboZJNdxAXZLngJoK9L"
                    }
                ]
            }

Without knowledge of the purpose and coin_type portions of the derivation path, or if using default values, this may result in incorrect information being returned.

For example: BTC and BCH share the same base58 params, but have different derivation paths (m/44'/0' and m/44'/145' respectively), resulting in different pub/priv/addr.

            {
                "coin": "BTC",
                "addresses": [
                    {
                        "index": 0,
                        "pubkey": "035a843f39a7fc686148c5e52ffebb41e84fbfefb3fdd2d64e5e82fddfbb0450ab",
                        "address": "1CRQnAaShSLH324WmZg4qhvfUW7tnkTqmZ",
                        "priv_key": "Kzzs67GWowSZjz9wJcLAR6h7Z2sDa1HUyvFCqKtH4FKG5fQ1PLoB"
                    }
                ]
            },
            {
                "coin": "BCH",
                "addresses": [
                    {
                        "index": 0,
                        "pubkey": "03c5db6d5b4a15d5a14d90a8d13bf8e7d54855daaecff7595b0bb9ef7beb91c5d4",
                        "address": "1L3dsQN1RfXsbk58dtz1UQqC4UyeeB1pMa",
                        "priv_key": "L3Pn8DWSuSwAmwSHYi2Nuo2VsJCKTpYurcuuvmBZjriEqownmpYc"
                    }
                ]
            }

Based on this, I believe we should avoid using default values for the purpose / coin_type parts of the derivation path, and return a KeyDerivationFailed error for mode: hd requests for coins which do not have derivation_path defined.

Update: resolved ✔️

@smk762
Copy link
Copy Markdown

smk762 commented Jul 23, 2025

In the response, the index field is a little vague, as it is not clear if it is the address index or the account index. Could we please replace this with the full derivation path so that all parts are visible? Example response:

            {
                "coin": "BTC",
                "addresses": [
                    {
                        "derivation_path": "m/44'/0'/0'/0/0",
                        "pubkey": "035a843f39a7fc686148c5e52ffebb41e84fbfefb3fdd2d64e5e82fddfbb0450ab",
                        "address": "1CRQnAaShSLH324WmZg4qhvfUW7tnkTqmZ",
                        "priv_key": "Kzzs67GWowSZjz9wJcLAR6h7Z2sDa1HUyvFCqKtH4FKG5fQ1PLoB"
                    },
                    {
                        "derivation_path": "m/44'/0'/0'/0/1",
                        "pubkey": "0217f00e1d569b5b648c679f615e67be50eb6c1b9d1da9e0d5b5187093dd9701e4",
                        "address": "1Aby1HDmYQQVHA7KsG2PuURGR4BTgS9ynT",
                        "priv_key": "Kwn5NnGB5dpNTM2VzFNTBZ5PmpCn93T9RdS1a76bquAA8UcuGzXf"
                    }
                ]
            },
            {
                "coin": "BCH",
                "addresses": [
                    {
                        "derivation_path": "m/44'/145'/0'/0/0",
                        "pubkey": "03c5db6d5b4a15d5a14d90a8d13bf8e7d54855daaecff7595b0bb9ef7beb91c5d4",
                        "address": "1L3dsQN1RfXsbk58dtz1UQqC4UyeeB1pMa",
                        "priv_key": "L3Pn8DWSuSwAmwSHYi2Nuo2VsJCKTpYurcuuvmBZjriEqownmpYc"
                    },
                    {
                        "derivation_path": "m/44'/145'/0'/0/1",
                        "pubkey": "0235068668d119b8dbf50a6888f35f783aaeefcbf2ef4f23052a6814e0c6165123",
                        "address": "14oZPGZmWTAaZvUJb6yxk2gMU7kinPacCB",
                        "priv_key": "L4UApWP5WqGbNKTjZwdDHVD6KsgSpWijUYdPPV34BDmaH7TqRd5h"
                    }
                ]
            }

Update: resolved ✔️

@smk762
Copy link
Copy Markdown

smk762 commented Jul 23, 2025

When requesting a response for a coin which does not exist in the coins file, the returned error is

{
    "mmrpc": "2.0",
    "error": "Internal error: Failed to parse protocol for COVID",
    "error_path": "offline_keys",
    "error_trace": "offline_keys:331]",
    "error_type": "Internal",
    "error_data": "Failed to parse protocol for COVID",
    "id": null
}

This error does not adequately explain the root cause of the problem, which is that COVID does not exist (in the coins configuration file), so a CoinConfigNotFound error is more appropriate.

Update: resolved ✔️

@smk762
Copy link
Copy Markdown

smk762 commented Jul 23, 2025

While testing high values via postman, a response was received as The RPC service aborted without responding. Console logs showed:

2.0 p2p.received_messages.count=0.0 p2p.received_messages.period_in_secs=60.0 p2p.relay_mesh.len=2.0
23 06:38:37, common:525] panicked at /home/smk/GITHUB/KP/komodo-defi-framework/mm2src/coins/rpc_command/offline_keys.rs:544:53:
attempt to add with overflow
23 06:38:37, common:526] backtrace
  panicking.rs:676] rust_begin_unwind 0x60137133795c
  panicking.rs:75] core::panicking::panic_fmt::h24e6103767c0d03d 0x60137135e59f
  panicking.rs:178] core::panicking::panic_const::panic_const_add_overflow::hbb06823529aae6cf 0x601371368476
  offline_keys.rs:544] coins::rpc_command::offline_keys::get_private_keys::{{closure}}::hf7fd9a968b93f3ad 0x60136cbe493b
  dispatcher.rs:127] mm2_main::rpc::dispatcher::handle_mmrpc::{{closure}}::hc5c1be81d1497ace 0x60136d329e80
  dispatcher.rs:227] mm2_main::rpc::dispatcher::dispatcher_v2::{{closure}}::he34427b73fd5a5e0 0x60136d3458b5
  dispatcher.rs:100] mm2_main::rpc::dispatcher::process_single_request::{{closure}}::h55476e6c28f4ca45 0x60136d2d3745
  rpc.rs:210] mm2_main::rpc::process_single_request::{{closure}}::hbbff86fa365ad223 0x60136cbd4612
  rpc.rs:166] mm2_main::rpc::process_json_request::{{closure}}::hc83e52cd3654a2d3 0x60136cbd3432
  rpc.rs:247] mm2_main::rpc::rpc_service::{{closure}}::process_rpc_request::{{closure}}::he3817059b296ca8f 0x60136cbd7b7e
  rpc.rs:282] mm2_main::rpc::rpc_service::{{closure}}::hb81abf8a9b7af25b 0x60136cbd6a1a
  rpc.rs:351] mm2_main::rpc::spawn_rpc::handle_request::{{closure}}::{{closure}}::h74b89b84eb0b0dbc 0x60136cbd8c00
  unwind_safe.rs:272] <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once::h3e05c0d1f9c3c8a2 0x60136d7add60
  ??:0] __rust_try 0x60136d7974ea
  task.rs:42] <tokio::runtime::blocking::task::BlockingTask<T> as core::future::future::Future>::poll::h7881e505c4fbb207 0x601370fa5743
  unwind_safe.rs:272] <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once::h943c3e231c0568cf 0x601370fa0f80
  ??:0] __rust_try 0x601370f652ca
  unwind_safe.rs:272] <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once::hca11c87d3b4ba599 0x601370fa0fe0
  ??:0] __rust_try 0x601370f7482a
  pthread_create.c:447] start_thread 0x7f54b329caa3
  clone3.S:78] clone3 0x7f54b3329c3b
Virtual memory addresses of /home/smk/GITHUB/KP/komodo-defi-framework/target/debug/kdf  PHDR:0x601369e17040  INTERP:0x601369e172e0  LOAD:0x601369e17000  LOAD:0x60136be16a00  LOAD:0x60137136d600  LOAD:0x601371831970  TLS:0x60137136d600  DYNAMIC:0x6013715dd170  GNU_RELRO:0x60137136d600  GNU_EH_FRAME:0x60136b225344  GNU_STACK:0x601369e17000  NOTE:0x601369e172fc

This happens where account_index > 4294967295 or start_index > 4294967285.

higher values for end_index return an errortype as expected, without panik! in console.

{
    "mmrpc": "2.0",
    "error": "Error parsing request: invalid type: floating point `4.294967299566574e27`, expected u32",
    "error_path": "dispatcher",
    "error_trace": "dispatcher:126]",
    "error_type": "InvalidRequest",
    "error_data": "invalid type: floating point `4.294967299566574e27`, expected u32",
    "id": null
}

Update: Resolved ✅

@smk762
Copy link
Copy Markdown

smk762 commented Jul 23, 2025

mode: iguana & mode: standard output correctly matches legacy desktop values for ETH / LTC / LTC-segwit (regardless of enable_hd value in MM2.json ✔️

image

You can use these values for unit tests for these modes, with the passphrase february soldier message acid member jump shadow walk novel impose puppy tornado.

{
    "mmrpc": "2.0",
    "result": {
        "result": [
            {
                "coin": "MATIC",
                "pubkey": "02799068e257fb4d026b160dbb1a0b1a6c8076d4505a52181bb64dd61590f59fae",
                "address": "0x8c40a6e127c7a13e26ce95dea88354c3fb134580",
                "priv_key": "0xe80e8473bce27d58bcd53f55c8dce41745364360e243490b904faef355f0ee6b"
            },
            {
                "coin": "LTC",
                "pubkey": "02799068e257fb4d026b160dbb1a0b1a6c8076d4505a52181bb64dd61590f59fae",
                "address": "LMhCwCpZBDAj55y88z3g77tp8nF3PRbmEr",
                "priv_key": "TAq4jACPNBGF9Gx8V3i91FFLtQHS6tgUN23ExUg6U5h7pf2XYe5g"
            },
            {
                "coin": "LTC-segwit",
                "pubkey": "02799068e257fb4d026b160dbb1a0b1a6c8076d4505a52181bb64dd61590f59fae",
                "address": "LMhCwCpZBDAj55y88z3g77tp8nF3PRbmEr",
                "priv_key": "TAq4jACPNBGF9Gx8V3i91FFLtQHS6tgUN23ExUg6U5h7pf2XYe5g"
            }
        ]
    },
    "id": null
}

@shamardy
Copy link
Copy Markdown
Collaborator

Can we please follow PR titles and labels standards according to the following
https://github.com/KomodoPlatform/komodo-defi-framework/blob/c5f544ce7b9cf7eeb09a5d8e7b45a65cae4e3fc7/.github/workflows/pr-lint.yml#L13-L56

devin-ai-integration bot added a commit that referenced this pull request Jul 23, 2025
- Change GetPrivateKeysRequest.mode from KeyExportMode to Option<KeyExportMode>
- Add serde default attribute to mode field
- Update get_private_keys function to default to HD mode when ctx.enable_hd() is true, otherwise Iguana mode
- Addresses GitHub comment by shamardy requesting optional mode parameter

Resolves: #2542 (comment)
Co-Authored-By: ca333 <ca333@users.noreply.github.com>
@CharlVS
Copy link
Copy Markdown

CharlVS commented Jul 23, 2025

Since we require the wallet password for mnemonic export, we should consider requiring it here (and all other future/wip priv-key RPCs) since you could dump the private keys for all coins in a single RPC (same as having seed phrase). The show_priv_key should be deprecated and throw an exception if used for non-legacy wallets (backwards compatibility) and eventually disable non-password access entirely.

Though, it would need further thought on how to handle wallets launched using the seed only (no wallet_name). Either require the seed as authentication for show_priv_key or allow access without a password since the user will have had to already provide the seed at launch (not a fan tho)

@shamardy shamardy changed the title feat: implement unified offline private key export API feat(wallet): implement unified offline private key export API Jul 23, 2025
@shamardy
Copy link
Copy Markdown
Collaborator

You should add some unit tests and make sure they work, here are some test vectors for some coins:

mnemonic: prosper boss develop coconut warrior silly cabin trial person glass toilet mixed push spirit love

BTC:

Path  Address  Public Key  Private Key 
m/44'/0'/0'/0/0 1DWZWURWrdJnuZBqQgv3THfmhbxWgJuFex 037e746753316b028859ff20bac70ed4803a3056038e54ef86f71f35e53a6c8625 KywJqZF9PrFSwWkocQ4JZSgfTD3eXYbfnM54Q3Ua7UKzGD4WTRbX
m/44'/0'/0'/0/1 17jQZo8xSjJeQLxexLZSZaBA9ks5tWh3fJ 030bd2b7ab3800a968544bb097a78c1ecfed233af342359e399d72fd970aa35323 KwLRhtqifoX1FuMFJytB85DCZf6YoSjuFSqPXBzPsyi56GXJaVpD
m/44'/0'/0'/0/2 13ZwKLGksE72YgMdKjJC9XZPM6TcpejJrJ 034bf56e7072f8f378a8efee382c9a438fa4b4c98c387d4a0db543afc434c4adaf L5kmC8cqWodyjm2JUQNfRbmyZeJMJMeYH4WJGUSVcdnD9X6aAs8Z
m/44'/0'/0'/0/3 1DXZSngSWk2EHJ5pWm2mKJR8Vn8xykomCG 02b80146def83c111e75371dd25ea119c9bf7ce8fb5e6cd634e3e99b22301a7d53 KyH1tWmWLvS45kh2MvRfhpKuW1HRPmZsceJDp9azLKsBGbHYN9af
m/44'/0'/0'/0/4 15WjN8CQU1HkLSrhNWL1QktmA9GEm2pJV5 027ca49323b5b214a44050dcb436756d36d1903caf4f94040ba4970fc4f40db6d3 L1rAQAN6WWbMxJM85uLtU4R5UPpiEZ6gSUNyQ78zh4aWhSq2MqdA
m/44'/0'/0'/0/5 1AhGmsc4MiUqC6HFbwCrekjPjaPXeU8c3U 02e0454fd990eb77600f1563c6973a03742055ca983c42cb9e075e1fb35c95566c L5mSNpwLTnaSWyMA5fTxzHrsz2pPXHCrpfDM5Vo87NLoR3i9wYcR
m/44'/0'/0'/0/6 1JdBYyPZ8BMSw95bXvc6Tkt34iNvdiXSm 02ed9e281e27689f39a0a8bbe6e73e42e266638246c15ba9815a221e792a168ceb KxvH3A1LmyYeCLnFjsDjq4eqZSbsNLxRcF1EeXtfAyWmLAT1rmRw
m/44'/0'/0'/0/7 18csp6LGkCmSehoqd4CHLUACFteUkpNbUu 02a6ee7221497e23a9ee441313b5ff6307f814cae05b4c6ee20944295e0367ab55 KzB5ZkwCxXT5u7Le3dBXgQMVEuDyWf7RYgP21N4rp9V9fn3bmch2
m/44'/0'/0'/0/8 18i2JMjka8TMjkEMXi9HDghZh2jGT5ZQ62 02d01e41defebe547e784c2d98460f9e3cc104998c09192c49b14f8c3317f48a1a Kxe6VcgjU4KrM99jMZjhCkCCUVgkZ17vNz6G3fmPXu8C23g5sSG1
m/44'/0'/0'/0/9 1JXxFXC1byE1G1PQrYNkrjXjfdUE43ybJp 02217185cf5a2369b97f4c37177421a85094221cec1aa61a6cd67bd0a5426ff647 L2Hm5A9KJN636T9Wg9bZQXDZcCNm7PshmLhYFCZKC2GVYyhrz3n1
m/44'/0'/0'/0/10 184eJRuy3ye4byKSYjBK8trotMMHkzvVyS 0265f4bbc3e66c3902548695a6fd8b118d8db776f8fcb638422ff2f0d87d9ce827 L1xLejxSH563Zdx8msxSAG5RcDQkJbXjwxopGa2Z9jUbQ5BCfrVd

BTC-Segwit:

Path  Address  Public Key  Private Key 
m/84'/0'/0'/0/0 bc1q4cn6qhvuajkdfhk3fzuup07ktrepcukc8hv0c8 024b796b083b51ea5820bbdb80fa4e7f09f5f8c6fe76bc68fa2d8d0452a4ddfa91 L2aJGVhekAig5a4Zx81NH9Q99h9gH7umiyqBWXrNX5w8xn2eeU5g
-- -- -- --
m/84'/0'/0'/0/1 bc1qv26wdgw5vqf7fcup92yhjmm234zwd2wrgv5f4f 0272a14e54bbfa321f7afa8d98b478f7e5bea5440f3e807bd87f5c00f75ef0941f L1susQQK5CaP7eT4MKyAzv8KthN53i5gHJmUGtKksY8r2Hbvvyv6
m/84'/0'/0'/0/2 bc1qvs2pggxxcl40n9cs9v9crkclmrx57hgp5f6579 03e10fed91ec91740c726b945671954c040cd42b3ad9ab5791133f1a33d4c42e5d Kz937rcd2Hack7TUgkcg3YAiSbTGGJciMCzFbu76FkJgZkwb5zES
m/84'/0'/0'/0/3 bc1qfsgtpl8r6wq86jxjh09khxrnqrga08lhahyclq 0289c31869518ac689a355b5de34a37cc138d3dd792a3501d2061ff57f00832fab KxmKL5oecYUFhokh5VSXsCGZSzN11SZjRikr6TMEKVdZ1zVzEgX2
m/84'/0'/0'/0/4 bc1q6j4t6xk2h6xgy2numpvw34l4nvdtgj85u69nts 037f3e43a93632fa4a68c399818687adc98e12c961df72be5200cb0b06cc22bd07 L3DgA9Phr6URSuvU2RF5R8w5jGAynEGEJhppPZip8QtPRNMcX59b
m/84'/0'/0'/0/5 bc1q6wrkq6amfqqsasclj8psnat6qhjth4gp2qv79h 028870c199e17e15180176903d0a066a9bc9d4e0c76dbd4c6e724bcf6207bb0d0b L1QNcEemGdAoXUzhkrUQ7MLf6tD2spHkzpgkNqxRJUqKSh8mAKMP
m/84'/0'/0'/0/6 bc1qzxql37zxv3nsu5e26z7mjcn3sa38g6scv8mvm2 02fe7dfb6f7c4daf37e92b824606b90aae1517953e68cdd8aeffb66bcc95917372 KzCEqom9vBMZAGyphsVC45T9b41Vx9fsZctCwsfEprmsP9ab5VFm
m/84'/0'/0'/0/7 bc1qmjlehz4qzgygxp7tn5dkvestf65fewf3y0hxp0 0269bb50666117ae6c3d0434bc063d9be03ac9ee96c6bac8bdad6e21877b619289 KzgiSTfgW3Ljk7gxQNCu1qZLozDfBRLFVZCe9RUr1SCbhMynC9VW
m/84'/0'/0'/0/8 bc1q8c7584eck6w2ddmrkmnegpygnsqsmppc7k2txv 025eb24c3de170de3d41c10422675d823cbf902025b2071d7aa1ab14846aaffbff L1qbiT31eaokoC49idCJd1Gx63BhMMEvo4KnYPHaWLzh7kqG8ifj
m/84'/0'/0'/0/9 bc1qlx89fzjuylgq6a8ghrcpfeyhfk9dnmhslcpfyd 029bf61654bf653e983bf6dd246b806c2348d3eca4c3a86eebf141b391d5b15f7a Kxgjq23cfTeDj2N6bxsoBXcSzRh7zHWgnhK2T7YDACLz4atDLUE7
m/84'/0'/0'/0/10 bc1q2ftzdc40n74a3zq8u8a93vasayvcwurfqexp3f 032b8c36f2c8a5e12c3e5d6e1f612536e88c9570c24d0b628b36bc18db3c5e5882 L269VEm3skqxP6MS8gEPsy6RWEbPPPGVRmtwvZ9kCh8yR4EmrojU

ETH:

Path  Address  Public Key  Private Key 
m/44'/60'/0'/0/0 0x6B06d67C539B101180aC03b61ba7F7f3158CE54d 0x02a2b68c3126ba160e5ffb7c0d5c5c5c56e724f57e5ec0ace40d6db990e688ed4a 0x646431107ae37e826aaa5108fe2c2611ef15615e78b4175919b85fd6366f19a3
-- -- -- --
m/44'/60'/0'/0/1 0x012F492f2d254e204dD8da3a4f0d6071C345b9D1 0x02d7efb9086100311021166c11b2dc7ca941ccbe242b51206555721efe93737678 0xc11fc3d704820e752bfae8db9f02e489c1e742392b35ac5b4a4e441e7955efa4
m/44'/60'/0'/0/2 0xa713617C963b82429909B09B9181a22884f1eb8f 0x03353b68f1b2c0891edf78395480bc67e128fb967c5722a6b41d784da295986d4d 0xddb38472a7d7095ad466b4a4e19f85f612f87e04a23c75eac8e7957d31ee22f0
m/44'/60'/0'/0/3 0xb5B8771202557BFd39DD0aF4DBd866d07Eb681eb 0x02dacf2657414d52658caa0a2ed2f2a05b402db3d26a9742e18c37c2eccf913fc2 0x8aebb36f4f1381e6012607e4cdbbff1c4e314abe3a4d65bdd869f6310d30f881
m/44'/60'/0'/0/4 0x0dA7bF602Ee906F966530114305f463968189cBB 0x026af00351b13e38c68721fde1b3e0737def344d098a9975c7d62047a4e366fa95 0x194f331d9b261108b4d43c1a955588845c9e0b2a6ae2b96a838150f3799da103
m/44'/60'/0'/0/5 0x1705e93FBD89320D9DE51C0a24c299c21eA65f5A 0x0294267ecefa419918dbad9e8154f7199cde5ea999ff5e87c36acfe100be37e4cb 0x2e36f031f064ef7195e1ff0f86f75ad8209d04abf4c1bd68e6fe91b572674ac3
m/44'/60'/0'/0/6 0x0cD81203a255C455252fE1d008d2a9531c665500 0x025e639cf346f4737f6735dc9e12dadc35564e19b07b8b5a0f687c6079bdddb610 0x18e604cb69d63883dbae7703021c3c38da8c6022db578f583f657ae0c106e245
m/44'/60'/0'/0/7 0x03a653366aC28F62daaD27dd8D842AE63becA583 0x031e07fbc033cd9d87ba159d5e7e3d3f82c0135e9ee5c4d10daf815a26ee006f23 0x3b79b2d7b08872f359c9b9781779fdbd49f0d3b315ac5ead0957c8ebd5c9defd
m/44'/60'/0'/0/8 0xFb1428D03B4C5f12651156F87ef8c80958795f02 0x028a26a577fb76e1a1d1151f144d60d39f7165bfa5ccba16f12bc3e783983cb02f 0xb88c4318481b2165be514ad87ff7d572054522ef73cc46c6658e7443eacd623d
m/44'/60'/0'/0/9 0x043bE2D18B4eE973cD5b293E8f1698Ae84518fB3 0x026729dfe0a3db7d97b7657f39ca17fb12797f2ecd26b61c2f178c6a4bad54de89 0x97f031f1e1922674ea9ee0ff73ff78b544c4d8d6fb8ceb6858e65bbb5b9df033
m/44'/60'/0'/0/10 0x21ee0774E41C6E25EF23dD2AA7Ed268f3483554B 0x03f31db52f4ea7928f77a2cb5db6ee349460fa008d78666b5316ab394eccd1fecb 0xa62756c4df2e85919d91a25771c647bca3c13cebb47bfa36f1052b903631a3d4

Atom:

Path  Address  Public Key  Private Key 
m/44'/118'/0'/0/0 cosmos1j398pch49fkgx986r4aqm57zp3phuzq4p30dhh cosmospub1addwnpepq09wmcqe8qvcmyvgre8g07q9z42rz6y7uguz5dxqvhw0tdrqa38csd8wlfa Nbfdi2ZHb+2W41DNJPaHxAi6oHcJ4lFLtBZkATGAB8M=
-- -- -- --
m/44'/118'/0'/0/1 cosmos1cecqkvtwn0vyr730yq3hawrl8rztvchz6kadk8 cosmospub1addwnpepq0uy8zghd8q8p5wjvz84catqgwuwem45s5rpvd9syq44jz2jmyqfvp049kz 8FJrDCXtcLl6OgjqF/l5QQvUYYpjwGn+F3q3pBp3e94=
m/44'/118'/0'/0/2 cosmos1c27v3agv745fhnjve8ch754rmzswuc7guglt76 cosmospub1addwnpepq2hrktz6ps2cal4hdya06g5hmyjzgj7m0aygwkzayd93vvcr7vd6uuw0ta0 VMDIUc2jiqX3jdLCtwR1ebmPiEIKE9yxXxsfTczoCWY=
m/44'/118'/0'/0/3 cosmos1jv30lxvmp9kttcmq3e7lu305prje6ry53m46h4 cosmospub1addwnpepq20j00x2s2lry9ujvw5g8xzpk7jsp83lxqwt5azze8pn8dpul7slks2aq8z 7tRbSkhKHtrLERxSL4KHbMr4vcTA0cCwugGiYW6hAnA=
m/44'/118'/0'/0/4 cosmos1fsy53ufwa7ahzcx28qpl5jddjxf97cmr6whjcv cosmospub1addwnpepqdp4dxaa6jnlwz2as43axaqzpgklffrr4knzzszeunnnnwxs9etesedphlf 2Y44A56CNcTFfriACkMYTr0z7pB/mAhEp470r+sO6hc=
m/44'/118'/0'/0/5 cosmos1kcfs2mf4k6jnm9dmjfqpq4clzdlsu747urgepm cosmospub1addwnpepqg7s2zryqyvadpay08mj8p244negrdsr79cv4lrenl8mzv4qkltygrd9js8 RkX/MS6W+DsUfrIEybj0/3X/IwW4bbXPGb5RDj9QLwM=
m/44'/118'/0'/0/6 cosmos16e24zsxkyhklgcdvvc5x3ct7y29jfmsl25akcs cosmospub1addwnpepqvv4v93xlcm3t0nlzlg5ry2zltxtgry668yk0qrh0rtz5wl43vyu68xcg7h r40MGxESA1zbZM0Fp3yQ81gq0BLM6wx5TpbhlVrkzxo=
m/44'/118'/0'/0/7 cosmos1ey7r3ju68k03gw83n9tjw7t5xyccgce2l9u275 cosmospub1addwnpepqfxdzd22rphgejfq6a9qcj23gr8jd4ax3cdr6xacskw7k2qetgpdjs489sh 37RPFEAENOjHQtV/R7kuuhkxkNqsCV2FHz+BVt9Z0OU=
m/44'/118'/0'/0/8 cosmos19jur8044v69yjw22exvfqfknvt5rjsagmjwhw9 cosmospub1addwnpepq2kqkf7zdaqfjujllh23zjj2th4hz7ygfthsjl04ymrf9c2745sycfc8sqk PJ90lTDBK+oqKKWHNoCBU+cp6YSjO0up4n/mUpaXerc=
m/44'/118'/0'/0/9 cosmos1s2r9sy8ya2cdxcg485mra8kpm366h777xav3a2 cosmospub1addwnpepq2rds3d396rwnthuqe88qyal7j60j4dukv9mj68qu6830ztjhdqac9jr8gl Z6NpPVQiSWosauzN3KbSkCcc2T94bFiTkJXHr5sJSss=
m/44'/118'/0'/0/10 cosmos1twd85ljwyp3ehfevj4yqat2xqxp02vxv7ga2ra cosmospub1addwnpepqda60e29z933xq6p2lync2hu8jvte85hgrvwxkdstp3c3vst32y2u5yqjgv N2m+0BMR95HzCC7et53675VbxfJHXGZ1ELUCDsWOdh8=

@ca333
Copy link
Copy Markdown

ca333 commented Jul 23, 2025

thanks @shamardy - issues were addressed in 46088b1

@devin-ai-integration
Copy link
Copy Markdown
Author

Devin is archived and cannot be woken up. Please unarchive Devin if you want to continue using it.

@smk762
Copy link
Copy Markdown

smk762 commented Jul 27, 2025

For all coin protocols, in iguana mode (MM2.json):
- the same privkey string is returned for the same coin with legacy (online), v2 (offline) and v2 (online).
- v2 requests with mode: hd return error as expected.

Note that output for Tendermint and segwit keys may be non-standard:
- ATOM matches ETH, minus the 0x. Format correct, but coins technically have different type values (118 = Cosmos; 60 = Ethereum)
- Segwit output is same as non-segwit output for the same coin (e.g. LTC/LTC-segwit). This is a known issue with legacy privkey export.

For all coin protocols, in HD mode (MM2.json):

  • v2 requests with mode: hd returns results which appear to be a valid format.
  • v2 requests with mode: iguana only returns an error for ZHTLC protocol. All other protocols return a successful response, with iguana keys, matching those output when running KDF in iguana mode.
  • legacy requests return single private key, same as the private key from v2 results at account/addess index 0/0.
  • Segwit output differs from non-segwit output for the same coin (e.g. LTC/LTC-segwit), as expected.
  • ATOM and ETH privkeys differ from each other as expected.

@smk762
Copy link
Copy Markdown

smk762 commented Jul 28, 2025

Output validation tests

Address index: HD output at account/address index 0/1 was compared with https://iancoleman.io/bip39/ as the source of truth.

  • BCH
  • KMD
  • tQTUM [confirmed via https://qtumwallet.org/]
  • ETH
  • ARRR [confirmed via https://github.com/PirateNetwork/piratepaperwallet] & ZOMBIE native daemon
  • LTC
  • LTC-segwit
  • ATOM [Address matches IanColeman, but pub/privkey format does not. Importing the KDF privkey export into https://chromewebstore.google.com/detail/cosmostation-wallet/fpkhgmpbidmiogeglndfbkegfdlnajnf returned the same address without errors, so will mark this as passed because Cosmostation is fine with it.]

Account index: HD output at account/address index 3/3 was compared with https://iancoleman.io/bip39/ as the source of truth (except where otherwise marked.

  • BCH
  • KMD
  • tQTUM [confirmed via https://qtumwallet.org/]
  • ETH
  • ARRR [confirmed via https://github.com/PirateNetwork/piratepaperwallet] & ZOMBIE native daemon
  • LTC
  • LTC-segwit
  • ATOM [Address matches IanColeman, but pub/privkey format does not. Importing the KDF privkey export into https://chromewebstore.google.com/detail/cosmostation-wallet/fpkhgmpbidmiogeglndfbkegfdlnajnf returned the same address without errors, so will mark this as passed because Cosmostation is fine with it.]

Additional comments

ETH privkey output is in lowercase, rather than mixed case. Sometimes this triggers validation check failures in third party input fields. Ideally we should conform to https://eips.ethereum.org/EIPS/eip-55 for this output.

The convertaddress RPC for this operation exists for baackwards compatibility with legacy output, but all new RPCs should perform this operation prior to output where required.

devin-ai-integration bot and others added 9 commits July 28, 2025 11:02
- Revert show_priv_key function to original behavior without offline fallback
- Remove KeyExportMode::Standard from offline key export API
- Remove offline_keys_export_internal function
- Make mode parameter required in GetPrivateKeysRequest
- Update API to only support HD and Iguana modes

This addresses PR feedback to avoid confusion in HD mode where the fallback
would incorrectly derive legacy Iguana private keys from HD wallet seeds.

Co-Authored-By: ca333 <ca333@users.noreply.github.com>
- Change GetPrivateKeysRequest.mode from KeyExportMode to Option<KeyExportMode>
- Add serde default attribute to mode field
- Update get_private_keys function to default to HD mode when ctx.enable_hd() is true, otherwise Iguana mode
- Addresses GitHub comment by shamardy requesting optional mode parameter

Resolves: #2542 (comment)
Co-Authored-By: ca333 <ca333@users.noreply.github.com>
- Remove unnecessary #[serde(default)] for Option<KeyExportMode>
- Remove wallet_type checks since this field doesn't exist in coin config
- Move get_private_keys import to top of dispatcher.rs file

Co-Authored-By: ca333 <ca333@users.noreply.github.com>
- Add PrefixValues::Tendermint variant with account_prefix field
- Update extract_prefix_values to handle TENDERMINT and TENDERMINTTOKEN protocols
- Add Tendermint support to both HD and Iguana key export functions
- Use tendermint::account_id_from_pubkey_hex for address generation
- Format private keys with 0x prefix for consistency with other non-UTXO protocols
- Support platform lookups for TENDERMINTTOKEN protocols

Co-Authored-By: ca333 <ca333@users.noreply.github.com>
…ermint protocols

- Remove 0x prefix from Tendermint private key formatting in both HD and Iguana export modes
- Keep 0x prefix for Ethereum protocols as expected
- Addresses shamardy's code review comment about incorrect Cosmos private key formatting

Co-Authored-By: ca333 <ca333@users.noreply.github.com>
…tests (#2547)

* feat: implement proper BIP39/44 HD key derivation with comprehensive tests

* fix: apply cargo fmt to resolve CI formatting issues

* fix: correct BTC-Segwit test vector private key and ensure all tests pass

- Fixed typo in expected private key for BTC-Segwit test vector
- All 6 offline key tests now pass successfully
- BIP39/44 HD key derivation implementation verified as compliant
- Segwit address generation working correctly with proper AddressFormat detection
)

* feat(offline-keys): add ZHTLC offline key export support for ARRR

* fix(offline-keys): apply cargo fmt formatting fixes

* feat(offline-keys): implement actual ZHTLC key derivation for ARRR

* fix(offline-keys): apply cargo fmt formatting fixes

* fix(offline-keys): resolve compilation warnings by renaming unused variables
* fix: remove nested result field in offline key export response

- Remove result field from IguanaKeysResponse and HdKeysResponse structures
- Update internal functions to return data directly
- Update GetPrivateKeysResponse enum to handle unwrapped data
- Update all test functions to work with new response structure
- Fixes nested 'result result' response issue

* fmt code

* fix: replace vec! with array literals to resolve clippy lint errors

* fix: remove needless borrow in tendermint account_id_from_pubkey_hex call
@shamardy shamardy force-pushed the offline_key_export branch from e43c589 to 9d48928 Compare July 28, 2025 08:02
shamardy and others added 3 commits July 28, 2025 11:22
…2552)

This commit refines key and address generation for all Ethereum-based protocols (ETH, ERC20, NFT) to align with standard ecosystem conventions.

- Public keys are now generated in the uncompressed format, which is necessary for correct address derivation.
- All generated Ethereum addresses are now formatted with the EIP-55 mixed-case checksum, providing an integrity check against typos.
- The public key display format in the RPC response is updated to use the standard `0x` prefix.
- Tests have been added and updated to validate the new address and key formats.
@smk762 smk762 self-requested a review July 28, 2025 12:00
smk762
smk762 previously approved these changes Jul 28, 2025
Copy link
Copy Markdown

@smk762 smk762 left a comment

Choose a reason for hiding this comment

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

LGTM

shamardy added 4 commits July 28, 2025 17:03
The `get_private_keys` RPC previously handled Z-coins (ZHTLC) incorrectly by treating them like UTXO-based coins. This resulted in several issues:

- It looped over an address index, attempting to derive multiple addresses for a single account, which is not how shielded accounts work.
- It displayed a misleading derivation path that included an address index (e.g., .../0/0).
- It generated and displayed a `secp256k1` public key that was irrelevant to the shielded address.

This commit refactors the logic to handle Z-coins as a special case:

1.  Key derivation for Z-coins now correctly stops at the account level, ignoring the address index.
2.  The RPC returns a single, accurate entry for the Z-coin account instead of a redundant list.
3.  The `derivation_path` in the response now correctly points to the account (e.g., m/44'/141'/0').
4.  The inapplicable `pubkey` field is now empty to avoid confusion, and the `viewing_key` is correctly populated as the relevant "public" component.

The existing behavior for UTXO, ETH, and other indexed coins remains unchanged.
The pubkey field is now empty for Z-coins in both modes to avoid confusion, as a standard secp256k1 public key is not used for shielded addresses.
The key derivation process for multiple coins has been refactored to run concurrently. The sequential `for` loops in `offline_hd_keys_export_internal` and `offline_iguana_keys_export_internal` are replaced with `futures::future::try_join_all`. This significantly improves performance when exporting keys for several coins at once by executing the CPU-intensive cryptographic operations in parallel.
The `get_private_keys` RPC method was returning misleading derivation path information for ZHTLC-enabled (shielded) coins when used in HD mode.

Previously, it would display the transparent derivation path (e.g., `m/44'/141'/0'`) while the shielded private key (`z_key`) was correctly derived using the `z_derivation_path` from the coin's configuration (e.g., `m/32'/141'/0'`). This discrepancy could lead to users being unable to recover their shielded funds, as they would be using the wrong derivation path.

This commit corrects the issue by:
1.  Adding a new optional `z_derivation_path` field to the `HdAddressInfo` struct in the RPC response.
2.  Populating this new field with the correct shielded derivation path for ZHTLC coins.
3.  Setting `z_derivation_path` to `None` for all other coin types to ensure the field only appears when relevant.

This makes the exported key data accurate and reliable for wallet recovery.
@shamardy shamardy merged commit a9fbf60 into main Jul 28, 2025
18 of 25 checks passed
@shamardy shamardy deleted the offline_key_export branch July 28, 2025 17:10
dimxy pushed a commit that referenced this pull request Aug 1, 2025
* dev: (21 commits)
  feat(wallet-connect): impl BTC (UTxO) activation via WalletConnect (#2499)
  feat(utxo): add new fixed txfee option for DINGO-like coins (#2454)
  ci(pull-requests): review notification bot (#2468)
  improvement(walletconnect): return the `pairing_topic` in `new_connection` response (#2538)
  bless clippy (#2560)
  refactor(toolchain): use latest available stable compiler (#2557)
  feat(wallet): implement unified offline private key export API (#2542)
  improve note for docker test start failure (#2550)
  fix(DOCS): add note for macos to fix docker containers startup failure (#2544)
  refactor(toolchain): general stabilization for stable rust (#2528)
  fix(ci): adds nodejs 20 to ci-container (#2536)
  fix(WASM and Debian): fix build failures (#2534)
  improvement(event-streaming): impl DeriveStreamerId trait for all streamers (#2489)
  fix(eth): Propagate structured EIP-1559 fee errors (#2532)
  fix(eth): Correctly implement ETH max withdrawal logic (#2531)
  feat(use-clap-for-cli): use clap to parse CLI-Args #2215 (#2510)
  feat(orderbook): expirable maker orders (#2516)
  improvement(eth): drop parity support (#2527)
  chore(release): finalize changelog for v2.5.0-beta (#2524)
  chore(toolchain): upgrade toolchain to nightly 1.86.0 (#2444)
  ...

# Conflicts:
#	mm2src/coins/lp_coins.rs
#	mm2src/coins/rpc_command/get_new_address.rs
#	mm2src/trezor/src/eth/eth_command.rs
dimxy pushed a commit that referenced this pull request Aug 1, 2025
* dev:
  feat(wallet-connect): impl BTC (UTxO) activation via WalletConnect (#2499)
  feat(utxo): add new fixed txfee option for DINGO-like coins (#2454)
  ci(pull-requests): review notification bot (#2468)
  improvement(walletconnect): return the `pairing_topic` in `new_connection` response (#2538)
  bless clippy (#2560)
  refactor(toolchain): use latest available stable compiler (#2557)
  feat(wallet): implement unified offline private key export API (#2542)
  improve note for docker test start failure (#2550)
  fix(DOCS): add note for macos to fix docker containers startup failure (#2544)
  refactor(toolchain): general stabilization for stable rust (#2528)
  fix(ci): adds nodejs 20 to ci-container (#2536)
  fix(WASM and Debian): fix build failures (#2534)
  improvement(event-streaming): impl DeriveStreamerId trait for all streamers (#2489)
  chore(release): v2.3.0-beta (#2284)

# Conflicts:
#	mm2src/coins/eth.rs
#	mm2src/coins/eth/eth_swap_v2/eth_maker_swap_v2.rs
#	mm2src/coins/eth/eth_swap_v2/eth_taker_swap_v2.rs
#	mm2src/coins/eth/eth_tests.rs
#	mm2src/coins/eth/eth_withdraw.rs
#	mm2src/coins/eth/v2_activation.rs
#	mm2src/coins/nft.rs
#	mm2src/coins/qrc20.rs
#	mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs
#	mm2src/mm2_main/src/rpc/lp_commands/one_inch/rpcs.rs
#	mm2src/mm2_main/src/rpc/lp_commands/tokens.rs
#	mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs
dimxy pushed a commit that referenced this pull request Aug 15, 2025
* dev: (24 commits)
  fix(ordermatch): ignore loop-back; clear on null root; reject stale keep-alives (#2580)
  fix(clippy): fix clippy warnings for #2565 (#2589)
  fix(Trezor): fix utxo and eth calls due to firmware changes (#2565)
  fix(utxo): calculate min_trading_vol based on fixed tx fees (#2564)
  feat(protocol): [0] solana support (#2586)
  fix(utxo): fix header deserialization; guard AuxPoW (#2583)
  chore(rust 1.89): make CI clippy/fmt pass (wasm32, all-targets) (#2581)
  fix(utxo): deserialize sapling root for PIVX block headers (#2572)
  improvement(dep-stack): security bumps (#2562)
  fix(utxo): correct block header deserialization for AuxPow and KAWPOW coins (#2563)
  feat(wallet-connect): impl BTC (UTxO) activation via WalletConnect (#2499)
  feat(utxo): add new fixed txfee option for DINGO-like coins (#2454)
  ci(pull-requests): review notification bot (#2468)
  improvement(walletconnect): return the `pairing_topic` in `new_connection` response (#2538)
  bless clippy (#2560)
  refactor(toolchain): use latest available stable compiler (#2557)
  feat(wallet): implement unified offline private key export API (#2542)
  improve note for docker test start failure (#2550)
  fix(DOCS): add note for macos to fix docker containers startup failure (#2544)
  refactor(toolchain): general stabilization for stable rust (#2528)
  ...

# Conflicts:
#	mm2src/coins/eth.rs
#	mm2src/coins/eth/eth_swap_v2/eth_maker_swap_v2.rs
#	mm2src/coins/eth/eth_swap_v2/eth_taker_swap_v2.rs
#	mm2src/coins/eth/eth_tests.rs
#	mm2src/coins/eth/eth_withdraw.rs
#	mm2src/coins/eth/v2_activation.rs
#	mm2src/coins/nft.rs
#	mm2src/coins/qrc20.rs
#	mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs
#	mm2src/mm2_main/src/rpc/lp_commands/one_inch/rpcs.rs
#	mm2src/mm2_main/src/rpc/lp_commands/tokens.rs
#	mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs
dimxy pushed a commit that referenced this pull request Aug 19, 2025
* dev:
  improvement(`static mut`s): `static mut` removal (#2590)
  fix(orders): set subscription on kickstart and skip GC of own pubkeys (#2597)
  fix(ordermatch): ignore loop-back; clear on null root; reject stale keep-alives (#2580)
  fix(clippy): fix clippy warnings for #2565 (#2589)
  fix(Trezor): fix utxo and eth calls due to firmware changes (#2565)
  fix(utxo): calculate min_trading_vol based on fixed tx fees (#2564)
  feat(protocol): [0] solana support (#2586)
  fix(utxo): fix header deserialization; guard AuxPoW (#2583)
  chore(rust 1.89): make CI clippy/fmt pass (wasm32, all-targets) (#2581)
  fix(utxo): deserialize sapling root for PIVX block headers (#2572)
  improvement(dep-stack): security bumps (#2562)
  fix(utxo): correct block header deserialization for AuxPow and KAWPOW coins (#2563)
  feat(wallet-connect): impl BTC (UTxO) activation via WalletConnect (#2499)
  feat(utxo): add new fixed txfee option for DINGO-like coins (#2454)
  ci(pull-requests): review notification bot (#2468)
  improvement(walletconnect): return the `pairing_topic` in `new_connection` response (#2538)
  bless clippy (#2560)
  refactor(toolchain): use latest available stable compiler (#2557)
  feat(wallet): implement unified offline private key export API (#2542)
  chore(release): v2.3.0-beta (#2284)

# Conflicts:
#	mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants