@teleportdao/bitcoin 2.0.5 → 2.0.8

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 (90) hide show
  1. package/dist/bitcoin-interface-ordinal.d.ts +108 -108
  2. package/dist/bitcoin-interface-ordinal.js +140 -140
  3. package/dist/bitcoin-interface-teleswap.d.ts +83 -101
  4. package/dist/bitcoin-interface-teleswap.d.ts.map +1 -1
  5. package/dist/bitcoin-interface-teleswap.js +119 -176
  6. package/dist/bitcoin-interface-teleswap.js.map +1 -1
  7. package/dist/bitcoin-interface-utils.d.ts +20 -20
  8. package/dist/bitcoin-interface-utils.js +45 -45
  9. package/dist/bitcoin-interface-wallet.d.ts +29 -28
  10. package/dist/bitcoin-interface-wallet.d.ts.map +1 -1
  11. package/dist/bitcoin-interface-wallet.js +126 -125
  12. package/dist/bitcoin-interface-wallet.js.map +1 -1
  13. package/dist/bitcoin-interface.d.ts +63 -66
  14. package/dist/bitcoin-interface.d.ts.map +1 -1
  15. package/dist/bitcoin-interface.js +112 -119
  16. package/dist/bitcoin-interface.js.map +1 -1
  17. package/dist/bitcoin-utils.d.ts +96 -96
  18. package/dist/bitcoin-utils.js +514 -514
  19. package/dist/bitcoin-wallet-base.d.ts +111 -111
  20. package/dist/bitcoin-wallet-base.d.ts.map +1 -1
  21. package/dist/bitcoin-wallet-base.js +258 -258
  22. package/dist/helper/brc20-helper.d.ts +42 -42
  23. package/dist/helper/brc20-helper.js +127 -127
  24. package/dist/helper/index.d.ts +3 -3
  25. package/dist/helper/index.js +29 -29
  26. package/dist/helper/ordinal-helper.d.ts +12 -12
  27. package/dist/helper/ordinal-helper.js +129 -129
  28. package/dist/helper/teleswap-helper.d.ts +95 -95
  29. package/dist/helper/teleswap-helper.js +186 -186
  30. package/dist/index.d.ts +12 -12
  31. package/dist/index.js +41 -41
  32. package/dist/ordinal-wallet.d.ts +492 -495
  33. package/dist/ordinal-wallet.d.ts.map +1 -1
  34. package/dist/ordinal-wallet.js +386 -386
  35. package/dist/ordinal-wallet.js.map +1 -1
  36. package/dist/sign/index.d.ts +1 -1
  37. package/dist/sign/index.js +8 -8
  38. package/dist/sign/sign-transaction.d.ts +12 -12
  39. package/dist/sign/sign-transaction.js +82 -82
  40. package/dist/teleswap-wallet.d.ts +45 -45
  41. package/dist/teleswap-wallet.js +68 -68
  42. package/dist/transaction-builder/bitcoin-transaction-builder.d.ts +9 -9
  43. package/dist/transaction-builder/bitcoin-transaction-builder.d.ts.map +1 -1
  44. package/dist/transaction-builder/bitcoin-transaction-builder.js +54 -54
  45. package/dist/transaction-builder/bitcoin-transaction-builder.js.map +1 -1
  46. package/dist/transaction-builder/index.d.ts +3 -3
  47. package/dist/transaction-builder/index.js +19 -19
  48. package/dist/transaction-builder/ordinal-transaction-builder.d.ts +63 -63
  49. package/dist/transaction-builder/ordinal-transaction-builder.js +125 -125
  50. package/dist/transaction-builder/transaction-builder.d.ts +223 -223
  51. package/dist/transaction-builder/transaction-builder.d.ts.map +1 -1
  52. package/dist/transaction-builder/transaction-builder.js +442 -447
  53. package/dist/transaction-builder/transaction-builder.js.map +1 -1
  54. package/dist/type.d.ts +55 -61
  55. package/dist/type.d.ts.map +1 -1
  56. package/dist/type.js +2 -2
  57. package/dist/utils/networks.d.ts +5 -5
  58. package/dist/utils/networks.js +53 -53
  59. package/dist/utils/tools.d.ts +18 -18
  60. package/dist/utils/tools.js +74 -74
  61. package/package.json +4 -4
  62. package/src/bitcoin-interface-ordinal.ts +185 -185
  63. package/src/bitcoin-interface-teleswap.ts +246 -251
  64. package/src/bitcoin-interface-utils.ts +60 -60
  65. package/src/bitcoin-interface-wallet.ts +112 -114
  66. package/src/bitcoin-interface.ts +146 -156
  67. package/src/bitcoin-utils.ts +591 -591
  68. package/src/bitcoin-wallet-base.ts +344 -344
  69. package/src/helper/brc20-helper.ts +179 -179
  70. package/src/helper/ordinal-helper.ts +118 -118
  71. package/src/index.ts +15 -15
  72. package/src/ordinal-wallet.ts +654 -659
  73. package/src/sign/index.ts +1 -1
  74. package/src/sign/sign-transaction.ts +108 -108
  75. package/src/teleswap-wallet.ts +133 -133
  76. package/src/transaction-builder/bitcoin-transaction-builder.ts +26 -26
  77. package/src/transaction-builder/index.ts +3 -3
  78. package/src/transaction-builder/ordinal-transaction-builder.ts +139 -139
  79. package/src/transaction-builder/transaction-builder.ts +686 -690
  80. package/src/type.ts +64 -74
  81. package/src/utils/networks.ts +33 -33
  82. package/src/utils/tools.ts +92 -92
  83. package/tsconfig.json +9 -9
  84. package/webpack.config.js +16 -16
  85. package/.tmp/block-parser.ts +0 -58
  86. package/.tmp/check.ts +0 -101
  87. package/.tmp/ordinal-helper.ts +0 -133
  88. package/.tmp/ordinal.ts +0 -25
  89. package/.tmp/psbt/sign-transaction.ts +0 -121
  90. package/.tmp/rbf.ts +0 -45
