@jack-kernel/sdk 1.1.0 → 1.2.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.
- package/dist/cjs/index.js +83 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/lifi/chain-map.js +39 -0
- package/dist/cjs/lifi/chain-map.js.map +1 -0
- package/dist/cjs/lifi/fallback.js +135 -0
- package/dist/cjs/lifi/fallback.js.map +1 -0
- package/dist/cjs/lifi/index.js +34 -0
- package/dist/cjs/lifi/index.js.map +1 -0
- package/dist/cjs/lifi/lifi-provider.js +496 -0
- package/dist/cjs/lifi/lifi-provider.js.map +1 -0
- package/dist/cjs/lifi/token-map.js +75 -0
- package/dist/cjs/lifi/token-map.js.map +1 -0
- package/dist/cjs/lifi/types.js +3 -0
- package/dist/cjs/lifi/types.js.map +1 -0
- package/dist/cjs/lifi/utils.js +45 -0
- package/dist/cjs/lifi/utils.js.map +1 -0
- package/dist/esm/index.js +69 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lifi/chain-map.js +35 -0
- package/dist/esm/lifi/chain-map.js.map +1 -0
- package/dist/esm/lifi/fallback.js +128 -0
- package/dist/esm/lifi/fallback.js.map +1 -0
- package/dist/esm/lifi/index.js +19 -0
- package/dist/esm/lifi/index.js.map +1 -0
- package/dist/esm/lifi/lifi-provider.js +492 -0
- package/dist/esm/lifi/lifi-provider.js.map +1 -0
- package/dist/esm/lifi/token-map.js +71 -0
- package/dist/esm/lifi/token-map.js.map +1 -0
- package/dist/esm/lifi/types.js +2 -0
- package/dist/esm/lifi/types.js.map +1 -0
- package/dist/esm/lifi/utils.js +41 -0
- package/dist/esm/lifi/utils.js.map +1 -0
- package/dist/types/index.d.ts +58 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lifi/chain-map.d.ts +27 -0
- package/dist/types/lifi/chain-map.d.ts.map +1 -0
- package/dist/types/lifi/fallback.d.ts +58 -0
- package/dist/types/lifi/fallback.d.ts.map +1 -0
- package/dist/types/lifi/index.d.ts +18 -0
- package/dist/types/lifi/index.d.ts.map +1 -0
- package/dist/types/lifi/lifi-provider.d.ts +133 -0
- package/dist/types/lifi/lifi-provider.d.ts.map +1 -0
- package/dist/types/lifi/token-map.d.ts +34 -0
- package/dist/types/lifi/token-map.d.ts.map +1 -0
- package/dist/types/lifi/types.d.ts +52 -0
- package/dist/types/lifi/types.d.ts.map +1 -0
- package/dist/types/lifi/utils.d.ts +29 -0
- package/dist/types/lifi/utils.d.ts.map +1 -0
- package/package.json +4 -1
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* LifiProvider — main entry point for all LI.FI operations.
|
|
4
|
+
*
|
|
5
|
+
* Handles initialization, parameter validation, SDK delegation,
|
|
6
|
+
* response normalization, retry logic, and fallback.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.LifiProvider = void 0;
|
|
12
|
+
const sdk_1 = require("@lifi/sdk");
|
|
13
|
+
const fallback_js_1 = require("./fallback.js");
|
|
14
|
+
const chain_map_js_1 = require("./chain-map.js");
|
|
15
|
+
const token_map_js_1 = require("./token-map.js");
|
|
16
|
+
const utils_js_1 = require("./utils.js");
|
|
17
|
+
/** Default configuration values. */
|
|
18
|
+
const DEFAULTS = {
|
|
19
|
+
integrator: 'jackkernel',
|
|
20
|
+
apiUrl: 'https://li.quest/v1',
|
|
21
|
+
chains: [42161, 10, 8453, 137],
|
|
22
|
+
timeout: 30_000,
|
|
23
|
+
maxRetries: 3,
|
|
24
|
+
retryDelay: 1_000,
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* LifiProvider wraps the `@lifi/sdk` to provide quote fetching, route
|
|
28
|
+
* discovery, status tracking, and execution capabilities for the JACK SDK.
|
|
29
|
+
*
|
|
30
|
+
* The constructor calls `createConfig` from `@lifi/sdk` with the integrator
|
|
31
|
+
* string "jackkernel" and any user-supplied configuration. Each public method
|
|
32
|
+
* validates input, delegates to the SDK with retry logic, normalizes the
|
|
33
|
+
* response, and falls back to the FallbackProvider on any error.
|
|
34
|
+
*/
|
|
35
|
+
class LifiProvider {
|
|
36
|
+
config;
|
|
37
|
+
/**
|
|
38
|
+
* Create a new LifiProvider.
|
|
39
|
+
*
|
|
40
|
+
* @param userConfig - Optional configuration overrides
|
|
41
|
+
* @throws If `createConfig` from `@lifi/sdk` fails
|
|
42
|
+
*/
|
|
43
|
+
constructor(userConfig) {
|
|
44
|
+
this.config = {
|
|
45
|
+
integrator: userConfig?.integrator ?? DEFAULTS.integrator,
|
|
46
|
+
apiKey: userConfig?.apiKey,
|
|
47
|
+
apiUrl: userConfig?.apiUrl ?? DEFAULTS.apiUrl,
|
|
48
|
+
rpcUrls: userConfig?.rpcUrls ?? {},
|
|
49
|
+
chains: userConfig?.chains ?? [...DEFAULTS.chains],
|
|
50
|
+
timeout: userConfig?.timeout ?? DEFAULTS.timeout,
|
|
51
|
+
maxRetries: userConfig?.maxRetries ?? DEFAULTS.maxRetries,
|
|
52
|
+
retryDelay: userConfig?.retryDelay ?? DEFAULTS.retryDelay,
|
|
53
|
+
};
|
|
54
|
+
try {
|
|
55
|
+
(0, sdk_1.createConfig)({
|
|
56
|
+
integrator: this.config.integrator,
|
|
57
|
+
...(this.config.apiKey ? { apiKey: this.config.apiKey } : {}),
|
|
58
|
+
...(Object.keys(this.config.rpcUrls).length > 0
|
|
59
|
+
? { rpcUrls: this.config.rpcUrls }
|
|
60
|
+
: {}),
|
|
61
|
+
chains: this.config.chains.map((id) => ({ id, name: String(id), network: String(id) })),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
66
|
+
throw new Error(`LifiProvider: failed to initialize LI.FI SDK — ${message}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// Public API (stubs — implemented in tasks 5.2, 5.3, 5.4)
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
/**
|
|
73
|
+
* Fetch a quote for the given intent parameters.
|
|
74
|
+
*
|
|
75
|
+
* Validates params, resolves chains/tokens, calls `getQuote` from `@lifi/sdk`
|
|
76
|
+
* with retry, normalizes the response, and falls back on error.
|
|
77
|
+
*
|
|
78
|
+
* @param params - Intent parameters
|
|
79
|
+
* @returns A normalized {@link LifiQuotePayload}
|
|
80
|
+
*/
|
|
81
|
+
async fetchQuote(params) {
|
|
82
|
+
// 1. Validate params
|
|
83
|
+
const invalid = this.validateParams(params);
|
|
84
|
+
if (invalid) {
|
|
85
|
+
return (0, fallback_js_1.buildFallbackQuote)(params, invalid);
|
|
86
|
+
}
|
|
87
|
+
// 2. Resolve source chain
|
|
88
|
+
const fromChainRes = (0, chain_map_js_1.resolveChain)(params.sourceChain);
|
|
89
|
+
if (!fromChainRes.ok) {
|
|
90
|
+
return (0, fallback_js_1.buildFallbackQuote)(params, {
|
|
91
|
+
enabled: true,
|
|
92
|
+
reasonCode: 'UNSUPPORTED_CHAIN',
|
|
93
|
+
message: fromChainRes.reason,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
const fromChainId = fromChainRes.chainId;
|
|
97
|
+
// 3. Resolve destination chain
|
|
98
|
+
const toChainRes = (0, chain_map_js_1.resolveChain)(params.destinationChain);
|
|
99
|
+
if (!toChainRes.ok) {
|
|
100
|
+
return (0, fallback_js_1.buildFallbackQuote)(params, {
|
|
101
|
+
enabled: true,
|
|
102
|
+
reasonCode: 'UNSUPPORTED_CHAIN',
|
|
103
|
+
message: toChainRes.reason,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
const toChainId = toChainRes.chainId;
|
|
107
|
+
// 4. Resolve source token
|
|
108
|
+
const fromTokenRes = (0, token_map_js_1.resolveToken)(fromChainId, params.tokenIn);
|
|
109
|
+
if (!fromTokenRes.ok) {
|
|
110
|
+
return (0, fallback_js_1.buildFallbackQuote)(params, {
|
|
111
|
+
enabled: true,
|
|
112
|
+
reasonCode: 'UNSUPPORTED_TOKEN',
|
|
113
|
+
message: fromTokenRes.reason,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
const fromToken = fromTokenRes.token;
|
|
117
|
+
// 5. Resolve destination token
|
|
118
|
+
const toTokenRes = (0, token_map_js_1.resolveToken)(toChainId, params.tokenOut);
|
|
119
|
+
if (!toTokenRes.ok) {
|
|
120
|
+
return (0, fallback_js_1.buildFallbackQuote)(params, {
|
|
121
|
+
enabled: true,
|
|
122
|
+
reasonCode: 'UNSUPPORTED_TOKEN',
|
|
123
|
+
message: toTokenRes.reason,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
const toToken = toTokenRes.token;
|
|
127
|
+
// 6. Convert amountIn to base units
|
|
128
|
+
const fromAmount = (0, utils_js_1.toBaseUnits)(params.amountIn, fromToken.decimals);
|
|
129
|
+
try {
|
|
130
|
+
// 7. Call getQuote from @lifi/sdk with retry
|
|
131
|
+
const data = await this.executeWithRetry(() => (0, sdk_1.getQuote)({
|
|
132
|
+
fromChain: fromChainId,
|
|
133
|
+
toChain: toChainId,
|
|
134
|
+
fromToken: fromToken.address,
|
|
135
|
+
toToken: toToken.address,
|
|
136
|
+
fromAmount: fromAmount,
|
|
137
|
+
fromAddress: '0x0000000000000000000000000000000000000000',
|
|
138
|
+
}));
|
|
139
|
+
// 8. If data is empty/null, return fallback
|
|
140
|
+
if (!data) {
|
|
141
|
+
return (0, fallback_js_1.buildFallbackQuote)(params, {
|
|
142
|
+
enabled: true,
|
|
143
|
+
reasonCode: 'LIFI_EMPTY_RESPONSE',
|
|
144
|
+
message: 'LI.FI returned an empty response',
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
// 9. Normalize the response
|
|
148
|
+
const amountOut = data.estimate?.toAmount
|
|
149
|
+
? (0, utils_js_1.fromBaseUnits)(data.estimate.toAmount, toToken.decimals)
|
|
150
|
+
: params.amountIn;
|
|
151
|
+
const routeId = data.id ?? (0, fallback_js_1.deterministicId)(JSON.stringify(data));
|
|
152
|
+
const estimatedGasUsd = data.estimate?.gasCosts?.[0]?.amountUSD ?? undefined;
|
|
153
|
+
return {
|
|
154
|
+
provider: 'lifi',
|
|
155
|
+
routeId,
|
|
156
|
+
timestamp: Date.now(),
|
|
157
|
+
quote: {
|
|
158
|
+
amountIn: params.amountIn,
|
|
159
|
+
amountOut,
|
|
160
|
+
minAmountOut: params.minAmountOut,
|
|
161
|
+
fromChainId,
|
|
162
|
+
toChainId,
|
|
163
|
+
fromToken: params.tokenIn,
|
|
164
|
+
toToken: params.tokenOut,
|
|
165
|
+
estimatedGasUsd,
|
|
166
|
+
},
|
|
167
|
+
raw: data,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
// 10. Catch errors and return fallback with mapped reason code
|
|
172
|
+
const reasonCode = this.mapErrorToReasonCode(error);
|
|
173
|
+
const message = error instanceof Error ? error.message : 'LI.FI quote request failed';
|
|
174
|
+
return (0, fallback_js_1.buildFallbackQuote)(params, {
|
|
175
|
+
enabled: true,
|
|
176
|
+
reasonCode,
|
|
177
|
+
message,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Fetch the best route for the given intent parameters.
|
|
183
|
+
*
|
|
184
|
+
* Validates params, resolves chains/tokens, calls `getRoutes` from `@lifi/sdk`
|
|
185
|
+
* with retry, selects the best route by output amount, normalizes, and falls
|
|
186
|
+
* back on error.
|
|
187
|
+
*
|
|
188
|
+
* @param params - Intent parameters
|
|
189
|
+
* @returns A normalized {@link LifiRoutePayload}
|
|
190
|
+
*/
|
|
191
|
+
async fetchRoute(params) {
|
|
192
|
+
// 1. Validate params
|
|
193
|
+
const invalid = this.validateParams(params);
|
|
194
|
+
if (invalid) {
|
|
195
|
+
return (0, fallback_js_1.buildFallbackRoute)(params, invalid);
|
|
196
|
+
}
|
|
197
|
+
// 2. Resolve source chain
|
|
198
|
+
const fromChainRes = (0, chain_map_js_1.resolveChain)(params.sourceChain);
|
|
199
|
+
if (!fromChainRes.ok) {
|
|
200
|
+
return (0, fallback_js_1.buildFallbackRoute)(params, {
|
|
201
|
+
enabled: true,
|
|
202
|
+
reasonCode: 'UNSUPPORTED_CHAIN',
|
|
203
|
+
message: fromChainRes.reason,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
const fromChainId = fromChainRes.chainId;
|
|
207
|
+
// 3. Resolve destination chain
|
|
208
|
+
const toChainRes = (0, chain_map_js_1.resolveChain)(params.destinationChain);
|
|
209
|
+
if (!toChainRes.ok) {
|
|
210
|
+
return (0, fallback_js_1.buildFallbackRoute)(params, {
|
|
211
|
+
enabled: true,
|
|
212
|
+
reasonCode: 'UNSUPPORTED_CHAIN',
|
|
213
|
+
message: toChainRes.reason,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
const toChainId = toChainRes.chainId;
|
|
217
|
+
// 4. Resolve source token
|
|
218
|
+
const fromTokenRes = (0, token_map_js_1.resolveToken)(fromChainId, params.tokenIn);
|
|
219
|
+
if (!fromTokenRes.ok) {
|
|
220
|
+
return (0, fallback_js_1.buildFallbackRoute)(params, {
|
|
221
|
+
enabled: true,
|
|
222
|
+
reasonCode: 'UNSUPPORTED_TOKEN',
|
|
223
|
+
message: fromTokenRes.reason,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
const fromToken = fromTokenRes.token;
|
|
227
|
+
// 5. Resolve destination token
|
|
228
|
+
const toTokenRes = (0, token_map_js_1.resolveToken)(toChainId, params.tokenOut);
|
|
229
|
+
if (!toTokenRes.ok) {
|
|
230
|
+
return (0, fallback_js_1.buildFallbackRoute)(params, {
|
|
231
|
+
enabled: true,
|
|
232
|
+
reasonCode: 'UNSUPPORTED_TOKEN',
|
|
233
|
+
message: toTokenRes.reason,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
const toToken = toTokenRes.token;
|
|
237
|
+
// 6. Convert amountIn to base units
|
|
238
|
+
const fromAmount = (0, utils_js_1.toBaseUnits)(params.amountIn, fromToken.decimals);
|
|
239
|
+
try {
|
|
240
|
+
// 7. Call getRoutes from @lifi/sdk with retry
|
|
241
|
+
const data = await this.executeWithRetry(() => (0, sdk_1.getRoutes)({
|
|
242
|
+
fromChainId,
|
|
243
|
+
toChainId,
|
|
244
|
+
fromTokenAddress: fromToken.address,
|
|
245
|
+
toTokenAddress: toToken.address,
|
|
246
|
+
fromAmount: fromAmount,
|
|
247
|
+
}));
|
|
248
|
+
// 8. If no routes returned, return fallback
|
|
249
|
+
if (!data.routes || data.routes.length === 0) {
|
|
250
|
+
return (0, fallback_js_1.buildFallbackRoute)(params, {
|
|
251
|
+
enabled: true,
|
|
252
|
+
reasonCode: 'LIFI_EMPTY_RESPONSE',
|
|
253
|
+
message: 'LI.FI returned no routes',
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
// 9. Select the best route by highest toAmount
|
|
257
|
+
const bestRoute = data.routes.reduce((best, route) => BigInt(route.toAmount ?? '0') > BigInt(best.toAmount ?? '0')
|
|
258
|
+
? route
|
|
259
|
+
: best);
|
|
260
|
+
// 10. Compute estimated duration as sum of step durations
|
|
261
|
+
const steps = bestRoute.steps;
|
|
262
|
+
const estimatedDuration = Array.isArray(steps)
|
|
263
|
+
? steps.reduce((sum, step) => {
|
|
264
|
+
const estimate = step.estimate;
|
|
265
|
+
if (typeof estimate === 'object' && estimate !== null) {
|
|
266
|
+
return sum + Number(estimate.executionDuration ?? 0);
|
|
267
|
+
}
|
|
268
|
+
return sum;
|
|
269
|
+
}, 0)
|
|
270
|
+
: undefined;
|
|
271
|
+
// 11. Normalize the response into a LifiRoutePayload
|
|
272
|
+
const routeId = bestRoute.id != null
|
|
273
|
+
? String(bestRoute.id)
|
|
274
|
+
: (0, fallback_js_1.deterministicId)(JSON.stringify(bestRoute));
|
|
275
|
+
return {
|
|
276
|
+
provider: 'lifi',
|
|
277
|
+
routeId,
|
|
278
|
+
timestamp: Date.now(),
|
|
279
|
+
route: {
|
|
280
|
+
fromChainId,
|
|
281
|
+
toChainId,
|
|
282
|
+
fromToken: params.tokenIn,
|
|
283
|
+
toToken: params.tokenOut,
|
|
284
|
+
steps: steps,
|
|
285
|
+
tags: bestRoute.tags,
|
|
286
|
+
estimatedDuration,
|
|
287
|
+
},
|
|
288
|
+
raw: bestRoute,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
// 12. Catch errors and return fallback with mapped reason code
|
|
293
|
+
const reasonCode = this.mapErrorToReasonCode(error);
|
|
294
|
+
const message = error instanceof Error ? error.message : 'LI.FI route request failed';
|
|
295
|
+
return (0, fallback_js_1.buildFallbackRoute)(params, {
|
|
296
|
+
enabled: true,
|
|
297
|
+
reasonCode,
|
|
298
|
+
message,
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Check the status of a LI.FI transaction.
|
|
304
|
+
*
|
|
305
|
+
* 1. Checks for missing txHash — returns fallback with 'MISSING_TX_HASH'
|
|
306
|
+
* 2. Calls `getStatus` from `@lifi/sdk` with retry
|
|
307
|
+
* 3. If data is empty/null, returns fallback with 'LIFI_EMPTY_RESPONSE'
|
|
308
|
+
* 4. Normalizes the response into a LifiStatusPayload
|
|
309
|
+
* 5. Catches errors and returns fallback with mapped reason code
|
|
310
|
+
*
|
|
311
|
+
* @param txHash - Transaction hash to query
|
|
312
|
+
* @returns A normalized {@link LifiStatusPayload}
|
|
313
|
+
*/
|
|
314
|
+
async fetchStatus(txHash) {
|
|
315
|
+
// 1. Check for missing txHash
|
|
316
|
+
if (!txHash) {
|
|
317
|
+
return (0, fallback_js_1.buildFallbackStatus)(txHash, {
|
|
318
|
+
enabled: true,
|
|
319
|
+
reasonCode: 'MISSING_TX_HASH',
|
|
320
|
+
message: 'Transaction hash is required',
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
try {
|
|
324
|
+
// 2. Call getStatus from @lifi/sdk with retry
|
|
325
|
+
const data = await this.executeWithRetry(() => (0, sdk_1.getStatus)({ txHash }));
|
|
326
|
+
// 3. If data is empty/null, return fallback
|
|
327
|
+
if (!data) {
|
|
328
|
+
return (0, fallback_js_1.buildFallbackStatus)(txHash, {
|
|
329
|
+
enabled: true,
|
|
330
|
+
reasonCode: 'LIFI_EMPTY_RESPONSE',
|
|
331
|
+
message: 'LI.FI returned an empty status response',
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
// 4. Normalize the response into a LifiStatusPayload
|
|
335
|
+
const statusData = data;
|
|
336
|
+
return {
|
|
337
|
+
provider: 'lifi',
|
|
338
|
+
timestamp: Date.now(),
|
|
339
|
+
status: {
|
|
340
|
+
state: statusData.status ?? 'UNKNOWN',
|
|
341
|
+
substatus: statusData.substatus,
|
|
342
|
+
txHash,
|
|
343
|
+
},
|
|
344
|
+
raw: data,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
catch (error) {
|
|
348
|
+
// 5. Catch errors and return fallback with mapped reason code
|
|
349
|
+
const reasonCode = this.mapErrorToReasonCode(error);
|
|
350
|
+
const message = error instanceof Error
|
|
351
|
+
? error.message
|
|
352
|
+
: 'LI.FI status request failed';
|
|
353
|
+
return (0, fallback_js_1.buildFallbackStatus)(txHash, {
|
|
354
|
+
enabled: true,
|
|
355
|
+
reasonCode,
|
|
356
|
+
message,
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
// ---------------------------------------------------------------------------
|
|
361
|
+
// Private helpers
|
|
362
|
+
// ---------------------------------------------------------------------------
|
|
363
|
+
/**
|
|
364
|
+
* Execute a function with exponential backoff retry logic.
|
|
365
|
+
*
|
|
366
|
+
* Retries on rate-limit (429) and server errors (5xx). Non-retryable errors
|
|
367
|
+
* are re-thrown immediately.
|
|
368
|
+
*
|
|
369
|
+
* @param fn - Async function to execute
|
|
370
|
+
* @returns The result of `fn`
|
|
371
|
+
* @throws The last error if all retries are exhausted
|
|
372
|
+
*/
|
|
373
|
+
async executeWithRetry(fn) {
|
|
374
|
+
let delay = this.config.retryDelay;
|
|
375
|
+
for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
|
|
376
|
+
try {
|
|
377
|
+
return await fn();
|
|
378
|
+
}
|
|
379
|
+
catch (error) {
|
|
380
|
+
if (!this.isRetryable(error) || attempt === this.config.maxRetries) {
|
|
381
|
+
throw error;
|
|
382
|
+
}
|
|
383
|
+
await this.sleep(delay);
|
|
384
|
+
delay *= 2; // exponential backoff
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
// Unreachable in practice, but satisfies the compiler
|
|
388
|
+
throw new Error('Retry exhausted');
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Determine whether an error is retryable.
|
|
392
|
+
*
|
|
393
|
+
* Retryable errors:
|
|
394
|
+
* - HTTP 429 (rate limited)
|
|
395
|
+
* - HTTP 5xx (server errors)
|
|
396
|
+
* - Network errors (TypeError, or message containing 'network' / 'fetch')
|
|
397
|
+
*
|
|
398
|
+
* @param error - The caught error
|
|
399
|
+
* @returns `true` if the request should be retried
|
|
400
|
+
*/
|
|
401
|
+
isRetryable(error) {
|
|
402
|
+
// Check for HTTP status codes on the error object
|
|
403
|
+
if (error !== null && typeof error === 'object') {
|
|
404
|
+
const statusCode = error['status'] ??
|
|
405
|
+
error['statusCode'];
|
|
406
|
+
if (typeof statusCode === 'number') {
|
|
407
|
+
if (statusCode === 429)
|
|
408
|
+
return true;
|
|
409
|
+
if (statusCode >= 500)
|
|
410
|
+
return true;
|
|
411
|
+
// Non-retryable client errors (4xx except 429)
|
|
412
|
+
return false;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
// Network errors
|
|
416
|
+
if (error instanceof TypeError)
|
|
417
|
+
return true;
|
|
418
|
+
if (error instanceof Error) {
|
|
419
|
+
const msg = error.message.toLowerCase();
|
|
420
|
+
if (msg.includes('network') || msg.includes('fetch'))
|
|
421
|
+
return true;
|
|
422
|
+
}
|
|
423
|
+
return false;
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Sleep for the given number of milliseconds.
|
|
427
|
+
*
|
|
428
|
+
* @param ms - Duration in milliseconds
|
|
429
|
+
*/
|
|
430
|
+
sleep(ms) {
|
|
431
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Validate that all required IntentParams fields are present and valid.
|
|
435
|
+
*
|
|
436
|
+
* @param params - Intent parameters to validate
|
|
437
|
+
* @returns A {@link LifiFallback} if validation fails, or `null` if valid
|
|
438
|
+
*/
|
|
439
|
+
validateParams(params) {
|
|
440
|
+
const requiredFields = [
|
|
441
|
+
'sourceChain',
|
|
442
|
+
'destinationChain',
|
|
443
|
+
'tokenIn',
|
|
444
|
+
'tokenOut',
|
|
445
|
+
'amountIn',
|
|
446
|
+
];
|
|
447
|
+
for (const field of requiredFields) {
|
|
448
|
+
const value = params[field];
|
|
449
|
+
if (value === undefined || value === null || value === '') {
|
|
450
|
+
return {
|
|
451
|
+
enabled: true,
|
|
452
|
+
reasonCode: 'MISSING_PARAMS',
|
|
453
|
+
message: `Missing required parameter: ${field}`,
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
// Validate amountIn is a valid positive number
|
|
458
|
+
const amount = Number(params.amountIn);
|
|
459
|
+
if (!Number.isFinite(amount) || amount <= 0) {
|
|
460
|
+
return {
|
|
461
|
+
enabled: true,
|
|
462
|
+
reasonCode: 'INVALID_AMOUNT',
|
|
463
|
+
message: `Invalid amount: "${params.amountIn}" must be a positive number`,
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
return null;
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Map an error to a LI.FI reason code based on HTTP status codes.
|
|
470
|
+
*
|
|
471
|
+
* - 400 or 422 → 'LIFI_BAD_REQUEST'
|
|
472
|
+
* - 429 → 'LIFI_RATE_LIMITED'
|
|
473
|
+
* - >= 500 → 'LIFI_SERVER_ERROR'
|
|
474
|
+
* - Otherwise → 'LIFI_UNAVAILABLE'
|
|
475
|
+
*
|
|
476
|
+
* @param error - The caught error
|
|
477
|
+
* @returns The appropriate {@link LifiReasonCode}
|
|
478
|
+
*/
|
|
479
|
+
mapErrorToReasonCode(error) {
|
|
480
|
+
if (error !== null && typeof error === 'object') {
|
|
481
|
+
const statusCode = error['status'] ??
|
|
482
|
+
error['statusCode'];
|
|
483
|
+
if (typeof statusCode === 'number') {
|
|
484
|
+
if (statusCode === 400 || statusCode === 422)
|
|
485
|
+
return 'LIFI_BAD_REQUEST';
|
|
486
|
+
if (statusCode === 429)
|
|
487
|
+
return 'LIFI_RATE_LIMITED';
|
|
488
|
+
if (statusCode >= 500)
|
|
489
|
+
return 'LIFI_SERVER_ERROR';
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
return 'LIFI_UNAVAILABLE';
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
exports.LifiProvider = LifiProvider;
|
|
496
|
+
//# sourceMappingURL=lifi-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifi-provider.js","sourceRoot":"","sources":["../../../src/lifi/lifi-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* TokenMap — pure mapping module for token symbol → address resolution.
|
|
4
|
+
*
|
|
5
|
+
* Lookups are case-insensitive via `symbol.toUpperCase()`.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.resolveToken = resolveToken;
|
|
9
|
+
exports.getSupportedTokens = getSupportedTokens;
|
|
10
|
+
/** Default token mappings per chain ID. Keyed by chain ID → uppercase symbol → TokenInfo. */
|
|
11
|
+
const TOKEN_MAP = {
|
|
12
|
+
// Arbitrum
|
|
13
|
+
42161: {
|
|
14
|
+
USDC: { address: '0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8', decimals: 6 },
|
|
15
|
+
WETH: { address: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', decimals: 18 },
|
|
16
|
+
ETH: { address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', decimals: 18 },
|
|
17
|
+
},
|
|
18
|
+
// Optimism
|
|
19
|
+
10: {
|
|
20
|
+
USDC: { address: '0x7F5c764cBc14f9669B88837ca1490cCa17c31607', decimals: 6 },
|
|
21
|
+
WETH: { address: '0x4200000000000000000000000000000000000006', decimals: 18 },
|
|
22
|
+
ETH: { address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', decimals: 18 },
|
|
23
|
+
},
|
|
24
|
+
// Base
|
|
25
|
+
8453: {
|
|
26
|
+
USDC: { address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', decimals: 6 },
|
|
27
|
+
WETH: { address: '0x4200000000000000000000000000000000000006', decimals: 18 },
|
|
28
|
+
ETH: { address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', decimals: 18 },
|
|
29
|
+
},
|
|
30
|
+
// Polygon
|
|
31
|
+
137: {
|
|
32
|
+
USDC: { address: '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174', decimals: 6 },
|
|
33
|
+
WETH: { address: '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619', decimals: 18 },
|
|
34
|
+
ETH: { address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', decimals: 18 },
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Resolve a token symbol on a given chain to its on-chain address and decimal count.
|
|
39
|
+
*
|
|
40
|
+
* @param chainId - Numeric chain ID (e.g. 42161 for Arbitrum)
|
|
41
|
+
* @param symbol - Token symbol (case-insensitive), e.g. "usdc", "WETH"
|
|
42
|
+
* @returns A discriminated union: `{ ok: true, token }` on success,
|
|
43
|
+
* `{ ok: false, reason }` when the token is not supported on the chain.
|
|
44
|
+
*/
|
|
45
|
+
function resolveToken(chainId, symbol) {
|
|
46
|
+
const chainTokens = TOKEN_MAP[chainId];
|
|
47
|
+
if (chainTokens === undefined) {
|
|
48
|
+
return { ok: false, reason: `Unsupported chain ID: ${chainId}` };
|
|
49
|
+
}
|
|
50
|
+
const token = chainTokens[symbol.toUpperCase()];
|
|
51
|
+
if (token !== undefined) {
|
|
52
|
+
return { ok: true, token };
|
|
53
|
+
}
|
|
54
|
+
return { ok: false, reason: `Unsupported token "${symbol}" on chain ${chainId}` };
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Return a copy of the token mappings for a given chain.
|
|
58
|
+
*
|
|
59
|
+
* @param chainId - Numeric chain ID
|
|
60
|
+
* @returns A new `Record<string, TokenInfo>` with all supported token entries for the chain,
|
|
61
|
+
* or an empty object if the chain is not supported.
|
|
62
|
+
*/
|
|
63
|
+
function getSupportedTokens(chainId) {
|
|
64
|
+
const chainTokens = TOKEN_MAP[chainId];
|
|
65
|
+
if (chainTokens === undefined) {
|
|
66
|
+
return {};
|
|
67
|
+
}
|
|
68
|
+
// Return a shallow copy so callers cannot mutate the internal map
|
|
69
|
+
const copy = {};
|
|
70
|
+
for (const [symbol, info] of Object.entries(chainTokens)) {
|
|
71
|
+
copy[symbol] = { ...info };
|
|
72
|
+
}
|
|
73
|
+
return copy;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=token-map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-map.js","sourceRoot":"","sources":["../../../src/lifi/token-map.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AA+CH,oCAUC;AASD,gDAWC;AAlED,6FAA6F;AAC7F,MAAM,SAAS,GAA8C;IAC3D,WAAW;IACX,KAAK,EAAE;QACL,IAAI,EAAE,EAAE,OAAO,EAAE,4CAA4C,EAAE,QAAQ,EAAE,CAAC,EAAE;QAC5E,IAAI,EAAE,EAAE,OAAO,EAAE,4CAA4C,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC7E,GAAG,EAAE,EAAE,OAAO,EAAE,4CAA4C,EAAE,QAAQ,EAAE,EAAE,EAAE;KAC7E;IACD,WAAW;IACX,EAAE,EAAE;QACF,IAAI,EAAE,EAAE,OAAO,EAAE,4CAA4C,EAAE,QAAQ,EAAE,CAAC,EAAE;QAC5E,IAAI,EAAE,EAAE,OAAO,EAAE,4CAA4C,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC7E,GAAG,EAAE,EAAE,OAAO,EAAE,4CAA4C,EAAE,QAAQ,EAAE,EAAE,EAAE;KAC7E;IACD,OAAO;IACP,IAAI,EAAE;QACJ,IAAI,EAAE,EAAE,OAAO,EAAE,4CAA4C,EAAE,QAAQ,EAAE,CAAC,EAAE;QAC5E,IAAI,EAAE,EAAE,OAAO,EAAE,4CAA4C,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC7E,GAAG,EAAE,EAAE,OAAO,EAAE,4CAA4C,EAAE,QAAQ,EAAE,EAAE,EAAE;KAC7E;IACD,UAAU;IACV,GAAG,EAAE;QACH,IAAI,EAAE,EAAE,OAAO,EAAE,4CAA4C,EAAE,QAAQ,EAAE,CAAC,EAAE;QAC5E,IAAI,EAAE,EAAE,OAAO,EAAE,4CAA4C,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC7E,GAAG,EAAE,EAAE,OAAO,EAAE,4CAA4C,EAAE,QAAQ,EAAE,EAAE,EAAE;KAC7E;CACF,CAAC;AAEF;;;;;;;GAOG;AACH,SAAgB,YAAY,CAAC,OAAe,EAAE,MAAc;IAC1D,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IACvC,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,yBAAyB,OAAO,EAAE,EAAE,CAAC;IACnE,CAAC;IACD,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;IAChD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IAC7B,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,sBAAsB,MAAM,cAAc,OAAO,EAAE,EAAE,CAAC;AACpF,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,kBAAkB,CAAC,OAAe;IAChD,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IACvC,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,kEAAkE;IAClE,MAAM,IAAI,GAA8B,EAAE,CAAC;IAC3C,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QACzD,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;IAC7B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/lifi/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Unit conversion utilities for converting between human-readable token amounts
|
|
4
|
+
* and base unit (wei-like) representations.
|
|
5
|
+
*
|
|
6
|
+
* Ported from apps/dashboard/src/lib/lifi.ts for reuse across the SDK.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.toBaseUnits = toBaseUnits;
|
|
10
|
+
exports.fromBaseUnits = fromBaseUnits;
|
|
11
|
+
/**
|
|
12
|
+
* Converts a human-readable token amount to its base unit representation.
|
|
13
|
+
*
|
|
14
|
+
* For example, converting "1.5" USDC (6 decimals) produces "1500000",
|
|
15
|
+
* and converting "1.5" ETH (18 decimals) produces "1500000000000000000".
|
|
16
|
+
*
|
|
17
|
+
* @param amount - The human-readable amount as a string (e.g. "1.5", "100", "0.001")
|
|
18
|
+
* @param decimals - The number of decimal places for the token
|
|
19
|
+
* @returns The amount in base units as a string with no decimal point
|
|
20
|
+
*/
|
|
21
|
+
function toBaseUnits(amount, decimals) {
|
|
22
|
+
const [whole = '0', fraction = ''] = amount.split('.');
|
|
23
|
+
const normalizedFraction = fraction.padEnd(decimals, '0').slice(0, decimals);
|
|
24
|
+
const base = `${whole}${normalizedFraction}`.replace(/^0+(?=\d)/, '');
|
|
25
|
+
return base.length ? base : '0';
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Converts a base unit amount back to a human-readable representation.
|
|
29
|
+
*
|
|
30
|
+
* For example, converting "1500000" with 6 decimals produces "1.5",
|
|
31
|
+
* and converting "1500000000000000000" with 18 decimals produces "1.5".
|
|
32
|
+
*
|
|
33
|
+
* @param amount - The base unit amount as a string (e.g. "1500000", "1000000000000000000")
|
|
34
|
+
* @param decimals - The number of decimal places for the token
|
|
35
|
+
* @returns The human-readable amount as a string with trailing zeros removed
|
|
36
|
+
*/
|
|
37
|
+
function fromBaseUnits(amount, decimals) {
|
|
38
|
+
if (!amount || amount === '0')
|
|
39
|
+
return '0';
|
|
40
|
+
const padded = amount.padStart(decimals + 1, '0');
|
|
41
|
+
const whole = padded.slice(0, -decimals) || '0';
|
|
42
|
+
const fraction = padded.slice(-decimals).replace(/0+$/, '');
|
|
43
|
+
return fraction ? `${whole}.${fraction}` : whole;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/lifi/utils.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAYH,kCAKC;AAYD,sCAMC;AAjCD;;;;;;;;;GASG;AACH,SAAgB,WAAW,CAAC,MAAc,EAAE,QAAgB;IAC1D,MAAM,CAAC,KAAK,GAAG,GAAG,EAAE,QAAQ,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACvD,MAAM,kBAAkB,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC7E,MAAM,IAAI,GAAG,GAAG,KAAK,GAAG,kBAAkB,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IACtE,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;AAClC,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,aAAa,CAAC,MAAc,EAAE,QAAgB;IAC5D,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,GAAG,CAAC;IAC1C,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;IAClD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC;IAChD,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC5D,OAAO,QAAQ,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;AACnD,CAAC"}
|