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

Use Hex for arguments and return values #709

Closed
wants to merge 26 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
284e202
Used Hex for argument in publicKeyHashToAddress
tomaszslabon Oct 13, 2023
c7c73e7
Used Hex as return value in addressToPublicKeyHash
tomaszslabon Oct 13, 2023
00f0e9e
Used Hex fro argument in computeHash160
tomaszslabon Oct 13, 2023
5faf6b4
Used Hex as return value in computeHash160
tomaszslabon Oct 13, 2023
ba1ca6e
Used Hex as argument in isScript functions
tomaszslabon Oct 13, 2023
d5a2cf5
Updated function docstring
tomaszslabon Oct 13, 2023
5122eaa
Minor function refactor
tomaszslabon Oct 13, 2023
aad0b94
Used Hex as argument in Bridge functions
tomaszslabon Oct 16, 2023
023170f
Used Hex in DepositReceipt
tomaszslabon Oct 16, 2023
ce3dcff
Used Hex for walletPublicKeyHash and redeemerOutputScript
tomaszslabon Oct 17, 2023
c66dc07
Merge branch 'main' into hex-argument-usage
tomaszslabon Oct 17, 2023
21c5531
Used Hex for TBTC token functionalities
tomaszslabon Oct 17, 2023
5ca3037
Used Hex for electrum
tomaszslabon Oct 17, 2023
04ebcb3
Used Hex for calculating deposit script
tomaszslabon Oct 17, 2023
7ae2146
Used Hex in services
tomaszslabon Oct 17, 2023
887d8ff
Used Hex for SPV proofs
tomaszslabon Oct 20, 2023
4108de6
Used Hex for raw transaction vectors
tomaszslabon Oct 20, 2023
c3213f0
Updated refund script
tomaszslabon Oct 20, 2023
b471fe5
Used Hex in mocked bridge
tomaszslabon Oct 20, 2023
4da7bf9
Merge branch 'main' into hex-argument-usage
tomaszslabon Oct 20, 2023
bbe0efc
Merge branch 'main' into hex-argument-usage
tomaszslabon Oct 23, 2023
527cdd9
Used Hex for functions dealing with compressed Bitcoin public keys
tomaszslabon Oct 24, 2023
d698946
Got rid of the dash in docstrings
tomaszslabon Oct 24, 2023
794b32c
Updated docstring
tomaszslabon Oct 24, 2023
995e166
Used Hex to represent transaction hashes for contract functions
tomaszslabon Oct 24, 2023
d45f995
Merge branch 'main' into hex-argument-usage
tomaszslabon Oct 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions typescript/scripts/refund.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
DepositScript,
ElectrumClient,
ElectrumCredentials,
Hex,
} from "../src"

program
Expand Down Expand Up @@ -60,15 +61,15 @@ const depositJson = JSON.parse(fs.readFileSync(depositJsonPath, "utf-8"))

const deposit: DepositReceipt = {
depositor: depositJson.depositor,
walletPublicKeyHash: depositJson.walletPublicKeyHash,
refundPublicKeyHash: depositJson.refundPublicKeyHash,
blindingFactor: depositJson.blindingFactor,
refundLocktime: depositJson.refundLocktime,
walletPublicKeyHash: Hex.from(depositJson.walletPublicKeyHash),
refundPublicKeyHash: Hex.from(depositJson.refundPublicKeyHash),
blindingFactor: Hex.from(depositJson.blindingFactor),
refundLocktime: Hex.from(depositJson.refundLocktime),
}
const recoveryAddress = depositJson.btcRecoveryAddress

console.log("======= refund provided data ========")
console.log("deposit JSON: ", deposit)
console.log("deposit JSON: ", depositJson)
console.log("deposit recovery amount: ", refundAmount)
console.log("deposit transaction ID: ", transactionId)
console.log("deposit transaction index: ", transactionIndex)
Expand Down
3 changes: 0 additions & 3 deletions typescript/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,3 @@ export * from "./services/redemptions"

// Export the entrypoint module.
export * from "./services/tbtc"

