Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove bcoin completely #707

Merged
merged 12 commits into from
Oct 6, 2023
Merged
7 changes: 1 addition & 6 deletions typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
"test": "mocha --exit --recursive 'test/**/*.test.ts'",
"typechain": "rm -rf ./typechain && for i in $npm_package_config_contracts; do typechain --target ethers-v5 --out-dir ./typechain $i; done && rm ./typechain/index.ts",
"build": "npm run typechain && tsc --project tsconfig.build.json",
"dev": "tsc --project tsconfig.build.json --watch",
"postinstall": "npm rebuild bcrypto"
"dev": "tsc --project tsconfig.build.json --watch"
},
"files": [
"dist/",
Expand All @@ -27,7 +26,6 @@
"dependencies": {
"@keep-network/ecdsa": "development",
"@keep-network/tbtc-v2": "development",
"bcoin": "git+https://github.com/keep-network/bcoin.git#5accd32c63e6025a0d35d67739c4a6e84095a1f8",
"bitcoinjs-lib": "6.0.2",
"bufio": "^1.0.6",
"ecpair": "^2.1.0",
Expand Down Expand Up @@ -61,8 +59,5 @@
},
"engines": {
"node": ">=14 <15"
},
"browser": {
"bcoin": "bcoin/lib/bcoin-browser"
}
}
21 changes: 0 additions & 21 deletions typescript/src/bitcoin-network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,27 +45,6 @@ export namespace BitcoinNetwork {
}
}

/**
* Converts enumerated {@link BitcoinNetwork} to a string expected by the
* {@link https://github.com/keep-network/bcoin/blob/aba6841e43546e8a485e96dc0019d1e788eab2ee/lib/protocol/networks.js#L33| `bcoin` library}
* @param bitcoinNetwork Bitcoin network.
* @returns String representing the given network in bcoin library.
* @throws An error if the network is not supported by bcoin.
*/
export function toBcoinNetwork(bitcoinNetwork: BitcoinNetwork): string {
switch (bitcoinNetwork) {
case BitcoinNetwork.Mainnet: {
return "main"
}
case BitcoinNetwork.Testnet: {
return "testnet"
}
default: {
throw new Error(`network not supported`)
}
}
}

/**
* Converts the provided {@link BitcoinNetwork} enumeration to a format expected
* by the `bitcoinjs-lib` library.
Expand Down
141 changes: 71 additions & 70 deletions typescript/src/bitcoin.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
import bcoin, { TX, Script } from "bcoin"
import wif from "wif"
import bufio from "bufio"
import { BigNumber, utils } from "ethers"
import { Hex } from "./hex"
import {
BitcoinNetwork,
toBcoinNetwork,
toBitcoinJsLibNetwork,
} from "./bitcoin-network"
import { payments } from "bitcoinjs-lib"
import { BitcoinNetwork, toBitcoinJsLibNetwork } from "./bitcoin-network"
import { Transaction as Tx, address, payments } from "bitcoinjs-lib"

/**
* Represents a transaction hash (or transaction ID) as an un-prefixed hex
Expand Down Expand Up @@ -412,46 +406,53 @@ export interface Client {
export function decomposeRawTransaction(
rawTransaction: RawTransaction
): DecomposedRawTransaction {
const toHex = (bufferWriter: any) => {
lukasz-zimnoch marked this conversation as resolved.
Show resolved Hide resolved
const toHex = (bufferWriter: any): string => {
return bufferWriter.render().toString("hex")
}

const vectorToRaw = (elements: any[]) => {
const getTxInputVector = (tx: Tx): string => {
const buffer = bufio.write()
buffer.writeVarint(elements.length)
for (const element of elements) {
element.toWriter(buffer)
}
buffer.writeVarint(tx.ins.length)
tx.ins.forEach((input) => {
buffer.writeHash(input.hash)
buffer.writeU32(input.index)
lukasz-zimnoch marked this conversation as resolved.
Show resolved Hide resolved
buffer.writeVarBytes(input.script)
lukasz-zimnoch marked this conversation as resolved.
Show resolved Hide resolved
lukasz-zimnoch marked this conversation as resolved.
Show resolved Hide resolved
buffer.writeU32(input.sequence)
})
return toHex(buffer)
}

const getTxInputVector = (tx: any) => {
return vectorToRaw(tx.inputs)
}

const getTxOutputVector = (tx: any) => {
return vectorToRaw(tx.outputs)
const getTxOutputVector = (tx: Tx): string => {
const buffer = bufio.write()
buffer.writeVarint(tx.outs.length)
tx.outs.forEach((output) => {
buffer.writeI64(output.value)
buffer.writeVarBytes(output.script)
})
return toHex(buffer)
}

const getTxVersion = (tx: any) => {
const getTxVersion = (tx: Tx): string => {
const buffer = bufio.write()
buffer.writeU32(tx.version)
return toHex(buffer)
}

const getTxLocktime = (tx: any) => {
const getTxLocktime = (tx: Tx): string => {
const buffer = bufio.write()
buffer.writeU32(tx.locktime)
return toHex(buffer)
}

const tx = TX.fromRaw(Buffer.from(rawTransaction.transactionHex, "hex"), null)
const transaction = Tx.fromBuffer(
Buffer.from(rawTransaction.transactionHex, "hex")
)

return {
version: getTxVersion(tx),
inputs: getTxInputVector(tx),
outputs: getTxOutputVector(tx),
locktime: getTxLocktime(tx),
version: getTxVersion(transaction),
inputs: getTxInputVector(transaction),
outputs: getTxOutputVector(transaction),
locktime: getTxLocktime(transaction),
}
}

Expand Down Expand Up @@ -502,26 +503,6 @@ export function compressPublicKey(publicKey: string | Hex): string {
return `${prefix}${publicKeyX}`
}

/**
* Creates a Bitcoin key ring based on the given private key.
* @param privateKey Private key that should be used to create the key ring
* @param witness Flag indicating whether the key ring will create witness
* or non-witness addresses
* @returns Bitcoin key ring.
*/
export function createKeyRing(
privateKey: string,
witness: boolean = true
): any {
const decodedPrivateKey = wif.decode(privateKey)

return new bcoin.KeyRing({
witness: witness,
privateKey: decodedPrivateKey.privateKey,
compressed: decodedPrivateKey.compressed,
})
}

/**
* Computes the HASH160 for the given text.
* @param text - Text the HASH160 is computed for.
Expand Down Expand Up @@ -573,39 +554,49 @@ export function hashLEToBigNumber(hash: Hex): BigNumber {
* unprefixed hex string (without 0x prefix).
* @param witness - If true, a witness public key hash will be encoded and
* P2WPKH address will be returned. Returns P2PKH address otherwise
* @param network - Network the address should be encoded for.
* @param bitcoinNetwork - Network the address should be encoded for.
* @returns P2PKH or P2WPKH address encoded from the given public key hash
* @throws Throws an error if network is not supported.
*/
export function encodeToBitcoinAddress(
publicKeyHash: string,
witness: boolean,
network: BitcoinNetwork
bitcoinNetwork: BitcoinNetwork
): string {
const buffer = Buffer.from(publicKeyHash, "hex")
const bcoinNetwork = toBcoinNetwork(network)
const hash = Buffer.from(publicKeyHash, "hex")
const network = toBitcoinJsLibNetwork(bitcoinNetwork)
return witness
? bcoin.Address.fromWitnessPubkeyhash(buffer).toString(bcoinNetwork)
: bcoin.Address.fromPubkeyhash(buffer).toString(bcoinNetwork)
? payments.p2wpkh({ hash, network }).address!
: payments.p2pkh({ hash, network }).address!
}

