Skip to content

✨ (signer-btc-legacy) [DSDK-1618]: Add basic transaction signing - #2029

Merged
aussedatlo merged 6 commits into
feat/dsdk-1617-btc-legacy-wallet-xpubfrom
feat/dsdk-1618-btc-legacy-basic-signing
Oct 23, 2026
Merged

aussedatlo merged 6 commits into
feat/dsdk-1617-btc-legacy-wallet-xpubfrom
feat/dsdk-1618-btc-legacy-basic-signing

Conversation

@aussedatlo

@aussedatlo aussedatlo commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

📝 Description

Basic transaction signing for signer-btc-legacy (ticket 1.4 of Plan: Bitcoin family on DMK). Stacked on #2000.

  • signTransaction(transaction, { skipOpenApp }) returns the signed transaction in hexadecimal. Its argument has the shape of hw-app-btc's createPaymentTransaction argument, with Uint8Arrays instead of Buffers, so Ledger Wallet passes what it builds today (ADR, rule 3).

  • Commands 0x42 (trusted input), 0x44 (untrusted hash start), 0x4A (hash outputs and change path) and 0x48 (sign). They take the profile's error map, like LegacyGetAddressCommand, and are exported for signer-zcash.

  • The flow is hw-app-btc's for inputs without SegWit: one trusted input per input, then for each input the whole transaction hashed with that input's script only, the change path, the outputs, and its signature.

  • The trusted input and signing tasks are services of the module (btcLegacyTypes.GetTrustedInputTask, btcLegacyTypes.SignTransactionTask). Their format steps are hooks behind two tokens, bound to the standard format:

    • TrustedInputSerializer: the previous transaction as the data of its 0x42 APDUs. This is where Zcash's v5/v6 parser goes.
    • TransactionSerializer: the header of each 0x44 stream and the signed transaction. This is where Zcash's version group and branch IDs go.

    A kit on another format rebinds them in its container (rebindSync, covered by a test).

  • DOGECOIN_PROFILE (xpubVersion 0x02facafd, from coin-bitcoin's networks.ts).

const { observable } = signer.signTransaction({
  inputs: [[previousTransaction, 1, null, null]],
  associatedKeysets: ["44'/2'/0'/0/0"],
  changePath: "44'/2'/0'/1/0",
  outputScriptHex,
});

Compared with Ledger Wallet. Four reference transactions were signed by ledger-live's own hw-app-btc createTransaction (dd044b36c83) on the real Litecoin and Dogecoin 2.4.13 apps, through the mock server and Speculinho. For each coin: one input and one output; then two inputs with a change output, a lock time and RBF sequences. The previous transactions are synthetic transactions paying the Speculos seed, and their inputs carry 107-byte scripts, split into blocks.

  • Unit test: the kit is replayed against the recorded answers. Every APDU matches hw-app-btc's, in order, and the signed transactions are byte-identical.
  • e2e: the same transactions signed on Flex give hw-app-btc's exact bytes, as the apps sign ECDSA deterministically.

hw-app-btc first sends get app and version (b001) to pick the SegWit trusted input mode. The kit leaves it out, as it has no SegWit flow yet.

Not in this PR (1.5, DSDK-1619):

  • the BIP143 flow;
  • the per-transaction P2 of a new transaction, which is 0x00 here;
  • a hook for extra steps such as Zcash's Sapling commit. It only runs in the BIP143 flow, so it would have no call site yet.

Sample app:

  • Litecoin screen: a "Sign Transaction" action.
  • New Dogecoin screen with the same action. Both take raw previous transactions, parsed by a shared util.
  • Playwright: LtcSignerDriver becomes BtcLegacySignerDriver, which takes the coin, and gets a dogeSigner fixture.
  • 6 specs against the real apps on Flex 1.7.0, 3 per coin: the two transactions, and a rejection that returns 6985.

❓ Context

  • JIRA or GitHub link: DSDK-1618
  • Feature: Legacy Bitcoin signer kit, basic signing

✅ Checklist

Pull Requests must pass CI checks and undergo code review. Set the PR as Draft if it is not yet ready for review.

  • Covered by automatic tests
  • Changeset is provided
  • Documentation is up-to-date
  • Impact of the changes:
    • signer-btc-legacy: new sign transaction API, new commands, tasks and format hooks in its module, Dogecoin profile
    • Sample app: Sign Transaction on the Litecoin screen, new Dogecoin screen; Playwright specs in signers/litecoin and signers/dogecoin (6 new specs, all on real Speculos), driver renamed

🧐 Checklist for the PR Reviewers

  • The code aligns with the requirements described in the linked JIRA or GitHub issue.
  • The PR description clearly documents the changes made and explains any technical trade-offs or design decisions.
  • There are no undocumented trade-offs, technical debt, or maintainability issues.
  • The PR has been tested thoroughly, and any potential edge cases have been considered and handled.
  • Any new dependencies have been justified and documented.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
device-sdk-ts-sample Ready Ready Preview Oct 23, 2026 10:18am UTC
doc-device-management-kit Ready Ready Preview Oct 23, 2026 10:18am UTC

Request Review

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Danger Check Results

Messages

✅

Danger: All checks passed successfully! 🎉

Generated by 🚫 dangerJS against b74a0aa

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Unresolved validation, unlocking-script construction, and command-payload sizing issues can produce invalid transactions or prevent signing.

3 open issues
What changed in this PR

Adds basic non-SegWit transaction signing to signer-btc-legacy, building on the extended-public-key support in #2000 and extending the sample app to Dogecoin.

Changes:

  • Adds the signing API, device commands, trusted-input processing, and replaceable transaction serializers.
  • Introduces a Dogecoin profile and transaction-signing forms for Litecoin and Dogecoin.
  • Adds recorded-command replay tests, end-to-end signing and rejection tests, documentation, and a minor-version changeset.
File Description
packages/​signer/​signer-btc-legacy/​src/​internal/​use-cases/​transaction/​SignTransactionUseCase.ts Forwards signing requests and options.
packages/​signer/​signer-btc-legacy/​src/​internal/​use-cases/​transaction/​SignTransactionUseCase.test.ts Tests forwarding and default options.
packages/​signer/​signer-btc-legacy/​src/​internal/​DefaultSignerBtcLegacy.ts Exposes transaction signing.
packages/​signer/​signer-btc-legacy/​src/​internal/​DefaultSignerBtcLegacy.test.ts Tests profile-specific signing dispatch.
packages/​signer/​signer-btc-legacy/​src/​internal/​btcLegacyTypes.ts Adds signing and serializer injection tokens.
packages/​signer/​signer-btc-legacy/​src/​internal/​btcLegacyModule.ts Registers signing services and serializers.
packages/​signer/​signer-btc-legacy/​src/​internal/​btcLegacyModule.test.ts Tests service bindings and serializer replacement.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​task/​utils/​legacyTransactionUtils.ts Adds integer encoding and script chunking.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​task/​SignTransactionTask.ts Coordinates validation, hashing, and signing.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​task/​SignTransactionTask.test.ts Tests reference transactions and errors.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​task/​GetTrustedInputTask.ts Streams previous transactions to the device.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​task/​GetTrustedInputTask.test.ts Tests streaming and error propagation.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​task/​format/​TrustedInputSerializer.ts Defines the trusted-input serialization hook.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​task/​format/​TransactionSerializer.ts Defines signing serialization hooks.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​task/​format/​StandardTrustedInputSerializer.ts Serializes standard previous transactions.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​task/​format/​StandardTransactionSerializer.ts Serializes headers and signed transactions.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​task/​__fixtures__/​referenceTransactions.ts Stores reference exchanges and signed bytes.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​command/​utils/​apduHeaderUtils.ts Adds command-header constants.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​command/​StartUntrustedHashTransactionInputCommand.ts Implements input-hashing commands.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​command/​StartUntrustedHashTransactionInputCommand.test.ts Tests hashing headers and errors.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​command/​SignTransactionCommand.ts Implements signature requests and response parsing.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​command/​SignTransactionCommand.test.ts Tests signature encoding and rejection handling.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​command/​ProvideOutputFullChangePathCommand.ts Sends the change derivation path.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​command/​ProvideOutputFullChangePathCommand.test.ts Tests change-path encoding and errors.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​command/​HashOutputFullCommand.ts Streams output-hashing payloads.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​command/​HashOutputFullCommand.test.ts Tests output chunk flags and rejection.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​command/​GetTrustedInputCommand.ts Implements trusted-input commands.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​command/​GetTrustedInputCommand.test.ts Tests trusted-input encoding and responses.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​BtcLegacyAppBinder.ts Runs signing in the profile’s app.
packages/​signer/​signer-btc-legacy/​src/​internal/​app-binder/​BtcLegacyAppBinder.test.ts Tests signing dispatch and preflight rejection.
packages/​signer/​signer-btc-legacy/​src/​api/​SignerBtcLegacy.ts Adds the public signing method.
packages/​signer/​signer-btc-legacy/​src/​api/​profiles/​dogecoinProfile.ts Defines the Dogecoin profile.
packages/​signer/​signer-btc-legacy/​src/​api/​model/​TransactionOptions.ts Defines signing options.
packages/​signer/​signer-btc-legacy/​src/​api/​model/​CreateTransactionArg.ts Defines transaction input models.
packages/​signer/​signer-btc-legacy/​src/​api/​index.ts Exports signing APIs and extension hooks.
packages/​signer/​signer-btc-legacy/​src/​api/​app-binder/​SignTransactionDeviceActionTypes.ts Defines signing results and interaction types.
packages/​signer/​signer-btc-legacy/​README.md Documents signing usage and format hooks.
apps/​sample/​src/​utils/​btcLegacyTransaction.ts Parses raw transactions and form values.
apps/​sample/​src/​components/​SignerView/​index.tsx Adds Dogecoin navigation.
apps/​sample/​src/​components/​SignerLitecoinView/​index.tsx Adds the Litecoin signing form.
apps/​sample/​src/​components/​SignerDogecoinView/​index.tsx Adds the Dogecoin signing view.
apps/​sample/​src/​app/​signers/​dogecoin/​page.tsx Adds the Dogecoin route.
apps/​sample/​playwright/​utils/​drivers/​BtcLegacySignerDriver.ts Generalizes the driver and adds signing interactions.
apps/​sample/​playwright/​fixtures.ts Provides Litecoin and Dogecoin drivers.
apps/​sample/​playwright/​cases/​signers/​litecoin/​sign-transaction.spec.ts Adds Litecoin signing and rejection scenarios.
apps/​sample/​playwright/​cases/​signers/​litecoin/​get-address.spec.ts Updates the renamed driver import.
apps/​sample/​playwright/​cases/​signers/​dogecoin/​sign-transaction.spec.ts Adds Dogecoin signing and rejection scenarios.
.changeset/​bitcoin-legacy-sign-transaction.md Records the minor-version feature addition.

Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Unresolved moderate issues remain in transaction parsing and signing-input validation, including empty outputs, malformed paths, and numeric range handling.

3 open issues
2 resolved since last review

Review effort: Lite

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The unresolved critical API compatibility issue and two moderate validation issues must be addressed before approval.

1 open issue
3 resolved since last review

Review effort: Lite

Comment on lines 36 to +38
private readonly profile: LegacyCoinProfile<ErrorCodes>,
@inject(btcLegacyTypes.SignTransactionTask)
private readonly signTransactionTask: SignTransactionTask<ErrorCodes>,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

legit but pkg is unreleased

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Validate associatedKeysets and changePath before opening the app so malformed paths are rejected during preflight.

2 open issues

Review effort: Lite

Comment on lines +138 to +142
const error = this.getTrustedInputTask.validate(transaction);
if (error !== undefined) {
return error;
}
}
@sonarqubecloud

Copy link
Copy Markdown

@aussedatlo
aussedatlo added this pull request to the merge queue Oct 23, 2026
Merged via the queue into develop with commit f35228e Oct 23, 2026
26 of 33 checks passed
@aussedatlo
aussedatlo deleted the feat/dsdk-1618-btc-legacy-basic-signing branch October 23, 2026 10:43

This branch was successfully deployed

2 active deployments
Preview – device-sdk-ts-sample — b74a0aa7 Deployed Oct 23, 2026 by vercel[bot]
Preview – doc-device-management-kit — b74a0aa7 Deployed Oct 23, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants