Skip to content

upgrade to caravan from (deprecated) unchained-bitcoin, add taproot support#61

Merged
turkycat merged 8 commits intomasterfrom
jdf/caravan-upgrade
Mar 11, 2025
Merged

upgrade to caravan from (deprecated) unchained-bitcoin, add taproot support#61
turkycat merged 8 commits intomasterfrom
jdf/caravan-upgrade

Conversation

@turkycat
Copy link
Contributor

@turkycat turkycat commented Mar 4, 2025

I compiled this locally, ran the tests, validate the taproot behavior of the cli tool and library against my own extended key tools (different impl) to verify our own test keys and addresses.

I also validated against the BIP86 test vectors

BIP86 test vectors
$ ./xpub.js derive -p p2tr -v xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ
{
  path: "m/86'/0'/0'/0/0",
  address: 'bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr'
}
$ ./xpub.js derive -p p2tr -v xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ -i 1
{
  path: "m/86'/0'/0'/0/1",
  address: 'bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh'
}
$ ./xpub.js derive -p p2tr -v xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ -c 1
{
  path: "m/86'/0'/0'/1/0",
  address: 'bc1p3qkhfews2uk44qtvauqyr2ttdsw7svhkl9nkm9s9c3x4ax5h60wqwruhk7'
}
$
$ ./xpub.js validate -v -a bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr
valid address bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr
$ ./xpub.js validate -v -a bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh
valid address bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh
$ ./xpub.js validate -v -a bc1p3qkhfews2uk44qtvauqyr2ttdsw7svhkl9nkm9s9c3x4ax5h60wqwruhk7
valid address bc1p3qkhfews2uk44qtvauqyr2ttdsw7svhkl9nkm9s9c3x4ax5h60wqwruhk7

contributes to PSEC-1321 CUS-395

@turkycat turkycat requested review from a team, bertonjulian, Copilot and joernroeder March 4, 2025 23:20
@turkycat turkycat self-assigned this Mar 4, 2025
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Overview

This PR upgrades the xpub-lib package from the deprecated unchained-bitcoin to caravan-bitcoin and adds Taproot tests. Key changes include updating all import references and constants, revising test cases to support Taproot addresses, and updating documentation accordingly.

Reviewed Changes

File Description
packages/xpub-lib/src/index.js Updated export references to use caravan-bitcoin
packages/xpub-tool/src/components/layout.js Updated link to reference caravan instead of unchained-bitcoin
packages/xpub-lib/src/conversion.test.js Replaced NETWORKS with Network in test cases
packages/xpub-lib/src/metadata.js Updated import and constant usage for network values
packages/xpub-lib/src/conversion.js Replaced constant usage with caravan's Network
packages/xpub-lib/src/paths.test.js Replaced NETWORKS with Network in derivation path tests
README.md Updated documentation to refer to caravan
packages/xpub-lib/src/paths.js Updated constants in derivation path logic
packages/xpub-lib/src/validation.js Updated import reference from unchained-bitcoin to caravan
packages/xpub-tool/gatsby-config.js Updated site description to reference caravan
packages/xpub-lib/src/validation.test.js Updated tests with caravan Network and added Taproot tests
packages/xpub-lib/README.md Updated documentation to reference caravan
packages/xpub-lib/src/metadata.test.js Updated constant usage for network tests
packages/xpub-lib/test/fixtures.js Added TAPROOT test keys
packages/xpub-lib/src/derivation.js Replaced default network constant with caravan's Network
packages/xpub-lib/src/derivation.test.js Replaced NETWORKS with Network in derivation tests

Copilot reviewed 18 out of 18 changed files in this pull request and generated no comments.

Comments suppressed due to low confidence (1)

packages/xpub-lib/src/validation.test.js:162

  • [nitpick] The test description 'valid bech32 v1 (P2TR) address on mainnet' uses a testnet key and network. Consider renaming it to 'valid bech32 v1 (P2TR) address on testnet' to accurately reflect the context.
