Skip to content

Commit

Permalink
Merge branch 'main' into update-bitcoinjs-lib-version
Browse files Browse the repository at this point in the history
  • Loading branch information
tomaszslabon authored Oct 6, 2023
2 parents a44d18d + 626fb40 commit ea0b36b
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 175 deletions.
57 changes: 0 additions & 57 deletions typescript/src/bitcoin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -780,60 +780,3 @@ export function isP2WSHScript(script: Buffer): boolean {
return false
}
}

/**
* Represents a structured JSON format for a Bitcoin transaction. It includes
* detailed information about its inputs and outputs, as well as the transaction
* itself.
*/
interface TxJSON {
hash: string
version: number
locktime: number
inputs: {
hash: string
index: number
sequence: number
script: string
witness: string[]
}[]
outputs: {
value: number
script: string
address: string
}[]
}

/**
* Converts a raw Bitcoin transaction into a structured JSON format.
* @param rawTransaction - A raw Bitcoin transaction in hexadecimal string format.
* @param bitcoinNetwork - Bitcoin network.
* @returns A structured JSON object representing the transaction.
*/
export function txToJSON(
rawTransaction: string,
bitcoinNetwork: BitcoinNetwork
): TxJSON {
const transaction = Tx.fromHex(rawTransaction)
const network = toBitcoinJsLibNetwork(bitcoinNetwork)

const txJSON: TxJSON = {
hash: transaction.getId(),
version: transaction.version,
locktime: transaction.locktime,
inputs: transaction.ins.map((input) => ({
hash: Hex.from(input.hash).reverse().toString(),
index: input.index,
sequence: input.sequence,
script: input.script.toString("hex"),
witness: input.witness.map((w) => w.toString("hex")),
})),
outputs: transaction.outs.map((output) => ({
value: output.value,
script: output.script.toString("hex"),
address: address.fromOutputScript(output.script, network),
})),
}

return txJSON
}
115 changes: 25 additions & 90 deletions typescript/test/bitcoin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,14 @@ import {
isP2WPKHScript,
isP2SHScript,
isP2WSHScript,
txToJSON,
decomposeRawTransaction,
} from "../src/bitcoin"
import { calculateDepositRefundLocktime } from "../src/deposit"
import { BitcoinNetwork } from "../src/bitcoin-network"
import { Hex } from "../src/hex"
import { BigNumber } from "ethers"
import {
btcAddresses,
btcAddressFromPublicKey,
mainnetTransaction,
testnetTransaction,
} from "./data/bitcoin"
import { btcAddresses, btcAddressFromPublicKey } from "./data/bitcoin"
import { depositSweepWithNoMainUtxoAndWitnessOutput } from "./data/deposit-sweep"

describe("Bitcoin", () => {
describe("compressPublicKey", () => {
Expand Down Expand Up @@ -739,88 +735,27 @@ describe("Bitcoin", () => {
})
})

describe("txToJSON", () => {
context("when network is mainnet", () => {
it("should return correct transaction JSON", () => {
const txJSON = txToJSON(mainnetTransaction, BitcoinNetwork.Mainnet)

expect(txJSON.hash).to.be.equal(
"bb20b27fef136ab1e5ee866a73bc9b33a038c3e258162e6c03e94f6e22941e0e"
)
expect(txJSON.version).to.be.equal(1)
expect(txJSON.locktime).to.be.equal(0)

expect(txJSON.inputs.length).to.be.equal(1)
expect(txJSON.inputs[0].hash).to.be.equal(
"a4082d137ab5c5264efb9f616ca4ac1673015c1e0817cd5cdc1b0379161be95e"
)
expect(txJSON.inputs[0].index).to.be.equal(5)
expect(txJSON.inputs[0].sequence).to.be.equal(4294967295)
expect(txJSON.inputs[0].script).to.be.equal("")
expect(txJSON.inputs[0].witness).to.deep.equal([
"",
"3044022022c7d7546fc0bb96a26c04823d97f0aa4bbe5d9af54acc8f4bd898e88" +
"b86956002206b126720f42b2f200434c6ae770b78aded9b32da4f020aba37f099" +
"d804eab02701",
"304402202b60c2ef3ba68eb473b65564e0fd038884407dc684c98309e3141bb53" +
"233dfd7022078d14fb2e433c71c6c62bd2019dd83859173a3b6973c62444930c1" +
"5d86d4bd1601",
"52210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd929" +
"76b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff0187" +
"4496feff2103c96d495bfdd5ba4145e3e046fee45e84a8a48ad05bd8dbb395c01" +
"1a32cf9f88053ae",
])

expect(txJSON.outputs.length).to.be.equal(2)
expect(txJSON.outputs[0].value).to.be.equal(11991850)
expect(txJSON.outputs[0].script).to.be.equal(
"76a914ee4b7569e9063064323332ad07dd18bc32402a0c88ac"
)
expect(txJSON.outputs[0].address).to.be.equal(
"1NizDcdk2mWE45yZr98JJ2dyi2W2zeZUn5"
)
expect(txJSON.outputs[1].value).to.be.equal(1805173)
expect(txJSON.outputs[1].script).to.be.equal(
"0020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d"
)
expect(txJSON.outputs[1].address).to.be.equal(
"bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej"
)
})
})

context("when network is testnet", () => {
it("should return correct transaction JSON", () => {
const txJSON = txToJSON(testnetTransaction, BitcoinNetwork.Testnet)

expect(txJSON.hash).to.be.equal(
"873effe868161e09ab65e1a23c7cecdc2792995c90ec94973f2fdbc59728ba89"
)
expect(txJSON.version).to.be.equal(1)
expect(txJSON.locktime).to.be.equal(0)

expect(txJSON.inputs.length).to.be.equal(1)
expect(txJSON.inputs[0].hash).to.be.equal(
"c0a5ed42f574b4b969ef0df16a70edb60d4a464739c5011bc051a8dedbaab730"
)
expect(txJSON.inputs[0].index).to.be.equal(0)
expect(txJSON.inputs[0].sequence).to.be.equal(4294967295)
expect(txJSON.inputs[0].script).to.be.equal(
"4830450221009ab9ba3a4c9d81c4ac4431c05eac57388c8332bb191507926a3424" +
"ec697ac23802203369c91742a7d5168ba3af429aed4f2d1022749a4ba5052b172b" +
"b6776d9a07c1012103548c7fe1d7a66f8e705a4299153b87f4874c80aaed2cf828" +
"cd552d6975a01b80"
)
expect(txJSON.inputs[0].witness).to.deep.equal([])

expect(txJSON.outputs.length).to.be.equal(1)
expect(txJSON.outputs[0].value).to.be.equal(270150)
expect(txJSON.outputs[0].script).to.be.equal(
"76a914819850140920deeacfee3a63193807daea8fc5d288ac"
)
expect(txJSON.outputs[0].address).to.be.equal(
"msLBvgMp45BN9CaQCoZ4ewjm71Fix7RgB2"
)
})
describe("decomposeRawTransaction", () => {
it("should return correctly decomposed transaction", () => {
const rawTransaction =
depositSweepWithNoMainUtxoAndWitnessOutput.expectedSweep.transaction
const decomposedTransaction = decomposeRawTransaction(rawTransaction)

expect(decomposedTransaction.version).to.be.equal("01000000")
expect(decomposedTransaction.inputs).to.be.equal(
"02bc187be612bc3db8cfcdec56b75e9bc0262ab6eacfe27cc1a699bacd53e3d07400" +
"000000c948304502210089a89aaf3fec97ac9ffa91cdff59829f0cb3ef852a468153" +
"e2c0e2b473466d2e022072902bb923ef016ac52e941ced78f816bf27991c2b73211e" +
"227db27ec200bc0a012103989d253b17a6a0f41838b84ff0d20e8898f9d7b1a98f25" +
"64da4cc29dcf8581d94c5c14934b98637ca318a4d6e7ca6ffd1690b8e77df6377508" +
"f9f0c90d000395237576a9148db50eb52063ea9d98b3eac91489a90f738986f68763" +
"ac6776a914e257eccafbc07c381642ce6e7e55120fb077fbed8804e0250162b175ac" +
"68ffffffffdc557e737b6688c5712649b86f7757a722dc3d42786f23b2fa826394df" +
"ec545c0000000000ffffffff"
)
expect(decomposedTransaction.outputs).to.be.equal(
"01488a0000000000001600148db50eb52063ea9d98b3eac91489a90f738986f6"
)
expect(decomposedTransaction.locktime).to.be.equal("00000000")
})
})
25 changes: 0 additions & 25 deletions typescript/test/data/bitcoin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,28 +104,3 @@ export const btcAddressFromPublicKey: Record<
},
},
}

// An arbitrary Bitcoin mainnet transaction:
// https://live.blockcypher.com/btc/tx/bb20b27fef136ab1e5ee866a73bc9b33a038c3e258162e6c03e94f6e22941e0e/
export const mainnetTransaction =
"010000000001015ee91b1679031bdc5ccd17081e5c017316aca46c619ffb4e26c5b57a13" +
"2d08a40500000000ffffffff022afbb600000000001976a914ee4b7569e9063064323332" +
"ad07dd18bc32402a0c88ac758b1b0000000000220020701a8d401c84fb13e6baf169d596" +
"84e17abd9fa216c8cc5b9fc63d622ff8c58d0400473044022022c7d7546fc0bb96a26c04" +
"823d97f0aa4bbe5d9af54acc8f4bd898e88b86956002206b126720f42b2f200434c6ae77" +
"0b78aded9b32da4f020aba37f099d804eab0270147304402202b60c2ef3ba68eb473b655" +
"64e0fd038884407dc684c98309e3141bb53233dfd7022078d14fb2e433c71c6c62bd2019" +
"dd83859173a3b6973c62444930c15d86d4bd16016952210375e00eb72e29da82b8936794" +
"7f29ef34afb75e8654f6ea368e0acdfd92976b7c2103a1b26313f430c4b15bb1fdce6632" +
"07659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e046fee45e84" +
"a8a48ad05bd8dbb395c011a32cf9f88053ae00000000"

// An arbitrary Bitcoin testnet transaction:
// https://live.blockcypher.com/btc-testnet/tx/873effe868161e09ab65e1a23c7cecdc2792995c90ec94973f2fdbc59728ba89/
export const testnetTransaction =
"010000000130b7aadbdea851c01b01c53947464a0db6ed706af10def69b9b474f542eda5" +
"c0000000006b4830450221009ab9ba3a4c9d81c4ac4431c05eac57388c8332bb19150792" +
"6a3424ec697ac23802203369c91742a7d5168ba3af429aed4f2d1022749a4ba5052b172b" +
"b6776d9a07c1012103548c7fe1d7a66f8e705a4299153b87f4874c80aaed2cf828cd552d" +
"6975a01b80ffffffff01461f0400000000001976a914819850140920deeacfee3a631938" +
"07daea8fc5d288ac00000000"
2 changes: 1 addition & 1 deletion typescript/test/deposit-sweep.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
TransactionHash,
UnspentTransactionOutput,
Transaction,
txToJSON,
} from "../src/bitcoin"
import { testnetWalletAddress, testnetWalletPrivateKey } from "./data/deposit"
import {
Expand All @@ -17,6 +16,7 @@ import {
} from "./data/deposit-sweep"
import { MockBitcoinClient } from "./utils/mock-bitcoin-client"
import { MockBridge } from "./utils/mock-bridge"
import { txToJSON } from "./utils/helpers"
import * as chai from "chai"
import chaiAsPromised from "chai-as-promised"
chai.use(chaiAsPromised)
Expand Down
2 changes: 1 addition & 1 deletion typescript/test/deposit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
RawTransaction,
TransactionHash,
UnspentTransactionOutput,
txToJSON,
} from "../src/bitcoin"
import { MockBitcoinClient } from "./utils/mock-bitcoin-client"
import {
Expand All @@ -30,6 +29,7 @@ import {
suggestDepositWallet,
} from "../src/deposit"
import { MockBridge } from "./utils/mock-bridge"
import { txToJSON } from "./utils/helpers"
import { Address } from "../src/ethereum"
import { BitcoinNetwork } from "../src"

Expand Down
2 changes: 1 addition & 1 deletion typescript/test/redemption.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
RawTransaction,
TransactionHash,
UnspentTransactionOutput,
txToJSON,
} from "../src/bitcoin"
import { MockBitcoinClient } from "./utils/mock-bitcoin-client"
import {
Expand Down Expand Up @@ -31,6 +30,7 @@ import {
submitRedemptionProof,
submitRedemptionTransaction,
} from "../src/redemption"
import { txToJSON } from "./utils/helpers"
import { MockBridge } from "./utils/mock-bridge"
import * as chai from "chai"
import chaiAsPromised from "chai-as-promised"
Expand Down
63 changes: 63 additions & 0 deletions typescript/test/utils/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Hex } from "../../src/hex"
import {
BitcoinNetwork,
toBitcoinJsLibNetwork,
} from "../../src/bitcoin-network"
import { Transaction, address } from "bitcoinjs-lib"

/**
* Represents a structured JSON format for a Bitcoin transaction. It includes
* detailed information about its inputs and outputs, as well as the transaction
* itself.
*/
interface TxJSON {
hash: string
version: number
locktime: number
inputs: {
hash: string
index: number
sequence: number
script: string
witness: string[]
}[]
outputs: {
value: number
script: string
address: string
}[]
}

/**
* Converts a raw Bitcoin transaction into a structured JSON format.
* @param rawTransaction - A raw Bitcoin transaction in hexadecimal string format.
* @param bitcoinNetwork - Bitcoin network.
* @returns A structured JSON object representing the transaction.
*/
export function txToJSON(
rawTransaction: string,
bitcoinNetwork: BitcoinNetwork
): TxJSON {
const transaction = Transaction.fromHex(rawTransaction)
const network = toBitcoinJsLibNetwork(bitcoinNetwork)

const txJSON: TxJSON = {
hash: transaction.getId(),
version: transaction.version,
locktime: transaction.locktime,
inputs: transaction.ins.map((input) => ({
hash: Hex.from(input.hash).reverse().toString(),
index: input.index,
sequence: input.sequence,
script: input.script.toString("hex"),
witness: input.witness.map((w) => w.toString("hex")),
})),
outputs: transaction.outs.map((output) => ({
value: output.value,
script: output.script.toString("hex"),
address: address.fromOutputScript(output.script, network),
})),
}

return txJSON
}

0 comments on commit ea0b36b

Please sign in to comment.