/**
* Decodes P2PKH or P2WPKH address into a public key hash. Throws if the
* provided address is not PKH-based.
* @param address - P2PKH or P2WPKH address that will be decoded.
* @param bitcoinAddress - P2PKH or P2WPKH address that will be decoded.
* @param bitcoinNetwork - Bitcoin network.
* @returns Public key hash decoded from the address. This will be an unprefixed
* hex string (without 0x prefix).
*/
export function decodeBitcoinAddress(address: string): string {
const addressObject = new bcoin.Address(address)
export function decodeBitcoinAddress(
bitcoinAddress: string,
bitcoinNetwork: BitcoinNetwork
tomaszslabon marked this conversation as resolved.
Show resolved Hide resolved
): string {
const network = toBitcoinJsLibNetwork(bitcoinNetwork)

const isPKH =
addressObject.isPubkeyhash() || addressObject.isWitnessPubkeyhash()
if (!isPKH) {
throw new Error("Address must be P2PKH or P2WPKH")
}
try {
// Try extracting hash from P2PKH address.
const hash = payments.p2pkh({ address: bitcoinAddress, network }).hash!
return hash.toString("hex")
} catch (err) {}

return addressObject.getHash("hex")
try {
// Try extracting hash from P2WPKH address.
const hash = payments.p2wpkh({ address: bitcoinAddress, network }).hash!
return hash.toString("hex")
} catch (err) {}

throw new Error("Address must be P2PKH or P2WPKH valid for given network")
}

/**
Expand Down Expand Up @@ -637,26 +628,36 @@ export function locktimeToNumber(locktimeLE: Buffer | string): number {

/**
* Creates the output script from the BTC address.
* @param address BTC address.
* @param bitcoinAddress Bitcoin address.
* @param bitcoinNetwork Bitcoin network.
* @returns The un-prefixed and not prepended with length output script.
*/
export function createOutputScriptFromAddress(address: string): Hex {
return Hex.from(Script.fromAddress(address).toRaw().toString("hex"))
export function createOutputScriptFromAddress(
bitcoinAddress: string,
bitcoinNetwork: BitcoinNetwork
tomaszslabon marked this conversation as resolved.
Show resolved Hide resolved
): Hex {
return Hex.from(
address.toOutputScript(
bitcoinAddress,
toBitcoinJsLibNetwork(bitcoinNetwork)
)
)
}

/**
* Creates the Bitcoin address from the output script.
* @param script The unprefixed and not prepended with length output script.
* @param network Bitcoin network.
* @param bitcoinNetwork Bitcoin network.
* @returns The Bitcoin address.
*/
export function createAddressFromOutputScript(
script: Hex,
network: BitcoinNetwork = BitcoinNetwork.Mainnet
bitcoinNetwork: BitcoinNetwork = BitcoinNetwork.Mainnet
): string {
return Script.fromRaw(script.toString(), "hex")
.getAddress()
?.toString(toBcoinNetwork(network))
return address.fromOutputScript(
script.toBuffer(),
toBitcoinJsLibNetwork(bitcoinNetwork)
)
}

/**
Expand Down
5 changes: 4 additions & 1 deletion typescript/src/deposit-refund.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,10 @@ export async function assembleDepositRefundTransaction(
utxo.outputIndex
)

const outputScript = createOutputScriptFromAddress(refunderAddress)
const outputScript = createOutputScriptFromAddress(
refunderAddress,
bitcoinNetwork
)
transaction.addOutput(outputScript.toBuffer(), outputValue.toNumber())

// In order to be able to spend the UTXO being refunded the transaction's
Expand Down
5 changes: 4 additions & 1 deletion typescript/src/deposit-sweep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,10 @@ export async function assembleDepositSweepTransaction(
}
outputValue = outputValue.sub(fee)

const outputScript = createOutputScriptFromAddress(walletAddress)
const outputScript = createOutputScriptFromAddress(
walletAddress,
bitcoinNetwork
)
transaction.addOutput(outputScript.toBuffer(), outputValue.toNumber())

// Sign the main UTXO input if there is main UTXO.
Expand Down
Loading