Skip to content

Feat/connect compose psbt tx - #26056

Open
szymonlesisz wants to merge 10 commits into
developfrom
feat/connect-psbt
Open

Feat/connect compose psbt tx#26056
szymonlesisz wants to merge 10 commits into
developfrom
feat/connect-psbt

Conversation

@szymonlesisz

@szymonlesisz szymonlesisz commented Mar 19, 2026

Copy link
Copy Markdown
Contributor

Description

  • add PSBT minimal parser
  • add composePsbt method.
    When requested parse psbt data and map inputs/outputs to trezor protobuf format, find tx inputs in known account utxos set, find tx outputs in known account addresses set.

Resolve
#22565

Screenshots:

🔍 Currents Test Results

🔍 Suite desktop test results: View in Currents

🔍 Suite web test results: View in Currents

🔍 Suite native android test results: View in Currents

🔒 Quarantined E2E Tests

Trezor Suite (web) — 5 test(s)
Test Type
Staking - Cardano > Stake Cardano 🤖 auto
Suite Sync - Update and Remove Labels > Update and remove labels syncs correctly to relay 🤖 auto
Trading - Swap > Swap SOL USDT token to ETH 🤖 auto
Trading - Swap coin to token > Swap Solana to USDC 🤖 auto
Quarantine test: "Recovery T2T1 - dry run,Recovery after partial recovery" 🙋 manual

Updated: 2026-09-08T12:09:11.092Z • 5 test(s) total

Trezor Suite (desktop) — 4 test(s)
Test Type
Staking - Cardano > Stake Cardano 🤖 auto
Suite Sync - Update and Remove Labels > Update and remove labels syncs correctly to relay 🤖 auto
Quarantine test: "Suite Sync - Quota Manager top-up,Exceeded wallet limit is topped up from the device pool" 🙋 manual
Trading - Swap > Swap SOL USDT token to ETH 🤖 auto

Updated: 2026-09-08T12:05:53.450Z • 4 test(s) total

🤖 LLM Test Recommendations

Summary: The changes concentrate on Bitcoin/PSBT transaction handling in @trezor/connect and @trezor/utxo-lib, including composePsbt, output composition, reference transactions, and PSBT parsing. The highest risk is regressions in Bitcoin transaction signing and sending. Rather than running the 134 tests that transitively import the broad utility files, the recommended strategy targets tests that actually construct, sign, or broadcast Bitcoin (and Bitcoin-like) transactions, plus the direct Connect signTransaction test. Type definitions, test fixtures, the CI matrix generator, and the composePsbt method itself are not exercised by the available suite/e2e candidates and should be covered by connect-level unit/e2e tests instead.

Changed files (17)
  • packages/connect-common/src/callableMethods.ts
  • packages/connect-common/src/types/api/bitcoin.type-test.ts
  • packages/connect-common/src/types/api/bitcoin/composePsbt.ts
  • packages/connect-common/src/types/api/bitcoin/index.ts
  • packages/connect-common/src/types/index.ts
  • packages/connect/e2e/__fixtures__/composePsbt.ts
  • packages/connect/e2e/__fixtures__/index.ts
  • packages/connect/src/api/bitcoin/outputs.ts
  • packages/connect/src/api/bitcoin/parsePsbt.ts
  • packages/connect/src/api/bitcoin/refTx.ts
  • packages/connect/src/api/composePsbt.ts
  • packages/connect/src/api/index.ts
  • packages/utxo-lib/src/__fixtures__/psbt.ts
  • packages/utxo-lib/src/index.ts
  • packages/utxo-lib/src/psbt.test.ts
  • packages/utxo-lib/src/psbt.ts
  • scripts/ci/connect-test-matrix-generator.js

Recommended tests (8)

🔴 High priority (4)
  • suite/e2e/tests/trezor-connect/signTransaction.test.ts — Directly exercises TrezorConnect.signTransaction for a BTC transaction, which shares the same Bitcoin output, reference transaction, and PSBT parsing/composition code paths modified in connect and utxo-lib. A regression here would be immediately visible in Connect-based signing flows.
  • suite/e2e/tests/wallet/pending-transactions.test.ts — Sends multiple Bitcoin regtest transactions with multiple outputs and verifies pending/confirmed state transitions. This directly exercises Bitcoin transaction composition, output handling, and broadcast paths affected by outputs.ts, refTx.ts, and psbt.ts changes.
  • suite/e2e/tests/wallet/send-doge.test.ts — Sends Dogecoin and validates device prompt amounts, total, fee, and address formatting. Dogecoin uses the Bitcoin-like output/refTx/PSBT infrastructure, so this catches regressions in UTXO transaction construction.
  • suite/e2e/tests/wallet/send-form-regtest.test.ts — Tests Bitcoin send form with multiple outputs, OP_RETURN data, locktime by block height, and satoshi unit switching. These features directly depend on correct output composition and transaction serialization logic touched by the changes.
🟡 Medium priority (4)
  • suite/e2e/tests/trading/sell-bitcoin.test.ts — Sells Bitcoin through the trading flow, requiring a real BTC send transaction to a provider address with device signing. This exercises the end-to-end output construction and signing path in a different user flow than wallet sends.
  • suite/e2e/tests/trading/swap-fees-bitcoin.test.ts — Performs a BTC swap with custom fee settings and verifies fee/total details on both the app prompt and the hardware device. Custom fee handling reaches deep into Bitcoin transaction composition and fee calculation logic.
  • suite/e2e/tests/wallet/import-btc-csv.test.ts — Imports a CSV file to populate multiple send outputs with addresses, amounts, and metadata labels. This exercises output creation and label association in the Bitcoin send form.
  • suite/e2e/tests/wallet/send-form-ltc.test.ts — Sends Litecoin using an output originating from a MimbleWimble peg-out transaction. This tests handling of non-standard Bitcoin-like outputs and custom blockbook backend integration.

⚠️ Changes with no test coverage (11)

  • packages/connect-common/src/types/api/bitcoin.type-test.ts
  • packages/connect-common/src/types/api/bitcoin/composePsbt.ts
  • packages/connect-common/src/types/api/bitcoin/index.ts
  • packages/connect-common/src/types/index.ts
  • packages/connect/e2e/__fixtures__/composePsbt.ts
  • packages/connect/e2e/__fixtures__/index.ts
  • packages/connect/src/api/bitcoin/parsePsbt.ts
  • packages/connect/src/api/composePsbt.ts
  • packages/utxo-lib/src/__fixtures__/psbt.ts
  • packages/utxo-lib/src/psbt.test.ts
  • scripts/ci/connect-test-matrix-generator.js

Updated: 2026-09-08T12:05:55.079Z

🌐 Preview deployments

🌐 Suite Web preview: https://dev.suite.sldev.cz/suite-web/feat/connect-psbt/web/

@szymonlesisz szymonlesisz added trading Related to Trading connect Connect API related (ie. fee calculation) no-project This label is used to specify that PR doesn't need to be added to a project labels Mar 19, 2026
@szymonlesisz
szymonlesisz force-pushed the feat/connect-psbt branch 2 times, most recently from 3244e95 to 6fa44ba Compare June 15, 2026 08:36
@szymonlesisz
szymonlesisz force-pushed the feat/connect-psbt branch 2 times, most recently from 93d46b7 to b8e8a84 Compare June 15, 2026 12:36
@szymonlesisz
szymonlesisz marked this pull request as ready for review June 15, 2026 12:44
@szymonlesisz
szymonlesisz requested a review from Copilot June 15, 2026 12:44

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.

Pull request overview

Adds PSBT (BIP-174 v0) support to the Connect transaction composition flow by introducing a minimal PSBT parser in utxo-lib and a new psbtTransactionData parameter for composeTransaction precompose requests, enabling mapping PSBT inputs/outputs to Trezor protobuf types (including OP_RETURN).

Changes:

  • Implement minimal PSBT parser/serializer (Psbt) in @trezor/utxo-lib with fixtures + unit tests.
  • Extend composeTransaction API/types/docs with optional psbtTransactionData and add PSBT parsing path in Connect.
  • Refactor output-script parsing into a shared helper and add E2E fixtures covering PSBT precompose.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/utxo-lib/src/psbt.ts Adds minimal PSBTv0 parser/serializer and exposes unsigned tx + maps.
