Recommended: JavaScript SDK with React Hooks
For new React apps, we recommend the JavaScript SDK with React Hooks (
@dynamic-labs-sdk/react-hooks) instead of the legacy React SDK documented here. The JS SDK comes with many benefits such as a much smaller bundle size and other optimizations. Use the React quickstart (JavaScript SDK) to get started.Signing PSBTs (Partially Signed Bitcoin Transactions) for Bitcoin Embedded Wallets
This guide explains how to use thesignPsbt method to sign Partially Signed Bitcoin Transactions (PSBTs) for Bitcoin embedded wallets. By default the method signs only the inputs related to the user’s wallet and returns a signed (but not finalized) PSBT for review and finalization. You can also opt in to co-signing a P2WSH multisig input.
Overview
PSBTs allow multiple parties to collaboratively build and sign Bitcoin transactions. ThesignPsbt method:
- Signs only inputs that belong to the user’s wallet address, plus any P2WSH multisig input whose witness script you allow with
allowedWitnessScripts - Does NOT finalize the PSBT, which remains partially signed for review
- Returns a signed PSBT that can be reviewed, combined with other signatures, and finalized by the user
Method Signature
Type Definitions
For Embedded Wallets
signingIndexes, allowedSighash, and allowedWitnessScripts are available in @dynamic-labs/bitcoin 5.14.0 and later.- Only require
unsignedPsbtBase64. All other fields are optional. - Read the sighash type from the PSBT. An input that declares none is signed with SIGHASH_ALL (0x01), or SIGHASH_DEFAULT (0x00) on a Taproot wallet.
- Sign all inputs that belong to the wallet address, unless you limit them with
signingIndexes. - Sign a P2WSH multisig input only when you list its witness script in
allowedWitnessScripts. - Do not support the
signatureparameter
Important Notes
PSBT is NOT Finalized
ThesignPsbt method does NOT finalize the PSBT. It only signs the inputs that belong to the user’s wallet. The returned PSBT:
- Contains signatures for the user’s inputs
- Remains in PSBT format (not a finalized transaction)
- Can be reviewed by the user before finalization
- Can be combined with signatures from other parties
- Must be finalized before broadcasting
Signing Only User-Related Inputs
By default the method signs all inputs that belong to the user’s wallet address. To sign only some of them, passsigningIndexes. Every index you list must belong to the wallet, otherwise the call throws an error and signs nothing. Inputs that belong to other addresses are left unsigned, unless they are P2WSH multisig inputs you allow with allowedWitnessScripts.
🔍 User Review and Finalization
After signing, the PSBT should be:- Reviewed by the user to verify transaction details
- Combined with other signatures if it’s a multi-party transaction
- Finalized using a Bitcoin library (e.g.,
bitcoinjs-lib) - Broadcast to the Bitcoin network
Usage Examples
Basic PSBT Signing for Embedded Wallets
This example signs all inputs that belong to the user’s embedded wallet:Complete Example with Review and Finalization
This example shows the complete flow: signing, reviewing, and finalizing a PSBT:Co-signing P2WSH multisig inputs
To co-sign a P2WSH multisig, for example a 2-of-3 that holds the embedded wallet’s key next to keys held elsewhere, pass the multisig’s witness script inallowedWitnessScripts. This requires @dynamic-labs/bitcoin 5.14.0 or later.
allowedWitnessScripts is an array of hex-encoded witness scripts. The wallet signs a P2WSH input only when all of these hold:
- The input’s witness script is in
allowedWitnessScripts. - The SHA-256 of the witness script matches the input’s
scriptPubKey. - The script is a standard
m-of-nmultisig. - The wallet’s own compressed public key is one of the keys in the script.
publicKey on the wallet’s Native SegWit entry in primaryWallet.additionalAddresses.
An input that fails any check is not signed. If you also pass signingIndexes naming that input, the call throws signingIndexes contains indexes that do not belong to the signing address.
Signature Hash Types
Embedded wallets read the sighash type from the PSBT (BIP-174PSBT_IN_SIGHASH_TYPE). An input that declares no type is signed with SIGHASH_ALL (0x01), or SIGHASH_DEFAULT (0x00) on a Taproot wallet.
Use allowedSighash to restrict which declared types the wallet accepts. The option can only reject a type, never select one. If an input declares a type outside the list, the call throws an error and signs nothing. An omitted or empty allowedSighash accepts any declared type.
Embedded Wallet Specific Notes
For embedded wallets:-
Simple default: Only
unsignedPsbtBase64is required: -
Input selection: The method signs all inputs that belong to the wallet address. Pass
signingIndexesto sign a subset. -
Sighash: The type comes from the PSBT. Use
allowedSighashto restrict which types are accepted. -
P2WSH multisig: Inputs of this kind are signed only when you list their witness script in
allowedWitnessScripts. -
No Signature Parameter: The
signatureparameter is not supported (TypeScript will prevent you from using it). - MFA Support: The signing process may require MFA authentication if enabled.
Error Handling
Common errors and how to handle them:Invalid PSBT Format
Best Practices
- Always Review Before Finalization: Parse and display the PSBT details to the user before finalization
- Validate PSBT Format: Check that the PSBT is valid before attempting to sign
- Handle Errors Gracefully: Wrap
signPsbtcalls in try-catch blocks - Restrict What You Sign: Set
allowedSighashto the types you expect, andsigningIndexeswhen you only want some inputs signed - Don’t Finalize Automatically: Let the user review and finalize the PSBT manually
- Store Signed PSBTs Securely: Signed PSBTs contain sensitive information, so handle them securely
PSBT Workflow
The typical PSBT workflow is:- Build PSBT: Create an unsigned PSBT with transaction details
- Sign PSBT: Use
signPsbtto sign inputs belonging to the user - Review PSBT: Parse and display transaction details for user review
- Combine Signatures: If multi-party, combine with other signatures
- Finalize PSBT: Convert the PSBT to a finalized transaction
- Broadcast Transaction: Send the finalized transaction to the Bitcoin network
Additional Resources
- Dynamic Labs Documentation
- BIP 174: Partially Signed Bitcoin Transaction Format
- bitcoinjs-lib PSBT Documentation
- Create a PSBT guide for testing
- Sign a PSBT (External Wallets) for external wallet flows