@atomiqlabs/sdk 8.8.3 → 8.9.1

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 (130) hide show
  1. package/api/index.d.ts +1 -0
  2. package/api/index.js +3 -0
  3. package/dist/ApiList.d.ts +37 -0
  4. package/dist/ApiList.js +30 -0
  5. package/dist/api/ApiEndpoints.d.ts +393 -0
  6. package/dist/api/ApiEndpoints.js +2 -0
  7. package/dist/api/ApiParser.d.ts +10 -0
  8. package/dist/api/ApiParser.js +134 -0
  9. package/dist/api/ApiTypes.d.ts +157 -0
  10. package/dist/api/ApiTypes.js +75 -0
  11. package/dist/api/SerializedAction.d.ts +40 -0
  12. package/dist/api/SerializedAction.js +59 -0
  13. package/dist/api/SwapperApi.d.ts +50 -0
  14. package/dist/api/SwapperApi.js +431 -0
  15. package/dist/api/index.d.ts +5 -0
  16. package/dist/api/index.js +24 -0
  17. package/dist/events/UnifiedSwapEventListener.d.ts +4 -3
  18. package/dist/events/UnifiedSwapEventListener.js +8 -2
  19. package/dist/http/HttpUtils.d.ts +4 -2
  20. package/dist/http/HttpUtils.js +10 -4
  21. package/dist/http/paramcoders/client/StreamingFetchPromise.d.ts +2 -1
  22. package/dist/http/paramcoders/client/StreamingFetchPromise.js +3 -2
  23. package/dist/index.d.ts +1 -0
  24. package/dist/index.js +1 -0
  25. package/dist/intermediaries/IntermediaryDiscovery.d.ts +7 -2
  26. package/dist/intermediaries/IntermediaryDiscovery.js +4 -4
  27. package/dist/intermediaries/apis/IntermediaryAPI.d.ts +171 -14
  28. package/dist/intermediaries/apis/IntermediaryAPI.js +174 -28
  29. package/dist/intermediaries/auth/SignedKeyBasedAuth.d.ts +14 -0
  30. package/dist/intermediaries/auth/SignedKeyBasedAuth.js +68 -0
  31. package/dist/storage/IUnifiedStorage.d.ts +45 -3
  32. package/dist/storage/UnifiedSwapStorage.d.ts +8 -2
  33. package/dist/storage/UnifiedSwapStorage.js +46 -8
  34. package/dist/swapper/Swapper.d.ts +41 -3
  35. package/dist/swapper/Swapper.js +93 -48
  36. package/dist/swapper/SwapperUtils.d.ts +18 -2
  37. package/dist/swapper/SwapperUtils.js +39 -1
  38. package/dist/swaps/ISwap.d.ts +70 -9
  39. package/dist/swaps/ISwap.js +28 -6
  40. package/dist/swaps/ISwapWrapper.d.ts +11 -1
  41. package/dist/swaps/ISwapWrapper.js +23 -3
  42. package/dist/swaps/escrow_swaps/IEscrowSwap.d.ts +1 -1
  43. package/dist/swaps/escrow_swaps/IEscrowSwap.js +4 -2
  44. package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.d.ts +2 -1
  45. package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.js +2 -2
  46. package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.d.ts +3 -1
  47. package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.js +3 -2
  48. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.d.ts +47 -31
  49. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.js +201 -67
  50. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.d.ts +3 -1
  51. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.js +6 -6
  52. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.d.ts +82 -15
  53. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.js +304 -98
  54. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.d.ts +3 -1
  55. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.js +6 -6
  56. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.d.ts +75 -42
  57. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.js +424 -87
  58. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.d.ts +3 -1
  59. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.js +7 -7
  60. package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.d.ts +54 -11
  61. package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.js +214 -41
  62. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.d.ts +2 -1
  63. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.js +7 -8
  64. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.d.ts +3 -1
  65. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.js +5 -5
  66. package/dist/swaps/spv_swaps/SpvFromBTCSwap.d.ts +76 -19
  67. package/dist/swaps/spv_swaps/SpvFromBTCSwap.js +290 -51
  68. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.d.ts +3 -1
  69. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.js +5 -5
  70. package/dist/swaps/trusted/ln/LnForGasSwap.d.ts +53 -12
  71. package/dist/swaps/trusted/ln/LnForGasSwap.js +163 -49
  72. package/dist/swaps/trusted/ln/LnForGasWrapper.js +1 -2
  73. package/dist/swaps/trusted/onchain/OnchainForGasSwap.d.ts +14 -13
  74. package/dist/swaps/trusted/onchain/OnchainForGasSwap.js +30 -47
  75. package/dist/swaps/trusted/onchain/OnchainForGasWrapper.d.ts +3 -1
  76. package/dist/swaps/trusted/onchain/OnchainForGasWrapper.js +4 -4
  77. package/dist/types/SwapExecutionAction.d.ts +141 -34
  78. package/dist/types/SwapExecutionAction.js +104 -0
  79. package/dist/types/SwapExecutionStep.d.ts +144 -0
  80. package/dist/types/SwapExecutionStep.js +87 -0
  81. package/dist/types/TokenAmount.d.ts +6 -0
  82. package/dist/types/TokenAmount.js +26 -1
  83. package/dist/utils/BitcoinUtils.d.ts +2 -0
  84. package/dist/utils/BitcoinUtils.js +34 -1
  85. package/dist/utils/Utils.d.ts +3 -1
  86. package/dist/utils/Utils.js +7 -1
  87. package/package.json +7 -4
  88. package/src/api/ApiEndpoints.ts +427 -0
  89. package/src/api/ApiParser.ts +138 -0
  90. package/src/api/ApiTypes.ts +229 -0
  91. package/src/api/SerializedAction.ts +97 -0
  92. package/src/api/SwapperApi.ts +545 -0
  93. package/src/api/index.ts +5 -0
  94. package/src/events/UnifiedSwapEventListener.ts +11 -3
  95. package/src/http/HttpUtils.ts +10 -4
  96. package/src/http/paramcoders/client/StreamingFetchPromise.ts +4 -2
  97. package/src/index.ts +1 -0
  98. package/src/intermediaries/IntermediaryDiscovery.ts +9 -2
  99. package/src/intermediaries/apis/IntermediaryAPI.ts +314 -30
  100. package/src/intermediaries/auth/SignedKeyBasedAuth.ts +69 -0
  101. package/src/storage/IUnifiedStorage.ts +45 -4
  102. package/src/storage/UnifiedSwapStorage.ts +42 -8
  103. package/src/swapper/Swapper.ts +134 -52
  104. package/src/swapper/SwapperUtils.ts +42 -2
  105. package/src/swaps/ISwap.ts +88 -16
  106. package/src/swaps/ISwapWrapper.ts +28 -3
  107. package/src/swaps/escrow_swaps/IEscrowSwap.ts +5 -3
  108. package/src/swaps/escrow_swaps/IEscrowSwapWrapper.ts +3 -1
  109. package/src/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.ts +4 -1
  110. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.ts +264 -67
  111. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.ts +6 -4
  112. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.ts +390 -89
  113. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.ts +6 -4
  114. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.ts +548 -94
  115. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.ts +7 -5
  116. package/src/swaps/escrow_swaps/tobtc/IToBTCSwap.ts +276 -45
  117. package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.ts +7 -6
  118. package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.ts +5 -3
  119. package/src/swaps/spv_swaps/SpvFromBTCSwap.ts +393 -57
  120. package/src/swaps/spv_swaps/SpvFromBTCWrapper.ts +5 -3
  121. package/src/swaps/trusted/ln/LnForGasSwap.ts +211 -47
  122. package/src/swaps/trusted/ln/LnForGasWrapper.ts +1 -2
  123. package/src/swaps/trusted/onchain/OnchainForGasSwap.ts +32 -51
  124. package/src/swaps/trusted/onchain/OnchainForGasWrapper.ts +5 -3
  125. package/src/types/SwapExecutionAction.ts +266 -43
  126. package/src/types/SwapExecutionStep.ts +224 -0
  127. package/src/types/TokenAmount.ts +36 -2
  128. package/src/utils/BitcoinUtils.ts +32 -0
  129. package/src/utils/Utils.ts +10 -1
  130. package/src/intermediaries/apis/TrustedIntermediaryAPI.ts +0 -258
