Let’s suppose that Bob and Alice share a flat and want to buy a television worth 2 bitcoins, paying half each. To do so, Bob could send 1 bitcoin to Alice so that she pays for the TV, but since the network fees are quite high, they decide to create a joint transaction with two inputs, one from Alice and one from Bob.

💡 The practical examples in the post are made in testnet. Therefore, if you want to execute the Bob and Alice commands with the same values or look up the transactions in a explorer, you have to do it from the corresponding testnet versions.

Creating the PSBT

The first thing they do is to create a partially signed transaction (PSBT) where they specify the UTXO they want to spend and the output they want to create.

The input data for the PSBT are the two UTXO of 1.000005 bitcoins each:

Alice’s UTXO: 73c13b277a1b176fd2b20324027fff9244949fc5dc913aa98c68bddf246260e5:0
Bob’s UTXO: 7797817c9b879c3333e1c7d5eedc70e6aa0ba1a2c6d098c94ce5e2671f4c9d5e:1

The data for the output are the destination address and the amount of bitcoins they want to send:

Destination address: tb1qjdntspzahv748vasmnfl62etfz9y9hjgmvg6gw
Amount of bitcoins: 2 btc

Since they use Sparrow as a wallet and it does not allow the creation of PSBTs of this type, they have to use another tool. To do this they use their own Bitcoin node and their command interface (bitcoin-cli).

To create the PSBT they use bitcoin-cli and the command "createpsbt".
This command takes two mandatory arguments, the inputs and the outputs. For the input, specify the transaction id and the output number. For the output, the destination address and the amount of bitcoins to be sent must be stated.

bitcoin-cli createpsbt '[{"txid": "txId", "vout": nOut}]' '[{"destination address": "num btc"}]'

⚠️ WARNING!
The difference between the input value and the output value is paid as mining commission. If you want to be refunded with the remaining money, you have to add an output with a refund address and give it a value!

The command executed by Alice and Bob is as follows:

bitcoin-cli createpsbt '[{"txid": "73c13b277a1b176fd2b20324027fff9244949fc5dc913aa98c68bddf246260e5", "vout": 0}, {"txid": "7797817c9b879c3333e1c7d5eedc70e6aa0ba1a2c6d098c94ce5e2671f4c9d5e", "vout": 1}]' '[{"tb1qjdntspzahv748vasmnfl62etfz9y9hjgmvg6gw": 2}]'

Output:

cHNidP8BAHsCAAAAAuVgYiTfvWiMqTqR3MWflESS/38CJAOy0m8XG3onO8FzAAAAAAD9////Xp1MH2fi5UzJmNDGoqELquZw3O7Vx+EzM5yHm3yBl3cBAAAAAP3///8BAMLrCwAAAAAWABSTZrgEXbs9U7Ow3NP9KytIikLeSAAAAAAAAAAA

The output obtained is the raw transaction encoded in base64. This transaction is not yet ready to be signed, it needs to be updated with the information about the segwit inputs and outputs. In order to finish assembling the transaction correctly Bob and Alice use the command "utxoupdatepsbt". This command takes as the only argument a raw transaction encoded in base64, exactly like the one generated by the command “createpsbt”.

bitcoin-cli utxoupdatepsbt "raw transaction encoded in base64"

The command executed by Alice and Bob is as follows:

bitcoin-cli utxoupdatepsbt "cHNidP8BAHsCAAAAAuVgYiTfvWiMqTqR3MWflESS/38CJAOy0m8XG3onO8FzAAAAAAD9////Xp1MH2fi5UzJmNDGoqELquZw3O7Vx+EzM5yHm3yBl3cBAAAAAP3///8BAMLrCwAAAAAWABSTZrgEXbs9U7Ow3NP9KytIikLeSAAAAAAAAAAA"

Output:

cHNidP8BAHsCAAAAAuVgYiTfvWiMqTqR3MWflESS/38CJAOy0m8XG3onO8FzAAAAAAD9////Xp1MH2fi5UzJmNDGoqELquZw3O7Vx+EzM5yHm3yBl3cBAAAAAP3///8BAMLrCwAAAAAWABSTZrgEXbs9U7Ow3NP9KytIikLeSAAAAAAAAQEf9OL1BQAAAAAWABSwcT0MvrjbtH8Tu7UWrYU7nU5ocwABAR/04vUFAAAAABYAFKnH89dqqyObFvPlDONKPDSRm78cAAA=

