Skip to content

Commit

Permalink
feat: bitcoin wallet utils (#546)
Browse files Browse the repository at this point in the history
<!--- Provide a general summary of your changes in the Title above -->

## Description
<!--- Describe your changes in detail -->

Currently the examples need to use a lot of code to get signer for the
two types of transactions. Since we already have some utils to fetch
UTXO's, it could useful to have some minimal wallet utils that allows
have more cleaner examples.

## Related Issue Or Context
<!--- If suggesting a new feature or change, please discuss it in an
issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps
to reproduce -->
<!--- Otherwise, describe context and motivation for change herre -->

Closes: #547 

## How Has This Been Tested? Testing details.
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran
to -->
<!--- see how your change affects other areas of the code, etc. -->

## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [X] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation

## Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes
that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->
- [ ] I have commented my code, particularly in hard-to-understand
areas.
- [ ] I have ensured that all acceptance criteria (or expected behavior)
from issue are met
- [ ] I have updated the documentation locally and in chainbridge-docs.
- [ ] I have added tests to cover my changes.
- [ ] I have ensured that all the checks are passing and green, I've
signed the CLA bot
  • Loading branch information
wainola authored Oct 9, 2024
1 parent 07323de commit f29559b
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 23 deletions.
26 changes: 14 additions & 12 deletions examples/bitcoin-to-evm-fungible-transfer/src/transfer.p2tr.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import {
createBitcoinFungibleTransfer,
TypeOfAddress,
getPublicKey,
broadcastTransaction,
fetchUTXOS,
getFeeEstimates,
processUtxos,
} from "@buildwithsygma/bitcoin";
import type { BitcoinTransferParams, UTXOData } from "@buildwithsygma/bitcoin";
import { BIP32Factory } from "bip32";
import { mnemonicToSeed } from "bip39";
import { crypto, initEccLib, networks } from "bitcoinjs-lib";
import { toXOnly } from "bitcoinjs-lib/src/psbt/bip371";
import { initEccLib, networks, Signer } from "bitcoinjs-lib";
import dotenv from "dotenv";
import * as tinysecp from "tiny-secp256k1";
import { broadcastTransaction, fetchUTXOS, getFeeEstimates, processUtxos } from '@buildwithsygma/utils'

import {
calculateSize,
Expand Down Expand Up @@ -51,15 +53,15 @@ async function btcToEvmTransfer(): Promise<void> {
initEccLib(tinysecp);
const bip32 = BIP32Factory(tinysecp);
console.log("Transfer BTC to EVM");
const seed = await mnemonicToSeed(MNEMONIC);
const rootKey = bip32.fromSeed(seed, networks.testnet);
const derivedNode = rootKey.derivePath(DERIVATION_PATH);

const publicKeyDropedDERHeader = toXOnly(derivedNode.publicKey);

const tweakedSigner = derivedNode.tweak(
crypto.taggedHash("TapTweak", publicKeyDropedDERHeader),
);
const { tweakedSigner, publicKeyDropedDERHeader } = await getPublicKey({
bip32,
mnemonic: MNEMONIC as string,
derivationPath: DERIVATION_PATH as string,
network: networks.testnet,
typeOfAddress: TypeOfAddress.P2TR
}
) as { publicKeyDropedDERHeader: Buffer, tweakedSigner: Signer };

const feeRate = await getFeeEstimates('5');
const utxos = await fetchUTXOS(
Expand Down
21 changes: 15 additions & 6 deletions examples/bitcoin-to-evm-fungible-transfer/src/transfer.p2wpkh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ import type { BitcoinTransferParams, UTXOData } from "@buildwithsygma/bitcoin";
import {
createBitcoinFungibleTransfer,
TypeOfAddress,
getPublicKey,
getFeeEstimates,
fetchUTXOS,
processUtxos,
broadcastTransaction
} from "@buildwithsygma/bitcoin";
import { BIP32Factory } from "bip32";
import { mnemonicToSeed } from "bip39";
import { BIP32Factory, BIP32Interface } from "bip32";
import { initEccLib, networks } from "bitcoinjs-lib";
import dotenv from "dotenv";
import * as tinysecp from "tiny-secp256k1";

import {
calculateSize,
} from "./blockstreamApi.js";
import { broadcastTransaction, fetchUTXOS, getFeeEstimates, processUtxos } from "@buildwithsygma/utils";

dotenv.config();

Expand Down Expand Up @@ -49,9 +52,15 @@ async function btcToEvmTransfer(): Promise<void> {
initEccLib(tinysecp);
const bip32 = BIP32Factory(tinysecp);
console.log("Transfer BTC to EVM");
const seed = await mnemonicToSeed(MNEMONIC);
const rootKey = bip32.fromSeed(seed, networks.testnet);
const derivedNode = rootKey.derivePath(DERIVATION_PATH);

const { derivedNode } = await getPublicKey({
bip32,
mnemonic: MNEMONIC as string,
derivationPath: DERIVATION_PATH as string,
network: networks.testnet,
typeOfAddress: TypeOfAddress.P2WPKH
}
) as { derivedNode: BIP32Interface };

const feeRate = await getFeeEstimates('5');
const utxos = await fetchUTXOS(ADDRESS as unknown as string);
Expand Down
2 changes: 2 additions & 0 deletions packages/bitcoin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@
},
"dependencies": {
"@buildwithsygma/core": "workspace:^",
"bip32": "4.0.0",
"bip39": "3.1.0",
"bitcoinjs-lib": "^6.1.6"
}
}
43 changes: 43 additions & 0 deletions packages/bitcoin/src/__test__/getPublicKey.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import type { BIP32Interface } from 'bip32';
import { BIP32Factory } from 'bip32';
import * as bip39 from 'bip39';
import * as bitcoinjs from 'bitcoinjs-lib';
import * as tinysecp from 'tiny-secp256k1';

import { TypeOfAddress } from '../types.js';
import { getPublicKey } from '../utils/wallet.js';

bitcoinjs.initEccLib(tinysecp);

describe('getPublicKey', () => {
const bip32 = BIP32Factory(tinysecp);

it('should return derivedNode for non-P2TR addresses', async () => {
const p2wpkhDerivationPath = "m/84'/0'/0'/0/0";
const mnemonic = bip39.generateMnemonic(256);
const result = (await getPublicKey({
bip32,
mnemonic: mnemonic,
derivationPath: p2wpkhDerivationPath,
network: bitcoinjs.networks.testnet,
typeOfAddress: TypeOfAddress.P2WPKH,
})) as { derivedNode: BIP32Interface };

expect(result.derivedNode).toBeDefined();
});

it('should return tweakedSigner and publicKeyDropedDERHeader for P2TR addresses', async () => {
const p2trDerivationPath = "m/86'/0'/0'/0/0";
const mnemonic = bip39.generateMnemonic(256);
const result = (await getPublicKey({
bip32,
mnemonic: mnemonic,
derivationPath: p2trDerivationPath,
network: bitcoinjs.networks.testnet,
typeOfAddress: TypeOfAddress.P2TR,
})) as unknown as { tweakedSigner: Buffer; publicKeyDropedDERHeader: Buffer };

expect(result.tweakedSigner).toBeDefined();
expect(result.publicKeyDropedDERHeader).toBeDefined();
});
});
15 changes: 14 additions & 1 deletion packages/bitcoin/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { BaseTransferParams } from '@buildwithsygma/core';
import type { networks, Psbt } from 'bitcoinjs-lib';
import type { BIP32API, BIP32Interface } from 'bip32';
import type { Network, networks, Psbt, Signer } from 'bitcoinjs-lib';

export enum TypeOfAddress {
P2WPKH = 'P2WPKH',
Expand Down Expand Up @@ -60,3 +61,15 @@ export type BitcoinTransferInputData = {
witnessUtxo: { value: number; script: Buffer };
tapInternalKey?: Buffer;
};

export type PublicKeyParams = {
bip32: BIP32API;
mnemonic: string;
derivationPath: string;
network: Network;
typeOfAddress: TypeOfAddress;
};

export type GetPublicKeyResult =
| { tweakedSigner: Signer; publicKeyDropedDERHeader: Buffer }
| { derivedNode: BIP32Interface };
File renamed without changes.
36 changes: 36 additions & 0 deletions packages/bitcoin/src/utils/wallet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { mnemonicToSeed } from 'bip39';
import { crypto } from 'bitcoinjs-lib';
import { toXOnly } from 'bitcoinjs-lib/src/psbt/bip371';

import { TypeOfAddress } from '../types.js';
import type { GetPublicKeyResult, PublicKeyParams } from '../types.js';

/**
* @category Bitcoin Wallet Helpers
* @description Return either tweakedSigner and publicKeyDropedDERHeader or derivedNode to sign a transaction
* @param {PublicKeyParams} - bip32, mnemonic, derivationPath, network, typeOfAddress
* @returns {Promise<GetPublicKeyResult>}
*/
export const getPublicKey = async ({
bip32,
mnemonic,
derivationPath,
network,
typeOfAddress,
}: PublicKeyParams): Promise<GetPublicKeyResult> => {
const seed = await mnemonicToSeed(mnemonic);
const rootKey = bip32.fromSeed(seed, network);
const derivedNode = rootKey.derivePath(derivationPath);

if (typeOfAddress === TypeOfAddress.P2TR) {
const publicKeyDropedDERHeader = toXOnly(derivedNode.publicKey);

const tweakedSigner = derivedNode.tweak(
crypto.taggedHash('TapTweak', publicKeyDropedDERHeader),
);

return { tweakedSigner, publicKeyDropedDERHeader };
}

return { derivedNode };
};
1 change: 1 addition & 0 deletions packages/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"typescript": "5.0.4"
},
"dependencies": {
"@buildwithsygma/bitcoin": "workspace:^",
"@buildwithsygma/core": "workspace:^",
"@buildwithsygma/evm": "workspace:^",
"@buildwithsygma/substrate": "workspace:^",
Expand Down
1 change: 0 additions & 1 deletion packages/utils/src/bitcoin/index.ts

This file was deleted.

1 change: 0 additions & 1 deletion packages/utils/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export * from './liquidity.js';
export * from './bitcoin/index.js';
7 changes: 5 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,8 @@ __metadata:
dependencies:
"@buildwithsygma/core": "workspace:^"
"@types/jest": "npm:^29.4.0"
bip32: "npm:4.0.0"
bip39: "npm:3.1.0"
bitcoinjs-lib: "npm:^6.1.6"
concurrently: "npm:7.0.0"
eslint: "npm:8"
Expand Down Expand Up @@ -703,6 +705,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@buildwithsygma/utils@workspace:packages/utils"
dependencies:
"@buildwithsygma/bitcoin": "workspace:^"
"@buildwithsygma/core": "workspace:^"
"@buildwithsygma/evm": "workspace:^"
"@buildwithsygma/substrate": "workspace:^"
Expand Down Expand Up @@ -4213,7 +4216,7 @@ __metadata:
languageName: node
linkType: hard

"bip32@npm:^4.0.0":
"bip32@npm:4.0.0, bip32@npm:^4.0.0":
version: 4.0.0
resolution: "bip32@npm:4.0.0"
dependencies:
Expand All @@ -4225,7 +4228,7 @@ __metadata:
languageName: node
linkType: hard

"bip39@npm:^3.1.0":
"bip39@npm:3.1.0, bip39@npm:^3.1.0":
version: 3.1.0
resolution: "bip39@npm:3.1.0"
dependencies:
Expand Down

0 comments on commit f29559b

Please sign in to comment.