@lifi/sdk-provider-bitcoin 4.0.0-alpha.2 → 4.0.0-alpha.21

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 (73) hide show
  1. package/dist/cjs/BitcoinProvider.js +1 -1
  2. package/dist/cjs/BitcoinProvider.js.map +1 -1
  3. package/dist/cjs/client/publicClient.d.ts +1 -2
  4. package/dist/cjs/core/BitcoinStepExecutor.d.ts +15 -0
  5. package/dist/cjs/core/BitcoinStepExecutor.js +53 -0
  6. package/dist/cjs/core/BitcoinStepExecutor.js.map +1 -0
  7. package/dist/cjs/core/tasks/BitcoinSignAndExecuteTask.d.ts +5 -0
  8. package/dist/cjs/core/tasks/BitcoinSignAndExecuteTask.js +101 -0
  9. package/dist/cjs/core/tasks/BitcoinSignAndExecuteTask.js.map +1 -0
  10. package/dist/cjs/core/tasks/BitcoinWaitForTransactionTask.d.ts +5 -0
  11. package/dist/cjs/core/tasks/BitcoinWaitForTransactionTask.js +45 -0
  12. package/dist/cjs/core/tasks/BitcoinWaitForTransactionTask.js.map +1 -0
  13. package/dist/cjs/errors/parseBitcoinErrors.d.ts +2 -2
  14. package/dist/cjs/errors/parseBitcoinErrors.js +3 -3
  15. package/dist/cjs/errors/parseBitcoinErrors.js.map +1 -1
  16. package/dist/cjs/types.d.ts +7 -1
  17. package/dist/cjs/types.js.map +1 -1
  18. package/dist/cjs/version.d.ts +1 -1
  19. package/dist/cjs/version.js +1 -1
  20. package/dist/cjs/version.js.map +1 -1
  21. package/dist/esm/BitcoinProvider.js +1 -1
  22. package/dist/esm/BitcoinProvider.js.map +1 -1
  23. package/dist/esm/client/publicClient.d.ts +1 -2
  24. package/dist/esm/core/BitcoinStepExecutor.d.ts +15 -0
  25. package/dist/esm/core/BitcoinStepExecutor.js +51 -0
  26. package/dist/esm/core/BitcoinStepExecutor.js.map +1 -0
  27. package/dist/esm/core/tasks/BitcoinSignAndExecuteTask.d.ts +5 -0
  28. package/dist/esm/core/tasks/BitcoinSignAndExecuteTask.js +106 -0
  29. package/dist/esm/core/tasks/BitcoinSignAndExecuteTask.js.map +1 -0
  30. package/dist/esm/core/tasks/BitcoinWaitForTransactionTask.d.ts +5 -0
  31. package/dist/esm/core/tasks/BitcoinWaitForTransactionTask.js +41 -0
  32. package/dist/esm/core/tasks/BitcoinWaitForTransactionTask.js.map +1 -0
  33. package/dist/esm/errors/parseBitcoinErrors.d.ts +2 -2
  34. package/dist/esm/errors/parseBitcoinErrors.js +3 -3
  35. package/dist/esm/errors/parseBitcoinErrors.js.map +1 -1
  36. package/dist/esm/types.d.ts +7 -1
  37. package/dist/esm/types.js +1 -1
  38. package/dist/esm/types.js.map +1 -1
  39. package/dist/esm/version.d.ts +1 -1
  40. package/dist/esm/version.js +1 -1
  41. package/dist/esm/version.js.map +1 -1
  42. package/dist/types/client/publicClient.d.ts +1 -2
  43. package/dist/types/client/publicClient.d.ts.map +1 -1
  44. package/dist/types/core/BitcoinStepExecutor.d.ts +16 -0
  45. package/dist/types/core/BitcoinStepExecutor.d.ts.map +1 -0
  46. package/dist/types/core/tasks/BitcoinSignAndExecuteTask.d.ts +6 -0
  47. package/dist/types/core/tasks/BitcoinSignAndExecuteTask.d.ts.map +1 -0
  48. package/dist/types/core/tasks/BitcoinWaitForTransactionTask.d.ts +6 -0
  49. package/dist/types/core/tasks/BitcoinWaitForTransactionTask.d.ts.map +1 -0
  50. package/dist/types/errors/parseBitcoinErrors.d.ts +2 -2
  51. package/dist/types/errors/parseBitcoinErrors.d.ts.map +1 -1
  52. package/dist/types/types.d.ts +7 -1
  53. package/dist/types/types.d.ts.map +1 -1
  54. package/dist/types/version.d.ts +1 -1
  55. package/dist/types/version.d.ts.map +1 -1
  56. package/package.json +4 -4
  57. package/src/BitcoinProvider.ts +1 -1
  58. package/src/client/publicClient.ts +1 -1
  59. package/src/core/BitcoinStepExecutor.ts +98 -0
  60. package/src/core/tasks/BitcoinSignAndExecuteTask.ts +168 -0
  61. package/src/core/tasks/BitcoinWaitForTransactionTask.ts +74 -0
  62. package/src/errors/parseBitcoinErrors.ts +4 -4
  63. package/src/types.ts +13 -1
  64. package/src/version.ts +1 -1
  65. package/dist/cjs/BitcoinStepExecutor.d.ts +0 -12
  66. package/dist/cjs/BitcoinStepExecutor.js +0 -199
  67. package/dist/cjs/BitcoinStepExecutor.js.map +0 -1
  68. package/dist/esm/BitcoinStepExecutor.d.ts +0 -12
  69. package/dist/esm/BitcoinStepExecutor.js +0 -212
  70. package/dist/esm/BitcoinStepExecutor.js.map +0 -1
  71. package/dist/types/BitcoinStepExecutor.d.ts +0 -13
  72. package/dist/types/BitcoinStepExecutor.d.ts.map +0 -1
  73. package/src/BitcoinStepExecutor.ts +0 -344