@@ -1,91 +1,315 @@
1
1
  import {ChainType} from "@atomiqlabs/base";
2
2
  import {Transaction} from "@scure/btc-signer";
3
+ import {isTokenAmount, TokenAmount} from "./TokenAmount";
4
+ import {BitcoinTokens, BtcToken, isBtcToken} from "./Token";
5
+
6
+ const swapExecutionActionWaitNames = {
7
+ LP: "Awaiting LP payout",
8
+ SETTLEMENT: "Automatic settlement",
9
+ BITCOIN_CONFS: "Bitcoin confirmations"
10
+ } as const;
11
+
12
+ function isSwapExecutionActionPsbtTx(
13
+ obj: any,
14
+ type?: "FUNDED_PSBT" | "RAW_PSBT"
15
+ ): obj is SwapExecutionActionSignPSBT["txs"][number] {
16
+ const resolvedType = type ?? obj?.type;
17
+ if(obj == null || typeof(obj) !== "object") return false;
18
+ if(resolvedType !== "FUNDED_PSBT" && resolvedType !== "RAW_PSBT") return false;
19
+ return obj.type === resolvedType &&
20
+ obj.psbt instanceof Transaction &&
21
+ typeof(obj.psbtHex) === "string" &&
22
+ typeof(obj.psbtBase64) === "string" &&
23
+ (
24
+ resolvedType === "FUNDED_PSBT"
25
+ ? Array.isArray(obj.signInputs) && obj.signInputs.every((input: any) => typeof(input) === "number")
26
+ : typeof(obj.in1sequence) === "number"
27
+ );
28
+ }
3
29
 
4
30
  /**
5
- * Swap execution action requiring a payment of the provided bolt11 lightning network invoice
31
+ * Swap execution action requiring the user to send assets to a specific LIGHTNING invoice or BITCOIN
32
+ * on-chain address
6
33
  *
7
34
  * @category Swap Actions
8
35
  */
9
- export type SwapExecutionActionLightning = {
10
- name: "Payment",
36
+ export type SwapExecutionActionSendToAddress<Lightning extends boolean = boolean> = {
37
+ type: "SendToAddress",
38
+ /**
39
+ * Human-readable name of the action
40
+ */
41
+ name: Lightning extends true ? "Deposit on Lightning" : "Deposit on Bitcoin",
42
+ /**
43
+ * Human-readable description of the action
44
+ */
11
45
  description: string,
12
- chain: "LIGHTNING",
46
+ /**
47
+ * Chain on which the payment is expected, either `LIGHTNING` or `BITCOIN` for on-chain
48
+ */
49
+ chain: Lightning extends true ? "LIGHTNING" : "BITCOIN",
50
+ /**
51
+ * An array of payments that should be made to different addresses, usually only a single address is returned
52
+ */
13
53
  txs: {
14
- type: "BOLT11_PAYMENT_REQUEST",
54
+ type: Lightning extends true ? "BOLT11_PAYMENT_REQUEST" : "BITCOIN_ADDRESS",
15
55
  address: string,
16
- hyperlink: string
17
- }[]
56
+ hyperlink: string,
57
+ amount: TokenAmount<BtcToken<Lightning>, true>
58
+ }[],
59
+ /**
60
+ * Waits till the transaction is received, doesn't wait for the actual confirmation!
61
+ *
62
+ * @returns A transaction ID of the received transaction
63
+ */
64
+ waitForTransactions: (maxWaitTimeSeconds?: number, pollIntervalSeconds?: number, abortSignal?: AbortSignal) => Promise<string>
18
65
  }
19
66
 
20
67
  /**
21
- * Swap execution action on on-chain Bitcoin, has following types:
22
- * - `"ADDRESS"` - Destination bitcoin address and BTC amount to be sent
68
+ * Type guard for {@link SwapExecutionActionSendToAddress}
69
+ *
70
+ * @category Swap Actions
71
+ */
72
+ export function isSwapExecutionActionSendToAddress<Lightning extends boolean = boolean>(
73
+ obj: any,
74
+ lightning?: Lightning
75
+ ): obj is SwapExecutionActionSendToAddress<Lightning> {
76
+ const resolvedLightning = lightning ?? (obj?.chain === "LIGHTNING");
77
+ return obj != null &&
78
+ typeof(obj) === "object" &&
79
+ obj.type === "SendToAddress" &&
80
+ obj.name === (resolvedLightning ? "Deposit on Lightning" : "Deposit on Bitcoin") &&
81
+ typeof(obj.description) === "string" &&
82
+ obj.chain === (resolvedLightning ? "LIGHTNING" : "BITCOIN") &&
83
+ Array.isArray(obj.txs) &&
84
+ obj.txs.every((tx: any) =>
85
+ tx != null &&
86
+ typeof(tx) === "object" &&
87
+ tx.type === (resolvedLightning ? "BOLT11_PAYMENT_REQUEST" : "BITCOIN_ADDRESS") &&
88
+ typeof(tx.address) === "string" &&
89
+ typeof(tx.hyperlink) === "string" &&
90
+ isTokenAmount(
91
+ tx.amount,
92
+ resolvedLightning ? BitcoinTokens.BTCLN : BitcoinTokens.BTC,
93
+ true
94
+ )
95
+ ) &&
96
+ typeof(obj.waitForTransactions) === "function";
97
+ }
98
+
99
+ /**
100
+ * Swap execution action requiring the user to sign the provided PSBT and then submit it back via the provided
101
+ * `submitPsbt()` function, has two variations:
23
102
  * - `"FUNDED_PSBT"` - A ready to sign PSBT with the inputs populated from the provided bitcoin wallet address
24
103
  * - `"RAW_PSBT"` - Raw PSBT without the inputs, the implementor needs to add the input UTXOs before signing
25
- * the transaction
104
+ * the transaction (also make sure to set the `nSequence` field of the 2nd input, index 1, to the provided
105
+ * `in1sequence` value)
26
106
  *
27
107
  * @category Swap Actions
28
108
  */
