bitcoin-s/docs/next/core/psbts.html
Docusaurus bot 7b837c5673 Deploy website
Deploy website version based on 267d5eb138
2020-03-04 15:49:12 +00:00

219 lines
No EOL
37 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"/><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"/><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="/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">Add Bitcoin-S to your project</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></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/sign">Sign api</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/txbuilder">TxBuilder example</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/key-manager">Key Manager</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></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Applications</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/next/applications/chain">Blockchain Verification</a></li><li class="navListItem"><a class="navItem" href="/docs/next/applications/cli">cli</a></li><li class="navListItem"><a class="navItem" href="/docs/next/applications/configuration">Application configuration</a></li><li class="navListItem"><a class="navItem" href="/docs/next/applications/dlc">Executing A DLC with Bitcoin-S</a></li><li class="navListItem"><a class="navItem" href="/docs/next/applications/node">Light client</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/wallet">Wallet</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">import</span> org.bitcoins.core.crypto.<span class="hljs-type">ECPrivateKey</span>
<span class="hljs-keyword">import</span> org.bitcoins.core.protocol.script.<span class="hljs-type">ScriptPubKey</span>
<span class="hljs-keyword">import</span> org.bitcoins.core.protocol.transaction.{<span class="hljs-type">BaseTransaction</span>, <span class="hljs-type">Transaction</span>}
<span class="hljs-keyword">import</span> org.bitcoins.core.psbt.<span class="hljs-type">PSBT</span>
<span class="hljs-keyword">import</span> org.bitcoins.core.script.crypto.<span class="hljs-type">HashType</span>
<span class="hljs-keyword">import</span> scodec.bits._
<span class="hljs-keyword">import</span> scala.concurrent.{<span class="hljs-type">ExecutionContext</span>, <span class="hljs-type">ExecutionContextExecutor</span>}
<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">// ec: ExecutionContextExecutor = scala.concurrent.impl.ExecutionContextImpl$$anon$3@675af691[Running, parallelism = 2, size = 1, active = 0, running = 0, steals = 8, tasks = 0, submissions = 0]</span>
<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">// unsignedTransaction: BaseTransaction = BaseTransactionImpl(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(75ddabb27b8845f5247975c8a5ba7c6f336c4570708ebe230caf6db5217ae858:0),EmptyScriptSignature,UInt32Impl(4294967295)), TransactionInputImpl(TransactionOutPoint(1dea7cd05979072a3578cab271c02244ea8a090bbb46aa680a65ecd027048d83:1),EmptyScriptSignature,UInt32Impl(4294967295))),Vector(TransactionOutput(149990000 sats,wpkh(d85c2b71d0060b09c9886aeb815e50991dda124d)), TransactionOutput(100000000 sats,wpkh(00aea9a2e5f0f876a588df5546e8742d1d87008f))),UInt32Impl(0))</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">// emptyPSBT: PSBT = PSBT(IndexedSeq(UnsignedTransaction(BaseTransactionImpl(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(75ddabb27b8845f5247975c8a5ba7c6f336c4570708ebe230caf6db5217ae858:0),EmptyScriptSignature,UInt32Impl(4294967295)), TransactionInputImpl(TransactionOutPoint(1dea7cd05979072a3578cab271c02244ea8a090bbb46aa680a65ecd027048d83:1),EmptyScriptSignature,UInt32Impl(4294967295))),Vector(TransactionOutput(149990000 sats,wpkh(d85c2b71d0060b09c9886aeb815e50991dda124d)), TransactionOutput(100000000 sats,wpkh(00aea9a2e5f0f876a588df5546e8742d1d87008f))),UInt32Impl(0)))),Vector(IndexedSeq(), IndexedSeq()),Vector(IndexedSeq(), IndexedSeq()))</span>
<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-comment">// utxo0: Transaction = BaseTransactionImpl(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(8b6f65ab71eeab8b2918acc2ea06b79de08b84680b40ae845fd28b013139d7aa:0),P2PKScriptSignature(ECDigitalSignature(3044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01)),UInt32Impl(4294967294))),Vector(TransactionOutput(50000000 sats,sh(0fb9463421696b82c833af241c78c17ddbde4934)), TransactionOutput(4949996240 sats,sh(29ca74f8a08f81999428185c97b5d852e4063f61))),UInt32Impl(101))</span>
<span class="hljs-keyword">val</span> utxo1 = <span class="hljs-type">Transaction</span>(
<span class="hljs-string">"0200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000"</span>)
<span class="hljs-comment">// utxo1: Transaction = WitnessTransactionImpl(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(75ddabb27b8845f5247975c8a5ba7c6f336c4570708ebe230caf6db5217ae858:1),P2SHScriptSignature(wpkh(5f275f436b09a8cc9a2eb2a2f528485c68a56323), EmptyScriptSignature),UInt32Impl(4294967294))),Vector(TransactionOutput(4749992920 sats,sh(aed962d6654f9a2b36608eb9d64d2b260db4f111)), TransactionOutput(200000000 sats,sh(b7f5faf40e3d40a5a459b1db3535f2b72fa921e8))),UInt32Impl(101),IndexedSeq(P2WPKHWitnessV0(List(035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f79, 3045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad7701))))</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">// psbtWithUTXOs: PSBT = PSBT(IndexedSeq(UnsignedTransaction(BaseTransactionImpl(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(75ddabb27b8845f5247975c8a5ba7c6f336c4570708ebe230caf6db5217ae858:0),EmptyScriptSignature,UInt32Impl(4294967295)), TransactionInputImpl(TransactionOutPoint(1dea7cd05979072a3578cab271c02244ea8a090bbb46aa680a65ecd027048d83:1),EmptyScriptSignature,UInt32Impl(4294967295))),Vector(TransactionOutput(149990000 sats,wpkh(d85c2b71d0060b09c9886aeb815e50991dda124d)), TransactionOutput(100000000 sats,wpkh(00aea9a2e5f0f876a588df5546e8742d1d87008f))),UInt32Impl(0)))),Vector(IndexedSeq(NonWitnessOrUnknownUTXO(BaseTransactionImpl(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(8b6f65ab71eeab8b2918acc2ea06b79de08b84680b40ae845fd28b013139d7aa:0),P2PKScriptSignature(ECDigitalSignature(3044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01)),UInt32Impl(4294967294))),Vector(TransactionOutput(50000000 sats,sh(0fb9463421696b82c833af241c78c17ddbde4934)), TransactionOutput(4949996240 sats,sh(29ca74f8a08f81999428185c97b5d852e4063f61))),UInt32Impl(101)))), IndexedSeq(NonWitnessOrUnknownUTXO(WitnessTransactionImpl(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(75ddabb27b8845f5247975c8a5ba7c6f336c4570708ebe230caf6db5217ae858:1),P2SHScriptSignature(wpkh(5f275f436b09a8cc9a2eb2a2f528485c68a56323), EmptyScriptSignature),UInt32Impl(4294967294))),Vector(TransactionOutput(4749992920 sats,sh(aed962d6654f9a2b36608eb9d64d2b260db4f111)), TransactionOutput(200000000 sats,sh(b7f5faf40e3d40a5a459b1db3535f2b72fa921e8))),UInt32Impl(101),IndexedSeq(P2WPKHWitnessV0(List(035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f79, 3045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad7701))))))),Vector(IndexedSeq(), IndexedSeq()))</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-comment">// redeemScript0: ScriptPubKey = multi(2,029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f,02dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7)</span>
<span class="hljs-keyword">val</span> psbtWithUpdatedFirstInput =
psbtWithUTXOs.addRedeemOrWitnessScriptToInput(redeemScript0, index = <span class="hljs-number">0</span>)
<span class="hljs-comment">// psbtWithUpdatedFirstInput: PSBT = PSBT(IndexedSeq(UnsignedTransaction(BaseTransactionImpl(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(75ddabb27b8845f5247975c8a5ba7c6f336c4570708ebe230caf6db5217ae858:0),EmptyScriptSignature,UInt32Impl(4294967295)), TransactionInputImpl(TransactionOutPoint(1dea7cd05979072a3578cab271c02244ea8a090bbb46aa680a65ecd027048d83:1),EmptyScriptSignature,UInt32Impl(4294967295))),Vector(TransactionOutput(149990000 sats,wpkh(d85c2b71d0060b09c9886aeb815e50991dda124d)), TransactionOutput(100000000 sats,wpkh(00aea9a2e5f0f876a588df5546e8742d1d87008f))),UInt32Impl(0)))),Vector(IndexedSeq(NonWitnessOrUnknownUTXO(BaseTransactionImpl(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(8b6f65ab71eeab8b2918acc2ea06b79de08b84680b40ae845fd28b013139d7aa:0),P2PKScriptSignature(ECDigitalSignature(3044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01)),UInt32Impl(4294967294))),Vector(TransactionOutput(50000000 sats,sh(0fb9463421696b82c833af241c78c17ddbde4934)), TransactionOutput(4949996240 sats,sh(29ca74f8a08f81999428185c97b5d852e4063f61))),UInt32Impl(101))), RedeemScript(multi(2,029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f,02dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7))), IndexedSeq(NonWitnessOrUnknownUTXO(WitnessTransactionImpl(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(75ddabb27b8845f5247975c8a5ba7c6f336c4570708ebe230caf6db5217ae858:1),P2SHScriptSignature(wpkh(5f275f436b09a8cc9a2eb2a2f528485c68a56323), EmptyScriptSignature),UInt32Impl(4294967294))),Vector(TransactionOutput(4749992920 sats,sh(aed962d6654f9a2b36608eb9d64d2b260db4f111)), TransactionOutput(200000000 sats,sh(b7f5faf40e3d40a5a459b1db3535f2b72fa921e8))),UInt32Impl(101),IndexedSeq(P2WPKHWitnessV0(List(035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f79, 3045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad7701))))))),Vector(IndexedSeq(), IndexedSeq()))</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-comment">// redeemScript1: ScriptPubKey = wsh(8c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903)</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">// witnessScript: ScriptPubKey = multi(2,03089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc,023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73)</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">// psbtWithUpdatedSecondInput: PSBT = PSBT(IndexedSeq(UnsignedTransaction(BaseTransactionImpl(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(75ddabb27b8845f5247975c8a5ba7c6f336c4570708ebe230caf6db5217ae858:0),EmptyScriptSignature,UInt32Impl(4294967295)), TransactionInputImpl(TransactionOutPoint(1dea7cd05979072a3578cab271c02244ea8a090bbb46aa680a65ecd027048d83:1),EmptyScriptSignature,UInt32Impl(4294967295))),Vector(TransactionOutput(149990000 sats,wpkh(d85c2b71d0060b09c9886aeb815e50991dda124d)), TransactionOutput(100000000 sats,wpkh(00aea9a2e5f0f876a588df5546e8742d1d87008f))),UInt32Impl(0)))),Vector(IndexedSeq(NonWitnessOrUnknownUTXO(BaseTransactionImpl(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(8b6f65ab71eeab8b2918acc2ea06b79de08b84680b40ae845fd28b013139d7aa:0),P2PKScriptSignature(ECDigitalSignature(3044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01)),UInt32Impl(4294967294))),Vector(TransactionOutput(50000000 sats,sh(0fb9463421696b82c833af241c78c17ddbde4934)), TransactionOutput(4949996240 sats,sh(29ca74f8a08f81999428185c97b5d852e4063f61))),UInt32Impl(101))), RedeemScript(multi(2,029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f,02dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7))), IndexedSeq(RedeemScript(wsh(8c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903)), WitnessUTXO(TransactionOutput(200000000 sats,sh(b7f5faf40e3d40a5a459b1db3535f2b72fa921e8))), WitnessScript(multi(2,03089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc,023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73)))),Vector(IndexedSeq(), IndexedSeq()))</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">// psbtWithSigHashFlags: PSBT = PSBT(IndexedSeq(UnsignedTransaction(BaseTransactionImpl(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(75ddabb27b8845f5247975c8a5ba7c6f336c4570708ebe230caf6db5217ae858:0),EmptyScriptSignature,UInt32Impl(4294967295)), TransactionInputImpl(TransactionOutPoint(1dea7cd05979072a3578cab271c02244ea8a090bbb46aa680a65ecd027048d83:1),EmptyScriptSignature,UInt32Impl(4294967295))),Vector(TransactionOutput(149990000 sats,wpkh(d85c2b71d0060b09c9886aeb815e50991dda124d)), TransactionOutput(100000000 sats,wpkh(00aea9a2e5f0f876a588df5546e8742d1d87008f))),UInt32Impl(0)))),Vector(IndexedSeq(NonWitnessOrUnknownUTXO(BaseTransactionImpl(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(8b6f65ab71eeab8b2918acc2ea06b79de08b84680b40ae845fd28b013139d7aa:0),P2PKScriptSignature(ECDigitalSignature(3044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01)),UInt32Impl(4294967294))),Vector(TransactionOutput(50000000 sats,sh(0fb9463421696b82c833af241c78c17ddbde4934)), TransactionOutput(4949996240 sats,sh(29ca74f8a08f81999428185c97b5d852e4063f61))),UInt32Impl(101))), RedeemScript(multi(2,029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f,02dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7)), SigHashType(SIGHASH_ALL(Int32Impl(1)))), IndexedSeq(RedeemScript(wsh(8c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903)), WitnessUTXO(TransactionOutput(200000000 sats,sh(b7f5faf40e3d40a5a459b1db3535f2b72fa921e8))), WitnessScript(multi(2,03089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc,023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73)), SigHashType(SIGHASH_ALL(Int32Impl(1))))),Vector(IndexedSeq(), IndexedSeq()))</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">ECPrivateKey</span>.fromWIFToPrivateKey(
<span class="hljs-string">"cP53pDbR5WtAD8dYAW9hhTjuvvTVaEiQBdrz9XPrgLBeRFiyCbQr"</span>)
<span class="hljs-comment">// privKey0: ECPrivateKey = Masked(ECPrivateKeyImpl)</span>
<span class="hljs-keyword">val</span> privKey1 = <span class="hljs-type">ECPrivateKey</span>.fromWIFToPrivateKey(
<span class="hljs-string">"cR6SXDoyfQrcp4piaiHE97Rsgta9mNhGTen9XeonVgwsh4iSgw6d"</span>)
<span class="hljs-comment">// privKey1: ECPrivateKey = Masked(ECPrivateKeyImpl)</span>
<span class="hljs-keyword">val</span> psbtFirstSigF =
psbtWithSigHashFlags
.sign(inputIndex = <span class="hljs-number">0</span>, signer = privKey0)
.flatMap(_.sign(inputIndex = <span class="hljs-number">0</span>, signer = privKey1))
<span class="hljs-comment">// psbtFirstSigF: concurrent.Future[PSBT] = Future(Success(PSBT(IndexedSeq(UnsignedTransaction(BaseTransactionImpl(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(75ddabb27b8845f5247975c8a5ba7c6f336c4570708ebe230caf6db5217ae858:0),EmptyScriptSignature,UInt32Impl(4294967295)), TransactionInputImpl(TransactionOutPoint(1dea7cd05979072a3578cab271c02244ea8a090bbb46aa680a65ecd027048d83:1),EmptyScriptSignature,UInt32Impl(4294967295))),Vector(TransactionOutput(149990000 sats,wpkh(d85c2b71d0060b09c9886aeb815e50991dda124d)), TransactionOutput(100000000 sats,wpkh(00aea9a2e5f0f876a588df5546e8742d1d87008f))),UInt32Impl(0)))),Vector(IndexedSeq(NonWitnessOrUnknownUTXO(BaseTransactionImpl(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(8b6f65ab71eeab8b2918acc2ea06b79de08b84680b40ae845fd28b013139d7aa:0),P2PKScriptSignature(ECDigitalSignature(3044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01)),UInt32Impl(4294967294))),Vector(TransactionOutput(50000000 sats,sh(0fb9463421696b82c833af241c78c17ddbde4934)), TransactionOutput(4949996240 sats,sh(29ca74f8a08f81999428185c97b5d852e4063f61))),UInt32Impl(101))), RedeemScript(multi(2,029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f,02dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7)), SigHashType(SIGHASH_ALL(Int32Impl(1))), PartialSignature(ECPublicKey(029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f),ECDigitalSignature(3044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01)), PartialSignature(ECPublicKey(03089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc),ECDigitalSignature(3045022100a806c8b9e660931fce821d0271e5cea1d1c946ed1b915cd848bd5ddf374cb6930220009b19df309183ef0135748f412bc6871f21b2ef76df57fd21a4edbc83e6110901))), IndexedSeq(RedeemScript(wsh(8c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903)), WitnessUTXO(TransactionOutput(200000000 sats,sh(b7f5faf40e3d40a5a459b1db3535f2b72fa921e8))), WitnessScript(multi(2,03089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc,023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73)), SigHashType(SIGHASH_ALL(Int32Impl(1))))),Vector(IndexedSeq(), IndexedSeq()))))</span>
psbtFirstSigF.map { psbtFirstSig =&gt;
<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>
<span class="hljs-keyword">val</span> transaction = finalizedPSBT.get.extractTransaction
}
<span class="hljs-comment">// res0: concurrent.Future[Unit] = Future(Failure(java.lang.IllegalArgumentException: requirement failed: DoubleSha256Digest must always be 32 bytes, got: 0))</span>
</code></pre>
</span></div></article></div><div class="docs-prevnext"><a class="docs-prev button" href="/docs/next/core/sign"><span class="arrow-prev"></span><span>Sign api</span></a><a class="docs-next button" href="/docs/next/core/txbuilder"><span class="function-name-prevnext">TxBuilder example</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/enQtNDEyMjY3MTg1MTg3LTYyYjkwOGUzMDQ4NDAwZjE1M2I3MmQyNWNlZjNlYjg4OGRjYTRjNWUwNjRjNjg4Y2NjZjAxYjU1N2JjMTU1YWM" 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 © 2020 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>