Saltar al contenido

Cómo hacer una transacción con UTXOs de wallets diferentes

Tiempo de lectura aprox: 6 minutos, 13 segundos

Supongamos que Bob y Alice comparten piso y quieren comprar un televisor que vale 2 bitcoin pagando la mitad cada uno. Para hacerlo, Bob podría enviar 1 bitcoin a Alice para que ella hiciera el pago del televisor, pero como las comisiones de red son bastante elevadas, deciden crear una transacción conjunta donde haya dos inputs, uno de Alice y uno de Bob.

Los ejemplos prácticos del post están hechos en testnet. Por lo tanto, si se quieren ejecutar los comandos de Bob y Alice con los mismos valores, o buscar las transacciones en un explorador, debe hacerse desde las correspondientes versiones en testnet.

Crear la PSBT

Lo primero que hacen es crear una transacción parcialmente firmada (PSBT) donde especifican los UTXO que quiere gastar cada uno y la salida que quieren crear. Los datos para la entrada de la PSBT son los dos UTXO de 1.000005 bitcoin cada uno:

UTXO de Alice: 73c13b277a1b176fd2b20324027fff9244949fc5dc913aa98c68bddf246260e5:0

UTXO de Bob: 7797817c9b879c3333e1c7d5eedc70e6aa0ba1a2c6d098c94ce5e2671f4c9d5e:1

Los datos para la salida son la dirección de destino y la cantidad de bitcoin que quieren enviar:

Dirección de destino: tb1qjdntspzahv748vasmnfl62etfz9y9hjgmvg6gw

Cantidad: 2 btc

Como utilizan Sparrow como wallet y esta no permite la creación de PSBTs de este tipo, deben utilizar otra herramienta. Para ello usan su propio nodo de Bitcoin y su interfaz de comandos (bitcoin-cli).

Para crear la PSBT usan bitcoin-cli y el comando «createpsbt». Este toma dos argumentos obligatorios, los inputs y los outputs. Para el input se debe especificar el id de la transacción y el número del output. Para el output se debe especificar la dirección de destino y la cantidad que se quiere enviar.

bitcoin-cli createpsbt '[{"txid": "txId", "vout": nOut}]' '[{"dirección de destino": "núm btc"}]'

ALERTA! La diferencia entre el valor de las entradas y el valor de la salida se paga en forma de comisión. Si se quiere devolver el dinero restante, hay que añadir una salida con una dirección de cambio y darle un valor!

El comando que ejecutan Alice y Bob es el siguiente:

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

Output:

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

El output que obtienen es la transacción en raw y codificada en base64. Esta transacción aún no está lista para ser firmada, necesita que se le actualice la información de los inputs y los outputs segwit. Para terminar de montar correctamente la transacción, Bob y Alice utilizan el comando «utxoupdatepsbt». Este comando toma como único argumento una transacción en raw codificada en base64, exactamente como la que nos genera el comando «createpsbt».

bitcoin-cli utxoupdatepsbt "transacción en raw y base64"

El comando que ejecutan Alice i Bob queda de la siguiente manera:

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

Output:

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

El output es la misma transacción en raw y codificada en base64, pero esta vez ya lista para ser firmada. Se puede comprobar el estado de la PSBT con el comando «analyzepsbt». Este comando analiza la PSBT y da información sobre el estado de la misma. Toma como argumento una PSBT en raw y base64:

bitcoin-cli analyzepsbt "transacción en raw y base64"

Bob y Alice comprueban el estado de su PSBT con el siguiente comando:

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"
}

En el JSON que nos proporciona la salida podemos ver cómo faltan las dos firmas, tanto la de Alice como la de Bob.

Idea! El comando anterior también nos permite ver cuánto bitcoin paga la transacción en forma de comisiones, es buena idea revisar que no estamos pagando más de la cuenta!

Firmar la PSBT

La primera en firmar la transacción será Alice. Para ello abre su wallet Sparrow y carga la transacción obtenida del comando «utxoupdatepsbt» en forma de texto:

Con la transacción cargada se puede ver como el propio Sparrow detecta que la primera entrada pertenece a Alice:

Con el fin de firmarla, Alice pulsa «Finalize Transaction for Signing» y a continuación «Sign». Una vez firmada, Alice se guarda la transacción con la opción «Save Transaction». Eso le genera un fichero «.psbt».

Como tiene curiosidad por saber si se ha hecho correctamente, vuelve a ejecutar el comando «analyzepsbt». Este toma como argumento una transacción en raw y codificada en base64. Con el fin de mostrar la transacción del fichero «.psbt» en el formato necesario, Alice utiliza el comando:

cat alice.psbt | base64 -w 0

Output:

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

Ya puede ejecutar el pedido «analyzepsbt» con la transacción codificada correctamente:

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"
}

Ahora Alice tiene la certeza de que ha firmado, ya que la salida del comando muestra que solo falta la firma de Bob.

Bob realiza los mismos pasos que ha dado Alice para firmar la transacción.

¡Alerta! Bob repite los pasos con la transacción obtenida en el comando «utxoupdatepsbt», no con la transacción firmada de Alice!

A continuación ejecuta el comando «analyzepsbt» también para asegurarse de que ha firmado correctamente:

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 puede ver que su firma se ha añadido correctamente y le señala como pendiente la firma de Alice.

Fusionar las PSBT y retransmitir la transacción final

Llegados a este punto, Bob y Alice tienen cada uno la PSBT firmada por separado. Solo les falta fusionarlas para tener la transacción final y poderla retransmitir a la red.

Para fusionarlas utilizan el comando «combinepsbt». Ésta toma por argumentos las PSBT en una lista de la siguiente manera:

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

El comando que ejecutan es el siguiente:

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

La salida del comando es la PSBT agregada de los dos. Pueden hacer una última comprobación con el comando «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"
}

Comprueban así que no falta ninguna de las dos firmas. A partir de este punto cualquiera de los dos puede cargar la transacción a Sparrow desde texto, como se ha hecho en los pasos anteriores, y retransmitirla mediante la opción «Broadcast Transaction».

Podemos comprobar en cualquier explorador de bloques que la transacción se ha enviado correctamente y paga los 2 bitcoin por el televisor:

ID de la transacción: c659c7cb31733f153f04c1fbffeec91b99a96f2e289f47852374d0101e303e50

La transacción ha sido enviada correctamente y Bob y Alice han podido pagar el televisor con una transacción conjunta!