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