@teleportdao/bitcoin 1.4.7 → 1.4.9
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.
- package/dist/bitcoin-base.d.ts.map +1 -1
- package/dist/bitcoin-base.js +3 -1
- package/dist/bitcoin-base.js.map +1 -1
- package/dist/bitcoin-interface-utils.d.ts +2 -2
- package/dist/bitcoin-interface.d.ts +8 -61
- package/dist/bitcoin-interface.d.ts.map +1 -1
- package/dist/bitcoin-interface.js +8 -8
- package/dist/bitcoin-interface.js.map +1 -1
- package/dist/bitcoin-utils-2.d.ts +2 -0
- package/dist/bitcoin-utils-2.d.ts.map +1 -0
- package/dist/bitcoin-utils-2.js +13 -0
- package/dist/bitcoin-utils-2.js.map +1 -0
- package/dist/bitcoin-utils.d.ts +6 -6
- package/dist/bitcoin-utils.d.ts.map +1 -1
- package/dist/bitcoin-utils.js +58 -31
- package/dist/bitcoin-utils.js.map +1 -1
- package/dist/bundle.js +9 -5
- package/dist/mempool-space.d.ts +69 -0
- package/dist/mempool-space.d.ts.map +1 -0
- package/dist/mempool-space.js +266 -0
- package/dist/mempool-space.js.map +1 -0
- package/dist/sign/sign-transaction.d.ts.map +1 -1
- package/dist/sign/sign-transaction.js +60 -2
- package/dist/sign/sign-transaction.js.map +1 -1
- package/dist/transaction-builder/transaction-builder.d.ts.map +1 -1
- package/dist/transaction-builder/transaction-builder.js +23 -21
- package/dist/transaction-builder/transaction-builder.js.map +1 -1
- package/package.json +15 -11
- package/src/bitcoin-base.ts +5 -2
- package/src/bitcoin-interface.ts +16 -15
- package/src/bitcoin-utils.ts +72 -73
- package/src/mempool-space.ts +255 -0
- package/src/sign/sign-transaction.ts +49 -48
- package/src/transaction-builder/transaction-builder.ts +38 -20
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teleportdao/bitcoin",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.9",
|
|
4
4
|
"description": "teleswap bitcoin package",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"browser": "dist/bundle.js",
|
|
@@ -8,30 +8,34 @@
|
|
|
8
8
|
"scripts": {
|
|
9
9
|
"test": "echo \"Error: no test specified\" && exit 2",
|
|
10
10
|
"build:tsc": "tsc",
|
|
11
|
-
"build:watch": "npx
|
|
11
|
+
"build:watch": "npx tsc --watch",
|
|
12
12
|
"build": "npx tsc && npx webpack"
|
|
13
13
|
},
|
|
14
14
|
"author": "",
|
|
15
15
|
"license": "ISC",
|
|
16
16
|
"dependencies": {
|
|
17
|
+
"@bitcoinerlab/secp256k1": "^1.0.5",
|
|
17
18
|
"@teleportdao/configs": "^1.4.6",
|
|
18
|
-
"@teleportdao/providers": "^1.4.
|
|
19
|
+
"@teleportdao/providers": "^1.4.9",
|
|
19
20
|
"axios": "^0.27.2",
|
|
20
21
|
"bignumber.js": "^9.1.1",
|
|
21
|
-
"bip32": "^
|
|
22
|
-
"bip39": "^3.0
|
|
23
|
-
"bitcoinjs-
|
|
24
|
-
"
|
|
22
|
+
"bip32": "^4.0.0",
|
|
23
|
+
"bip39": "^3.1.0",
|
|
24
|
+
"bitcoinjs-ecpair": "npm:bitcoinjs-lib@^5.2.0",
|
|
25
|
+
"bitcoinjs-lib": "^6.1.5",
|
|
25
26
|
"coinselect": "^3.1.13",
|
|
26
|
-
"ecpair": "^2.1
|
|
27
|
+
"ecpair": "^2.0.1",
|
|
27
28
|
"merkle-lib": "^2.0.10",
|
|
28
29
|
"merkle-patricia-tree": "^2.3.2",
|
|
29
|
-
"
|
|
30
|
-
"
|
|
30
|
+
"npm": "^10.2.3",
|
|
31
|
+
"uninstall": "^0.0.0",
|
|
31
32
|
"varuint-bitcoin": "^1.1.2"
|
|
32
33
|
},
|
|
33
34
|
"publishConfig": {
|
|
34
35
|
"access": "public"
|
|
35
36
|
},
|
|
36
|
-
"gitHead": "
|
|
37
|
+
"gitHead": "cb98230f4b9dddad7318f3830bc1890e20a3cda4",
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@babel/preset-react": "^7.23.3"
|
|
40
|
+
}
|
|
37
41
|
}
|
package/src/bitcoin-base.ts
CHANGED
|
@@ -6,13 +6,17 @@ import type { ExtendedUtxo, SignerInfo, Target } from "./transaction-builder/tra
|
|
|
6
6
|
import BitcoinSign from "./sign/sign-transaction"
|
|
7
7
|
|
|
8
8
|
import * as bip39 from "bip39"
|
|
9
|
-
import * as bip32 from "bip32"
|
|
10
9
|
import { hdWalletPath } from "@teleportdao/configs"
|
|
11
10
|
import { getPubKeyFromPrivateKeyHex } from "./bitcoin-utils"
|
|
12
11
|
import networks from "./utils/networks"
|
|
13
12
|
import { Network, Payment } from "bitcoinjs-lib"
|
|
14
13
|
import { BitcoinInterface } from "./bitcoin-interface"
|
|
15
14
|
|
|
15
|
+
import BIP32Factory from "bip32"
|
|
16
|
+
import ecc from "@bitcoinerlab/secp256k1"
|
|
17
|
+
|
|
18
|
+
const bip32 = BIP32Factory(ecc)
|
|
19
|
+
|
|
16
20
|
class BitcoinBase {
|
|
17
21
|
network: Network
|
|
18
22
|
hdWalletPath: {
|
|
@@ -244,5 +248,4 @@ class BitcoinBase {
|
|
|
244
248
|
return txId
|
|
245
249
|
}
|
|
246
250
|
}
|
|
247
|
-
|
|
248
251
|
export { BitcoinBase }
|
package/src/bitcoin-interface.ts
CHANGED
|
@@ -11,14 +11,15 @@ import { getBurnTransactionInfo } from "./helper/burn-request-helper"
|
|
|
11
11
|
import { BitcoinInterfaceUtils } from "./bitcoin-interface-utils"
|
|
12
12
|
import type { BitcoinConnectionInfo } from "./transaction-builder/bitcoin-transaction-builder"
|
|
13
13
|
import type { SignerInfo } from "./transaction-builder/transaction-builder"
|
|
14
|
+
import ms from "./mempool-space"
|
|
14
15
|
|
|
15
16
|
export class BitcoinInterface extends BitcoinInterfaceUtils {
|
|
16
17
|
rpcProvider?: bitcoinProvider.RPC
|
|
17
18
|
apiProviderName!: string
|
|
18
19
|
// todo : add provider type
|
|
19
20
|
minTeleporterFeeAmount: number
|
|
20
|
-
provider:
|
|
21
|
-
apiProvider!: bitcoinProvider.ApiProviders.BlockStream
|
|
21
|
+
provider: any
|
|
22
|
+
apiProvider!: bitcoinProvider.ApiProviders.BlockStream | bitcoinProvider.ApiProviders.NowNodes
|
|
22
23
|
constructor(
|
|
23
24
|
connectionInfo: BitcoinConnectionInfo,
|
|
24
25
|
networkName: string,
|
|
@@ -33,7 +34,7 @@ export class BitcoinInterface extends BitcoinInterfaceUtils {
|
|
|
33
34
|
|
|
34
35
|
if (connectionInfo.api.enabled) {
|
|
35
36
|
this.apiProviderName = connectionInfo.api.provider
|
|
36
|
-
this.apiProvider = bitcoinProvider.getApiProvider(connectionInfo.api as any, networkName)
|
|
37
|
+
this.apiProvider = bitcoinProvider.getApiProvider(connectionInfo.api as any, networkName)!
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
this.minTeleporterFeeAmount = config.minTeleporterFeeAmount
|
|
@@ -63,12 +64,8 @@ export class BitcoinInterface extends BitcoinInterfaceUtils {
|
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
// speed : low normal fast
|
|
66
|
-
async getFeeRate(speed
|
|
67
|
-
|
|
68
|
-
throw new Error("incorrect speed")
|
|
69
|
-
}
|
|
70
|
-
let fee = await this.provider.getFeeRate(speed)
|
|
71
|
-
return +fee
|
|
67
|
+
async getFeeRate(speed?: "normal" | "slow" | "fast") {
|
|
68
|
+
return new ms(this.testnet).getRecommendedFeeRate(speed)
|
|
72
69
|
}
|
|
73
70
|
|
|
74
71
|
// ----------- specific
|
|
@@ -219,7 +216,7 @@ export class BitcoinInterface extends BitcoinInterfaceUtils {
|
|
|
219
216
|
results.push(
|
|
220
217
|
result
|
|
221
218
|
.map((utxos, i) =>
|
|
222
|
-
utxos.map((tx) => ({
|
|
219
|
+
utxos.map((tx: any) => ({
|
|
223
220
|
hash: tx.txId,
|
|
224
221
|
value: tx.value,
|
|
225
222
|
index: tx.index,
|
|
@@ -237,7 +234,7 @@ export class BitcoinInterface extends BitcoinInterfaceUtils {
|
|
|
237
234
|
throw new Error("this function need an api provider")
|
|
238
235
|
}
|
|
239
236
|
let utxos = (await this.apiProvider.getUtxos(address)) ?? []
|
|
240
|
-
return utxos.reduce((a, tx) => a + Number(tx.value), 0)
|
|
237
|
+
return utxos.reduce((a: any, tx: any) => a + Number(tx.value), 0)
|
|
241
238
|
}
|
|
242
239
|
|
|
243
240
|
// ------------------ utxo provider + rpc or blockstream----------------
|
|
@@ -269,9 +266,11 @@ export class BitcoinInterface extends BitcoinInterfaceUtils {
|
|
|
269
266
|
}
|
|
270
267
|
let blockTxs = []
|
|
271
268
|
for (let blockNumber = +startBlockNumber + 1; blockNumber <= endBlockNumber; blockNumber += 1) {
|
|
272
|
-
|
|
269
|
+
console.log(blockNumber)
|
|
270
|
+
|
|
271
|
+
const response = await this.getBlockTransactions(addresses, blockNumber, inputTxIds)
|
|
273
272
|
blockTxs.push(response)
|
|
274
|
-
await sleep(200)
|
|
273
|
+
// await sleep(200)
|
|
275
274
|
}
|
|
276
275
|
blockTxs = await Promise.all(blockTxs)
|
|
277
276
|
return blockTxs.flat(1)
|
|
@@ -291,7 +290,7 @@ export class BitcoinInterface extends BitcoinInterfaceUtils {
|
|
|
291
290
|
if (this.apiProviderName !== "BlockStream") {
|
|
292
291
|
throw new Error("just support BlockStream as api provider for this function")
|
|
293
292
|
}
|
|
294
|
-
let txs = await this.apiProvider.getTransactionHistoryForMultipleAddresses(
|
|
293
|
+
let txs = await (this.apiProvider as any).getTransactionHistoryForMultipleAddresses(
|
|
295
294
|
addresses,
|
|
296
295
|
startBlockNumber,
|
|
297
296
|
)
|
|
@@ -303,7 +302,9 @@ export class BitcoinInterface extends BitcoinInterfaceUtils {
|
|
|
303
302
|
if (this.apiProviderName !== "BlockStream") {
|
|
304
303
|
throw new Error("teleporter just support BlockStream as api provider")
|
|
305
304
|
}
|
|
306
|
-
let txs = await this.apiProvider.getMempoolTransactionHistoryForMultipleAddresses(
|
|
305
|
+
let txs = await (this.apiProvider as any).getMempoolTransactionHistoryForMultipleAddresses(
|
|
306
|
+
addresses,
|
|
307
|
+
)
|
|
307
308
|
return txs.flat(1)
|
|
308
309
|
}
|
|
309
310
|
|
package/src/bitcoin-utils.ts
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import * as bip39 from "bip39"
|
|
2
|
-
import * as bip32 from "bip32"
|
|
3
1
|
import networks from "./utils/networks"
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
import * as bip39 from "bip39"
|
|
4
|
+
import BIP32Factory from "bip32"
|
|
5
|
+
import * as ecc from "@bitcoinerlab/secp256k1"
|
|
8
6
|
import * as bitcoin from "bitcoinjs-lib"
|
|
7
|
+
import * as bitcoinEcPair from "bitcoinjs-ecpair"
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const ECPair = bitcoin.ECPair
|
|
9
|
+
const bip32 = BIP32Factory(ecc)
|
|
10
|
+
const ECPair = bitcoinEcPair.ECPair
|
|
13
11
|
|
|
14
12
|
let varUnit = require("varuint-bitcoin")
|
|
15
13
|
const fastRoot = require("merkle-lib/fastRoot")
|
|
@@ -46,6 +44,44 @@ export function generateMnemonic() {
|
|
|
46
44
|
return mnemonic
|
|
47
45
|
}
|
|
48
46
|
|
|
47
|
+
export function reverseBytes(hexInput: string) {
|
|
48
|
+
return Buffer.from(hexInput, "hex").reverse().toString("hex")
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function getPublicKeyHexByXpubAndIndex(
|
|
52
|
+
xpub: string,
|
|
53
|
+
index = 0,
|
|
54
|
+
isChange = false,
|
|
55
|
+
network = networks.bitcoin,
|
|
56
|
+
) {
|
|
57
|
+
const node = bip32.fromBase58(xpub, network)
|
|
58
|
+
return node
|
|
59
|
+
.derive(isChange ? 1 : 0)
|
|
60
|
+
.derive(index)
|
|
61
|
+
.publicKey.toString("hex")
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function getPubKeyFromPrivateKeyWIF(
|
|
65
|
+
privateKeyWIF: string,
|
|
66
|
+
network = bitcoin.networks.bitcoin,
|
|
67
|
+
) {
|
|
68
|
+
let key = ECPair.fromWIF(privateKeyWIF, network)
|
|
69
|
+
return key.publicKey
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function getPubKeyFromPrivateKeyHex(
|
|
73
|
+
privateKeyHex: string,
|
|
74
|
+
network = bitcoin.networks.bitcoin,
|
|
75
|
+
) {
|
|
76
|
+
let key = ECPair.fromPrivateKey(Buffer.from(privateKeyHex, "hex"), { network })
|
|
77
|
+
return key.publicKey
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function getPrivateKeyHexFromWIF(privateKeyWIF: string, network = bitcoin.networks.bitcoin) {
|
|
81
|
+
let key = ECPair.fromWIF(privateKeyWIF, network)
|
|
82
|
+
return key.privateKey!.toString("hex")
|
|
83
|
+
}
|
|
84
|
+
|
|
49
85
|
export function parseRawTransaction(rawTransaction: string) {
|
|
50
86
|
const size = {
|
|
51
87
|
version: 4,
|
|
@@ -102,44 +138,6 @@ export function parseRawTransaction(rawTransaction: string) {
|
|
|
102
138
|
return { version, flag, vin, vout, witness, locktime }
|
|
103
139
|
}
|
|
104
140
|
|
|
105
|
-
export function reverseBytes(hexInput: string) {
|
|
106
|
-
return Buffer.from(hexInput, "hex").reverse().toString("hex")
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export function getPublicKeyHexByXpubAndIndex(
|
|
110
|
-
xpub: string,
|
|
111
|
-
index = 0,
|
|
112
|
-
isChange = false,
|
|
113
|
-
network = networks.bitcoin,
|
|
114
|
-
) {
|
|
115
|
-
const node = bip32.fromBase58(xpub, network)
|
|
116
|
-
return node
|
|
117
|
-
.derive(isChange ? 1 : 0)
|
|
118
|
-
.derive(index)
|
|
119
|
-
.publicKey.toString("hex")
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export function getPubKeyFromPrivateKeyWIF(
|
|
123
|
-
privateKeyWIF: string,
|
|
124
|
-
network = bitcoin.networks.bitcoin,
|
|
125
|
-
) {
|
|
126
|
-
let key = bitcoin.ECPair.fromWIF(privateKeyWIF, network)
|
|
127
|
-
return key.publicKey
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export function getPubKeyFromPrivateKeyHex(
|
|
131
|
-
privateKeyHex: string,
|
|
132
|
-
network = bitcoin.networks.bitcoin,
|
|
133
|
-
) {
|
|
134
|
-
let key = bitcoin.ECPair.fromPrivateKey(Buffer.from(privateKeyHex, "hex"), { network })
|
|
135
|
-
return key.publicKey
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export function getPrivateKeyHexFromWIF(privateKeyWIF: string, network = bitcoin.networks.bitcoin) {
|
|
139
|
-
let key = bitcoin.ECPair.fromWIF(privateKeyWIF, network)
|
|
140
|
-
return key.privateKey!.toString("hex")
|
|
141
|
-
}
|
|
142
|
-
|
|
143
141
|
export function calculateMerkleProof(
|
|
144
142
|
blockTransactions: string[],
|
|
145
143
|
txId: string,
|
|
@@ -202,6 +200,7 @@ export function parseBlockHeader(headerHex: string) {
|
|
|
202
200
|
}
|
|
203
201
|
}
|
|
204
202
|
|
|
203
|
+
// used in block parser functions ( newt 2 functions )
|
|
205
204
|
export function convertBitcoinScriptToAddress(script: Buffer, network = bitcoin.networks.bitcoin) {
|
|
206
205
|
try {
|
|
207
206
|
return bitcoin.address.fromOutputScript(script, network)
|
|
@@ -414,11 +413,11 @@ function toXOnlyPublicKey(pubKey: Buffer) {
|
|
|
414
413
|
|
|
415
414
|
export function getAddressType(address: string, network = bitcoin.networks.bitcoin) {
|
|
416
415
|
if (address.startsWith(`${network.bech32}1p`)) {
|
|
417
|
-
// todo
|
|
416
|
+
// todo validate p2tr address
|
|
418
417
|
return "p2tr"
|
|
419
418
|
}
|
|
420
419
|
if (address.startsWith(network.bech32)) {
|
|
421
|
-
|
|
420
|
+
bitcoin.address.fromBech32(address)
|
|
422
421
|
return "p2wpkh"
|
|
423
422
|
}
|
|
424
423
|
let base58Data = bitcoin.address.fromBase58Check(address)
|
|
@@ -462,12 +461,12 @@ export function createAddressObjectByScript(
|
|
|
462
461
|
network,
|
|
463
462
|
})
|
|
464
463
|
break
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
464
|
+
case "p2tr":
|
|
465
|
+
addressObject = bitcoin.payments.p2tr({
|
|
466
|
+
output: script,
|
|
467
|
+
network,
|
|
468
|
+
})
|
|
469
|
+
break
|
|
471
470
|
default:
|
|
472
471
|
throw new Error("address type is incorrect")
|
|
473
472
|
}
|
|
@@ -504,13 +503,13 @@ export function createAddressObjectByHash(
|
|
|
504
503
|
network,
|
|
505
504
|
})
|
|
506
505
|
break
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
506
|
+
case "p2tr":
|
|
507
|
+
// here hash is the public key of tweaked private key (internal public key)
|
|
508
|
+
addressObject = bitcoin.payments.p2tr({
|
|
509
|
+
pubkey: hash,
|
|
510
|
+
network,
|
|
511
|
+
})
|
|
512
|
+
break
|
|
514
513
|
default:
|
|
515
514
|
throw new Error("address type is incorrect")
|
|
516
515
|
}
|
|
@@ -544,12 +543,12 @@ export function createAddressObjectByPublicKey(
|
|
|
544
543
|
})
|
|
545
544
|
break
|
|
546
545
|
case "p2tr":
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
546
|
+
// this public key is public key of main private key
|
|
547
|
+
addressObject = bitcoin.payments.p2tr({
|
|
548
|
+
internalPubkey: toXOnlyPublicKey(publicKey),
|
|
549
|
+
network,
|
|
550
|
+
})
|
|
551
|
+
break
|
|
553
552
|
default:
|
|
554
553
|
throw new Error("address type is incorrect")
|
|
555
554
|
}
|
|
@@ -578,12 +577,12 @@ export function createAddressObjectByAddress(address: string, network = bitcoin.
|
|
|
578
577
|
network,
|
|
579
578
|
})
|
|
580
579
|
break
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
580
|
+
case "p2tr":
|
|
581
|
+
addressObject = bitcoin.payments.p2tr({
|
|
582
|
+
address,
|
|
583
|
+
network,
|
|
584
|
+
})
|
|
585
|
+
break
|
|
587
586
|
default:
|
|
588
587
|
throw new Error("address type is incorrect")
|
|
589
588
|
}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { AxiosInstance } from "axios"
|
|
2
|
+
import { getAxiosInstance } from "./utils/tools"
|
|
3
|
+
|
|
4
|
+
class BlockStream {
|
|
5
|
+
api: AxiosInstance
|
|
6
|
+
constructor(
|
|
7
|
+
testnet = false,
|
|
8
|
+
// not used yet
|
|
9
|
+
_config?: {
|
|
10
|
+
token?: string
|
|
11
|
+
},
|
|
12
|
+
) {
|
|
13
|
+
const baseUrl = testnet
|
|
14
|
+
? "https://mempool.space/testnet/api/v1"
|
|
15
|
+
: "https://mempool.space/api/v1"
|
|
16
|
+
this.api = getAxiosInstance({
|
|
17
|
+
baseUrl,
|
|
18
|
+
} as any)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async getOutspend(txId: string, index: number) {
|
|
22
|
+
let response = await this.api.get(`/tx/${txId}/outspend/${index}`)
|
|
23
|
+
return response.data
|
|
24
|
+
}
|
|
25
|
+
async getOutspends(txId: string) {
|
|
26
|
+
let response = await this.api.get(`/tx/${txId}/outspends`)
|
|
27
|
+
return response.data
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async getLatestBlockNumber() {
|
|
31
|
+
const result = await this.api.get(`/blocks/tip/height`)
|
|
32
|
+
return result.data
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async getBlockHash(blockNumber: number) {
|
|
36
|
+
const result = await this.api.get(`/block-height/${blockNumber}`)
|
|
37
|
+
return result.data
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async getBlockHeaderHex(blockNumber: number) {
|
|
41
|
+
const hash = await this.getBlockHash(blockNumber)
|
|
42
|
+
const result = await this.api.get(`/block/${hash}/header`)
|
|
43
|
+
return result.data
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// --------------
|
|
47
|
+
|
|
48
|
+
async getConfirmedTransactions(userAddress: string, lastReceivedTxId = "") {
|
|
49
|
+
const result = await this.api.get(`/address/${userAddress}/txs/chain/${lastReceivedTxId}`)
|
|
50
|
+
return result.data
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async getMempoolTransactions(userAddress: string) {
|
|
54
|
+
const result = await this.api.get(`/address/${userAddress}/txs/mempool`)
|
|
55
|
+
return result.data
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async getTransaction(txId: string) {
|
|
59
|
+
const result = await this.api.get(`/tx/${txId}`)
|
|
60
|
+
let tx = result.data
|
|
61
|
+
return {
|
|
62
|
+
txId: tx.txid,
|
|
63
|
+
version: tx.version,
|
|
64
|
+
locktime: tx.locktime,
|
|
65
|
+
blockTime: tx.status.block_time,
|
|
66
|
+
blockNumber: tx.status.block_height || null,
|
|
67
|
+
blockHash: tx.status.block_hash || null,
|
|
68
|
+
vout: tx.vout.map((vo: any) => ({
|
|
69
|
+
address: vo.scriptpubkey_address || null,
|
|
70
|
+
script: vo.scriptpubkey,
|
|
71
|
+
value: vo.value,
|
|
72
|
+
})),
|
|
73
|
+
vin: tx.vin.map((vi: any) => ({
|
|
74
|
+
txId: vi.txid,
|
|
75
|
+
index: vi.vout,
|
|
76
|
+
address: vi.prevout.scriptpubkey_address || null,
|
|
77
|
+
script: vi.prevout.scriptpubkey,
|
|
78
|
+
value: vi.prevout.value,
|
|
79
|
+
})),
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async getRawTransaction(txId: string) {
|
|
84
|
+
const result = await this.api.get(`/tx/${txId}/hex`)
|
|
85
|
+
return result.data
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async getTransactionHistory(userAddress: string, blockNumber = 0, lastSeenTxId = undefined) {
|
|
89
|
+
let maximumTxsLength = 15
|
|
90
|
+
// get transactions from lastSeenTxId to the end
|
|
91
|
+
let fetchTxs = true
|
|
92
|
+
let allResults = []
|
|
93
|
+
let lastReceivedTxId = ""
|
|
94
|
+
while (fetchTxs) {
|
|
95
|
+
let result = await this.getConfirmedTransactions(userAddress, lastReceivedTxId)
|
|
96
|
+
let lastSeenTxIdIndex = result.findIndex((tx: any) => tx.txid === lastSeenTxId)
|
|
97
|
+
result = result.filter((_value: any) => +_value.status.block_height > blockNumber)
|
|
98
|
+
result =
|
|
99
|
+
lastSeenTxIdIndex < 0
|
|
100
|
+
? result
|
|
101
|
+
: result.filter((_value: any, index: number) => index < lastSeenTxIdIndex)
|
|
102
|
+
allResults.push(...result)
|
|
103
|
+
lastReceivedTxId = result[result.length - 1]?.txid
|
|
104
|
+
fetchTxs = result.length === maximumTxsLength && lastSeenTxIdIndex < 0 && result.length !== 0
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return allResults.map((tx) => ({
|
|
108
|
+
address: userAddress,
|
|
109
|
+
txId: tx.txid,
|
|
110
|
+
version: tx.version,
|
|
111
|
+
locktime: tx.locktime,
|
|
112
|
+
blockNumber: tx.status.block_height || null,
|
|
113
|
+
blockHash: tx.status.block_hash || null,
|
|
114
|
+
blockTime: tx.status.block_time || null,
|
|
115
|
+
vout: tx.vout.map((vo: any) => ({
|
|
116
|
+
address: vo.scriptpubkey_address || null,
|
|
117
|
+
script: vo.scriptpubkey,
|
|
118
|
+
value: vo.value,
|
|
119
|
+
})),
|
|
120
|
+
vin: tx.vin.map((vi: any) => ({
|
|
121
|
+
txId: vi.txid,
|
|
122
|
+
index: vi.vout,
|
|
123
|
+
address: vi.prevout.scriptpubkey_address || null,
|
|
124
|
+
script: vi.prevout.scriptpubkey,
|
|
125
|
+
value: vi.prevout.value,
|
|
126
|
+
})),
|
|
127
|
+
}))
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async getMempoolTransactionHistory(userAddress: string) {
|
|
131
|
+
let result = await this.getMempoolTransactions(userAddress)
|
|
132
|
+
return result.map((tx: any) => ({
|
|
133
|
+
address: userAddress,
|
|
134
|
+
txId: tx.txid,
|
|
135
|
+
version: tx.version,
|
|
136
|
+
locktime: tx.locktime,
|
|
137
|
+
vout: tx.vout.map((vo: any) => ({
|
|
138
|
+
address: vo.scriptpubkey_address || null,
|
|
139
|
+
script: vo.scriptpubkey,
|
|
140
|
+
value: vo.value,
|
|
141
|
+
})),
|
|
142
|
+
vin: tx.vin.map((vi: any) => ({
|
|
143
|
+
txId: vi.txid,
|
|
144
|
+
index: vi.vout,
|
|
145
|
+
address: vi.prevout.scriptpubkey_address || null,
|
|
146
|
+
script: vi.prevout.scriptpubkey,
|
|
147
|
+
value: vi.prevout.value,
|
|
148
|
+
})),
|
|
149
|
+
}))
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async getMempoolTransactionHistoryForMultipleAddresses(addresses: string[], blockNumber = 0) {
|
|
153
|
+
const allPromises = []
|
|
154
|
+
for (let address of addresses) {
|
|
155
|
+
let promise = await this.getMempoolTransactionHistory(address)
|
|
156
|
+
allPromises.push(promise)
|
|
157
|
+
}
|
|
158
|
+
let result = await Promise.all(allPromises)
|
|
159
|
+
return result
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async getTransactionHistoryForMultipleAddresses(userAddresses: string[], blockNumber = 0) {
|
|
163
|
+
const allPromises = []
|
|
164
|
+
for (let address of userAddresses) {
|
|
165
|
+
let promise = await this.getTransactionHistory(address, blockNumber)
|
|
166
|
+
allPromises.push(promise)
|
|
167
|
+
}
|
|
168
|
+
let result = await Promise.all(allPromises)
|
|
169
|
+
return result
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async getUtxos(userAddress: string): Promise<
|
|
173
|
+
{
|
|
174
|
+
address: string
|
|
175
|
+
txId: string
|
|
176
|
+
index: number
|
|
177
|
+
value: number
|
|
178
|
+
blockNumber?: number
|
|
179
|
+
}[]
|
|
180
|
+
> {
|
|
181
|
+
const result = await this.api.get(`/address/${userAddress}/utxo`)
|
|
182
|
+
return result.data.map((tx: any) => ({
|
|
183
|
+
address: userAddress,
|
|
184
|
+
txId: tx.txid,
|
|
185
|
+
index: tx.vout,
|
|
186
|
+
value: tx.value,
|
|
187
|
+
blockNumber: tx.status?.block_height || undefined,
|
|
188
|
+
}))
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async getBalance(address: string) {
|
|
192
|
+
let utxos = await this.getUtxos(address)
|
|
193
|
+
return utxos.reduce((a: any, tx: any) => a + Number(tx.value), 0)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async getBlockTransactionIds(blockHash: string) {
|
|
197
|
+
let result = await this.api.get(`/block/${blockHash}/txids`)
|
|
198
|
+
return result.data
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async getFeeRate(speed: "normal" | "slow" | "fast" = "normal") {
|
|
202
|
+
let result = await this.api.get(`/fee-estimates`)
|
|
203
|
+
let fees = {
|
|
204
|
+
slow: +result.data[10],
|
|
205
|
+
normal: +result.data[6],
|
|
206
|
+
fast: +result.data[3],
|
|
207
|
+
}
|
|
208
|
+
return fees[speed] || fees.normal
|
|
209
|
+
}
|
|
210
|
+
async getRecommendedFeeRate(speed: "normal" | "slow" | "fast" = "normal") {
|
|
211
|
+
let result = await this.api.get(`/fees/recommended`)
|
|
212
|
+
|
|
213
|
+
let fees = {
|
|
214
|
+
slow: +result.data.economyFee,
|
|
215
|
+
normal: +result.data.halfHourFee,
|
|
216
|
+
fast: +result.data.fastestFee,
|
|
217
|
+
}
|
|
218
|
+
return fees[speed] || fees.normal
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async sendRawTransaction(rawTransaction: string) {
|
|
222
|
+
const result = await this.api.post(`/tx`, rawTransaction)
|
|
223
|
+
return result.data
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// not used
|
|
227
|
+
|
|
228
|
+
async getMerkleProof(txId: string) {
|
|
229
|
+
let result = (await this.api.get(`/tx/${txId}/merkle-proof`)).data
|
|
230
|
+
let intermediateNodes = result.merkle.reduce(
|
|
231
|
+
(a: any, merkle: any) => a + Buffer.from(merkle, "hex").reverse().toString("hex"),
|
|
232
|
+
"0x",
|
|
233
|
+
)
|
|
234
|
+
let transactionIndex = result.pos
|
|
235
|
+
return {
|
|
236
|
+
intermediateNodes,
|
|
237
|
+
transactionIndex,
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
async getLatestBlock() {
|
|
242
|
+
const result = await this.api.get(`/blocks`)
|
|
243
|
+
// 10 newest blocks
|
|
244
|
+
const blocks = result.data
|
|
245
|
+
return blocks[0]
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async getBlock(blockNumber: number) {
|
|
249
|
+
const blockHash = await this.getBlockHash(blockNumber)
|
|
250
|
+
const result = await this.api.get(`/block/${blockHash}`)
|
|
251
|
+
return result.data
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export default BlockStream
|