From 40465df54e7e80098e62a41aac49912c3c1ff819 Mon Sep 17 00:00:00 2001 From: Otto Allmendinger Date: Tue, 7 Jan 2025 18:03:19 +0100 Subject: [PATCH] feat: add example for createDescriptorWalletWithWalletPassphrase Issue: BTC-0 --- examples/ts/create-descriptor-wallet.ts | 79 +++++++++++++++++++ .../src/descriptor/NamedDescriptor.ts | 5 +- modules/abstract-utxo/src/descriptor/index.ts | 2 +- 3 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 examples/ts/create-descriptor-wallet.ts diff --git a/examples/ts/create-descriptor-wallet.ts b/examples/ts/create-descriptor-wallet.ts new file mode 100644 index 0000000000..4cd8f9f5fd --- /dev/null +++ b/examples/ts/create-descriptor-wallet.ts @@ -0,0 +1,79 @@ +/** + * Create a multi-sig wallet at BitGo. + * This makes use of the convenience function generateWallet + * + * This tool will help you see how to use the BitGo API to easily create a wallet. + * In this form, it creates 2 keys on the host which runs this example. + * It is HIGHLY RECOMMENDED that you GENERATE THE KEYS ON SEPARATE MACHINES for real money wallets! + * + * To perform more advanced features, such as encrypting keys yourself, please look at createWalletAdvanced.js + * + * Copyright 2022, BitGo, Inc. All Rights Reserved. + */ + +/** + * Add Low Fee webhook to a wallet. + * + * Copyright 2022 BitGo, Inc. All Rights Reserved. + */ + +import { BitGoAPI } from '@bitgo/sdk-api'; +import { Tbtc } from '@bitgo/sdk-coin-btc'; // Replace with your given coin (e.g. Ltc, Tltc) +import { AbstractUtxoCoin, descriptor } from '@bitgo/abstract-utxo'; +require('dotenv').config({ path: '../../.env' }); + +const bitgo = new BitGoAPI({ + accessToken: process.env.TESTNET_ACCESS_TOKEN, + env: 'test', // Change this to env: 'production' when you are ready for production +}); + +// Set the coin name to match the blockchain and network +// btc = bitcoin, tbtc = testnet bitcoin +const coin = 'tbtc'; +bitgo.register(coin, Tbtc.createInstance); + +// TODO: set a label for your new wallet here +const label = 'Example Descriptor Wallet'; + +// TODO: set your passphrase for your new wallet here +const passphrase = 'test_wallet_passphrase'; + +// TODO: set your enterprise ID for your new wallet here +const enterprise = 'your_enterprise_id'; + +async function main() { + console.log( + // this wrapper creates three keys: userKey, backupKey, and bitgoKey + // at the moment, this is a somewhat artificial requirement from wallet platform + // in the future, we will allow for more flexible key generation + await descriptor.createWallet.createDescriptorWalletWithWalletPassphrase( + bitgo, + bitgo.coin(coin) as AbstractUtxoCoin, + { + label, + walletPassphrase: passphrase, + enterprise, + descriptorsFromKeys(userKey, cosigners) { + // userKey is backed up at BitGo with the wallet passphrase + // cosigners are backup key and BitGo key + const xpubs = [userKey, ...cosigners].map((key) => key.neutered().toBase58()); + + return [ + // here is a single-sig descriptor for the user key + descriptor.createNamedDescriptorWithSignature('SingleSigWpkh', `wpkh(${xpubs[0]}/*)`, userKey), + // here is a 2of3 multisig descriptor for the backup key and BitGo key + descriptor.createNamedDescriptorWithSignature( + 'MultiSigWsh', + `wsh(multi(2,${xpubs.map((xpub) => `${xpub}/*`).join(',')})`, + userKey + ), + // equivalent to the above, but returns two descriptors (external and internal) + ...descriptor.createWallet.DefaultWsh2Of3(userKey, cosigners), + ]; + }, + } + ) + ); +} + +main().catch((e) => console.log(e)); diff --git a/modules/abstract-utxo/src/descriptor/NamedDescriptor.ts b/modules/abstract-utxo/src/descriptor/NamedDescriptor.ts index 7dcd661669..0c3fbbb2b3 100644 --- a/modules/abstract-utxo/src/descriptor/NamedDescriptor.ts +++ b/modules/abstract-utxo/src/descriptor/NamedDescriptor.ts @@ -24,9 +24,12 @@ export type NamedDescriptor = { export function createNamedDescriptorWithSignature( name: string, - descriptor: Descriptor, + descriptor: string | Descriptor, signingKey: BIP32Interface ): NamedDescriptor { + if (typeof descriptor === 'string') { + descriptor = Descriptor.fromString(descriptor, 'derivable'); + } const value = descriptor.toString(); const signature = signMessage(value, signingKey, networks.bitcoin).toString('hex'); return { name, value, signatures: [signature] }; diff --git a/modules/abstract-utxo/src/descriptor/index.ts b/modules/abstract-utxo/src/descriptor/index.ts index 8e9ebf7ea4..539df3632d 100644 --- a/modules/abstract-utxo/src/descriptor/index.ts +++ b/modules/abstract-utxo/src/descriptor/index.ts @@ -1,6 +1,6 @@ export { Miniscript, Descriptor } from '@bitgo/wasm-miniscript'; export { assertDescriptorWalletAddress } from './assertDescriptorWalletAddress'; -export { NamedDescriptor } from './NamedDescriptor'; +export { NamedDescriptor, createNamedDescriptorWithSignature, hasValidSignature } from './NamedDescriptor'; export { isDescriptorWallet, getDescriptorMapFromWallet } from './descriptorWallet'; export { getPolicyForEnv } from './validatePolicy'; export * as createWallet from './createWallet';