29
- export type SwapExecutionActionBitcoin<
30
- T extends "ADDRESS" | "FUNDED_PSBT" | "RAW_PSBT" = "ADDRESS" | "FUNDED_PSBT" | "RAW_PSBT"
109
+ export type SwapExecutionActionSignPSBT<
110
+ T extends "FUNDED_PSBT" | "RAW_PSBT" = "FUNDED_PSBT" | "RAW_PSBT"
31
111
  > = {
32
- name: "Payment",
112
+ type: "SignPSBT",
113
+ /**
114
+ * Human-readable name of the action
115
+ */
116
+ name: "Deposit on Bitcoin",
117
+ /**
118
+ * Human-readable description of the action
119
+ */
33
120
  description: string,
121
+ /**
122
+ * Chain is always bitcoin
123
+ */
34
124
  chain: "BITCOIN",
35
- txs: (T extends "ADDRESS" ? {
36
- type: "ADDRESS",
37
- amount: number,
38
- address: string,
39
- hyperlink: string
40
- } : T extends "FUNDED_PSBT" ? {
125
+ /**
126
+ * An array of PSBTs that need to be signed, usually contains only a single PSBT
127
+ */
128
+ txs: T extends "FUNDED_PSBT" ? {
41
129
  type: "FUNDED_PSBT",
42
130
  psbt: Transaction,
43
131
  psbtHex: string,
44
132
  psbtBase64: string,
45
- signInputs: number[]
46
- } : {
133
+ signInputs: number[],
134
+ feeRate: number
135
+ }[] : {
47
136
  type: "RAW_PSBT",
48
137
  psbt: Transaction,
49
138
  psbtHex: string,
50
139
  psbtBase64: string,
51
- in1sequence: number
52
- })[]
140
+ in1sequence: number,
141
+ feeRate: number
142
+ }[],
143
+ /**
144
+ * Submit a signed PSBT, accepts hexadecimal, base64 and `@scure/btc-signer` {@link Transaction} object.
145
+ *
146
+ * @returns An array of transaction IDs of the submitted Bitcoin transactions
147
+ */
148
+ submitPsbt: (signedPsbt: string | Transaction | (string | Transaction)[], idempotent?: boolean) => Promise<string[]>
53
149
  }
54
150
 
55
151
  /**
56
- * Swap execution action for committing (initiating) the escrow on the smart chain side
152
+ * Type guard for {@link SwapExecutionActionSignPSBT}
57
153
  *
58
154
  * @category Swap Actions
59
155
  */
