From 81a67825fea8a3982469e8a15732c102f57428b3 Mon Sep 17 00:00:00 2001 From: Dagur Valberg Johannsson Date: Mon, 16 Mar 2026 16:53:56 +0100 Subject: [PATCH] Don't require input path for all inputs Not all inputs need a signature; only require it for the input paths that do. --- docs/dapp.md | 2 +- docs/protocol.md | 12 ++++++------ packages/core/src/protocols/hdwalletv1.test.ts | 11 +++++++---- packages/core/src/protocols/hdwalletv1.ts | 9 +++++---- packages/wallet/src/integration/sign-request.test.ts | 12 ++++++------ 5 files changed, 25 insertions(+), 21 deletions(-) diff --git a/docs/dapp.md b/docs/dapp.md index d656a05..acf9046 100644 --- a/docs/dapp.md +++ b/docs/dapp.md @@ -133,7 +133,7 @@ const request: SignTransactionRequest = { userPrompt: "Confirm swap", broadcast: true, }, - inputPaths: [["receive", 0], ["defi", 5]], // one per sourceOutput + inputPaths: [[0, "receive", 0], [1, "defi", 5]], // [inputIndex, pathName, addressIndex] }; try { diff --git a/docs/protocol.md b/docs/protocol.md index 3e1818f..0b918c7 100644 --- a/docs/protocol.md +++ b/docs/protocol.md @@ -229,7 +229,7 @@ interface SignTransactionRequest { action: "sign_transaction_request"; transaction: WcSignTransactionRequest; // from @bch-wc2/interfaces sequence: number; - inputPaths: [PathName, number][]; // [pathName, addressIndex] per sourceOutput + inputPaths: [number, PathName, number][]; // [inputIndex, pathName, addressIndex] time: number; } ``` @@ -242,11 +242,11 @@ to match responses to requests. (for signing), version, locktime, and an optional `userPrompt` string shown to the user in the wallet UI. -`inputPaths` is a parallel array to `transaction.sourceOutputs` (and to `transaction.transaction.inputs`). -Each entry is a `[PathName, number]` tuple identifying the HD derivation path name and address index -that the dapp used to derive the locking script for that input. This allows the wallet to sign each -input without scanning or guessing which key was used. The array must have the same length as -`sourceOutputs`. +`inputPaths` is a sparse array of `[inputIndex, PathName, addressIndex]` tuples. Each entry identifies +the HD derivation path name and address index the dapp used to derive the locking script for the input +at position `inputIndex`. Only inputs that require wallet signing need an entry — contract inputs with +pre-set unlocking bytecode can be omitted. This allows the wallet to sign each input without scanning +or guessing which key was used. ### sign_transaction_response diff --git a/packages/core/src/protocols/hdwalletv1.test.ts b/packages/core/src/protocols/hdwalletv1.test.ts index 210f6b0..22ddf5a 100644 --- a/packages/core/src/protocols/hdwalletv1.test.ts +++ b/packages/core/src/protocols/hdwalletv1.test.ts @@ -11,8 +11,8 @@ describe("isSignTransactionRequest", () => { transaction: { transaction: {}, sourceOutputs: [] }, sequence: 1, inputPaths: [ - ["receive", 0], - ["change", 3], + [0, "receive", 0], + [2, "change", 3], ], time: 1000, }; @@ -39,13 +39,16 @@ describe("isSignTransactionRequest", () => { it("rejects tuple with wrong types", () => { expect( - isSignTransactionRequest({ ...valid, inputPaths: [[0, "receive"]] }), + isSignTransactionRequest({ + ...valid, + inputPaths: [["receive", 0, 1]], + }), ).toBe(false); }); it("rejects tuple with wrong length", () => { expect( - isSignTransactionRequest({ ...valid, inputPaths: [["receive"]] }), + isSignTransactionRequest({ ...valid, inputPaths: [[0, "receive"]] }), ).toBe(false); }); diff --git a/packages/core/src/protocols/hdwalletv1.ts b/packages/core/src/protocols/hdwalletv1.ts index ea3699b..ae967c6 100644 --- a/packages/core/src/protocols/hdwalletv1.ts +++ b/packages/core/src/protocols/hdwalletv1.ts @@ -114,7 +114,7 @@ export interface SignTransactionRequest extends ProtocolMessage { action: RelayMsgAction.SignTransactionRequest; transaction: WcSignTransactionRequest; sequence: number; - inputPaths: [PathName, number][]; // [pathName, addressIndex] per sourceOutput + inputPaths: [number, PathName, number][]; // [inputIndex, pathName, addressIndex] } export interface SignTransactionResponse extends ProtocolMessage { @@ -161,9 +161,10 @@ export function isSignTransactionRequest( msg.inputPaths.every( (p: any) => Array.isArray(p) && - p.length === 2 && - typeof p[0] === "string" && - typeof p[1] === "number", + p.length === 3 && + typeof p[0] === "number" && + typeof p[1] === "string" && + typeof p[2] === "number", ) ); } diff --git a/packages/wallet/src/integration/sign-request.test.ts b/packages/wallet/src/integration/sign-request.test.ts index 88b3268..c79d400 100644 --- a/packages/wallet/src/integration/sign-request.test.ts +++ b/packages/wallet/src/integration/sign-request.test.ts @@ -116,9 +116,9 @@ describe("WalletConnectionManager — sign_transaction_request with inputPaths", broadcast: false, }, inputPaths: [ - ["receive", 0], - ["defi", 5], - ["change", 2], + [0, "receive", 0], + [1, "defi", 5], + [2, "change", 2], ], time: Math.floor(Date.now() / 1000), }; @@ -131,9 +131,9 @@ describe("WalletConnectionManager — sign_transaction_request with inputPaths", expect(pendingRequests[0].connectionId).toBe(connectionId); expect(pendingRequests[0].request.inputPaths).toEqual([ - ["receive", 0], - ["defi", 5], - ["change", 2], + [0, "receive", 0], + [1, "defi", 5], + [2, "change", 2], ]); }, 15000);