@teleportdao/bitcoin 1.7.12 → 1.7.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/bitcoin-base.d.ts +93 -0
  2. package/dist/bitcoin-base.d.ts.map +1 -0
  3. package/dist/bitcoin-base.js +236 -0
  4. package/dist/bitcoin-base.js.map +1 -0
  5. package/dist/bitcoin-interface-utils.d.ts.map +1 -1
  6. package/dist/bitcoin-interface-utils.js +2 -1
  7. package/dist/bitcoin-interface-utils.js.map +1 -1
  8. package/dist/helper/burn-request-helper.d.ts +7 -0
  9. package/dist/helper/burn-request-helper.d.ts.map +1 -0
  10. package/dist/helper/burn-request-helper.js +26 -0
  11. package/dist/helper/burn-request-helper.js.map +1 -0
  12. package/dist/helper/teleport-request-helper.d.ts +47 -0
  13. package/dist/helper/teleport-request-helper.d.ts.map +1 -0
  14. package/dist/helper/teleport-request-helper.js +146 -0
  15. package/dist/helper/teleport-request-helper.js.map +1 -0
  16. package/dist/helper/teleswap-helper.d.ts.map +1 -1
  17. package/dist/helper/teleswap-helper.js +1 -2
  18. package/dist/helper/teleswap-helper.js.map +1 -1
  19. package/dist/teleport-dao-payments.d.ts +76 -0
  20. package/dist/teleport-dao-payments.d.ts.map +1 -0
  21. package/dist/teleport-dao-payments.js +217 -0
  22. package/dist/teleport-dao-payments.js.map +1 -0
  23. package/dist/teleswap-wallet.d.ts.map +1 -1
  24. package/dist/teleswap-wallet.js +4 -1
  25. package/dist/teleswap-wallet.js.map +1 -1
  26. package/dist/utils/tools.d.ts.map +1 -1
  27. package/dist/utils/tools.js.map +1 -1
  28. package/package.json +4 -4
  29. package/src/bitcoin-interface-ordinal.ts +181 -181
  30. package/src/bitcoin-interface-teleswap.ts +252 -252
  31. package/src/bitcoin-interface-utils.ts +60 -59
  32. package/src/bitcoin-interface.ts +247 -247
  33. package/src/bitcoin-utils.ts +591 -591
  34. package/src/bitcoin-wallet-base.ts +310 -310
  35. package/src/helper/brc20-helper.ts +181 -181
  36. package/src/helper/ordinal-helper.ts +118 -118
  37. package/src/helper/teleswap-helper.ts +2 -4
  38. package/src/index.ts +15 -15
  39. package/src/ordinal-wallet.ts +738 -738
  40. package/src/sign/index.ts +1 -1
  41. package/src/sign/sign-transaction.ts +108 -108
  42. package/src/teleswap-wallet.ts +155 -152
  43. package/src/transaction-builder/bitcoin-transaction-builder.ts +44 -44
  44. package/src/transaction-builder/index.ts +3 -3
  45. package/src/transaction-builder/ordinal-transaction-builder.ts +147 -147
  46. package/src/transaction-builder/transaction-builder.ts +706 -706
  47. package/src/type.ts +43 -43
  48. package/src/utils/networks.ts +33 -33
  49. package/src/utils/tools.ts +90 -89
  50. package/tsconfig.json +9 -9
  51. package/webpack.config.js +16 -16
@@ -1,591 +1,591 @@
1
- /* eslint-disable @typescript-eslint/no-var-requires */
2
- import * as bip39 from "bip39"
3
- import BIP32Factory from "bip32"
4
- import * as ecc from "@bitcoinerlab/secp256k1"
5
- import * as bitcoin from "bitcoinjs-lib"
6
- import * as bitcoinEcPair from "bitcoinjs-ecpair"
7
- import networks from "./utils/networks"
8
- import { Transaction } from "./type"
9
-
10
- const bip32 = BIP32Factory(ecc)
11
- const { ECPair } = bitcoinEcPair
12
-
13
- bitcoin.initEccLib(ecc)
14
-
15
- const varUnit = require("varuint-bitcoin")
16
- const fastRoot = require("merkle-lib/fastRoot")
17
- const merkle = require("merkle-lib")
18
- const merkleProof = require("merkle-lib/proof")
19
-
20
- // const bip32Prefix = {
21
- // xprv: "0x0488ade4", // Mainnet - P2PKH or P2SH - m/44'/0'
22
- // yprv: "0x049d7878", // Mainnet - P2WPKH in P2SH - m/49'/0'
23
- // zprv: "0x04b2430c", // Mainnet - P2WPKH - m/84'/0'
24
- // Yprv: "0x0295b005", // Mainnet - Multi-signature P2WSH in P2SH
25
- // Zprv: "0x02aa7a99", // Mainnet - Multi-signature P2WSH
26
- // tprv: "0x04358394", // Testnet - P2PKH or P2SH - m/44'/1'
27
- // uprv: "0x044a4e28", // Testnet - P2WPKH in P2SH - m/49'/1'
28
- // vprv: "0x045f18bc", // Testnet - P2WPKH - m/84'/1'
29
- // Uprv: "0x024285b5", // Testnet - Multi-signature P2WSH in P2SH
30
- // Vprv: "0x02575048", // Testnet - Multi-signature P2WSH
31
-
32
- // xpub: "0x0488b21e", // Mainnet - P2PKH or P2SH - m/44'/0'
33
- // ypub: "0x049d7cb2", // Mainnet - P2WPKH in P2SH - m/49'/0'
34
- // zpub: "0x04b24746", // Mainnet - P2WPKH - m/84'/0'
35
- // Ypub: "0x0295b43f", // Mainnet - Multi-signature P2WSH in P2SH
36
- // Zpub: "0x02aa7ed3", // Mainnet - Multi-signature P2WSH
37
- // tpub: "0x043587cf", // Testnet - P2PKH or P2SH - m/44'/1'
38
- // upub: "0x044a5262", // Testnet - P2WPKH in P2SH - m/49'/1'
39
- // vpub: "0x045f1cf6", // Testnet - P2WPKH - m/84'/1'
40
- // Upub: "0x024289ef", // Testnet - Multi-signature P2WSH in P2SH
41
- // Vpub: "0x02575483", // Testnet - Multi-signature P2WSH
42
- // }
43
- export { networks }
44
-
45
- export function generateMnemonic() {
46
- const mnemonic = bip39.generateMnemonic(256)
47
- return mnemonic
48
- }
49
-
50
- export async function getPrivateKeyHexFromMnemonic(mnemonic: string, index = 0, isChange = false) {
51
- const node = bip32.fromSeed(await bip39.mnemonicToSeed(mnemonic))
52
- return node
53
- .derive(isChange ? 1 : 0)
54
- .derive(index)
55
- .privateKey!.toString("hex")
56
- }
57
-
58
- export function reverseBytes(hexInput: string) {
59
- return Buffer.from(hexInput, "hex").reverse().toString("hex")
60
- }
61
-
62
- export function getPublicKeyHexByXpubAndIndex(
63
- xpub: string,
64
- index = 0,
65
- isChange = false,
66
- network = networks.bitcoin,
67
- ) {
68
- const node = bip32.fromBase58(xpub, network)
69
- return node
70
- .derive(isChange ? 1 : 0)
71
- .derive(index)
72
- .publicKey.toString("hex")
73
- }
74
-
75
- export function getPubKeyFromPrivateKeyWIF(
76
- privateKeyWIF: string,
77
- network = bitcoin.networks.bitcoin,
78
- ) {
79
- let key = ECPair.fromWIF(privateKeyWIF, network)
80
- return key.publicKey
81
- }
82
-
83
- export function getPubKeyFromPrivateKeyHex(
84
- privateKeyHex: string,
85
- network = bitcoin.networks.bitcoin,
86
- ) {
87
- let key = ECPair.fromPrivateKey(Buffer.from(privateKeyHex, "hex"), { network })
88
- return key.publicKey
89
- }
90
-
91
- export function getPrivateKeyHexFromWIF(privateKeyWIF: string, network = bitcoin.networks.bitcoin) {
92
- let key = ECPair.fromWIF(privateKeyWIF, network)
93
- return key.privateKey!.toString("hex")
94
- }
95
-
96
- export function parseRawTransaction(rawTransaction: string) {
97
- const size = {
98
- version: 4,
99
- flag: 2,
100
- tx: 32,
101
- index: 4,
102
- sequence: 4,
103
- amount: 8,
104
- }
105
-
106
- let offset = 0
107
- let version = rawTransaction.slice(offset, size.version * 2)
108
- offset += size.version * 2
109
- let flag = rawTransaction.slice(offset, offset + size.flag * 2)
110
- offset = flag === "0001" ? offset + size.flag * 2 : offset // * 0x0001 is flag in segwit transactions
111
-
112
- let inputsStartIndex = offset
113
-
114
- let numberOfInputs = varUnit.decode(Buffer.from(rawTransaction.slice(offset), "hex"))
115
- let noiSize = varUnit.encodingLength(numberOfInputs)
116
- offset += noiSize * 2
117
-
118
- for (let i = 0; i < numberOfInputs; i += 1) {
119
- offset += size.tx * 2
120
- offset += size.index * 2
121
- let sigLength = varUnit.decode(Buffer.from(rawTransaction.slice(offset), "hex"))
122
- let sigLengthSize = varUnit.encodingLength(sigLength)
123
- offset += sigLengthSize * 2
124
- offset += sigLength * 2
125
- offset += size.sequence * 2
126
- }
127
- let inputLastIndex = offset
128
- let outputStartIndex = offset
129
-
130
- let numberOfOutputs = varUnit.decode(Buffer.from(rawTransaction.slice(offset), "hex"))
131
- let nooSize = varUnit.encodingLength(numberOfOutputs)
132
- offset += nooSize * 2
133
-
134
- for (let i = 0; i < numberOfOutputs; i += 1) {
135
- offset += size.amount * 2
136
- let unlockSigLength = varUnit.decode(Buffer.from(rawTransaction.slice(offset), "hex"))
137
- let unlockSigLengthSize = varUnit.encodingLength(unlockSigLength)
138
- offset += unlockSigLengthSize * 2
139
- offset += unlockSigLength * 2
140
- }
141
- let outputLastIndex = offset
142
-
143
- version = `0x${version}`
144
- flag = `0x${flag}`
145
- const vin = `0x${rawTransaction.slice(inputsStartIndex, inputLastIndex)}`
146
- const vout = `0x${rawTransaction.slice(outputStartIndex, outputLastIndex)}`
147
- let witness = `0x${rawTransaction.slice(outputLastIndex, rawTransaction.length - 8)}`
148
- let locktime = `0x${rawTransaction.slice(rawTransaction.length - 8, rawTransaction.length)}`
149
- return { version, flag, vin, vout, witness, locktime }
150
- }
151
-
152
- export function calculateMerkleProof(
153
- blockTransactions: string[],
154
- txId: string,
155
- blockMerkleRoot?: string,
156
- ) {
157
- let transactionIndex = blockTransactions.findIndex((tx) => tx === txId)
158
- if (transactionIndex < 0) throw new Error("txId is not in this tree")
159
- let data = blockTransactions.map((a) => Buffer.from(a, "hex").reverse())
160
-
161
- if (
162
- blockMerkleRoot &&
163
- blockMerkleRoot !== fastRoot(data, bitcoin.crypto.hash256).toString("hex")
164
- ) {
165
- throw new Error("calculated merkleRoot and block merkleRoot not matched")
166
- }
167
-
168
- let tree = merkle(data, bitcoin.crypto.hash256)
169
- let proof = merkleProof(tree, data[transactionIndex])
170
-
171
- let intermediateNodesArray = proof
172
- .map((_id?: Buffer) => _id && _id.toString("hex"))
173
- .filter((_id?: Buffer) => _id != null)
174
- let intermediateNodes: string = intermediateNodesArray.reduce(
175
- (a: string, value: string, index: number) =>
176
- index !== transactionIndex % 2 && index < intermediateNodesArray.length - 1 ? a + value : a,
177
- "0x",
178
- )
179
- return {
180
- intermediateNodes,
181
- transactionIndex,
182
- }
183
- }
184
-
185
- export function parseBlockHeader(headerHex: string) {
186
- const size: {
187
- [key: string]: number
188
- } = {
189
- version: 4,
190
- previousBlockHash: 32,
191
- merkleRoot: 32,
192
- timestamp: 4,
193
- difficulty: 4,
194
- nonce: 4,
195
- }
196
- let offset = 0
197
- let result: {
198
- [key: string]: string
199
- } = {}
200
- for (let key in size) {
201
- result[key] = headerHex.slice(offset, offset + size[key] * 2)
202
- offset += size[key] * 2
203
- }
204
- return result as {
205
- version: string
206
- previousBlockHash: string
207
- merkleRoot: string
208
- timestamp: string
209
- difficulty: string
210
- nonce: string
211
- }
212
- }
213
-
214
- export function getAddressType(address: string, network = bitcoin.networks.bitcoin) {
215
- if (address.startsWith(`${network.bech32}1p`)) {
216
- // todo validate p2tr address
217
- return "p2tr"
218
- }
219
- if (address.startsWith(network.bech32)) {
220
- bitcoin.address.fromBech32(address)
221
- return "p2wpkh"
222
- }
223
- let base58Data = bitcoin.address.fromBase58Check(address)
224
- if (base58Data.version === Number(network.scriptHash)) {
225
- return "p2sh"
226
- }
227
- if (base58Data.version === Number(network.pubKeyHash)) {
228
- return "p2pkh"
229
- }
230
-
231
- throw new Error("invalid address")
232
- }
233
-
234
- export function createAddressObjectByAddress(address: string, network = bitcoin.networks.bitcoin) {
235
- let addressType = getAddressType(address, network)
236
- let addressObject
237
- switch (addressType) {
238
- case "p2pkh":
239
- addressObject = bitcoin.payments.p2pkh({
240
- address,
241
- network,
242
- })
243
- break
244
- case "p2wpkh":
245
- addressObject = bitcoin.payments.p2wpkh({
246
- address,
247
- network,
248
- })
249
- break
250
- case "p2sh":
251
- addressObject = bitcoin.payments.p2sh({
252
- address,
253
- network,
254
- })
255
- break
256
- case "p2tr":
257
- addressObject = bitcoin.payments.p2tr({
258
- address,
259
- network,
260
- })
261
- break
262
- default:
263
- throw new Error("address type is incorrect")
264
- }
265
- return { addressObject, addressType }
266
- }
267
-
268
- // used in block parser functions ( newt 2 functions )
269
- export function convertBitcoinScriptToAddress(script: Buffer, network = bitcoin.networks.bitcoin) {
270
- try {
271
- return bitcoin.address.fromOutputScript(script, network)
272
- } catch (error) {
273
- return undefined
274
- }
275
- }
276
-
277
- export function parseRawBlock(
278
- rawBlockHex: string,
279
- blockNumber?: number,
280
- network = bitcoin.networks.bitcoin,
281
- ) {
282
- let block = bitcoin.Block.fromBuffer(Buffer.from(rawBlockHex, "hex"))
283
- let blockHash = block.getHash().toString("hex")
284
- let merkleRoot = block.merkleRoot!.toString("hex")
285
- let prvBlockHash = block.prevHash!.toString("hex")
286
- return {
287
- blockNumber,
288
- merkleRoot,
289
- prvBlockHash,
290
- transactions: block.transactions?.map((tx) => ({
291
- txId: tx.getId(),
292
- version: tx.version,
293
- locktime: tx.locktime,
294
- blockNumber,
295
- blockHash,
296
- vout: tx.outs.map((vo, index) => ({
297
- address: convertBitcoinScriptToAddress(vo.script, network),
298
- script: vo.script.toString("hex"),
299
- value: vo.value,
300
- index,
301
- })),
302
- vin: tx.ins.map((vi) => ({
303
- txId: Buffer.from(vi.hash).reverse().toString("hex"),
304
- index: vi.index,
305
- })),
306
- })),
307
- }
308
- }
309
-
310
- export function extractTransactionsAndBlockInfoFromRawBlock(
311
- rawBlockHex: string,
312
- blockNumber: number,
313
- addresses: string[] = [],
314
- inputTxIds: {
315
- txId: string
316
- index: number
317
- address: string
318
- script?: string
319
- value?: number
320
- }[] = [],
321
- network = bitcoin.networks.bitcoin,
322
- ) {
323
- let block = bitcoin.Block.fromBuffer(Buffer.from(rawBlockHex, "hex"))
324
- let blockHash = block.getHash().reverse().toString("hex")
325
- let merkleRoot = block.merkleRoot!.toString("hex")
326
- let prvBlockHash = block.prevHash!.toString("hex")
327
-
328
- let blockInfo = {
329
- blockNumber,
330
- blockHash,
331
- merkleRoot,
332
- prvBlockHash,
333
- }
334
-
335
- let addressScript = addresses.map((address) =>
336
- createAddressObjectByAddress(address, network).addressObject.output!.toString("hex"),
337
- )
338
-
339
- let blockTxIds = block.transactions!.map((tx) => tx.getId())
340
-
341
- let withdrawTxs: Transaction[] = []
342
- let depositTxs: Transaction[] = []
343
- block.transactions?.forEach((tx) => {
344
- let txId = tx.getId()
345
-
346
- let inputTxAddress: string | undefined
347
- let isWithdraw = tx.ins.find((vi) => {
348
- let viTxId = Buffer.from(vi.hash).reverse().toString("hex")
349
- let viInput = inputTxIds.find((vin) => vin.txId === viTxId && vin.index === vi.index)
350
- inputTxAddress = viInput?.address
351
- return !!inputTxAddress
352
- })
353
- if (isWithdraw && inputTxAddress) {
354
- let txMerkleProof = calculateMerkleProof(blockTxIds, txId, merkleRoot)
355
-
356
- withdrawTxs.push({
357
- txId: tx.getId(),
358
- version: tx.version,
359
- locktime: tx.locktime,
360
- blockNumber,
361
- blockHash,
362
- merkleProof: txMerkleProof,
363
- vout: tx.outs.map((vo) => ({
364
- address: convertBitcoinScriptToAddress(vo.script, network),
365
- script: vo.script.toString("hex"),
366
- value: vo.value,
367
- })),
368
- vin: tx.ins.map((vi) => {
369
- let viTxId = Buffer.from(vi.hash).reverse().toString("hex")
370
- let viInput = inputTxIds.find((vin) => vin.txId === viTxId && vin.index === vi.index)
371
- return {
372
- txId: Buffer.from(vi.hash).reverse().toString("hex"),
373
- index: vi.index,
374
- address: viInput?.address,
375
- script: viInput?.script,
376
- value: viInput?.value,
377
- }
378
- }),
379
- address: inputTxAddress,
380
- addressScript: createAddressObjectByAddress(
381
- inputTxAddress,
382
- network,
383
- ).addressObject.output!.toString("hex"),
384
- })
385
- }
386
-
387
- let addressIndex: number = -1
388
- let isDeposit = tx.outs.find((blockTxVo) => {
389
- let sIndex = addressScript.findIndex(
390
- (addScript) => addScript === blockTxVo.script.toString("hex"),
391
- )
392
- if (sIndex >= 0) {
393
- addressIndex = sIndex
394
- return true
395
- }
396
- return false
397
- })
398
-
399
- if (isDeposit && addressIndex >= 0) {
400
- let txMerkleProof = calculateMerkleProof(blockTxIds, txId, merkleRoot)
401
- depositTxs.push({
402
- txId: tx.getId(),
403
- version: tx.version,
404
- locktime: tx.locktime,
405
- blockNumber,
406
- blockHash,
407
- merkleProof: txMerkleProof,
408
- vout: tx.outs.map((vo) => ({
409
- address: convertBitcoinScriptToAddress(vo.script, network),
410
- script: vo.script.toString("hex"),
411
- value: vo.value,
412
- })),
413
- vin: tx.ins.map((vi) => ({
414
- txId: Buffer.from(vi.hash).reverse().toString("hex"),
415
- index: vi.index,
416
- })),
417
- addressScript: addressScript[addressIndex],
418
- address: addresses[addressIndex],
419
- })
420
- }
421
- })
422
- return {
423
- blockInfo,
424
- withdrawTxs,
425
- depositTxs,
426
- }
427
- }
428
-
429
- export function validateAddress(address: string, network = bitcoin.networks.bitcoin) {
430
- try {
431
- let isValid = false
432
- let isAddressSegwit = address.startsWith(network.bech32)
433
- if (isAddressSegwit) {
434
- bitcoin.address.fromBech32(address)
435
- isValid = true
436
- } else {
437
- let base58Data = bitcoin.address.fromBase58Check(address)
438
- isValid =
439
- base58Data.version === Number(network.scriptHash) ||
440
- base58Data.version === Number(network.pubKeyHash)
441
- }
442
- return isValid
443
- } catch (error) {
444
- return false
445
- }
446
- }
447
-
448
- function toXOnlyPublicKey(pubKey: Buffer) {
449
- return pubKey.length === 32 ? pubKey : pubKey.slice(1, 33)
450
- }
451
-
452
- export function createAddressObjectByScript(
453
- { addressType, script }: { addressType: string; script: Buffer },
454
- network: bitcoin.Network = bitcoin.networks.bitcoin,
455
- ) {
456
- let addressObject
457
- switch (addressType) {
458
- case "p2pkh":
459
- addressObject = bitcoin.payments.p2pkh({
460
- output: script,
461
- network,
462
- })
463
- break
464
- case "p2wpkh":
465
- addressObject = bitcoin.payments.p2wpkh({
466
- output: script,
467
- network,
468
- })
469
- break
470
- case "p2sh":
471
- addressObject = bitcoin.payments.p2sh({
472
- output: script,
473
- network,
474
- })
475
- break
476
- case "p2wsh":
477
- addressObject = bitcoin.payments.p2wsh({
478
- output: script,
479
- network,
480
- })
481
- break
482
- case "p2tr":
483
- addressObject = bitcoin.payments.p2tr({
484
- output: script,
485
- network,
486
- })
487
- break
488
- default:
489
- throw new Error("address type is incorrect")
490
- }
491
- return addressObject
492
- }
493
-
494
- export function createAddressObjectByHash(
495
- { addressType, hash }: { addressType: string; hash: Buffer },
496
- network: bitcoin.Network = bitcoin.networks.bitcoin,
497
- ) {
498
- let addressObject
499
- switch (addressType) {
500
- case "p2pkh":
501
- addressObject = bitcoin.payments.p2pkh({
502
- hash,
503
- network,
504
- })
505
- break
506
- case "p2wpkh":
507
- addressObject = bitcoin.payments.p2wpkh({
508
- hash,
509
- network,
510
- })
511
- break
512
- case "p2sh":
513
- addressObject = bitcoin.payments.p2sh({
514
- hash,
515
- network,
516
- })
517
- break
518
- case "p2wsh":
519
- addressObject = bitcoin.payments.p2wsh({
520
- hash,
521
- network,
522
- })
523
- break
524
- case "p2tr":
525
- // here hash is the public key of tweaked private key (internal public key)
526
- addressObject = bitcoin.payments.p2tr({
527
- pubkey: hash,
528
- network,
529
- })
530
- break
531
- default:
532
- throw new Error("address type is incorrect")
533
- }
534
- return addressObject
535
- }
536
-
537
- export function createAddressObjectByPublicKey(
538
- { addressType, publicKey }: { addressType: string; publicKey: Buffer },
539
- network: bitcoin.Network = bitcoin.networks.bitcoin,
540
- ): bitcoin.payments.Payment {
541
- let addressObject
542
- switch (addressType) {
543
- case "p2pkh":
544
- addressObject = bitcoin.payments.p2pkh({
545
- pubkey: publicKey,
546
- network,
547
- })
548
- break
549
- case "p2wpkh":
550
- addressObject = bitcoin.payments.p2wpkh({
551
- pubkey: publicKey,
552
- network,
553
- })
554
- break
555
- case "p2sh-p2wpkh":
556
- addressObject = bitcoin.payments.p2sh({
557
- redeem: bitcoin.payments.p2wpkh({
558
- pubkey: publicKey,
559
- network,
560
- }),
561
- })
562
- break
563
- case "p2tr":
564
- // this public key is public key of main private key
565
- addressObject = bitcoin.payments.p2tr({
566
- internalPubkey: toXOnlyPublicKey(publicKey),
567
- network,
568
- })
569
- break
570
- default:
571
- throw new Error("address type is incorrect")
572
- }
573
- return addressObject
574
- }
575
-
576
- export function publicKeyConvertor(publicKeyHex: string, compressed = true) {
577
- let pubkey = ECPair.fromPublicKey(Buffer.from(publicKeyHex, "hex"), {
578
- compressed,
579
- })
580
- return pubkey.publicKey.toString("hex")
581
- }
582
-
583
- export const addressTypeHelper: {
584
- addressTypesNumber: {
585
- [key: string]: number
586
- }
587
- addressTypes: string[]
588
- } = {
589
- addressTypesNumber: { p2pk: 0, p2pkh: 1, p2sh: 2, p2wpkh: 3, p2wsh: 4, p2tr: 5 },
590
- addressTypes: ["p2pk", "p2pkh", "p2sh", "p2wpkh", "p2wsh", "p2tr"],
591
- }
1
+ /* eslint-disable @typescript-eslint/no-var-requires */
2
+ import * as bip39 from "bip39"
3
+ import BIP32Factory from "bip32"
4
+ import * as ecc from "@bitcoinerlab/secp256k1"
5
+ import * as bitcoin from "bitcoinjs-lib"
6
+ import * as bitcoinEcPair from "bitcoinjs-ecpair"
7
+ import networks from "./utils/networks"
8
+ import { Transaction } from "./type"
9
+
10
+ const bip32 = BIP32Factory(ecc)
11
+ const { ECPair } = bitcoinEcPair
12
+
13
+ bitcoin.initEccLib(ecc)
14
+
15
+ const varUnit = require("varuint-bitcoin")
16
+ const fastRoot = require("merkle-lib/fastRoot")
17
+ const merkle = require("merkle-lib")
18
+ const merkleProof = require("merkle-lib/proof")
19
+
20
+ // const bip32Prefix = {
21
+ // xprv: "0x0488ade4", // Mainnet - P2PKH or P2SH - m/44'/0'
22
+ // yprv: "0x049d7878", // Mainnet - P2WPKH in P2SH - m/49'/0'
23
+ // zprv: "0x04b2430c", // Mainnet - P2WPKH - m/84'/0'
24
+ // Yprv: "0x0295b005", // Mainnet - Multi-signature P2WSH in P2SH
25
+ // Zprv: "0x02aa7a99", // Mainnet - Multi-signature P2WSH
26
+ // tprv: "0x04358394", // Testnet - P2PKH or P2SH - m/44'/1'
27
+ // uprv: "0x044a4e28", // Testnet - P2WPKH in P2SH - m/49'/1'
28
+ // vprv: "0x045f18bc", // Testnet - P2WPKH - m/84'/1'
29
+ // Uprv: "0x024285b5", // Testnet - Multi-signature P2WSH in P2SH
30
+ // Vprv: "0x02575048", // Testnet - Multi-signature P2WSH
31
+
32
+ // xpub: "0x0488b21e", // Mainnet - P2PKH or P2SH - m/44'/0'
33
+ // ypub: "0x049d7cb2", // Mainnet - P2WPKH in P2SH - m/49'/0'
34
+ // zpub: "0x04b24746", // Mainnet - P2WPKH - m/84'/0'
35
+ // Ypub: "0x0295b43f", // Mainnet - Multi-signature P2WSH in P2SH
36
+ // Zpub: "0x02aa7ed3", // Mainnet - Multi-signature P2WSH
37
+ // tpub: "0x043587cf", // Testnet - P2PKH or P2SH - m/44'/1'
38
+ // upub: "0x044a5262", // Testnet - P2WPKH in P2SH - m/49'/1'
39
+ // vpub: "0x045f1cf6", // Testnet - P2WPKH - m/84'/1'
40
+ // Upub: "0x024289ef", // Testnet - Multi-signature P2WSH in P2SH
41
+ // Vpub: "0x02575483", // Testnet - Multi-signature P2WSH
42
+ // }
43
+ export { networks }
44
+
45
+ export function generateMnemonic() {
46
+ const mnemonic = bip39.generateMnemonic(256)
47
+ return mnemonic
48
+ }
49
+
50
+ export async function getPrivateKeyHexFromMnemonic(mnemonic: string, index = 0, isChange = false) {
51
+ const node = bip32.fromSeed(await bip39.mnemonicToSeed(mnemonic))
52
+ return node
53
+ .derive(isChange ? 1 : 0)
54
+ .derive(index)
55
+ .privateKey!.toString("hex")
56
+ }
57
+
58
+ export function reverseBytes(hexInput: string) {
59
+ return Buffer.from(hexInput, "hex").reverse().toString("hex")
60
+ }
61
+
62
+ export function getPublicKeyHexByXpubAndIndex(
63
+ xpub: string,
64
+ index = 0,
65
+ isChange = false,
66
+ network = networks.bitcoin,
67
+ ) {
68
+ const node = bip32.fromBase58(xpub, network)
69
+ return node
70
+ .derive(isChange ? 1 : 0)
71
+ .derive(index)
72
+ .publicKey.toString("hex")
73
+ }
74
+
75
+ export function getPubKeyFromPrivateKeyWIF(
76
+ privateKeyWIF: string,
77
+ network = bitcoin.networks.bitcoin,
78
+ ) {
79
+ let key = ECPair.fromWIF(privateKeyWIF, network)
80
+ return key.publicKey
81
+ }
82
+
83
+ export function getPubKeyFromPrivateKeyHex(
84
+ privateKeyHex: string,
85
+ network = bitcoin.networks.bitcoin,
86
+ ) {
87
+ let key = ECPair.fromPrivateKey(Buffer.from(privateKeyHex, "hex"), { network })
88
+ return key.publicKey
89
+ }
90
+
91
+ export function getPrivateKeyHexFromWIF(privateKeyWIF: string, network = bitcoin.networks.bitcoin) {
92
+ let key = ECPair.fromWIF(privateKeyWIF, network)
93
+ return key.privateKey!.toString("hex")
94
+ }
95
+
96
+ export function parseRawTransaction(rawTransaction: string) {
97
+ const size = {
98
+ version: 4,
99
+ flag: 2,
100
+ tx: 32,
101
+ index: 4,
102
+ sequence: 4,
103
+ amount: 8,
104
+ }
105
+
106
+ let offset = 0
107
+ let version = rawTransaction.slice(offset, size.version * 2)
108
+ offset += size.version * 2
109
+ let flag = rawTransaction.slice(offset, offset + size.flag * 2)
110
+ offset = flag === "0001" ? offset + size.flag * 2 : offset // * 0x0001 is flag in segwit transactions
111
+
112
+ let inputsStartIndex = offset
113
+
114
+ let numberOfInputs = varUnit.decode(Buffer.from(rawTransaction.slice(offset), "hex"))
115
+ let noiSize = varUnit.encodingLength(numberOfInputs)
116
+ offset += noiSize * 2
117
+
118
+ for (let i = 0; i < numberOfInputs; i += 1) {
119
+ offset += size.tx * 2
120
+ offset += size.index * 2
121
+ let sigLength = varUnit.decode(Buffer.from(rawTransaction.slice(offset), "hex"))
122
+ let sigLengthSize = varUnit.encodingLength(sigLength)
123
+ offset += sigLengthSize * 2
124
+ offset += sigLength * 2
125
+ offset += size.sequence * 2
126
+ }
127
+ let inputLastIndex = offset
128
+ let outputStartIndex = offset
129
+
130
+ let numberOfOutputs = varUnit.decode(Buffer.from(rawTransaction.slice(offset), "hex"))
131
+ let nooSize = varUnit.encodingLength(numberOfOutputs)
132
+ offset += nooSize * 2
133
+
134
+ for (let i = 0; i < numberOfOutputs; i += 1) {
135
+ offset += size.amount * 2
136
+ let unlockSigLength = varUnit.decode(Buffer.from(rawTransaction.slice(offset), "hex"))
137
+ let unlockSigLengthSize = varUnit.encodingLength(unlockSigLength)
138
+ offset += unlockSigLengthSize * 2
139
+ offset += unlockSigLength * 2
140
+ }
141
+ let outputLastIndex = offset
142
+
143
+ version = `0x${version}`
144
+ flag = `0x${flag}`
145
+ const vin = `0x${rawTransaction.slice(inputsStartIndex, inputLastIndex)}`
146
+ const vout = `0x${rawTransaction.slice(outputStartIndex, outputLastIndex)}`
147
+ let witness = `0x${rawTransaction.slice(outputLastIndex, rawTransaction.length - 8)}`
148
+ let locktime = `0x${rawTransaction.slice(rawTransaction.length - 8, rawTransaction.length)}`
149
+ return { version, flag, vin, vout, witness, locktime }
150
+ }
151
+
152
+ export function calculateMerkleProof(
153
+ blockTransactions: string[],
154
+ txId: string,
155
+ blockMerkleRoot?: string,
156
+ ) {
157
+ let transactionIndex = blockTransactions.findIndex((tx) => tx === txId)
158
+ if (transactionIndex < 0) throw new Error("txId is not in this tree")
159
+ let data = blockTransactions.map((a) => Buffer.from(a, "hex").reverse())
160
+
161
+ if (
162
+ blockMerkleRoot &&
163
+ blockMerkleRoot !== fastRoot(data, bitcoin.crypto.hash256).toString("hex")
164
+ ) {
165
+ throw new Error("calculated merkleRoot and block merkleRoot not matched")
166
+ }
167
+
168
+ let tree = merkle(data, bitcoin.crypto.hash256)
169
+ let proof = merkleProof(tree, data[transactionIndex])
170
+
171
+ let intermediateNodesArray = proof
172
+ .map((_id?: Buffer) => _id && _id.toString("hex"))
173
+ .filter((_id?: Buffer) => _id != null)
174
+ let intermediateNodes: string = intermediateNodesArray.reduce(
175
+ (a: string, value: string, index: number) =>
176
+ index !== transactionIndex % 2 && index < intermediateNodesArray.length - 1 ? a + value : a,
177
+ "0x",
178
+ )
179
+ return {
180
+ intermediateNodes,
181
+ transactionIndex,
182
+ }
183
+ }
184
+
185
+ export function parseBlockHeader(headerHex: string) {
186
+ const size: {
187
+ [key: string]: number
188
+ } = {
189
+ version: 4,
190
+ previousBlockHash: 32,
191
+ merkleRoot: 32,
192
+ timestamp: 4,
193
+ difficulty: 4,
194
+ nonce: 4,
195
+ }
196
+ let offset = 0
197
+ let result: {
198
+ [key: string]: string
199
+ } = {}
200
+ for (let key in size) {
201
+ result[key] = headerHex.slice(offset, offset + size[key] * 2)
202
+ offset += size[key] * 2
203
+ }
204
+ return result as {
205
+ version: string
206
+ previousBlockHash: string
207
+ merkleRoot: string
208
+ timestamp: string
209
+ difficulty: string
210
+ nonce: string
211
+ }
212
+ }
213
+
214
+ export function getAddressType(address: string, network = bitcoin.networks.bitcoin) {
215
+ if (address.startsWith(`${network.bech32}1p`)) {
216
+ // todo validate p2tr address
217
+ return "p2tr"
218
+ }
219
+ if (address.startsWith(network.bech32)) {
220
+ bitcoin.address.fromBech32(address)
221
+ return "p2wpkh"
222
+ }
223
+ let base58Data = bitcoin.address.fromBase58Check(address)
224
+ if (base58Data.version === Number(network.scriptHash)) {
225
+ return "p2sh"
226
+ }
227
+ if (base58Data.version === Number(network.pubKeyHash)) {
228
+ return "p2pkh"
229
+ }
230
+
231
+ throw new Error("invalid address")
232
+ }
233
+
234
+ export function createAddressObjectByAddress(address: string, network = bitcoin.networks.bitcoin) {
235
+ let addressType = getAddressType(address, network)
236
+ let addressObject
237
+ switch (addressType) {
238
+ case "p2pkh":
239
+ addressObject = bitcoin.payments.p2pkh({
240
+ address,
241
+ network,
242
+ })
243
+ break
244
+ case "p2wpkh":
245
+ addressObject = bitcoin.payments.p2wpkh({
246
+ address,
247
+ network,
248
+ })
249
+ break
250
+ case "p2sh":
251
+ addressObject = bitcoin.payments.p2sh({
252
+ address,
253
+ network,
254
+ })
255
+ break
256
+ case "p2tr":
257
+ addressObject = bitcoin.payments.p2tr({
258
+ address,
259
+ network,
260
+ })
261
+ break
262
+ default:
263
+ throw new Error("address type is incorrect")
264
+ }
265
+ return { addressObject, addressType }
266
+ }
267
+
268
+ // used in block parser functions ( newt 2 functions )
269
+ export function convertBitcoinScriptToAddress(script: Buffer, network = bitcoin.networks.bitcoin) {
270
+ try {
271
+ return bitcoin.address.fromOutputScript(script, network)
272
+ } catch (error) {
273
+ return undefined
274
+ }
275
+ }
276
+
277
+ export function parseRawBlock(
278
+ rawBlockHex: string,
279
+ blockNumber?: number,
280
+ network = bitcoin.networks.bitcoin,
281
+ ) {
282
+ let block = bitcoin.Block.fromBuffer(Buffer.from(rawBlockHex, "hex"))
283
+ let blockHash = block.getHash().toString("hex")
284
+ let merkleRoot = block.merkleRoot!.toString("hex")
285
+ let prvBlockHash = block.prevHash!.toString("hex")
286
+ return {
287
+ blockNumber,
288
+ merkleRoot,
289
+ prvBlockHash,
290
+ transactions: block.transactions?.map((tx) => ({
291
+ txId: tx.getId(),
292
+ version: tx.version,
293
+ locktime: tx.locktime,
294
+ blockNumber,
295
+ blockHash,
296
+ vout: tx.outs.map((vo, index) => ({
297
+ address: convertBitcoinScriptToAddress(vo.script, network),
298
+ script: vo.script.toString("hex"),
299
+ value: vo.value,
300
+ index,
301
+ })),
302
+ vin: tx.ins.map((vi) => ({
303
+ txId: Buffer.from(vi.hash).reverse().toString("hex"),
304
+ index: vi.index,
305
+ })),
306
+ })),
307
+ }
308
+ }
309
+
310
+ export function extractTransactionsAndBlockInfoFromRawBlock(
311
+ rawBlockHex: string,
312
+ blockNumber: number,
313
+ addresses: string[] = [],
314
+ inputTxIds: {
315
+ txId: string
316
+ index: number
317
+ address: string
318
+ script?: string
319
+ value?: number
320
+ }[] = [],
321
+ network = bitcoin.networks.bitcoin,
322
+ ) {
323
+ let block = bitcoin.Block.fromBuffer(Buffer.from(rawBlockHex, "hex"))
324
+ let blockHash = block.getHash().reverse().toString("hex")
325
+ let merkleRoot = block.merkleRoot!.toString("hex")
326
+ let prvBlockHash = block.prevHash!.toString("hex")
327
+
328
+ let blockInfo = {
329
+ blockNumber,
330
+ blockHash,
331
+ merkleRoot,
332
+ prvBlockHash,
333
+ }
334
+
335
+ let addressScript = addresses.map((address) =>
336
+ createAddressObjectByAddress(address, network).addressObject.output!.toString("hex"),
337
+ )
338
+
339
+ let blockTxIds = block.transactions!.map((tx) => tx.getId())
340
+
341
+ let withdrawTxs: Transaction[] = []
342
+ let depositTxs: Transaction[] = []
343
+ block.transactions?.forEach((tx) => {
344
+ let txId = tx.getId()
345
+
346
+ let inputTxAddress: string | undefined
347
+ let isWithdraw = tx.ins.find((vi) => {
348
+ let viTxId = Buffer.from(vi.hash).reverse().toString("hex")
349
+ let viInput = inputTxIds.find((vin) => vin.txId === viTxId && vin.index === vi.index)
350
+ inputTxAddress = viInput?.address
351
+ return !!inputTxAddress
352
+ })
353
+ if (isWithdraw && inputTxAddress) {
354
+ let txMerkleProof = calculateMerkleProof(blockTxIds, txId, merkleRoot)
355
+
356
+ withdrawTxs.push({
357
+ txId: tx.getId(),
358
+ version: tx.version,
359
+ locktime: tx.locktime,
360
+ blockNumber,
361
+ blockHash,
362
+ merkleProof: txMerkleProof,
363
+ vout: tx.outs.map((vo) => ({
364
+ address: convertBitcoinScriptToAddress(vo.script, network),
365
+ script: vo.script.toString("hex"),
366
+ value: vo.value,
367
+ })),
368
+ vin: tx.ins.map((vi) => {
369
+ let viTxId = Buffer.from(vi.hash).reverse().toString("hex")
370
+ let viInput = inputTxIds.find((vin) => vin.txId === viTxId && vin.index === vi.index)
371
+ return {
372
+ txId: Buffer.from(vi.hash).reverse().toString("hex"),
373
+ index: vi.index,
374
+ address: viInput?.address,
375
+ script: viInput?.script,
376
+ value: viInput?.value,
377
+ }
378
+ }),
379
+ address: inputTxAddress,
380
+ addressScript: createAddressObjectByAddress(
381
+ inputTxAddress,
382
+ network,
383
+ ).addressObject.output!.toString("hex"),
384
+ })
385
+ }
386
+
387
+ let addressIndex: number = -1
388
+ let isDeposit = tx.outs.find((blockTxVo) => {
389
+ let sIndex = addressScript.findIndex(
390
+ (addScript) => addScript === blockTxVo.script.toString("hex"),
391
+ )
392
+ if (sIndex >= 0) {
393
+ addressIndex = sIndex
394
+ return true
395
+ }
396
+ return false
397
+ })
398
+
399
+ if (isDeposit && addressIndex >= 0) {
400
+ let txMerkleProof = calculateMerkleProof(blockTxIds, txId, merkleRoot)
401
+ depositTxs.push({
402
+ txId: tx.getId(),
403
+ version: tx.version,
404
+ locktime: tx.locktime,
405
+ blockNumber,
406
+ blockHash,
407
+ merkleProof: txMerkleProof,
408
+ vout: tx.outs.map((vo) => ({
409
+ address: convertBitcoinScriptToAddress(vo.script, network),
410
+ script: vo.script.toString("hex"),
411
+ value: vo.value,
412
+ })),
413
+ vin: tx.ins.map((vi) => ({
414
+ txId: Buffer.from(vi.hash).reverse().toString("hex"),
415
+ index: vi.index,
416
+ })),
417
+ addressScript: addressScript[addressIndex],
418
+ address: addresses[addressIndex],
419
+ })
420
+ }
421
+ })
422
+ return {
423
+ blockInfo,
424
+ withdrawTxs,
425
+ depositTxs,
426
+ }
427
+ }
428
+
429
+ export function validateAddress(address: string, network = bitcoin.networks.bitcoin) {
430
+ try {
431
+ let isValid = false
432
+ let isAddressSegwit = address.startsWith(network.bech32)
433
+ if (isAddressSegwit) {
434
+ bitcoin.address.fromBech32(address)
435
+ isValid = true
436
+ } else {
437
+ let base58Data = bitcoin.address.fromBase58Check(address)
438
+ isValid =
439
+ base58Data.version === Number(network.scriptHash) ||
440
+ base58Data.version === Number(network.pubKeyHash)
441
+ }
442
+ return isValid
443
+ } catch (error) {
444
+ return false
445
+ }
446
+ }
447
+
448
+ function toXOnlyPublicKey(pubKey: Buffer) {
449
+ return pubKey.length === 32 ? pubKey : pubKey.slice(1, 33)
450
+ }
451
+
452
+ export function createAddressObjectByScript(
453
+ { addressType, script }: { addressType: string; script: Buffer },
454
+ network: bitcoin.Network = bitcoin.networks.bitcoin,
455
+ ) {
456
+ let addressObject
457
+ switch (addressType) {
458
+ case "p2pkh":
459
+ addressObject = bitcoin.payments.p2pkh({
460
+ output: script,
461
+ network,
462
+ })
463
+ break
464
+ case "p2wpkh":
465
+ addressObject = bitcoin.payments.p2wpkh({
466
+ output: script,
467
+ network,
468
+ })
469
+ break
470
+ case "p2sh":
471
+ addressObject = bitcoin.payments.p2sh({
472
+ output: script,
473
+ network,
474
+ })
475
+ break
476
+ case "p2wsh":
477
+ addressObject = bitcoin.payments.p2wsh({
478
+ output: script,
479
+ network,
480
+ })
481
+ break
482
+ case "p2tr":
483
+ addressObject = bitcoin.payments.p2tr({
484
+ output: script,
485
+ network,
486
+ })
487
+ break
488
+ default:
489
+ throw new Error("address type is incorrect")
490
+ }
491
+ return addressObject
492
+ }
493
+
494
+ export function createAddressObjectByHash(
495
+ { addressType, hash }: { addressType: string; hash: Buffer },
496
+ network: bitcoin.Network = bitcoin.networks.bitcoin,
497
+ ) {
498
+ let addressObject
499
+ switch (addressType) {
500
+ case "p2pkh":
501
+ addressObject = bitcoin.payments.p2pkh({
502
+ hash,
503
+ network,
504
+ })
505
+ break
506
+ case "p2wpkh":
507
+ addressObject = bitcoin.payments.p2wpkh({
508
+ hash,
509
+ network,
510
+ })
511
+ break
512
+ case "p2sh":
513
+ addressObject = bitcoin.payments.p2sh({
514
+ hash,
515
+ network,
516
+ })
517
+ break
518
+ case "p2wsh":
519
+ addressObject = bitcoin.payments.p2wsh({
520
+ hash,
521
+ network,
522
+ })
523
+ break
524
+ case "p2tr":
525
+ // here hash is the public key of tweaked private key (internal public key)
526
+ addressObject = bitcoin.payments.p2tr({
527
+ pubkey: hash,
528
+ network,
529
+ })
530
+ break
531
+ default:
532
+ throw new Error("address type is incorrect")
533
+ }
534
+ return addressObject
535
+ }
536
+
537
+ export function createAddressObjectByPublicKey(
538
+ { addressType, publicKey }: { addressType: string; publicKey: Buffer },
539
+ network: bitcoin.Network = bitcoin.networks.bitcoin,
540
+ ): bitcoin.payments.Payment {
541
+ let addressObject
542
+ switch (addressType) {
543
+ case "p2pkh":
544
+ addressObject = bitcoin.payments.p2pkh({
545
+ pubkey: publicKey,
546
+ network,
547
+ })
548
+ break
549
+ case "p2wpkh":
550
+ addressObject = bitcoin.payments.p2wpkh({
551
+ pubkey: publicKey,
552
+ network,
553
+ })
554
+ break
555
+ case "p2sh-p2wpkh":
556
+ addressObject = bitcoin.payments.p2sh({
557
+ redeem: bitcoin.payments.p2wpkh({
558
+ pubkey: publicKey,
559
+ network,
560
+ }),
561
+ })
562
+ break
563
+ case "p2tr":
564
+ // this public key is public key of main private key
565
+ addressObject = bitcoin.payments.p2tr({
566
+ internalPubkey: toXOnlyPublicKey(publicKey),
567
+ network,
568
+ })
569
+ break
570
+ default:
571
+ throw new Error("address type is incorrect")
572
+ }
573
+ return addressObject
574
+ }
575
+
576
+ export function publicKeyConvertor(publicKeyHex: string, compressed = true) {
577
+ let pubkey = ECPair.fromPublicKey(Buffer.from(publicKeyHex, "hex"), {
578
+ compressed,
579
+ })
580
+ return pubkey.publicKey.toString("hex")
581
+ }
582
+
583
+ export const addressTypeHelper: {
584
+ addressTypesNumber: {
585
+ [key: string]: number
586
+ }
587
+ addressTypes: string[]
588
+ } = {
589
+ addressTypesNumber: { p2pk: 0, p2pkh: 1, p2sh: 2, p2wpkh: 3, p2wsh: 4, p2tr: 5 },
590
+ addressTypes: ["p2pk", "p2pkh", "p2sh", "p2wpkh", "p2wsh", "p2tr"],
591
+ }