bitcoin-s/docs/next/core/psbts.html
Docusaurus bot c454dc9160 Deploy website
Deploy website version based on 43efce500d
2025-01-01 16:02:04 +00:00

229 lines
No EOL
30 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><title>Partially Signed Bitcoin Transactions · bitcoin-s</title><meta name="viewport" content="width=device-width, initial-scale=1.0"/><meta name="generator" content="Docusaurus"/><meta name="description" content="Creating unsigned or partially signed transactions to be passed "/><meta name="docsearch:version" content="next"/><meta name="docsearch:language" content="en"/><meta property="og:title" content="Partially Signed Bitcoin Transactions · bitcoin-s"/><meta property="og:type" content="website"/><meta property="og:url" content="https://bitcoin-s.org/"/><meta property="og:description" content="Creating unsigned or partially signed transactions to be passed "/><meta property="og:image" content="https://bitcoin-s.org/img/undraw_online.svg"/><meta name="twitter:card" content="summary"/><meta name="twitter:image" content="https://bitcoin-s.org/img/undraw_tweetstorm.svg"/><link rel="shortcut icon" href="/img/favicon.ico"/><link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.css"/><link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css"/><script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-61958686-2', 'auto');
ga('send', 'pageview');
</script><link rel="stylesheet" href="/css/code-block-buttons.css"/><script type="text/javascript" src="https://buttons.github.io/buttons.js"></script><script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js"></script><script type="text/javascript" src="https://fonts.googleapis.com/css?family=Montserrat:500"></script><script type="text/javascript" src="https://www.googletagmanager.com/gtag/js?id=UA-61958686-2"></script><script type="text/javascript" src="/js/code-block-buttons.js"></script><script src="/js/scrollSpy.js"></script><link rel="stylesheet" href="/css/main.css"/><script src="/js/codetabs.js"></script></head><body class="sideNavVisible separateOnPageNav"><div class="fixedHeaderContainer"><div class="headerWrapper wrapper"><header><a href="/"><img class="logo" src="/img/favicon.ico" alt="bitcoin-s"/><h2 class="headerTitleWithLogo">bitcoin-s</h2></a><a href="/versions"><h3>next</h3></a><div class="navigationWrapper navigationSlider"><nav class="slidingNav"><ul class="nav-site nav-site-internal"><li class="siteNavGroupActive"><a href="/docs/next/core/core-intro" target="_self">Docs</a></li><li class=""><a href="/download" target="_self">Download</a></li><li class=""><a href="/api/org/bitcoins" target="_self">API</a></li><li class=""><a href="/help" target="_self">Help</a></li><li class="navSearchWrapper reactNavSearchWrapper"><input type="text" id="search_input_react" placeholder="Search" title="Search"/></li></ul></nav></div></header></div></div><div class="navPusher"><div class="docMainWrapper wrapper"><div class="docsNavContainer" id="docsNav"><nav class="toc"><div class="toggleNav"><section class="navWrapper wrapper"><div class="navBreadcrumb wrapper"><div class="navToggle" id="navToggler"><div class="hamburger-menu"><div class="line1"></div><div class="line2"></div><div class="line3"></div></div></div><h2><i></i><span>Core Module</span></h2><div class="tocToggler" id="tocToggler"><i class="icon-toc"></i></div></div><div class="navGroups"><div class="navGroup"><h3 class="navGroupCategoryTitle">Getting Started</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/next/getting-started">Intro and Getting Started</a></li><li class="navListItem"><a class="navItem" href="/docs/next/bips">Supported BIPs</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Getting Setup</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/next/getting-setup">Getting Bitcoin-S installed on your machine</a></li><li class="navListItem"><a class="navItem" href="/docs/next/ui-setup">Installing the DLC Wallet UI</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Applications</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/next/applications/cli">CLI</a></li><li class="navListItem"><a class="navItem" href="/docs/next/applications/server">Application Server</a></li><li class="navListItem"><a class="navItem" href="/docs/next/applications/gui">GUI</a></li><li class="navListItem"><a class="navItem" href="/docs/next/applications/server-systemd">Systemd installation</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Chain</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/next/chain/chain">Blockchain Verification</a></li><li class="navListItem"><a class="navItem" href="/docs/next/chain/filter-sync">Syncing Blockfilters</a></li><li class="navListItem"><a class="navItem" href="/docs/next/chain/chain-query-api">Chain Query API</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Configuration</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/next/config/configuration">Application Configuration</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Core Module</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/next/core/core-intro">Core Module</a></li><li class="navListItem"><a class="navItem" href="/docs/next/core/addresses">Generating Addresses</a></li><li class="navListItem"><a class="navItem" href="/docs/next/core/hd-keys">HD Key Generation</a></li><li class="navListItem"><a class="navItem" href="/docs/next/core/adding-spks">Adding New Script Types</a></li><li class="navListItem"><a class="navItem" href="/docs/next/core/spending-info">Signing Transactions</a></li><li class="navListItem navListItemActive"><a class="navItem" href="/docs/next/core/psbts">Partially Signed Bitcoin Transactions</a></li><li class="navListItem"><a class="navItem" href="/docs/next/core/dlc">Discreet Log Contract Data Structures</a></li><li class="navListItem"><a class="navItem" href="/docs/next/core/txbuilder">TxBuilder Example</a></li><li class="navListItem"><a class="navItem" href="/docs/next/core/lightning-network">Lightning Network Data Types</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Crypto Module</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/next/crypto/crypto-intro">Crypto Module</a></li><li class="navListItem"><a class="navItem" href="/docs/next/crypto/sign">Sign API</a></li><li class="navListItem"><a class="navItem" href="/docs/next/crypto/adaptor-signatures">Adaptor Signatures</a></li><li class="navListItem"><a class="navItem" href="/docs/next/crypto/musig">MuSig</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Fee Provider</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/next/fee-provider/fee-provider">Fee Provider</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Key Manager</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/next/key-manager/server-key-manager">Server Key Manager</a></li><li class="navListItem"><a class="navItem" href="/docs/next/key-manager/key-manager">Key Manager</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Node</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/next/node/node">Light Client</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Wallet</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/next/wallet/wallet">Wallet</a></li><li class="navListItem"><a class="navItem" href="/docs/next/wallet/wallet-callbacks">Wallet Callbacks</a></li><li class="navListItem"><a class="navItem" href="/docs/next/wallet/wallet-get-address">Wallet Get Address APIs</a></li><li class="navListItem"><a class="navItem" href="/docs/next/wallet/address-tagging">Address and UTXO tagging</a></li><li class="navListItem"><a class="navItem" href="/docs/next/wallet/dlc">Executing A DLC with Bitcoin-S</a></li><li class="navListItem"><a class="navItem" href="/docs/next/wallet/wallet-rescan">wallet/wallet-rescan</a></li><li class="navListItem"><a class="navItem" href="/docs/next/wallet/wallet-sync">Wallet Sync</a></li><li class="navListItem"><a class="navItem" href="/docs/next/wallet/wallet-rpc">Wallet RPC Examples</a></li><li class="navListItem"><a class="navItem" href="/docs/next/wallet/backups">Wallet Backups</a></li><li class="navListItem"><a class="navItem" href="/docs/next/wallet/wallet-election-example">Wallet Election Example</a></li><li class="navListItem"><a class="navItem" href="/docs/next/wallet/wallet-price-example">Wallet Price Example</a></li><li class="navListItem"><a class="navItem" href="/docs/next/wallet/wallet-sports-betting-example">Wallet Sports Betting Example</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Tor</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/next/tor/tor">Tor Setup</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">RPC Clients</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/next/rpc/rpc-clients-intro">Introduction</a></li><li class="navListItem"><a class="navItem" href="/docs/next/rpc/rpc-eclair">Eclair</a></li><li class="navListItem"><a class="navItem" href="/docs/next/rpc/rpc-bitcoind">bitcoind/Bitcoin Core</a></li><li class="navListItem"><a class="navItem" href="/docs/next/rpc/lnd-rpc">LND</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Secp256k1</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/next/secp256k1/secp256k1">Secp256k1</a></li><li class="navListItem"><a class="navItem" href="/docs/next/secp256k1/jni-modify">Adding to Secp256k1 JNI</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Testkit</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/next/testkit/testkit">Testkit</a></li><li class="navListItem"><a class="navItem" href="/docs/next/testkit/testkit-core">Testkit Core</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">DLC Oracle</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/next/oracle/build-oracle-server">Building the Oracle Server</a></li><li class="navListItem"><a class="navItem" href="/docs/next/oracle/oracle-server">Oracle Server</a></li><li class="navListItem"><a class="navItem" href="/docs/next/oracle/oracle-election-example">Election Example</a></li><li class="navListItem"><a class="navItem" href="/docs/next/oracle/oracle-price-example">Price Example</a></li><li class="navListItem"><a class="navItem" href="/docs/next/oracle/oracle-sports-betting-example">Sports Betting Example</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Contributing</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/next/contributing">Contributing</a></li><li class="navListItem"><a class="navItem" href="/docs/next/contributing-website">Contributing to the website</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Security</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/next/security">Security</a></li></ul></div></div></section></div><script>
var coll = document.getElementsByClassName('collapsible');
var checkActiveCategory = true;
for (var i = 0; i < coll.length; i++) {
var links = coll[i].nextElementSibling.getElementsByTagName('*');
if (checkActiveCategory){
for (var j = 0; j < links.length; j++) {
if (links[j].classList.contains('navListItemActive')){
coll[i].nextElementSibling.classList.toggle('hide');
coll[i].childNodes[1].classList.toggle('rotate');
checkActiveCategory = false;
break;
}
}
}
coll[i].addEventListener('click', function() {
var arrow = this.childNodes[1];
arrow.classList.toggle('rotate');
var content = this.nextElementSibling;
content.classList.toggle('hide');
});
}
document.addEventListener('DOMContentLoaded', function() {
createToggler('#navToggler', '#docsNav', 'docsSliderActive');
createToggler('#tocToggler', 'body', 'tocActive');
var headings = document.querySelector('.toc-headings');
headings && headings.addEventListener('click', function(event) {
var el = event.target;
while(el !== headings){
if (el.tagName === 'A') {
document.body.classList.remove('tocActive');
break;
} else{
el = el.parentNode;
}
}
}, false);
function createToggler(togglerSelector, targetSelector, className) {
var toggler = document.querySelector(togglerSelector);
var target = document.querySelector(targetSelector);
if (!toggler) {
return;
}
toggler.onclick = function(event) {
event.preventDefault();
target.classList.toggle(className);
};
}
});
</script></nav></div><div class="container mainContainer docsContainer"><div class="wrapper"><div class="post"><header class="postHeader"><a class="edit-page-link button" href="https://github.com/bitcoin-s/bitcoin-s/blob/master/docs/core/psbts.md" target="_blank" rel="noreferrer noopener">Edit</a><h1 id="__docusaurus" class="postHeaderTitle">Partially Signed Bitcoin Transactions</h1></header><article><div><span><p>Creating unsigned or partially signed transactions to be passed
around to other signers can be a useful for many applications.
PSBTs offer a standardized format to serialize the necessary data
for signing the transaction, as well as, validating that you in fact
want to sign this transaction.</p>
<blockquote>
<p>If you want to jump into the details of the specification,
you should checkout
<a href="https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki">BIP 174</a>.</p>
</blockquote>
<p>Bitcoin-S fully supports PSBTs with functionality for
creation, updating, combining, signing, finalizing,
and transaction extraction.</p>
<p>An example on a typical PSBT workflow:</p>
<pre><code class="hljs css language-scala"><span class="hljs-keyword">implicit</span> <span class="hljs-keyword">val</span> ec: <span class="hljs-type">ExecutionContextExecutor</span> = <span class="hljs-type">ExecutionContext</span>.global
<span class="hljs-comment">// First you need an unsigned transaction,</span>
<span class="hljs-comment">// here we have a standard 2 input, 2 output transaction</span>
<span class="hljs-comment">// This transaction must be of type BaseTransaction</span>
<span class="hljs-comment">// and have empty ScriptSignatures for all of it's inputs</span>
<span class="hljs-keyword">val</span> unsignedTransaction = <span class="hljs-type">BaseTransaction</span>(
<span class="hljs-string">"020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000"</span>)
<span class="hljs-comment">// To create the initial PSBT all we need to do is</span>
<span class="hljs-keyword">val</span> emptyPSBT = <span class="hljs-type">PSBT</span>.fromUnsignedTx(unsignedTransaction)
<span class="hljs-comment">// Now that we have an empty PSBT we can start updating it with data we know</span>
<span class="hljs-comment">// First, we want to fill the UTXO fields that we will need for signing and extraction</span>
<span class="hljs-comment">// The transactions we add are the fully serialized transaction that we are spending from</span>
<span class="hljs-keyword">val</span> utxo0 = <span class="hljs-type">Transaction</span>(
<span class="hljs-string">"0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000"</span>)
<span class="hljs-keyword">val</span> utxo1 = <span class="hljs-type">Transaction</span>(
<span class="hljs-string">"0200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000"</span>)
<span class="hljs-keyword">val</span> psbtWithUTXOs = emptyPSBT.addUTXOToInput(utxo0, index = <span class="hljs-number">0</span>).addUTXOToInput(utxo1, index = <span class="hljs-number">1</span>)
<span class="hljs-comment">// After we have the relevant UTXOs we can add the</span>
<span class="hljs-comment">// redeem scripts, witness scripts, and BIP 32 derivation paths if needed</span>
<span class="hljs-comment">// In this transaction the first input is a P2SH 2-of-2 multisig</span>
<span class="hljs-comment">// so we need to add its corresponding redeem script.</span>
<span class="hljs-comment">// Here we are just using a deserialized version of the redeem script but</span>
<span class="hljs-comment">// you may generate your ScriptPubKey another way in practice</span>
<span class="hljs-keyword">val</span> redeemScript0 = <span class="hljs-type">ScriptPubKey</span>.fromAsmBytes(
<span class="hljs-string">hex"5221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae"</span>)
<span class="hljs-keyword">val</span> psbtWithUpdatedFirstInput =
psbtWithUTXOs.addRedeemOrWitnessScriptToInput(redeemScript0, index = <span class="hljs-number">0</span>)
<span class="hljs-comment">// The second input in this transaction is a P2SH(P2WSH) 2-of-2 multisig</span>
<span class="hljs-comment">// so we need to add its corresponding redeem script and witness script.</span>
<span class="hljs-comment">// Here we add them both using the same function, the PSBT updater will</span>
<span class="hljs-comment">// be able to figure out, based on the available data, where to correctly</span>
<span class="hljs-keyword">val</span> redeemScript1 = <span class="hljs-type">ScriptPubKey</span>.fromAsmBytes(
<span class="hljs-string">hex"00208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903"</span>)
<span class="hljs-keyword">val</span> witnessScript = <span class="hljs-type">ScriptPubKey</span>.fromAsmBytes(
<span class="hljs-string">hex"522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae"</span>)
<span class="hljs-comment">// put the data in the PSBT</span>
<span class="hljs-keyword">val</span> psbtWithUpdatedSecondInput = psbtWithUpdatedFirstInput
.addRedeemOrWitnessScriptToInput(redeemScript1, index = <span class="hljs-number">1</span>)
.addRedeemOrWitnessScriptToInput(witnessScript, index = <span class="hljs-number">1</span>)
<span class="hljs-comment">// Before signing we need to add the needed SigHash flags so we know how to sign the transaction</span>
<span class="hljs-comment">// If one is not provided it will be assumed to be SigHashAll</span>
<span class="hljs-keyword">val</span> psbtWithSigHashFlags = psbtWithUpdatedSecondInput
.addSigHashTypeToInput(<span class="hljs-type">HashType</span>.sigHashAll, index = <span class="hljs-number">0</span>)
.addSigHashTypeToInput(<span class="hljs-type">HashType</span>.sigHashAll, index = <span class="hljs-number">1</span>)
<span class="hljs-comment">// Next, we can now sign the PSBT</span>
<span class="hljs-comment">// Signing a PSBT will return a Future[PSBT] so this will need to be handled</span>
<span class="hljs-comment">// correctly in an application</span>
<span class="hljs-comment">// Here we use the relevant private keys to sign the first input</span>
<span class="hljs-keyword">val</span> privKey0 = <span class="hljs-type">ECPrivateKeyUtil</span>.fromWIFToPrivateKey(
<span class="hljs-string">"cP53pDbR5WtAD8dYAW9hhTjuvvTVaEiQBdrz9XPrgLBeRFiyCbQr"</span>).toPrivateKey
<span class="hljs-keyword">val</span> privKey1 = <span class="hljs-type">ECPrivateKeyUtil</span>.fromWIFToPrivateKey(
<span class="hljs-string">"cR6SXDoyfQrcp4piaiHE97Rsgta9mNhGTen9XeonVgwsh4iSgw6d"</span>).toPrivateKey
<span class="hljs-keyword">val</span> psbtFirstSig =
psbtWithSigHashFlags
.sign(inputIndex = <span class="hljs-number">0</span>, signer = privKey0)
.sign(inputIndex = <span class="hljs-number">0</span>, signer = privKey1)
<span class="hljs-comment">// Alternatively, you can use produce a signature with a ECSignatureParams</span>
<span class="hljs-comment">// using the BitcoinSigner will return a PartialSignature that can be added to a PSBT</span>
<span class="hljs-comment">// First we need to declare out spendingInfoSingle</span>
<span class="hljs-keyword">val</span> outPoint = unsignedTransaction.inputs.head.previousOutput
<span class="hljs-keyword">val</span> output = utxo0.outputs(outPoint.vout.toInt)
<span class="hljs-keyword">val</span> spendingInfoSingle = <span class="hljs-type">ECSignatureParams</span>(
<span class="hljs-type">InputInfo</span>(outPoint = outPoint,
output = output,
redeemScriptOpt = <span class="hljs-type">Some</span>(redeemScript0),
scriptWitnessOpt = <span class="hljs-type">None</span>,
conditionalPath = <span class="hljs-type">ConditionalPath</span>.<span class="hljs-type">NoCondition</span>,
previousOutputMap = <span class="hljs-type">PreviousOutputMap</span>.empty),
prevTransaction = utxo0,
signer = privKey0,
hashType = <span class="hljs-type">HashType</span>.sigHashAll
)
<span class="hljs-comment">// Then we can sign the transaction</span>
<span class="hljs-keyword">val</span> signature = <span class="hljs-type">BitcoinSigner</span>.signSingle(
spendingInfo = spendingInfoSingle,
unsignedTx = unsignedTransaction,
privKey0.signLowRWithHashType)
<span class="hljs-comment">// We can then add the signature to the PSBT</span>
<span class="hljs-comment">// Note: this signature could be produced by us or another party</span>
psbtWithSigHashFlags.addSignature(signature, inputIndex = <span class="hljs-number">0</span>)
<span class="hljs-comment">// With our first input signed we can now move on to showing how another party could sign our second input</span>
<span class="hljs-comment">// In this scenario, let's say that the second input does not belong to us and we need</span>
<span class="hljs-comment">// another party to sign it. In this case we would need to send the PSBT to the other party.</span>
<span class="hljs-comment">// The two standard formats for this are in byte form or in base64 you can access these easily.</span>
<span class="hljs-keyword">val</span> bytes = psbtFirstSig.bytes
<span class="hljs-keyword">val</span> base64 = psbtFirstSig.base64
<span class="hljs-comment">// After the other party has signed their input they can send us back the PSBT with the signatures</span>
<span class="hljs-comment">// To import we can use any of these functions</span>
<span class="hljs-keyword">val</span> fromBytes = <span class="hljs-type">PSBT</span>.fromBytes(
<span class="hljs-string">hex"70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000220202dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f0000008000000080010000800001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8872202023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d2010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000"</span>)
<span class="hljs-keyword">val</span> fromBase64 = <span class="hljs-type">PSBT</span>.fromBase64(
<span class="hljs-string">"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD"</span>)
<span class="hljs-comment">// After we've imported the PSBT we can combine it with our own signed PSBT so we can</span>
<span class="hljs-comment">// have one PSBT with all of the necessary data</span>
<span class="hljs-keyword">val</span> combinedPSBT = fromBase64.combinePSBT(psbtFirstSig)
<span class="hljs-comment">// Now that the PSBT has all the necessary data, we can finalize it and extract the transaction</span>
<span class="hljs-comment">// This will return a Try[PSBT] and will fail if you do not have all the required fields filled</span>
<span class="hljs-keyword">val</span> finalizedPSBT = combinedPSBT.finalizePSBT
<span class="hljs-comment">// After it has been finalized we can extract the fully signed transaction that is ready</span>
<span class="hljs-comment">// to be broadcast to the network.</span>
<span class="hljs-comment">// You can also use extractTransactionAndValidate that will validate if the transaction is valid</span>
finalizedPSBT.get.extractTransaction
</code></pre>
</span></div></article></div><div class="docs-prevnext"><a class="docs-prev button" href="/docs/next/core/spending-info"><span class="arrow-prev"></span><span>Signing Transactions</span></a><a class="docs-next button" href="/docs/next/core/dlc"><span>Discreet Log Contract Data Structures</span><span class="arrow-next"></span></a></div></div></div><nav class="onPageNav"></nav></div><footer class="nav-footer" id="footer"><section class="sitemap"><a href="/" class="nav-home"><img src="/img/favicon.ico" alt="bitcoin-s" width="66" height="58"/></a><div><h5>Docs</h5><a href="/docs/en/getting-started">Getting Started</a><a href="/docs/en/core/core-intro">Guides</a><a href="/api/org/bitcoins">API Reference</a></div><div><h5>Community</h5><a href="/en/users.html">User Showcase</a><a href="https://join.slack.com/t/suredbits/shared_invite/zt-eavycu0x-WQL7XOakzQo8tAy7jHHZUw" target="_blank" rel="noreferrer noopener">Slack</a><a href="https://gitter.im/bitcoin-s-core/">Gitter chat</a></div><div><h5>More</h5><a href="https://github.com/bitcoin-s/bitcoin-s">GitHub</a><a class="github-button" href="https://github.com/bitcoin-s/bitcoin-s" data-icon="octicon-star" data-count-href="/bitcoin-s/bitcoin-s-core/stargazers" data-show-count="true" data-count-aria-label="# stargazers on GitHub" aria-label="Star this project on GitHub">Star</a></div></section><section class="copyright">Copyright © 2025 Suredbits &amp; the bitcoin-s developers</section></footer></div><script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.js"></script><script>
document.addEventListener('keyup', function(e) {
if (e.target !== document.body) {
return;
}
// keyCode for '/' (slash)
if (e.keyCode === 191) {
const search = document.getElementById('search_input_react');
search && search.focus();
}
});
</script><script>
var search = docsearch({
apiKey: '0a510688bf8448e19aeb380377d328d3',
indexName: 'bitcoin-s',
inputSelector: '#search_input_react'
});
</script></body></html>