@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,738 +1,738 @@
1
- import BigNumber from "bignumber.js"
2
- import { bitcoin as bitcoinProviders } from "@teleportdao/providers"
3
- import { BitcoinBaseWallet } from "./bitcoin-wallet-base"
4
- // eslint-disable-next-line import/no-extraneous-dependencies
5
- import { BitcoinConnectionInfo } from "./type"
6
- import type { SignerInfo, ChangeTarget, Target, ExtendedUtxo } from "./transaction-builder"
7
-
8
- import { OrdinalTransactionBuilder } from "./transaction-builder"
9
- import BitcoinSign from "./sign/sign-transaction"
10
- //
11
- import { BitcoinInterfaceOrdinal } from "./bitcoin-interface-ordinal"
12
-
13
- import { generateBrc2OpReturn } from "./helper/brc20-helper"
14
- import { sleep } from "./utils/tools"
15
-
16
- export class OrdinalWallet extends BitcoinBaseWallet {
17
- unisat: bitcoinProviders.UniSat
18
- transactionBuilder: OrdinalTransactionBuilder
19
- btcInterface: BitcoinInterfaceOrdinal
20
- signer: BitcoinSign
21
- constructor(
22
- networkName: string,
23
- uniSatToken: string,
24
- connectionInfo: BitcoinConnectionInfo = {
25
- api: {
26
- provider: "MempoolSpace",
27
- },
28
- },
29
- ) {
30
- super(networkName, connectionInfo)
31
- if (!connectionInfo.rpc?.enabled) {
32
- throw new Error("rpc is required")
33
- }
34
- this.transactionBuilder = new OrdinalTransactionBuilder(connectionInfo, networkName)
35
- this.signer = new BitcoinSign(this.network)
36
- this.btcInterface = new BitcoinInterfaceOrdinal(connectionInfo, networkName, uniSatToken)
37
- this.unisat = this.btcInterface.unisat
38
- }
39
-
40
- async sendSignedPsbtWithRetry(signedPsbt: string, { numberOfRetry = 5, sleepTime = 5000 } = {}) {
41
- let count = 0
42
- while (count <= numberOfRetry) {
43
- try {
44
- let txId = await this.sendSignedPsbt(signedPsbt)
45
- return txId
46
- } catch (e: any) {
47
- console.log(e.message)
48
- await sleep(sleepTime + count * 5000)
49
- count += 1
50
- }
51
- }
52
- throw new Error("failed to send transaction")
53
- }
54
-
55
- static deployBRC20Data(tickName: string, max: number | string, limit: number | string) {
56
- let data = {
57
- p: "brc-20",
58
- op: "deploy",
59
- tick: tickName,
60
- max: `${max}`,
61
- lim: `${limit}`,
62
- }
63
- return {
64
- buffer: Buffer.from(JSON.stringify(data), "utf8"),
65
- type: "text/plain",
66
- // type: "application/json",
67
- }
68
- }
69
-
70
- static mintBRC20Data(tickName: string, amount: string | number) {
71
- let data = {
72
- p: "brc-20",
73
- op: "mint",
74
- tick: tickName,
75
- amt: `${amount}`,
76
- }
77
- return {
78
- buffer: Buffer.from(JSON.stringify(data), "utf8"),
79
- type: "text/plain",
80
- // type: "application/json",
81
- }
82
- }
83
-
84
- static transferBRC20Data(tickName: string, amount: string | number) {
85
- let data = {
86
- p: "brc-20",
87
- op: "transfer",
88
- tick: tickName,
89
- amt: `${amount}`,
90
- }
91
- return {
92
- buffer: Buffer.from(JSON.stringify(data), "utf8"),
93
- type: "text/plain",
94
- // type: "application/json",
95
- }
96
- }
97
-
98
- async sendUsingUtxosUnsigned({
99
- receivers,
100
- speed = "normal",
101
- utxo,
102
- changeAddress,
103
- staticFeeRate,
104
- }: {
105
- receivers: {
106
- address: string
107
- value: number
108
- }[]
109
- changeAddress: string
110
- speed?: "normal" | "fast" | "slow"
111
- staticFeeRate?: number
112
- utxo: ExtendedUtxo[]
113
- }) {
114
- let extendedUtxo: ExtendedUtxo[] = utxo
115
-
116
- receivers.forEach(({ value }) => {
117
- if (value - +value.toFixed(0) !== 0)
118
- throw new Error("incorrect amount. amount should be in satoshi")
119
- })
120
-
121
- // eslint-disable-next-line no-underscore-dangle
122
- let feeRate = staticFeeRate || (await this.transactionBuilder._getFeeRate(speed))
123
- let unsignedTx = await this.transactionBuilder.processUnsignedTransaction({
124
- extendedUtxo,
125
- targets: receivers,
126
- changeAddress,
127
- feeRate,
128
- fullAmount: false,
129
- })
130
-
131
- return {
132
- ...unsignedTx,
133
- possibleTxId: this.transactionBuilder.getUnsignedPsbtTxId(unsignedTx.unsignedTransaction),
134
- }
135
- }
136
-
137
- async sendUsingUtxos({
138
- receivers,
139
- speed = "normal",
140
- utxo,
141
- }: {
142
- receivers: {
143
- address: string
144
- value: number
145
- }[]
146
- speed?: "normal" | "fast" | "slow"
147
- utxo?: ExtendedUtxo[]
148
- }) {
149
- if (!this.currentAccount || !this.currentAccountType || !this.publicKey || !this.privateKey) {
150
- throw new Error("account not initialized")
151
- }
152
-
153
- let extendedUtxo: ExtendedUtxo[] = utxo
154
- ? utxo.filter((u) => u.signerInfo.address === this.currentAccount!)
155
- : await this.getExtendedUtxo({
156
- address: this.currentAccount,
157
- addressType: this.currentAccountType,
158
- publicKey: this.publicKey.toString("hex"),
159
- })
160
-
161
- let unsignedTx = await this.sendUsingUtxosUnsigned({
162
- receivers,
163
- speed,
164
- utxo: extendedUtxo,
165
- changeAddress: this.bitcoinAddress!,
166
- })
167
- let signedPsbt = await this.signer.signPsbt(unsignedTx, this.privateKey)
168
- let signedTx = this.signer.finalizePsbts([signedPsbt])
169
- let txId = await this.transactionBuilder.sendTx(signedTx)
170
- const { inputs, outputs, change, fee } = unsignedTx
171
- return { txId, inputs, outputs, change, fee }
172
- }
173
-
174
- async inscribeOrdinalDepositUnsigned(
175
- file: {
176
- buffer: Buffer
177
- type: string
178
- },
179
- signer: SignerInfo,
180
- extendedUtxo?: ExtendedUtxo[],
181
- staticFeeRate?: number,
182
- ) {
183
- const publicKey = Buffer.from(signer.publicKey, "hex")
184
- let transferOrdinal = this.transactionBuilder.createOrdinalAddress(file, publicKey)
185
- const leafScript = transferOrdinal.redeem.output
186
- const { ordinalAddress } = transferOrdinal
187
-
188
- let feeRate = staticFeeRate || (await this.btcInterface.getFeeRate("normal"))
189
- let fee = +(((400 + leafScript.length) / 4) * feeRate * 1.5).toFixed(0)
190
- let ordinalAmount = 600
191
-
192
- let utxo1: ExtendedUtxo[] =
193
- extendedUtxo || (await this.btcInterface.getBTCUtxo(signer.address, signer))
194
-
195
- let inscribeDepositUnsignedInfo = await this.sendUsingUtxosUnsigned({
196
- receivers: [
197
- {
198
- address: ordinalAddress,
199
- value: ordinalAmount + fee,
200
- },
201
- ],
202
- utxo: utxo1,
203
- changeAddress: signer.address,
204
- })
205
-
206
- return {
207
- inscribeDepositUnsignedInfo,
208
- transferOrdinal,
209
- }
210
- }
211
-
212
- async inscribeOrdinalUnsigned(
213
- file: {
214
- buffer: Buffer
215
- type: string
216
- },
217
- signer: SignerInfo,
218
- extendedUtxo?: ExtendedUtxo[],
219
- staticFeeRate?: number,
220
- ) {
221
- const { inscribeDepositUnsignedInfo, transferOrdinal } =
222
- await this.inscribeOrdinalDepositUnsigned(file, signer, extendedUtxo, staticFeeRate)
223
- const { ordinalAddress } = transferOrdinal
224
- let ordinalAmount = 600
225
- let inscribeDeposit: {
226
- hash: string
227
- value: number
228
- index: number
229
- } = {
230
- hash: inscribeDepositUnsignedInfo.possibleTxId,
231
- value: inscribeDepositUnsignedInfo.outputs[0].value,
232
- index: 0,
233
- }
234
- let inscribeUnsignedInfo = this.transactionBuilder.createInscribeUnsignedTx(
235
- transferOrdinal,
236
- inscribeDeposit,
237
- this.bitcoinAddress!,
238
- ordinalAmount,
239
- )
240
- return {
241
- inscribeDepositUnsignedInfo: {
242
- ...inscribeDepositUnsignedInfo,
243
- possibleTxId: this.transactionBuilder.getUnsignedPsbtTxId(
244
- inscribeDepositUnsignedInfo.unsignedTransaction,
245
- ),
246
- },
247
- inscribeUnsignedInfo: {
248
- ...inscribeUnsignedInfo,
249
- possibleTxId: this.transactionBuilder.getUnsignedPsbtTxId(
250
- inscribeUnsignedInfo.unsignedTransaction,
251
- ),
252
- },
253
- inscribeAddress: ordinalAddress,
254
- }
255
- }
256
-
257
- async inscribeOrdinal(
258
- file: {
259
- buffer: Buffer
260
- type: string
261
- },
262
- extendedUtxo?: ExtendedUtxo[],
263
- staticFeeRate?: number,
264
- ) {
265
- if (!this.currentAccount || !this.currentAccountType || !this.publicKey || !this.privateKey) {
266
- throw new Error("account not initialized")
267
- }
268
-
269
- const { inscribeDepositUnsignedInfo, transferOrdinal } =
270
- await this.inscribeOrdinalDepositUnsigned(file, this.signerInfo!, extendedUtxo, staticFeeRate)
271
-
272
- let ordinalUtxo = await this.btcInterface.getBTCUtxo(
273
- transferOrdinal.ordinalAddress,
274
- this.signerInfo!,
275
- )
276
-
277
- let inscribeDeposit: {
278
- inputs: {
279
- hash: string
280
- value: number
281
- index: number
282
- signerInfo: SignerInfo
283
- }[]
284
- hash: string
285
- value: number
286
- index: number
287
- change?: ChangeTarget
288
- changeIndex?: number
289
- }
290
-
291
- if (ordinalUtxo.length > 1) {
292
- throw new Error("multiple deposit found for this ordinal address")
293
- }
294
-
295
- if (
296
- ordinalUtxo.length === 0 ||
297
- ordinalUtxo[0].value <
298
- inscribeDepositUnsignedInfo.outputs[0].value -
299
- inscribeDepositUnsignedInfo.outputs[0].value * 0.15
300
- ) {
301
- const signedPsbt1 = await this.signer.signPsbt(inscribeDepositUnsignedInfo, this.privateKey!)
302
- console.log("inscribe deposit tx ...")
303
- const inscribeDepositTxId = await this.sendSignedPsbt(signedPsbt1)
304
- console.log(`inscribe deposit txId : ${inscribeDepositTxId}`)
305
-
306
- inscribeDeposit = {
307
- hash: inscribeDepositTxId,
308
- value: inscribeDepositUnsignedInfo.outputs[0].value,
309
- index: 0,
310
- inputs: inscribeDepositUnsignedInfo.inputs,
311
- change: inscribeDepositUnsignedInfo.change,
312
- changeIndex: inscribeDepositUnsignedInfo.change
313
- ? inscribeDepositUnsignedInfo.outputs.length
314
- : undefined,
315
- }
316
- } else {
317
- inscribeDeposit = {
318
- hash: ordinalUtxo[0].hash,
319
- value: ordinalUtxo[0].value,
320
- index: ordinalUtxo[0].index,
321
- inputs: [],
322
- }
323
- console.log("no need to deposit", inscribeDeposit)
324
- }
325
-
326
- const ordinalAmount = 600
327
- let inscribeUnsignedInfo = this.transactionBuilder.createInscribeUnsignedTx(
328
- transferOrdinal,
329
- inscribeDeposit,
330
- this.bitcoinAddress!,
331
- ordinalAmount,
332
- )
333
-
334
- const signedPsbt2 = await this.signer.signPsbt(
335
- inscribeUnsignedInfo,
336
- this.privateKey!,
337
- undefined,
338
- false,
339
- )
340
-
341
- console.log("inscribeTxId ...")
342
- await sleep(10 * 1000)
343
- let inscribeTxId = await this.sendSignedPsbtWithRetry(signedPsbt2)
344
- console.log("inscribeTxId", inscribeTxId)
345
- return {
346
- inscribeTx: { hash: inscribeTxId, index: 0, value: ordinalAmount },
347
- inscribeDepositTx: inscribeDeposit,
348
- inscribeAddress: transferOrdinal.ordinalAddress,
349
- }
350
- }
351
-
352
- async deployBrc20(
353
- brc: { tick: string; max: number; limit: number },
354
- extendedUtxo?: ExtendedUtxo[],
355
- staticFeeRate?: number,
356
- ) {
357
- let file = OrdinalWallet.deployBRC20Data(brc.tick, brc.max, brc.limit)
358
- return this.inscribeOrdinal(file, extendedUtxo, staticFeeRate)
359
- }
360
-
361
- async mintBrc20(
362
- brc: { tick: string; amount: number | string },
363
- extendedUtxo?: ExtendedUtxo[],
364
- staticFeeRate?: number,
365
- ) {
366
- let file = OrdinalWallet.mintBRC20Data(brc.tick, brc.amount)
367
- return this.inscribeOrdinal(file, extendedUtxo, staticFeeRate)
368
- }
369
-
370
- async inscribeBrc20Unsigned(
371
- brc: { tick: string; amount: number | string },
372
- signer: SignerInfo,
373
- extendedUtxo?: ExtendedUtxo[],
374
- staticFeeRate?: number,
375
- ) {
376
- let file = OrdinalWallet.transferBRC20Data(brc.tick, brc.amount)
377
- return this.inscribeOrdinalUnsigned(file, signer, extendedUtxo, staticFeeRate)
378
- }
379
-
380
- async inscribeBrc20(
381
- brc: { tick: string; amount: number | string },
382
- extendedUtxo?: ExtendedUtxo[],
383
- staticFeeRate?: number,
384
- ) {
385
- let file = OrdinalWallet.transferBRC20Data(brc.tick, brc.amount)
386
- return this.inscribeOrdinal(file, extendedUtxo, staticFeeRate)
387
- }
388
-
389
- async transferBrc20Unsigned(
390
- receiver: string,
391
- brcInscribeUtxo: {
392
- hash: string
393
- value: number
394
- index: number
395
- },
396
- signer: SignerInfo,
397
- extendedUtxo?: ExtendedUtxo[],
398
- staticFeeRate?: number,
399
- otherTargets?: Target[],
400
- ) {
401
- let utxo = extendedUtxo || (await this.btcInterface.getBTCUtxo(signer.address, signer))
402
- let feeRate = staticFeeRate || (await this.btcInterface.getFeeRate("normal"))
403
- let unsignedTx = await this.transactionBuilder.createNftPsbt({
404
- extendedUtxo: utxo,
405
- nftExtendedUtxo: {
406
- hash: brcInscribeUtxo.hash,
407
- index: 0,
408
- value: brcInscribeUtxo.value,
409
- signerInfo: signer,
410
- },
411
- feeRate,
412
- receiverAddress: receiver,
413
- changeAddress: signer.address,
414
- otherTargets,
415
- })
416
- return {
417
- ...unsignedTx,
418
- possibleTxId: this.transactionBuilder.getUnsignedPsbtTxId(unsignedTx.unsignedTransaction),
419
- }
420
- }
421
-
422
- async transferBrc20(
423
- receiver: string,
424
- brcInscribeUtxo: {
425
- hash: string
426
- value: number
427
- index: number
428
- },
429
- extendedUtxo: ExtendedUtxo[],
430
- staticFeeRate?: number,
431
- otherTargets?: Target[],
432
- ) {
433
- if (!this.currentAccount || !this.currentAccountType || !this.publicKey || !this.privateKey) {
434
- throw new Error("account not initialized")
435
- }
436
- let feeRate = staticFeeRate || (await this.btcInterface.getFeeRate("normal"))
437
- let unsignedTx = await this.transactionBuilder.createNftPsbt({
438
- extendedUtxo,
439
- nftExtendedUtxo: {
440
- hash: brcInscribeUtxo.hash,
441
- index: 0,
442
- value: brcInscribeUtxo.value,
443
- signerInfo: this.signerInfo!,
444
- },
445
- feeRate,
446
- receiverAddress: receiver,
447
- changeAddress: this.bitcoinAddress!,
448
- otherTargets,
449
- })
450
-
451
- let signedTx = await this.signer.signPsbt(unsignedTx, this.privateKey!)
452
- let finalTransferTxId = await this.sendSignedPsbtWithRetry(signedTx)
453
- return {
454
- hash: finalTransferTxId,
455
- index: 0,
456
- value: brcInscribeUtxo.value,
457
- inputs: unsignedTx.inputs,
458
- change: unsignedTx.change,
459
- changeIndex: unsignedTx.change ? unsignedTx.outputs.length : undefined,
460
- }
461
- }
462
-
463
- async inscribeAndTransferBrc20Unsigned(
464
- receiver: string,
465
- brc: { tick: string; amount: number | string },
466
- signer: SignerInfo,
467
- otherTargets?: Target[],
468
- extendedUtxo?: ExtendedUtxo[],
469
- staticFeeRate?: number,
470
- ) {
471
- // check all fee before process transaction
472
- let brc20Balance = await this.unisat.getBrc20AddressBalanceForTicker(signer.address, brc.tick)
473
-
474
- if (BigNumber(brc20Balance.transferableBalance).gte(brc.amount)) {
475
- let transferrableInscription = brc20Balance.transferableInscriptions.find(
476
- (insc) => insc.data.tick === brc.tick && BigNumber(insc.data.amt).isEqualTo(brc.amount),
477
- )
478
-
479
- console.log("transferrableInscription", transferrableInscription)
480
- }
481
-
482
- if (BigNumber(brc20Balance.availableBalanceSafe).isLessThan(brc.amount)) {
483
- throw new Error("insufficient balance")
484
- }
485
-
486
- let feeRate = staticFeeRate || (await this.btcInterface.getFeeRate("normal"))
487
-
488
- let utxo1: ExtendedUtxo[] =
489
- extendedUtxo || (await this.btcInterface.getBTCUtxo(signer.address, signer))
490
- let utxo2: ExtendedUtxo[] = []
491
- const { inscribeAddress, inscribeDepositUnsignedInfo, inscribeUnsignedInfo } =
492
- await this.inscribeBrc20Unsigned(brc, signer, utxo1, feeRate)
493
-
494
- utxo2 = utxo1.filter(
495
- (u) =>
496
- inscribeDepositUnsignedInfo.inputs.findIndex(
497
- (i) => i.hash === u.hash && i.index === u.index,
498
- ) === -1,
499
- )
500
-
501
- if (inscribeDepositUnsignedInfo.change) {
502
- utxo2.push({
503
- hash: inscribeDepositUnsignedInfo.possibleTxId,
504
- index: inscribeDepositUnsignedInfo.outputs.length,
505
- value: inscribeDepositUnsignedInfo.change.value,
506
- signerInfo: signer,
507
- })
508
- }
509
- let transferTxUnsignedInfo = await this.transferBrc20Unsigned(
510
- receiver,
511
- {
512
- hash: inscribeUnsignedInfo.possibleTxId,
513
- value: inscribeUnsignedInfo.outputs[0].value,
514
- index: 0,
515
- },
516
- signer,
517
- utxo2,
518
- feeRate,
519
- otherTargets,
520
- )
521
- return {
522
- inscribeDepositUnsignedInfo,
523
- inscribeUnsignedInfo,
524
- transferTxUnsignedInfo,
525
- inscribeAddress,
526
- }
527
- }
528
-
529
- async inscribeAndTransferBrc20(
530
- receiver: string,
531
- brc: { tick: string; amount: number | string },
532
- otherTargets?: Target[],
533
- extendedUtxo?: ExtendedUtxo[],
534
- staticFeeRate?: number,
535
- ) {
536
- // check all fee before process transaction
537
- let brc20Balance = await this.unisat.getBrc20AddressBalanceForTicker(
538
- this.bitcoinAddress!,
539
- brc.tick,
540
- )
541
-
542
- if (BigNumber(brc20Balance.transferableBalance).gte(brc.amount)) {
543
- let transferrableInscription = brc20Balance.transferableInscriptions.find(
544
- (insc) => insc.data.tick === brc.tick && BigNumber(insc.data.amt).isEqualTo(brc.amount),
545
- )
546
- console.log("transferrableInscription", transferrableInscription)
547
-
548
- if (transferrableInscription) {
549
- let ins = await this.btcInterface.unisat.getInscriptionInfo(
550
- transferrableInscription.inscriptionId,
551
- )
552
-
553
- if (ins) {
554
- let transferTx = await this.transferBrc20(
555
- receiver,
556
- {
557
- hash: ins.utxo.txid!,
558
- index: ins.utxo.vout!,
559
- value: ins.utxo.satoshi!,
560
- },
561
- extendedUtxo ||
562
- (await this.btcInterface.getBTCUtxo(this.bitcoinAddress!, this.signerInfo!)),
563
- staticFeeRate || (await this.btcInterface.getFeeRate("normal")),
564
- otherTargets,
565
- )
566
- return {
567
- transferTx,
568
- }
569
- }
570
- }
571
- }
572
-
573
- if (BigNumber(brc20Balance.availableBalanceSafe).isLessThan(brc.amount)) {
574
- throw new Error(`insufficient balance ${brc20Balance.availableBalanceSafe} ${brc.amount}`)
575
- }
576
-
577
- let feeRate = staticFeeRate || (await this.btcInterface.getFeeRate("normal"))
578
-
579
- let utxo1: ExtendedUtxo[] =
580
- extendedUtxo || (await this.btcInterface.getBTCUtxo(this.bitcoinAddress!, this.signerInfo!))
581
- let utxo2: ExtendedUtxo[] = []
582
- const { inscribeAddress, inscribeDepositTx, inscribeTx } = await this.inscribeBrc20(
583
- brc,
584
- utxo1,
585
- feeRate,
586
- )
587
-
588
- utxo2 = utxo1.filter(
589
- (u) =>
590
- inscribeDepositTx.inputs.findIndex((i) => i.hash === u.hash && i.index === u.index) === -1,
591
- )
592
-
593
- if (inscribeDepositTx.change) {
594
- utxo2.push({
595
- hash: inscribeDepositTx.hash,
596
- index: inscribeDepositTx.changeIndex!,
597
- value: inscribeDepositTx.change.value,
598
- signerInfo: this.signerInfo!,
599
- })
600
- }
601
- await sleep(10 * 1000)
602
- let transferTx = await this.transferBrc20(receiver, inscribeTx, utxo2, feeRate, otherTargets)
603
- return {
604
- inscribeTx,
605
- inscribeAddress,
606
- inscribeDepositTx,
607
- transferTx,
608
- }
609
- }
610
-
611
- async wrapBrc20Unsigned(
612
- recipientAddress: string,
613
- brc: { tick: string; amount: number | string },
614
- brc20TokenId: number,
615
- signer: SignerInfo,
616
- lockerAddress: string,
617
- exchange?: {
618
- outputToken: string
619
- outputAmount: string
620
- },
621
- extendedUtxo?: ExtendedUtxo[],
622
- staticFeeRate?: number,
623
- {
624
- chainId = 137, // 80001
625
- appId = exchange ? 1 : 0,
626
- } = {},
627
- ) {
628
- const isExchange = !!exchange
629
- let dataHex = generateBrc2OpReturn({
630
- chainId,
631
- appId,
632
- brc20TokenId,
633
- inputAmount: BigNumber(brc.amount).multipliedBy(1e18).toFixed(0),
634
- recipientAddress,
635
- isExchange,
636
- outputToken: exchange?.outputToken,
637
- outputAmount: exchange?.outputAmount,
638
- })
639
- let opTarget = this.transactionBuilder.getOpReturnTarget(dataHex)
640
- return this.inscribeAndTransferBrc20Unsigned(
641
- lockerAddress,
642
- brc,
643
- signer,
644
- [opTarget],
645
- extendedUtxo,
646
- staticFeeRate,
647
- )
648
- }
649
-
650
- async wrapBrc20OnlyTransferUnsigned(
651
- recipientAddress: string,
652
- brcInscribeTx: {
653
- hash: string
654
- value: number
655
- index: number
656
- },
657
- brc: { tick: string; amount: number | string },
658
- brc20TokenId: number,
659
- signer: SignerInfo,
660
- lockerAddress: string,
661
- exchange?: {
662
- outputToken: string
663
- outputAmount: string
664
- },
665
- extendedUtxo?: ExtendedUtxo[],
666
- staticFeeRate?: number,
667
- {
668
- chainId = 137, // 80001
669
- appId = exchange ? 1 : 0,
670
- } = {},
671
- ) {
672
- let utxo: ExtendedUtxo[] =
673
- extendedUtxo || (await this.btcInterface.getBTCUtxo(signer.address, signer))
674
-
675
- const isExchange = !!exchange
676
- let dataHex = generateBrc2OpReturn({
677
- chainId,
678
- appId,
679
- brc20TokenId,
680
- inputAmount: BigNumber(brc.amount).multipliedBy(1e18).toFixed(0),
681
- recipientAddress,
682
- isExchange,
683
- outputToken: exchange?.outputToken,
684
- outputAmount: exchange?.outputAmount,
685
- })
686
- let opTarget = this.transactionBuilder.getOpReturnTarget(dataHex)
687
- let feeRate = staticFeeRate || (await this.btcInterface.getFeeRate("normal"))
688
- let transferTxUnsignedInfo = await this.transferBrc20Unsigned(
689
- lockerAddress,
690
- brcInscribeTx,
691
- signer,
692
- utxo,
693
- feeRate,
694
- [opTarget],
695
- )
696
- return transferTxUnsignedInfo
697
- }
698
-
699
- async wrapBrc20(
700
- recipientAddress: string,
701
- brc: { tick: string; amount: number | string },
702
- brc20TokenId: number,
703
- lockerAddress: string,
704
- exchange?: {
705
- outputToken: string
706
- outputAmount: string
707
- },
708
- extendedUtxo?: ExtendedUtxo[],
709
- staticFeeRate?: number,
710
- {
711
- chainId = 137, // 80001
712
- appId = exchange ? 1 : 0,
713
- } = {},
714
- ) {
715
- const isExchange = !!exchange
716
-
717
- let dataHex = generateBrc2OpReturn({
718
- chainId,
719
- appId,
720
- brc20TokenId,
721
- inputAmount: BigNumber(brc.amount).multipliedBy(1e18).toFixed(0),
722
- recipientAddress,
723
- isExchange,
724
- outputToken: exchange?.outputToken,
725
- outputAmount: exchange?.outputAmount,
726
- })
727
- let opTarget = this.transactionBuilder.getOpReturnTarget(dataHex)
728
- return this.inscribeAndTransferBrc20(
729
- lockerAddress,
730
- brc,
731
- [opTarget],
732
- extendedUtxo,
733
- staticFeeRate,
734
- )
735
- }
736
- }
737
-
738
- export default OrdinalWallet
1
+ import BigNumber from "bignumber.js"
2
+ import { bitcoin as bitcoinProviders } from "@teleportdao/providers"
3
+ import { BitcoinBaseWallet } from "./bitcoin-wallet-base"
4
+ // eslint-disable-next-line import/no-extraneous-dependencies
5
+ import { BitcoinConnectionInfo } from "./type"
6
+ import type { SignerInfo, ChangeTarget, Target, ExtendedUtxo } from "./transaction-builder"
7
+
8
+ import { OrdinalTransactionBuilder } from "./transaction-builder"
9
+ import BitcoinSign from "./sign/sign-transaction"
10
+ //
11
+ import { BitcoinInterfaceOrdinal } from "./bitcoin-interface-ordinal"
12
+
13
+ import { generateBrc2OpReturn } from "./helper/brc20-helper"
14
+ import { sleep } from "./utils/tools"
15
+
16
+ export class OrdinalWallet extends BitcoinBaseWallet {
17
+ unisat: bitcoinProviders.UniSat
18
+ transactionBuilder: OrdinalTransactionBuilder
19
+ btcInterface: BitcoinInterfaceOrdinal
20
+ signer: BitcoinSign
21
+ constructor(
22
+ networkName: string,
23
+ uniSatToken: string,
24
+ connectionInfo: BitcoinConnectionInfo = {
25
+ api: {
26
+ provider: "MempoolSpace",
27
+ },
28
+ },
29
+ ) {
30
+ super(networkName, connectionInfo)
31
+ if (!connectionInfo.rpc?.enabled) {
32
+ throw new Error("rpc is required")
33
+ }
34
+ this.transactionBuilder = new OrdinalTransactionBuilder(connectionInfo, networkName)
35
+ this.signer = new BitcoinSign(this.network)
36
+ this.btcInterface = new BitcoinInterfaceOrdinal(connectionInfo, networkName, uniSatToken)
37
+ this.unisat = this.btcInterface.unisat
38
+ }
39
+
40
+ async sendSignedPsbtWithRetry(signedPsbt: string, { numberOfRetry = 5, sleepTime = 5000 } = {}) {
41
+ let count = 0
42
+ while (count <= numberOfRetry) {
43
+ try {
44
+ let txId = await this.sendSignedPsbt(signedPsbt)
45
+ return txId
46
+ } catch (e: any) {
47
+ console.log(e.message)
48
+ await sleep(sleepTime + count * 5000)
49
+ count += 1
50
+ }
51
+ }
52
+ throw new Error("failed to send transaction")
53
+ }
54
+
55
+ static deployBRC20Data(tickName: string, max: number | string, limit: number | string) {
56
+ let data = {
57
+ p: "brc-20",
58
+ op: "deploy",
59
+ tick: tickName,
60
+ max: `${max}`,
61
+ lim: `${limit}`,
62
+ }
63
+ return {
64
+ buffer: Buffer.from(JSON.stringify(data), "utf8"),
65
+ type: "text/plain",
66
+ // type: "application/json",
67
+ }
68
+ }
69
+
70
+ static mintBRC20Data(tickName: string, amount: string | number) {
71
+ let data = {
72
+ p: "brc-20",
73
+ op: "mint",
74
+ tick: tickName,
75
+ amt: `${amount}`,
76
+ }
77
+ return {
78
+ buffer: Buffer.from(JSON.stringify(data), "utf8"),
79
+ type: "text/plain",
80
+ // type: "application/json",
81
+ }
82
+ }
83
+
84
+ static transferBRC20Data(tickName: string, amount: string | number) {
85
+ let data = {
86
+ p: "brc-20",
87
+ op: "transfer",
88
+ tick: tickName,
89
+ amt: `${amount}`,
90
+ }
91
+ return {
92
+ buffer: Buffer.from(JSON.stringify(data), "utf8"),
93
+ type: "text/plain",
94
+ // type: "application/json",
95
+ }
96
+ }
97
+
98
+ async sendUsingUtxosUnsigned({
99
+ receivers,
100
+ speed = "normal",
101
+ utxo,
102
+ changeAddress,
103
+ staticFeeRate,
104
+ }: {
105
+ receivers: {
106
+ address: string
107
+ value: number
108
+ }[]
109
+ changeAddress: string
110
+ speed?: "normal" | "fast" | "slow"
111
+ staticFeeRate?: number
112
+ utxo: ExtendedUtxo[]
113
+ }) {
114
+ let extendedUtxo: ExtendedUtxo[] = utxo
115
+
116
+ receivers.forEach(({ value }) => {
117
+ if (value - +value.toFixed(0) !== 0)
118
+ throw new Error("incorrect amount. amount should be in satoshi")
119
+ })
120
+
121
+ // eslint-disable-next-line no-underscore-dangle
122
+ let feeRate = staticFeeRate || (await this.transactionBuilder._getFeeRate(speed))
123
+ let unsignedTx = await this.transactionBuilder.processUnsignedTransaction({
124
+ extendedUtxo,
125
+ targets: receivers,
126
+ changeAddress,
127
+ feeRate,
128
+ fullAmount: false,
129
+ })
130
+
131
+ return {
132
+ ...unsignedTx,
133
+ possibleTxId: this.transactionBuilder.getUnsignedPsbtTxId(unsignedTx.unsignedTransaction),
134
+ }
135
+ }
136
+
137
+ async sendUsingUtxos({
138
+ receivers,
139
+ speed = "normal",
140
+ utxo,
141
+ }: {
142
+ receivers: {
143
+ address: string
144
+ value: number
145
+ }[]
146
+ speed?: "normal" | "fast" | "slow"
147
+ utxo?: ExtendedUtxo[]
148
+ }) {
149
+ if (!this.currentAccount || !this.currentAccountType || !this.publicKey || !this.privateKey) {
150
+ throw new Error("account not initialized")
151
+ }
152
+
153
+ let extendedUtxo: ExtendedUtxo[] = utxo
154
+ ? utxo.filter((u) => u.signerInfo.address === this.currentAccount!)
155
+ : await this.getExtendedUtxo({
156
+ address: this.currentAccount,
157
+ addressType: this.currentAccountType,
158
+ publicKey: this.publicKey.toString("hex"),
159
+ })
160
+
161
+ let unsignedTx = await this.sendUsingUtxosUnsigned({
162
+ receivers,
163
+ speed,
164
+ utxo: extendedUtxo,
165
+ changeAddress: this.bitcoinAddress!,
166
+ })
167
+ let signedPsbt = await this.signer.signPsbt(unsignedTx, this.privateKey)
168
+ let signedTx = this.signer.finalizePsbts([signedPsbt])
169
+ let txId = await this.transactionBuilder.sendTx(signedTx)
170
+ const { inputs, outputs, change, fee } = unsignedTx
171
+ return { txId, inputs, outputs, change, fee }
172
+ }
173
+
174
+ async inscribeOrdinalDepositUnsigned(
175
+ file: {
176
+ buffer: Buffer
177
+ type: string
178
+ },
179
+ signer: SignerInfo,
180
+ extendedUtxo?: ExtendedUtxo[],
181
+ staticFeeRate?: number,
182
+ ) {
183
+ const publicKey = Buffer.from(signer.publicKey, "hex")
184
+ let transferOrdinal = this.transactionBuilder.createOrdinalAddress(file, publicKey)
185
+ const leafScript = transferOrdinal.redeem.output
186
+ const { ordinalAddress } = transferOrdinal
187
+
188
+ let feeRate = staticFeeRate || (await this.btcInterface.getFeeRate("normal"))
189
+ let fee = +(((400 + leafScript.length) / 4) * feeRate * 1.5).toFixed(0)
190
+ let ordinalAmount = 600
191
+
192
+ let utxo1: ExtendedUtxo[] =
193
+ extendedUtxo || (await this.btcInterface.getBTCUtxo(signer.address, signer))
194
+
195
+ let inscribeDepositUnsignedInfo = await this.sendUsingUtxosUnsigned({
196
+ receivers: [
197
+ {
198
+ address: ordinalAddress,
199
+ value: ordinalAmount + fee,
200
+ },
201
+ ],
202
+ utxo: utxo1,
203
+ changeAddress: signer.address,
204
+ })
205
+
206
+ return {
207
+ inscribeDepositUnsignedInfo,
208
+ transferOrdinal,
209
+ }
210
+ }
211
+
212
+ async inscribeOrdinalUnsigned(
213
+ file: {
214
+ buffer: Buffer
215
+ type: string
216
+ },
217
+ signer: SignerInfo,
218
+ extendedUtxo?: ExtendedUtxo[],
219
+ staticFeeRate?: number,
220
+ ) {
221
+ const { inscribeDepositUnsignedInfo, transferOrdinal } =
222
+ await this.inscribeOrdinalDepositUnsigned(file, signer, extendedUtxo, staticFeeRate)
223
+ const { ordinalAddress } = transferOrdinal
224
+ let ordinalAmount = 600
225
+ let inscribeDeposit: {
226
+ hash: string
227
+ value: number
228
+ index: number
229
+ } = {
230
+ hash: inscribeDepositUnsignedInfo.possibleTxId,
231
+ value: inscribeDepositUnsignedInfo.outputs[0].value,
232
+ index: 0,
233
+ }
234
+ let inscribeUnsignedInfo = this.transactionBuilder.createInscribeUnsignedTx(
235
+ transferOrdinal,
236
+ inscribeDeposit,
237
+ this.bitcoinAddress!,
238
+ ordinalAmount,
239
+ )
240
+ return {
241
+ inscribeDepositUnsignedInfo: {
242
+ ...inscribeDepositUnsignedInfo,
243
+ possibleTxId: this.transactionBuilder.getUnsignedPsbtTxId(
244
+ inscribeDepositUnsignedInfo.unsignedTransaction,
245
+ ),
246
+ },
247
+ inscribeUnsignedInfo: {
248
+ ...inscribeUnsignedInfo,
249
+ possibleTxId: this.transactionBuilder.getUnsignedPsbtTxId(
250
+ inscribeUnsignedInfo.unsignedTransaction,
251
+ ),
252
+ },
253
+ inscribeAddress: ordinalAddress,
254
+ }
255
+ }
256
+
257
+ async inscribeOrdinal(
258
+ file: {
259
+ buffer: Buffer
260
+ type: string
261
+ },
262
+ extendedUtxo?: ExtendedUtxo[],
263
+ staticFeeRate?: number,
264
+ ) {
265
+ if (!this.currentAccount || !this.currentAccountType || !this.publicKey || !this.privateKey) {
266
+ throw new Error("account not initialized")
267
+ }
268
+
269
+ const { inscribeDepositUnsignedInfo, transferOrdinal } =
270
+ await this.inscribeOrdinalDepositUnsigned(file, this.signerInfo!, extendedUtxo, staticFeeRate)
271
+
272
+ let ordinalUtxo = await this.btcInterface.getBTCUtxo(
273
+ transferOrdinal.ordinalAddress,
274
+ this.signerInfo!,
275
+ )
276
+
277
+ let inscribeDeposit: {
278
+ inputs: {
279
+ hash: string
280
+ value: number
281
+ index: number
282
+ signerInfo: SignerInfo
283
+ }[]
284
+ hash: string
285
+ value: number
286
+ index: number
287
+ change?: ChangeTarget
288
+ changeIndex?: number
289
+ }
290
+
291
+ if (ordinalUtxo.length > 1) {
292
+ throw new Error("multiple deposit found for this ordinal address")
293
+ }
294
+
295
+ if (
296
+ ordinalUtxo.length === 0 ||
297
+ ordinalUtxo[0].value <
298
+ inscribeDepositUnsignedInfo.outputs[0].value -
299
+ inscribeDepositUnsignedInfo.outputs[0].value * 0.15
300
+ ) {
301
+ const signedPsbt1 = await this.signer.signPsbt(inscribeDepositUnsignedInfo, this.privateKey!)
302
+ console.log("inscribe deposit tx ...")
303
+ const inscribeDepositTxId = await this.sendSignedPsbt(signedPsbt1)
304
+ console.log(`inscribe deposit txId : ${inscribeDepositTxId}`)
305
+
306
+ inscribeDeposit = {
307
+ hash: inscribeDepositTxId,
308
+ value: inscribeDepositUnsignedInfo.outputs[0].value,
309
+ index: 0,
310
+ inputs: inscribeDepositUnsignedInfo.inputs,
311
+ change: inscribeDepositUnsignedInfo.change,
312
+ changeIndex: inscribeDepositUnsignedInfo.change
313
+ ? inscribeDepositUnsignedInfo.outputs.length
314
+ : undefined,
315
+ }
316
+ } else {
317
+ inscribeDeposit = {
318
+ hash: ordinalUtxo[0].hash,
319
+ value: ordinalUtxo[0].value,
320
+ index: ordinalUtxo[0].index,
321
+ inputs: [],
322
+ }
323
+ console.log("no need to deposit", inscribeDeposit)
324
+ }
325
+
326
+ const ordinalAmount = 600
327
+ let inscribeUnsignedInfo = this.transactionBuilder.createInscribeUnsignedTx(
328
+ transferOrdinal,
329
+ inscribeDeposit,
330
+ this.bitcoinAddress!,
331
+ ordinalAmount,
332
+ )
333
+
334
+ const signedPsbt2 = await this.signer.signPsbt(
335
+ inscribeUnsignedInfo,
336
+ this.privateKey!,
337
+ undefined,
338
+ false,
339
+ )
340
+
341
+ console.log("inscribeTxId ...")
342
+ await sleep(10 * 1000)
343
+ let inscribeTxId = await this.sendSignedPsbtWithRetry(signedPsbt2)
344
+ console.log("inscribeTxId", inscribeTxId)
345
+ return {
346
+ inscribeTx: { hash: inscribeTxId, index: 0, value: ordinalAmount },
347
+ inscribeDepositTx: inscribeDeposit,
348
+ inscribeAddress: transferOrdinal.ordinalAddress,
349
+ }
350
+ }
351
+
352
+ async deployBrc20(
353
+ brc: { tick: string; max: number; limit: number },
354
+ extendedUtxo?: ExtendedUtxo[],
355
+ staticFeeRate?: number,
356
+ ) {
357
+ let file = OrdinalWallet.deployBRC20Data(brc.tick, brc.max, brc.limit)
358
+ return this.inscribeOrdinal(file, extendedUtxo, staticFeeRate)
359
+ }
360
+
361
+ async mintBrc20(
362
+ brc: { tick: string; amount: number | string },
363
+ extendedUtxo?: ExtendedUtxo[],
364
+ staticFeeRate?: number,
365
+ ) {
366
+ let file = OrdinalWallet.mintBRC20Data(brc.tick, brc.amount)
367
+ return this.inscribeOrdinal(file, extendedUtxo, staticFeeRate)
368
+ }
369
+
370
+ async inscribeBrc20Unsigned(
371
+ brc: { tick: string; amount: number | string },
372
+ signer: SignerInfo,
373
+ extendedUtxo?: ExtendedUtxo[],
374
+ staticFeeRate?: number,
375
+ ) {
376
+ let file = OrdinalWallet.transferBRC20Data(brc.tick, brc.amount)
377
+ return this.inscribeOrdinalUnsigned(file, signer, extendedUtxo, staticFeeRate)
378
+ }
379
+
380
+ async inscribeBrc20(
381
+ brc: { tick: string; amount: number | string },
382
+ extendedUtxo?: ExtendedUtxo[],
383
+ staticFeeRate?: number,
384
+ ) {
385
+ let file = OrdinalWallet.transferBRC20Data(brc.tick, brc.amount)
386
+ return this.inscribeOrdinal(file, extendedUtxo, staticFeeRate)
387
+ }
388
+
389
+ async transferBrc20Unsigned(
390
+ receiver: string,
391
+ brcInscribeUtxo: {
392
+ hash: string
393
+ value: number
394
+ index: number
395
+ },
396
+ signer: SignerInfo,
397
+ extendedUtxo?: ExtendedUtxo[],
398
+ staticFeeRate?: number,
399
+ otherTargets?: Target[],
400
+ ) {
401
+ let utxo = extendedUtxo || (await this.btcInterface.getBTCUtxo(signer.address, signer))
402
+ let feeRate = staticFeeRate || (await this.btcInterface.getFeeRate("normal"))
403
+ let unsignedTx = await this.transactionBuilder.createNftPsbt({
404
+ extendedUtxo: utxo,
405
+ nftExtendedUtxo: {
406
+ hash: brcInscribeUtxo.hash,
407
+ index: 0,
408
+ value: brcInscribeUtxo.value,
409
+ signerInfo: signer,
410
+ },
411
+ feeRate,
412
+ receiverAddress: receiver,
413
+ changeAddress: signer.address,
414
+ otherTargets,
415
+ })
416
+ return {
417
+ ...unsignedTx,
418
+ possibleTxId: this.transactionBuilder.getUnsignedPsbtTxId(unsignedTx.unsignedTransaction),
419
+ }
420
+ }
421
+
422
+ async transferBrc20(
423
+ receiver: string,
424
+ brcInscribeUtxo: {
425
+ hash: string
426
+ value: number
427
+ index: number
428
+ },
429
+ extendedUtxo: ExtendedUtxo[],
430
+ staticFeeRate?: number,
431
+ otherTargets?: Target[],
432
+ ) {
433
+ if (!this.currentAccount || !this.currentAccountType || !this.publicKey || !this.privateKey) {
434
+ throw new Error("account not initialized")
435
+ }
436
+ let feeRate = staticFeeRate || (await this.btcInterface.getFeeRate("normal"))
437
+ let unsignedTx = await this.transactionBuilder.createNftPsbt({
438
+ extendedUtxo,
439
+ nftExtendedUtxo: {
440
+ hash: brcInscribeUtxo.hash,
441
+ index: 0,
442
+ value: brcInscribeUtxo.value,
443
+ signerInfo: this.signerInfo!,
444
+ },
445
+ feeRate,
446
+ receiverAddress: receiver,
447
+ changeAddress: this.bitcoinAddress!,
448
+ otherTargets,
449
+ })
450
+
451
+ let signedTx = await this.signer.signPsbt(unsignedTx, this.privateKey!)
452
+ let finalTransferTxId = await this.sendSignedPsbtWithRetry(signedTx)
453
+ return {
454
+ hash: finalTransferTxId,
455
+ index: 0,
456
+ value: brcInscribeUtxo.value,
457
+ inputs: unsignedTx.inputs,
458
+ change: unsignedTx.change,
459
+ changeIndex: unsignedTx.change ? unsignedTx.outputs.length : undefined,
460
+ }
461
+ }
462
+
463
+ async inscribeAndTransferBrc20Unsigned(
464
+ receiver: string,
465
+ brc: { tick: string; amount: number | string },
466
+ signer: SignerInfo,
467
+ otherTargets?: Target[],
468
+ extendedUtxo?: ExtendedUtxo[],
469
+ staticFeeRate?: number,
470
+ ) {
471
+ // check all fee before process transaction
472
+ let brc20Balance = await this.unisat.getBrc20AddressBalanceForTicker(signer.address, brc.tick)
473
+
474
+ if (BigNumber(brc20Balance.transferableBalance).gte(brc.amount)) {
475
+ let transferrableInscription = brc20Balance.transferableInscriptions.find(
476
+ (insc) => insc.data.tick === brc.tick && BigNumber(insc.data.amt).isEqualTo(brc.amount),
477
+ )
478
+
479
+ console.log("transferrableInscription", transferrableInscription)
480
+ }
481
+
482
+ if (BigNumber(brc20Balance.availableBalanceSafe).isLessThan(brc.amount)) {
483
+ throw new Error("insufficient balance")
484
+ }
485
+
486
+ let feeRate = staticFeeRate || (await this.btcInterface.getFeeRate("normal"))
487
+
488
+ let utxo1: ExtendedUtxo[] =
489
+ extendedUtxo || (await this.btcInterface.getBTCUtxo(signer.address, signer))
490
+ let utxo2: ExtendedUtxo[] = []
491
+ const { inscribeAddress, inscribeDepositUnsignedInfo, inscribeUnsignedInfo } =
492
+ await this.inscribeBrc20Unsigned(brc, signer, utxo1, feeRate)
493
+
494
+ utxo2 = utxo1.filter(
495
+ (u) =>
496
+ inscribeDepositUnsignedInfo.inputs.findIndex(
497
+ (i) => i.hash === u.hash && i.index === u.index,
498
+ ) === -1,
499
+ )
500
+
501
+ if (inscribeDepositUnsignedInfo.change) {
502
+ utxo2.push({
503
+ hash: inscribeDepositUnsignedInfo.possibleTxId,
504
+ index: inscribeDepositUnsignedInfo.outputs.length,
505
+ value: inscribeDepositUnsignedInfo.change.value,
506
+ signerInfo: signer,
507
+ })
508
+ }
509
+ let transferTxUnsignedInfo = await this.transferBrc20Unsigned(
510
+ receiver,
511
+ {
512
+ hash: inscribeUnsignedInfo.possibleTxId,
513
+ value: inscribeUnsignedInfo.outputs[0].value,
514
+ index: 0,
515
+ },
516
+ signer,
517
+ utxo2,
518
+ feeRate,
519
+ otherTargets,
520
+ )
521
+ return {
522
+ inscribeDepositUnsignedInfo,
523
+ inscribeUnsignedInfo,
524
+ transferTxUnsignedInfo,
525
+ inscribeAddress,
526
+ }
527
+ }
528
+
529
+ async inscribeAndTransferBrc20(
530
+ receiver: string,
531
+ brc: { tick: string; amount: number | string },
532
+ otherTargets?: Target[],
533
+ extendedUtxo?: ExtendedUtxo[],
534
+ staticFeeRate?: number,
535
+ ) {
536
+ // check all fee before process transaction
537
+ let brc20Balance = await this.unisat.getBrc20AddressBalanceForTicker(
538
+ this.bitcoinAddress!,
539
+ brc.tick,
540
+ )
541
+
542
+ if (BigNumber(brc20Balance.transferableBalance).gte(brc.amount)) {
543
+ let transferrableInscription = brc20Balance.transferableInscriptions.find(
544
+ (insc) => insc.data.tick === brc.tick && BigNumber(insc.data.amt).isEqualTo(brc.amount),
545
+ )
546
+ console.log("transferrableInscription", transferrableInscription)
547
+
548
+ if (transferrableInscription) {
549
+ let ins = await this.btcInterface.unisat.getInscriptionInfo(
550
+ transferrableInscription.inscriptionId,
551
+ )
552
+
553
+ if (ins) {
554
+ let transferTx = await this.transferBrc20(
555
+ receiver,
556
+ {
557
+ hash: ins.utxo.txid!,
558
+ index: ins.utxo.vout!,
559
+ value: ins.utxo.satoshi!,
560
+ },
561
+ extendedUtxo ||
562
+ (await this.btcInterface.getBTCUtxo(this.bitcoinAddress!, this.signerInfo!)),
563
+ staticFeeRate || (await this.btcInterface.getFeeRate("normal")),
564
+ otherTargets,
565
+ )
566
+ return {
567
+ transferTx,
568
+ }
569
+ }
570
+ }
571
+ }
572
+
573
+ if (BigNumber(brc20Balance.availableBalanceSafe).isLessThan(brc.amount)) {
574
+ throw new Error(`insufficient balance ${brc20Balance.availableBalanceSafe} ${brc.amount}`)
575
+ }
576
+
577
+ let feeRate = staticFeeRate || (await this.btcInterface.getFeeRate("normal"))
578
+
579
+ let utxo1: ExtendedUtxo[] =
580
+ extendedUtxo || (await this.btcInterface.getBTCUtxo(this.bitcoinAddress!, this.signerInfo!))
581
+ let utxo2: ExtendedUtxo[] = []
582
+ const { inscribeAddress, inscribeDepositTx, inscribeTx } = await this.inscribeBrc20(
583
+ brc,
584
+ utxo1,
585
+ feeRate,
586
+ )
587
+
588
+ utxo2 = utxo1.filter(
589
+ (u) =>
590
+ inscribeDepositTx.inputs.findIndex((i) => i.hash === u.hash && i.index === u.index) === -1,
591
+ )
592
+
593
+ if (inscribeDepositTx.change) {
594
+ utxo2.push({
595
+ hash: inscribeDepositTx.hash,
596
+ index: inscribeDepositTx.changeIndex!,
597
+ value: inscribeDepositTx.change.value,
598
+ signerInfo: this.signerInfo!,
599
+ })
600
+ }
601
+ await sleep(10 * 1000)
602
+ let transferTx = await this.transferBrc20(receiver, inscribeTx, utxo2, feeRate, otherTargets)
603
+ return {
604
+ inscribeTx,
605
+ inscribeAddress,
606
+ inscribeDepositTx,
607
+ transferTx,
608
+ }
609
+ }
610
+
611
+ async wrapBrc20Unsigned(
612
+ recipientAddress: string,
613
+ brc: { tick: string; amount: number | string },
614
+ brc20TokenId: number,
615
+ signer: SignerInfo,
616
+ lockerAddress: string,
617
+ exchange?: {
618
+ outputToken: string
619
+ outputAmount: string
620
+ },
621
+ extendedUtxo?: ExtendedUtxo[],
622
+ staticFeeRate?: number,
623
+ {
624
+ chainId = 137, // 80001
625
+ appId = exchange ? 1 : 0,
626
+ } = {},
627
+ ) {
628
+ const isExchange = !!exchange
629
+ let dataHex = generateBrc2OpReturn({
630
+ chainId,
631
+ appId,
632
+ brc20TokenId,
633
+ inputAmount: BigNumber(brc.amount).multipliedBy(1e18).toFixed(0),
634
+ recipientAddress,
635
+ isExchange,
636
+ outputToken: exchange?.outputToken,
637
+ outputAmount: exchange?.outputAmount,
638
+ })
639
+ let opTarget = this.transactionBuilder.getOpReturnTarget(dataHex)
640
+ return this.inscribeAndTransferBrc20Unsigned(
641
+ lockerAddress,
642
+ brc,
643
+ signer,
644
+ [opTarget],
645
+ extendedUtxo,
646
+ staticFeeRate,
647
+ )
648
+ }
649
+
650
+ async wrapBrc20OnlyTransferUnsigned(
651
+ recipientAddress: string,
652
+ brcInscribeTx: {
653
+ hash: string
654
+ value: number
655
+ index: number
656
+ },
657
+ brc: { tick: string; amount: number | string },
658
+ brc20TokenId: number,
659
+ signer: SignerInfo,
660
+ lockerAddress: string,
661
+ exchange?: {
662
+ outputToken: string
663
+ outputAmount: string
664
+ },
665
+ extendedUtxo?: ExtendedUtxo[],
666
+ staticFeeRate?: number,
667
+ {
668
+ chainId = 137, // 80001
669
+ appId = exchange ? 1 : 0,
670
+ } = {},
671
+ ) {
672
+ let utxo: ExtendedUtxo[] =
673
+ extendedUtxo || (await this.btcInterface.getBTCUtxo(signer.address, signer))
674
+
675
+ const isExchange = !!exchange
676
+ let dataHex = generateBrc2OpReturn({
677
+ chainId,
678
+ appId,
679
+ brc20TokenId,
680
+ inputAmount: BigNumber(brc.amount).multipliedBy(1e18).toFixed(0),
681
+ recipientAddress,
682
+ isExchange,
683
+ outputToken: exchange?.outputToken,
684
+ outputAmount: exchange?.outputAmount,
685
+ })
686
+ let opTarget = this.transactionBuilder.getOpReturnTarget(dataHex)
687
+ let feeRate = staticFeeRate || (await this.btcInterface.getFeeRate("normal"))
688
+ let transferTxUnsignedInfo = await this.transferBrc20Unsigned(
689
+ lockerAddress,
690
+ brcInscribeTx,
691
+ signer,
692
+ utxo,
693
+ feeRate,
694
+ [opTarget],
695
+ )
696
+ return transferTxUnsignedInfo
697
+ }
698
+
699
+ async wrapBrc20(
700
+ recipientAddress: string,
701
+ brc: { tick: string; amount: number | string },
702
+ brc20TokenId: number,
703
+ lockerAddress: string,
704
+ exchange?: {
705
+ outputToken: string
706
+ outputAmount: string
707
+ },
708
+ extendedUtxo?: ExtendedUtxo[],
709
+ staticFeeRate?: number,
710
+ {
711
+ chainId = 137, // 80001
712
+ appId = exchange ? 1 : 0,
713
+ } = {},
714
+ ) {
715
+ const isExchange = !!exchange
716
+
717
+ let dataHex = generateBrc2OpReturn({
718
+ chainId,
719
+ appId,
720
+ brc20TokenId,
721
+ inputAmount: BigNumber(brc.amount).multipliedBy(1e18).toFixed(0),
722
+ recipientAddress,
723
+ isExchange,
724
+ outputToken: exchange?.outputToken,
725
+ outputAmount: exchange?.outputAmount,
726
+ })
727
+ let opTarget = this.transactionBuilder.getOpReturnTarget(dataHex)
728
+ return this.inscribeAndTransferBrc20(
729
+ lockerAddress,
730
+ brc,
731
+ [opTarget],
732
+ extendedUtxo,
733
+ staticFeeRate,
734
+ )
735
+ }
736
+ }
737
+
738
+ export default OrdinalWallet