Skip to content

Commit

Permalink
wip: working taproot multisig policy
Browse files Browse the repository at this point in the history
  • Loading branch information
Polybius93 committed May 6, 2024
1 parent 57be0bf commit 745e726
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 45 deletions.
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { BitGoAddress } from './models.js';
import { getNativeSegwitPublicKeys, getTaprootMultisigScript, getTaprootPublicKeys } from './payment-functions.js';
import { bitcoinToSats } from './utilities.js';
import { testLedger } from './ledger_test.js';
import { getScripts } from './ledger.js';
import { createScripts, getScripts } from './ledger.js';

dotenv.config();

Expand Down
57 changes: 29 additions & 28 deletions src/ledger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,42 +29,43 @@ const TEST_MASTER_FINGERPRINT = 'd34db33f';

// const TAPROOT_UNSPENDABLE_KEY_STRING = '50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0';

// export function createScripts(): {
// nativeSegwitPublicKey: Buffer;
// nativeSegwitScript: Payment;
// taprootPublicKey: Buffer;
// taprootScript: Payment;
// } {
// const bitcoinNetwork = testnet;

// const seedBytes = randomBytes(32);
// console.log('Seed Bytes:', bytesToHex(seedBytes));
export function createScripts(): {
nativeSegwitPublicKey: Buffer;
nativeSegwitScript: Payment;
taprootPublicKey: Buffer;
taprootScript: Payment;
} {
const bitcoinNetwork = testnet;

// const node = bip32.fromSeed(Buffer.from(seedBytes), bitcoinNetwork);
const seedBytes = randomBytes(32);
console.log('Seed Bytes:', bytesToHex(seedBytes));

// const extendedPrivateKey = node.toBase58();
// console.log('Extended private key:', extendedPrivateKey);
const node = bip32.fromSeed(Buffer.from(seedBytes), bitcoinNetwork);
const masterFingerPrint = node.fingerprint.toString('hex');
console.log('Master Fingerprint', masterFingerPrint);
const extendedPrivateKey = node.toBase58();
console.log('Extended private key:', extendedPrivateKey);

// const extendedPublicKey = node.neutered().toBase58();
// console.log('Extended public key:', extendedPublicKey);
const extendedPublicKey = node.neutered().toBase58();
console.log('Extended public key:', extendedPublicKey);

// const nativeSegwitPublicKey = node.derivePath("m/48'/1'/0'/2'").publicKey;
// console.log('derivation path:', "m/48'/1'/0'/2'");
// console.log('Native Segwit Public key:', bytesToHex(nativeSegwitPublicKey));
const nativeSegwitPublicKey = node.derivePath("m/48'/1'/0'/2'").publicKey;
console.log('derivation path:', "m/48'/1'/0'/2'");
console.log('Native Segwit Public key:', bytesToHex(nativeSegwitPublicKey));

// const nativeSegwitScript = p2wpkh({ pubkey: nativeSegwitPublicKey, network: bitcoinNetwork });
// console.log('Native Segwit Script:', nativeSegwitScript.address);
const nativeSegwitScript = p2wpkh({ pubkey: nativeSegwitPublicKey, network: bitcoinNetwork });
console.log('Native Segwit Script:', nativeSegwitScript.address);

// const taprootPublicKey = node.derivePath("m/48'/1'/0'/2").publicKey;
// const childNode = node.derivePath("48'/1'/0'/2");
// console.log('derivation path:', "m/48'/1'/0'/2");
// console.log('Taproot Public key:', bytesToHex(taprootPublicKey));
const taprootPublicKey = node.derivePath("m/48'/1'/0'/2").publicKey;
const childNode = node.derivePath("48'/1'/0'/2");
console.log('derivation path:', "m/48'/1'/0'/2");
console.log('Taproot Public key:', bytesToHex(taprootPublicKey));

// const taprootScript = p2tr({ pubkey: taprootPublicKey.subarray(1), network: bitcoinNetwork });
// console.log('Taproot Script:', taprootScript.address);
const taprootScript = p2tr({ pubkey: taprootPublicKey.subarray(1), network: bitcoinNetwork });
console.log('Taproot Script:', taprootScript.address);

// return { nativeSegwitPublicKey, nativeSegwitScript, taprootPublicKey, taprootScript };
// }
return { nativeSegwitPublicKey, nativeSegwitScript, taprootPublicKey, taprootScript };
}

