@yodlpay/payment-decoder 1.3.4 → 1.3.6
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/index.d.ts +6 -4
- package/dist/index.js +273 -306
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -84,6 +84,8 @@ interface DecodeBridgeOptions {
|
|
|
84
84
|
includeAcross?: boolean;
|
|
85
85
|
/** Receipt of the fill (destination) tx, used for Across fill-side lookups. */
|
|
86
86
|
fillReceipt?: TransactionReceipt;
|
|
87
|
+
/** Receipt of the source tx, used to skip re-fetching when hash is the source. */
|
|
88
|
+
sourceReceipt?: TransactionReceipt;
|
|
87
89
|
}
|
|
88
90
|
declare function decodeBridgePayment(hash: Hex, clients: ChainClients, options?: DecodeBridgeOptions): Promise<Extract<PaymentInfo, {
|
|
89
91
|
type: "bridge";
|
|
@@ -107,6 +109,10 @@ interface DecodedYodlEvent {
|
|
|
107
109
|
*/
|
|
108
110
|
declare function decodeYodlFromLogs(logs: readonly Log[], routerAddress: Address): DecodedYodlEvent | undefined;
|
|
109
111
|
|
|
112
|
+
declare function decodePayment(hash: Hex, chainId: number, clients: ChainClients, cachedReceipt?: TransactionReceipt): Promise<PaymentInfo>;
|
|
113
|
+
|
|
114
|
+
declare function decodeYodlPayment(txHash: Hex, chainId: number, clients: ChainClients, cachedReceipt?: TransactionReceipt): Promise<YodlPayment>;
|
|
115
|
+
|
|
110
116
|
declare class NoBridgeFoundError extends Error {
|
|
111
117
|
constructor(message?: string);
|
|
112
118
|
}
|
|
@@ -114,8 +120,4 @@ declare class NoYodlEventError extends Error {
|
|
|
114
120
|
constructor(message?: string);
|
|
115
121
|
}
|
|
116
122
|
|
|
117
|
-
declare function decodePayment(hash: Hex, chainId: number, clients: ChainClients, cachedReceipt?: TransactionReceipt): Promise<PaymentInfo>;
|
|
118
|
-
|
|
119
|
-
declare function decodeYodlPayment(txHash: Hex, chainId: number, clients: ChainClients, cachedReceipt?: TransactionReceipt): Promise<YodlPayment>;
|
|
120
|
-
|
|
121
123
|
export { type BridgeInfo, type ChainClients, type DecodedYodlEvent, NoBridgeFoundError, NoYodlEventError, type PaymentEvent, type PaymentInfo, type ServiceProvider, type SwapInfo, type TokenInInfo, type TokenOutInfo, type Webhook, type YodlPayment, createClients, decodeBridgePayment, decodePayment, decodeYodlFromLogs, decodeYodlPayment, detectChain };
|
package/dist/index.js
CHANGED
|
@@ -1,18 +1,7 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import { parseDepositLogs, parseFillLogs } from "@across-protocol/app-sdk";
|
|
3
|
-
import { getRouter as getRouter2 } from "@yodlpay/tokenlists";
|
|
4
|
-
|
|
5
|
-
// src/across-client.ts
|
|
6
|
-
import { isHash } from "viem";
|
|
7
|
-
import { z } from "zod";
|
|
1
|
+
// src/bridges/bridge-payment.ts
|
|
2
|
+
import { parseDepositLogs as parseDepositLogs2, parseFillLogs as parseFillLogs2 } from "@across-protocol/app-sdk";
|
|
8
3
|
|
|
9
4
|
// src/errors.ts
|
|
10
|
-
import {
|
|
11
|
-
AbiDecodingDataSizeTooSmallError,
|
|
12
|
-
AbiEventSignatureEmptyTopicsError,
|
|
13
|
-
AbiEventSignatureNotFoundError,
|
|
14
|
-
DecodeLogTopicsMismatch
|
|
15
|
-
} from "viem";
|
|
16
5
|
var ExpectedDecodeError = class extends Error {
|
|
17
6
|
constructor(message = "Expected decode error") {
|
|
18
7
|
super(message);
|
|
@@ -31,141 +20,37 @@ var NoYodlEventError = class extends Error {
|
|
|
31
20
|
this.name = "NoYodlEventError";
|
|
32
21
|
}
|
|
33
22
|
};
|
|
34
|
-
function isExpectedDecodeError(error) {
|
|
35
|
-
return error instanceof AbiEventSignatureNotFoundError || error instanceof AbiEventSignatureEmptyTopicsError || error instanceof AbiDecodingDataSizeTooSmallError || error instanceof DecodeLogTopicsMismatch;
|
|
36
|
-
}
|
|
37
23
|
|
|
38
|
-
// src/across-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
var chainId = z.union([
|
|
42
|
-
z.number().int().positive(),
|
|
43
|
-
z.string().regex(/^\d+$/).transform(Number)
|
|
44
|
-
]).pipe(z.number().int().positive());
|
|
45
|
-
var txHash = z.string().refine((v) => isHash(v));
|
|
46
|
-
var nullableTxHash = txHash.nullish().transform((v) => v ?? null);
|
|
47
|
-
var depositId = z.union([
|
|
48
|
-
z.string().regex(/^\d+$/),
|
|
49
|
-
z.number().int().nonnegative().transform((v) => String(v))
|
|
50
|
-
]);
|
|
51
|
-
var AcrossDepositStatusSchema = z.object({
|
|
52
|
-
status: z.enum(["filled", "pending", "expired", "refunded"]),
|
|
53
|
-
originChainId: chainId,
|
|
54
|
-
destinationChainId: chainId,
|
|
55
|
-
depositId,
|
|
56
|
-
depositTxnRef: txHash.optional(),
|
|
57
|
-
depositTxHash: txHash.optional(),
|
|
58
|
-
fillTxnRef: nullableTxHash,
|
|
59
|
-
fillTx: nullableTxHash,
|
|
60
|
-
actionsSucceeded: z.boolean().nullish().transform((v) => v ?? null)
|
|
61
|
-
}).transform((d) => {
|
|
62
|
-
const depositTxnRef = d.depositTxnRef ?? d.depositTxHash;
|
|
63
|
-
if (!depositTxnRef) {
|
|
64
|
-
throw new Error("Missing depositTxnRef and depositTxHash");
|
|
65
|
-
}
|
|
66
|
-
return {
|
|
67
|
-
status: d.status,
|
|
68
|
-
originChainId: d.originChainId,
|
|
69
|
-
destinationChainId: d.destinationChainId,
|
|
70
|
-
depositId: d.depositId,
|
|
71
|
-
depositTxnRef,
|
|
72
|
-
fillTxnRef: d.fillTxnRef ?? d.fillTx,
|
|
73
|
-
actionsSucceeded: d.actionsSucceeded
|
|
74
|
-
};
|
|
75
|
-
});
|
|
76
|
-
async function fetchAcrossDepositByDepositId(originChainId, depositId2) {
|
|
77
|
-
const url = new URL(ACROSS_API);
|
|
78
|
-
url.searchParams.set("originChainId", String(originChainId));
|
|
79
|
-
url.searchParams.set("depositId", depositId2);
|
|
80
|
-
return fetchAcrossDeposit(url);
|
|
81
|
-
}
|
|
82
|
-
async function fetchAcrossDeposit(url) {
|
|
83
|
-
const controller = new AbortController();
|
|
84
|
-
const timeout = setTimeout(() => controller.abort(), ACROSS_TIMEOUT_MS);
|
|
85
|
-
let response;
|
|
86
|
-
try {
|
|
87
|
-
response = await fetch(url, { signal: controller.signal });
|
|
88
|
-
} catch (error) {
|
|
89
|
-
const message = error instanceof Error && error.name === "AbortError" ? `Across API request timed out after ${ACROSS_TIMEOUT_MS}ms` : "Across API request failed";
|
|
90
|
-
throw new Error(message, { cause: error });
|
|
91
|
-
} finally {
|
|
92
|
-
clearTimeout(timeout);
|
|
93
|
-
}
|
|
94
|
-
if (response.status === 404) throw new NoBridgeFoundError();
|
|
95
|
-
if (!response.ok) {
|
|
96
|
-
const body = await response.text().catch(() => "");
|
|
97
|
-
const kind = response.status === 429 || response.status >= 500 ? "temporary error" : "error";
|
|
98
|
-
throw new Error(
|
|
99
|
-
`Across API ${kind} (${response.status})${body ? ` - ${body}` : ""}`
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
const data = await response.json().catch(() => {
|
|
103
|
-
throw new Error("Across API returned invalid JSON");
|
|
104
|
-
});
|
|
105
|
-
const result = AcrossDepositStatusSchema.safeParse(data);
|
|
106
|
-
if (!result.success) {
|
|
107
|
-
throw new Error(
|
|
108
|
-
`Across API response validation failed: ${result.error.message}`
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
return result.data;
|
|
112
|
-
}
|
|
113
|
-
async function fetchAcrossDepositByTx(hash) {
|
|
114
|
-
const url = new URL(ACROSS_API);
|
|
115
|
-
url.searchParams.set("depositTxnRef", hash);
|
|
116
|
-
return fetchAcrossDeposit(url);
|
|
117
|
-
}
|
|
24
|
+
// src/bridges/across-bridge.ts
|
|
25
|
+
import { parseDepositLogs, parseFillLogs } from "@across-protocol/app-sdk";
|
|
26
|
+
import { getRouter as getRouter2 } from "@yodlpay/tokenlists";
|
|
118
27
|
|
|
119
|
-
// src/decode-utils.ts
|
|
28
|
+
// src/core/decode-utils.ts
|
|
120
29
|
import { tokenlist } from "@yodlpay/tokenlists";
|
|
121
30
|
import {
|
|
122
|
-
decodeEventLog,
|
|
123
31
|
erc20Abi as erc20Abi2,
|
|
124
32
|
getAddress,
|
|
125
|
-
isAddressEqual
|
|
33
|
+
isAddressEqual,
|
|
34
|
+
parseEventLogs
|
|
126
35
|
} from "viem";
|
|
127
36
|
|
|
128
37
|
// src/abi.ts
|
|
129
38
|
import { getRouterAbi } from "@yodlpay/tokenlists";
|
|
39
|
+
import { parseAbi } from "viem";
|
|
130
40
|
var yodlAbi = getRouterAbi("0.8");
|
|
131
|
-
var relaySwapAbi = [
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
name: "Swap",
|
|
135
|
-
inputs: [
|
|
136
|
-
{ name: "sender", type: "address", indexed: true },
|
|
137
|
-
{ name: "recipient", type: "address", indexed: true },
|
|
138
|
-
{ name: "inputToken", type: "address", indexed: false },
|
|
139
|
-
{ name: "outputToken", type: "address", indexed: false },
|
|
140
|
-
{ name: "inputAmount", type: "uint256", indexed: false },
|
|
141
|
-
{ name: "outputAmount", type: "uint256", indexed: false }
|
|
142
|
-
]
|
|
143
|
-
}
|
|
144
|
-
];
|
|
145
|
-
var entryPointAbi = [
|
|
146
|
-
{
|
|
147
|
-
type: "event",
|
|
148
|
-
name: "UserOperationEvent",
|
|
149
|
-
inputs: [
|
|
150
|
-
{ name: "userOpHash", type: "bytes32", indexed: true },
|
|
151
|
-
{ name: "sender", type: "address", indexed: true },
|
|
152
|
-
{ name: "paymaster", type: "address", indexed: true },
|
|
153
|
-
{ name: "nonce", type: "uint256", indexed: false },
|
|
154
|
-
{ name: "success", type: "bool", indexed: false },
|
|
155
|
-
{ name: "actualGasCost", type: "uint256", indexed: false },
|
|
156
|
-
{ name: "actualGasUsed", type: "uint256", indexed: false }
|
|
157
|
-
]
|
|
158
|
-
}
|
|
159
|
-
];
|
|
41
|
+
var relaySwapAbi = parseAbi([
|
|
42
|
+
"event Swap(address indexed sender, address indexed recipient, address inputToken, address outputToken, uint256 inputAmount, uint256 outputAmount)"
|
|
43
|
+
]);
|
|
160
44
|
|
|
161
45
|
// src/utils.ts
|
|
162
46
|
import { getTokenByAddress } from "@yodlpay/tokenlists";
|
|
163
47
|
import {
|
|
164
48
|
erc20Abi,
|
|
165
49
|
getContract,
|
|
166
|
-
hexToString
|
|
50
|
+
hexToString,
|
|
51
|
+
stringify
|
|
167
52
|
} from "viem";
|
|
168
|
-
import { z
|
|
53
|
+
import { z } from "zod";
|
|
169
54
|
function decodeMemo(memo) {
|
|
170
55
|
if (!memo || memo === "0x") return "";
|
|
171
56
|
try {
|
|
@@ -174,8 +59,8 @@ function decodeMemo(memo) {
|
|
|
174
59
|
return "";
|
|
175
60
|
}
|
|
176
61
|
}
|
|
177
|
-
var erc20String =
|
|
178
|
-
var erc20Decimals =
|
|
62
|
+
var erc20String = z.string().max(64).transform((s) => s.replace(/\p{Cc}/gu, ""));
|
|
63
|
+
var erc20Decimals = z.number().int().nonnegative().max(36);
|
|
179
64
|
async function resolveToken(address, chainId2, client) {
|
|
180
65
|
try {
|
|
181
66
|
return getTokenByAddress(address, chainId2);
|
|
@@ -196,98 +81,56 @@ async function resolveToken(address, chainId2, client) {
|
|
|
196
81
|
}
|
|
197
82
|
}
|
|
198
83
|
|
|
199
|
-
// src/decode-utils.ts
|
|
200
|
-
function* matchingEvents(logs, options) {
|
|
201
|
-
const { abi, eventName, address, context } = options;
|
|
202
|
-
for (const log of logs) {
|
|
203
|
-
if (address && !isAddressEqual(log.address, address)) {
|
|
204
|
-
continue;
|
|
205
|
-
}
|
|
206
|
-
try {
|
|
207
|
-
const decoded = decodeEventLog({
|
|
208
|
-
abi,
|
|
209
|
-
data: log.data,
|
|
210
|
-
topics: log.topics
|
|
211
|
-
});
|
|
212
|
-
if (decoded.eventName === eventName) {
|
|
213
|
-
yield { decoded, log };
|
|
214
|
-
}
|
|
215
|
-
} catch (error) {
|
|
216
|
-
if (!isExpectedDecodeError(error)) {
|
|
217
|
-
const contextStr = context ? ` (${context})` : "";
|
|
218
|
-
console.warn(
|
|
219
|
-
`[payment-decoder] Unexpected error decoding ${eventName}${contextStr}:`,
|
|
220
|
-
error
|
|
221
|
-
);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
function findEventInLogs(logs, options, transform) {
|
|
227
|
-
for (const { decoded, log } of matchingEvents(logs, options)) {
|
|
228
|
-
return transform(decoded, log);
|
|
229
|
-
}
|
|
230
|
-
return void 0;
|
|
231
|
-
}
|
|
232
|
-
function collectEventsFromLogs(logs, options, transform) {
|
|
233
|
-
const results = [];
|
|
234
|
-
for (const { decoded, log } of matchingEvents(logs, options)) {
|
|
235
|
-
results.push(transform(decoded, log));
|
|
236
|
-
}
|
|
237
|
-
return results;
|
|
238
|
-
}
|
|
84
|
+
// src/core/decode-utils.ts
|
|
239
85
|
function decodeYodlFromLogs(logs, routerAddress) {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
);
|
|
86
|
+
const parsed = parseEventLogs({
|
|
87
|
+
abi: yodlAbi,
|
|
88
|
+
logs: logs.filter((l) => isAddressEqual(l.address, routerAddress)),
|
|
89
|
+
eventName: "Yodl",
|
|
90
|
+
strict: true
|
|
91
|
+
});
|
|
92
|
+
const first = parsed[0];
|
|
93
|
+
if (!first) return void 0;
|
|
94
|
+
const args = first.args;
|
|
95
|
+
return {
|
|
96
|
+
sender: args.sender,
|
|
97
|
+
receiver: args.receiver,
|
|
98
|
+
token: args.token,
|
|
99
|
+
amount: args.amount,
|
|
100
|
+
memo: decodeMemo(args.memo),
|
|
101
|
+
logIndex: first.logIndex ?? 0
|
|
102
|
+
};
|
|
260
103
|
}
|
|
261
104
|
function decodeSwapFromLogs(logs) {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
105
|
+
const parsed = parseEventLogs({
|
|
106
|
+
abi: relaySwapAbi,
|
|
107
|
+
logs: [...logs],
|
|
108
|
+
eventName: "Swap",
|
|
109
|
+
strict: true
|
|
110
|
+
});
|
|
111
|
+
const first = parsed[0];
|
|
112
|
+
if (!first) return void 0;
|
|
113
|
+
return {
|
|
114
|
+
tokenIn: first.args.inputToken,
|
|
115
|
+
tokenOut: first.args.outputToken,
|
|
116
|
+
tokenInAmount: first.args.inputAmount,
|
|
117
|
+
tokenOutAmount: first.args.outputAmount,
|
|
118
|
+
service: "relay"
|
|
119
|
+
};
|
|
276
120
|
}
|
|
277
121
|
function extractTokenTransfers(logs) {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
);
|
|
122
|
+
const parsed = parseEventLogs({
|
|
123
|
+
abi: erc20Abi2,
|
|
124
|
+
logs: [...logs],
|
|
125
|
+
eventName: "Transfer",
|
|
126
|
+
strict: false
|
|
127
|
+
});
|
|
128
|
+
return parsed.flatMap((log) => {
|
|
129
|
+
if (!log.args) return [];
|
|
130
|
+
const { from, to, value } = log.args;
|
|
131
|
+
if (!from || !to || value === void 0) return [];
|
|
132
|
+
return [{ token: log.address, from, to, amount: value }];
|
|
133
|
+
});
|
|
291
134
|
}
|
|
292
135
|
function isKnownToken(address) {
|
|
293
136
|
return tokenlist.some((t) => isAddressEqual(t.address, address));
|
|
@@ -418,12 +261,12 @@ function buildPaymentEvent(yodlEvent, webhooks, blockTimestamp, senderOverride)
|
|
|
418
261
|
};
|
|
419
262
|
}
|
|
420
263
|
|
|
421
|
-
// src/embedded-params.ts
|
|
264
|
+
// src/core/embedded-params.ts
|
|
422
265
|
import { decodeFunctionData, toFunctionSelector } from "viem";
|
|
423
266
|
|
|
424
267
|
// src/validation.ts
|
|
425
|
-
import { isAddress, isHex } from "viem";
|
|
426
|
-
import { z as
|
|
268
|
+
import { isAddress, isHash, isHex } from "viem";
|
|
269
|
+
import { z as z2 } from "zod";
|
|
427
270
|
|
|
428
271
|
// src/chains.ts
|
|
429
272
|
import { chains as allChains } from "@yodlpay/tokenlists";
|
|
@@ -431,25 +274,25 @@ var chains = allChains.filter((c) => !c.testnet);
|
|
|
431
274
|
|
|
432
275
|
// src/validation.ts
|
|
433
276
|
var validChainIds = chains.map((c) => c.id);
|
|
434
|
-
var txHashSchema =
|
|
435
|
-
var chainIdSchema =
|
|
277
|
+
var txHashSchema = z2.string().refine((val) => isHash(val), "Invalid transaction hash");
|
|
278
|
+
var chainIdSchema = z2.coerce.number().int().refine((id) => validChainIds.includes(id), {
|
|
436
279
|
message: `Chain ID must be one of: ${validChainIds.join(", ")}`
|
|
437
280
|
});
|
|
438
|
-
var ArgsSchema =
|
|
439
|
-
|
|
440
|
-
|
|
281
|
+
var ArgsSchema = z2.union([
|
|
282
|
+
z2.tuple([txHashSchema, chainIdSchema]),
|
|
283
|
+
z2.tuple([txHashSchema])
|
|
441
284
|
]);
|
|
442
|
-
var WebhooksSchema =
|
|
443
|
-
|
|
444
|
-
webhookAddress:
|
|
445
|
-
payload:
|
|
285
|
+
var WebhooksSchema = z2.array(
|
|
286
|
+
z2.object({
|
|
287
|
+
webhookAddress: z2.string().refine((val) => isAddress(val)),
|
|
288
|
+
payload: z2.array(z2.string().refine((val) => isHex(val)))
|
|
446
289
|
}).transform((webhook) => ({
|
|
447
290
|
...webhook,
|
|
448
291
|
memo: webhook.payload[0] ? decodeMemo(webhook.payload[0]) : ""
|
|
449
292
|
}))
|
|
450
293
|
).catch([]);
|
|
451
294
|
|
|
452
|
-
// src/embedded-params.ts
|
|
295
|
+
// src/core/embedded-params.ts
|
|
453
296
|
function getYodlSelector() {
|
|
454
297
|
const yodlFunction = yodlAbi.find(
|
|
455
298
|
(i) => i.type === "function" && i.name === "yodlWithToken"
|
|
@@ -479,13 +322,96 @@ function extractEmbeddedParams(data) {
|
|
|
479
322
|
return [];
|
|
480
323
|
}
|
|
481
324
|
|
|
482
|
-
// src/
|
|
325
|
+
// src/bridges/across-client.ts
|
|
326
|
+
import { isHash as isHash2 } from "viem";
|
|
327
|
+
import { z as z3 } from "zod";
|
|
328
|
+
var ACROSS_API = "https://app.across.to/api/deposit/status";
|
|
329
|
+
var ACROSS_TIMEOUT_MS = 8e3;
|
|
330
|
+
var chainId = z3.union([
|
|
331
|
+
z3.number().int().positive(),
|
|
332
|
+
z3.string().regex(/^\d+$/).transform(Number)
|
|
333
|
+
]).pipe(z3.number().int().positive());
|
|
334
|
+
var txHash = z3.string().refine((v) => isHash2(v));
|
|
335
|
+
var nullableTxHash = txHash.nullish().transform((v) => v ?? null);
|
|
336
|
+
var depositId = z3.union([
|
|
337
|
+
z3.string().regex(/^\d+$/),
|
|
338
|
+
z3.number().int().nonnegative().transform((v) => String(v))
|
|
339
|
+
]);
|
|
340
|
+
var AcrossDepositStatusSchema = z3.object({
|
|
341
|
+
status: z3.enum(["filled", "pending", "expired", "refunded"]),
|
|
342
|
+
originChainId: chainId,
|
|
343
|
+
destinationChainId: chainId,
|
|
344
|
+
depositId,
|
|
345
|
+
depositTxnRef: txHash.optional(),
|
|
346
|
+
depositTxHash: txHash.optional(),
|
|
347
|
+
fillTxnRef: nullableTxHash,
|
|
348
|
+
fillTx: nullableTxHash,
|
|
349
|
+
actionsSucceeded: z3.boolean().nullish().transform((v) => v ?? null)
|
|
350
|
+
}).transform((d) => {
|
|
351
|
+
const depositTxnRef = d.depositTxnRef ?? d.depositTxHash;
|
|
352
|
+
if (!depositTxnRef) {
|
|
353
|
+
throw new Error("Missing depositTxnRef and depositTxHash");
|
|
354
|
+
}
|
|
355
|
+
return {
|
|
356
|
+
status: d.status,
|
|
357
|
+
originChainId: d.originChainId,
|
|
358
|
+
destinationChainId: d.destinationChainId,
|
|
359
|
+
depositId: d.depositId,
|
|
360
|
+
depositTxnRef,
|
|
361
|
+
fillTxnRef: d.fillTxnRef ?? d.fillTx,
|
|
362
|
+
actionsSucceeded: d.actionsSucceeded
|
|
363
|
+
};
|
|
364
|
+
});
|
|
365
|
+
async function fetchAcrossDepositByDepositId(originChainId, depositId2) {
|
|
366
|
+
const url = new URL(ACROSS_API);
|
|
367
|
+
url.searchParams.set("originChainId", String(originChainId));
|
|
368
|
+
url.searchParams.set("depositId", depositId2);
|
|
369
|
+
return fetchAcrossDeposit(url);
|
|
370
|
+
}
|
|
371
|
+
async function fetchAcrossDeposit(url) {
|
|
372
|
+
const controller = new AbortController();
|
|
373
|
+
const timeout = setTimeout(() => controller.abort(), ACROSS_TIMEOUT_MS);
|
|
374
|
+
let response;
|
|
375
|
+
try {
|
|
376
|
+
response = await fetch(url, { signal: controller.signal });
|
|
377
|
+
} catch (error) {
|
|
378
|
+
const message = error instanceof Error && error.name === "AbortError" ? `Across API request timed out after ${ACROSS_TIMEOUT_MS}ms` : "Across API request failed";
|
|
379
|
+
throw new Error(message, { cause: error });
|
|
380
|
+
} finally {
|
|
381
|
+
clearTimeout(timeout);
|
|
382
|
+
}
|
|
383
|
+
if (response.status === 404) throw new NoBridgeFoundError();
|
|
384
|
+
if (!response.ok) {
|
|
385
|
+
const body = await response.text().catch(() => "");
|
|
386
|
+
const kind = response.status === 429 || response.status >= 500 ? "temporary error" : "error";
|
|
387
|
+
throw new Error(
|
|
388
|
+
`Across API ${kind} (${response.status})${body ? ` - ${body}` : ""}`
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
const data = await response.json().catch(() => {
|
|
392
|
+
throw new Error("Across API returned invalid JSON");
|
|
393
|
+
});
|
|
394
|
+
const result = AcrossDepositStatusSchema.safeParse(data);
|
|
395
|
+
if (!result.success) {
|
|
396
|
+
throw new Error(
|
|
397
|
+
`Across API response validation failed: ${result.error.message}`
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
return result.data;
|
|
401
|
+
}
|
|
402
|
+
async function fetchAcrossDepositByTx(hash) {
|
|
403
|
+
const url = new URL(ACROSS_API);
|
|
404
|
+
url.searchParams.set("depositTxnRef", hash);
|
|
405
|
+
return fetchAcrossDeposit(url);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// src/bridges/relay-bridge.ts
|
|
483
409
|
import { getRouter } from "@yodlpay/tokenlists";
|
|
484
410
|
import {
|
|
485
|
-
|
|
486
|
-
|
|
411
|
+
isAddressEqual as isAddressEqual2,
|
|
412
|
+
parseEventLogs as parseEventLogs2
|
|
487
413
|
} from "viem";
|
|
488
|
-
import { entryPoint08Address } from "viem/account-abstraction";
|
|
414
|
+
import { entryPoint08Abi, entryPoint08Address } from "viem/account-abstraction";
|
|
489
415
|
|
|
490
416
|
// src/clients.ts
|
|
491
417
|
import {
|
|
@@ -503,7 +429,7 @@ function createClients() {
|
|
|
503
429
|
for (const chain of chains) {
|
|
504
430
|
clients[chain.id] = createPublicClient({
|
|
505
431
|
chain,
|
|
506
|
-
transport: http(rpcOverrides[chain.id])
|
|
432
|
+
transport: http(rpcOverrides[chain.id], { batch: true })
|
|
507
433
|
});
|
|
508
434
|
}
|
|
509
435
|
return clients;
|
|
@@ -533,7 +459,7 @@ async function detectChain(hash, clients) {
|
|
|
533
459
|
return found.value;
|
|
534
460
|
}
|
|
535
461
|
|
|
536
|
-
// src/relay-client.ts
|
|
462
|
+
// src/bridges/relay-client.ts
|
|
537
463
|
var RELAY_API = "https://api.relay.link";
|
|
538
464
|
async function getRelayRequests(params) {
|
|
539
465
|
const url = new URL(`${RELAY_API}/requests/v2`);
|
|
@@ -557,7 +483,7 @@ async function fetchRelayRequest(hash) {
|
|
|
557
483
|
return request;
|
|
558
484
|
}
|
|
559
485
|
|
|
560
|
-
// src/relay-bridge.ts
|
|
486
|
+
// src/bridges/relay-bridge.ts
|
|
561
487
|
async function calculateOutputAmountGross(inputAmount, inputToken, inputChainId, outputToken, outputChainId, clients) {
|
|
562
488
|
const [{ decimals: inputDecimals }, { decimals: outputDecimals }] = await Promise.all([
|
|
563
489
|
resolveToken(inputToken, inputChainId, getClient(clients, inputChainId)),
|
|
@@ -572,23 +498,18 @@ async function calculateOutputAmountGross(inputAmount, inputToken, inputChainId,
|
|
|
572
498
|
if (decimalDiff > 0) return inputAmount / 10n ** BigInt(decimalDiff);
|
|
573
499
|
return inputAmount * 10n ** BigInt(-decimalDiff);
|
|
574
500
|
}
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
return decoded.args.sender;
|
|
586
|
-
}
|
|
587
|
-
} catch {
|
|
588
|
-
}
|
|
501
|
+
function extractSenderFromSource(sourceReceipt) {
|
|
502
|
+
const userOps = parseEventLogs2({
|
|
503
|
+
abi: entryPoint08Abi,
|
|
504
|
+
logs: sourceReceipt.logs.filter(
|
|
505
|
+
(l) => isAddressEqual2(l.address, entryPoint08Address)
|
|
506
|
+
),
|
|
507
|
+
eventName: "UserOperationEvent"
|
|
508
|
+
});
|
|
509
|
+
if (userOps[0]) {
|
|
510
|
+
return userOps[0].args.sender;
|
|
589
511
|
}
|
|
590
|
-
|
|
591
|
-
return sourceTx.from;
|
|
512
|
+
return sourceReceipt.from;
|
|
592
513
|
}
|
|
593
514
|
async function resolveBridgeTokens(sourceReceipt, destReceipt, yodlEvent, sender, inputAmountGross, inputChainId, outputChainId, clients) {
|
|
594
515
|
const sourceTransfers = extractTokenTransfers(sourceReceipt.logs);
|
|
@@ -639,7 +560,7 @@ function parseRelayResponse(request) {
|
|
|
639
560
|
inputAmountGross: BigInt(data?.metadata?.currencyIn?.amount ?? 0)
|
|
640
561
|
};
|
|
641
562
|
}
|
|
642
|
-
async function decodeRelayBridgePayment(hash, clients) {
|
|
563
|
+
async function decodeRelayBridgePayment(hash, clients, options = {}) {
|
|
643
564
|
const request = await fetchRelayRequest(hash);
|
|
644
565
|
const {
|
|
645
566
|
sourceChainId,
|
|
@@ -654,9 +575,12 @@ async function decodeRelayBridgePayment(hash, clients) {
|
|
|
654
575
|
throw new NoBridgeFoundError();
|
|
655
576
|
}
|
|
656
577
|
const { address: routerAddress } = getRouter(destinationChainId);
|
|
578
|
+
const hashLower = hash.toLowerCase();
|
|
579
|
+
const cachedDestReceipt = options.fillReceipt && destinationTxHash.toLowerCase() === hashLower ? options.fillReceipt : void 0;
|
|
580
|
+
const cachedSourceReceipt = options.sourceReceipt && sourceTxHash.toLowerCase() === hashLower ? options.sourceReceipt : void 0;
|
|
657
581
|
const [destReceipt, sourceReceipt] = await Promise.all([
|
|
658
|
-
destProvider.getTransactionReceipt({ hash: destinationTxHash }),
|
|
659
|
-
sourceProvider.getTransactionReceipt({ hash: sourceTxHash })
|
|
582
|
+
cachedDestReceipt ?? destProvider.getTransactionReceipt({ hash: destinationTxHash }),
|
|
583
|
+
cachedSourceReceipt ?? sourceProvider.getTransactionReceipt({ hash: sourceTxHash })
|
|
660
584
|
]);
|
|
661
585
|
const yodlEvent = decodeYodlFromLogs(destReceipt.logs, routerAddress);
|
|
662
586
|
if (!yodlEvent) {
|
|
@@ -664,10 +588,10 @@ async function decodeRelayBridgePayment(hash, clients) {
|
|
|
664
588
|
"No Yodl event found in destination transaction"
|
|
665
589
|
);
|
|
666
590
|
}
|
|
667
|
-
const
|
|
591
|
+
const sender = extractSenderFromSource(sourceReceipt);
|
|
592
|
+
const [destBlock, destTx] = await Promise.all([
|
|
668
593
|
destProvider.getBlock({ blockNumber: destReceipt.blockNumber }),
|
|
669
|
-
destProvider.getTransaction({ hash: destinationTxHash })
|
|
670
|
-
extractSenderFromSource(sourceReceipt, sourceProvider, sourceTxHash)
|
|
594
|
+
destProvider.getTransaction({ hash: destinationTxHash })
|
|
671
595
|
]);
|
|
672
596
|
const tokens = await resolveBridgeTokens(
|
|
673
597
|
sourceReceipt,
|
|
@@ -696,30 +620,27 @@ async function decodeRelayBridgePayment(hash, clients) {
|
|
|
696
620
|
return { type: "bridge", ...payment, ...bridge };
|
|
697
621
|
}
|
|
698
622
|
|
|
699
|
-
// src/across-bridge.ts
|
|
700
|
-
async function resolveAcrossStatus(hash, fillReceipt) {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
623
|
+
// src/bridges/across-bridge.ts
|
|
624
|
+
async function resolveAcrossStatus(hash, fillReceipt, cachedFillLog) {
|
|
625
|
+
const fillLog = cachedFillLog !== void 0 ? cachedFillLog : fillReceipt ? parseFillLogs(fillReceipt.logs) : null;
|
|
626
|
+
if (fillLog) {
|
|
627
|
+
const status = await fetchAcrossDepositByDepositId(
|
|
628
|
+
Number(fillLog.originChainId),
|
|
629
|
+
String(fillLog.depositId)
|
|
630
|
+
);
|
|
631
|
+
if (status.fillTxnRef?.toLowerCase() === hash.toLowerCase()) {
|
|
632
|
+
return status;
|
|
706
633
|
}
|
|
634
|
+
return await fetchAcrossDepositByTx(hash);
|
|
707
635
|
}
|
|
708
|
-
|
|
709
|
-
if (!fillLog) {
|
|
710
|
-
throw new NoBridgeFoundError();
|
|
711
|
-
}
|
|
712
|
-
const status = await fetchAcrossDepositByDepositId(
|
|
713
|
-
Number(fillLog.originChainId),
|
|
714
|
-
String(fillLog.depositId)
|
|
715
|
-
);
|
|
716
|
-
if (status.fillTxnRef !== hash) {
|
|
717
|
-
throw new NoBridgeFoundError();
|
|
718
|
-
}
|
|
719
|
-
return status;
|
|
636
|
+
return await fetchAcrossDepositByTx(hash);
|
|
720
637
|
}
|
|
721
|
-
async function decodeAcrossBridgePayment(hash, clients,
|
|
722
|
-
const status = await resolveAcrossStatus(
|
|
638
|
+
async function decodeAcrossBridgePayment(hash, clients, options = {}) {
|
|
639
|
+
const status = await resolveAcrossStatus(
|
|
640
|
+
hash,
|
|
641
|
+
options.fillReceipt,
|
|
642
|
+
options.parsedFillLog
|
|
643
|
+
);
|
|
723
644
|
if (status.status !== "filled" || !status.fillTxnRef) {
|
|
724
645
|
throw new NoBridgeFoundError();
|
|
725
646
|
}
|
|
@@ -736,18 +657,21 @@ async function decodeAcrossBridgePayment(hash, clients, fillReceipt) {
|
|
|
736
657
|
throw new NoBridgeFoundError();
|
|
737
658
|
}
|
|
738
659
|
const { address: routerAddress } = getRouter2(destinationChainId);
|
|
660
|
+
const hashLower = hash.toLowerCase();
|
|
661
|
+
const cachedDestReceipt = options.fillReceipt && destinationTxHash.toLowerCase() === hashLower ? options.fillReceipt : void 0;
|
|
662
|
+
const cachedSourceReceipt = options.sourceReceipt && sourceTxHash.toLowerCase() === hashLower ? options.sourceReceipt : void 0;
|
|
739
663
|
const [sourceReceipt, destReceipt] = await Promise.all([
|
|
740
|
-
sourceProvider.getTransactionReceipt({ hash: sourceTxHash }),
|
|
741
|
-
destProvider.getTransactionReceipt({ hash: destinationTxHash })
|
|
664
|
+
cachedSourceReceipt ?? sourceProvider.getTransactionReceipt({ hash: sourceTxHash }),
|
|
665
|
+
cachedDestReceipt ?? destProvider.getTransactionReceipt({ hash: destinationTxHash })
|
|
742
666
|
]);
|
|
743
667
|
const yodlEvent = decodeYodlFromLogs(destReceipt.logs, routerAddress);
|
|
744
668
|
if (!yodlEvent) {
|
|
745
669
|
throw new NoBridgeFoundError();
|
|
746
670
|
}
|
|
747
|
-
const
|
|
671
|
+
const sender = extractSenderFromSource(sourceReceipt);
|
|
672
|
+
const [destBlock, destTx] = await Promise.all([
|
|
748
673
|
destProvider.getBlock({ blockNumber: destReceipt.blockNumber }),
|
|
749
|
-
destProvider.getTransaction({ hash: destinationTxHash })
|
|
750
|
-
extractSenderFromSource(sourceReceipt, sourceProvider, sourceTxHash)
|
|
674
|
+
destProvider.getTransaction({ hash: destinationTxHash })
|
|
751
675
|
]);
|
|
752
676
|
const depositLog = parseDepositLogs(sourceReceipt.logs);
|
|
753
677
|
const depositData = depositLog && depositLog.depositId === BigInt(status.depositId) ? {
|
|
@@ -805,12 +729,25 @@ async function decodeAcrossBridgePayment(hash, clients, fillReceipt) {
|
|
|
805
729
|
return { type: "bridge", ...payment, ...bridge };
|
|
806
730
|
}
|
|
807
731
|
|
|
808
|
-
// src/bridge-payment.ts
|
|
732
|
+
// src/bridges/bridge-payment.ts
|
|
809
733
|
async function decodeBridgePayment(hash, clients, options = {}) {
|
|
810
734
|
const includeAcross = options.includeAcross ?? true;
|
|
735
|
+
const parsedFillLog = options.fillReceipt ? parseFillLogs2(options.fillReceipt.logs) : null;
|
|
736
|
+
const parsedDepositLog = options.sourceReceipt ? parseDepositLogs2(options.sourceReceipt.logs) : null;
|
|
737
|
+
const hasAcrossEvents = !!(parsedFillLog || parsedDepositLog);
|
|
738
|
+
if (includeAcross && hasAcrossEvents) {
|
|
739
|
+
return await decodeAcrossBridgePayment(hash, clients, {
|
|
740
|
+
fillReceipt: options.fillReceipt,
|
|
741
|
+
sourceReceipt: options.sourceReceipt,
|
|
742
|
+
parsedFillLog
|
|
743
|
+
});
|
|
744
|
+
}
|
|
811
745
|
let relayError;
|
|
812
746
|
try {
|
|
813
|
-
return await decodeRelayBridgePayment(hash, clients
|
|
747
|
+
return await decodeRelayBridgePayment(hash, clients, {
|
|
748
|
+
fillReceipt: options.fillReceipt,
|
|
749
|
+
sourceReceipt: options.sourceReceipt
|
|
750
|
+
});
|
|
814
751
|
} catch (error) {
|
|
815
752
|
relayError = error;
|
|
816
753
|
if (!includeAcross) {
|
|
@@ -818,7 +755,10 @@ async function decodeBridgePayment(hash, clients, options = {}) {
|
|
|
818
755
|
}
|
|
819
756
|
}
|
|
820
757
|
try {
|
|
821
|
-
return await decodeAcrossBridgePayment(hash, clients,
|
|
758
|
+
return await decodeAcrossBridgePayment(hash, clients, {
|
|
759
|
+
fillReceipt: options.fillReceipt,
|
|
760
|
+
sourceReceipt: options.sourceReceipt
|
|
761
|
+
});
|
|
822
762
|
} catch (acrossError) {
|
|
823
763
|
if (!(relayError instanceof NoBridgeFoundError) && !(acrossError instanceof NoBridgeFoundError)) {
|
|
824
764
|
throw new Error("Both Relay and Across bridge decoders failed", {
|
|
@@ -835,8 +775,9 @@ async function decodeBridgePayment(hash, clients, options = {}) {
|
|
|
835
775
|
}
|
|
836
776
|
}
|
|
837
777
|
|
|
838
|
-
// src/payment-decoder.ts
|
|
778
|
+
// src/core/payment-decoder.ts
|
|
839
779
|
import { getRouter as getRouter3 } from "@yodlpay/tokenlists";
|
|
780
|
+
import { isAddressEqual as isAddressEqual3 } from "viem";
|
|
840
781
|
async function tryDecodeBridge(hash, clients, options = {}) {
|
|
841
782
|
try {
|
|
842
783
|
return await decodeBridgePayment(hash, clients, options);
|
|
@@ -851,24 +792,42 @@ async function decodePayment(hash, chainId2, clients, cachedReceipt) {
|
|
|
851
792
|
const provider = getClient(clients, chainId2);
|
|
852
793
|
const receipt = cachedReceipt ?? await provider.getTransactionReceipt({ hash });
|
|
853
794
|
const { address: routerAddress } = getRouter3(chainId2);
|
|
854
|
-
const [block, tx] = await Promise.all([
|
|
855
|
-
provider.getBlock({ blockNumber: receipt.blockNumber }),
|
|
856
|
-
provider.getTransaction({ hash })
|
|
857
|
-
]);
|
|
858
795
|
const yodlEvent = decodeYodlFromLogs(receipt.logs, routerAddress);
|
|
859
796
|
const swapLogs = yodlEvent ? receipt.logs.filter((l) => (l.logIndex ?? 0) < yodlEvent.logIndex) : receipt.logs;
|
|
860
797
|
const swapEvent = decodeSwapFromLogs(swapLogs);
|
|
861
798
|
if (yodlEvent) {
|
|
862
|
-
const blockTimestamp = toBlockTimestamp(block);
|
|
863
|
-
const webhooks = extractEmbeddedParams(tx.input);
|
|
864
|
-
const paymentEvent = buildPaymentEvent(yodlEvent, webhooks, blockTimestamp);
|
|
865
799
|
if (swapEvent) {
|
|
866
|
-
|
|
800
|
+
const [block2, tx2] = await Promise.all([
|
|
801
|
+
provider.getBlock({ blockNumber: receipt.blockNumber }),
|
|
802
|
+
provider.getTransaction({ hash })
|
|
803
|
+
]);
|
|
804
|
+
const paymentEvent2 = buildPaymentEvent(
|
|
805
|
+
yodlEvent,
|
|
806
|
+
extractEmbeddedParams(tx2.input),
|
|
807
|
+
toBlockTimestamp(block2)
|
|
808
|
+
);
|
|
809
|
+
return { type: "swap", ...paymentEvent2, ...swapEvent };
|
|
867
810
|
}
|
|
868
|
-
const
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
811
|
+
const effectiveSender = extractSenderFromSource(receipt);
|
|
812
|
+
const isSameChainPayment = isAddressEqual3(
|
|
813
|
+
effectiveSender,
|
|
814
|
+
yodlEvent.sender
|
|
815
|
+
);
|
|
816
|
+
if (!isSameChainPayment) {
|
|
817
|
+
const bridgeResult2 = await tryDecodeBridge(hash, clients, {
|
|
818
|
+
fillReceipt: receipt
|
|
819
|
+
});
|
|
820
|
+
if (bridgeResult2) return bridgeResult2;
|
|
821
|
+
}
|
|
822
|
+
const [block, tx] = await Promise.all([
|
|
823
|
+
provider.getBlock({ blockNumber: receipt.blockNumber }),
|
|
824
|
+
provider.getTransaction({ hash })
|
|
825
|
+
]);
|
|
826
|
+
const paymentEvent = buildPaymentEvent(
|
|
827
|
+
yodlEvent,
|
|
828
|
+
extractEmbeddedParams(tx.input),
|
|
829
|
+
toBlockTimestamp(block)
|
|
830
|
+
);
|
|
872
831
|
const inferredSwap = inferSwapFromTransfers(
|
|
873
832
|
swapLogs,
|
|
874
833
|
yodlEvent.sender,
|
|
@@ -879,18 +838,26 @@ async function decodePayment(hash, chainId2, clients, cachedReceipt) {
|
|
|
879
838
|
}
|
|
880
839
|
return { type: "direct", ...paymentEvent };
|
|
881
840
|
}
|
|
882
|
-
const bridgeResult = await tryDecodeBridge(hash, clients
|
|
841
|
+
const bridgeResult = await tryDecodeBridge(hash, clients, {
|
|
842
|
+
sourceReceipt: receipt
|
|
843
|
+
});
|
|
883
844
|
if (bridgeResult) return bridgeResult;
|
|
884
845
|
throw new NoYodlEventError();
|
|
885
846
|
}
|
|
886
847
|
|
|
887
|
-
// src/yodl-payment.ts
|
|
848
|
+
// src/core/yodl-payment.ts
|
|
888
849
|
import {
|
|
889
850
|
formatUnits,
|
|
851
|
+
isAddressEqual as isAddressEqual4,
|
|
890
852
|
zeroAddress
|
|
891
853
|
} from "viem";
|
|
892
854
|
async function buildTokenInfo(params, clients) {
|
|
893
|
-
const
|
|
855
|
+
const sameToken = isAddressEqual4(params.tokenIn, params.tokenOut) && params.inChainId === params.outChainId;
|
|
856
|
+
const [inToken, outToken] = sameToken ? await resolveToken(
|
|
857
|
+
params.tokenIn,
|
|
858
|
+
params.inChainId,
|
|
859
|
+
getClient(clients, params.inChainId)
|
|
860
|
+
).then((t) => [t, t]) : await Promise.all([
|
|
894
861
|
resolveToken(
|
|
895
862
|
params.tokenIn,
|
|
896
863
|
params.inChainId,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yodlpay/payment-decoder",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.6",
|
|
4
4
|
"description": "Decode Yodl payment hashes into structured payment data",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"yodl",
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"prepublishOnly": "bun run build"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@biomejs/biome": "^2.4.
|
|
42
|
-
"@relayprotocol/relay-sdk": "^5.2.
|
|
41
|
+
"@biomejs/biome": "^2.4.8",
|
|
42
|
+
"@relayprotocol/relay-sdk": "^5.2.1",
|
|
43
43
|
"@semantic-release/changelog": "^6.0.3",
|
|
44
44
|
"@semantic-release/git": "^10.0.1",
|
|
45
45
|
"@types/bun": "latest",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@across-protocol/app-sdk": "^0.5.0",
|
|
52
|
-
"@yodlpay/tokenlists": "^1.1.
|
|
52
|
+
"@yodlpay/tokenlists": "^1.1.13"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"typescript": "^5",
|