Created
March 6, 2024 19:55
-
-
Save harding/d44c4a44dffb6c5f44eb6f96146978f3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash -eu | |
# NO WARRANTY PROVIDED OR IMPLIED. USE AT YOUR OWN RISK. | |
########### | |
## Paths ## | |
########### | |
# This is the keypath provided in the Casa recovery email minus the "m" | |
KEYPATH="/49/0/0" | |
# Sub-paths. This not provided by Casa in their recovery | |
# instructions but seems to follow the Electrum v4 default, which is | |
# - External: /0/* | |
# - Internal (change): /1/* | |
EXTERNAL_SUBPATH="/0/*" | |
INTERNAL_SUBPATH="/1/*" | |
########### | |
## Xpubs ## | |
########### | |
# All operations with this script require you to enter the extended | |
# pubkeys (xpubs) for all five signing keys. If you want to use the | |
# descriptors for address verification or signing, you will also need to | |
# provide their fingerprints (FPs). | |
# | |
# The Casa recovery email includes ypubs (not xpubs) for the mobile and | |
# recovery keys. You will need to convert those ypubs to xpubs, which | |
# can be done with the following tool: | |
# | |
# https://jlopp.github.io/xpub-converter/ | |
# | |
# Note: you can use that page offline for additional privacy, although | |
# the operator of that website is currently Casa's CTO, so I ran it | |
# online | |
MOBILE_FP=FILL_THIS_IN | |
MOBILE_XPUB=FILL_THIS_IN | |
RECOVERY_FP=FILL_THIS_IN | |
RECOVERY_XPUB=FILL_THIS_IN | |
# For HW wallets, use HWI to get the xpubs. E.g., plug in the device, | |
# enter its pin (or use `hwi promptpin`), use `hwi enumerate` to get | |
# it's fingerprint, and use something like this to get its xpub: | |
# hwi -t ledger getxpub m$KEYPATH | |
HW1_FP=FILL_THIS_IN | |
HW1_XPUB=FILL_THIS_IN | |
HW2_FP=FILL_THIS_IN | |
HW2_XPUB=FILL_THIS_IN | |
HW3_FP=FILL_THIS_IN | |
HW3_XPUB=FILL_THIS_IN | |
############################## END CONFIGURATION ################################### | |
## You shouldn't need to edit anything below this point, except for special cases ## | |
#################################################################################### | |
# sh: P2SH, wsh: witness script hash, sortedmulti: multisig with keys in | |
# BIP67 order, 3: 3-of-n multisig | |
external_descriptor="sh(wsh(sortedmulti(3," | |
internal_descriptor="sh(wsh(sortedmulti(3," | |
# The five fingerprints and xpubs | |
external_descriptor="${external_descriptor}[$MOBILE_FP$KEYPATH]$MOBILE_XPUB$EXTERNAL_SUBPATH," | |
internal_descriptor="${internal_descriptor}[$MOBILE_FP$KEYPATH]$MOBILE_XPUB$INTERNAL_SUBPATH," | |
external_descriptor="${external_descriptor}[$RECOVERY_FP$KEYPATH]$RECOVERY_XPUB$EXTERNAL_SUBPATH," | |
internal_descriptor="${internal_descriptor}[$RECOVERY_FP$KEYPATH]$RECOVERY_XPUB$INTERNAL_SUBPATH," | |
external_descriptor="${external_descriptor}[$HW1_FP$KEYPATH]$HW1_XPUB$EXTERNAL_SUBPATH," | |
internal_descriptor="${internal_descriptor}[$HW1_FP$KEYPATH]$HW1_XPUB$INTERNAL_SUBPATH," | |
external_descriptor="${external_descriptor}[$HW2_FP$KEYPATH]$HW2_XPUB$EXTERNAL_SUBPATH," | |
internal_descriptor="${internal_descriptor}[$HW2_FP$KEYPATH]$HW2_XPUB$INTERNAL_SUBPATH," | |
external_descriptor="${external_descriptor}[$HW3_FP$KEYPATH]$HW3_XPUB$EXTERNAL_SUBPATH" | |
internal_descriptor="${internal_descriptor}[$HW3_FP$KEYPATH]$HW3_XPUB$INTERNAL_SUBPATH" | |
# Close the sh/wsh/sortedmulti parens | |
external_descriptor="${external_descriptor})))" | |
internal_descriptor="${internal_descriptor})))" | |
# Validate the descriptors and update them to include a checksum | |
external_descriptor=$( bitcoin-cli getdescriptorinfo "$external_descriptor" | jq -r .descriptor ) | |
if [ "$external_descriptor" == "" ]; then | |
echo "Error parsing external descriptor. Check fingerprints and keys for typos. Terminating script..." | |
exit 1 | |
fi | |
internal_descriptor=$( bitcoin-cli getdescriptorinfo "$internal_descriptor" | jq -r .descriptor ) | |
if [ "$internal_descriptor" == "" ]; then | |
echo "Error parsing internal descriptor. Check fingerprints and keys for typos. Terminating script..." | |
exit 1 | |
fi | |
case "$1" in | |
get_descriptors) | |
echo "$external_descriptor" | |
echo "$internal_descriptor" | |
;; | |
derive_receiving_addresses) | |
# Only derive receiving (external) addresses | |
bitcoin-cli deriveaddresses "$external_descriptor" 1000 | |
;; | |
# Note, if you get a "ripemd160 not supported error", see https://github.com/bitcoin-core/HWI/issues/656 | |
verify_receive_address) | |
shift | |
if [ $# -lt 1 ] ; then | |
echo "$0 verify_receive_address <address> <hwi_arguments>" | |
exit 1 | |
fi | |
ADDRESS="$1" ; shift | |
index=$( $0 derive_receiving_addresses | jq 'index("'$ADDRESS'")' ) | |
if ! echo "$index" | grep -q '^[0-9]\+$' ; then | |
echo "Address not found: $ADDRESS" | |
exit 1 | |
fi | |
# Our original ranged descriptor looks like: | |
# sh(wsh(sortedmulti(3,[.../49/0/0]xpub.../0/*,.... | |
# We need a single-address descriptor that looks like: | |
# sh(wsh(sortedmulti(3,[.../49/0/0/]xpub.../0/$index,.... | |
address_descriptor=$( echo "$external_descriptor" | sed """ | |
# Remove the checksum | |
s/#.*//; | |
# Replace the range "*" with the particular index | |
s/\*/$index/g; | |
""" ) | |
# Give the individual descriptor a checksum | |
address_descriptor=$( bitcoin-cli getdescriptorinfo "$address_descriptor" | jq -r .descriptor ) | |
derived_address=$( bitcoin-cli deriveaddresses "$address_descriptor" | jq -r '.[]' ) | |
if [ "$ADDRESS" != "$derived_address" ] ; then | |
echo "Something went wrong. Provided address $ADDRESS not the same as computed address $derived_address. Exiting..." | |
exit 1 | |
fi | |
echo "Press enter to run the following command to verify address $ADDRESS:" | |
echo | |
echo " hwi" "$@" displayaddress --desc "$address_descriptor" | |
echo | |
echo "Press CTRL-C if any necessary parameters to hwi, like -t and -d, are missing" | |
echo "Also remember to unlock your device with its pin before pressing enter" | |
read | |
hwi "$@" displayaddress --desc "$address_descriptor" | |
;; | |
scan_utxos) | |
# NB: increase the ranges if you've sent or received more than that | |
# number of payments using your Casa wallet. | |
bitcoin-cli scantxoutset start '[{"desc": "'"$internal_descriptor"'", "range": 1000}, {"desc": "'"$external_descriptor"'", "range": 1000}]' | |
;; | |
*) | |
echo "Unknown command: $1" | |
exit 1 | |
;; | |
esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment