Bitcoin (PSBT)
Bitcoin requests are PSBTs. Your wallet builds the PSBT; BitTool Signer adds its signatures and returns the PSBT; your wallet finalizes and broadcasts.
Transport
| Request | Response | Notes |
|---|---|---|
ur:crypto-psbt | ur:crypto-psbt | Recommended. UR body = CBOR byte string holding the PSBT. |
ur:psbt | ur:psbt | The newer registry name, same content. |
BBQr (B$…, encodings H, 2, Z) | BBQr (2 or H) | Coinkite's format. Z (deflate) is accepted; responses use 2 (Base32), or H if the request did. |
Base64 (cHNidP…) or hex (70736274ff…) text in one QR code | Same text if ≤ 1,800 characters, otherwise animated ur:crypto-psbt | For small transactions. |
.psbt file (Base64 or hex, line-wrapped is fine) | Same | Via Files/AirDrop on the signer phone. |
The response always uses the request's own format (except as noted), so you can reuse the decoder you already have.
What the PSBT must contain
| Requirement | Detail |
|---|---|
| Version | PSBT v0 or v2 (BIP 370). v0 is the safest choice. |
| Size | 1–100 inputs, 1–100 outputs. |
| Derivation | Every input the signer should sign carries bip32Derivation (master fingerprint + full path) for its key. Taproot inputs use tapBip32Derivation and tapInternalKey. |
| Previous transactions | Legacy and SegWit v0 inputs (P2PKH, P2WPKH, P2SH-P2WPKH, P2WSH …) need the full previous transaction in nonWitnessUtxo. witnessUtxo alone is accepted only when every input is Taproot. |
| Sighash | SIGHASH_ALL, or SIGHASH_DEFAULT for Taproot. Anything else is rejected. |
| Change | Give change outputs their bip32Derivation too. BitTool Signer labels an output "change" only after re-deriving its script from its own keys. |
| Outputs | Standard scripts and OP_RETURN up to 83 bytes. |
| Network | Mainnet only. |
nonWitnessUtxo is requiredSegWit v0 signatures commit to the amount of the input being spent but not to the amounts of the other inputs. A malicious coordinator can lie about input amounts across two signing rounds and trick a signer into paying a huge fee (the SegWit fee attack disclosed in 2020). With the full previous transaction the signer can check every amount itself. Taproot signatures commit to all input amounts, which is why all-Taproot transactions are exempt.
Supported scripts
| Script | Signs |
|---|---|
| P2PKH, P2WPKH, P2SH-P2WPKH | Yes (single key) |
| P2TR key path (BIP86) | Yes |
Multisig P2SH, P2WSH, P2SH-P2WSH (multi/sortedmulti) | Yes, one partial signature per local key |
P2TR script path, CHECKSIG/CHECKSIGVERIFY and CHECKSIGADD threshold leaves (leaf version 0xc0) | Yes |
| MuSig2 and other scripts | No |
The response
The response is your PSBT with signatures added: partialSig for ECDSA inputs, tapKeySig or tapScriptSig for Taproot. Nothing is finalized and nothing else changes. Before you finalize:
- Check that the unsigned transaction is byte-for-byte the one you sent (there is no request ID in PSBT transports).
- Verify every new signature against its input.
- For multisig, combine with the other cosigners' PSBTs.
- Finalize, extract and broadcast.
- Burn with change (R3-01, Low, iPhone only). For a transaction that burns coins with a nonzero
OP_RETURNoutput and also returns change, the one-line summary on BitTool Signer's result screen and in its Activity reads "Every output returns to your wallet". The signing screen itself shows the burn, its amount and the High risk correctly, and the PSBT is unaffected. BitTool Signer for Android 1.0.0 shows the burn in the summary too. - Change at any index (BTS-08, Medium, both apps). An output is treated as change when its script matches one of the wallet's own single-sig profiles at any index, including indexes a watch-only wallet will never scan. Keep change at ordinary indexes, and treat a request that moves everything to an unusual path of the user's wallet with suspicion.
See Security reviews.
Code
Build the PSBT with bitcoinjs-lib and wrap it in ur:crypto-psbt with Keystone's @keystonehq/bc-ur-registry:
import * as bitcoin from 'bitcoinjs-lib';
import { CryptoPSBT } from '@keystonehq/bc-ur-registry';
import { URDecoder } from '@ngraveio/bc-ur';
import { secp256k1 } from '@noble/curves/secp256k1.js';
// utxos: [{ txid, vout, value, prevTxHex, pubkey, path }] path like "m/84'/0'/0'/0/3"
export function buildPsbt({ utxos, to, amount, change, masterFingerprint }) {
const fingerprint = Buffer.from(masterFingerprint, 'hex');
const psbt = new bitcoin.Psbt(); // mainnet
for (const u of utxos) {
const prevTx = bitcoin.Transaction.fromHex(u.prevTxHex);
psbt.addInput({
hash: u.txid,
index: u.vout,
nonWitnessUtxo: Buffer.from(u.prevTxHex, 'hex'), // required for SegWit v0 and legacy inputs
witnessUtxo: { script: prevTx.outs[u.vout].script, value: u.value },
bip32Derivation: [{ masterFingerprint: fingerprint, path: u.path, pubkey: u.pubkey }],
});
}
psbt.addOutput({ address: to, value: amount });
psbt.addOutput({ // change: give the path so the signer can recognize it
address: change.address, value: change.value,
bip32Derivation: [{ masterFingerprint: fingerprint, path: change.path, pubkey: change.pubkey }],
});
const encoder = new CryptoPSBT(psbt.toBuffer()).toUREncoder(400);
const frames = [];
for (let i = 0; i < encoder.fragmentsLength; i++) frames.push(encoder.nextPart().toUpperCase());
return { psbt, frames };
}
Read the signed PSBT back, check it, finalize:
const validator = (pubkey, msghash, signature) => secp256k1.verify(signature, msghash, pubkey, { prehash: false });
export function finalizeSignedPsbt(frames, original) {
const decoder = new URDecoder();
for (const frame of frames) decoder.receivePart(frame);
if (!decoder.isSuccess()) throw new Error('Incomplete or invalid QR');
const ur = decoder.resultUR();
if (ur.type !== 'crypto-psbt') throw new Error(`Expected crypto-psbt, got ${ur.type}`);
const signed = bitcoin.Psbt.fromBuffer(CryptoPSBT.fromCBOR(ur.cbor).getPSBT());
// The signer only adds signatures: the transaction itself must be unchanged.
if (!signed.data.globalMap.unsignedTx.toBuffer().equals(original.data.globalMap.unsignedTx.toBuffer()))
throw new Error('The signed PSBT is for a different transaction');
if (!signed.validateSignaturesOfAllInputs(validator)) throw new Error('Invalid signature');
signed.finalizeAllInputs();
return signed.extractTransaction().toHex(); // ready to broadcast
}
Test vectors
- P2WPKH with change
- Taproot key path
Input 100,000 sats at m/84'/0'/0'/0/0; send 60,000 sats to bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4, 39,000 sats change to m/84'/0'/0'/1/0, 1,000 sats fee. The previous transaction is synthetic.
Request (your wallet → BitTool Signer)
cHNidP8BAHECAAAAAekP8Koj3Yg9KuehyjwZqkAWg+Oc9XIc9Mif9dK3rUrGAAAAAAD/////AmDqAAAAAAAAFgAUdR526BmRltRUlBxF0bOjI/FDO9ZYmAAAAAAAABYAFD40mF3Kb93J+zaZQOTH2OKHP1KcAAAAAAABAFICAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAD/////AaCGAQAAAAAAFgAUwM681sPTyox13F7GLr5VMw75EOIAAAAAAQEfoIYBAAAAAAAWABTAzrzWw9PKjHXcXsYuvlUzDvkQ4iIGAzDVT9DdQgpuX402JPXzSCyuNQ951fB1O/W+75wtka88GHPF2gpUAACAAAAAgAAAAIAAAAAAAAAAAAAAIgIDAlMkiI5Cmrjj268feAJki5zQHptBhIXF+kwbm1cA4aYYc8XaClQAAIAAAACAAAAAgAEAAAAAAAAAAA==
Show the QR text and raw CBOR
UR:CRYPTO-PSBT/1-3/LPADAXCFADJLCYRFDSIHPRHDKGHKADJZJOJKIDJYZMADAEJSAOAEAEAEADWLBSWTPKCNUTLOFSDRVDOYSGFNCFPKFZCMLSVLNSYKJPCEWKSPNEYKTDRLPMGESWAEAEAEAEAEZMZMZMZMAOHNWDAEAEAEAEAEAECMAEBBKPCKKOVSCFMEMTTYGHMWCEFETTQDOTCNWNFXFRTBHDMKAEAEAEAEAEAECMAEBBFMEEMKHLSGJLUTSOZOENNLFZVESTTPVOLTFHGMNSAEAEAEQZMKTNSA
UR:CRYPTO-PSBT/2-3/LPAOAXCFADJLCYRFDSIHPRHDKGAEAEADAEGMAOAEAEAEADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADAEAEAEAEAEZMZMZMZMADNBLNADAEAEAEAEAECMAEBBRTTORFTBSRTESGLKKPUOHYSWDMRNGOEOBAYTBEVOAEAEAEAEADADCTNBLNADAEAEAEAEAECMAEBBRTTORFTBSRTESGLKKPUOHYSWDMRNGOEOBAYTBEVOCPAMGWBSRYCW
UR:CRYPTO-PSBT/3-3/LPAXAXCFADJLCYRFDSIHPRHDKGAXDYTLGWTIUTFWBKJTHELGENDKYKWFFDDWPLECBSKKTLWTKPFRYKRNWSNSDPMEPEFNCSJKSKTNBKGHAEAELAAEAEAELAAEAEAELAAEAEAEAEAEAEAEAEAEAECPAOAXAOGUDKLOMNFWNYROVLUYPECTKSAOIELUNSTICKNDFPLRLPSKZSGSCWNDHGAEVYOLCSJKSKTNBKGHAEAELAAEAEAELAAEAEAELAADAEAEAEAEAEAEAEAEAEAEGWCEHDPR
59016c70736274ff0100710200000001e90ff0aa23dd883d2ae7a1ca3c19aa401683e39cf5721cf4c89ff5d2b7ad4ac60000000000ffffffff0260ea000000000000160014751e76e8199196d454941c45d1b3a323f1433bd658980000000000001600143e34985dca6fddc9fb369940e4c7d8e2873f529c0000000000010052020000000101010101010101010101010101010101010101010101010101010101010101010000000000ffffffff01a086010000000000160014c0cebcd6c3d3ca8c75dc5ec62ebe55330ef910e20000000001011fa086010000000000160014c0cebcd6c3d3ca8c75dc5ec62ebe55330ef910e222060330d54fd0dd420a6e5f8d3624f5f3482cae350f79d5f0753bf5beef9c2d91af3c1873c5da0a54000080000000800000008000000000000000000000220203025324888e429ab8e3dbaf1f7802648b9cd01e9b418485c5fa4c1b9b5700e1a61873c5da0a540000800000008000000080010000000000000000
Response (BitTool Signer → your wallet)
cHNidP8BAHECAAAAAekP8Koj3Yg9KuehyjwZqkAWg+Oc9XIc9Mif9dK3rUrGAAAAAAD/////AmDqAAAAAAAAFgAUdR526BmRltRUlBxF0bOjI/FDO9ZYmAAAAAAAABYAFD40mF3Kb93J+zaZQOTH2OKHP1KcAAAAAAABAFICAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAD/////AaCGAQAAAAAAFgAUwM681sPTyox13F7GLr5VMw75EOIAAAAAAQEfoIYBAAAAAAAWABTAzrzWw9PKjHXcXsYuvlUzDvkQ4iICAzDVT9DdQgpuX402JPXzSCyuNQ951fB1O/W+75wtka88SDBFAiEAnxTBvsytWOKIqCL+jVnOZoU8wKKB3sg9FqBU6YKagoUCIC4lC/U2vuJKimL4vEacD8f6CnzzwQjDbBZOBoNWSJMgASIGAzDVT9DdQgpuX402JPXzSCyuNQ951fB1O/W+75wtka88GHPF2gpUAACAAAAAgAAAAIAAAAAAAAAAAAAAIgIDAlMkiI5Cmrjj268feAJki5zQHptBhIXF+kwbm1cA4aYYc8XaClQAAIAAAACAAAAAgAEAAAAAAAAAAA==
Show the QR text and raw CBOR
UR:CRYPTO-PSBT/1-3/LPADAXCFADUYCYVWCKDTWYHDNEHKADTPJOJKIDJYZMADAEJSAOAEAEAEADWLBSWTPKCNUTLOFSDRVDOYSGFNCFPKFZCMLSVLNSYKJPCEWKSPNEYKTDRLPMGESWAEAEAEAEAEZMZMZMZMAOHNWDAEAEAEAEAEAECMAEBBKPCKKOVSCFMEMTTYGHMWCEFETTQDOTCNWNFXFRTBHDMKAEAEAEAEAEAECMAEBBFMEEMKHLSGJLUTSOZOENNLFZVESTTPVOLTFHGMNSAEAEAEAEAEADAEGMAOAEAEAEADADADADADADADADADADADADADADADADADADADADADADADADADADADCLBBLDOY
UR:CRYPTO-PSBT/2-3/LPAOAXCFADUYCYVWCKDTWYHDNEADADADADADADAEAEAEAEAEZMZMZMZMADNBLNADAEAEAEAEAECMAEBBRTTORFTBSRTESGLKKPUOHYSWDMRNGOEOBAYTBEVOAEAEAEAEADADCTNBLNADAEAEAEAEAECMAEBBRTTORFTBSRTESGLKKPUOHYSWDMRNGOEOBAYTBEVOCPAOAXDYTLGWTIUTFWBKJTHELGENDKYKWFFDDWPLECBSKKTLWTKPFRYKRNWSNSDPMEPEFNFDDYFEAOCLAENEBBSERNSFPMHDVOLOPDCPZELGHKTOIYLPFNRTOELYUESPFSCMNBGHWLLFNYLFLPAONLJTAAPK
UR:CRYPTO-PSBT/3-3/LPAXAXCFADUYCYVWCKDTWYHDNECXDMDABDYKENRNVOGELEIDYARFFGNSBSSTZSBKKEWFSEAYSRJZCMGLAMLSHFFDMUCXADCPAMAXDYTLGWTIUTFWBKJTHELGENDKYKWFFDDWPLECBSKKTLWTKPFRYKRNWSNSDPMEPEFNCSJKSKTNBKGHAEAELAAEAEAELAAEAEAELAAEAEAEAEAEAEAEAEAEAECPAOAXAOGUDKLOMNFWNYROVLUYPECTKSAOIELUNSTICKNDFPLRLPSKZSGSCWNDHGAEVYOLCSJKSKTNBKGHAEAELAAEAEAELAAEAEAELAADAEAEAEAEAEAEAEAEAEAEHHDLWYGS
5901d870736274ff0100710200000001e90ff0aa23dd883d2ae7a1ca3c19aa401683e39cf5721cf4c89ff5d2b7ad4ac60000000000ffffffff0260ea000000000000160014751e76e8199196d454941c45d1b3a323f1433bd658980000000000001600143e34985dca6fddc9fb369940e4c7d8e2873f529c0000000000010052020000000101010101010101010101010101010101010101010101010101010101010101010000000000ffffffff01a086010000000000160014c0cebcd6c3d3ca8c75dc5ec62ebe55330ef910e20000000001011fa086010000000000160014c0cebcd6c3d3ca8c75dc5ec62ebe55330ef910e222020330d54fd0dd420a6e5f8d3624f5f3482cae350f79d5f0753bf5beef9c2d91af3c4830450221009f14c1beccad58e288a822fe8d59ce66853cc0a281dec83d16a054e9829a828502202e250bf536bee24a8a62f8bc469c0fc7fa0a7cf3c108c36c164e0683564893200122060330d54fd0dd420a6e5f8d3624f5f3482cae350f79d5f0753bf5beef9c2d91af3c1873c5da0a54000080000000800000008000000000000000000000220203025324888e429ab8e3dbaf1f7802648b9cd01e9b418485c5fa4c1b9b5700e1a61873c5da0a540000800000008000000080010000000000000000
Assembled by your wallet
02000000000101e90ff0aa23dd883d2ae7a1ca3c19aa401683e39cf5721cf4c89ff5d2b7ad4ac60000000000ffffffff0260ea000000000000160014751e76e8199196d454941c45d1b3a323f1433bd658980000000000001600143e34985dca6fddc9fb369940e4c7d8e2873f529c024830450221009f14c1beccad58e288a822fe8d59ce66853cc0a281dec83d16a054e9829a828502202e250bf536bee24a8a62f8bc469c0fc7fa0a7cf3c108c36c164e06835648932001210330d54fd0dd420a6e5f8d3624f5f3482cae350f79d5f0753bf5beef9c2d91af3c00000000
6f492df497b5e455fb3305d0272fe9c6dc3d8cc9d0054be3aaefee77daca82b7
Input 50,000 sats at m/86'/0'/0'/0/0, witnessUtxo only (allowed because every input is Taproot); send 49,000 sats, 1,000 sats fee. Schnorr signatures use fresh auxiliary randomness, so your own signature over this PSBT will differ; verify it rather than comparing bytes.
Request (your wallet → BitTool Signer)
cHNidP8BAFICAAAAAX/dUwHqQRbJZhU8W3fRniz4rOZuphwyI6FEAba4ela5AAAAAAD/////AWi/AAAAAAAAFgAUdR526BmRltRUlBxF0bOjI/FDO9YAAAAAAAEBK1DDAAAAAAAAIlEgpghp8NvPHcZZyc7Lr4BQE16p6M3EhwU/HcaICUncaEwhFsyKS8ZNiXvdxfvC9nD3qLoLOGd5EGzxIjxvxdfNb8EVGQBzxdoKVgAAgAAAAIAAAACAAAAAAAAAAAABFyDMikvGTYl73cX7wvZw96i6CzhneRBs8SI8b8XXzW/BFQAA
Show the QR text and raw CBOR
UR:CRYPTO-PSBT/1-2/LPADAOCSWPCYWMRDFWONHDKOHDWDJOJKIDJYZMADAEGMAOAEAEAEADLBUTGUADWDFPCMSOIYBZFNHPKTTTNNDWYAPSVAJTOLCEEYCNOYFYADRPROKNHFRHAEAEAEAEAEZMZMZMZMADISRSAEAEAEAEAEAECMAEBBKPCKKOVSCFMEMTTYGHMWCEFETTQDOTCNWNFXFRTBAEAEAEAEAEADADDNGDSRAEAEAEAEAEAECPGYCXOLAYINWTUYTKCASWHKSOTOAEGWMWTI
UR:CRYPTO-PSBT/2-2/LPAOAOCSWPCYWMRDFWONHDKOSBPELAGDBWHYPTVSSNSSLTAHFHCASWLOASGAUOISGSCLCMSFLEGRSWGTLDKGUTSKZOSAYNJOYLPDRDBDETIOKKBEJZWNCPFNJLSKTSSNJLSEBZCFAEJKSKTNBKHFAEAELAAEAEAELAAEAEAELAAEAEAEAEAEAEAEAEADCHCXSFLEGRSWGTLDKGUTSKZOSAYNJOYLPDRDBDETIOKKBEJZWNCPFNJLSKTSSNJLSEBZAEAEEOJZGYLO
58ea70736274ff01005202000000017fdd5301ea4116c966153c5b77d19e2cf8ace66ea61c3223a14401b6b87a56b90000000000ffffffff0168bf000000000000160014751e76e8199196d454941c45d1b3a323f1433bd6000000000001012b50c3000000000000225120a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c2116cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115190073c5da0a5600008000000080000000800000000000000000011720cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc1150000
Response (BitTool Signer → your wallet)
cHNidP8BAFICAAAAAX/dUwHqQRbJZhU8W3fRniz4rOZuphwyI6FEAba4ela5AAAAAAD/////AWi/AAAAAAAAFgAUdR526BmRltRUlBxF0bOjI/FDO9YAAAAAAAEBK1DDAAAAAAAAIlEgpghp8NvPHcZZyc7Lr4BQE16p6M3EhwU/HcaICUncaEwBE0CiqtbEW/l3qZ5NrQB8IaRcXT9o+CcVa49IBDXZJwmDFlYRnfkafMOiF5IiWbEjfOaLjurboMktvSVjXD4g2UFPIRbMikvGTYl73cX7wvZw96i6CzhneRBs8SI8b8XXzW/BFRkAc8XaClYAAIAAAACAAAAAgAAAAAAAAAAAARcgzIpLxk2Je93F+8L2cPeougs4Z3kQbPEiPG/F181vwRUAAA==
Show the QR text and raw CBOR
UR:CRYPTO-PSBT/1-2/LPADAOCFADDYCYHSFRYNOTHDMKHKADDPJOJKIDJYZMADAEGMAOAEAEAEADLBUTGUADWDFPCMSOIYBZFNHPKTTTNNDWYAPSVAJTOLCEEYCNOYFYADRPROKNHFRHAEAEAEAEAEZMZMZMZMADISRSAEAEAEAEAEAECMAEBBKPCKKOVSCFMEMTTYGHMWCEFETTQDOTCNWNFXFRTBAEAEAEAEAEADADDNGDSRAEAEAEAEAEAECPGYCXOLAYINWTUYTKCASWHKSOTOSBPELAGDBWHYPTVSSNSSLTAHFHCASWLOASGAUOISGSADBWFZOEPKTBSSHPYTKTPTNNGMJTUYAH
UR:CRYPTO-PSBT/2-2/LPAOAOCFADDYCYHSFRYNOTHDMKGTPMAEKECLOXHHHLFHISYADIBZJEMYFDAAECTADIASLSCMHFBYNTYTCYKESROECHMOCPHKPACNKEVALUMNWDUYNBSODPRYDAIAHHFMCXTAFPGWCLCMSFLEGRSWGTLDKGUTSKZOSAYNJOYLPDRDBDETIOKKBEJZWNCPFNJLSKTSSNJLSEBZCFAEJKSKTNBKHFAEAELAAEAEAELAAEAEAELAAEAEAEAEAEAEAEAEADCHCXSFLEGRSWGTLDKGUTSKZOSAYNJOYLPDRDBDETIOKKBEJZWNCPFNJLSKTSSNJLSEBZAEAEFPRTCNGO
59012d70736274ff01005202000000017fdd5301ea4116c966153c5b77d19e2cf8ace66ea61c3223a14401b6b87a56b90000000000ffffffff0168bf000000000000160014751e76e8199196d454941c45d1b3a323f1433bd6000000000001012b50c3000000000000225120a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c011340a2aad6c45bf977a99e4dad007c21a45c5d3f68f827156b8f480435d92709831656119df91a7cc3a217922259b1237ce68b8eeadba0c92dbd25635c3e20d9414f2116cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115190073c5da0a5600008000000080000000800000000000000000011720cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc1150000
Assembled by your wallet
020000000001017fdd5301ea4116c966153c5b77d19e2cf8ace66ea61c3223a14401b6b87a56b90000000000ffffffff0168bf000000000000160014751e76e8199196d454941c45d1b3a323f1433bd60140a2aad6c45bf977a99e4dad007c21a45c5d3f68f827156b8f480435d92709831656119df91a7cc3a217922259b1237ce68b8eeadba0c92dbd25635c3e20d9414f00000000
69578e8043f5f24a4228f0519d2f18071865a8a16434ac784cd3dbd8c0b89764
Multisig
- Import each cosigner's key: BitTool Signer exports its BIP48 cosigner key on the coin-level page (
m/48'/0'/0'/2'for P2WSH). - Build the PSBT with
witnessScript(andredeemScriptfor P2SH-P2WSH) and abip32Derivationentry for every cosigner key on each input. - Send it to each signer in turn, or in parallel and combine. BitTool Signer adds signatures only for keys it holds. If one phone holds two cosigner keys in different wallets, it asks for each wallet's password separately.
- Existing signatures are verified and kept, so the PSBT can go round in any order.
BitTool Signer reviews the script it is asked to sign, but it cannot know whether the policy is the one the user intended. Show the full policy (threshold, all fingerprints) in your wallet when the multisig wallet is created.