@@ -1,344 +0,0 @@
1
- import type { Client, ReplacementReason } from '@bigmi/core'
2
- import {
3
- AddressType,
4
- getAddressInfo,
5
- hexToUnit8Array,
6
- signPsbt,
7
- waitForTransaction,
8
- withTimeout,
9
- } from '@bigmi/core'
10
- import * as ecc from '@bitcoinerlab/secp256k1'
11
- import {
12
- BaseStepExecutor,
13
- ChainId,
14
- checkBalance,
15
- getStepTransaction,
16
- LiFiErrorCode,
17
- type LiFiStepExtended,
18
- type SDKClient,
19
- type StepExecutorOptions,
20
- stepComparison,
21
- TransactionError,
22
- type TransactionParameters,
23
- waitForDestinationChainTransaction,
24
- } from '@lifi/sdk'
25
- import { address, initEccLib, networks, Psbt } from 'bitcoinjs-lib'
26
- import { getBitcoinPublicClient } from './client/publicClient.js'
27
- import { parseBitcoinErrors } from './errors/parseBitcoinErrors.js'
28
- import { generateRedeemScript } from './utils/generateRedeemScript.js'
29
- import { isPsbtFinalized } from './utils/isPsbtFinalized.js'
30
- import { toXOnly } from './utils/toXOnly.js'
31
-
32
- interface BitcoinStepExecutorOptions extends StepExecutorOptions {
33
- client: Client
34
- }
35
-
36
- export class BitcoinStepExecutor extends BaseStepExecutor {
37
- private client: Client
38
-
39
- constructor(options: BitcoinStepExecutorOptions) {
40
- super(options)
41
- this.client = options.client
42
- }
43
-
44
- checkClient = (step: LiFiStepExtended) => {
45
- // TODO: check chain and possibly implement chain switch?
46
- // Prevent execution of the quote by wallet different from the one which requested the quote
47
- if (this.client.account?.address !== step.action.fromAddress) {
48
- throw new TransactionError(
49
- LiFiErrorCode.WalletChangedDuringExecution,
50
- 'The wallet address that requested the quote does not match the wallet address attempting to sign the transaction.'
51
- )
52
- }
53
- }
54
-
55
- executeStep = async (
56
- client: SDKClient,
57
- step: LiFiStepExtended
58
- ): Promise<LiFiStepExtended> => {
59
- step.execution = this.statusManager.initExecutionObject(step)
60
-
61
- const fromChain = await client.getChainById(step.action.fromChainId)
62
- const toChain = await client.getChainById(step.action.toChainId)
63
-
64
- const isBridgeExecution = fromChain.id !== toChain.id
65
- const currentProcessType = isBridgeExecution ? 'CROSS_CHAIN' : 'SWAP'
66
-
67
- let process = this.statusManager.findOrCreateProcess({
68
- step,
69
- type: currentProcessType,
70
- chainId: fromChain.id,
71
- })
72
-
73
- const publicClient = await getBitcoinPublicClient(client, ChainId.BTC)
74
-
75
- if (process.status !== 'DONE') {
76
- try {
77
- let txHash: string
78
- let txHex: string
79
- if (process.txHash) {
80
- // Make sure that the chain is still correct
81
- this.checkClient(step)
82
-
83
- // Wait for exiting transaction
84
- txHash = process.txHash
85
- txHex = process.txHex
86
- } else {
87
- process = this.statusManager.updateProcess(
88
- step,
89
- process.type,
90
- 'STARTED'
91
- )
92
-
93
- // Check balance
94
- await checkBalance(client, this.client.account!.address, step)
95
-
96
- // Create new transaction
97
- if (!step.transactionRequest) {
98
- // biome-ignore lint/correctness/noUnusedVariables: destructuring
99
- const { execution, ...stepBase } = step
100
- const updatedStep = await getStepTransaction(client, stepBase)
101
- const comparedStep = await stepComparison(
102
- this.statusManager,
103
- step,
104
- updatedStep,
105
- this.allowUserInteraction,
106
- this.executionOptions
107
- )
108
- Object.assign(step, {
109
- ...comparedStep,
110
- execution: step.execution,
111
- })
112
- }
113
-
114
- if (!step.transactionRequest?.data) {
115
- throw new TransactionError(
116
- LiFiErrorCode.TransactionUnprepared,
117
- 'Unable to prepare transaction.'
118
- )
119
- }
120
-
121
- process = this.statusManager.updateProcess(
122
- step,
123
- process.type,
124
- 'ACTION_REQUIRED'
125
- )
126
-
127
- if (!this.allowUserInteraction) {
128
- return step
129
- }
130
-
131
- let transactionRequest: TransactionParameters = {
132
- data: step.transactionRequest.data,
133
- }
134
-
135
- if (this.executionOptions?.updateTransactionRequestHook) {
136
- const customizedTransactionRequest: TransactionParameters =
137
- await this.executionOptions.updateTransactionRequestHook({
138
- requestType: 'transaction',
139
- ...transactionRequest,
140
- })
141
-
142
- transactionRequest = {
143
- ...transactionRequest,
144
- ...customizedTransactionRequest,
145
- }
146
- }
147
-
148
- if (!transactionRequest.data) {
149
- throw new TransactionError(
150
- LiFiErrorCode.TransactionUnprepared,
151
- 'Unable to prepare transaction.'
152
- )
153
- }
154
-
155
- this.checkClient(step)
156
-
157
- const psbtHex = transactionRequest.data
158
-
159
- // Initialize ECC library required for Taproot operations
160
- // https://github.com/bitcoinjs/bitcoinjs-lib?tab=readme-ov-file#using-taproot
161
- initEccLib(ecc)
162
-
163
- const psbt = Psbt.fromHex(psbtHex, { network: networks.bitcoin })
164
-
165
- psbt.data.inputs.forEach((input, index) => {
166
- const accountAddress = input.witnessUtxo
167
- ? address.fromOutputScript(
168
- input.witnessUtxo.script,
169
- networks.bitcoin
170
- )
171
- : (this.client.account?.address as string)
172
- const addressInfo = getAddressInfo(accountAddress)
173
- if (addressInfo.type === AddressType.p2tr) {
174
- // Taproot (P2TR) addresses require specific PSBT fields for proper signing
175
-
176
- // tapInternalKey: Required for Taproot key-path spending
177
- // Most wallets / libraries usually handle this already
178
- if (!input.tapInternalKey) {
179
- const pubKey = this.client.account?.publicKey
180
- if (pubKey) {
181
- const tapInternalKey = toXOnly(hexToUnit8Array(pubKey))
182
- psbt.updateInput(index, {
183
- tapInternalKey,
184
- })
185
- }
186
- }
187
- // sighashType: Required by bitcoinjs-lib even though the bitcoin protocol allows defaults
188
- // check if sighashType is default (0) or not set (undefined)
189
- if (!input.sighashType) {
190
- psbt.updateInput(index, {
191
- sighashType: 1, // Default to Transaction.SIGHASH_ALL - 1
192
- })
193
- }
194
- }
195
- // redeemScript: Required by Pay-to-Script-Hash (P2SH) addresses for proper spending
196
- if (addressInfo.type === AddressType.p2sh) {
197
- if (!input.redeemScript) {
198
- const pubKey = this.client.account?.publicKey
199
- if (pubKey) {
200
- psbt.updateInput(index, {
201
- redeemScript: generateRedeemScript(hexToUnit8Array(pubKey)),
202
- })
203
- }
204
- }
205
- }
206
- })
207
-
208
- const inputsToSign = Array.from(
209
- psbt.data.inputs
210
- .reduce((map, input, index) => {
211
- const accountAddress = input.witnessUtxo
212
- ? address.fromOutputScript(
213
- input.witnessUtxo.script,
214
- networks.bitcoin
215
- )
216
- : (this.client.account?.address as string)
217
- if (map.has(accountAddress)) {
218
- map.get(accountAddress).signingIndexes.push(index)
219
- } else {
220
- map.set(accountAddress, {
221
- address: accountAddress,
222
- sigHash: 1, // Default to Transaction.SIGHASH_ALL - 1
223
- signingIndexes: [index],
224
- })
225
- }
226
- return map
227
- }, new Map())
228
- .values()
229
- )
230
-
231
- // We give users 10 minutes to sign the transaction or it should be considered expired
232
- const signedPsbtHex = await withTimeout(
233
- () =>
234
- signPsbt(this.client, {
235
- psbt: psbt.toHex(),
236
- inputsToSign: inputsToSign,
237
- finalize: false,
238
- }),
239
- {
240
- timeout: 600_000,
241
- errorInstance: new TransactionError(
242
- LiFiErrorCode.TransactionExpired,
243
- 'Transaction has expired.'
244
- ),
245
- }
246
- )
247
-
248
- const signedPsbt = Psbt.fromHex(signedPsbtHex)
249
-
250
- if (!isPsbtFinalized(signedPsbt)) {
251
- signedPsbt.finalizeAllInputs()
252
- }
253
-
254
- txHex = signedPsbt.extractTransaction().toHex()
255
-
256
- txHash = await publicClient.sendUTXOTransaction({
257
- hex: txHex,
258
- })
259
-
260
- process = this.statusManager.updateProcess(
261
- step,
262
- process.type,
263
- 'PENDING',
264
- {
265
- txHash: txHash,
266
- txLink: `${fromChain.metamask.blockExplorerUrls[0]}tx/${txHash}`,
267
- txHex,
268
- }
269
- )
270
- }
271
-
272
- let replacementReason: ReplacementReason | undefined
273
- const transaction = await waitForTransaction(publicClient, {
274
- txId: txHash,
275
- txHex,
276
- senderAddress: this.client.account?.address,
277
- onReplaced: (response) => {
278
- replacementReason = response.reason
279
- process = this.statusManager.updateProcess(
280
- step,
281
- process.type,
282
- 'PENDING',
283
- {
284
- txHash: response.transaction.txid,
285
- txLink: `${fromChain.metamask.blockExplorerUrls[0]}tx/${response.transaction.txid}`,
286
- }
287
- )
288
- },
289
- })
290
-
291
- if (replacementReason === 'cancelled') {
292
- throw new TransactionError(
293
- LiFiErrorCode.TransactionCanceled,
294
- 'User canceled transaction.'
295
- )
296
- }
297
-
298
- if (transaction.txid !== txHash) {
299
- process = this.statusManager.updateProcess(
300
- step,
301
- process.type,
302
- 'PENDING',
303
- {
304
- txHash: transaction.txid,
305
- txLink: `${fromChain.metamask.blockExplorerUrls[0]}tx/${transaction.txid}`,
306
- }
307
- )
308
- }
309
-
310
- if (isBridgeExecution) {
311
- process = this.statusManager.updateProcess(step, process.type, 'DONE')
312
- }
313
- } catch (e: any) {
314
- const error = await parseBitcoinErrors(e, step, process)
315
- process = this.statusManager.updateProcess(
316
- step,
317
- process.type,
318
- 'FAILED',
319
- {
320
- error: {
321
- message: error.cause.message,
322
- code: error.code,
323
- },
324
- }
325
- )
326
- this.statusManager.updateExecution(step, 'FAILED')
327
- throw error
328
- }
329
- }
330
-
331
- await waitForDestinationChainTransaction(
332
- client,
333
- step,
334
- process,
335
- fromChain,
336
- toChain,
337
- this.statusManager,
338
- 10_000
339
- )
340
-
341
- // DONE
342
- return step
343
- }
344
- }