✨ (signer-zcash) [LIVE-25878]: Implement transparent signTransaction with Ledger Wallet legacy args#1498
✨ (signer-zcash) [LIVE-25878]: Implement transparent signTransaction with Ledger Wallet legacy args#1498may01 wants to merge 7 commits into
Conversation
…allet legacy args
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
There was a problem hiding this comment.
Pull request overview
This PR implements a full Ledger Wallet–compatible transparent Zcash signTransaction flow in @ledgerhq/device-signer-kit-zcash, replacing the previous placeholder API with a multi-step APDU pipeline (trusted inputs → hash inputs/outputs → optional Sapling commit → per-input signatures → signed tx assembly) and updating the public API accordingly.
Changes:
- Replace
signTransaction(derivationPath, rawTx)withsignTransaction(args: LegacyCreateTransactionArg, options?)and thread the new shape through signer/use-cases/app-binder. - Add/extend Zcash APDU commands +
SignTransactionTaskorchestration, plus transaction parsing/serialization utilities and trusted-input chunking updates. - Add Vitest coverage (unit + integration-style fixtures), update docs, and expand the sample app UI to craft legacy-compatible signing args.
Reviewed changes
Copilot reviewed 36 out of 36 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Adds Zcash signer package to the root package list. |
| packages/signer/signer-zcash/src/internal/use-cases/transaction/SignTransactionUseCase.ts | Updates use-case signature to accept LegacyCreateTransactionArg. |
| packages/signer/signer-zcash/src/internal/use-cases/transaction/SignTransactionUseCase.test.ts | Adds test coverage for updated use-case wiring. |
| packages/signer/signer-zcash/src/internal/DefaultSignerZcash.ts | Updates public signer method signature and delegation to use-case. |
| packages/signer/signer-zcash/src/internal/DefaultSignerZcash.test.ts | Adds a basic expectation for the new signTransaction invocation path. |
| packages/signer/signer-zcash/src/internal/app-binder/ZcashAppBinder.ts | Updates binder API to accept transactionArg. |
| packages/signer/signer-zcash/src/internal/app-binder/ZcashAppBinder.test.ts | Adds binder tests for signTransaction and task wiring. |
| packages/signer/signer-zcash/src/internal/app-binder/task/utils/legacyTransactionUtils.ts | Adds legacy tx parsing/serialization helpers used by signing. |
| packages/signer/signer-zcash/src/internal/app-binder/task/utils/legacyTransactionUtils.test.ts | Adds unit tests for transaction util helpers. |
| packages/signer/signer-zcash/src/internal/app-binder/task/SignTransactionTask.ts | Implements the transparent Zcash signing orchestration task. |
| packages/signer/signer-zcash/src/internal/app-binder/task/SignTransactionTask.test.ts | Adds extensive fixture-driven tests for signing task behavior. |
| packages/signer/signer-zcash/src/internal/app-binder/task/GetTrustedInputTask.ts | Adjusts trusted-input chunk splitting (notably scriptSig chunking). |
| packages/signer/signer-zcash/src/internal/app-binder/task/GetTrustedInputTask.test.ts | Updates expected APDUs to match the new chunking. |
| packages/signer/signer-zcash/src/internal/app-binder/task/fixtures/signTransactionFromLedgerWalletLogs2026-05-12.ts | Adds Ledger Wallet log fixture and expectations for a 2-input Sapling case. |
| packages/signer/signer-zcash/src/internal/app-binder/task/fixtures/signTransactionFromLedgerWalletLogs2026-05-11.ts | Adds Ledger Wallet log fixture and expectations for a 1-input Sapling case. |
| packages/signer/signer-zcash/src/internal/app-binder/command/ZcashSaplingOutputCommitCommand.ts | Adds Sapling output-commit command (short SIGN). |
| packages/signer/signer-zcash/src/internal/app-binder/command/ZcashSaplingOutputCommitCommand.test.ts | Adds APDU-shape test for Sapling output commit. |
| packages/signer/signer-zcash/src/internal/app-binder/command/utils/apduHeaderUtils.ts | Adds Zcash INS/P1/P2 constants needed for new commands. |
| packages/signer/signer-zcash/src/internal/app-binder/command/StartUntrustedHashTransactionInputCommand.ts | Adds command for START_UNTRUSTED_HASH_TRANSACTION_INPUT. |
| packages/signer/signer-zcash/src/internal/app-binder/command/StartUntrustedHashTransactionInputCommand.test.ts | Adds unit tests for the new hash-input command. |
| packages/signer/signer-zcash/src/internal/app-binder/command/SignTransactionCommand.ts | Implements SIGN_TRANSACTION APDU creation and response parsing. |
| packages/signer/signer-zcash/src/internal/app-binder/command/SignTransactionCommand.test.ts | Adds APDU-shape tests and signature normalization tests. |
| packages/signer/signer-zcash/src/internal/app-binder/command/ProvideOutputFullChangePathCommand.ts | Adds finalize-input command for change-path provisioning. |
| packages/signer/signer-zcash/src/internal/app-binder/command/HashOutputFullCommand.ts | Adds finalize-input command for hashing outputs in chunks. |
| packages/signer/signer-zcash/src/internal/app-binder/command/FinalizeInputCommands.test.ts | Adds unit tests for finalize-input commands. |
| packages/signer/signer-zcash/src/api/SignerZcash.ts | Updates the public interface method signature for signTransaction. |
| packages/signer/signer-zcash/src/api/model/TransactionOptions.ts | Cleans up transaction options type (removes placeholder comment). |
| packages/signer/signer-zcash/src/api/model/CreateTransactionArg.ts | Introduces legacy-compatible transaction arg types. |
| packages/signer/signer-zcash/src/api/index.ts | Re-exports new legacy transaction types and return type. |
| packages/signer/signer-zcash/src/api/app-binder/SignTransactionDeviceActionTypes.ts | Changes signTransaction output type to HexaString. |
| packages/signer/signer-zcash/README.md | Documents the new signing API and provides detailed usage guidance. |
| apps/sample/src/components/SignerZcashView/index.tsx | Updates sample app UI to build LegacyCreateTransactionArg (up to 3 inputs). |
| apps/sample/src/components/SessionIdWrapper.tsx | Loosens component type to React.ComponentType for dynamic import use. |
| apps/sample/src/components/ResizableTextArea.tsx | Adds disabled state styling/behavior to the resizable text area. |
| apps/sample/src/app/signers/zcash/page.tsx | Disables SSR for Zcash signer view via dynamic import. |
| .changeset/warm-rivers-build.md | Adds a minor changeset for the Zcash signer API + feature work. |
Comments suppressed due to low confidence (4)
packages/signer/signer-zcash/src/internal/app-binder/task/GetTrustedInputTask.ts:350
splitTransactionToTrustedInputChunksno longer verifies that parsing consumed the full input transaction (the previousoffset !== transaction.lengthguard was removed). Without that check, extra trailing bytes intransactioncan be silently ignored and still sent to the device as a “valid” trusted input. Consider reinstating a strict consumption check (or explicitly documenting why trailing bytes are acceptable).
if (isTxV4) {
chunks.push(transaction.slice(offset));
offset = transaction.length;
} else {
chunks.push(splitV5ExtraData(locktime, expiry));
}
return splitForApduData(chunks);
packages/signer/signer-zcash/src/internal/app-binder/command/SignTransactionCommand.ts:72
SignTransactionCommand.getApdu()hard-codesins: 0x48instead of using the sharedINS.SIGN_TRANSACTIONconstant fromcommand/utils/apduHeaderUtils. Other commands consistently useINS.*(e.g.,ProvideOutputFullChangePathCommand.ts:55usesINS.FINALIZE_INPUT), so this should follow the same pattern for consistency and easier future refactors.
const apduArgs: ApduBuilderArgs = {
cla: ZCASH_CLA,
ins: 0x48,
p2: P2.DEFAULT,
p1: 0x00,
};
packages/signer/signer-zcash/src/internal/app-binder/task/SignTransactionTask.ts:114
outputScriptHexis parsed viaBuffer.from(outputScriptHex, "hex"), which does not reliably throw on malformed/odd-length hex and can produce truncated or unexpected bytes. Since this is user-provided API input, consider validating thatoutputScriptHexis a non-empty, even-length hex string (and erroring early) before sending APDUs.
timestamp: Buffer.alloc(0),
};
const outputScript = Buffer.from(outputScriptHex, "hex");
packages/signer/signer-zcash/src/internal/app-binder/command/SignTransactionCommand.ts:104
parseResponse()force-setssignature[0] = 0x30for any non-empty response. If the goal is to normalize the known Ledger Wallet log quirk where signatures start with0x31, it would be safer to only rewrite when the first byte is actually0x31(so unexpected/non-DER payloads aren’t silently mutated).
).orDefaultLazy(() => {
const signature = new Uint8Array(apduResponse.data);
if (signature.length > 0) {
signature[0] = 0x30;
}
return CommandResultFactory({
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
bf3cf3e to
34c7368
Compare
There was a problem hiding this comment.
This assignment isn't doing anything anymore.
|


📝 Description
Implements transparent Zcash payment signing in
@ledgerhq/device-signer-kit-zcashby replacing the placeholdersignTransactionflow with a full Ledger Wallet–compatible pipeline.Problem:
signTransactionpreviously accepted a rawderivationPath+Uint8Arrayand did not perform the multi-step Zcash signing protocol (trusted inputs, untrusted hash, Sapling commit, signature assembly).Solution:
LegacyCreateTransactionArg/LegacyTransaction(aligned with Ledger WalletcreatePaymentTransactionandsplitTransaction).SignTransactionTask: trusted-input collection per UTXO, change-path handling, untrusted hash input, per-input signing, optional Sapling output commit, and serialized signed transaction output.StartUntrustedHashTransactionInputCommand,HashOutputFullCommand,ProvideOutputFullChangePathCommand,ZcashSaplingOutputCommitCommand, plus updates toSignTransactionCommand.legacyTransactionUtilsfor v5 transaction building, script parsing, and wire serialization.GetTrustedInputTaskfor previous-tx overrides when Sapling/Orchard payloads are not represented in transparentoutputs.SignTransactionTaskintegration tests driven by Ledger Wallet APDU log fixtures from 2026-05-11 / 2026-05-12).API change (minor):
signTransactionnow takes(args: LegacyCreateTransactionArg, options?)instead of(derivationPath, transaction).❓ Context
✅ Checklist
Pull Requests must pass CI checks and undergo code review. Set the PR as Draft if it is not yet ready for review.
🧐 Checklist for the PR Reviewers