Skip to content

Commit

Permalink
Integrate bitcoinjs-lib changes around deposit sweeps
Browse files Browse the repository at this point in the history
Here we pull changes from #700
  • Loading branch information
lukasz-zimnoch committed Oct 10, 2023
1 parent 66cbee1 commit 1b21713
Show file tree
Hide file tree
Showing 10 changed files with 551 additions and 243 deletions.
33 changes: 32 additions & 1 deletion typescript/src/lib/bitcoin/address.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,36 @@
import bcoin, { Script } from "bcoin"
import { Hex } from "../utils"
import { BitcoinNetwork, toBcoinNetwork } from "./network"
import {
BitcoinNetwork,
toBcoinNetwork,
toBitcoinJsLibNetwork,
} from "./network"
import { payments } from "bitcoinjs-lib"

/**
* Creates the Bitcoin address from the public key. Supports SegWit (P2WPKH) and
* Legacy (P2PKH) formats.
* @param publicKey - Public key used to derive the Bitcoin address.
* @param bitcoinNetwork - Target Bitcoin network.
* @param witness - Flag to determine address format: true for SegWit (P2WPKH)
* and false for Legacy (P2PKH). Default is true.
* @returns The derived Bitcoin address.
*/
export function publicKeyToAddress(
publicKey: Hex,
bitcoinNetwork: BitcoinNetwork,
witness: boolean = true
): string {
const network = toBitcoinJsLibNetwork(bitcoinNetwork)

if (witness) {
// P2WPKH (SegWit)
return payments.p2wpkh({ pubkey: publicKey.toBuffer(), network }).address!
} else {
// P2PKH (Legacy)
return payments.p2pkh({ pubkey: publicKey.toBuffer(), network }).address!
}
}

/**
* Converts a public key hash into a P2PKH/P2WPKH address.
Expand Down Expand Up @@ -71,6 +101,7 @@ function outputScriptToAddress(
* Utility functions allowing to perform Bitcoin address conversions.
*/
export const BitcoinAddressConverter = {
publicKeyToAddress,
publicKeyHashToAddress,
addressToPublicKeyHash,
addressToOutputScript,
Expand Down
1 change: 1 addition & 0 deletions typescript/src/lib/bitcoin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ export * from "./ecdsa-key"
export * from "./hash"
export * from "./header"
export * from "./network"
export * from "./script"
export * from "./spv"
export * from "./tx"
24 changes: 24 additions & 0 deletions typescript/src/lib/bitcoin/network.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Hex } from "../utils"
import { networks } from "bitcoinjs-lib"

/**
* Bitcoin networks.
Expand Down Expand Up @@ -64,3 +65,26 @@ export function toBcoinNetwork(bitcoinNetwork: BitcoinNetwork): string {
}
}
}

/**
* Converts the provided {@link BitcoinNetwork} enumeration to a format expected
* by the `bitcoinjs-lib` library.
* @param bitcoinNetwork - Specified Bitcoin network.
* @returns Network representation compatible with the `bitcoinjs-lib` library.
* @throws An error if the network is not supported by `bitcoinjs-lib`.
*/
export function toBitcoinJsLibNetwork(
bitcoinNetwork: BitcoinNetwork
): networks.Network {
switch (bitcoinNetwork) {
case BitcoinNetwork.Mainnet: {
return networks.bitcoin
}
case BitcoinNetwork.Testnet: {
return networks.testnet
}
default: {
throw new Error(`network not supported`)
}
}
}
67 changes: 67 additions & 0 deletions typescript/src/lib/bitcoin/script.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { payments } from "bitcoinjs-lib"

/**
* Checks if the provided script comes from a P2PKH input.
* @param script The script to be checked.
* @returns True if the script is P2PKH, false otherwise.
*/
function isP2PKHScript(script: Buffer): boolean {
try {
payments.p2pkh({ output: script })
return true
} catch (err) {
return false
}
}

/**
* Checks if the provided script comes from a P2WPKH input.
* @param script The script to be checked.
* @returns True if the script is P2WPKH, false otherwise.
*/
function isP2WPKHScript(script: Buffer): boolean {
try {
payments.p2wpkh({ output: script })
return true
} catch (err) {
return false
}
}