@@ -1,344 +1,344 @@
1
- import * as bip39 from "bip39"
2
- import { hdWalletPath } from "@teleportdao/configs"
3
- import { Network, Payment } from "bitcoinjs-lib"
4
- import BIP32Factory from "bip32"
5
- import ecc from "@bitcoinerlab/secp256k1"
6
- import BigNumber from "bignumber.js"
7
- import { BitcoinTransactionBuilder } from "./transaction-builder"
8
- import type { APIConnectionInfo, RPCConnectionInfo, UtxoConnectionInfo } from "./type"
9
-
10
- import type {
11
- ExtendedUtxo,
12
- SignerInfo,
13
- Target,
14
- TargetAddress,
15
- } from "./transaction-builder/transaction-builder"
16
- import BitcoinSign from "./sign/sign-transaction"
17
-
18
- import { getPubKeyFromPrivateKeyHex } from "./bitcoin-utils"
19
- import networks from "./utils/networks"
20
- import { BitcoinInterfaceWallet } from "./bitcoin-interface-wallet"
21
- import { runWithRetries } from "./utils/tools"
22
-
23
- const bip32 = BIP32Factory(ecc)
24
-
25
- export type FeeRateType = "normal" | "slow" | "fast" | number
26
- export class BitcoinBaseWallet {
27
- network: Network
28
- hdWalletPath: {
29
- p2pkh: string
30
- p2wpkh: string
31
- "p2sh-p2wpkh": string
32
- p2sh: string
33
- p2wsh: string
34
- "p2sh-p2wsh": string
35
- p2tr: string
36
- }
37
- transactionBuilder: BitcoinTransactionBuilder
38
- btcInterface: BitcoinInterfaceWallet
39
- signer: BitcoinSign
40
- currentAccount?: string
41
- currentAccountType?: string
42
- privateKey?: Buffer
43
- publicKey?: Buffer
44
- publicKeys?: Buffer[]
45
- addressObj?: Payment
46
- bitcoinAddress: string | undefined
47
- constructor(
48
- networkName: string,
49
- connectionInfo?: {
50
- utxo?: UtxoConnectionInfo
51
- // rpc used for getRawTransaction in transaction builder if set (optional)
52
- rpc?: RPCConnectionInfo
53
- },
54
- ) {
55
- this.network = networks[networkName]
56
- this.hdWalletPath = hdWalletPath.bitcoin
57
-
58
- this.transactionBuilder = new BitcoinTransactionBuilder(
59
- networkName,
60
- this.network,
61
- connectionInfo,
62
- )
63
- this.btcInterface = this.transactionBuilder.btcInterface
64
-
65
- this.signer = new BitcoinSign(this.network)
66
-
67
- // initialize account
68
- this.currentAccount = undefined
69
- this.currentAccountType = undefined
70
- this.privateKey = undefined
71
- this.publicKey = undefined
72
- }
73
-
74
- static satoshiToBTC(satoshi: number | string) {
75
- return new BigNumber(satoshi).dividedBy(1e8).toString()
76
- }
77
-
78
- static btcToSatoshi(btc: number | string) {
79
- return new BigNumber(btc).multipliedBy(1e8).toFixed(0)
80
- }
81
-
82
- // initialize account
83
-
84
- get signerInfo() {
85
- return this.privateKey
86
- ? {
87
- address: this.bitcoinAddress!,
88
- publicKey: this.publicKey!.toString("hex"),
89
- addressType: this.currentAccountType!,
90
- }
91
- : undefined
92
- }
93
-
94
- setAccountPrivateKey(privateKeyHex: string) {
95
- this.privateKey = Buffer.from(privateKeyHex, "hex")
96
- let publicKey = getPubKeyFromPrivateKeyHex(privateKeyHex, this.network)
97
- this.publicKey = publicKey
98
- this.setAccountType("p2wpkh")
99
- }
100
-
101
- setAccountType(accountType = "p2pkh") {
102
- if (!this.publicKey) {
103
- throw new Error("account not initialized")
104
- }
105
- let addressObj = this.transactionBuilder.createAddressObject({
106
- addressType: accountType,
107
- publicKey: this.publicKey,
108
- })
109
- this.currentAccount = addressObj.address
110
- this.currentAccountType = accountType
111
- this.addressObj = addressObj
112
- this.bitcoinAddress = addressObj.address
113
- return addressObj.address!
114
- }
115
-
116
- setAccountPrivateKeyByMnemonic({
117
- mnemonic,
118
- mnemonicPassword = "",
119
- index = 0,
120
- walletNumber = 0,
121
- addressType = "p2sh-p2wpkh",
122
- }: {
123
- mnemonic: string
124
- mnemonicPassword?: string
125
- index?: number
126
- walletNumber?: number
127
- addressType?: string
128
- }) {
129
- if (!bip39.validateMnemonic(mnemonic)) throw new Error("invalid mnemonic")
130
- const seed = bip39.mnemonicToSeedSync(mnemonic, mnemonicPassword)
131
- const node = bip32.fromSeed(seed)
132
-
133
- let basePath = this.hdWalletPath[addressType as keyof typeof this.hdWalletPath]
134
- if (!basePath) {
135
- throw new Error("incorrect path or addressType")
136
- }
137
- const path = `${basePath}/${walletNumber}`
138
- const account = node.derivePath(path)
139
- const userKeyPair = account.derive(index)
140
- this.setAccountPrivateKey(userKeyPair.privateKey!.toString("hex"))
141
- return this.setAccountType(addressType)
142
- }
143
-
144
- // helper function
145
-
146
- checkBalanceIsSufficient({
147
- targets,
148
- extendedUtxo,
149
- changeAddress,
150
- feeRate,
151
- }: {
152
- targets: Target[]
153
- extendedUtxo: ExtendedUtxo[]
154
- changeAddress: string
155
- feeRate: number
156
- }) {
157
- try {
158
- this.transactionBuilder.helperHandleInputsAndOutputs({
159
- targets,
160
- extendedUtxo,
161
- changeObject: {
162
- address: changeAddress,
163
- },
164
- feeRate,
165
- })
166
- return true
167
- } catch (err) {
168
- return false
169
- }
170
- }
171
-
172
- async getExtendedUtxo(input: SignerInfo) {
173
- return this.btcInterface.getExtendedUtxo(input)
174
- }
175
-
176
- async getFeeRate(feeRate: FeeRateType = "normal") {
177
- if (feeRate === 0) throw new Error("feeRate should be greater than 0")
178
- if (+feeRate > 0) return +feeRate
179
- if (typeof feeRate === "string") return this.btcInterface.getFeeRate(feeRate)
180
- throw new Error("incorrect feeRate")
181
- }
182
-
183
- // signed methods
184
-
185
- async sendBTC(
186
- receiverAddress: string,
187
- amountInSatoshi: number | "all",
188
- fee: FeeRateType = "normal",
189
- staticExtendedUtxo?: ExtendedUtxo[],
190
- ) {
191
- if (!this.signerInfo! || !this.privateKey) {
192
- throw new Error("account not initialized")
193
- }
194
- const unsignedTx = await this.sendBTCUnsignedTx(
195
- receiverAddress,
196
- amountInSatoshi,
197
- this.signerInfo!,
198
- fee,
199
- staticExtendedUtxo,
200
- )
201
- let signedPsbt = await this.signer.signPsbt(unsignedTx, this.privateKey)
202
- let signedTx = this.signer.finalizePsbts([signedPsbt])
203
- let txId = await this.sendSignedTx(signedTx)
204
- return txId
205
- }
206
-
207
- async sendBTCMultipleAddress(
208
- receivers: TargetAddress[],
209
- fee: FeeRateType = "normal",
210
- staticExtendedUtxo?: ExtendedUtxo[],
211
- ) {
212
- if (!this.signerInfo! || !this.privateKey) {
213
- throw new Error("account not initialized")
214
- }
215
- const unsignedTx = await this.sendBTCToMultipleAddressUnsignedTx(
216
- receivers,
217
- this.signerInfo!,
218
- fee,
219
- staticExtendedUtxo,
220
- )
221
- let signedPsbt = await this.signer.signPsbt(unsignedTx, this.privateKey)
222
- let signedTx = this.signer.finalizePsbts([signedPsbt])
223
- let txId = await this.sendSignedTx(signedTx)
224
- return txId
225
- }
226
-
227
- // unsigned methods
228
- async sendBTCToMultipleAddressUnsignedTx(
229
- receivers: TargetAddress[],
230
- signerInfo: SignerInfo,
231
- fee: FeeRateType = "normal",
232
- staticExtendedUtxo?: ExtendedUtxo[],
233
- fullAmount = false,
234
- ) {
235
- if (!fullAmount) {
236
- receivers.forEach((r) => {
237
- if (BigNumber(r.value).isEqualTo(0)) throw new Error("incorrect amount")
238
- })
239
- } else if (receivers.length > 1) throw new Error("fullAmount only support one receiver")
240
-
241
- let feeRate = await this.getFeeRate(fee)
242
- let extendedUtxo = staticExtendedUtxo || (await this.getExtendedUtxo(signerInfo))
243
-
244
- let unsignedTx = await this.transactionBuilder.processUnsignedTransaction({
245
- extendedUtxo,
246
- targets: receivers,
247
- changeAddress: signerInfo.address,
248
- feeRate,
249
- fullAmount,
250
- })
251
- return unsignedTx
252
- }
253
-
254
- async sendBTCUnsignedTx(
255
- receiver: string,
256
- amountInSatoshi: number | "all",
257
- signerInfo: SignerInfo,
258
- fee: FeeRateType = "normal",
259
- staticExtendedUtxo?: ExtendedUtxo[],
260
- ) {
261
- return this.sendBTCToMultipleAddressUnsignedTx(
262
- [{ address: receiver, value: amountInSatoshi === "all" ? 0 : amountInSatoshi }],
263
- signerInfo,
264
- fee,
265
- staticExtendedUtxo,
266
- amountInSatoshi === "all",
267
- )
268
- }
269
-
270
- // send tx
271
-
272
- async sendSignedTx(signedTx: string) {
273
- let txId = await this.btcInterface.sendRawTransaction(signedTx)
274
- return txId
275
- }
276
-
277
- async sendSignedPsbt(signedPsbt: string) {
278
- let signedTx = this.signer.finalizePsbts([signedPsbt])
279
- let txId = await this.sendSignedTx(signedTx)
280
- return txId
281
- }
282
-
283
- async sendSignedPsbtWithRetry(signedPsbt: string, { maxTries = 5, retrySleep = 5000 } = {}) {
284
- return runWithRetries(() => this.sendSignedPsbt(signedPsbt), {
285
- retrySleep,
286
- maxTries,
287
- })
288
- }
289
-
290
- async sendMultiSignedPsbt(signedPsbts: string[] = []) {
291
- let signedTx = this.signer.finalizePsbts(signedPsbts)
292
- let txId = await this.btcInterface.sendRawTransaction(signedTx)
293
- return txId
294
- }
295
-
296
- // increase transaction fee (beta vesrion)
297
- async increaseTransactionFeeUnsignedPsbt(
298
- txId: string,
299
- signerInfos: SignerInfo[],
300
- extraExtendedUtxo: ExtendedUtxo[],
301
- changeAddress: string,
302
- staticFeeRate?: number,
303
- ) {
304
- let transaction = await this.btcInterface.apiProvider.getTransaction(txId)
305
-
306
- let extendedUtxo = transaction.vin.map((vi) => ({
307
- signerInfo: signerInfos.find((s) => s.address === vi.address)!,
308
- hash: vi.txId,
309
- value: +vi.value,
310
- index: vi.index,
311
- }))
312
-
313
- if (extendedUtxo.find((x) => !x.signerInfo?.address)) {
314
- throw new Error("signerInfo not match")
315
- }
316
-
317
- let changeIndex = transaction.vout.findIndex((vo) =>
318
- transaction.vin.find((vi) => vo.address === vi.address || vo.address === changeAddress),
319
- )
320
-
321
- const feeRate = staticFeeRate || (await this.btcInterface.getFeeRate("fast"))
322
-
323
- let targets = transaction.vout
324
- .filter((_, index) => index !== changeIndex)
325
- .map((vo) =>
326
- vo.address
327
- ? {
328
- address: vo.address,
329
- value: vo.value,
330
- }
331
- : {
332
- script: Buffer.from(vo.script, "hex"),
333
- value: vo.value,
334
- },
335
- )
336
- return this.transactionBuilder.processUnsignedTransaction({
337
- extendedUtxo: [...extendedUtxo, ...extraExtendedUtxo],
338
- targets,
339
- feeRate,
340
- changeAddress: changeIndex >= 0 ? transaction.vout[changeIndex].address : changeAddress,
341
- selectType: "inOrder",
342
- })
343
- }
344
- }
1
+ import * as bip39 from "bip39"
2
+ import { hdWalletPath } from "@teleportdao/configs"
3
+ import { Network, Payment } from "bitcoinjs-lib"
4
+ import BIP32Factory from "bip32"
5
+ import ecc from "@bitcoinerlab/secp256k1"
6
+ import BigNumber from "bignumber.js"
7
+ import { BitcoinTransactionBuilder } from "./transaction-builder"
8
+ import type { RPCConnectionInfo, UtxoConnectionInfo } from "./type"
9
+
10
+ import type {
11
+ ExtendedUtxo,
12
+ SignerInfo,
13
+ Target,
14
+ TargetAddress,
15
+ } from "./transaction-builder/transaction-builder"
16
+ import BitcoinSign from "./sign/sign-transaction"
17
+
18
+ import { getPubKeyFromPrivateKeyHex } from "./bitcoin-utils"
19
+ import networks from "./utils/networks"
20
+ import { BitcoinInterfaceWallet } from "./bitcoin-interface-wallet"
21
+ import { runWithRetries } from "./utils/tools"
22
+
23
+ const bip32 = BIP32Factory(ecc)
24
+
25
+ export type FeeRateType = "normal" | "slow" | "fast" | number
26
+ export class BitcoinBaseWallet {
27
+ network: Network
28
+ hdWalletPath: {
29
+ p2pkh: string
30
+ p2wpkh: string
31
+ "p2sh-p2wpkh": string
32
+ p2sh: string
33
+ p2wsh: string
34
+ "p2sh-p2wsh": string
35
+ p2tr: string
36
+ }
37
+ transactionBuilder: BitcoinTransactionBuilder
38
+ btcInterface: BitcoinInterfaceWallet
39
+ signer: BitcoinSign
40
+ currentAccount?: string
41
+ currentAccountType?: string
42
+ privateKey?: Buffer
43
+ publicKey?: Buffer
44
+ publicKeys?: Buffer[]
45
+ addressObj?: Payment
46
+ bitcoinAddress: string | undefined
47
+ constructor(
48
+ networkName: string,
49
+ connectionInfo?: {
50
+ utxo?: UtxoConnectionInfo
51
+ // rpc used for getRawTransaction in transaction builder if set (optional)
52
+ rpc?: RPCConnectionInfo
53
+ },
54
+ ) {
55
+ this.network = networks[networkName]
56
+ this.hdWalletPath = hdWalletPath.bitcoin
57
+
58
+ this.transactionBuilder = new BitcoinTransactionBuilder(
59
+ networkName,
60
+ this.network,
61
+ connectionInfo,
62
+ )
63
+ this.btcInterface = this.transactionBuilder.btcInterface
64
+
65
+ this.signer = new BitcoinSign(this.network)
66
+
67
+ // initialize account
68
+ this.currentAccount = undefined
69
+ this.currentAccountType = undefined
70
+ this.privateKey = undefined
71
+ this.publicKey = undefined
72
+ }
73
+
74
+ static satoshiToBTC(satoshi: number | string) {
75
+ return new BigNumber(satoshi).dividedBy(1e8).toString()
76
+ }
77
+
78
+ static btcToSatoshi(btc: number | string) {
79
+ return new BigNumber(btc).multipliedBy(1e8).toFixed(0)
80
+ }
81
+
82
+ // initialize account
83
+
84
+ get signerInfo() {
85
+ return this.privateKey
86
+ ? {
87
+ address: this.bitcoinAddress!,
88
+ publicKey: this.publicKey!.toString("hex"),
89
+ addressType: this.currentAccountType!,
90
+ }
91
+ : undefined
92
+ }
93
+
94
+ setAccountPrivateKey(privateKeyHex: string) {
95
+ this.privateKey = Buffer.from(privateKeyHex, "hex")
96
+ let publicKey = getPubKeyFromPrivateKeyHex(privateKeyHex, this.network)
97
+ this.publicKey = publicKey
98
+ this.setAccountType("p2wpkh")
99
+ }
100
+
101
+ setAccountType(accountType = "p2pkh") {
102
+ if (!this.publicKey) {
103
+ throw new Error("account not initialized")
104
+ }
105
+ let addressObj = this.transactionBuilder.createAddressObject({
106
+ addressType: accountType,
107
+ publicKey: this.publicKey,
108
+ })
109
+ this.currentAccount = addressObj.address
110
+ this.currentAccountType = accountType
111
+ this.addressObj = addressObj
112
+ this.bitcoinAddress = addressObj.address
113
+ return addressObj.address!
114
+ }
115
+
116
+ setAccountPrivateKeyByMnemonic({
117
+ mnemonic,
118
+ mnemonicPassword = "",
119
+ index = 0,
120
+ walletNumber = 0,
121
+ addressType = "p2sh-p2wpkh",
122
+ }: {
123
+ mnemonic: string
124
+ mnemonicPassword?: string
125
+ index?: number
126
+ walletNumber?: number
127
+ addressType?: string
128
+ }) {
129
+ if (!bip39.validateMnemonic(mnemonic)) throw new Error("invalid mnemonic")
130
+ const seed = bip39.mnemonicToSeedSync(mnemonic, mnemonicPassword)
131
+ const node = bip32.fromSeed(seed)
132
+
133
+ let basePath = this.hdWalletPath[addressType as keyof typeof this.hdWalletPath]
134
+ if (!basePath) {
135
+ throw new Error("incorrect path or addressType")
136
+ }
137
+ const path = `${basePath}/${walletNumber}`
138
+ const account = node.derivePath(path)
139
+ const userKeyPair = account.derive(index)
140
+ this.setAccountPrivateKey(userKeyPair.privateKey!.toString("hex"))
141
+ return this.setAccountType(addressType)
142
+ }
143
+
144
+ // helper function
145
+
146
+ checkBalanceIsSufficient({
147
+ targets,
148
+ extendedUtxo,
149
+ changeAddress,
150
+ feeRate,
151
+ }: {
152
+ targets: Target[]
153
+ extendedUtxo: ExtendedUtxo[]
154
+ changeAddress: string
155
+ feeRate: number
156
+ }) {
157
+ try {
158
+ this.transactionBuilder.helperHandleInputsAndOutputs({
159
+ targets,
160
+ extendedUtxo,
161
+ changeObject: {
162
+ address: changeAddress,
163
+ },
164
+ feeRate,
165
+ })
166
+ return true
167
+ } catch (err) {
168
+ return false
169
+ }
170
+ }
171
+
172
+ async getExtendedUtxo(input: SignerInfo) {
173
+ return this.btcInterface.getExtendedUtxo(input)
174
+ }
175
+
176
+ async getFeeRate(feeRate: FeeRateType = "normal") {
177
+ if (feeRate === 0) throw new Error("feeRate should be greater than 0")
178
+ if (+feeRate > 0) return +feeRate
179
+ if (typeof feeRate === "string") return this.btcInterface.getFeeRate(feeRate)
180
+ throw new Error("incorrect feeRate")
181
+ }
182
+
183
+ // signed methods
184
+
185
+ async sendBTC(
186
+ receiverAddress: string,
187
+ amountInSatoshi: number | "all",
188
+ fee: FeeRateType = "normal",
189
+ staticExtendedUtxo?: ExtendedUtxo[],
190
+ ) {
191
+ if (!this.signerInfo! || !this.privateKey) {
192
+ throw new Error("account not initialized")
193
+ }
194
+ const unsignedTx = await this.sendBTCUnsignedTx(
195
+ receiverAddress,
196
+ amountInSatoshi,
197
+ this.signerInfo!,
198
+ fee,
199
+ staticExtendedUtxo,
200
+ )
201
+ let signedPsbt = await this.signer.signPsbt(unsignedTx, this.privateKey)
202
+ let signedTx = this.signer.finalizePsbts([signedPsbt])
203
+ let txId = await this.sendSignedTx(signedTx)
204
+ return txId
205
+ }
206
+
207
+ async sendBTCMultipleAddress(
208
+ receivers: TargetAddress[],
209
+ fee: FeeRateType = "normal",
210
+ staticExtendedUtxo?: ExtendedUtxo[],
211
+ ) {
212
+ if (!this.signerInfo! || !this.privateKey) {
213
+ throw new Error("account not initialized")
214
+ }
215
+ const unsignedTx = await this.sendBTCToMultipleAddressUnsignedTx(
216
+ receivers,
217
+ this.signerInfo!,
218
+ fee,
219
+ staticExtendedUtxo,
220
+ )
221
+ let signedPsbt = await this.signer.signPsbt(unsignedTx, this.privateKey)
222
+ let signedTx = this.signer.finalizePsbts([signedPsbt])
223
+ let txId = await this.sendSignedTx(signedTx)
224
+ return txId
225
+ }
226
+
227
+ // unsigned methods
228
+ async sendBTCToMultipleAddressUnsignedTx(
229
+ receivers: TargetAddress[],
230
+ signerInfo: SignerInfo,
231
+ fee: FeeRateType = "normal",
232
+ staticExtendedUtxo?: ExtendedUtxo[],
233
+ fullAmount = false,
234
+ ) {
235
+ if (!fullAmount) {
236
+ receivers.forEach((r) => {
237
+ if (BigNumber(r.value).isEqualTo(0)) throw new Error("incorrect amount")
238
+ })
239
+ } else if (receivers.length > 1) throw new Error("fullAmount only support one receiver")
240
+
241
+ let feeRate = await this.getFeeRate(fee)
242
+ let extendedUtxo = staticExtendedUtxo || (await this.getExtendedUtxo(signerInfo))
243
+
244
+ let unsignedTx = await this.transactionBuilder.processUnsignedTransaction({
245
+ extendedUtxo,
246
+ targets: receivers,
247
+ changeAddress: signerInfo.address,
248
+ feeRate,
249
+ fullAmount,
250
+ })
251
+ return unsignedTx
252
+ }
253
+
254
+ async sendBTCUnsignedTx(
255
+ receiver: string,
256
+ amountInSatoshi: number | "all",
257
+ signerInfo: SignerInfo,
258
+ fee: FeeRateType = "normal",
259
+ staticExtendedUtxo?: ExtendedUtxo[],
260
+ ) {
261
+ return this.sendBTCToMultipleAddressUnsignedTx(
262
+ [{ address: receiver, value: amountInSatoshi === "all" ? 0 : amountInSatoshi }],
263
+ signerInfo,
264
+ fee,
265
+ staticExtendedUtxo,
266
+ amountInSatoshi === "all",
267
+ )
268
+ }
269
+
270
+ // send tx
271
+
272
+ async sendSignedTx(signedTx: string) {
273
+ let txId = await this.btcInterface.sendRawTransaction(signedTx)
274
+ return txId
275
+ }
276
+
277
+ async sendSignedPsbt(signedPsbt: string) {
278
+ let signedTx = this.signer.finalizePsbts([signedPsbt])
279
+ let txId = await this.sendSignedTx(signedTx)
280
+ return txId
281
+ }
282
+
283
+ async sendSignedPsbtWithRetry(signedPsbt: string, { maxTries = 5, retrySleep = 5000 } = {}) {
284
+ return runWithRetries(() => this.sendSignedPsbt(signedPsbt), {
285
+ retrySleep,
286
+ maxTries,
287
+ })
288
+ }
289
+
290
+ async sendMultiSignedPsbt(signedPsbts: string[] = []) {
291
+ let signedTx = this.signer.finalizePsbts(signedPsbts)
292
+ let txId = await this.btcInterface.sendRawTransaction(signedTx)
293
+ return txId
294
+ }
295
+
296
+ // increase transaction fee (beta vesrion)
297
+ async increaseTransactionFeeUnsignedPsbt(
298
+ txId: string,
299
+ signerInfos: SignerInfo[],
300
+ extraExtendedUtxo: ExtendedUtxo[],
301
+ changeAddress: string,
302
+ staticFeeRate?: number,
303
+ ) {
304
+ let transaction = await this.btcInterface.apiProvider.getTransaction(txId)
305
+
306
+ let extendedUtxo = transaction.vin.map((vi) => ({
307
+ signerInfo: signerInfos.find((s) => s.address === vi.address)!,
308
+ hash: vi.txId,
309
+ value: +vi.value,
310
+ index: vi.index,
311
+ }))
312
+
313
+ if (extendedUtxo.find((x) => !x.signerInfo?.address)) {
314
+ throw new Error("signerInfo not match")
315
+ }
316
+
317
+ let changeIndex = transaction.vout.findIndex((vo) =>
318
+ transaction.vin.find((vi) => vo.address === vi.address || vo.address === changeAddress),
319
+ )
320
+
321
+ const feeRate = staticFeeRate || (await this.btcInterface.getFeeRate("fast"))
322
+
323
+ let targets = transaction.vout
324
+ .filter((_, index) => index !== changeIndex)
325
+ .map((vo) =>
326
+ vo.address
327
+ ? {
328
+ address: vo.address,
329
+ value: vo.value,
330
+ }
331
+ : {
332
+ script: Buffer.from(vo.script, "hex"),
333
+ value: vo.value,
334
+ },
335
+ )
336
+ return this.transactionBuilder.processUnsignedTransaction({
337
+ extendedUtxo: [...extendedUtxo, ...extraExtendedUtxo],
338
+ targets,
339
+ feeRate,
340
+ changeAddress: changeIndex >= 0 ? transaction.vout[changeIndex].address : changeAddress,
341
+ selectType: "inOrder",
342
+ })
343
+ }
344
+ }