3

My goal

Learn how to send an imported tr(wif) and wpkh() utxo in the same transaction.

What I've tried

I imported a WIF utxo containing a v1 segwit utxo.

bitcoin-cli importdescriptors '[{"desc":"tr(wifkey)#checksum", "timestamp":unixts}]'

I didn't know the checksum, but when importing I got an error that told me what the checksum should be, so I used that.

The balance showed up after import, I assume it was imported correctly.

Learned createrawtransaction, fundrawtransaction, signrawtransactionwithwallet are not acceptable for taproot. This was resulting in "Witness program was passed an empty witness".

It seems psbt commands are more appropriate. However, I couldn't figure out how to successfully sign with cli. I kept getting "complete": false returned.

I then tried bitcoin-qt and attempted to sweep funds to an address as a test. I received this: fail signing

While using bitcoin-cli and running bitcoin-cli listunspent I see:

[
  {
    "txid": "TX_1",
    "vout": x,
    "address": "ADDR_1",
    "label": "xxx1",
    "scriptPubKey": "44_LEGNTH_HEX_STRING",
    "amount": xxxxxx.xxxxxx,
    "confirmations": xxx,
    "spendable": true,
    "solvable": true,
    "desc": "wpkh([FINGERPRINT/84'/0'/0'/0/0]KEY)#CHECKSUM1",
    "parent_descs": [
      "wpkh(xpub_key/84'/0'/0'/0/*)#CHECKSUM-parent"
    ],
    "safe": true
  },
  {
    "txid": "TX_2",
    "vout": xx,
    "address": "ADDR_2",
    "label": "xxx2",
    "scriptPubKey": "68_LENGTH_HEX_STRING",
    "amount": xxxxxx.xxxxxx,
    "confirmations": xxxx,
    "spendable": true,
    "solvable": true,
    "desc": "tr([FINGERPRINT2]KEY2)#CHECKSUM2",
    "parent_descs": [
      "tr(KEY2)#CHECKSUM2"
    ],
    "safe": true
  }
]

Output sanitized

Question

  • What are the methodical steps starting with an imported WIF/taproot utxo + wpkh utxo and creating a signed tx to send funds?
