Created
March 6, 2024 19:55
Revisions
-
harding created this gist
Mar 6, 2024 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,164 @@ #!/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