@portal-hq/web 3.13.2 → 3.14.0-alpha.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/lib/commonjs/index.js +127 -9
- package/lib/commonjs/index.test.js +13 -0
- package/lib/commonjs/integrations/delegations/index.js +109 -2
- package/lib/commonjs/integrations/delegations/index.test.js +171 -0
- package/lib/commonjs/integrations/ramps/noah/index.test.js +18 -5
- package/lib/commonjs/integrations/trading/index.js +16 -5
- package/lib/commonjs/integrations/trading/lifi/index.js +297 -25
- package/lib/commonjs/integrations/trading/lifi/lifi.tradeAsset.test.js +360 -0
- package/lib/commonjs/integrations/trading/lifi/lifiStatusPoll.js +118 -0
- package/lib/commonjs/integrations/trading/lifi/lifiStatusPoll.test.js +66 -0
- package/lib/commonjs/integrations/trading/zero-x/index.js +129 -26
- package/lib/commonjs/integrations/trading/zero-x/index.test.js +163 -1
- package/lib/commonjs/integrations/yield/index.js +18 -4
- package/lib/commonjs/integrations/yield/yieldxyz.getValidators.test.js +71 -0
- package/lib/commonjs/integrations/yield/yieldxyz.highLevel.test.js +330 -0
- package/lib/commonjs/integrations/yield/yieldxyz.js +517 -1
- package/lib/commonjs/internal/pollLoop.js +64 -0
- package/lib/commonjs/internal/pollLoop.test.js +100 -0
- package/lib/commonjs/internal/stripStalePlanningNonce.js +65 -0
- package/lib/commonjs/internal/stripStalePlanningNonce.test.js +35 -0
- package/lib/commonjs/internal/waitForEvmOrUserOpConfirmation.js +155 -0
- package/lib/commonjs/internal/waitForEvmOrUserOpConfirmation.test.js +33 -0
- package/lib/commonjs/internal/waitForEvmTxConfirmation.js +104 -0
- package/lib/commonjs/internal/waitForSolanaTxConfirmation.js +106 -0
- package/lib/commonjs/internal/yieldEvmNetwork.js +60 -0
- package/lib/commonjs/mpc/index.js +116 -1
- package/lib/commonjs/provider/index.js +17 -0
- package/lib/commonjs/shared/trace/index.js +0 -1
- package/lib/esm/index.js +127 -9
- package/lib/esm/index.test.js +13 -0
- package/lib/esm/integrations/delegations/index.js +109 -2
- package/lib/esm/integrations/delegations/index.test.js +171 -0
- package/lib/esm/integrations/ramps/noah/index.test.js +18 -5
- package/lib/esm/integrations/trading/index.js +16 -5
- package/lib/esm/integrations/trading/lifi/index.js +292 -25
- package/lib/esm/integrations/trading/lifi/lifi.tradeAsset.test.js +332 -0
- package/lib/esm/integrations/trading/lifi/lifiStatusPoll.js +113 -0
- package/lib/esm/integrations/trading/lifi/lifiStatusPoll.test.js +64 -0
- package/lib/esm/integrations/trading/zero-x/index.js +129 -26
- package/lib/esm/integrations/trading/zero-x/index.test.js +141 -2
- package/lib/esm/integrations/yield/index.js +18 -4
- package/lib/esm/integrations/yield/yieldxyz.getValidators.test.js +66 -0
- package/lib/esm/integrations/yield/yieldxyz.highLevel.test.js +325 -0
- package/lib/esm/integrations/yield/yieldxyz.js +517 -1
- package/lib/esm/internal/pollLoop.js +59 -0
- package/lib/esm/internal/pollLoop.test.js +98 -0
- package/lib/esm/internal/stripStalePlanningNonce.js +61 -0
- package/lib/esm/internal/stripStalePlanningNonce.test.js +33 -0
- package/lib/esm/internal/waitForEvmOrUserOpConfirmation.js +151 -0
- package/lib/esm/internal/waitForEvmOrUserOpConfirmation.test.js +31 -0
- package/lib/esm/internal/waitForEvmTxConfirmation.js +100 -0
- package/lib/esm/internal/waitForSolanaTxConfirmation.js +102 -0
- package/lib/esm/internal/yieldEvmNetwork.js +55 -0
- package/lib/esm/mpc/index.js +116 -1
- package/lib/esm/provider/index.js +17 -0
- package/lib/esm/shared/trace/index.js +0 -1
- package/noah-types.d.ts +16 -2
- package/package.json +3 -2
- package/src/index.test.ts +15 -0
- package/src/index.ts +203 -14
- package/src/integrations/delegations/index.test.ts +251 -0
- package/src/integrations/delegations/index.ts +202 -4
- package/src/integrations/ramps/noah/index.test.ts +18 -5
- package/src/integrations/trading/index.ts +10 -7
- package/src/integrations/trading/lifi/index.ts +388 -28
- package/src/integrations/trading/lifi/lifi.tradeAsset.test.ts +436 -0
- package/src/integrations/trading/lifi/lifiStatusPoll.test.ts +74 -0
- package/src/integrations/trading/lifi/lifiStatusPoll.ts +158 -0
- package/src/integrations/trading/zero-x/index.test.ts +297 -1
- package/src/integrations/trading/zero-x/index.ts +181 -27
- package/src/integrations/yield/index.ts +24 -4
- package/src/integrations/yield/yieldxyz.getValidators.test.ts +70 -0
- package/src/integrations/yield/yieldxyz.highLevel.test.ts +403 -0
- package/src/integrations/yield/yieldxyz.ts +740 -8
- package/src/internal/pollLoop.test.ts +109 -0
- package/src/internal/pollLoop.ts +87 -0
- package/src/internal/stripStalePlanningNonce.test.ts +38 -0
- package/src/internal/stripStalePlanningNonce.ts +66 -0
- package/src/internal/waitForEvmOrUserOpConfirmation.test.ts +31 -0
- package/src/internal/waitForEvmOrUserOpConfirmation.ts +194 -0
- package/src/internal/waitForEvmTxConfirmation.ts +155 -0
- package/src/internal/waitForSolanaTxConfirmation.ts +135 -0
- package/src/internal/yieldEvmNetwork.ts +57 -0
- package/src/mpc/index.ts +142 -1
- package/src/provider/index.ts +25 -0
- package/src/shared/trace/index.ts +0 -1
- package/src/shared/types/README.md +6 -0
- package/src/shared/types/api.ts +12 -1
- package/src/shared/types/common.ts +332 -20
- package/src/shared/types/delegations.ts +10 -0
- package/src/shared/types/index.ts +1 -0
- package/src/shared/types/lifi.ts +82 -0
- package/src/shared/types/noah.ts +124 -33
- package/src/shared/types/yieldxyz.ts +186 -0
- package/src/shared/types/zero-x.ts +66 -0
- package/types.d.ts +6 -0
|
@@ -1,61 +1,421 @@
|
|
|
1
1
|
import Mpc from '../../../mpc'
|
|
2
|
+
import { sdkLogger } from '../../../logger'
|
|
3
|
+
import { waitForEvmTxConfirmation } from '../../../internal/waitForEvmTxConfirmation'
|
|
4
|
+
import { stripStalePlanningNonceIfJsonObject } from '../../../internal/stripStalePlanningNonce'
|
|
2
5
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
6
|
+
pollLifiStatusUntilTerminal,
|
|
7
|
+
} from './lifiStatusPoll'
|
|
8
|
+
import type {
|
|
9
|
+
LifiPollStatusOptions,
|
|
5
10
|
LifiRoutesRequest,
|
|
6
11
|
LifiRoutesResponse,
|
|
12
|
+
LifiQuoteRequest,
|
|
13
|
+
LifiQuoteResponse,
|
|
7
14
|
LifiStatusRequest,
|
|
8
15
|
LifiStatusResponse,
|
|
16
|
+
LifiStatusRawResponse,
|
|
17
|
+
LifiStep,
|
|
9
18
|
LifiStepTransactionRequest,
|
|
10
19
|
LifiStepTransactionResponse,
|
|
20
|
+
LifiTradeAssetOptions,
|
|
21
|
+
LifiTradeAssetParams,
|
|
22
|
+
LifiTradeAssetResult,
|
|
11
23
|
} from '../../../shared/types'
|
|
12
24
|
|
|
13
|
-
|
|
25
|
+
const LOG_PREFIX = '[LiFi]'
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Internal sentinel error used to avoid emitting duplicate `failed` progress events.
|
|
29
|
+
*/
|
|
30
|
+
class LifiReportedError extends Error {
|
|
31
|
+
constructor(message: string) {
|
|
32
|
+
super(message)
|
|
33
|
+
this.name = 'LifiReportedError'
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface LifiOptions extends LifiTradeAssetOptions {}
|
|
38
|
+
|
|
39
|
+
export interface ILiFi {
|
|
40
|
+
getRoutes(data: LifiRoutesRequest): Promise<LifiRoutesResponse>
|
|
41
|
+
getQuote(data: LifiQuoteRequest): Promise<LifiQuoteResponse>
|
|
42
|
+
getStatus(data: LifiStatusRequest): Promise<LifiStatusResponse>
|
|
43
|
+
getRouteStep(
|
|
44
|
+
data: LifiStepTransactionRequest,
|
|
45
|
+
): Promise<LifiStepTransactionResponse>
|
|
46
|
+
tradeAsset(
|
|
47
|
+
params: LifiTradeAssetParams,
|
|
48
|
+
options?: LifiTradeAssetOptions,
|
|
49
|
+
): Promise<LifiTradeAssetResult>
|
|
50
|
+
pollStatus(
|
|
51
|
+
request: Pick<LifiStatusRequest, 'txHash' | 'fromChain' | 'toChain' | 'bridge'>,
|
|
52
|
+
options?: LifiPollStatusOptions & {
|
|
53
|
+
onUpdate?: (raw: LifiStatusRawResponse) => boolean | void
|
|
54
|
+
},
|
|
55
|
+
): Promise<LifiStatusRawResponse>
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Normalize LiFi chain key / id to CAIP-2 `eip155:*` for the Portal provider. */
|
|
59
|
+
export function normalizeChainToNetwork(chain: string): string {
|
|
60
|
+
const c = chain.trim()
|
|
61
|
+
if (c.startsWith('eip155:')) {
|
|
62
|
+
return c
|
|
63
|
+
}
|
|
64
|
+
if (/^0x[0-9a-fA-F]+$/.test(c)) {
|
|
65
|
+
return `eip155:${parseInt(c, 16)}`
|
|
66
|
+
}
|
|
67
|
+
if (/^\d+$/.test(c)) {
|
|
68
|
+
return `eip155:${c}`
|
|
69
|
+
}
|
|
70
|
+
return c
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function resolveLifiStepNetworkCaip2(step: LifiStep): string {
|
|
74
|
+
const fromTx = step.transactionRequest?.chainId
|
|
75
|
+
if (fromTx) {
|
|
76
|
+
return normalizeChainToNetwork(fromTx)
|
|
77
|
+
}
|
|
78
|
+
return normalizeChainToNetwork(step.action.fromChainId)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function parseLifiTransactionRequestFromStep(
|
|
82
|
+
step: LifiStep,
|
|
83
|
+
): Record<string, unknown> {
|
|
84
|
+
const tr = step.transactionRequest
|
|
85
|
+
if (!tr) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
`${LOG_PREFIX} Step has no transactionRequest; call getRouteStep first.`,
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
const base: Record<string, unknown> = {
|
|
91
|
+
data: tr.data,
|
|
92
|
+
to: tr.to,
|
|
93
|
+
from: tr.from,
|
|
94
|
+
value: tr.value ?? '0x0',
|
|
95
|
+
gas: tr.gasLimit,
|
|
96
|
+
gasPrice: tr.gasPrice,
|
|
97
|
+
}
|
|
98
|
+
if (tr.maxFeePerGas != null) {
|
|
99
|
+
base.maxFeePerGas = tr.maxFeePerGas
|
|
100
|
+
}
|
|
101
|
+
if (tr.maxPriorityFeePerGas != null) {
|
|
102
|
+
base.maxPriorityFeePerGas = tr.maxPriorityFeePerGas
|
|
103
|
+
}
|
|
104
|
+
return base
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function statusBridgeFromStepTool(
|
|
108
|
+
tool: string | undefined,
|
|
109
|
+
): LifiStatusRequest['bridge'] {
|
|
110
|
+
if (!tool) {
|
|
111
|
+
return undefined
|
|
112
|
+
}
|
|
113
|
+
return tool.toLowerCase() as LifiStatusRequest['bridge']
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function mergeLifiOptions(
|
|
117
|
+
instance: LifiTradeAssetOptions | undefined,
|
|
118
|
+
perCall: LifiTradeAssetOptions | undefined,
|
|
119
|
+
): LifiTradeAssetOptions {
|
|
120
|
+
return {
|
|
121
|
+
...instance,
|
|
122
|
+
...perCall,
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export default class LiFi implements ILiFi {
|
|
14
127
|
private mpc: Mpc
|
|
128
|
+
private readonly defaultTradeOptions: LifiTradeAssetOptions
|
|
15
129
|
|
|
16
|
-
constructor({ mpc }: { mpc: Mpc }) {
|
|
130
|
+
constructor({ mpc, ...tradeDefaults }: { mpc: Mpc } & LifiOptions) {
|
|
17
131
|
this.mpc = mpc
|
|
132
|
+
this.defaultTradeOptions = tradeDefaults
|
|
18
133
|
}
|
|
19
134
|
|
|
20
|
-
/**
|
|
21
|
-
* Retrieves routes from the Li.Fi integration.
|
|
22
|
-
* @param data - The parameters for the routes request.
|
|
23
|
-
* @returns A `LifiRoutesResponse` promise.
|
|
24
|
-
* @throws An error if the operation fails.
|
|
25
|
-
*/
|
|
26
135
|
public async getRoutes(data: LifiRoutesRequest): Promise<LifiRoutesResponse> {
|
|
27
136
|
return this.mpc?.getLifiRoutes(data)
|
|
28
137
|
}
|
|
29
138
|
|
|
30
|
-
/**
|
|
31
|
-
* Retrieves a quote from the Li.Fi integration.
|
|
32
|
-
* @param data - The parameters for the quote request.
|
|
33
|
-
* @returns A `LifiQuoteResponse` promise.
|
|
34
|
-
* @throws An error if the operation fails.
|
|
35
|
-
*/
|
|
36
139
|
public async getQuote(data: LifiQuoteRequest): Promise<LifiQuoteResponse> {
|
|
37
140
|
return this.mpc?.getLifiQuote(data)
|
|
38
141
|
}
|
|
39
142
|
|
|
40
|
-
/**
|
|
41
|
-
* Retrieves the status of a transaction from the Li.Fi integration.
|
|
42
|
-
* @param data - The parameters for the status request.
|
|
43
|
-
* @returns A `LifiStatusResponse` promise.
|
|
44
|
-
* @throws An error if the operation fails.
|
|
45
|
-
*/
|
|
46
143
|
public async getStatus(data: LifiStatusRequest): Promise<LifiStatusResponse> {
|
|
47
144
|
return this.mpc?.getLifiStatus(data)
|
|
48
145
|
}
|
|
49
146
|
|
|
50
|
-
/**
|
|
51
|
-
* Retrieves an unsigned transaction from the Li.Fi integration that has yet to be signed/submitted.
|
|
52
|
-
* @param data - The step transaction request containing the step details.
|
|
53
|
-
* @returns A `LifiStepTransactionResponse` promise.
|
|
54
|
-
* @throws An error if the operation fails.
|
|
55
|
-
*/
|
|
56
147
|
public async getRouteStep(
|
|
57
148
|
data: LifiStepTransactionRequest,
|
|
58
149
|
): Promise<LifiStepTransactionResponse> {
|
|
59
150
|
return this.mpc?.getLifiRouteStep(data)
|
|
60
151
|
}
|
|
152
|
+
|
|
153
|
+
public async pollStatus(
|
|
154
|
+
request: Pick<
|
|
155
|
+
LifiStatusRequest,
|
|
156
|
+
'txHash' | 'fromChain' | 'toChain' | 'bridge'
|
|
157
|
+
>,
|
|
158
|
+
options?: LifiPollStatusOptions & {
|
|
159
|
+
onUpdate?: (raw: LifiStatusRawResponse) => boolean | void
|
|
160
|
+
},
|
|
161
|
+
): Promise<LifiStatusRawResponse> {
|
|
162
|
+
const {
|
|
163
|
+
everyMs = 10_000,
|
|
164
|
+
initialDelayMs = 10_000,
|
|
165
|
+
timeoutMs = 600_000,
|
|
166
|
+
maxConsecutiveErrors = 10,
|
|
167
|
+
backoff = { factor: 1.5, maxIntervalMs: 15_000 },
|
|
168
|
+
onUpdate,
|
|
169
|
+
} = options ?? {}
|
|
170
|
+
|
|
171
|
+
return pollLifiStatusUntilTerminal({
|
|
172
|
+
getStatus: (r) => this.mpc.getLifiStatus(r),
|
|
173
|
+
request,
|
|
174
|
+
onUpdate,
|
|
175
|
+
everyMs,
|
|
176
|
+
initialDelayMs,
|
|
177
|
+
timeoutMs,
|
|
178
|
+
maxConsecutiveErrors,
|
|
179
|
+
backoff,
|
|
180
|
+
})
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
public async tradeAsset(
|
|
184
|
+
params: LifiTradeAssetParams,
|
|
185
|
+
options?: LifiTradeAssetOptions,
|
|
186
|
+
): Promise<LifiTradeAssetResult> {
|
|
187
|
+
try {
|
|
188
|
+
const o = mergeLifiOptions(this.defaultTradeOptions, options)
|
|
189
|
+
const signAndSend = o.signAndSendTransaction
|
|
190
|
+
if (!signAndSend) {
|
|
191
|
+
throw new Error(`${LOG_PREFIX} tradeAsset requires signAndSendTransaction`)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const effectiveWait = async (
|
|
195
|
+
txHash: string,
|
|
196
|
+
network: string,
|
|
197
|
+
): Promise<void | boolean> => {
|
|
198
|
+
if (o.waitForConfirmation) {
|
|
199
|
+
return o.waitForConfirmation(txHash, network)
|
|
200
|
+
}
|
|
201
|
+
if (o.evmRequestFn) {
|
|
202
|
+
if (!network.startsWith('eip155:')) {
|
|
203
|
+
sdkLogger.warn(
|
|
204
|
+
`${LOG_PREFIX} Cannot verify confirmation for non-EVM network ${network}. ` +
|
|
205
|
+
'Provide waitForConfirmation or use Portal.waitForConfirmation.',
|
|
206
|
+
)
|
|
207
|
+
return Promise.resolve(false)
|
|
208
|
+
}
|
|
209
|
+
return waitForEvmTxConfirmation(txHash, network, o.evmRequestFn, {
|
|
210
|
+
pollIntervalMs: o.evmPollerOptions?.pollIntervalMs,
|
|
211
|
+
timeoutMs: o.evmPollerOptions?.timeoutMs,
|
|
212
|
+
// Intentionally differs from Yield's optimistic `resolve_false` timeout
|
|
213
|
+
// handling: LiFi must abort here so we do not continue into bridge-status
|
|
214
|
+
// polling after source-chain confirmation has already timed out.
|
|
215
|
+
onTimeout: 'throw',
|
|
216
|
+
})
|
|
217
|
+
}
|
|
218
|
+
throw new Error(
|
|
219
|
+
`${LOG_PREFIX} tradeAsset requires waitForConfirmation or evmRequestFn fallback.`,
|
|
220
|
+
)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
params.onProgress?.('fetching_routes')
|
|
224
|
+
|
|
225
|
+
const routesRes = await this.getRoutes({
|
|
226
|
+
fromChainId: normalizeChainToNetwork(params.fromChain),
|
|
227
|
+
toChainId: normalizeChainToNetwork(params.toChain),
|
|
228
|
+
fromTokenAddress: params.fromToken,
|
|
229
|
+
toTokenAddress: params.toToken,
|
|
230
|
+
fromAmount: params.amount,
|
|
231
|
+
fromAddress: params.fromAddress,
|
|
232
|
+
toAddress: params.toAddress,
|
|
233
|
+
options: params.routeOptions,
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
if (routesRes.error) {
|
|
237
|
+
throw new Error(`${LOG_PREFIX} getRoutes: ${routesRes.error}`)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const routes = routesRes.data?.rawResponse.routes ?? []
|
|
241
|
+
if (routes.length === 0) {
|
|
242
|
+
throw new Error(`${LOG_PREFIX} No routes returned from LiFi`)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const idx = params.routeIndex ?? 0
|
|
246
|
+
const route = routes[idx]
|
|
247
|
+
if (!route) {
|
|
248
|
+
throw new Error(`${LOG_PREFIX} no route available at index ${idx}`)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
params.onProgress?.('route_selected', { route, routeIndex: idx })
|
|
252
|
+
|
|
253
|
+
const hashes: string[] = []
|
|
254
|
+
const stepsOut: LifiStep[] = []
|
|
255
|
+
const totalSteps = route.steps.length
|
|
256
|
+
|
|
257
|
+
for (let stepIndex = 0; stepIndex < route.steps.length; stepIndex++) {
|
|
258
|
+
const step = route.steps[stepIndex]
|
|
259
|
+
|
|
260
|
+
// Validate step exists (defensive check for sparse arrays)
|
|
261
|
+
if (!step) {
|
|
262
|
+
throw new Error(
|
|
263
|
+
`${LOG_PREFIX} Step at index ${stepIndex} is undefined or null. This indicates a malformed route response.`,
|
|
264
|
+
)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
params.onProgress?.('preparing_step', {
|
|
268
|
+
route,
|
|
269
|
+
routeIndex: idx,
|
|
270
|
+
step,
|
|
271
|
+
stepIndex,
|
|
272
|
+
totalSteps,
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
const stepRes = await this.getRouteStep(step)
|
|
276
|
+
if (stepRes.error) {
|
|
277
|
+
throw new Error(`${LOG_PREFIX} getRouteStep: ${stepRes.error}`)
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const populated = stepRes.data?.rawResponse
|
|
281
|
+
if (!populated) {
|
|
282
|
+
throw new Error(`${LOG_PREFIX} getRouteStep returned no step data`)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const network = resolveLifiStepNetworkCaip2(populated)
|
|
286
|
+
let tx = parseLifiTransactionRequestFromStep(populated)
|
|
287
|
+
if (network.startsWith('eip155:')) {
|
|
288
|
+
const stripped = stripStalePlanningNonceIfJsonObject(tx)
|
|
289
|
+
// Validate stripped result is still an object
|
|
290
|
+
if (
|
|
291
|
+
typeof stripped !== 'object' ||
|
|
292
|
+
stripped === null ||
|
|
293
|
+
Array.isArray(stripped)
|
|
294
|
+
) {
|
|
295
|
+
throw new Error(
|
|
296
|
+
`${LOG_PREFIX} stripStalePlanningNonce returned invalid type: ${typeof stripped}`,
|
|
297
|
+
)
|
|
298
|
+
}
|
|
299
|
+
tx = stripped as Record<string, unknown>
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
params.onProgress?.('signing', {
|
|
303
|
+
route,
|
|
304
|
+
routeIndex: idx,
|
|
305
|
+
step: populated,
|
|
306
|
+
stepIndex,
|
|
307
|
+
totalSteps,
|
|
308
|
+
transaction: tx,
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
const txHash = await signAndSend(tx, network)
|
|
312
|
+
if (typeof txHash !== 'string' || txHash.trim().length === 0) {
|
|
313
|
+
const msg = `Invalid transaction hash returned from signAndSendTransaction at step ${stepIndex} for network ${network}.`
|
|
314
|
+
params.onProgress?.('failed', {
|
|
315
|
+
errorMessage: msg,
|
|
316
|
+
txHash,
|
|
317
|
+
routeIndex: idx,
|
|
318
|
+
stepIndex,
|
|
319
|
+
totalSteps,
|
|
320
|
+
step: populated,
|
|
321
|
+
})
|
|
322
|
+
throw new LifiReportedError(`${LOG_PREFIX} ${msg}`)
|
|
323
|
+
}
|
|
324
|
+
hashes.push(txHash)
|
|
325
|
+
|
|
326
|
+
params.onProgress?.('submitted', {
|
|
327
|
+
route,
|
|
328
|
+
routeIndex: idx,
|
|
329
|
+
step: populated,
|
|
330
|
+
stepIndex,
|
|
331
|
+
totalSteps,
|
|
332
|
+
txHash,
|
|
333
|
+
})
|
|
334
|
+
|
|
335
|
+
params.onProgress?.('confirming', {
|
|
336
|
+
route,
|
|
337
|
+
routeIndex: idx,
|
|
338
|
+
step: populated,
|
|
339
|
+
stepIndex,
|
|
340
|
+
totalSteps,
|
|
341
|
+
txHash,
|
|
342
|
+
})
|
|
343
|
+
|
|
344
|
+
const waiterResult = (await effectiveWait(txHash, network)) as
|
|
345
|
+
| boolean
|
|
346
|
+
| void
|
|
347
|
+
const ok = waiterResult === true
|
|
348
|
+
if (!ok) {
|
|
349
|
+
const msg = `${LOG_PREFIX} on-chain confirmation did not complete (waitForConfirmation did not return true) for ${txHash} on ${network}`
|
|
350
|
+
params.onProgress?.('failed', {
|
|
351
|
+
errorMessage: msg,
|
|
352
|
+
txHash,
|
|
353
|
+
routeIndex: idx,
|
|
354
|
+
stepIndex,
|
|
355
|
+
totalSteps,
|
|
356
|
+
step: populated,
|
|
357
|
+
})
|
|
358
|
+
throw new LifiReportedError(msg)
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const bridgeTool = statusBridgeFromStepTool(populated.tool)
|
|
362
|
+
const crossLike =
|
|
363
|
+
populated.type === 'cross' ||
|
|
364
|
+
populated.action.fromChainId !== populated.action.toChainId
|
|
365
|
+
|
|
366
|
+
if (crossLike && bridgeTool) {
|
|
367
|
+
params.onProgress?.('lifi_pending', {
|
|
368
|
+
route,
|
|
369
|
+
routeIndex: idx,
|
|
370
|
+
step: populated,
|
|
371
|
+
stepIndex,
|
|
372
|
+
totalSteps,
|
|
373
|
+
txHash,
|
|
374
|
+
})
|
|
375
|
+
|
|
376
|
+
const pollOpts = params.statusPoll ?? {}
|
|
377
|
+
const terminal = await this.pollStatus(
|
|
378
|
+
{
|
|
379
|
+
txHash,
|
|
380
|
+
fromChain: params.fromChain,
|
|
381
|
+
toChain: params.toChain,
|
|
382
|
+
bridge: bridgeTool,
|
|
383
|
+
},
|
|
384
|
+
pollOpts,
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
params.onProgress?.('step_done', {
|
|
388
|
+
route,
|
|
389
|
+
routeIndex: idx,
|
|
390
|
+
step: populated,
|
|
391
|
+
stepIndex,
|
|
392
|
+
totalSteps,
|
|
393
|
+
txHash,
|
|
394
|
+
lifiStatus: terminal,
|
|
395
|
+
})
|
|
396
|
+
} else {
|
|
397
|
+
params.onProgress?.('step_done', {
|
|
398
|
+
route,
|
|
399
|
+
routeIndex: idx,
|
|
400
|
+
step: populated,
|
|
401
|
+
stepIndex,
|
|
402
|
+
totalSteps,
|
|
403
|
+
txHash,
|
|
404
|
+
})
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
stepsOut.push(populated)
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
params.onProgress?.('complete', { route, routeIndex: idx })
|
|
411
|
+
return { hashes, steps: stepsOut, route }
|
|
412
|
+
} catch (error: unknown) {
|
|
413
|
+
if (!(error instanceof LifiReportedError)) {
|
|
414
|
+
const errorMessage =
|
|
415
|
+
error instanceof Error ? error.message : String(error)
|
|
416
|
+
params.onProgress?.('failed', { errorMessage })
|
|
417
|
+
}
|
|
418
|
+
throw error
|
|
419
|
+
}
|
|
420
|
+
}
|
|
61
421
|
}
|