You can achieve this without any script, simply using the Bitcoin Core wallet. For each public key you received funds on you can import a pk()
descriptor containing the corresponding private key, WIF-encoded. Then you can rescan the block chain for the wallet to get knowledge of the outputs paying to you. Finally you can sweep those funds as you would normally spend from a Bitcoin Core wallet.
Let me guide you through an example to achieve this on regtest. Note the WIF encoding differs on test networks, but the process is the same on mainnet. I'll be using the private key cSWVo8YMehg6STxqw6xGgmMJE6Ac6RCJ7owcrBZRAT7QANtyAAEj
, corresponding to public key 023ad6336ae257527ff59ec4356fa5d2ac33fff5e04be9e5958dfed9b0100b7948
.
First, create a descriptor for the private key and get its checksum using getdescriptorinfo
:
$ bitcoin-cli -regtest getdescriptorinfo "pk(cSWVo8YMehg6STxqw6xGgmMJE6Ac6RCJ7owcrBZRAT7QANtyAAEj)"
{
"descriptor": "pk(023ad6336ae257527ff59ec4356fa5d2ac33fff5e04be9e5958dfed9b0100b7948)#vl2598s2",
"checksum": "0hjwa0sj",
"isrange": false,
"issolvable": true,
"hasprivatekeys": true
}
Then create a wallet and import this descriptor:
$ bitcoin-cli -regtest createwallet p2pk_recovery false true
{
"name": "p2pk_recovery",
"warning": ""
}
$ bitcoin-cli -regtest -rpcwallet=p2pk_recovery importdescriptors '[{"desc":"pk(cSWVo8YMehg6STxqw6xGgmMJE6Ac6RCJ7owcrBZRAT7QANtyAAEj)#0hjwa0sj","timestamp":"now"}]'
[
{
"success": true
}
]
$ bitcoin-cli -regtest -rpcwallet=p2pk_recovery listdescriptors
{
"wallet_name": "p2pk_recovery",
"descriptors": [
{
"desc": "pk(023ad6336ae257527ff59ec4356fa5d2ac33fff5e04be9e5958dfed9b0100b7948)#vl2598s2",
"timestamp": 1681809105,
"active": false
}
]
}
Then rescan the chain. I didn't have to do this on my end, but you can use rescanblockchain
. If you already know the height of the outputs you are looking for i strongly advise you specify a range to speed up the rescan. For instance if you know you've only got outputs between blocks 100 and 150:
$ bitcoin-cli -regtest -rpcwallet=p2pk_recovery rescanblockchain 100 150
{
"start_height": 100,
"stop_height": 150
}
By now you should have at least one utxo for at least one of the imported descriptors in your wallet:
$ bitcoin-cli -regtest -rpcwallet=p2pk_recovery listunspent
[
{
"txid": "29c3b60341cff26bdce49c3611259ac50cddde4225307c6a130f12abfdb7e22a",
"vout": 0,
"address": "myzWnxTFbp4La7uSAK4ppyg45bTw96hQ2S",
"label": "",
"scriptPubKey": "21023ad6336ae257527ff59ec4356fa5d2ac33fff5e04be9e5958dfed9b0100b7948ac",
"amount": 0.00051000,
"confirmations": 1,
"spendable": true,
"solvable": true,
"desc": "pk([caa89f91]023ad6336ae257527ff59ec4356fa5d2ac33fff5e04be9e5958dfed9b0100b7948)#kmv3ht9h",
"parent_descs": [
"pk(023ad6336ae257527ff59ec4356fa5d2ac33fff5e04be9e5958dfed9b0100b7948)#vl2598s2"
],
"safe": true
}
]
You can then trivially spend the coins from your wallet. For instance:
$ bitcoin-cli -named -regtest -rpcwallet=p2pk_recovery sendtoaddress address=bcrt1pne0s48y6akyw2zd4uzua033u9dxeywxu7wd6fzu3l2dcf7sc3qhsd87l2x amount=0.0005 fee_rate=1
de3c9371404c07493e8c5f43149b91c5c1ed556ebc93ace47617d96026d4902d
If you are using Bitcoin Core version 24
or higher you can also use the sendall
command that allows for an easier sweep of all confirmed coins in the wallet since you don't have to set the amount. For instance (with the same value as above):
bitcoin-cli -named -regtest -rpcwallet=p2pk_recovery sendall recipients='["bcrt1pne0s48y6akyw2zd4uzua033u9dxeywxu7wd6fzu3l2dcf7sc3qhsd87l2x"]' fee_rate=1
Note also that i'm using a 1sat/vb feerate on regtest, but on mainnet you want to use an accurate fee estimation instead of this arbitrary value.
sendall
RPC to sweep everything into a new address. You should perhaps explicitly comment on the feerate, as currently the mempool is kinda bonkers. – Murch May 03 '23 at 15:31sendall
and for some reason figured i'd just stick to the familiarsendtoaddress
. I've added some comments on usingsendall
and on the feerate. Feel free to amend if you think it could be clearer. – Antoine Poinsot May 03 '23 at 15:51