60
- export type SwapExecutionActionCommit<T extends ChainType> = {
61
- name: "Commit",
62
- description: string,
63
- chain: T["ChainId"],
64
- txs: T["TX"][]
156
+ export function isSwapExecutionActionSignPSBT<
157
+ T extends "FUNDED_PSBT" | "RAW_PSBT" = "FUNDED_PSBT" | "RAW_PSBT"
158
+ >(
159
+ obj: any,
160
+ psbtType?: T
161
+ ): obj is SwapExecutionActionSignPSBT<T> {
162
+ const resolvedPsbtType = psbtType ?? obj?.txs?.[0]?.type;
163
+ return obj != null &&
164
+ typeof(obj) === "object" &&
165
+ obj.type === "SignPSBT" &&
166
+ obj.name === "Deposit on Bitcoin" &&
167
+ typeof(obj.description) === "string" &&
168
+ obj.chain === "BITCOIN" &&
169
+ Array.isArray(obj.txs) &&
170
+ obj.txs.every((tx: any) => isSwapExecutionActionPsbtTx(tx, resolvedPsbtType)) &&
171
+ typeof(obj.submitPsbt) === "function";
65
172
  }
66
173
 
67
174
  /**
68
- * Swap execution action for claiming (settling) the swap on the smart chain side
175
+ * Swap execution action requiring the user to sign the provided smart chain transactions, these can then
176
+ * be either broadcasted manually, or sent via the provided `submitTransactions()` function
69
177
  *
70
178
  * @category Swap Actions
71
179
  */
72
- export type SwapExecutionActionClaim<T extends ChainType> = {
73
- name: "Claim",
180
+ export type SwapExecutionActionSignSmartChainTx<T extends ChainType = ChainType> = {
181
+ type: "SignSmartChainTransaction",
182
+ /**
183
+ * Human-readable name of the action
184
+ */
185
+ name: "Initiate swap" | "Settle manually" | "Refund",
186
+ /**
187
+ * Human-readable description of the action
188
+ */
74
189
  description: string,
190
+ /**
191
+ * Chain identifier of the smart chain on which the corresponding transactions should be signed
192
+ */
75
193
  chain: T["ChainId"],
76
- txs: T["TX"][]
194
+ /**
195
+ * Smart chain transactions that should be signed and either broadcasted manually or submitted back
196
+ * to the provided `submitTransactions()` function
197
+ */
198
+ txs: T["TX"][],
199
+ /**
200
+ * Submits the signed transactions and waits for their confirmation
201
+ *
202
+ * @remarks This might not do any validation on the submitted transactions, so returned txids are informational
203
+ * only and may not be persisted immediately. The swap may wait for an authoritative state transition before
204
+ * considering the submitted transactions accepted.
205
+ *
206
+ * Make sure to only submit valid signed transactions obtained from this action object, and pass an AbortSignal
207
+ * if you need a timeout, otherwise this call can wait indefinitely when invalid transactions are submitted.
208
+ */
209
+ submitTransactions: (txs: (T["SignedTXType"] | string)[], abortSignal?: AbortSignal, idempotent?: boolean) => Promise<string[]>,
210
+ /**
211
+ * The address of the signer that has to sign the transactions
212
+ */
213
+ requiredSigner: string
214
+ }
215
+
216
+ /**
217
+ * Type guard for {@link SwapExecutionActionSignSmartChainTx}
218
+ *
219
+ * @category Swap Actions
220
+ */
221
+ export function isSwapExecutionActionSignSmartChainTx<T extends ChainType = ChainType>(
222
+ obj: any,
223
+ chainIdentifier?: T["ChainId"] | T["ChainId"][]
224
+ ): obj is SwapExecutionActionSignSmartChainTx<T> {
225
+ const allowedChains = chainIdentifier == null ? null : Array.isArray(chainIdentifier) ? chainIdentifier : [chainIdentifier];
226
+ return obj != null &&
227
+ typeof(obj) === "object" &&
228
+ obj.type === "SignSmartChainTransaction" &&
229
+ (
230
+ obj.name === "Initiate swap" ||
231
+ obj.name === "Settle manually" ||
232
+ obj.name === "Refund"
233
+ ) &&
234
+ typeof(obj.description) === "string" &&
235
+ typeof(obj.chain) === "string" &&
236
+ (allowedChains == null || allowedChains.includes(obj.chain)) &&
237
+ Array.isArray(obj.txs) &&
238
+ typeof(obj.submitTransactions) === "function" &&
239
+ typeof(obj.requiredSigner) === "string";
77
240
  }
78
241
 
79
242
  /**
80
- * Swap execution action for refunding the swap on the smart chain side after it fails
243
+ * Swap action indicating that the user should wait for either LP to process the swap, automatic settlement to happen or
244
+ * until the Bitcoin transaction gets enough confirmations
81
245
  *
82
246
  * @category Swap Actions
83
247
  */
84
- export type SwapExecutionActionRefund<T extends ChainType> = {
85
- name: "Refund",
248
+ export type SwapExecutionActionWait<
249
+ T extends "LP" | "SETTLEMENT" | "BITCOIN_CONFS" = "LP" | "SETTLEMENT" | "BITCOIN_CONFS"
250
+ > = {
251
+ type: "Wait",
252
+ /**
253
+ * Human-readable name of the action
254
+ */
255
+ name: T extends "LP"
256
+ ? "Awaiting LP payout"
257
+ : T extends "SETTLEMENT"
258
+ ? "Automatic settlement"
259
+ : "Bitcoin confirmations",
260
+ /**
261
+ * Human-readable description of the action
262
+ */
86
263
  description: string,
87
- chain: T["ChainId"],
88
- txs: T["TX"][]
264
+ /**
265
+ * Allows you to await till this action resolves
266
+ *
267
+ * @param maxWaitTimeSeconds Maximum time in seconds to wait for
268
+ * @param pollIntervalSeconds How often to poll for the state change (default 5 seconds)
269
+ * @param abortSignal AbortSignal to abort the wait
270
+ * @param btcConfirmationsCallback Optional callback when awaiting bitcoin confirmations, gets called when
271
+ * number of bitcoin confirmations change
272
+ */
273
+ wait: T extends "BITCOIN_CONFS"
274
+ ? (
275
+ maxWaitTimeSeconds?: number, pollIntervalSeconds?: number, abortSignal?: AbortSignal,
276
+ btcConfirmationsCallback?: (txId?: string, confirmations?: number, targetConfirmations?: number, txEtaMs?: number) => void
277
+ ) => Promise<void>
278
+ : (maxWaitTimeSeconds?: number, pollIntervalSeconds?: number, abortSignal?: AbortSignal) => Promise<void>,
279
+ /**
280
+ * Expected time in seconds for this action to take
281
+ */
282
+ expectedTimeSeconds: number,
283
+ /**
284
+ * Recommended time interval in seconds after which you should re-check the current action
285
+ */
286
+ pollTimeSeconds: number
287
+ }
288
+
289
+ /**
290
+ * Type guard for {@link SwapExecutionActionWait}
291
+ *
292
+ * @category Swap Actions
293
+ */
294
+ export function isSwapExecutionActionWait<
295
+ T extends "LP" | "SETTLEMENT" | "BITCOIN_CONFS" = "LP" | "SETTLEMENT" | "BITCOIN_CONFS"
296
+ >(
297
+ obj: any,
298
+ waitType?: T
299
+ ): obj is SwapExecutionActionWait<T> {
300
+ const resolvedWaitType = waitType ??
301
+ (Object.keys(swapExecutionActionWaitNames).find(key =>
302
+ swapExecutionActionWaitNames[key as keyof typeof swapExecutionActionWaitNames] === obj?.name
303
+ ) as keyof typeof swapExecutionActionWaitNames | undefined);
304
+ return obj != null &&
305
+ typeof(obj) === "object" &&
306
+ obj.type === "Wait" &&
307
+ resolvedWaitType != null &&
308
+ obj.name === swapExecutionActionWaitNames[resolvedWaitType] &&
309
+ typeof(obj.description) === "string" &&
310
+ typeof(obj.wait) === "function" &&
311
+ typeof(obj.expectedTimeSeconds) === "number" &&
312
+ typeof(obj.pollTimeSeconds) === "number";
89
313
  }
90
314
 
91
315
  /**
@@ -93,8 +317,7 @@ export type SwapExecutionActionRefund<T extends ChainType> = {
93
317
  *
94
318
  * @category Swap Actions
95
319
  */
96
- export type SwapExecutionAction<T extends ChainType> = SwapExecutionActionLightning |
97
- SwapExecutionActionBitcoin |
98
- SwapExecutionActionCommit<T> |
99
- SwapExecutionActionClaim<T> |
100
- SwapExecutionActionRefund<T>;
320
+ export type SwapExecutionAction = SwapExecutionActionSendToAddress |
321
+ SwapExecutionActionSignPSBT |
322
+ SwapExecutionActionSignSmartChainTx |
323
+ SwapExecutionActionWait;
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Execution step describing destination-side setup required before the swap can continue.
3
+ *
4
+ * @category Swap Steps
5
+ */
6
+ export type SwapExecutionStepSetup<Chain extends string = string> = {
7
+ type: "Setup",
8
+ side: "destination",
9
+ chain: Chain,
10
+ title: string,
11
+ description: string,
12
+ /**
13
+ * Current status of the setup step.
14
+ *
15
+ * - `awaiting`: The setup transaction or action still needs to be performed.
16
+ * - `completed`: The setup was already completed successfully.
17
+ * - `soft_expired`: The setup should be treated as expired by the user, but it may still progress because of in-flight or background processing.
18
+ * - `expired`: The setup can no longer be performed because the swap expired.
19
+ */
20
+ status: "awaiting" | "completed" | "soft_expired" | "expired",
21
+ setupTxId?: string
22
+ }
23
+
24
+ /**
25
+ * Type guard for {@link SwapExecutionStepSetup}
26
+ *
27
+ * @category Swap Steps
28
+ */
29
+ export function isSwapExecutionStepSetup<Chain extends string = string>(obj: any, chain?: Chain): obj is SwapExecutionStepSetup<Chain> {
30
+ return typeof(obj) === "object" &&
31
+ obj.type === "Setup" &&
32
+ obj.side === "destination" &&
33
+ typeof(obj.chain) === "string" &&
34
+ (chain==null || obj.chain===chain) &&
35
+ typeof(obj.title) === "string" &&
36
+ typeof(obj.description) === "string" &&
37
+ (
38
+ obj.status === "awaiting" ||
39
+ obj.status === "completed" ||
40
+ obj.status === "soft_expired" ||
41
+ obj.status === "expired"
42
+ );
43
+ }
44
+
45
+ /**
46
+ * Execution step describing the user payment that initiates or funds the swap.
47
+ *
48
+ * @category Swap Steps
49
+ */
50
+ export type SwapExecutionStepPayment<Chain extends string = string> = {
51
+ type: "Payment",
52
+ side: "source",
53
+ chain: Chain,
54
+ title: string,
55
+ description: string,
56
+ /**
57
+ * Current status of the payment step.
58
+ *
59
+ * - `inactive`: The payment step is not yet active because a previous step must complete first.
60
+ * - `awaiting`: The payment is expected, but no payment transaction is known yet.
61
+ * - `received`: A payment transaction is known, but it is not yet fully confirmed.
62
+ * - `confirmed`: The payment was confirmed and fully satisfies the swap requirements.
63
+ * - `soft_expired`: The payment should be treated as expired by the user, but it may still progress because of in-flight or background processing.
64
+ * - `expired`: The payment step can no longer be completed because the swap expired.
65
+ */
66
+ status: "inactive" | "awaiting" | "received" | "confirmed" | "soft_expired" | "expired",
67
+ /**
68
+ * Optional confirmation progress for Bitcoin on-chain payments.
69
+ */
70
+ confirmations?: {
71
+ /**
72
+ * Number of confirmations currently observed for the payment.
73
+ */
74
+ current: number,
75
+ /**
76
+ * Number of confirmations required before the payment is considered final.
77
+ */
78
+ target: number,
79
+ /**
80
+ * Estimated remaining time in seconds until the target confirmation count is reached.
81
+ *
82
+ * Can be `-1` if the estimate is not available.
83
+ */
84
+ etaSeconds: number
85
+ },
86
+ initTxId?: string,
87
+ settleTxId?: string
88
+ }
89
+
90
+ /**
91
+ * Type guard for {@link SwapExecutionStepPayment}
92
+ *
93
+ * @category Swap Steps
94
+ */
95
+ export function isSwapExecutionStepPayment<Chain extends string = string>(obj: any, chain?: Chain): obj is SwapExecutionStepPayment<Chain> {
96
+ return typeof(obj) === "object" &&
97
+ obj.type === "Payment" &&
98
+ obj.side === "source" &&
99
+ typeof(obj.chain) === "string" &&
100
+ (chain==null || obj.chain===chain) &&
101
+ typeof(obj.title) === "string" &&
102
+ typeof(obj.description) === "string" &&
103
+ (
104
+ obj.status === "inactive" ||
105
+ obj.status === "awaiting" ||
106
+ obj.status === "received" ||
107
+ obj.status === "confirmed" ||
108
+ obj.status === "soft_expired" ||
109
+ obj.status === "expired"
110
+ ) &&
111
+ (
112
+ obj.confirmations == null ||
113
+ (
114
+ typeof(obj.confirmations) === "object" &&
115
+ typeof(obj.confirmations.current) === "number" &&
116
+ typeof(obj.confirmations.target) === "number" &&
117
+ typeof(obj.confirmations.etaSeconds) === "number"
118
+ )
119
+ );
120
+ }
121
+
122
+ /**
123
+ * Execution step describing payout or settlement on the destination side of the swap.
124
+ *
125
+ * @category Swap Steps
126
+ */
127
+ export type SwapExecutionStepSettlement<
128
+ Chain extends string = string,
129
+ AdditionalStatuses extends "awaiting_automatic" | "awaiting_manual" | "soft_settled" = "awaiting_automatic" | "awaiting_manual" | "soft_settled"
130
+ > = {
131
+ type: "Settlement",
132
+ side: "destination",
133
+ chain: Chain,
134
+ title: string,
135
+ description: string,
136
+ /**
137
+ * Current status of the settlement step.
138
+ *
139
+ * - `inactive`: The settlement step is not yet active because a previous step must complete first.
140
+ * - `waiting_lp`: The swap is waiting for the intermediary (LP) to create or process the destination-side payout.
141
+ * - `awaiting_automatic`: The swap is waiting for automatic settlement by watchtowers.
142
+ * - `awaiting_manual`: The swap is ready for manual destination-side settlement by the user.
143
+ * - `soft_settled`: The user already received the payout, but the swap is not yet fully finalized on the source side.
144
+ * - `soft_expired`: The settlement should be treated as expired by the user, but it may still progress because of in-flight or background processing.
145
+ * - `settled`: The settlement completed successfully.
146
+ * - `expired`: Settlement is no longer possible because the swap expired or failed.
147
+ */
148
+ status: "inactive" | "waiting_lp" | "soft_expired" | "settled" | "expired" | AdditionalStatuses,
149
+ initTxId?: string,
150
+ settleTxId?: string
151
+ }
152
+
153
+ /**
154
+ * Type guard for {@link SwapExecutionStepSettlement}
155
+ *
156
+ * @category Swap Steps
157
+ */
158
+ export function isSwapExecutionStepSettlement<Chain extends string = string>(obj: any, chain?: Chain): obj is SwapExecutionStepSettlement<Chain> {
159
+ return typeof(obj) === "object" &&
160
+ obj.type === "Settlement" &&
161
+ obj.side === "destination" &&
162
+ typeof(obj.chain) === "string" &&
163
+ (chain==null || obj.chain===chain) &&
164
+ typeof(obj.title) === "string" &&
165
+ typeof(obj.description) === "string" &&
166
+ (
167
+ obj.status === "inactive" ||
168
+ obj.status === "waiting_lp" ||
169
+ obj.status === "awaiting_automatic" ||
170
+ obj.status === "awaiting_manual" ||
171
+ obj.status === "soft_settled" ||
172
+ obj.status === "soft_expired" ||
173
+ obj.status === "settled" ||
174
+ obj.status === "expired"
175
+ );
176
+ }
177
+
178
+ /**
179
+ * Execution step describing a source-side refund path after a failed swap.
180
+ *
181
+ * @category Swap Steps
182
+ */
183
+ export type SwapExecutionStepRefund<Chain extends string = string> = {
184
+ type: "Refund",
185
+ side: "source",
186
+ chain: Chain,
187
+ title: string,
188
+ description: string,
189
+ /**
190
+ * Current status of the refund step.
191
+ *
192
+ * - `inactive`: The refund path is not currently available.
193
+ * - `awaiting`: The swap can be refunded and the user may perform the refund action.
194
+ * - `refunded`: The refund was completed successfully.
195
+ */
196
+ status: "inactive" | "awaiting" | "refunded",
197
+ refundTxId?: string
198
+ }
199
+
200
+ /**
201
+ * Type guard for {@link SwapExecutionStepRefund}
202
+ *
203
+ * @category Swap Steps
204
+ */
205
+ export function isSwapExecutionStepRefund<Chain extends string = string>(obj: any, chain?: Chain): obj is SwapExecutionStepRefund<Chain> {
206
+ return typeof(obj) === "object" &&
207
+ obj.type === "Refund" &&
208
+ obj.side === "source" &&
209
+ typeof(obj.chain) === "string" &&
210
+ (chain==null || obj.chain===chain) &&
211
+ typeof(obj.title) === "string" &&
212
+ typeof(obj.description) === "string" &&
213
+ (obj.status === "inactive" || obj.status === "awaiting" || obj.status === "refunded");
214
+ }
215
+
216
+ /**
217
+ * Union of all supported swap execution step variants.
218
+ *
219
+ * @category Swap Steps
220
+ */
221
+ export type SwapExecutionStep = SwapExecutionStepSetup |
222
+ SwapExecutionStepPayment |
223
+ SwapExecutionStepSettlement |
224
+ SwapExecutionStepRefund;
@@ -1,5 +1,5 @@
1
1
  import {ISwapPrice} from "../prices/abstract/ISwapPrice";
2
- import {Token} from "./Token";
2
+ import {isToken, Token} from "./Token";
3
3
  import {PriceInfoType} from "./PriceInfoType";
4
4
  import {toDecimal} from "../utils/Utils";
5
5
 
@@ -66,6 +66,40 @@ export type TokenAmount<
66
66
  isUnknown: Known extends true ? false : true
67
67
  };
68
68
 
69
+ /**
70
+ * Type guard for {@link TokenAmount}
71
+ *
72
+ * @category Tokens
73
+ */
74
+ export function isTokenAmount<
75
+ T extends Token = Token,
76
+ Known extends boolean = boolean
77
+ >(
78
+ obj: any,
79
+ token?: T,
80
+ known?: Known
81
+ ): obj is TokenAmount<T, Known> {
82
+ const hasExpectedKnownState = known == null
83
+ ? (
84
+ (typeof(obj?.rawAmount) === "bigint" && obj?.isUnknown === false) ||
85
+ (obj?.rawAmount === undefined && obj?.isUnknown === true)
86
+ )
87
+ : known
88
+ ? typeof(obj?.rawAmount) === "bigint" && obj?.isUnknown === false
89
+ : obj?.rawAmount === undefined && obj?.isUnknown === true;
90
+
91
+ return obj != null &&
92
+ typeof(obj) === "object" &&
93
+ typeof(obj.amount) === "string" &&
94
+ typeof(obj._amount) === "number" &&
95
+ (token == null ? isToken(obj.token) : token.equals(obj.token)) &&
96
+ typeof(obj.currentUsdValue) === "function" &&
97
+ typeof(obj.usdValue) === "function" &&
98
+ (obj.pastUsdValue == null || typeof(obj.pastUsdValue) === "number") &&
99
+ typeof(obj.toString) === "function" &&
100
+ hasExpectedKnownState;
101
+ }
102
+
69
103
  /**
70
104
  * Factory function to create a TokenAmount
71
105
  *
@@ -130,4 +164,4 @@ export function toTokenAmount<
130
164
  toString: () => amountStr + " " + token.ticker,
131
165
  isUnknown: false
132
166
  } as TokenAmount<T>;
133
- }
167
+ }
@@ -130,3 +130,35 @@ export function parsePsbtTransaction(_psbt: Transaction | string): Transaction {
130
130
  }
131
131
  }
132
132
 
133
+ export function getVoutIndex(psbt: Transaction, network: BTC_NETWORK, address: string, amount: bigint): number | undefined {
134
+ const script = toOutputScript(network, address);
135
+ for(let i=0;i<psbt.outputsLength;i++) {
136
+ const output = psbt.getOutput(i);
137
+ if(
138
+ output.amount===amount &&
139
+ output.script!=null &&
140
+ script.equals(Buffer.from(output.script))
141
+ ) {
142
+ return i;
143
+ }
144
+ }
145
+ }
146
+
147
+ export function getSenderAddress(psbt: Transaction, network: BTC_NETWORK, inputIndex: number = 0): string | undefined {
148
+ if(psbt.inputsLength<=inputIndex) return undefined;
149
+
150
+ const input = psbt.getInput(inputIndex);
151
+ let script: Uint8Array | undefined;
152
+ if(input.witnessUtxo?.script!=null) {
153
+ script = input.witnessUtxo.script as Uint8Array;
154
+ } else if(input.nonWitnessUtxo!=null && input.index!=null) {
155
+ script = input.nonWitnessUtxo.outputs[input.index]?.script;
156
+ }
157
+ if(script==null) return undefined;
158
+
159
+ try {
160
+ return Address(network).encode(OutScript.decode(script));
161
+ } catch (e) {
162
+ return Buffer.from(script).toString("hex");
163
+ }
164
+ }