The output is the same raw transaction encoded in base64 but this time it is ready to be signed. The status of the PSBT can be checked with the command "analyzepsbt". This command analyzes the PSBT and gives information about its status. It takes as argument a raw PSBT encoded in base64:

bitcoin-cli analyzepsbt "raw transaction encoded in base64"

Bob and Alice check the status of their PSBT with the following command:

bitcoin-cli analyzepsbt "cHNidP8BAHsCAAAAAuVgYiTfvWiMqTqR3MWflESS/38CJAOy0m8XG3onO8FzAAAAAAD9////Xp1MH2fi5UzJmNDGoqELquZw3O7Vx+EzM5yHm3yBl3cBAAAAAP3///8BAMLrCwAAAAAWABSTZrgEXbs9U7Ow3NP9KytIikLeSAAAAAAAAQEf9OL1BQAAAAAWABSwcT0MvrjbtH8Tu7UWrYU7nU5ocwABAR/04vUFAAAAABYAFKnH89dqqyObFvPlDONKPDSRm78cAAA="

Output:

{
  "inputs": [
    {
      "has_utxo": true,
      "is_final": false,
      "next": "updater",
      "missing": {
        "pubkeys": [
          "b0713d0cbeb8dbb47f13bbb516ad853b9d4e6873"
        ]
      }
    },
    {
      "has_utxo": true,
      "is_final": false,
      "next": "updater",
      "missing": {
        "pubkeys": [
          "a9c7f3d76aab239b16f3e50ce34a3c34919bbf1c"
        ]
      }
    }
  ],
  "fee": 0.00001000,
  "next": "updater"
}

In the JSON that the output provides we can see how both the Alice’s and the Bob’s signatures are missing.

💡 Idea!
The above command also allows us to see how many bitcoins the transaction pays in the form of commissions, it is a good idea to check that we are not paying more than we should!

Signing the PSBT

The first to sign the transaction will be Alice. To do so, she opens her Sparrow wallet and uploads the transaction obtained from the command “utxoupdatepsbt” in the form of a text:

With the transaction loaded it can be seen how Sparrow itself detects that the first entry belongs to Alice:

In order to sign it Alice presses “Finalize Transaction for Signing” and then “Sign”. Once signed Alice saves the transaction by pressing the “Save Transaction” option. This generates a “.psbt” file.

As she is curious to know if it has been done correctly she executes the command “analyzepsbt”. This takes as argument a raw transaction encoded in base64. In order to show the transaction of the “.psbt” file in the required format Alice uses the command:

cat alice.psbt | base64 -w 0

Output:

cHNidP8BAHsCAAAAAuVgYiTfvWiMqTqR3MWflESS/38CJAOy0m8XG3onO8FzAAAAAAD9////Xp1MH2fi5UzJmNDGoqELquZw3O7Vx+EzM5yHm3yBl3cBAAAAAP3///8BAMLrCwAAAAAWABSTZrgEXbs9U7Ow3NP9KytIikLeSAAAAAAAAQEf9OL1BQAAAAAWABSwcT0MvrjbtH8Tu7UWrYU7nU5ocyICAqMy+J7K6eLwFZ82KfZ8NEOYP/fT2XJBP7fZKzgTHebMRzBEAiAfOG5ztzUxczR0VOE/RyEHFzE+7WzxURU2M3uaMneq2wIgdNMkWI40nt+IB+LFq8vJ+/s3JqDCk/0IB51Bj/vdtFcBAAEBH/Ti9QUAAAAAFgAUqcfz12qrI5sW8+UM40o8NJGbvxwAAA==

She can now execute the command “analyzepsbt” with the transaction coded correctly:

bitcoin-cli analyzepsbt "cHNidP8BAHsCAAAAAuVgYiTfvWiMqTqR3MWflESS/38CJAOy0m8XG3onO8FzAAAAAAD9////Xp1MH2fi5UzJmNDGoqELquZw3O7Vx+EzM5yHm3yBl3cBAAAAAP3///8BAMLrCwAAAAAWABSTZrgEXbs9U7Ow3NP9KytIikLeSAAAAAAAAQEf9OL1BQAAAAAWABSwcT0MvrjbtH8Tu7UWrYU7nU5ocyICAqMy+J7K6eLwFZ82KfZ8NEOYP/fT2XJBP7fZKzgTHebMRzBEAiAfOG5ztzUxczR0VOE/RyEHFzE+7WzxURU2M3uaMneq2wIgdNMkWI40nt+IB+LFq8vJ+/s3JqDCk/0IB51Bj/vdtFcBAAEBH/Ti9QUAAAAAFgAUqcfz12qrI5sW8+UM40o8NJGbvxwAAA=="