test("valid bech32 v1 (P2TR) address on mainnet", () => {

@turkycat
Copy link
Contributor Author

turkycat commented Mar 4, 2025

Note that I've added tests to validate taproot addresses in this PR.

I made those same changes on master to prove the failures:

test runs on master
$ yarn test
yarn run v1.22.22
$ yarn run compile
$ babel -d lib/ src/
Browserslist: caniuse-lite is outdated. Please run:
npx browserslist@latest --update-db
Successfully compiled 16 files with Babel (406ms).
$ jest lib
 PASS  lib/utils.test.js
 PASS  src/utils.test.js
 PASS  lib/paths.test.js
 PASS  src/metadata.test.js
 PASS  src/conversion.test.js
 PASS  lib/conversion.test.js
 PASS  src/paths.test.js
 PASS  lib/metadata.test.js
 FAIL  src/validation.test.js
  ● isValidAddress › valid bech32 v1 (P2TR) address on mainnet

    expect(received).toBeTruthy()

    Received: false

      161 |   })
      162 |   test("valid bech32 v1 (P2TR) address on mainnet", () => {
    > 163 |     expect(isValidAddress(KEY.MAIN.TAPROOT, NETWORKS.MAINNET)).toBeTruthy()
          |                                                                ^
      164 |   })
      165 | 
      166 |   // TESTNET

      at Object.<anonymous> (src/validation.test.js:163:64)
      at processTicksAndRejections (node:internal/process/task_queues:95:5)

  ● isValidAddress › valid bech32 v1 (P2TR) address on mainnet

    expect(received).toBeTruthy()

    Received: false

      175 |   })
      176 |   test("valid bech32 v1 (P2TR) address on mainnet", () => {
    > 177 |     expect(isValidAddress(KEY.TEST.TAPROOT, NETWORKS.TESTNET)).toBeTruthy()
          |                                                                ^
      178 |   })
      179 | 
      180 |   // INVALID: NETWORK MISMATCH

      at Object.<anonymous> (src/validation.test.js:177:64)
      at processTicksAndRejections (node:internal/process/task_queues:95:5)

 FAIL  lib/validation.test.js
  ● isValidAddress › valid bech32 v1 (P2TR) address on mainnet

    expect(received).toBeTruthy()

    Received: false

      137 |   });
      138 |   test("valid bech32 v1 (P2TR) address on mainnet", function () {
    > 139 |     expect((0, _validation.isValidAddress)(_fixtures.KEY.MAIN.TAPROOT, _unchainedBitcoin.NETWORKS.MAINNET)).toBeTruthy();
          |                                                                                                             ^
      140 |   }); // TESTNET
      141 | 
      142 |   test("valid legacy (P2PKH) address on testnet", function () {

      at Object.<anonymous> (lib/validation.test.js:139:109)
      at processTicksAndRejections (node:internal/process/task_queues:95:5)

  ● isValidAddress › valid bech32 v1 (P2TR) address on mainnet

    expect(received).toBeTruthy()

    Received: false

      150 |   });
      151 |   test("valid bech32 v1 (P2TR) address on mainnet", function () {
    > 152 |     expect((0, _validation.isValidAddress)(_fixtures.KEY.TEST.TAPROOT, _unchainedBitcoin.NETWORKS.TESTNET)).toBeTruthy();
          |                                                                                                             ^
      153 |   }); // INVALID: NETWORK MISMATCH
      154 | 
      155 |   test("invalid legacy (P2PKH) address (wrong network)", function () {

      at Object.<anonymous> (lib/validation.test.js:152:109)
      at processTicksAndRejections (node:internal/process/task_queues:95:5)

 PASS  src/derivation.test.js (26.307 s)
 PASS  lib/derivation.test.js (26.561 s)

Test Suites: 2 failed, 10 passed, 12 total
Tests:       4 failed, 200 passed, 204 total
test runs on this branch
$ yarn test
yarn run v1.22.22
$ yarn run compile
$ babel -d lib/ src/
Browserslist: caniuse-lite is outdated. Please run:
npx browserslist@latest --update-db
Successfully compiled 16 files with Babel (436ms).
$ jest lib
 PASS  lib/utils.test.js
 PASS  src/utils.test.js
 PASS  lib/paths.test.js
 PASS  lib/conversion.test.js
 PASS  src/paths.test.js
 PASS  src/metadata.test.js
 PASS  src/conversion.test.js
 PASS  lib/validation.test.js
 PASS  lib/metadata.test.js
 PASS  src/validation.test.js
 PASS  lib/derivation.test.js (25.172 s)
 PASS  src/derivation.test.js (25.493 s)

Test Suites: 12 passed, 12 total
Tests:       204 passed, 204 total

@turkycat
Copy link
Contributor Author

turkycat commented Mar 5, 2025

blocked by #62

@bertonjulian
Copy link
Contributor

@turkycat as discussed, I added a bunch of changes:

  1. Removed the xpub-tool and xpub-components-bootstrap packages.
  2. Updated to Node v20.12.2
  3. Updated bitcoinjs-lib to 6.1.7 as that supports Taproot.
  4. Added tiny-secp256k1 dep as thats required for Taproot support.
  5. Added the P2TR Purpose to support creating Taproot addresses from an XPub.
  6. Added several tests to make sure P2TR address derivation was working (aka addressFromExtPubKey).

Things left to update:

  1. xpub-cli does not currently support P2TR.
  2. The getPurposeFromExtPubKey function will not work correctly for P2TR.

@turkycat
Copy link
Contributor Author

turkycat commented Mar 5, 2025

  1. The getPurposeFromExtPubKey function will not work correctly for P2TR.

This is expected as there are no extended key formats that imply taproot. I also think that concept is dead, everyone just uses xpub these days anyway

Thanks for the additions!

@turkycat turkycat changed the title upgrade to caravan from (deprecated) unchained-bitcoin, add taproot tests upgrade to caravan from (deprecated) unchained-bitcoin, add taproot support Mar 5, 2025
@turkycat turkycat requested a review from Copilot March 5, 2025 17:59
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Overview

This PR upgrades the codebase to use the Caravan library instead of the deprecated unchained-bitcoin and adds taproot (p2tr) support. Additionally, it removes various legacy React components from the xpub-components-bootstrap package.

  • Updated imports and references from unchained-bitcoin to Caravan in both library and CLI code.
  • Added taproot support by introducing a new "p2tr" derivation case and updating corresponding help texts and tests.
  • Removed deprecated bootstrap components to streamline the UI components.

Reviewed Changes

File Description
packages/xpub-lib/jest.config.js Adjusts Jest config to ignore most node_modules except for valibot
packages/xpub-cli/src/xpub.js Migrates import style and adds taproot support; renames the account-related option
packages/xpub-lib/src/conversion.test.js Updates tests to reflect the new Caravan-based imports
packages/xpub-lib/src/conversion.js Updates conversion function to use Caravan’s Network
README.md & packages/xpub-lib/README.md Updates dependency references and documentation for the new library and added taproot support
packages/xpub-components-bootstrap/* Removes several deprecated React components

Copilot reviewed 48 out of 48 changed files in this pull request and generated no comments.

Comments suppressed due to low confidence (1)

packages/xpub-cli/src/xpub.js:128

  • The network variable is reassigned later in the code even though it was declared earlier. Consider reusing the existing variable to avoid redundancy.
const network = cmdObj.testnet ? Network.TESTNET : Network.MAINNET

@turkycat
Copy link
Contributor Author

turkycat commented Mar 5, 2025

copilot's last comment is incorrect, the file contains two different programs, each declaring their own network value

@turkycat turkycat requested a review from laf-rge March 5, 2025 18:22
@turkycat turkycat force-pushed the jdf/caravan-upgrade branch from d28b536 to dec8e96 Compare March 5, 2025 18:43
return bc1Address
return bc1qAddress
}
case Purpose.P2TR: {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯

Copy link

@ramontayag ramontayag left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks ok to me, though my headspace isn't here currently so I suggest getting others to review as well

Copy link
Contributor

@bertonjulian bertonjulian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Tested the CLI against an xpub & tpub from a test Sparrow wallet and compared p2tr addresses generated. As discussed offline, we will likely remove getPurposeFromExtPubKey as it would produce incorrect results for p2tr. But that might happen in a separate PR.

@turkycat
Copy link
Contributor Author

produce incorrect results for p2tr

Sorry to nitpick, but for the PR history I want to be clear that it isn't really an incorrect result for p2tr, it's that there is no extended key format that is strongly associated with p2tr. Julian and I have agreed that this function provides little value because these x/y/z pub associations were never officially standardized and the use of the latter two never really took off. It is currently most common to see xpub usage with p2wpkh, which already breaks the suggested getPurposeFromExtPubKey.

@turkycat turkycat merged commit 727024a into master Mar 11, 2025
2 checks passed
@turkycat turkycat deleted the jdf/caravan-upgrade branch March 11, 2025 13:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants