@teleportdao/bitcoin 1.4.8 → 1.5.0
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/.tmp/check.ts +16 -0
- package/dist/bitcoin-base.d.ts +7 -0
- package/dist/bitcoin-base.d.ts.map +1 -1
- package/dist/bitcoin-base.js +21 -1
- package/dist/bitcoin-base.js.map +1 -1
- package/dist/bitcoin-interface-utils.d.ts +2 -2
- package/dist/bitcoin-interface.d.ts +2 -2
- package/dist/bitcoin-interface.d.ts.map +1 -1
- package/dist/bitcoin-interface.js +6 -9
- 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/helper/teleport-request-helper.d.ts.map +1 -1
- package/dist/helper/teleport-request-helper.js +2 -2
- package/dist/helper/teleport-request-helper.js.map +1 -1
- 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/teleport-dao-payments.d.ts +5 -3
- package/dist/teleport-dao-payments.d.ts.map +1 -1
- package/dist/teleport-dao-payments.js +6 -5
- package/dist/teleport-dao-payments.js.map +1 -1
- package/package.json +15 -11
- package/src/bitcoin-base.ts +29 -2
- package/src/bitcoin-interface.ts +18 -9
- package/src/bitcoin-utils.ts +72 -73
- package/src/helper/teleport-request-helper.js +5 -3
- package/src/sign/sign-transaction.ts +49 -48
- package/src/teleport-dao-payments.ts +8 -2
- package/src/mempool-space.ts +0 -255
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
|
}
|
|
@@ -86,9 +86,11 @@ function parseRawRequest(opReturnData) {
|
|
|
86
86
|
let appId = Number(`0x${appIdHex}`) // 2 bytes
|
|
87
87
|
|
|
88
88
|
// get type base on appId
|
|
89
|
-
let requestType = teleportRequestsType.find(
|
|
90
|
-
(
|
|
91
|
-
|
|
89
|
+
let requestType = Object.keys(teleportRequestsType).find(
|
|
90
|
+
(key) =>
|
|
91
|
+
appId >= teleportRequestsType[key].appIdRange[0] &&
|
|
92
|
+
appId <= teleportRequestsType[key].appIdRange[1],
|
|
93
|
+
)
|
|
92
94
|
|
|
93
95
|
switch (requestType) {
|
|
94
96
|
case "transfer":
|
|
@@ -1,16 +1,44 @@
|
|
|
1
|
-
import { Psbt, crypto, Network
|
|
2
|
-
// import
|
|
3
|
-
|
|
4
|
-
import
|
|
5
|
-
|
|
1
|
+
import { Psbt, crypto, Network } from "bitcoinjs-lib"
|
|
2
|
+
// import BIP32Factory from "bip32"
|
|
3
|
+
import ecc from "@bitcoinerlab/secp256k1"
|
|
4
|
+
import * as bitcoinEcPair from "bitcoinjs-ecpair"
|
|
5
|
+
const ECPair = bitcoinEcPair.ECPair
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
function tapTweakHash(pubKey: Buffer, h?: Buffer) {
|
|
8
|
+
return crypto.taggedHash("TapTweak", Buffer.concat(h ? [pubKey, h] : [pubKey]))
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function tweakSigner(
|
|
12
|
+
privateKey: Buffer,
|
|
13
|
+
opts = {} as {
|
|
14
|
+
[key: string]: Buffer
|
|
15
|
+
},
|
|
16
|
+
network: Network,
|
|
17
|
+
) {
|
|
18
|
+
let newPrv = privateKey
|
|
19
|
+
let keyPair = ECPair.fromPrivateKey(privateKey, {
|
|
20
|
+
network: network,
|
|
21
|
+
compressed: true,
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
if (!keyPair.privateKey) throw new Error("private key not exist")
|
|
25
|
+
|
|
26
|
+
if (keyPair.publicKey.toString("hex").startsWith("03")) {
|
|
27
|
+
newPrv = ecc.privateNegate(keyPair.privateKey) as Buffer
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const tweakedPrivateKey = ecc.privateAdd(
|
|
31
|
+
newPrv,
|
|
32
|
+
tapTweakHash(Buffer.from(keyPair.publicKey.toString("hex").slice(2), "hex"), opts?.tweakHash),
|
|
33
|
+
)
|
|
34
|
+
if (!tweakedPrivateKey) {
|
|
35
|
+
throw new Error("Invalid tweaked private key!")
|
|
36
|
+
}
|
|
10
37
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
38
|
+
return ECPair.fromPrivateKey(Buffer.from(tweakedPrivateKey), {
|
|
39
|
+
network: network,
|
|
40
|
+
})
|
|
41
|
+
}
|
|
14
42
|
|
|
15
43
|
class BitcoinLikeSignTransaction {
|
|
16
44
|
network: Network
|
|
@@ -18,38 +46,6 @@ class BitcoinLikeSignTransaction {
|
|
|
18
46
|
this.network = network
|
|
19
47
|
}
|
|
20
48
|
|
|
21
|
-
// tweakSigner(
|
|
22
|
-
// privateKey: Buffer,
|
|
23
|
-
// opts = {} as {
|
|
24
|
-
// [key: string]: Buffer
|
|
25
|
-
// },
|
|
26
|
-
// ) {
|
|
27
|
-
// let newPrv = privateKey
|
|
28
|
-
// let keyPair = ECPair.fromPrivateKey(privateKey, {
|
|
29
|
-
// network: this.network,
|
|
30
|
-
// compressed: true,
|
|
31
|
-
// })
|
|
32
|
-
|
|
33
|
-
// if (!keyPair.privateKey) throw new Error("private key not exist")
|
|
34
|
-
|
|
35
|
-
// if (keyPair.publicKey.toString("hex").startsWith("03")) {
|
|
36
|
-
// newPrv = ecc.privateNegate(keyPair.privateKey) as Buffer
|
|
37
|
-
// }
|
|
38
|
-
|
|
39
|
-
// const tweakedPrivateKey = ecc.privateAdd(
|
|
40
|
-
// newPrv,
|
|
41
|
-
// tapTweakHash(Buffer.from(keyPair.publicKey.toString("hex").slice(2), "hex"), opts?.tweakHash),
|
|
42
|
-
// )
|
|
43
|
-
// if (!tweakedPrivateKey) {
|
|
44
|
-
// throw new Error("Invalid tweaked private key!")
|
|
45
|
-
// }
|
|
46
|
-
|
|
47
|
-
// return ECPair.fromPrivateKey(Buffer.from(tweakedPrivateKey), {
|
|
48
|
-
// network: this.network,
|
|
49
|
-
// })
|
|
50
|
-
// }
|
|
51
|
-
|
|
52
|
-
// todo : change to psbt
|
|
53
49
|
async signPsbt(
|
|
54
50
|
unsignedPsbt: {
|
|
55
51
|
unsignedTransaction: string
|
|
@@ -68,7 +64,13 @@ class BitcoinLikeSignTransaction {
|
|
|
68
64
|
let numberOfInputs = psbt.inputCount
|
|
69
65
|
|
|
70
66
|
for (let i = 0; i < numberOfInputs; i += 1) {
|
|
71
|
-
|
|
67
|
+
let type = psbt.getInputType(i)
|
|
68
|
+
if (type === "nonstandard") {
|
|
69
|
+
let a = tweakSigner(privateKey, undefined, this.network)
|
|
70
|
+
await psbt.signInputAsync(i, a)
|
|
71
|
+
} else {
|
|
72
|
+
await psbt.signInputAsync(i, keyPair)
|
|
73
|
+
}
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
// psbt.signAllInputs(keyPair)
|
|
@@ -82,13 +84,12 @@ class BitcoinLikeSignTransaction {
|
|
|
82
84
|
)
|
|
83
85
|
const psbt =
|
|
84
86
|
finals.length === 1 ? finals[0] : new Psbt({ network: this.network }).combine(...finals)
|
|
87
|
+
|
|
85
88
|
psbt.finalizeAllInputs()
|
|
86
89
|
|
|
87
|
-
// psbt.finalizeAllInputs()
|
|
88
|
-
// const tx = psbt.extractTransaction()
|
|
89
|
-
// const rawTx = tx.toBuffer()
|
|
90
|
-
// const hex = rawTx.toString("hex")
|
|
91
90
|
let finalizeTx = psbt.extractTransaction()
|
|
91
|
+
// const rawTx = finalizeTx.toBuffer()
|
|
92
|
+
// const hex = rawTx.toString("hex")
|
|
92
93
|
return finalizeTx.toHex()
|
|
93
94
|
}
|
|
94
95
|
}
|
|
@@ -18,6 +18,7 @@ export type TransferRequest = {
|
|
|
18
18
|
deadline?: number // 4 bytes
|
|
19
19
|
isFixedToken?: boolean // 1 byte
|
|
20
20
|
feeSpeed?: "normal" | "fast" | "slow"
|
|
21
|
+
staticFeeRate?: number
|
|
21
22
|
}
|
|
22
23
|
export class TeleportDaoPayment extends BitcoinBase {
|
|
23
24
|
// payment
|
|
@@ -62,6 +63,7 @@ export class TeleportDaoPayment extends BitcoinBase {
|
|
|
62
63
|
deadline, // 4 bytes
|
|
63
64
|
isFixedToken = false, // 1 byte
|
|
64
65
|
feeSpeed = "normal",
|
|
66
|
+
staticFeeRate,
|
|
65
67
|
}: TransferRequest) {
|
|
66
68
|
if (!this.currentAccount || !this.currentAccountType || !this.publicKey || !this.privateKey) {
|
|
67
69
|
throw new Error("account not initialized")
|
|
@@ -89,6 +91,7 @@ export class TeleportDaoPayment extends BitcoinBase {
|
|
|
89
91
|
deadline,
|
|
90
92
|
isFixedToken,
|
|
91
93
|
feeSpeed,
|
|
94
|
+
staticFeeRate,
|
|
92
95
|
})
|
|
93
96
|
let signedPsbt = await this.signer.signPsbt(unsignedTx, this.privateKey)
|
|
94
97
|
let txId = await this.sendSignedPsbt(signedPsbt)
|
|
@@ -154,10 +157,11 @@ export class TeleportDaoPayment extends BitcoinBase {
|
|
|
154
157
|
deadline = 0, // 4 bytes
|
|
155
158
|
isFixedToken = false, // 1 byte
|
|
156
159
|
feeSpeed = "normal",
|
|
160
|
+
staticFeeRate,
|
|
157
161
|
}: TransferRequest & {
|
|
158
162
|
extendedUtxo: ExtendedUtxo[]
|
|
159
163
|
}) {
|
|
160
|
-
let feeRate = await this.transactionBuilder._getFeeRate(feeSpeed)
|
|
164
|
+
let feeRate = staticFeeRate || (await this.transactionBuilder._getFeeRate(feeSpeed))
|
|
161
165
|
let targets = await this.getBitcoinToEthTargetOutputs({
|
|
162
166
|
lockerAddress,
|
|
163
167
|
amount,
|
|
@@ -196,6 +200,7 @@ export class TeleportDaoPayment extends BitcoinBase {
|
|
|
196
200
|
isBorrow = false,
|
|
197
201
|
tokenAddress = "0x0000000000000000000000000000000000000000", // 20 bytes
|
|
198
202
|
borrowAmount = 0, // 28 bytes
|
|
203
|
+
staticFeeRate,
|
|
199
204
|
}: {
|
|
200
205
|
lockerAddress: string
|
|
201
206
|
amount: number
|
|
@@ -203,6 +208,7 @@ export class TeleportDaoPayment extends BitcoinBase {
|
|
|
203
208
|
appId: number
|
|
204
209
|
recipientAddress: string // 20 bytes
|
|
205
210
|
percentageFee: number // 2 bytes in satoshi
|
|
211
|
+
staticFeeRate: number
|
|
206
212
|
mode?: 0 | 1 | boolean // 1 byte
|
|
207
213
|
isBorrow?: boolean
|
|
208
214
|
tokenAddress?: string // 20 bytes
|
|
@@ -239,7 +245,7 @@ export class TeleportDaoPayment extends BitcoinBase {
|
|
|
239
245
|
opTarget,
|
|
240
246
|
],
|
|
241
247
|
changeAddress: this.currentAccount,
|
|
242
|
-
feeRate:
|
|
248
|
+
feeRate: staticFeeRate,
|
|
243
249
|
fullAmount: false,
|
|
244
250
|
})
|
|
245
251
|
let signedPsbt = await this.signer.signPsbt(unsignedTx, this.privateKey)
|
package/src/mempool-space.ts
DELETED
|
@@ -1,255 +0,0 @@
|
|
|
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
|