Don't require input path for all inputs

Not all inputs need a signature; only require it for the input paths
that do.
This commit is contained in:
Dagur Valberg Johannsson 2026-03-16 16:53:56 +01:00
parent 6d4d8139f0
commit 81a67825fe
No known key found for this signature in database
GPG key ID: FD701804AEE88107
5 changed files with 25 additions and 21 deletions

View file

@ -133,7 +133,7 @@ const request: SignTransactionRequest = {
userPrompt: "Confirm swap", userPrompt: "Confirm swap",
broadcast: true, broadcast: true,
}, },
inputPaths: [["receive", 0], ["defi", 5]], // one per sourceOutput inputPaths: [[0, "receive", 0], [1, "defi", 5]], // [inputIndex, pathName, addressIndex]
}; };
try { try {

View file

@ -229,7 +229,7 @@ interface SignTransactionRequest {
action: "sign_transaction_request"; action: "sign_transaction_request";
transaction: WcSignTransactionRequest; // from @bch-wc2/interfaces transaction: WcSignTransactionRequest; // from @bch-wc2/interfaces
sequence: number; sequence: number;
inputPaths: [PathName, number][]; // [pathName, addressIndex] per sourceOutput inputPaths: [number, PathName, number][]; // [inputIndex, pathName, addressIndex]
time: number; 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 (for signing), version, locktime, and an optional `userPrompt` string shown to the user in the
wallet UI. wallet UI.
`inputPaths` is a parallel array to `transaction.sourceOutputs` (and to `transaction.transaction.inputs`). `inputPaths` is a sparse array of `[inputIndex, PathName, addressIndex]` tuples. Each entry identifies
Each entry is a `[PathName, number]` tuple identifying the HD derivation path name and address index the HD derivation path name and address index the dapp used to derive the locking script for the input
that the dapp used to derive the locking script for that input. This allows the wallet to sign each at position `inputIndex`. Only inputs that require wallet signing need an entry — contract inputs with
input without scanning or guessing which key was used. The array must have the same length as pre-set unlocking bytecode can be omitted. This allows the wallet to sign each input without scanning
`sourceOutputs`. or guessing which key was used.
### sign_transaction_response ### sign_transaction_response

View file

@ -11,8 +11,8 @@ describe("isSignTransactionRequest", () => {
transaction: { transaction: {}, sourceOutputs: [] }, transaction: { transaction: {}, sourceOutputs: [] },
sequence: 1, sequence: 1,
inputPaths: [ inputPaths: [
["receive", 0], [0, "receive", 0],
["change", 3], [2, "change", 3],
], ],
time: 1000, time: 1000,
}; };
@ -39,13 +39,16 @@ describe("isSignTransactionRequest", () => {
it("rejects tuple with wrong types", () => { it("rejects tuple with wrong types", () => {
expect( expect(
isSignTransactionRequest({ ...valid, inputPaths: [[0, "receive"]] }), isSignTransactionRequest({
...valid,
inputPaths: [["receive", 0, 1]],
}),
).toBe(false); ).toBe(false);
}); });
it("rejects tuple with wrong length", () => { it("rejects tuple with wrong length", () => {
expect( expect(
isSignTransactionRequest({ ...valid, inputPaths: [["receive"]] }), isSignTransactionRequest({ ...valid, inputPaths: [[0, "receive"]] }),
).toBe(false); ).toBe(false);
}); });

View file

@ -114,7 +114,7 @@ export interface SignTransactionRequest extends ProtocolMessage {
action: RelayMsgAction.SignTransactionRequest; action: RelayMsgAction.SignTransactionRequest;
transaction: WcSignTransactionRequest; transaction: WcSignTransactionRequest;
sequence: number; sequence: number;
inputPaths: [PathName, number][]; // [pathName, addressIndex] per sourceOutput inputPaths: [number, PathName, number][]; // [inputIndex, pathName, addressIndex]
} }
export interface SignTransactionResponse extends ProtocolMessage { export interface SignTransactionResponse extends ProtocolMessage {
@ -161,9 +161,10 @@ export function isSignTransactionRequest(
msg.inputPaths.every( msg.inputPaths.every(
(p: any) => (p: any) =>
Array.isArray(p) && Array.isArray(p) &&
p.length === 2 && p.length === 3 &&
typeof p[0] === "string" && typeof p[0] === "number" &&
typeof p[1] === "number", typeof p[1] === "string" &&
typeof p[2] === "number",
) )
); );
} }

View file

@ -116,9 +116,9 @@ describe("WalletConnectionManager — sign_transaction_request with inputPaths",
broadcast: false, broadcast: false,
}, },
inputPaths: [ inputPaths: [
["receive", 0], [0, "receive", 0],
["defi", 5], [1, "defi", 5],
["change", 2], [2, "change", 2],
], ],
time: Math.floor(Date.now() / 1000), 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].connectionId).toBe(connectionId);
expect(pendingRequests[0].request.inputPaths).toEqual([ expect(pendingRequests[0].request.inputPaths).toEqual([
["receive", 0], [0, "receive", 0],
["defi", 5], [1, "defi", 5],
["change", 2], [2, "change", 2],
]); ]);
}, 15000); }, 15000);