19
  • 1
    You need to use a descriptor wallet, and import the key as a taproot descriptor (if it's just a key path key, it would be tr(WIF), but scripts can also be included there). Further, you need to use PSBT RPCs; the old raw transacrion RPCs in general do not support taproot. Jun 4, 2023 at 11:32
  • I'm currently doing createpsbt then walletcreatefundedpsbt but not sure where to go from here. I've tried both walletprocesspsbt and finalizepsbt but they return the base64 encoding and "complete": false. I've tried utxoupdatepsbt but unsure what I would need to do since I've already successfully imported this into my wallet. What steps am I missing? Jun 4, 2023 at 21:51
  • It would be useful if you'd include the exact commands and output you're seeing in your question. If need be, you can try to recreate on regtest / signet / testnet. Jun 4, 2023 at 21:58
  • 1
    A tr(WIF) descriptor is not ranged, so that's clearly not what you're doing on regtest Jun 5, 2023 at 0:18
  • 2
    Whatever you want to go in an OP_RETURN goes there. But again, please update your question with whatever your question has now evolved to be Jun 5, 2023 at 11:30

1 Answer 1

2

Regularly you'd use walletcreatefundedpsbt and then walletprocesspsbt. But since you've only got two coins in your wallet that you want to sweep you can simply use sendall.

Let's walk through a reproduction of your scenario. I've created two regtest-WIF-encoded private keys:

  • cRZ9wuYhwKYm82rXfSk9hhc9beJy6p7rV4y3aoAdzqFD6YAUVQcJ (corresponding to 029d759b09cec94b6f2bd322cedd5d136e7f24a4936998fe24da09827d8a12e9dd)
  • cVFkDn9fS1rwU1SR7geC3rgoGNXLpZXsnrCq2gutYVsGA2FoLpCD (corresponding to 03bd0d0b820dae844107803c9323fe73e81b9adf8abe329930ae9311dab6c3573e)

I'm creating a new wallet and importing a tr() and wpkh() descriptor.

$ bitcoin-cli -regtest createwallet repro_stackexchange
{
  "name": "repro_stackexchange",
  "warning": ""
}
$ bitcoin-cli -regtest -rpcwallet=repro_stackexchange importdescriptors '[{"desc":"tr(cRZ9wuYhwKYm82rXfSk9hhc9beJy6p7rV4y3aoAdzqFD6YAUVQcJ)#uj39yr2v","timestamp":"now"},{"desc":"wpkh(cVFkDn9fS1rwU1SR7geC3rgoGNXLpZXsnrCq2gutYVsGA2FoLpCD)#nayxphlw","timestamp":"now"}]'
[
  {
    "success": true
  },
  {
    "success": true
  }
]

Now i'm sending a coin to each descriptor:

$ bitcoin-cli -named -regtest -rpcwallet=main sendtoaddress address=bcrt1ps66a3wss3l0ay0agnkd57cfu6qrw26z632e0kez0ppjzkyaq0vhskxlrvs amount=0.00042 fee_rate=1
b2e975dee4ab0c68748e85fc847d7ef3fef44f53ee95e4765b1cc2b2c33939d2
$ bitcoin-cli -named -regtest -rpcwallet=main sendtoaddress address=bcrt1q9vsfxgf4t3wmtj9429g539txyv4p2qnuak03sv amount=0.00043 fee_rate=1
e34a3b8116f328d2b1529134dfcc795fbe27eae3991eeb017bc582879cb73b81

We can see that the reproduction wallet got the two coins:

$ bitcoin-cli -regtest -rpcwallet=repro_stackexchange listunspent 0
[
  {
    "txid": "e34a3b8116f328d2b1529134dfcc795fbe27eae3991eeb017bc582879cb73b81",
    "vout": 0,
    "address": "bcrt1q9vsfxgf4t3wmtj9429g539txyv4p2qnuak03sv",
    "label": "",
    "scriptPubKey": "00142b209321355c5db5c8b55151489566232a15027c",
    "amount": 0.00043000,
    "confirmations": 0,
    "ancestorcount": 1,
    "ancestorsize": 130,
    "ancestorfees": 130,
    "spendable": true,
    "solvable": true,
    "desc": "wpkh([2b209321]03bd0d0b820dae844107803c9323fe73e81b9adf8abe329930ae9311dab6c3573e)#k6qfdnw5",
    "parent_descs": [
      "wpkh(03bd0d0b820dae844107803c9323fe73e81b9adf8abe329930ae9311dab6c3573e)#45n94hja"
    ],
    "safe": false
  },
  {
    "txid": "b2e975dee4ab0c68748e85fc847d7ef3fef44f53ee95e4765b1cc2b2c33939d2",
    "vout": 1,
    "address": "bcrt1ps66a3wss3l0ay0agnkd57cfu6qrw26z632e0kez0ppjzkyaq0vhskxlrvs",
    "label": "",
    "scriptPubKey": "512086b5d8ba108fdfd23fa89d9b4f613cd006e5685a8ab2fb644f08642b13a07b2f",
    "amount": 0.00042000,
    "confirmations": 0,
    "ancestorcount": 1,
    "ancestorsize": 154,
    "ancestorfees": 154,
    "spendable": true,
    "solvable": true,
    "desc": "tr([caa3ae90]9d759b09cec94b6f2bd322cedd5d136e7f24a4936998fe24da09827d8a12e9dd)#e2lr407t",
    "parent_descs": [
      "tr(9d759b09cec94b6f2bd322cedd5d136e7f24a4936998fe24da09827d8a12e9dd)#u9ras3xm"
    ],
    "safe": false
  }
]

Now i'll get the transactions confirmed and sweep the coins using sendall:

$ bitcoin-cli -regtest -rpcwallet=main generatetoaddress 1 $(bitcoin-cli -regtest -rpcwallet=main getnewaddress)
$ bitcoin-cli -named -regtest -rpcwallet=repro_stackexchange sendall recipients='["bcrt1qre2fezscuke8qaj9ham2klddj2rt7m4s78tvqq"]' fee_rate=1
{
  "txid": "a39b70bf4636bb78053d10a3bc03eb6866e6777e84aeb274bb4002a543b7bb99",
  "complete": true
}

Let's inspect the transaction. It does indeed spend the two coins from the wallet (one Taproot and one native segwit v0 as you can see from the witness):

$ bitcoin-cli -regtest getrawtransaction a39b70bf4636bb78053d10a3bc03eb6866e6777e84aeb274bb4002a543b7bb99 1
{
  "txid": "a39b70bf4636bb78053d10a3bc03eb6866e6777e84aeb274bb4002a543b7bb99",
  "hash": "be1fcf89ec92649ee0780a8ea86ade1512a7fff6cfc8f75430b1115f1321b8f1",
  "version": 2,
  "size": 298,
  "vsize": 167,
  "weight": 667,
  "locktime": 0,
  "vin": [
    {
      "txid": "e34a3b8116f328d2b1529134dfcc795fbe27eae3991eeb017bc582879cb73b81",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "txinwitness": [
        "304402201e3ba83ca58a357e72d9df4d555f11a747e128ab2131868cb5620afc9b383d540220011c6fe77e37ed8ca83d50870fc5cc3995ecbd1cbd6305ede59bd4fd8aa05c2901",
        "03bd0d0b820dae844107803c9323fe73e81b9adf8abe329930ae9311dab6c3573e"
      ],
      "sequence": 4294967293
    },
    {
      "txid": "b2e975dee4ab0c68748e85fc847d7ef3fef44f53ee95e4765b1cc2b2c33939d2",
      "vout": 1,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "txinwitness": [
        "6cd85a806478d00f062e0bd7a43f46d7be082e4287819fcf07d3dda1d6a613a11e1197d15021f87aad16a697e326181d82156ff957fcb6593f5d030f33516471"
      ],
      "sequence": 4294967293
    }
  ],
  "vout": [
    {
      "value": 0.00084833,
      "n": 0,
      "scriptPubKey": {
        "asm": "0 1e549c8a18e5b2707645bf76ab7dad9286bf6eb0",
        "desc": "addr(bcrt1qre2fezscuke8qaj9ham2klddj2rt7m4s78tvqq)#5gumgp89",
        "hex": "00141e549c8a18e5b2707645bf76ab7dad9286bf6eb0",
        "address": "bcrt1qre2fezscuke8qaj9ham2klddj2rt7m4s78tvqq",
        "type": "witness_v0_keyhash"
      }
    }
  ],
  "hex": "02000000000102813bb79c8782c57b01eb1e99e3ea27be5f79ccdf349152b1d228f316813b4ae30000000000fdffffffd23939c3b2c21c5b76e495ee534ff4fef37e7d84fc858e74680cabe4de75e9b20100000000fdffffff01614b0100000000001600141e549c8a18e5b2707645bf76ab7dad9286bf6eb00247304402201e3ba83ca58a357e72d9df4d555f11a747e128ab2131868cb5620afc9b383d540220011c6fe77e37ed8ca83d50870fc5cc3995ecbd1cbd6305ede59bd4fd8aa05c29012103bd0d0b820dae844107803c9323fe73e81b9adf8abe329930ae9311dab6c3573e01406cd85a806478d00f062e0bd7a43f46d7be082e4287819fcf07d3dda1d6a613a11e1197d15021f87aad16a697e326181d82156ff957fcb6593f5d030f3351647100000000"
}
4
  • Antoine, great thorough answer. I do have a concept question follow up. Can you take any WIF and import it as any descriptor type? For instance if you previously had a taproot utxo/descriptor would you need to make sure that was imported as a tr()? or could you import also as wpkh()? Jun 7, 2023 at 3:06
  • Antoine, another followup question. When i run something like bitcoin-cli -rpcwallet=wallet_x2 getnewaddress "label" "bech32m" How do I know it's using the imported tr() descriptor? and not the wallet's generic tr ranged descriptor? Jun 7, 2023 at 3:43
  • You can use a WIF encoded private key everywhere a key expression is expected. Jun 7, 2023 at 7:54
  • 1
    You can set a descriptor as active when importing it to use it to generate receive addresses (but it needs to be ranged if i'm remembering correctly). Otherwise just use deriveaddresses. Jun 7, 2023 at 7:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.