// TODO: Replace all properties that are expected to be un-prefixed hexadecimal
// strings with a Hex type to increase API consistency.
25 changes: 11 additions & 14 deletions typescript/src/lib/bitcoin/address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,19 @@ function publicKeyToAddress(

/**
* Converts a public key hash into a P2PKH/P2WPKH address.
* @param publicKeyHash Public key hash that will be encoded. Must be an
* unprefixed hex string (without 0x prefix).
* @param publicKeyHash Public key hash that will be encoded.
* @param witness If true, a witness public key hash will be encoded and
* P2WPKH address will be returned. Returns P2PKH address otherwise
* @param bitcoinNetwork Network the address should be encoded for.
* @returns P2PKH or P2WPKH address encoded from the given public key hash
* @returns P2PKH or P2WPKH address encoded from the given public key hash.
* @throws Throws an error if network is not supported.
*/
function publicKeyHashToAddress(
publicKeyHash: string,
publicKeyHash: Hex,
witness: boolean,
bitcoinNetwork: BitcoinNetwork
): string {
const hash = Buffer.from(publicKeyHash, "hex")
const hash = publicKeyHash.toBuffer()
const network = toBitcoinJsLibNetwork(bitcoinNetwork)
return witness
? payments.p2wpkh({ hash, network }).address!
Expand All @@ -54,35 +53,33 @@ function publicKeyHashToAddress(
* provided address is not PKH-based.
* @param address P2PKH or P2WPKH address that will be decoded.
* @param bitcoinNetwork Network the address should be decoded for.
* @returns Public key hash decoded from the address. This will be an unprefixed
* hex string (without 0x prefix).
* @returns Public key hash decoded from the address.
*/
function addressToPublicKeyHash(
address: string,
bitcoinNetwork: BitcoinNetwork
): string {
): Hex {
const network = toBitcoinJsLibNetwork(bitcoinNetwork)

try {
// Try extracting hash from P2PKH address.
const hash = payments.p2pkh({ address: address, network }).hash!
return hash.toString("hex")
return Hex.from(payments.p2pkh({ address: address, network }).hash!)
} catch (err) {}

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

// If neither of them succeeded, throw an error.
throw new Error("Address must be P2PKH or P2WPKH valid for given network")
}

/**
* Converts an address to the respective output script.
* @param address BTC address.
* @param bitcoinNetwork Bitcoin network corresponding to the address.
* @returns The un-prefixed and not prepended with length output script.
* @returns The output script not prepended with length.
lukasz-zimnoch marked this conversation as resolved.
Show resolved Hide resolved
*/
function addressToOutputScript(
address: string,
Expand All @@ -95,7 +92,7 @@ function addressToOutputScript(

/**
* Converts an output script to the respective network-specific address.
* @param script The unprefixed and not prepended with length output script.
* @param script The output script not prepended with length.
* @param bitcoinNetwork Bitcoin network the address should be produced for.
* @returns The Bitcoin address.
*/
Expand Down
3 changes: 2 additions & 1 deletion typescript/src/lib/bitcoin/client.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { BitcoinNetwork } from "./network"
import { BitcoinRawTx, BitcoinTx, BitcoinTxHash, BitcoinUtxo } from "./tx"
import { BitcoinTxMerkleBranch } from "./spv"
import { Hex } from "../../lib/utils"

/**
* Represents a Bitcoin client.
Expand Down Expand Up @@ -66,7 +67,7 @@ export interface BitcoinClient {
* block.
* @return Concatenation of block headers in a hexadecimal format.
*/
getHeadersChain(blockHeight: number, chainLength: number): Promise<string>
getHeadersChain(blockHeight: number, chainLength: number): Promise<Hex>

/**
* Get Merkle branch for a given transaction.
Expand Down
27 changes: 13 additions & 14 deletions typescript/src/lib/bitcoin/ecdsa-key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,36 @@ import { BitcoinNetwork, toBitcoinJsLibNetwork } from "./network"
* @param publicKey - Public key that should be checked.
* @returns True if the key is a compressed Bitcoin public key, false otherwise.
*/
function isCompressedPublicKey(publicKey: string): boolean {
function isCompressedPublicKey(publicKey: Hex): boolean {
const publicKeyStr = publicKey.toString()

// Must have 33 bytes and 02 or 03 prefix.
return (
publicKey.length == 66 &&
(publicKey.substring(0, 2) == "02" || publicKey.substring(0, 2) == "03")
publicKeyStr.length == 66 &&
(publicKeyStr.substring(0, 2) == "02" ||
publicKeyStr.substring(0, 2) == "03")
)
}

/**
* Compresses the given uncompressed Bitcoin public key.
* @param publicKey Uncompressed 64-byte public key as an unprefixed hex string.
* @param publicKey Uncompressed 64-byte public key.
* @returns Compressed 33-byte public key prefixed with 02 or 03.
*/
function compressPublicKey(publicKey: string | Hex): string {
if (typeof publicKey === "string") {
publicKey = Hex.from(publicKey)
}

publicKey = publicKey.toString()
function compressPublicKey(publicKey: Hex): string {
const publicKeyStr = publicKey.toString()

// Must have 64 bytes and no prefix.
if (publicKey.length != 128) {
if (publicKeyStr.length != 128) {
throw new Error(
"The public key parameter must be 64-byte. Neither 0x nor 04 prefix is allowed"
)
}

// The X coordinate is the first 32 bytes.
const publicKeyX = publicKey.substring(0, 64)
const publicKeyX = publicKeyStr.substring(0, 64)
// The Y coordinate is the next 32 bytes.
const publicKeyY = publicKey.substring(64)
const publicKeyY = publicKeyStr.substring(64)

const prefix = BigNumber.from(`0x${publicKeyY}`).mod(2).eq(0) ? "02" : "03"

Expand All @@ -59,7 +58,7 @@ export const BitcoinPublicKeyUtils = {
* @param privateKey Private key that should be used to create the key pair.
* Should be passed in the WIF format.
* @param bitcoinNetwork Bitcoin network the given key pair is relevant for.
* @returns Bitcoin key ring.
* @returns Bitcoin key pair.
*/
function createKeyPair(
privateKey: string,
Expand Down
14 changes: 6 additions & 8 deletions typescript/src/lib/bitcoin/hash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,19 @@ import { Hex } from "../utils"
/**
* Computes the HASH160 (i.e. RIPEMD160(SHA256(text))) for the given text.
* @param text Text the HASH160 is computed for.
* @returns Hash as a 20-byte un-prefixed hex string.
* @returns 20-byte-long hash.
*/
function computeHash160(text: string): string {
const sha256Hash = utils.sha256(
Hex.from(Buffer.from(text, "hex")).toPrefixedString()
)
function computeHash160(text: Hex): Hex {
const sha256Hash = utils.sha256(text.toPrefixedString())
const hash160 = utils.ripemd160(sha256Hash)

return Hex.from(hash160).toString()
return Hex.from(hash160)
}

/**
* Computes the double SHA256 for the given text.
* @param text Text the double SHA256 is computed for.
* @returns Hash as a 32-byte un-prefixed hex string.
* @returns 32-byte-long hash.
* @dev Do not confuse it with computeSha256 which computes single SHA256.
*/
function computeHash256(text: Hex): Hex {
Expand All @@ -40,7 +38,7 @@ function hashLEToBigNumber(hash: Hex): BigNumber {
/**
* Computes the single SHA256 for the given text.
* @param text Text the single SHA256 is computed for.
* @returns Hash as a 32-byte un-prefixed hex string.
* @returns 32-byte-long hash.
* @dev Do not confuse it with computeHash256 which computes double SHA256.
*/
function computeSha256(text: Hex): Hex {
Expand Down
11 changes: 5 additions & 6 deletions typescript/src/lib/bitcoin/header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,15 @@ function deserializeHeader(rawHeader: Hex): BitcoinHeader {
* @param rawHeadersChain - Raw Bitcoin block headers chain.
* @returns Deserialized Bitcoin block headers.
*/
function deserializeHeadersChain(rawHeadersChain: string): BitcoinHeader[] {
if (rawHeadersChain.length % 160 !== 0) {
function deserializeHeadersChain(rawHeadersChain: Hex): BitcoinHeader[] {
const headersChain = rawHeadersChain.toString()
if (headersChain.length % 160 !== 0) {
throw new Error("Incorrect length of Bitcoin headers")
}

const result: BitcoinHeader[] = []
for (let i = 0; i < rawHeadersChain.length; i += 160) {
result.push(
deserializeHeader(Hex.from(rawHeadersChain.substring(i, i + 160)))
)
for (let i = 0; i < headersChain.length; i += 160) {
result.push(deserializeHeader(Hex.from(headersChain.substring(i, i + 160))))
}

return result
Expand Down
17 changes: 9 additions & 8 deletions typescript/src/lib/bitcoin/script.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Hex } from "../utils"
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 {
function isP2PKHScript(script: Hex): boolean {
try {
payments.p2pkh({ output: script })
payments.p2pkh({ output: script.toBuffer() })
return true
} catch (err) {
return false
Expand All @@ -19,9 +20,9 @@ function isP2PKHScript(script: Buffer): boolean {
* @param script The script to be checked.
* @returns True if the script is P2WPKH, false otherwise.
*/
function isP2WPKHScript(script: Buffer): boolean {
function isP2WPKHScript(script: Hex): boolean {
try {
payments.p2wpkh({ output: script })
payments.p2wpkh({ output: script.toBuffer() })
return true
} catch (err) {
return false
Expand All @@ -33,9 +34,9 @@ function isP2WPKHScript(script: Buffer): boolean {
* @param script The script to be checked.
* @returns True if the script is P2SH, false otherwise.
*/
function isP2SHScript(script: Buffer): boolean {
function isP2SHScript(script: Hex): boolean {
try {
payments.p2sh({ output: script })
payments.p2sh({ output: script.toBuffer() })
return true
} catch (err) {
return false
Expand All @@ -47,9 +48,9 @@ function isP2SHScript(script: Buffer): boolean {
* @param script The script to be checked.
* @returns True if the script is P2WSH, false otherwise.
*/
function isP2WSHScript(script: Buffer): boolean {
function isP2WSHScript(script: Hex): boolean {
try {
payments.p2wsh({ output: script })
payments.p2wsh({ output: script.toBuffer() })
return true
} catch (err) {
return false
Expand Down
33 changes: 17 additions & 16 deletions typescript/src/lib/bitcoin/spv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,20 @@ import { BitcoinHashUtils } from "./hash"
*/
export interface BitcoinSpvProof {
/**
* The merkle proof of transaction inclusion in a block, as an un-prefixed
* hex string.
* The merkle proof of transaction inclusion in a block.
*/
merkleProof: string
merkleProof: Hex

/**
* Transaction index in the block (0-indexed).
*/
txIndexInBlock: number

/**
* Single byte-string of 80-byte block headers, lowest height first, as an
* un-prefixed hex string.
* Concatenated block headers in hexadecimal format. Each block header is
* 80-byte-long. The block header with the lowest height is first.
*/
bitcoinHeaders: string
bitcoinHeaders: Hex
}

/**
Expand All @@ -46,7 +45,7 @@ export interface BitcoinTxMerkleBranch {
* in order to trace up to obtain the merkle root of the including block,
* the deepest pairing first. Each hash is an unprefixed hex string.
*/
merkle: string[]
merkle: Hex[]

/**
* The 0-based index of the transaction's position in the block.
Expand Down Expand Up @@ -117,12 +116,12 @@ export async function assembleBitcoinSpvProof(
* @param txMerkleBranch - Branch of a Merkle tree leading to a transaction.
* @returns Transaction inclusion proof in hexadecimal form.
*/
function createMerkleProof(txMerkleBranch: BitcoinTxMerkleBranch): string {
function createMerkleProof(txMerkleBranch: BitcoinTxMerkleBranch): Hex {
let proof = Buffer.from("")
txMerkleBranch.merkle.forEach(function (item) {
proof = Buffer.concat([proof, Buffer.from(item, "hex").reverse()])
proof = Buffer.concat([proof, item.toBuffer().reverse()])
})
return proof.toString("hex")
return Hex.from(proof)
}

/**
Expand Down Expand Up @@ -315,19 +314,21 @@ function validateMerkleTreeHashes(
}

/**
* Splits a given Merkle proof string into an array of intermediate node hashes.
* @param merkleProof A string representation of the Merkle proof.
* Splits a given concatenated Merkle proof into an array of intermediate node
* hashes.
* @param merkleProof A concatenated representation of the Merkle proof.
* @returns An array of intermediate node hashes.
* @throws {Error} If the length of the Merkle proof is not a multiple of 64.
*/
function splitMerkleProof(merkleProof: string): Hex[] {
if (merkleProof.length % 64 != 0) {
function splitMerkleProof(merkleProof: Hex): Hex[] {
const merkleProofStr = merkleProof.toString()
if (merkleProofStr.length % 64 != 0) {
throw new Error("Incorrect length of Merkle proof")
}

const intermediateNodeHashes: Hex[] = []
for (let i = 0; i < merkleProof.length; i += 64) {
intermediateNodeHashes.push(Hex.from(merkleProof.slice(i, i + 64)))
for (let i = 0; i < merkleProofStr.length; i += 64) {
intermediateNodeHashes.push(Hex.from(merkleProofStr.slice(i, i + 64)))
}

return intermediateNodeHashes
Expand Down
Loading