{
 "number": 36070,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/36070",
 "title": "wallet: Add deriveHDKey interface",
 "author": "PraneethGunas",
 "author_association": "FIRST_TIME_CONTRIBUTOR",
 "created_at": "2026-08-24T17:59:33Z",
 "updated_at": "2026-09-16T13:17:52Z",
 "age_days": 23,
 "draft": false,
 "labels": [
  "Wallet"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "462038a1a1d41087fe2ffc5125ffa4590ee74e6e",
 "head_ref": "derivehdkey-interface",
 "head_repo": "PraneethGunas/bitcoin",
 "head_history": [
  {
   "t": "2026-08-29T00:22:21Z",
   "sha": "6131eab5b9a055d2d2686ab2903d3de4363671d3"
  },
  {
   "t": "2026-09-01T16:38:27Z",
   "sha": "32d7ebf478eb91bde84cfc24f6fa16098ebd9e14"
  },
  {
   "t": "2026-09-09T19:19:12Z",
   "sha": "3c886852451458f852a2202cc361d0b6bcfc8bee"
  },
  {
   "t": "2026-09-10T20:13:46Z",
   "sha": "431f0d976d04ea62ab4255fdfdaa54a3aea2a0cd"
  },
  {
   "t": "2026-09-15T22:35:10Z",
   "sha": "462038a1a1d41087fe2ffc5125ffa4590ee74e6e"
  }
 ],
 "additions": 163,
 "deletions": 55,
 "changed_files": 7,
 "commit_count": 3,
 "size_bucket": "M",
 "mergeable_state": "unstable",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "concept_ack": [
     {
      "login": "polespinasa",
      "url": "https://github.com/bitcoin/bitcoin/pull/36070#issuecomment-5407245227"
     },
     {
      "login": "jeanpablojp",
      "url": "https://github.com/bitcoin/bitcoin/pull/36070#pullrequestreview-5043268518"
     },
     {
      "login": "pseudoramdom",
      "url": "https://github.com/bitcoin/bitcoin/pull/36070#pullrequestreview-5201817506"
     }
    ]
   },
   "conflicts": [
    {
     "number": 35998,
     "title": "wallet: Handle or explicitly ignore `WalletBatch` write failures",
     "author": "achow101"
    }
   ]
  }
 },
 "acks_parsed": {
  "polespinasa": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-08-25T07:54:27Z",
   "stale": false
  },
  "jeanpablojp": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-08-27T16:39:38Z",
   "stale": false
  },
  "pseudoramdom": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-09-14T19:24:08Z",
   "stale": false
  }
 },
 "acks_tally": {
  "ack": 0,
  "stale_ack": 0,
  "concept_ack": 3,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 0,
  "changes_requested": 0,
  "distinct_reviewers": [
   "achow101",
   "hebasto",
   "jeanpablojp",
   "polespinasa",
   "pseudoramdom"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "unstable",
  "last_author_activity": "2026-09-15T22:43:13Z",
  "last_reviewer_activity": "2026-09-16T13:11:21Z",
  "last_reviewer": "polespinasa",
  "author_silent_days": 1,
  "waiting_on_author_days": 1,
  "days_since_update": 1
 },
 "refs": {
  "mentioned": [
   32784,
   34861,
   35436,
   35645
  ],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 35436,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-09-14",
    "title": "wallet: Add addHDkey interface"
   },
   {
    "number": 34861,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-09-17",
    "title": "wallet: Add importdescriptors interface"
   },
   {
    "number": 32784,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-08-15",
    "title": "wallet: derivehdkey RPC to get xpub at arbitrary path"
   },
   {
    "number": 35645,
    "type": "issue",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "Multisig Wizard tracking issue"
   }
  ],
  "conflicts": [
   35998
  ]
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [
  "src/wallet/rpc/wallet.cpp",
  "src/wallet/test/wallet_interfaces_tests.cpp",
  "src/wallet/test/wallet_tests.cpp",
  "src/wallet/wallet.cpp",
  "src/wallet/wallet.h",
  "test/functional/wallet_derivehdkey.py"
 ],
 "body": "This PR adds a wallet interface for derivehdkey.\n\nThe motivation is the same as #35436 and #34861. The derivehdkey RPC exists\n(#32784), but the GUI does not go through RPC, so the logic is currently out of\nits reach. A dedicated wallet interface makes it available for multisig setup.\nAlongside the addhdkey interface, this lets the GUI add an HD key and derive a\nshareable xpub from it. Tracked as the deriveHDKey item in #35645.\n\nKey changes:\n- Add CWallet::DeriveHDKey(), which selects the HD key and derives it at the\n  requested path.\n- Update the derivehdkey RPC to call it, rather than repeating the hardened path check, the key selection and the derivation. The watch-only and unlock checks stay in the RPC, along with the xpub argument parsing.\n- Add interfaces::Wallet::deriveHDKey(), which returns the derived xpub and its\n  key origin. Private key material does not cross the interface.\n- Add unit test coverage for interfaces::Wallet::deriveHDKey().\n\nThe RPC maps every WalletError to -4, moving the unhardened path and failed derivation cases from -8 and the key selection cases from -5. The watch-only -4 and locked wallet -13 are unchanged.",
 "commits": [
  {
   "sha": "132dd25ad4cb2fd04698e371108c3b1c653d93eb",
   "date": "2026-09-15T21:34:31Z",
   "message": "wallet: Add CWallet::DeriveHDKey\n\nThe derivehdkey RPC selects the HD key and derives it inline, which the GUI\ncannot reach. Move both into the wallet."
  },
  {
   "sha": "c18cc35876975958f1a67c3cf872a5bae5651fcf",
   "date": "2026-09-15T22:22:06Z",
   "message": "wallet: Have derivehdkey use CWallet::DeriveHDKey\n\nThe RPC now consumes CWallet::DeriveHDKey instead of repeating the hardened\npath check, the key selection and the derivation. Those errors now come from\nthe wallet and are reported as -4."
  },
  {
   "sha": "462038a1a1d41087fe2ffc5125ffa4590ee74e6e",
   "date": "2026-09-15T22:22:09Z",
   "message": "wallet: Add deriveHDKey interface\n\nOnly the xpub is returned. interfaces::Wallet is not authenticated, so the\nprivate key is not passed over it."
  }
 ],
 "timeline": [
  {
   "t": "2026-08-25T07:54:27Z",
   "kind": "comment",
   "who": "polespinasa",
   "assoc": "MEMBER",
   "text": "concept ACK\n\nwill review soon :)"
  },
  {
   "t": "2026-08-27T16:39:38Z",
   "kind": "review",
   "who": "jeanpablojp",
   "assoc": "CONTRIBUTOR",
   "state": "COMMENTED",
   "commit": "a1250d2f413016c4b4524d50823ef816af9aff40",
   "text": "Concept ACK\n\nLeft some comments."
  },
  {
   "t": "2026-08-27T16:39:39Z",
   "kind": "review_comment",
   "who": "jeanpablojp",
   "assoc": "CONTRIBUTOR",
   "path": "src/wallet/test/wallet_interfaces_tests.cpp",
   "commit": "a1250d2f413016c4b4524d50823ef816af9aff40",
   "in_reply_to": null,
   "text": "This case passes even when the derivation comes from a different key: `origin.path` just echoes the argument, and `IsValid()` holds for any derived key. I made `SelectHDKey` return a `CExtKey` the wallet doesn't hold and all six cases still passed, while `wallet_derivehdkey.py` failed on the same mutation.\n\nComparing against the wallet's own active HD key would catch this, the way `bip32_derive_ext_key` does for `DeriveExtKey`:\n\n```suggestion\n    LOCK(wallet->cs_wallet);\n    const auto active{wallet->GetHDPubKeys(CWallet::HDKeyFilter::Active)};\n    BOOST_REQUIRE_EQUAL(active.size(), 1U);\n    const auto xprv{wallet->GetExtKey(active.begin()->first)};\n    BOOST_REQUIRE(xprv);\n    const auto expected{DeriveExtKey(*xprv, path)};\n    BOOST_REQUIRE(expected);\n    BOOST_CHECK(result->first == expected->first.Neuter());\n    BOOST_CHECK(result->second == expected->second);\n```"
  },
  {
   "t": "2026-08-27T16:39:39Z",
   "kind": "review_comment",
   "who": "jeanpablojp",
   "assoc": "CONTRIBUTOR",
   "path": "src/wallet/rpc/wallet.cpp",
   "commit": "a1250d2f413016c4b4524d50823ef816af9aff40",
   "in_reply_to": null,
   "text": "Is this branch reachable? `EnsureWalletIsUnlocked` runs a few lines above with `cs_wallet` already held, and `vMasterKey` is `GUARDED_BY(cs_wallet)`, so nothing can lock the wallet in between. Asking because the commit message says the RPC maps it."
  },
  {
   "t": "2026-08-28T11:21:33Z",
   "kind": "review_comment",
   "who": "polespinasa",
   "assoc": "MEMBER",
   "path": "src/wallet/rpc/wallet.cpp",
   "commit": "5de0c29e06f41f6901fd0d0ec69c9359612371e5",
   "in_reply_to": null,
   "text": "in 5de0c29e06f41f6901fd0d0ec69c9359612371e5 wallet: Return WalletError from SelectHDKey\n\nThis is dead code, it can never be executed because if the wallet is locked, `EnsureWalletIsUnlocked(*wallet);` (L1006) will throw before."
  },
  {
   "t": "2026-08-28T11:23:35Z",
   "kind": "review_comment",
   "who": "polespinasa",
   "assoc": "MEMBER",
   "path": "src/wallet/wallet.h",
   "commit": "11953500e91920bc6357190bcd8956212913743d",
   "in_reply_to": null,
   "text": "in 11953500e91920bc6357190bcd8956212913743d wallet: Move derivehdkey HD key selection into CWallet\n\nI would make this return `Expected` since the beginning. Probably commit 1 and 2 should be squashed, you are already changing the return type here, so why not go directly to the \"final\" version?"
  },
  {
   "t": "2026-08-28T11:28:20Z",
   "kind": "review_comment",
   "who": "polespinasa",
   "assoc": "MEMBER",
   "path": "src/wallet/wallet.cpp",
   "commit": "3c886852451458f852a2202cc361d0b6bcfc8bee",
   "in_reply_to": null,
   "text": "in a1250d2f413016c4b4524d50823ef816af9aff40 wallet: Add deriveHDKey interface\n\nAll this is duplicated from RPC code. Why not just make both the interface and the RPC rely on the same code? Because of both using different code functions, they both return different error codes for same errors.\n\nAlso probably this commit could be split in different commits. First a preparatory commit that creates the DeriveHDKey function + testing, then a commit rebasing the RPC to use it, then a commit creating the interface. You can check #34861 for a commit structure idea :)"
  },
  {
   "t": "2026-08-28T11:29:48Z",
   "kind": "review",
   "who": "polespinasa",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "a1250d2f413016c4b4524d50823ef816af9aff40",
   "text": "did a first swift review"
  },
  {
   "t": "2026-08-29T00:22:21Z",
   "kind": "force_push",
   "who": "PraneethGunas",
   "commit": "6131eab5b9a055d2d2686ab2903d3de4363671d3"
  },
  {
   "t": "2026-08-29T00:25:59Z",
   "kind": "review_comment",
   "who": "PraneethGunas",
   "assoc": "NONE",
   "path": "src/wallet/rpc/wallet.cpp",
   "commit": "a1250d2f413016c4b4524d50823ef816af9aff40",
   "in_reply_to": 3873791661,
   "text": "Right, removed this branch"
  },
  {
   "t": "2026-08-29T00:26:40Z",
   "kind": "review_comment",
   "who": "PraneethGunas",
   "assoc": "NONE",
   "path": "src/wallet/wallet.h",
   "commit": "11953500e91920bc6357190bcd8956212913743d",
   "in_reply_to": 3880182690,
   "text": "Squashed, SelectHDKey returns util::Expected from the start now."
  },
  {
   "t": "2026-08-29T00:28:41Z",
   "kind": "review_comment",
   "who": "PraneethGunas",
   "assoc": "NONE",
   "path": "src/wallet/wallet.cpp",
   "commit": "3c886852451458f852a2202cc361d0b6bcfc8bee",
   "in_reply_to": 3880212723,
   "text": "Done. Split into \"Add CWallet::DeriveHDKey\" and \"Add deriveHDKey interface\".\n\nOn sharing code with the RPC: it already calls SelectHDKey(). What's left is the watch-only, hardened-path and unlock guards, which pin the error codes wallet_derivehdkey.py asserts (-4, -8, -13).\n\nDeriveHDKey() returns GenericError for every failure, so routing the rest through it would turn \"Unable to derive HD key at the requested path\" from -8 into -5. Keeping -8 would need a new WalletErrorCode just so one caller can pick a different number, which src/wallet/types.h:48-50 warns against."
  },
  {
   "t": "2026-08-29T16:24:27Z",
   "kind": "review",
   "who": "jeanpablojp",
   "assoc": "CONTRIBUTOR",
   "state": "COMMENTED",
   "commit": "6131eab5b9a055d2d2686ab2903d3de4363671d3",
   "text": "Reviewed again. Left one more comment on the new test."
  },
  {
   "t": "2026-08-29T16:24:27Z",
   "kind": "review_comment",
   "who": "jeanpablojp",
   "assoc": "CONTRIBUTOR",
   "path": "src/wallet/test/wallet_tests.cpp",
   "commit": "6131eab5b9a055d2d2686ab2903d3de4363671d3",
   "in_reply_to": null,
   "text": "Same problem the interface test had: `origin.path` just echoes the argument, and `IsValid()` holds for any key. With `SelectHDKey` returning a key the wallet doesn't hold, this one passes while the interface test fails; same for blanking the origin fingerprint or returning the key before derivation.\n\n```suggestion\n    const auto active{wallet->GetHDPubKeys(CWallet::HDKeyFilter::Active)};\n    BOOST_REQUIRE_EQUAL(active.size(), 1U);\n    const auto xprv{wallet->GetExtKey(active.begin()->first)};\n    BOOST_REQUIRE(xprv);\n    const auto expected{DeriveExtKey(*xprv, path)};\n    BOOST_REQUIRE(expected);\n    BOOST_CHECK(result->first == expected->first);\n    BOOST_CHECK(result->second == expected->second);\n```"
  },
  {
   "t": "2026-09-01T16:38:27Z",
   "kind": "force_push",
   "who": "PraneethGunas",
   "commit": "32d7ebf478eb91bde84cfc24f6fa16098ebd9e14"
  },
  {
   "t": "2026-09-01T16:39:52Z",
   "kind": "review_comment",
   "who": "PraneethGunas",
   "assoc": "NONE",
   "path": "src/wallet/test/wallet_tests.cpp",
   "commit": "6131eab5b9a055d2d2686ab2903d3de4363671d3",
   "in_reply_to": 3887075593,
   "text": "Fixed"
  },
  {
   "t": "2026-09-02T09:21:26Z",
   "kind": "comment",
   "who": "hebasto",
   "assoc": "MEMBER",
   "text": "From https://github.com/bitcoin/bitcoin/actions/runs/33532997440/job/100190403622?pr=36070:\n```diff\n--- a/src/interfaces/wallet.h\n+++ b/src/interfaces/wallet.h\n@@ -34,19 +34,16 @@\n #include <vector>\n\n class ArgsManager;\n-class CKeyID;\n-class CPubKey;\n class CScript;\n class PartiallySignedTransaction;\n class uint256;\n enum class FeeReason;\n enum class OutputType;\n struct bilingual_str;\n+\n namespace wallet {\n-struct CreatedTransactionResult;\n class CCoinControl;\n class CWallet;\n-enum class AddressPurpose;\n struct CRecipient;\n struct WalletContext;\n } // namespace wallet\n```"
  },
  {
   "t": "2026-09-09T19:19:12Z",
   "kind": "force_push",
   "who": "PraneethGunas",
   "commit": "3c886852451458f852a2202cc361d0b6bcfc8bee"
  },
  {
   "t": "2026-09-09T23:03:19Z",
   "kind": "comment",
   "who": "achow101",
   "assoc": "MEMBER",
   "text": "Why is `SelectHDKey` being split into a separate function? This PR should only create one function: `DeriveHDKey`, and that should be called by RPC. There should not need to be a RPC that is essentially duplicating code of `CWallet::DeriveHDKey`. This also allows the unit tests to be dropped as the functional tests (can) cover those cases."
  },
  {
   "t": "2026-09-10T18:25:44Z",
   "kind": "comment",
   "who": "PraneethGunas",
   "assoc": "NONE",
   "text": "[quoted text omitted]\n\nIt was done so that the the RPC error codes and messages are preserved. Also, looking at the discussions in https://github.com/bitcoin/bitcoin/pull/35436#discussion_r3470335539 it makes sense to collapse the error codes down  based on how the errors are logged/displayed https://github.com/bitcoin/bitcoin/pull/35436#discussion_r3470712824"
  },
  {
   "t": "2026-09-10T20:13:46Z",
   "kind": "force_push",
   "who": "PraneethGunas",
   "commit": "431f0d976d04ea62ab4255fdfdaa54a3aea2a0cd"
  },
  {
   "t": "2026-09-10T20:46:44Z",
   "kind": "comment",
   "who": "PraneethGunas",
   "assoc": "NONE",
   "text": "Rebased on master and rebuilt the history"
  },
  {
   "t": "2026-09-10T20:48:08Z",
   "kind": "review_comment",
   "who": "PraneethGunas",
   "assoc": "NONE",
   "path": "src/wallet/wallet.cpp",
   "commit": "3c886852451458f852a2202cc361d0b6bcfc8bee",
   "in_reply_to": 3880212723,
   "text": "Now both the interface and the RPC rely on the same CWallet::DeriveHDKey"
  },
  {
   "t": "2026-09-14T19:15:08Z",
   "kind": "review_comment",
   "who": "pseudoramdom",
   "assoc": "MEMBER",
   "path": "src/wallet/wallet.cpp",
   "commit": "462038a1a1d41087fe2ffc5125ffa4590ee74e6e",
   "in_reply_to": null,
   "text": "In `wallet: Add CWallet::DeriveHDKey` -\n\nThere's a lot going on in this commit - extracting to wallet.cpp, changing the RPC error contracts.\nIt would still be beneficial to have 2 commits\n- Extract the wallet method whilst preserving existing behavior, including RPC code.\n- Adopt WalletError, making the error related changes explicit."
  },
  {
   "t": "2026-09-14T19:19:24Z",
   "kind": "review_comment",
   "who": "pseudoramdom",
   "assoc": "MEMBER",
   "path": "src/wallet/test/wallet_interfaces_tests.cpp",
   "commit": "431f0d976d04ea62ab4255fdfdaa54a3aea2a0cd",
   "in_reply_to": null,
   "text": "Now that https://github.com/bitcoin/bitcoin/pull/35436, can you rebase to that this doesn't look like a new file is added :)"
  },
  {
   "t": "2026-09-14T19:19:54Z",
   "kind": "review_comment",
   "who": "pseudoramdom",
   "assoc": "MEMBER",
   "path": "src/wallet/test/wallet_interfaces_tests.cpp",
   "commit": "431f0d976d04ea62ab4255fdfdaa54a3aea2a0cd",
   "in_reply_to": 4008699280,
   "text": "i.e. this commit might be easier to review after rebasing on master."
  },
  {
   "t": "2026-09-14T19:23:53Z",
   "kind": "review_comment",
   "who": "pseudoramdom",
   "assoc": "MEMBER",
   "path": "test/functional/wallet_derivehdkey.py",
   "commit": "462038a1a1d41087fe2ffc5125ffa4590ee74e6e",
   "in_reply_to": null,
   "text": "In `wallet: Add CWallet::DeriveHDKey`\n\nI'm not sure if we're okay with changing the error contract since `derivehdkey` will ship in v32.\nIf not, we likely have to duplicate the checks to retain the error codes.\n@achow101"
  },
  {
   "t": "2026-09-14T19:24:08Z",
   "kind": "review",
   "who": "pseudoramdom",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "431f0d976d04ea62ab4255fdfdaa54a3aea2a0cd",
   "text": "Concept ACK. Left some comments"
  },
  {
   "t": "2026-09-15T22:35:10Z",
   "kind": "force_push",
   "who": "PraneethGunas",
   "commit": "462038a1a1d41087fe2ffc5125ffa4590ee74e6e"
  },
  {
   "t": "2026-09-15T22:35:57Z",
   "kind": "review_comment",
   "who": "PraneethGunas",
   "assoc": "NONE",
   "path": "src/wallet/wallet.cpp",
   "commit": "462038a1a1d41087fe2ffc5125ffa4590ee74e6e",
   "in_reply_to": 4008661346,
   "text": "I've split this into separate commits for better readability"
  },
  {
   "t": "2026-09-15T22:36:42Z",
   "kind": "review_comment",
   "who": "PraneethGunas",
   "assoc": "NONE",
   "path": "src/wallet/test/wallet_interfaces_tests.cpp",
   "commit": "431f0d976d04ea62ab4255fdfdaa54a3aea2a0cd",
   "in_reply_to": 4008699280,
   "text": "Rebased and resolved."
  },
  {
   "t": "2026-09-15T22:43:13Z",
   "kind": "review_comment",
   "who": "PraneethGunas",
   "assoc": "NONE",
   "path": "test/functional/wallet_derivehdkey.py",
   "commit": "462038a1a1d41087fe2ffc5125ffa4590ee74e6e",
   "in_reply_to": 4008735800,
   "text": "Restored the watch-only and unlock checks in the RPC, so -4 and -13 are unchanged from v32.\n\n-8 and -5 are now collapsed to -4, or we can duplicate the checks in the RPC to preserve the v32 behaviour."
  },
  {
   "t": "2026-09-16T10:15:05Z",
   "kind": "review_comment",
   "who": "polespinasa",
   "assoc": "MEMBER",
   "path": "test/functional/wallet_derivehdkey.py",
   "commit": "462038a1a1d41087fe2ffc5125ffa4590ee74e6e",
   "in_reply_to": 4008735800,
   "text": "Haven't reviewed yet, but re changing error codes:\nhttps://github.com/bitcoin/bitcoin/pull/35690#issuecomment-4939490752"
  },
  {
   "t": "2026-09-16T13:11:21Z",
   "kind": "review_comment",
   "who": "polespinasa",
   "assoc": "MEMBER",
   "path": "src/wallet/wallet.cpp",
   "commit": "462038a1a1d41087fe2ffc5125ffa4590ee74e6e",
   "in_reply_to": 4008661346,
   "text": "I don't think the current structure is what Ram meant.\nFirst commit duplicates code now, and the 2ndo removes it which is confusing. Let me suggest another approach:\n\nA way to do this in a clean and easily readable way is to first extract the RPC functionality into some helper function inside the `rpc/wallet.cpp`, then have another move-only commit that moves that helper function into `wallet.cpp`. And then another one changing the error codes.\n\nSo tldr;\n\n1. Extract in the same rpc file the functionality of `DeriveHDKey` into a `DeriveHDKey` helper function\n2. Change the error codes.\n3. Move the `DeriveHDKey` function to `wallet.cpp`.\n4. Add the interface\n\nThis is easy to review because the extracting code is in the same file and does not change much. Both old code and the new function are in the same commit.\nThe change errors is pretty straight forward.\nThe move commit can easily be reviewed with --color-moved=dimmed-zebra\n\nLeft a proposal here:\nhttps://github.com/polespinasa/bitcoin/commits/pr-36070/"
  }
 ],
 "labels_log": [
  {
   "t": "2026-08-24T17:59:38Z",
   "action": "labeled",
   "label": "Wallet",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-27T16:09:35Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-29T02:18:15Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-09-01T12:54:01Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-09-09T22:22:16Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-09-14T13:15:37Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-09-16T00:19:13Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  }
 ],
 "state_log": [
  {
   "t": "2026-08-24T17:59:37Z",
   "kind": "renamed",
   "who": "DrahtBot",
   "from": " wallet: Add deriveHDKey interface",
   "to": "wallet: Add deriveHDKey interface"
  }
 ],
 "text_chars": 9084,
 "text_tokens_estimate": 2271,
 "changed_paths": [
  "src/interfaces/wallet.h",
  "src/wallet/interfaces.cpp",
  "src/wallet/rpc/wallet.cpp",
  "src/wallet/test/wallet_interfaces_tests.cpp",
  "src/wallet/wallet.cpp",
  "src/wallet/wallet.h",
  "test/functional/wallet_derivehdkey.py"
 ],
 "files": [
  {
   "path": "src/interfaces/wallet.h",
   "add": 4,
   "del": 0
  },
  {
   "path": "src/wallet/interfaces.cpp",
   "add": 7,
   "del": 0
  },
  {
   "path": "src/wallet/rpc/wallet.cpp",
   "add": 5,
   "del": 48
  },
  {
   "path": "src/wallet/test/wallet_interfaces_tests.cpp",
   "add": 38,
   "del": 0
  },
  {
   "path": "src/wallet/wallet.cpp",
   "add": 97,
   "del": 0
  },
  {
   "path": "src/wallet/wallet.h",
   "add": 5,
   "del": 0
  },
  {
   "path": "test/functional/wallet_derivehdkey.py",
   "add": 7,
   "del": 7
  }
 ],
 "test_lines": 52,
 "git": {
  "head": "462038a1a1d41087fe2ffc5125ffa4590ee74e6e",
  "head_matches_backup": true,
  "base": "51ddab532cb38213e2258c24c492bc8a392ffc90",
  "commits": [
   {
    "sha": "132dd25ad4",
    "subject": "wallet: Add CWallet::DeriveHDKey",
    "files": 2,
    "add": 102,
    "del": 0
   },
   {
    "sha": "c18cc35876",
    "subject": "wallet: Have derivehdkey use CWallet::DeriveHDKey",
    "files": 2,
    "add": 12,
    "del": 55
   },
   {
    "sha": "462038a1a1",
    "subject": "wallet: Add deriveHDKey interface",
    "files": 3,
    "add": 49,
    "del": 0
   }
  ],
  "patch_truncated": false
 },
 "input_hash": "18047a14f5850a46",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}