Output:

{
  "inputs": [
    {
      "has_utxo": true,
      "is_final": false,
      "next": "finalizer"
    },
    {
      "has_utxo": true,
      "is_final": false,
      "next": "updater",
      "missing": {
        "pubkeys": [
          "a9c7f3d76aab239b16f3e50ce34a3c34919bbf1c"
        ]
      }
    }
  ],
  "fee": 0.00001000,
  "next": "updater"
}

Since the command output shows that only Bob’s signature is missing, Alice is sure that she has signed correctly.

Bob performs the same steps that Alice has done to sign the transaction.

⚠️ Warning!
Bob repeats the steps with the transaction obtained in the command “utxoupdatepsbt” not with the signed transaction from Alice!

At the end he executes the command “analyzepsbt” also to make sure that he has signed correctly:

bitcoin-cli analyzepsbt "cHNidP8BAHsCAAAAAuVgYiTfvWiMqTqR3MWflESS/38CJAOy0m8XG3onO8FzAAAAAAD9////Xp1MH2fi5UzJmNDGoqELquZw3O7Vx+EzM5yHm3yBl3cBAAAAAP3///8BAMLrCwAAAAAWABSTZrgEXbs9U7Ow3NP9KytIikLeSAAAAAAAAQEf9OL1BQAAAAAWABSwcT0MvrjbtH8Tu7UWrYU7nU5ocwABAR/04vUFAAAAABYAFKnH89dqqyObFvPlDONKPDSRm78cIgIDDHkSKRVSKLVTwBM8zclLbfzoU0ax431MOeTO7jhNgQJHMEQCIHu7QJ227MnOCoWIgkfKkFpiBlUEfm/Tzs66+wSti5LnAiB767C0BufcXueZR/muH+DeFVSGTE+Hbjt8sgvlyUDGZAEAAA=="

Output:

{
  "inputs": [
    {
      "has_utxo": true,
      "is_final": false,
      "next": "updater",
      "missing": {
        "pubkeys": [
          "b0713d0cbeb8dbb47f13bbb516ad853b9d4e6873"
        ]
      }
    },
    {
      "has_utxo": true,
      "is_final": false,
      "next": "finalizer"
    }
  ],
  "fee": 0.00001000,
  "next": "updater"
}

Bob can see that his signature has been correctly added and indicates Alice’s signature as pending.

Combine the PSBTs and broadcast the final transaction.

At this point Bob and Alice each have the PSBT signed separately. They only need to combine them in order to have the final transaction and be able to broadcast it to the network.

To merge them they use the command "combinepsbt". This takes for arguments the PSBTs in a list as follows:

bitcoin-cli combinepsbt '["psbt_alice", "psbt_bob"]'

The command they execute is as follows:

bitcoin-cli combinepsbt '["cHNidP8BAHsCAAAAAuVgYiTfvWiMqTqR3MWflESS/38CJAOy0m8XG3onO8FzAAAAAAD9////Xp1MH2fi5UzJmNDGoqELquZw3O7Vx+EzM5yHm3yBl3cBAAAAAP3///8BAMLrCwAAAAAWABSTZrgEXbs9U7Ow3NP9KytIikLeSAAAAAAAAQEf9OL1BQAAAAAWABSwcT0MvrjbtH8Tu7UWrYU7nU5ocyICAqMy+J7K6eLwFZ82KfZ8NEOYP/fT2XJBP7fZKzgTHebMRzBEAiAfOG5ztzUxczR0VOE/RyEHFzE+7WzxURU2M3uaMneq2wIgdNMkWI40nt+IB+LFq8vJ+/s3JqDCk/0IB51Bj/vdtFcBAAEBH/Ti9QUAAAAAFgAUqcfz12qrI5sW8+UM40o8NJGbvxwAAA==", "cHNidP8BAHsCAAAAAuVgYiTfvWiMqTqR3MWflESS/38CJAOy0m8XG3onO8FzAAAAAAD9////Xp1MH2fi5UzJmNDGoqELquZw3O7Vx+EzM5yHm3yBl3cBAAAAAP3///8BAMLrCwAAAAAWABSTZrgEXbs9U7Ow3NP9KytIikLeSAAAAAAAAQEf9OL1BQAAAAAWABSwcT0MvrjbtH8Tu7UWrYU7nU5ocwABAR/04vUFAAAAABYAFKnH89dqqyObFvPlDONKPDSRm78cIgIDDHkSKRVSKLVTwBM8zclLbfzoU0ax431MOeTO7jhNgQJHMEQCIHu7QJ227MnOCoWIgkfKkFpiBlUEfm/Tzs66+wSti5LnAiB767C0BufcXueZR/muH+DeFVSGTE+Hbjt8sgvlyUDGZAEAAA=="]'