/**
* Checks if the provided script comes from a P2SH input.
* @param script The script to be checked.
* @returns True if the script is P2SH, false otherwise.
*/
function isP2SHScript(script: Buffer): boolean {
try {
payments.p2sh({ output: script })
return true
} catch (err) {
return false
}
}

/**
* Checks if the provided script comes from a P2PKH input.
* @param script The script to be checked.
* @returns True if the script is P2WSH, false otherwise.
*/
function isP2WSHScript(script: Buffer): boolean {
try {
payments.p2wsh({ output: script })
return true
} catch (err) {
return false
}
}

/**
* Utility functions allowing to deal with Bitcoin scripts.
*/
export const BitcoinScriptUtils = {
isP2PKHScript,
isP2WPKHScript,
isP2SHScript,
isP2WSHScript,
}
55 changes: 26 additions & 29 deletions typescript/src/services/deposits/deposit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ import {
extractBitcoinRawTxVectors,
toBcoinNetwork,
} from "../../lib/bitcoin"

const { opcodes } = bcoin.script.common
import { Stack, script, opcodes } from "bitcoinjs-lib"

/**
* Component representing an instance of the tBTC v2 deposit process.
Expand Down Expand Up @@ -193,33 +192,31 @@ export class DepositScript {
* @returns Plain-text deposit script as an un-prefixed hex string.
*/
async getPlainText(): Promise<string> {
// All HEXes pushed to the script must be un-prefixed.
const script = new bcoin.Script()
script.clear()
script.pushData(Buffer.from(this.receipt.depositor.identifierHex, "hex"))
script.pushOp(opcodes.OP_DROP)
script.pushData(Buffer.from(this.receipt.blindingFactor, "hex"))
script.pushOp(opcodes.OP_DROP)
script.pushOp(opcodes.OP_DUP)
script.pushOp(opcodes.OP_HASH160)
script.pushData(Buffer.from(this.receipt.walletPublicKeyHash, "hex"))
script.pushOp(opcodes.OP_EQUAL)
script.pushOp(opcodes.OP_IF)
script.pushOp(opcodes.OP_CHECKSIG)
script.pushOp(opcodes.OP_ELSE)
script.pushOp(opcodes.OP_DUP)
script.pushOp(opcodes.OP_HASH160)
script.pushData(Buffer.from(this.receipt.refundPublicKeyHash, "hex"))
script.pushOp(opcodes.OP_EQUALVERIFY)
script.pushData(Buffer.from(this.receipt.refundLocktime, "hex"))
script.pushOp(opcodes.OP_CHECKLOCKTIMEVERIFY)
script.pushOp(opcodes.OP_DROP)
script.pushOp(opcodes.OP_CHECKSIG)
script.pushOp(opcodes.OP_ENDIF)
script.compile()

// Return script as HEX string.
return script.toRaw().toString("hex")
const chunks: Stack = []

// All HEXes pushed to the script must be un-prefixed
chunks.push(Buffer.from(this.receipt.depositor.identifierHex, "hex"))
chunks.push(opcodes.OP_DROP)
chunks.push(Buffer.from(this.receipt.blindingFactor, "hex"))
chunks.push(opcodes.OP_DROP)
chunks.push(opcodes.OP_DUP)
chunks.push(opcodes.OP_HASH160)
chunks.push(Buffer.from(this.receipt.walletPublicKeyHash, "hex"))
chunks.push(opcodes.OP_EQUAL)
chunks.push(opcodes.OP_IF)
chunks.push(opcodes.OP_CHECKSIG)
chunks.push(opcodes.OP_ELSE)
chunks.push(opcodes.OP_DUP)
chunks.push(opcodes.OP_HASH160)
chunks.push(Buffer.from(this.receipt.refundPublicKeyHash, "hex"))
chunks.push(opcodes.OP_EQUALVERIFY)
chunks.push(Buffer.from(this.receipt.refundLocktime, "hex"))
chunks.push(opcodes.OP_CHECKLOCKTIMEVERIFY)
chunks.push(opcodes.OP_DROP)
chunks.push(opcodes.OP_CHECKSIG)
chunks.push(opcodes.OP_ENDIF)

return script.compile(chunks).toString("hex")
}

/**
Expand Down
Loading

0 comments on commit 1b21713

Please sign in to comment.