export function getScripts(): {
masterFingerPrint: string;
Expand Down
43 changes: 27 additions & 16 deletions src/ledger_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ const TEST_EXTENDED_PUBLIC_KEY =
const TEST_MASTER_FINGERPRINT = '8400dc04';
const TAPROOT_UNSPENDABLE_KEY_STRING = '50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0';

const TEST_EXTENDED_PRIVATE_KEY_2 =
'tprv8ZgxMBicQKsPfJ6T1H5ErNLa1fZyj2fxCR7vRqVokCLvWg9JypYJoGVdvU6UNkj59o6qDdB97QFk7CQa2XnKZGSzQGhfoc4hCGXrviFuxwP';
const TEST_EXTENDED_PUBLIC_KEY_2 =
'tpubD6NzVbkrYhZ4Ym8EtvjqFmzgah5utMrrmiihiMY7AU9KMAQ5cDMtym7W6ccSUinTVbDqK1Vno96HNhaqhS1DuVCrjHoFG9bFa3DKUUMErCv';
const TEST_MASTER_FINGERPRINT_2 = 'b2cd3e18';

initEccLib(ecc);
const bip32 = BIP32Factory(ecc);

Expand All @@ -29,35 +35,40 @@ export async function main(transport: any) {
const fpr = await ledgerApp.getMasterFingerprint();

// ==> Register Taproot Multisig Wallet ##########################################################
const derivationPath = "86'/1'/0'/0/0";
const derivationPath = "86'/1'/0'";

// ==> Get Ledger Derived Public Key
const ledgerExtendedPublicKey = await ledgerApp.getExtendedPubkey(`m/${derivationPath}`);
const ledgerDerivedPublicKey = bip32
.fromBase58(ledgerExtendedPublicKey, testnet)
.publicKey.subarray(1)
.toString('hex');
console.log(`[Ledger][${bitcoinNetworkName}] Ledger Derived Public Key: ${ledgerDerivedPublicKey}`);

// ==> Get External Derived Public Key
const externalDerivedPublicKey = bip32

console.log(`[Ledger][${bitcoinNetworkName}] Ledger Extended Public Key: ${ledgerExtendedPublicKey}`);

// ==> Get External Derived Public Keys
const externalExtendedPublicKey1 = bip32
.fromBase58(TEST_EXTENDED_PRIVATE_KEY, testnet)
.derivePath(`m/${derivationPath}`)
.neutered()
.publicKey.toString('hex');
.toBase58();

const externalExtendedPublicKey2 = bip32
.fromBase58(TEST_EXTENDED_PRIVATE_KEY_2, testnet)
.derivePath(`m/${derivationPath}`)
.neutered()
.toBase58();

console.log(`[Ledger][${bitcoinNetworkName}] External Derived Public Key: ${externalDerivedPublicKey}`);
console.log(`[Ledger][${bitcoinNetworkName}] External Extended Public Key: ${externalExtendedPublicKey1}`);
console.log(`[Ledger][${bitcoinNetworkName}] External Extended Public Key: ${externalExtendedPublicKey2}`);

// ==> Create Key Info
const ledgerKeyInfo = `[${fpr}/${derivationPath}]${ledgerExtendedPublicKey}`;
const externalKeyInfo = `[${TEST_MASTER_FINGERPRINT}/${derivationPath}]${externalDerivedPublicKey}`;
const externalKeyInfo1 = `[${TEST_MASTER_FINGERPRINT}/${derivationPath}]${externalExtendedPublicKey1}`;
const externalKeyInfo2 = `[${TEST_MASTER_FINGERPRINT_2}/${derivationPath}]${externalExtendedPublicKey2}`;

// ==> Create Multisig Wallet Policy
// I tried with both the keyInfo as you suggested in the example, and with the actual key, but it didn't work.
const multisigPolicy = new WalletPolicy('Multisig Taproot Wallet', `tr(@0,and_v(v:pk(@1),pk(@2)))`, [
TAPROOT_UNSPENDABLE_KEY_STRING,
externalDerivedPublicKey,
ledgerDerivedPublicKey,
const multisigPolicy = new WalletPolicy('Multisig Taproot Wallet', `tr(@0/**,and_v(v:pk(@1/**),pk(@2/**)))`, [
externalKeyInfo1,
externalKeyInfo2,
ledgerKeyInfo,
]);

// ==> Register Wallet
Expand Down

0 comments on commit 745e726

Please sign in to comment.