packages/utxo-lib/src/index.ts Re-exports Psbt from the library entrypoint.
packages/utxo-lib/tests/fixtures/psbt.ts Adds PSBT fixtures (BIP174 + derived vectors).
packages/utxo-lib/tests/psbt.test.ts Adds unit tests for parsing/round-tripping/strictness and mutation serialization.
packages/connect/src/api/bitcoin/parsePSBTx.ts Adds PSBT-to-PrecomposeResultFinal mapping (inputs/outputs/fee computation).
packages/connect/src/api/composeTransaction.ts Adds psbtTransactionData param and precompose fast-path using PSBT parsing.
packages/connect/src/api/bitcoin/outputs.ts Exposes shared parseOutputScript helper (address vs OP_RETURN).
packages/connect/src/api/bitcoin/refTx.ts Switches to shared parseOutputScript helper and adjusts OP_RETURN handling.
packages/connect/e2e/fixtures/composeTransaction.ts Adds PSBT precompose fixture cases (mainnet P2PKH + testnet P2WPKH/OP_RETURN).
packages/connect-explorer/src/pages/methods/bitcoin/composeTransaction.mdx Documents psbtTransactionData in Explorer schema/param descriptions.
packages/connect-common/src/types/api/composeTransaction.ts Extends public API types with psbtTransactionData.
packages/connect-common/src/types/api/tests/bitcoin.ts Updates type-level API tests to include psbtTransactionData.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/connect/src/api/bitcoin/parsePSBTx.ts
Comment thread packages/connect/src/api/composeTransaction.ts Outdated
Comment thread packages/connect/src/api/composeTransaction.ts Outdated
Comment thread packages/connect/src/api/bitcoin/parsePSBTx.ts
@vytick
vytick requested a review from FreeWall August 24, 2026 12:40
@vytick vytick moved this to 🔎 Needs review in Suite Aug 24, 2026
@vytick vytick assigned vytick and FreeWall and unassigned vytick Aug 24, 2026
@trezor-bot

trezor-bot Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

✅ Previously successful run of [Test] suite-native Android E2E workflow has been found.
⏭️ Skipping tests for this run.
💡 If you are unsure about your latest changes, please rerun the workflow manually. (Use the Re-run all jobs option)


export declare function composePsbt(
params: Params<ComposePsbtParams>,
): Response<PrecomposeResultFinal>;

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.

new api is introduced here so it is natural to ask if we really need all the fields in its return type?

these are non negotiable - type, inputs, outputs. But the question is do we also need these? fee totalSpent feePerByte bytes, outputsPermutation, and max.

@szymonlesisz szymonlesisz Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes we do need them, similar to composeTransaction this method is meant to return data for suite send form and later for TrezorConnect.signTrancation

Comment thread packages/connect/src/api/composePsbt.ts Outdated
Comment on lines +28 to +31
const coinInfo = getBitcoinNetwork(payload.coin);
if (!coinInfo) {
throw ERRORS.TypedError('Method_UnknownCoin');
}

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.

consistency improvement #32183

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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


export type ComposePsbtParams = {
account: {
path: string;

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.

nitpick #32182

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

}
}

const fee = sumOfInputs - sumOfOutputs;

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.

little hardening suggested here #32184
not very important.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

bytes,
inputs,
outputs,
outputsPermutation: [],

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.

is this really okey to ignore outuptsPermutation? maybe nobody uses it but if the return type is PrecomposeResultFinal it could be confusing that it does not contain same data

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

}
outputs.push({
script_type: 'PAYTOOPRETURN',
amount: '0',

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.

I understand that op_return outputs are basically unspendable but is it necessary to set their amout to 0? doesn't it have some effect on fee calculation? 🤔

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

no it doesnt have effect on fe calculation, but this is the shape of PROTO.TxOutputType used in the next step in TrezorConnect.signTransaction

}

const fee = sumOfInputs - sumOfOutputs;
const bytes = psbt.unsignedTx.virtualSize();

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.

my agent claims that using unsignedTx for fee calculation inflates fee

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

good catch, now its calculated using getTransactionVbytes (TxWeightCalculator)

6b8092f

const bytes = psbt.unsignedTx.virtualSize();
const feePerByte = Number(fee) / bytes;

return {

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.

what about version and lock_time? if they are provided in psbt data, they should be decoded and passed to the subsequent singTransaction call. If they are not, we are safe, but in that case I would at least throw some "ntot supported error" from psbt parsing

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

cdf40ff added to ComposePsbtResult (extended PrecomposeResultFinal)

Comment on lines +56 to +58
if (unsignedTxEntries.length !== 1 || !unsignedTxEntries[0]) {
throw new Error('PSBT must contain exactly one unsigned transaction.');
}

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.

yes, but are we checking that it is really unsigned? according to the specs and my agent it should be unsigned but the Transaction.fromBuffer is just a general parser of btc transaction which does not enforce this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

connect Connect API related (ie. fee calculation) no-project This label is used to specify that PR doesn't need to be added to a project trading Related to Trading

Projects

Status: 🔎 Needs review

Development

Successfully merging this pull request may close these issues.

5 participants