Output:

cHNidP8BAHsCAAAAAuVgYiTfvWiMqTqR3MWflESS/38CJAOy0m8XG3onO8FzAAAAAAD9////Xp1MH2fi5UzJmNDGoqELquZw3O7Vx+EzM5yHm3yBl3cBAAAAAP3///8BAMLrCwAAAAAWABSTZrgEXbs9U7Ow3NP9KytIikLeSAAAAAAAAQEf9OL1BQAAAAAWABSwcT0MvrjbtH8Tu7UWrYU7nU5ocyICAqMy+J7K6eLwFZ82KfZ8NEOYP/fT2XJBP7fZKzgTHebMRzBEAiAfOG5ztzUxczR0VOE/RyEHFzE+7WzxURU2M3uaMneq2wIgdNMkWI40nt+IB+LFq8vJ+/s3JqDCk/0IB51Bj/vdtFcBAAEBH/Ti9QUAAAAAFgAUqcfz12qrI5sW8+UM40o8NJGbvxwiAgMMeRIpFVIotVPAEzzNyUtt/OhTRrHjfUw55M7uOE2BAkcwRAIge7tAnbbsyc4KhYiCR8qQWmIGVQR+b9POzrr7BK2LkucCIHvrsLQG59xe55lH+a4f4N4VVIZMT4duO3yyC+XJQMZkAQAA

The output of the command is the aggregated PSBT from both of them. They can run a last check with the command “analyzepsbt”:

bitcoin-cli analyzepsbt "cHNidP8BAHsCAAAAAuVgYiTfvWiMqTqR3MWflESS/38CJAOy0m8XG3onO8FzAAAAAAD9////Xp1MH2fi5UzJmNDGoqELquZw3O7Vx+EzM5yHm3yBl3cBAAAAAP3///8BAMLrCwAAAAAWABSTZrgEXbs9U7Ow3NP9KytIikLeSAAAAAAAAQEf9OL1BQAAAAAWABSwcT0MvrjbtH8Tu7UWrYU7nU5ocyICAqMy+J7K6eLwFZ82KfZ8NEOYP/fT2XJBP7fZKzgTHebMRzBEAiAfOG5ztzUxczR0VOE/RyEHFzE+7WzxURU2M3uaMneq2wIgdNMkWI40nt+IB+LFq8vJ+/s3JqDCk/0IB51Bj/vdtFcBAAEBH/Ti9QUAAAAAFgAUqcfz12qrI5sW8+UM40o8NJGbvxwiAgMMeRIpFVIotVPAEzzNyUtt/OhTRrHjfUw55M7uOE2BAkcwRAIge7tAnbbsyc4KhYiCR8qQWmIGVQR+b9POzrr7BK2LkucCIHvrsLQG59xe55lH+a4f4N4VVIZMT4duO3yyC+XJQMZkAQAA"
{
  "inputs": [
    {
      "has_utxo": true,
      "is_final": false,
      "next": "finalizer"
    },
    {
      "has_utxo": true,
      "is_final": false,
      "next": "finalizer"
    }
  ],
  "estimated_vsize": 177,
  "estimated_feerate": 0.00005649,
  "fee": 0.00001000,
  "next": "finalizer"
}

They thus check that neither of the two signatures is missing. At this point either of the two can broadcast the transaction by loading it to the Sparrow from text, as in the previous steps, and selecting the “Broadcast Transaction” option.

We can check in any web browser that the transaction has been sent correctly and pay the 2 bitcoins for the TV:

transaction id: c659c7cb31733f153f04c1fbffeec91b99a96f2e289f47852374d0101e303e50

The transaction has been sent correctly and Bob and Alice have been able to pay for the TV with a joint transaction!!!!