@yodlpay/payment-decoder 0.1.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/LICENSE.md ADDED
@@ -0,0 +1,32 @@
1
+ # Business Source License 1.1
2
+
3
+ **Parameters**
4
+
5
+ * **Licensor:** Yodl Verein, Switzerland 🇨🇭
6
+ * **Software:** @yodlpay/payment-decoder
7
+ * **Change Date:** The fourth anniversary of the first publicly available distribution of a specific version of the Licensed Work.
8
+ * **Change License:** MIT
9
+ * **Additional Use Grant:** Use of the Software for any Production Use, or any use not specifically granted in Section 1, is strictly prohibited without prior written approval from Yodl.
10
+
11
+ ---
12
+
13
+ ## 1. License Grant and Conditions
14
+
15
+ The Licensor hereby grants you the right to copy, modify, create derivative works, redistribute, and make non-production use of the Software.
16
+
17
+ **Production use** is allowed only as permitted by the **Additional Use Grant** above. Any other production use requires a separate license from the Licensor.
18
+
19
+ All copies of the Software, or derivative works thereof, must include this License file and the following notice in all source files:
20
+ > "This source code is licensed under the Business Source License 1.1. See LICENSE.md for details."
21
+
22
+ ## 2. Change of License
23
+
24
+ On the **Change Date**, or upon the occurrence of a Change Event (if any) specified by the Licensor, the Software shall automatically become licensed under the **Change License**. From that point forward, your use of the Software shall be governed by the terms of the Change License, and this License shall terminate.
25
+
26
+ ## 3. Intellectual Property
27
+
28
+ The Licensor retains all intellectual property rights, including copyrights, in and to the Software. You may not remove or alter any trademark, logo, copyright, or other proprietary notices in or on the Software.
29
+
30
+ ## 4. Disclaimer of Warranty
31
+
32
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE LICENSOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # @yodlpay/payment-decoder
2
+
3
+ Decode Yodl payment transaction hashes into structured payment data. Supports direct payments, swaps, and cross-chain bridges.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @yodlpay/payment-decoder
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```ts
14
+ import { decodeYodlPayment, type ChainClients } from "@yodlpay/payment-decoder";
15
+ import { createPublicClient, http } from "viem";
16
+ import { arbitrum, base, bsc } from "viem/chains";
17
+
18
+ // Create a map of chain clients with your RPC URLs
19
+ const clients = {
20
+ [arbitrum.id]: createPublicClient({ chain: arbitrum, transport: http("https://your-arbitrum-rpc.com") }),
21
+ [base.id]: createPublicClient({ chain: base, transport: http("https://your-base-rpc.com") }),
22
+ [bsc.id]: createPublicClient({ chain: bsc, transport: http("https://your-bsc-rpc.com") }),
23
+ } as ChainClients;
24
+
25
+ const payment = await decodeYodlPayment("0x1234...abcd", base.id, clients);
26
+
27
+ console.log(payment.senderAddress, "→", payment.receiverAddress);
28
+ console.log("Net:", payment.tokenOutAmountNet, "Gross:", payment.tokenOutAmountGross);
29
+ ```
30
+
31
+ ## API
32
+
33
+ ### `decodeYodlPayment(hash, chainId, clients)`
34
+
35
+ Decode a Yodl payment transaction into a structured `YodlPayment` object.
36
+
37
+ - `hash` - Transaction hash to decode
38
+ - `chainId` - Chain ID where the transaction was executed
39
+ - `clients` - Map of chainId → PublicClient (must include all chains needed for bridges)
40
+
41
+ ### `ChainClients`
42
+
43
+ Type alias for the clients map: `Record<number, PublicClient>`
44
+
45
+ ## CLI
46
+
47
+ Decode a transaction directly from the command line. Outputs JSON to stdout.
48
+
49
+ ```bash
50
+ bun run decode <txHash> <chainId>
51
+ ```
52
+
53
+ **Arguments:**
54
+
55
+ - `txHash` - The transaction hash (64 hex characters with `0x` prefix)
56
+ - `chainId` - The chain ID where the transaction occurred (e.g., `8453` for Base, `42161` for Arbitrum)
57
+
58
+ **Example:**
59
+
60
+ ```bash
61
+ bun run decode 0xe7ecad85dcfb6b4e25c833fa3617a45cf34df505cb698e04ad7d75a39032158f 42161
62
+ ```
63
+
64
+ The CLI uses public RPC endpoints. For production use, configure your own RPC URLs via the library API.
65
+
66
+ ## Understanding Amounts
67
+
68
+ When a payment involves a swap or bridge, there are two output amounts:
69
+
70
+ - **`tokenOutAmountGross`** - Total output from the swap/bridge (before fees and rebates)
71
+ - **`tokenOutAmountNet`** - What the receiver actually received
72
+
73
+ The difference is the [Relay fee](https://docs.relay.link/how-it-works/fees), which covers execution costs, swap costs, and Relay's service fee:
74
+
75
+ ```
76
+ Swap output: 172,403 USDT (tokenOutAmountGross)
77
+ ├── Receiver gets: 169,492 USDT (tokenOutAmountNet)
78
+ └── Relay fee: 2,911 USDT
79
+ ```
80
+
81
+ For direct payments (no swap), both values are equal.
82
+
83
+ **Always use `tokenOutAmountNet`** when you need to know how much the receiver got paid.
84
+
85
+ ## Errors
86
+
87
+ - `NoYodlEventError` - No Yodl payment event found in the transaction
88
+ - `NoBridgeFoundError` - No bridge transaction found for the given hash
89
+
90
+ ## License
91
+
92
+ See license in LICENSE.md
@@ -0,0 +1,102 @@
1
+ import { PublicClient, Address, Hex, Log } from 'viem';
2
+
3
+ type ChainClients = Record<number, PublicClient>;
4
+ declare function createClients(): ChainClients;
5
+
6
+ type ServiceProvider = "relay";
7
+ interface Webhook {
8
+ webhookAddress: Address;
9
+ payload: readonly Hex[];
10
+ memo: string;
11
+ }
12
+ interface PaymentEvent {
13
+ sender: Address;
14
+ receiver: Address;
15
+ token: Address;
16
+ amount: bigint;
17
+ memo: string;
18
+ webhooks: readonly Webhook[];
19
+ blockTimestamp: Date;
20
+ }
21
+ interface SwapInfo {
22
+ tokenIn: Address;
23
+ tokenOut: Address;
24
+ tokenInAmount: bigint;
25
+ tokenOutAmount: bigint;
26
+ service: ServiceProvider;
27
+ }
28
+ interface BridgeInfo extends SwapInfo {
29
+ originChainId: number;
30
+ originTxHash: Hex;
31
+ destinationChainId: number;
32
+ destinationTxHash: Hex;
33
+ tokenOutAmountGross: bigint;
34
+ }
35
+ type PaymentInfo = (PaymentEvent & {
36
+ type: "direct";
37
+ }) | (PaymentEvent & SwapInfo & {
38
+ type: "swap";
39
+ }) | (PaymentEvent & BridgeInfo & {
40
+ type: "bridge";
41
+ });
42
+ interface YodlPayment {
43
+ senderAddress: Address;
44
+ receiverAddress: Address;
45
+ memo: string;
46
+ processorMemo: string;
47
+ processorAddress: Address;
48
+ data: Record<string, unknown>;
49
+ tokenInAddress: Address;
50
+ tokenInAmount: string;
51
+ tokenOutAddress: Address;
52
+ originChainId: number;
53
+ originTxHash: Hex;
54
+ destinationChainId: number;
55
+ destinationTxHash: Hex;
56
+ solver: string | null;
57
+ tokenOutAmountGross: string;
58
+ tokenOutAmountNet: string;
59
+ blockTimestamp: Date;
60
+ }
61
+
62
+ /**
63
+ * Decoded Yodl event data from onchain logs.
64
+ * Does not include blockTimestamp or webhooks — callers provide those.
65
+ */
66
+ interface DecodedYodlEvent {
67
+ sender: Address;
68
+ receiver: Address;
69
+ token: Address;
70
+ amount: bigint;
71
+ memo: string;
72
+ }
73
+ /**
74
+ * Decode Yodl payment event from transaction logs.
75
+ * Only trusts logs from the legitimate Yodl router for the given chain.
76
+ */
77
+ declare function decodeYodlFromLogs(logs: readonly Log[], routerAddress: Address): DecodedYodlEvent | undefined;
78
+
79
+ declare class NoBridgeFoundError extends Error {
80
+ constructor(message?: string);
81
+ }
82
+ declare class NoYodlEventError extends Error {
83
+ constructor(message?: string);
84
+ }
85
+
86
+ declare function decodePayment(hash: Hex, chainId: number, clients: ChainClients): Promise<PaymentInfo>;
87
+
88
+ /**
89
+ * Decode a bridge transaction given any hash (source or destination).
90
+ * Fetches bridge info from Relay, then decodes the Yodl event from the destination chain.
91
+ * Extracts the original sender from the source chain's UserOperationEvent.
92
+ *
93
+ * SECURITY: Token data is extracted from onchain logs, not trusted from Relay.
94
+ * Relay is only used for bridge discovery (hashes + chain IDs).
95
+ */
96
+ declare function decodeBridgePayment(hash: Hex, clients: ChainClients): Promise<Extract<PaymentInfo, {
97
+ type: "bridge";
98
+ }>>;
99
+
100
+ declare function decodeYodlPayment(txHash: Hex, chainId: number, clients: ChainClients): Promise<YodlPayment>;
101
+
102
+ export { type BridgeInfo, type ChainClients, type DecodedYodlEvent, NoBridgeFoundError, NoYodlEventError, type PaymentEvent, type PaymentInfo, type ServiceProvider, type SwapInfo, type Webhook, type YodlPayment, createClients, decodeBridgePayment, decodePayment, decodeYodlFromLogs, decodeYodlPayment };
package/dist/index.js ADDED
@@ -0,0 +1,584 @@
1
+ // src/clients.ts
2
+ import { chains } from "@yodlpay/tokenlists";
3
+ import { createPublicClient, http } from "viem";
4
+ function createClients() {
5
+ const clients = {};
6
+ for (const chain of chains) {
7
+ clients[chain.id] = createPublicClient({
8
+ chain,
9
+ transport: http()
10
+ });
11
+ }
12
+ return clients;
13
+ }
14
+ function getClient(clients, chainId) {
15
+ const client = clients[chainId];
16
+ if (!client) throw new Error(`No client configured for chain ${chainId}`);
17
+ return client;
18
+ }
19
+
20
+ // src/decode-utils.ts
21
+ import {
22
+ decodeEventLog,
23
+ erc20Abi,
24
+ isAddressEqual
25
+ } from "viem";
26
+
27
+ // src/abi.ts
28
+ import { getRouterAbi } from "@yodlpay/tokenlists";
29
+ var yodlAbi = getRouterAbi("0.8");
30
+ var relaySwapAbi = [
31
+ {
32
+ type: "event",
33
+ name: "Swap",
34
+ inputs: [
35
+ { name: "sender", type: "address", indexed: true },
36
+ { name: "recipient", type: "address", indexed: true },
37
+ { name: "inputToken", type: "address", indexed: false },
38
+ { name: "outputToken", type: "address", indexed: false },
39
+ { name: "inputAmount", type: "uint256", indexed: false },
40
+ { name: "outputAmount", type: "uint256", indexed: false }
41
+ ]
42
+ }
43
+ ];
44
+ var entryPointAbi = [
45
+ {
46
+ type: "event",
47
+ name: "UserOperationEvent",
48
+ inputs: [
49
+ { name: "userOpHash", type: "bytes32", indexed: true },
50
+ { name: "sender", type: "address", indexed: true },
51
+ { name: "paymaster", type: "address", indexed: true },
52
+ { name: "nonce", type: "uint256", indexed: false },
53
+ { name: "success", type: "bool", indexed: false },
54
+ { name: "actualGasCost", type: "uint256", indexed: false },
55
+ { name: "actualGasUsed", type: "uint256", indexed: false }
56
+ ]
57
+ }
58
+ ];
59
+
60
+ // src/errors.ts
61
+ import {
62
+ AbiDecodingDataSizeTooSmallError,
63
+ AbiEventSignatureEmptyTopicsError,
64
+ AbiEventSignatureNotFoundError,
65
+ DecodeLogTopicsMismatch
66
+ } from "viem";
67
+ var ExpectedDecodeError = class extends Error {
68
+ constructor(message = "Expected decode error") {
69
+ super(message);
70
+ this.name = "ExpectedDecodeError";
71
+ }
72
+ };
73
+ var NoBridgeFoundError = class extends Error {
74
+ constructor(message = "No bridge transaction found") {
75
+ super(message);
76
+ this.name = "NoBridgeFoundError";
77
+ }
78
+ };
79
+ var NoYodlEventError = class extends Error {
80
+ constructor(message = "No Yodl event found in logs") {
81
+ super(message);
82
+ this.name = "NoYodlEventError";
83
+ }
84
+ };
85
+ function isExpectedDecodeError(error) {
86
+ return error instanceof AbiEventSignatureNotFoundError || error instanceof AbiEventSignatureEmptyTopicsError || error instanceof AbiDecodingDataSizeTooSmallError || error instanceof DecodeLogTopicsMismatch;
87
+ }
88
+
89
+ // src/utils.ts
90
+ import { hexToString } from "viem";
91
+ function decodeMemo(memo) {
92
+ if (!memo || memo === "0x") return "";
93
+ try {
94
+ return hexToString(memo, { size: 32 }).replace(/\0/g, "");
95
+ } catch {
96
+ return "";
97
+ }
98
+ }
99
+
100
+ // src/decode-utils.ts
101
+ function* matchingEvents(logs, options) {
102
+ const { abi, eventName, address, context } = options;
103
+ for (const log of logs) {
104
+ if (address && !isAddressEqual(log.address, address)) {
105
+ continue;
106
+ }
107
+ try {
108
+ const decoded = decodeEventLog({
109
+ abi,
110
+ data: log.data,
111
+ topics: log.topics
112
+ });
113
+ if (decoded.eventName === eventName) {
114
+ yield { decoded, log };
115
+ }
116
+ } catch (error) {
117
+ if (!isExpectedDecodeError(error)) {
118
+ const contextStr = context ? ` (${context})` : "";
119
+ console.warn(
120
+ `[payment-decoder] Unexpected error decoding ${eventName}${contextStr}:`,
121
+ error
122
+ );
123
+ }
124
+ }
125
+ }
126
+ }
127
+ function findEventInLogs(logs, options, transform) {
128
+ for (const { decoded, log } of matchingEvents(logs, options)) {
129
+ return transform(decoded, log);
130
+ }
131
+ return void 0;
132
+ }
133
+ function collectEventsFromLogs(logs, options, transform) {
134
+ const results = [];
135
+ for (const { decoded, log } of matchingEvents(logs, options)) {
136
+ results.push(transform(decoded, log));
137
+ }
138
+ return results;
139
+ }
140
+ function decodeYodlFromLogs(logs, routerAddress) {
141
+ return findEventInLogs(
142
+ logs,
143
+ {
144
+ abi: yodlAbi,
145
+ eventName: "Yodl",
146
+ address: routerAddress,
147
+ context: "Yodl event"
148
+ },
149
+ (decoded) => {
150
+ const args = decoded.args;
151
+ return {
152
+ sender: args.sender,
153
+ receiver: args.receiver,
154
+ token: args.token,
155
+ amount: args.amount,
156
+ memo: decodeMemo(args.memo)
157
+ };
158
+ }
159
+ );
160
+ }
161
+ function decodeSwapFromLogs(logs) {
162
+ return findEventInLogs(
163
+ logs,
164
+ { abi: relaySwapAbi, eventName: "Swap", context: "Relay Swap" },
165
+ (decoded) => {
166
+ const args = decoded.args;
167
+ return {
168
+ tokenIn: args.inputToken,
169
+ tokenOut: args.outputToken,
170
+ tokenInAmount: args.inputAmount,
171
+ tokenOutAmount: args.outputAmount,
172
+ service: "relay"
173
+ };
174
+ }
175
+ );
176
+ }
177
+ function extractTokenTransfers(logs) {
178
+ return collectEventsFromLogs(
179
+ logs,
180
+ { abi: erc20Abi, eventName: "Transfer", context: "ERC20 Transfer" },
181
+ (decoded, log) => {
182
+ const args = decoded.args;
183
+ return {
184
+ token: log.address,
185
+ from: args.from,
186
+ to: args.to,
187
+ amount: args.value
188
+ };
189
+ }
190
+ );
191
+ }
192
+ function findInputTransfer(transfers, sender) {
193
+ const fromSender = transfers.filter((t) => isAddressEqual(t.from, sender));
194
+ if (fromSender.length === 0) return void 0;
195
+ const largest = fromSender.reduce(
196
+ (max, t) => t.amount > max.amount ? t : max
197
+ );
198
+ return { token: largest.token, amount: largest.amount };
199
+ }
200
+ function toBlockTimestamp(block) {
201
+ return new Date(Number(block.timestamp) * 1e3);
202
+ }
203
+ function buildPaymentEvent(yodlEvent, webhooks, blockTimestamp, senderOverride) {
204
+ return {
205
+ ...yodlEvent,
206
+ ...senderOverride !== void 0 && { sender: senderOverride },
207
+ webhooks,
208
+ blockTimestamp
209
+ };
210
+ }
211
+
212
+ // src/payment-decoder.ts
213
+ import { getRouter as getRouter2 } from "@yodlpay/tokenlists";
214
+
215
+ // src/embedded-params.ts
216
+ import { decodeFunctionData, toFunctionSelector } from "viem";
217
+
218
+ // src/validation.ts
219
+ import { chains as chains2 } from "@yodlpay/tokenlists";
220
+ import { isAddress, isHex } from "viem";
221
+ import { z } from "zod";
222
+ var validChainIds = chains2.map((c) => c.id);
223
+ var ArgsSchema = z.tuple([
224
+ z.string().regex(/^0x[a-fA-F0-9]{64}$/, "Invalid transaction hash").transform((val) => val),
225
+ z.coerce.number().int().refine((id) => validChainIds.includes(id), {
226
+ message: `Chain ID must be one of: ${validChainIds.join(", ")}`
227
+ })
228
+ ]);
229
+ var WebhooksSchema = z.array(
230
+ z.object({
231
+ webhookAddress: z.string().refine((val) => isAddress(val)),
232
+ payload: z.array(z.string().refine((val) => isHex(val)))
233
+ }).transform((webhook) => ({
234
+ ...webhook,
235
+ memo: webhook.payload[0] ? decodeMemo(webhook.payload[0]) : ""
236
+ }))
237
+ ).catch([]);
238
+
239
+ // src/embedded-params.ts
240
+ function getYodlSelector() {
241
+ const yodlFunction = yodlAbi.find(
242
+ (i) => i.type === "function" && i.name === "yodlWithToken"
243
+ );
244
+ if (!yodlFunction) throw new Error("yodlWithToken not found in ABI");
245
+ return toFunctionSelector(yodlFunction).slice(2);
246
+ }
247
+ function extractEmbeddedParams(data) {
248
+ if (!data) return [];
249
+ const yodlSelector = getYodlSelector();
250
+ const input = data.slice(2);
251
+ let pos = input.indexOf(yodlSelector);
252
+ while (pos >= 0 && pos < input.length - 8) {
253
+ try {
254
+ const decoded = decodeFunctionData({
255
+ abi: yodlAbi,
256
+ data: `0x${input.slice(pos)}`
257
+ });
258
+ const params = decoded.args?.[0];
259
+ if (params && typeof params === "object" && "webhooks" in params) {
260
+ return WebhooksSchema.parse(params.webhooks);
261
+ }
262
+ } catch {
263
+ }
264
+ pos = input.indexOf(yodlSelector, pos + 8);
265
+ }
266
+ return [];
267
+ }
268
+
269
+ // src/relay-bridge.ts
270
+ import { getRouter, getTokenByAddress } from "@yodlpay/tokenlists";
271
+ import {
272
+ decodeEventLog as decodeEventLog2,
273
+ isAddressEqual as isAddressEqual2
274
+ } from "viem";
275
+ import { entryPoint08Address } from "viem/account-abstraction";
276
+
277
+ // src/relay-client.ts
278
+ import { MAINNET_RELAY_API, TESTNET_RELAY_API } from "@relayprotocol/relay-sdk";
279
+ async function getRelayRequests(params, options) {
280
+ const baseUrl = options?.testnet ? TESTNET_RELAY_API : MAINNET_RELAY_API;
281
+ const url = new URL(`${baseUrl}/requests/v2`);
282
+ for (const [key, value] of Object.entries(params)) {
283
+ if (value !== void 0) {
284
+ url.searchParams.set(key, String(value));
285
+ }
286
+ }
287
+ const response = await fetch(url);
288
+ if (!response.ok) {
289
+ throw new Error(`Relay API error: ${response.status}`);
290
+ }
291
+ return response.json();
292
+ }
293
+ async function fetchRelayRequest(hash) {
294
+ const response = await getRelayRequests({ hash });
295
+ const request = response.requests?.[0];
296
+ if (!request) {
297
+ throw new NoBridgeFoundError();
298
+ }
299
+ return request;
300
+ }
301
+
302
+ // src/relay-bridge.ts
303
+ function calculateOutputAmountGross(inputAmount, inputToken, inputChainId, outputToken, outputChainId) {
304
+ const { decimals: inputDecimals } = getTokenByAddress(
305
+ inputToken,
306
+ inputChainId
307
+ );
308
+ const { decimals: outputDecimals } = getTokenByAddress(
309
+ outputToken,
310
+ outputChainId
311
+ );
312
+ const decimalDiff = inputDecimals - outputDecimals;
313
+ if (decimalDiff === 0) return inputAmount;
314
+ if (decimalDiff > 0) return inputAmount / 10n ** BigInt(decimalDiff);
315
+ return inputAmount * 10n ** BigInt(-decimalDiff);
316
+ }
317
+ async function extractSenderFromSource(sourceReceipt, sourceProvider, sourceHash) {
318
+ for (const log of sourceReceipt.logs) {
319
+ if (!isAddressEqual2(log.address, entryPoint08Address)) continue;
320
+ try {
321
+ const decoded = decodeEventLog2({
322
+ abi: entryPointAbi,
323
+ data: log.data,
324
+ topics: log.topics
325
+ });
326
+ if (decoded.eventName === "UserOperationEvent") {
327
+ return decoded.args.sender;
328
+ }
329
+ } catch {
330
+ }
331
+ }
332
+ const sourceTx = await sourceProvider.getTransaction({ hash: sourceHash });
333
+ return sourceTx.from;
334
+ }
335
+ function resolveBridgeTokens(sourceReceipt, destReceipt, yodlEvent, sender, inputAmountGross, inputChainId, outputChainId) {
336
+ const sourceTransfers = extractTokenTransfers(sourceReceipt.logs);
337
+ const inputTransfer = findInputTransfer(sourceTransfers, sender);
338
+ const tokenIn = inputTransfer?.token;
339
+ const tokenInAmount = inputTransfer?.amount;
340
+ if (!tokenIn || !tokenInAmount) {
341
+ throw new ExpectedDecodeError(
342
+ "No input token or amount found in source chain"
343
+ );
344
+ }
345
+ const tokenOut = yodlEvent.token;
346
+ const tokenOutAmount = yodlEvent.amount;
347
+ const swapEvent = decodeSwapFromLogs(destReceipt.logs);
348
+ let tokenOutAmountGross = 0n;
349
+ if (swapEvent !== void 0) {
350
+ tokenOutAmountGross = swapEvent.tokenOutAmount;
351
+ } else if (inputAmountGross > 0n && tokenIn && tokenOut) {
352
+ tokenOutAmountGross = calculateOutputAmountGross(
353
+ inputAmountGross,
354
+ tokenIn,
355
+ inputChainId,
356
+ tokenOut,
357
+ outputChainId
358
+ );
359
+ }
360
+ return {
361
+ tokenIn,
362
+ tokenInAmount,
363
+ tokenOut,
364
+ tokenOutAmount,
365
+ tokenOutAmountGross
366
+ };
367
+ }
368
+ function parseRelayResponse(request) {
369
+ const data = request.data;
370
+ const inTx = data?.inTxs?.[0];
371
+ const outTx = data?.outTxs?.[0];
372
+ if (!inTx?.hash || !inTx?.chainId || !outTx?.hash || !outTx?.chainId) {
373
+ throw new NoBridgeFoundError();
374
+ }
375
+ return {
376
+ originChainId: inTx.chainId,
377
+ originTxHash: inTx.hash,
378
+ destinationChainId: outTx.chainId,
379
+ destinationTxHash: outTx.hash,
380
+ inputAmountGross: BigInt(data?.metadata?.currencyIn?.amount ?? 0)
381
+ };
382
+ }
383
+ async function decodeBridgePayment(hash, clients) {
384
+ const request = await fetchRelayRequest(hash);
385
+ const {
386
+ originChainId,
387
+ originTxHash,
388
+ destinationChainId,
389
+ destinationTxHash,
390
+ inputAmountGross
391
+ } = parseRelayResponse(request);
392
+ const destProvider = getClient(clients, destinationChainId);
393
+ const sourceProvider = getClient(clients, originChainId);
394
+ const { address: routerAddress } = getRouter(destinationChainId);
395
+ const [destReceipt, sourceReceipt] = await Promise.all([
396
+ destProvider.getTransactionReceipt({ hash: destinationTxHash }),
397
+ sourceProvider.getTransactionReceipt({ hash: originTxHash })
398
+ ]);
399
+ const yodlEvent = decodeYodlFromLogs(destReceipt.logs, routerAddress);
400
+ if (!yodlEvent) {
401
+ throw new NoYodlEventError(
402
+ "No Yodl event found in destination transaction"
403
+ );
404
+ }
405
+ const [destBlock, destTx, sender] = await Promise.all([
406
+ destProvider.getBlock({ blockNumber: destReceipt.blockNumber }),
407
+ destProvider.getTransaction({ hash: destinationTxHash }),
408
+ extractSenderFromSource(sourceReceipt, sourceProvider, originTxHash)
409
+ ]);
410
+ const tokens = resolveBridgeTokens(
411
+ sourceReceipt,
412
+ destReceipt,
413
+ yodlEvent,
414
+ sender,
415
+ inputAmountGross,
416
+ originChainId,
417
+ destinationChainId
418
+ );
419
+ const bridge = {
420
+ originChainId,
421
+ originTxHash,
422
+ destinationChainId,
423
+ destinationTxHash,
424
+ ...tokens,
425
+ service: "relay"
426
+ };
427
+ const payment = buildPaymentEvent(
428
+ yodlEvent,
429
+ extractEmbeddedParams(destTx.input),
430
+ toBlockTimestamp(destBlock),
431
+ sender
432
+ );
433
+ return { type: "bridge", ...payment, ...bridge };
434
+ }
435
+
436
+ // src/payment-decoder.ts
437
+ async function tryDecodeBridge(hash, clients) {
438
+ try {
439
+ return await decodeBridgePayment(hash, clients);
440
+ } catch (error) {
441
+ if (!(error instanceof NoBridgeFoundError)) {
442
+ if (process.env.NODE_ENV === "development") {
443
+ console.warn("Unexpected error checking bridge info:", error);
444
+ }
445
+ }
446
+ return void 0;
447
+ }
448
+ }
449
+ async function decodePayment(hash, chainId, clients) {
450
+ const provider = getClient(clients, chainId);
451
+ const receipt = await provider.getTransactionReceipt({ hash });
452
+ const { address: routerAddress } = getRouter2(chainId);
453
+ const [block, tx] = await Promise.all([
454
+ provider.getBlock({ blockNumber: receipt.blockNumber }),
455
+ provider.getTransaction({ hash })
456
+ ]);
457
+ const yodlEvent = decodeYodlFromLogs(receipt.logs, routerAddress);
458
+ const swapEvent = decodeSwapFromLogs(receipt.logs);
459
+ if (yodlEvent) {
460
+ const blockTimestamp = toBlockTimestamp(block);
461
+ const webhooks = extractEmbeddedParams(tx.input);
462
+ const paymentEvent = buildPaymentEvent(yodlEvent, webhooks, blockTimestamp);
463
+ if (swapEvent) {
464
+ return { type: "swap", ...paymentEvent, ...swapEvent };
465
+ }
466
+ const bridgeResult2 = await tryDecodeBridge(hash, clients);
467
+ if (bridgeResult2) return bridgeResult2;
468
+ return { type: "direct", ...paymentEvent };
469
+ }
470
+ const bridgeResult = await tryDecodeBridge(hash, clients);
471
+ if (bridgeResult) return bridgeResult;
472
+ throw new NoYodlEventError();
473
+ }
474
+
475
+ // src/yodl-payment.ts
476
+ import { getTokenByAddress as getTokenByAddress2 } from "@yodlpay/tokenlists";
477
+ import { formatUnits, zeroAddress } from "viem";
478
+ function formatTokenAmounts(params) {
479
+ const { decimals: inDecimals } = getTokenByAddress2(
480
+ params.tokenIn,
481
+ params.inChainId
482
+ );
483
+ const { decimals: outDecimals } = getTokenByAddress2(
484
+ params.tokenOut,
485
+ params.outChainId
486
+ );
487
+ const tokenOutAmountGross = formatUnits(
488
+ params.tokenOutAmountGross,
489
+ outDecimals
490
+ );
491
+ const tokenOutAmountNet = formatUnits(params.tokenOutAmountNet, outDecimals);
492
+ return {
493
+ tokenInAddress: params.tokenIn,
494
+ tokenInAmount: formatUnits(params.tokenInAmount, inDecimals),
495
+ tokenOutAddress: params.tokenOut,
496
+ tokenOutAmountGross,
497
+ tokenOutAmountNet
498
+ };
499
+ }
500
+ function extractTokenInfo(paymentInfo, chainId, txHash) {
501
+ switch (paymentInfo.type) {
502
+ case "direct": {
503
+ return {
504
+ ...formatTokenAmounts({
505
+ tokenIn: paymentInfo.token,
506
+ tokenInAmount: paymentInfo.amount,
507
+ tokenOut: paymentInfo.token,
508
+ tokenOutAmountGross: paymentInfo.amount,
509
+ tokenOutAmountNet: paymentInfo.amount,
510
+ inChainId: chainId,
511
+ outChainId: chainId
512
+ }),
513
+ originChainId: chainId,
514
+ originTxHash: txHash,
515
+ destinationChainId: chainId,
516
+ destinationTxHash: txHash,
517
+ solver: null
518
+ };
519
+ }
520
+ case "swap": {
521
+ return {
522
+ ...formatTokenAmounts({
523
+ tokenIn: paymentInfo.tokenIn,
524
+ tokenInAmount: paymentInfo.tokenInAmount,
525
+ tokenOut: paymentInfo.token,
526
+ tokenOutAmountGross: paymentInfo.tokenOutAmount,
527
+ tokenOutAmountNet: paymentInfo.amount,
528
+ inChainId: chainId,
529
+ outChainId: chainId
530
+ }),
531
+ originChainId: chainId,
532
+ originTxHash: txHash,
533
+ destinationChainId: chainId,
534
+ destinationTxHash: txHash,
535
+ solver: paymentInfo.service ?? null
536
+ };
537
+ }
538
+ case "bridge": {
539
+ return {
540
+ ...formatTokenAmounts({
541
+ tokenIn: paymentInfo.tokenIn,
542
+ tokenInAmount: paymentInfo.tokenInAmount,
543
+ tokenOut: paymentInfo.tokenOut,
544
+ tokenOutAmountGross: paymentInfo.tokenOutAmountGross,
545
+ tokenOutAmountNet: paymentInfo.amount,
546
+ inChainId: paymentInfo.originChainId,
547
+ outChainId: paymentInfo.destinationChainId
548
+ }),
549
+ originChainId: paymentInfo.originChainId,
550
+ originTxHash: paymentInfo.originTxHash,
551
+ destinationChainId: paymentInfo.destinationChainId,
552
+ destinationTxHash: paymentInfo.destinationTxHash,
553
+ solver: paymentInfo.service ?? null
554
+ };
555
+ }
556
+ }
557
+ }
558
+ async function decodeYodlPayment(txHash, chainId, clients) {
559
+ const paymentInfo = await decodePayment(txHash, chainId, clients);
560
+ const firstWebhook = paymentInfo.webhooks[0];
561
+ const processorAddress = firstWebhook?.webhookAddress ?? zeroAddress;
562
+ const processorMemo = firstWebhook?.memo ?? "";
563
+ const tokenInfo = extractTokenInfo(paymentInfo, chainId, txHash);
564
+ return {
565
+ senderAddress: paymentInfo.sender,
566
+ receiverAddress: paymentInfo.receiver,
567
+ memo: paymentInfo.memo,
568
+ processorMemo,
569
+ processorAddress,
570
+ data: {},
571
+ ...tokenInfo,
572
+ blockTimestamp: paymentInfo.blockTimestamp
573
+ };
574
+ }
575
+ export {
576
+ NoBridgeFoundError,
577
+ NoYodlEventError,
578
+ createClients,
579
+ decodeBridgePayment,
580
+ decodePayment,
581
+ decodeYodlFromLogs,
582
+ decodeYodlPayment
583
+ };
584
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/clients.ts","../src/decode-utils.ts","../src/abi.ts","../src/errors.ts","../src/utils.ts","../src/payment-decoder.ts","../src/embedded-params.ts","../src/validation.ts","../src/relay-bridge.ts","../src/relay-client.ts","../src/yodl-payment.ts"],"sourcesContent":["import { chains } from \"@yodlpay/tokenlists\";\nimport { createPublicClient, http, type PublicClient } from \"viem\";\n\nexport type ChainClients = Record<number, PublicClient>;\n\nexport function createClients() {\n\tconst clients: ChainClients = {};\n\tfor (const chain of chains) {\n\t\tclients[chain.id] = createPublicClient({\n\t\t\tchain,\n\t\t\ttransport: http(),\n\t\t});\n\t}\n\treturn clients;\n}\n\nexport function getClient(clients: ChainClients, chainId: number) {\n\tconst client = clients[chainId];\n\tif (!client) throw new Error(`No client configured for chain ${chainId}`);\n\treturn client;\n}\n","import {\n\ttype Abi,\n\ttype Address,\n\ttype DecodeEventLogReturnType,\n\tdecodeEventLog,\n\terc20Abi,\n\tisAddressEqual,\n\ttype Log,\n} from \"viem\";\nimport { relaySwapAbi, yodlAbi } from \"./abi.ts\";\nimport { isExpectedDecodeError } from \"./errors.ts\";\nimport type { PaymentEvent, SwapInfo, Webhook } from \"./types.ts\";\nimport { decodeMemo } from \"./utils.ts\";\n\ninterface DecodeOptions<TAbi extends Abi> {\n\tabi: TAbi;\n\teventName: string;\n\taddress?: Address;\n\tcontext?: string;\n}\n\n/**\n * Decoded Yodl event data from onchain logs.\n * Does not include blockTimestamp or webhooks — callers provide those.\n */\nexport interface DecodedYodlEvent {\n\tsender: Address;\n\treceiver: Address;\n\ttoken: Address;\n\tamount: bigint;\n\tmemo: string;\n}\n\n/**\n * Yield decoded events matching the given ABI and event name.\n * Handles expected decode errors internally and logs unexpected ones.\n */\nfunction* matchingEvents<TAbi extends Abi>(\n\tlogs: readonly Log[],\n\toptions: DecodeOptions<TAbi>,\n): Generator<{ decoded: DecodeEventLogReturnType<TAbi>; log: Log }> {\n\tconst { abi, eventName, address, context } = options;\n\n\tfor (const log of logs) {\n\t\tif (address && !isAddressEqual(log.address, address)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\ttry {\n\t\t\tconst decoded = decodeEventLog({\n\t\t\t\tabi,\n\t\t\t\tdata: log.data,\n\t\t\t\ttopics: log.topics,\n\t\t\t}) as DecodeEventLogReturnType<TAbi>;\n\n\t\t\tif (decoded.eventName === eventName) {\n\t\t\t\tyield { decoded, log };\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (!isExpectedDecodeError(error)) {\n\t\t\t\tconst contextStr = context ? ` (${context})` : \"\";\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`[payment-decoder] Unexpected error decoding ${eventName}${contextStr}:`,\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Find the first matching event in transaction logs and transform it.\n */\nfunction findEventInLogs<TAbi extends Abi, TResult>(\n\tlogs: readonly Log[],\n\toptions: DecodeOptions<TAbi>,\n\ttransform: (decoded: DecodeEventLogReturnType<TAbi>, log: Log) => TResult,\n): TResult | undefined {\n\tfor (const { decoded, log } of matchingEvents(logs, options)) {\n\t\treturn transform(decoded, log);\n\t}\n\treturn undefined;\n}\n\n/**\n * Collect all matching events from transaction logs and transform them.\n */\nfunction collectEventsFromLogs<TAbi extends Abi, TResult>(\n\tlogs: readonly Log[],\n\toptions: DecodeOptions<TAbi>,\n\ttransform: (decoded: DecodeEventLogReturnType<TAbi>, log: Log) => TResult,\n): TResult[] {\n\tconst results: TResult[] = [];\n\tfor (const { decoded, log } of matchingEvents(logs, options)) {\n\t\tresults.push(transform(decoded, log));\n\t}\n\treturn results;\n}\n\n/**\n * Decode Yodl payment event from transaction logs.\n * Only trusts logs from the legitimate Yodl router for the given chain.\n */\nexport function decodeYodlFromLogs(\n\tlogs: readonly Log[],\n\trouterAddress: Address,\n): DecodedYodlEvent | undefined {\n\treturn findEventInLogs(\n\t\tlogs,\n\t\t{\n\t\t\tabi: yodlAbi,\n\t\t\teventName: \"Yodl\",\n\t\t\taddress: routerAddress,\n\t\t\tcontext: \"Yodl event\",\n\t\t},\n\t\t(decoded) => {\n\t\t\tconst args = decoded.args as {\n\t\t\t\tsender: Address;\n\t\t\t\treceiver: Address;\n\t\t\t\ttoken: Address;\n\t\t\t\tamount: bigint;\n\t\t\t\tmemo: `0x${string}`;\n\t\t\t};\n\t\t\treturn {\n\t\t\t\tsender: args.sender,\n\t\t\t\treceiver: args.receiver,\n\t\t\t\ttoken: args.token,\n\t\t\t\tamount: args.amount,\n\t\t\t\tmemo: decodeMemo(args.memo),\n\t\t\t};\n\t\t},\n\t);\n}\n\n/**\n * Decode Relay Swap event from transaction logs.\n * Returns swap info if found, undefined otherwise.\n */\nexport function decodeSwapFromLogs(logs: readonly Log[]): SwapInfo | undefined {\n\treturn findEventInLogs(\n\t\tlogs,\n\t\t{ abi: relaySwapAbi, eventName: \"Swap\", context: \"Relay Swap\" },\n\t\t(decoded) => {\n\t\t\tconst args = decoded.args as {\n\t\t\t\tinputToken: Address;\n\t\t\t\toutputToken: Address;\n\t\t\t\tinputAmount: bigint;\n\t\t\t\toutputAmount: bigint;\n\t\t\t};\n\t\t\treturn {\n\t\t\t\ttokenIn: args.inputToken,\n\t\t\t\ttokenOut: args.outputToken,\n\t\t\t\ttokenInAmount: args.inputAmount,\n\t\t\t\ttokenOutAmount: args.outputAmount,\n\t\t\t\tservice: \"relay\",\n\t\t\t};\n\t\t},\n\t);\n}\n\n/**\n * Represents an ERC20 token transfer extracted from onchain logs.\n */\nexport interface TokenTransfer {\n\ttoken: Address;\n\tfrom: Address;\n\tto: Address;\n\tamount: bigint;\n}\n\n/**\n * Extract ERC20 Transfer events from transaction logs.\n * Uses viem's erc20Abi to decode standard Transfer events.\n *\n * @param logs - Transaction logs from a receipt\n * @returns Array of decoded token transfers\n */\nexport function extractTokenTransfers(logs: readonly Log[]): TokenTransfer[] {\n\treturn collectEventsFromLogs(\n\t\tlogs,\n\t\t{ abi: erc20Abi, eventName: \"Transfer\", context: \"ERC20 Transfer\" },\n\t\t(decoded, log) => {\n\t\t\tconst args = decoded.args as {\n\t\t\t\tfrom: Address;\n\t\t\t\tto: Address;\n\t\t\t\tvalue: bigint;\n\t\t\t};\n\t\t\treturn {\n\t\t\t\ttoken: log.address as Address,\n\t\t\t\tfrom: args.from,\n\t\t\t\tto: args.to,\n\t\t\t\tamount: args.value,\n\t\t\t};\n\t\t},\n\t);\n}\n\n/**\n * Find the input transfer from a specific sender.\n * For bridge transactions, this identifies the token/amount the user sent.\n *\n * @param transfers - Array of token transfers from a transaction\n * @param sender - The sender address to search for\n * @returns The transfer with the largest amount from the sender, or undefined\n */\nexport function findInputTransfer(\n\ttransfers: TokenTransfer[],\n\tsender: Address,\n): { token: Address; amount: bigint } | undefined {\n\tconst fromSender = transfers.filter((t) => isAddressEqual(t.from, sender));\n\tif (fromSender.length === 0) return undefined;\n\t// Return the largest transfer if multiple (main payment vs fees)\n\tconst largest = fromSender.reduce((max, t) =>\n\t\tt.amount > max.amount ? t : max,\n\t);\n\treturn { token: largest.token, amount: largest.amount };\n}\n\n/**\n * Convert a block's timestamp (seconds since epoch) to a Date.\n */\nexport function toBlockTimestamp(block: { timestamp: bigint }): Date {\n\treturn new Date(Number(block.timestamp) * 1000);\n}\n\n/**\n * Build a PaymentEvent from a decoded Yodl event, webhooks, and block timestamp.\n * Optionally overrides the sender (e.g. for bridge transactions where the\n * original sender differs from the destination tx sender).\n */\nexport function buildPaymentEvent(\n\tyodlEvent: DecodedYodlEvent,\n\twebhooks: readonly Webhook[],\n\tblockTimestamp: Date,\n\tsenderOverride?: Address,\n): PaymentEvent {\n\treturn {\n\t\t...yodlEvent,\n\t\t...(senderOverride !== undefined && { sender: senderOverride }),\n\t\twebhooks,\n\t\tblockTimestamp,\n\t};\n}\n","import { getRouterAbi } from \"@yodlpay/tokenlists\";\n\nexport const yodlAbi = getRouterAbi(\"0.8\");\n\nexport const relaySwapAbi = [\n\t{\n\t\ttype: \"event\",\n\t\tname: \"Swap\",\n\t\tinputs: [\n\t\t\t{ name: \"sender\", type: \"address\", indexed: true },\n\t\t\t{ name: \"recipient\", type: \"address\", indexed: true },\n\t\t\t{ name: \"inputToken\", type: \"address\", indexed: false },\n\t\t\t{ name: \"outputToken\", type: \"address\", indexed: false },\n\t\t\t{ name: \"inputAmount\", type: \"uint256\", indexed: false },\n\t\t\t{ name: \"outputAmount\", type: \"uint256\", indexed: false },\n\t\t],\n\t},\n] as const;\n\n// ERC-4337 EntryPoint ABI for UserOperationEvent\n// Used to extract the original sender for bridge transactions\nexport const entryPointAbi = [\n\t{\n\t\ttype: \"event\",\n\t\tname: \"UserOperationEvent\",\n\t\tinputs: [\n\t\t\t{ name: \"userOpHash\", type: \"bytes32\", indexed: true },\n\t\t\t{ name: \"sender\", type: \"address\", indexed: true },\n\t\t\t{ name: \"paymaster\", type: \"address\", indexed: true },\n\t\t\t{ name: \"nonce\", type: \"uint256\", indexed: false },\n\t\t\t{ name: \"success\", type: \"bool\", indexed: false },\n\t\t\t{ name: \"actualGasCost\", type: \"uint256\", indexed: false },\n\t\t\t{ name: \"actualGasUsed\", type: \"uint256\", indexed: false },\n\t\t],\n\t},\n] as const;\n","import {\n\tAbiDecodingDataSizeTooSmallError,\n\tAbiEventSignatureEmptyTopicsError,\n\tAbiEventSignatureNotFoundError,\n\tDecodeLogTopicsMismatch,\n} from \"viem\";\n\nexport class ExpectedDecodeError extends Error {\n\tconstructor(message = \"Expected decode error\") {\n\t\tsuper(message);\n\t\tthis.name = \"ExpectedDecodeError\";\n\t}\n}\n\nexport class NoBridgeFoundError extends Error {\n\tconstructor(message = \"No bridge transaction found\") {\n\t\tsuper(message);\n\t\tthis.name = \"NoBridgeFoundError\";\n\t}\n}\n\nexport class NoYodlEventError extends Error {\n\tconstructor(message = \"No Yodl event found in logs\") {\n\t\tsuper(message);\n\t\tthis.name = \"NoYodlEventError\";\n\t}\n}\n\n/**\n * Check if an error is an expected event decoding error.\n * These errors occur when a log doesn't match the expected event signature,\n * which is normal when scanning logs for specific events.\n */\nexport function isExpectedDecodeError(error: unknown): boolean {\n\treturn (\n\t\terror instanceof AbiEventSignatureNotFoundError ||\n\t\terror instanceof AbiEventSignatureEmptyTopicsError ||\n\t\terror instanceof AbiDecodingDataSizeTooSmallError ||\n\t\terror instanceof DecodeLogTopicsMismatch\n\t);\n}\n","import { type Hex, hexToString } from \"viem\";\n\n/**\n * Decode memo from hex to UTF-8 string, handling empty/invalid values.\n * Uses size: 32 to properly handle null-padded bytes32 values.\n */\nexport function decodeMemo(memo: Hex): string {\n\tif (!memo || memo === \"0x\") return \"\";\n\ttry {\n\t\treturn hexToString(memo, { size: 32 }).replace(/\\0/g, \"\");\n\t} catch {\n\t\treturn \"\";\n\t}\n}\n\n/**\n * Serialize a JSON object with bigint values to a string.\n *\n * @param value - The JSON object to serialize\n * @returns The serialized string\n */\nexport function serializeJsonWithBigInts(value: unknown): string {\n\treturn JSON.stringify(\n\t\tvalue,\n\t\t(_key, value) => (typeof value === \"bigint\" ? value.toString() : value),\n\t\t2,\n\t);\n}\n","import { getRouter } from \"@yodlpay/tokenlists\";\nimport type { Hex } from \"viem\";\nimport type { ChainClients } from \"./clients.ts\";\nimport { getClient } from \"./clients.ts\";\nimport {\n\tbuildPaymentEvent,\n\tdecodeSwapFromLogs,\n\tdecodeYodlFromLogs,\n\ttoBlockTimestamp,\n} from \"./decode-utils.ts\";\nimport { extractEmbeddedParams } from \"./embedded-params.ts\";\nimport { NoBridgeFoundError, NoYodlEventError } from \"./errors.ts\";\nimport { decodeBridgePayment } from \"./relay-bridge.ts\";\nimport type { PaymentInfo } from \"./types.ts\";\n\nasync function tryDecodeBridge(\n\thash: Hex,\n\tclients: ChainClients,\n): Promise<PaymentInfo | undefined> {\n\ttry {\n\t\treturn await decodeBridgePayment(hash, clients);\n\t} catch (error) {\n\t\tif (!(error instanceof NoBridgeFoundError)) {\n\t\t\tif (process.env.NODE_ENV === \"development\") {\n\t\t\t\tconsole.warn(\"Unexpected error checking bridge info:\", error);\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n}\n\nexport async function decodePayment(\n\thash: Hex,\n\tchainId: number,\n\tclients: ChainClients,\n): Promise<PaymentInfo> {\n\tconst provider = getClient(clients, chainId);\n\tconst receipt = await provider.getTransactionReceipt({ hash });\n\tconst { address: routerAddress } = getRouter(chainId);\n\tconst [block, tx] = await Promise.all([\n\t\tprovider.getBlock({ blockNumber: receipt.blockNumber }),\n\t\tprovider.getTransaction({ hash }),\n\t]);\n\n\tconst yodlEvent = decodeYodlFromLogs(receipt.logs, routerAddress);\n\tconst swapEvent = decodeSwapFromLogs(receipt.logs);\n\n\tif (yodlEvent) {\n\t\tconst blockTimestamp = toBlockTimestamp(block);\n\t\tconst webhooks = extractEmbeddedParams(tx.input);\n\t\tconst paymentEvent = buildPaymentEvent(yodlEvent, webhooks, blockTimestamp);\n\n\t\tif (swapEvent) {\n\t\t\treturn { type: \"swap\" as const, ...paymentEvent, ...swapEvent };\n\t\t}\n\n\t\t// Check if this is the destination side of a bridge\n\t\tconst bridgeResult = await tryDecodeBridge(hash, clients);\n\t\tif (bridgeResult) return bridgeResult;\n\n\t\treturn { type: \"direct\" as const, ...paymentEvent };\n\t}\n\n\t// No Yodl on provided chain — must be a bridge (source or destination hash)\n\tconst bridgeResult = await tryDecodeBridge(hash, clients);\n\tif (bridgeResult) return bridgeResult;\n\n\tthrow new NoYodlEventError();\n}\n","import { decodeFunctionData, type Hex, toFunctionSelector } from \"viem\";\nimport { yodlAbi } from \"./abi.ts\";\nimport type { Webhook } from \"./types.ts\";\nimport { WebhooksSchema } from \"./validation.ts\";\n\nfunction getYodlSelector() {\n\tconst yodlFunction = yodlAbi.find(\n\t\t(i) => i.type === \"function\" && i.name === \"yodlWithToken\",\n\t);\n\tif (!yodlFunction) throw new Error(\"yodlWithToken not found in ABI\");\n\treturn toFunctionSelector(yodlFunction).slice(2);\n}\n\n/**\n * Extract embedded webhook parameters from transaction input data.\n * Scans for Yodl function calls embedded within other contract calls (e.g., bridges).\n */\nexport function extractEmbeddedParams(data: Hex | undefined): Webhook[] {\n\tif (!data) return [];\n\n\tconst yodlSelector = getYodlSelector();\n\n\tconst input = data.slice(2); // remove 0x\n\tlet pos = input.indexOf(yodlSelector);\n\n\twhile (pos >= 0 && pos < input.length - 8) {\n\t\ttry {\n\t\t\tconst decoded = decodeFunctionData({\n\t\t\t\tabi: yodlAbi,\n\t\t\t\tdata: `0x${input.slice(pos)}`,\n\t\t\t});\n\t\t\tconst params = decoded.args?.[0];\n\t\t\tif (params && typeof params === \"object\" && \"webhooks\" in params) {\n\t\t\t\treturn WebhooksSchema.parse(params.webhooks);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Expected: current position doesn't contain valid function data\n\t\t\t// Continue scanning for the selector at the next position\n\t\t}\n\t\tpos = input.indexOf(yodlSelector, pos + 8);\n\t}\n\n\treturn [];\n}\n","import { chains } from \"@yodlpay/tokenlists\";\nimport { type Address, type Hex, isAddress, isHex } from \"viem\";\nimport { z } from \"zod\";\nimport { decodeMemo } from \"./utils.ts\";\n\nconst validChainIds = chains.map((c) => c.id);\n\nexport const ArgsSchema = z.tuple([\n\tz\n\t\t.string()\n\t\t.regex(/^0x[a-fA-F0-9]{64}$/, \"Invalid transaction hash\")\n\t\t.transform((val) => val as Hex),\n\tz.coerce\n\t\t.number()\n\t\t.int()\n\t\t.refine((id) => validChainIds.includes(id), {\n\t\t\tmessage: `Chain ID must be one of: ${validChainIds.join(\", \")}`,\n\t\t}),\n]);\n\nexport const WebhooksSchema = z\n\t.array(\n\t\tz\n\t\t\t.object({\n\t\t\t\twebhookAddress: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.refine((val): val is Address => isAddress(val)),\n\t\t\t\tpayload: z.array(z.string().refine((val): val is Hex => isHex(val))),\n\t\t\t})\n\t\t\t.transform((webhook) => ({\n\t\t\t\t...webhook,\n\t\t\t\tmemo: webhook.payload[0] ? decodeMemo(webhook.payload[0]) : \"\",\n\t\t\t})),\n\t)\n\t.catch([]);\n","import { getRouter, getTokenByAddress } from \"@yodlpay/tokenlists\";\nimport {\n\ttype Address,\n\tdecodeEventLog,\n\ttype Hex,\n\tisAddressEqual,\n\ttype PublicClient,\n\ttype TransactionReceipt,\n} from \"viem\";\nimport { entryPoint08Address } from \"viem/account-abstraction\";\nimport { entryPointAbi } from \"./abi.ts\";\nimport type { ChainClients } from \"./clients.ts\";\nimport { getClient } from \"./clients.ts\";\nimport {\n\tbuildPaymentEvent,\n\ttype DecodedYodlEvent,\n\tdecodeSwapFromLogs,\n\tdecodeYodlFromLogs,\n\textractTokenTransfers,\n\tfindInputTransfer,\n\ttoBlockTimestamp,\n} from \"./decode-utils.ts\";\nimport { extractEmbeddedParams } from \"./embedded-params.ts\";\nimport {\n\tExpectedDecodeError,\n\tNoBridgeFoundError,\n\tNoYodlEventError,\n} from \"./errors.ts\";\nimport { fetchRelayRequest, type RelayRequest } from \"./relay-client.ts\";\nimport type { BridgeInfo, PaymentInfo, ServiceProvider } from \"./types.ts\";\n\n/**\n * Calculate outputAmountGross by converting inputAmount to output decimals.\n * Uses getTokenByAddress to get reliable decimals from tokenlists.\n */\nfunction calculateOutputAmountGross(\n\tinputAmount: bigint,\n\tinputToken: Address,\n\tinputChainId: number,\n\toutputToken: Address,\n\toutputChainId: number,\n): bigint {\n\tconst { decimals: inputDecimals } = getTokenByAddress(\n\t\tinputToken,\n\t\tinputChainId,\n\t);\n\tconst { decimals: outputDecimals } = getTokenByAddress(\n\t\toutputToken,\n\t\toutputChainId,\n\t);\n\n\tconst decimalDiff = inputDecimals - outputDecimals;\n\tif (decimalDiff === 0) return inputAmount;\n\tif (decimalDiff > 0) return inputAmount / 10n ** BigInt(decimalDiff);\n\treturn inputAmount * 10n ** BigInt(-decimalDiff);\n}\n\n/**\n * Extract the original sender from the source chain transaction.\n * First tries ERC-4337 UserOperationEvent from the canonical EntryPoint,\n * then falls back to tx.from for non-4337 transactions.\n */\nasync function extractSenderFromSource(\n\tsourceReceipt: TransactionReceipt,\n\tsourceProvider: PublicClient,\n\tsourceHash: Hex,\n): Promise<Address> {\n\tfor (const log of sourceReceipt.logs) {\n\t\tif (!isAddressEqual(log.address, entryPoint08Address)) continue;\n\t\ttry {\n\t\t\tconst decoded = decodeEventLog({\n\t\t\t\tabi: entryPointAbi,\n\t\t\t\tdata: log.data,\n\t\t\t\ttopics: log.topics,\n\t\t\t});\n\t\t\tif (decoded.eventName === \"UserOperationEvent\") {\n\t\t\t\treturn decoded.args.sender as Address;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Expected for non-matching events\n\t\t}\n\t}\n\n\t// Fallback: use tx.from from source transaction (for non-4337 txs)\n\tconst sourceTx = await sourceProvider.getTransaction({ hash: sourceHash });\n\treturn sourceTx.from;\n}\n\n/**\n * Resolve bridge token addresses, amounts, and tokenOutAmountGross from onchain data.\n * Uses ERC20 transfers from the source chain and Yodl/swap events from the destination.\n */\nfunction resolveBridgeTokens(\n\tsourceReceipt: TransactionReceipt,\n\tdestReceipt: TransactionReceipt,\n\tyodlEvent: DecodedYodlEvent,\n\tsender: Address,\n\tinputAmountGross: bigint,\n\tinputChainId: number,\n\toutputChainId: number,\n): Pick<\n\tBridgeInfo,\n\t| \"tokenIn\"\n\t| \"tokenInAmount\"\n\t| \"tokenOut\"\n\t| \"tokenOutAmount\"\n\t| \"tokenOutAmountGross\"\n> {\n\t// Extract input token from source chain ERC20 Transfer events (trusted onchain data)\n\tconst sourceTransfers = extractTokenTransfers(sourceReceipt.logs);\n\tconst inputTransfer = findInputTransfer(sourceTransfers, sender);\n\tconst tokenIn = inputTransfer?.token;\n\tconst tokenInAmount = inputTransfer?.amount;\n\n\tif (!tokenIn || !tokenInAmount) {\n\t\tthrow new ExpectedDecodeError(\n\t\t\t\"No input token or amount found in source chain\",\n\t\t);\n\t}\n\n\t// Output token/amount from Yodl event (trusted onchain data)\n\tconst tokenOut = yodlEvent.token;\n\tconst tokenOutAmount = yodlEvent.amount;\n\n\t// Check for Relay Swap event on destination chain — use actual swap output as gross if present\n\tconst swapEvent = decodeSwapFromLogs(destReceipt.logs);\n\n\tlet tokenOutAmountGross = 0n;\n\tif (swapEvent !== undefined) {\n\t\ttokenOutAmountGross = swapEvent.tokenOutAmount;\n\t} else if (inputAmountGross > 0n && tokenIn && tokenOut) {\n\t\ttokenOutAmountGross = calculateOutputAmountGross(\n\t\t\tinputAmountGross,\n\t\t\ttokenIn,\n\t\t\tinputChainId,\n\t\t\ttokenOut,\n\t\t\toutputChainId,\n\t\t);\n\t}\n\n\treturn {\n\t\ttokenIn,\n\t\ttokenInAmount,\n\t\ttokenOut,\n\t\ttokenOutAmount,\n\t\ttokenOutAmountGross,\n\t};\n}\n\ninterface ParsedRelayData {\n\toriginChainId: number;\n\toriginTxHash: Hex;\n\tdestinationChainId: number;\n\tdestinationTxHash: Hex;\n\tinputAmountGross: bigint;\n}\n\nfunction parseRelayResponse(request: RelayRequest): ParsedRelayData {\n\tconst data = request.data;\n\tconst inTx = data?.inTxs?.[0];\n\tconst outTx = data?.outTxs?.[0];\n\n\tif (!inTx?.hash || !inTx?.chainId || !outTx?.hash || !outTx?.chainId) {\n\t\tthrow new NoBridgeFoundError();\n\t}\n\n\treturn {\n\t\toriginChainId: inTx.chainId,\n\t\toriginTxHash: inTx.hash as Hex,\n\t\tdestinationChainId: outTx.chainId,\n\t\tdestinationTxHash: outTx.hash as Hex,\n\t\tinputAmountGross: BigInt(data?.metadata?.currencyIn?.amount ?? 0),\n\t};\n}\n\n/**\n * Decode a bridge transaction given any hash (source or destination).\n * Fetches bridge info from Relay, then decodes the Yodl event from the destination chain.\n * Extracts the original sender from the source chain's UserOperationEvent.\n *\n * SECURITY: Token data is extracted from onchain logs, not trusted from Relay.\n * Relay is only used for bridge discovery (hashes + chain IDs).\n */\nexport async function decodeBridgePayment(\n\thash: Hex,\n\tclients: ChainClients,\n): Promise<Extract<PaymentInfo, { type: \"bridge\" }>> {\n\tconst request = await fetchRelayRequest(hash);\n\tconst {\n\t\toriginChainId,\n\t\toriginTxHash,\n\t\tdestinationChainId,\n\t\tdestinationTxHash,\n\t\tinputAmountGross,\n\t} = parseRelayResponse(request);\n\n\tconst destProvider = getClient(clients, destinationChainId);\n\tconst sourceProvider = getClient(clients, originChainId);\n\tconst { address: routerAddress } = getRouter(destinationChainId);\n\n\tconst [destReceipt, sourceReceipt] = await Promise.all([\n\t\tdestProvider.getTransactionReceipt({ hash: destinationTxHash }),\n\t\tsourceProvider.getTransactionReceipt({ hash: originTxHash }),\n\t]);\n\n\tconst yodlEvent = decodeYodlFromLogs(destReceipt.logs, routerAddress);\n\tif (!yodlEvent) {\n\t\tthrow new NoYodlEventError(\n\t\t\t\"No Yodl event found in destination transaction\",\n\t\t);\n\t}\n\n\tconst [destBlock, destTx, sender] = await Promise.all([\n\t\tdestProvider.getBlock({ blockNumber: destReceipt.blockNumber }),\n\t\tdestProvider.getTransaction({ hash: destinationTxHash }),\n\t\textractSenderFromSource(sourceReceipt, sourceProvider, originTxHash),\n\t]);\n\n\tconst tokens = resolveBridgeTokens(\n\t\tsourceReceipt,\n\t\tdestReceipt,\n\t\tyodlEvent,\n\t\tsender,\n\t\tinputAmountGross,\n\t\toriginChainId,\n\t\tdestinationChainId,\n\t);\n\n\tconst bridge: BridgeInfo = {\n\t\toriginChainId,\n\t\toriginTxHash,\n\t\tdestinationChainId,\n\t\tdestinationTxHash,\n\t\t...tokens,\n\t\tservice: \"relay\" as ServiceProvider,\n\t};\n\n\tconst payment = buildPaymentEvent(\n\t\tyodlEvent,\n\t\textractEmbeddedParams(destTx.input),\n\t\ttoBlockTimestamp(destBlock),\n\t\tsender,\n\t);\n\n\treturn { type: \"bridge\" as const, ...payment, ...bridge };\n}\n","import type { paths } from \"@relayprotocol/relay-sdk\";\nimport { MAINNET_RELAY_API, TESTNET_RELAY_API } from \"@relayprotocol/relay-sdk\";\nimport { NoBridgeFoundError } from \"./errors.ts\";\n\n// Extract types from the auto-generated OpenAPI types\ntype GetRequestsQuery = paths[\"/requests/v2\"][\"get\"][\"parameters\"][\"query\"];\ntype GetRequestsResponse =\n\tpaths[\"/requests/v2\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\n// Re-export for convenience\nexport type RelayRequestParams = NonNullable<GetRequestsQuery>;\nexport type RelayRequestsResponse = GetRequestsResponse;\nexport type RelayRequest = NonNullable<GetRequestsResponse[\"requests\"]>[number];\n\n// Client options\nexport interface RelayClientOptions {\n\ttestnet?: boolean;\n}\n\n/**\n * Fetch relay requests from the Relay Link API.\n *\n * @param params - Query parameters for the /requests/v2 endpoint\n * @param options - Client options (e.g., testnet mode)\n * @returns The API response containing requests and optional continuation token\n * @throws Error if the API request fails\n */\nexport async function getRelayRequests(\n\tparams: RelayRequestParams,\n\toptions?: RelayClientOptions,\n): Promise<RelayRequestsResponse> {\n\tconst baseUrl = options?.testnet ? TESTNET_RELAY_API : MAINNET_RELAY_API;\n\tconst url = new URL(`${baseUrl}/requests/v2`);\n\n\t// Build query string from params\n\tfor (const [key, value] of Object.entries(params)) {\n\t\tif (value !== undefined) {\n\t\t\turl.searchParams.set(key, String(value));\n\t\t}\n\t}\n\n\tconst response = await fetch(url);\n\tif (!response.ok) {\n\t\tthrow new Error(`Relay API error: ${response.status}`);\n\t}\n\n\treturn response.json() as Promise<RelayRequestsResponse>;\n}\n\n/**\n * Fetch relay request from Relay API.\n *\n * @throws {NoBridgeFoundError} If no bridge transaction found\n */\nexport async function fetchRelayRequest(hash: string): Promise<RelayRequest> {\n\tconst response = await getRelayRequests({ hash });\n\tconst request = response.requests?.[0];\n\n\tif (!request) {\n\t\tthrow new NoBridgeFoundError();\n\t}\n\n\treturn request;\n}\n","import { getTokenByAddress } from \"@yodlpay/tokenlists\";\nimport { type Address, formatUnits, type Hex, zeroAddress } from \"viem\";\nimport type { ChainClients } from \"./clients\";\nimport { decodePayment } from \"./payment-decoder\";\nimport type { PaymentInfo, YodlPayment } from \"./types\";\n\n/**\n * Format token amounts using decimal info from tokenlists.\n * Centralizes the getTokenByAddress + formatUnits pattern.\n */\nfunction formatTokenAmounts(params: {\n\ttokenIn: Address;\n\ttokenInAmount: bigint;\n\ttokenOut: Address;\n\ttokenOutAmountGross: bigint;\n\ttokenOutAmountNet: bigint;\n\tinChainId: number;\n\toutChainId: number;\n}) {\n\tconst { decimals: inDecimals } = getTokenByAddress(\n\t\tparams.tokenIn,\n\t\tparams.inChainId,\n\t);\n\tconst { decimals: outDecimals } = getTokenByAddress(\n\t\tparams.tokenOut,\n\t\tparams.outChainId,\n\t);\n\n\tconst tokenOutAmountGross = formatUnits(\n\t\tparams.tokenOutAmountGross,\n\t\toutDecimals,\n\t);\n\tconst tokenOutAmountNet = formatUnits(params.tokenOutAmountNet, outDecimals);\n\n\treturn {\n\t\ttokenInAddress: params.tokenIn,\n\t\ttokenInAmount: formatUnits(params.tokenInAmount, inDecimals),\n\t\ttokenOutAddress: params.tokenOut,\n\t\ttokenOutAmountGross,\n\t\ttokenOutAmountNet,\n\t};\n}\n\n/**\n * Extract token addresses, amounts, and chain/tx info based on payment type.\n *\n * Amount semantics:\n * - tokenInAmount: what user actually spent\n * - tokenOutAmountGross: total output from swap/bridge (before fees)\n * - tokenOutAmountNet: what merchant actually receives (payment.amount)\n */\nfunction extractTokenInfo(\n\tpaymentInfo: PaymentInfo,\n\tchainId: number,\n\ttxHash: Hex,\n) {\n\tswitch (paymentInfo.type) {\n\t\tcase \"direct\": {\n\t\t\treturn {\n\t\t\t\t...formatTokenAmounts({\n\t\t\t\t\ttokenIn: paymentInfo.token,\n\t\t\t\t\ttokenInAmount: paymentInfo.amount,\n\t\t\t\t\ttokenOut: paymentInfo.token,\n\t\t\t\t\ttokenOutAmountGross: paymentInfo.amount,\n\t\t\t\t\ttokenOutAmountNet: paymentInfo.amount,\n\t\t\t\t\tinChainId: chainId,\n\t\t\t\t\toutChainId: chainId,\n\t\t\t\t}),\n\t\t\t\toriginChainId: chainId,\n\t\t\t\toriginTxHash: txHash,\n\t\t\t\tdestinationChainId: chainId,\n\t\t\t\tdestinationTxHash: txHash,\n\t\t\t\tsolver: null,\n\t\t\t};\n\t\t}\n\t\tcase \"swap\": {\n\t\t\treturn {\n\t\t\t\t...formatTokenAmounts({\n\t\t\t\t\ttokenIn: paymentInfo.tokenIn,\n\t\t\t\t\ttokenInAmount: paymentInfo.tokenInAmount,\n\t\t\t\t\ttokenOut: paymentInfo.token,\n\t\t\t\t\ttokenOutAmountGross: paymentInfo.tokenOutAmount,\n\t\t\t\t\ttokenOutAmountNet: paymentInfo.amount,\n\t\t\t\t\tinChainId: chainId,\n\t\t\t\t\toutChainId: chainId,\n\t\t\t\t}),\n\t\t\t\toriginChainId: chainId,\n\t\t\t\toriginTxHash: txHash,\n\t\t\t\tdestinationChainId: chainId,\n\t\t\t\tdestinationTxHash: txHash,\n\t\t\t\tsolver: paymentInfo.service ?? null,\n\t\t\t};\n\t\t}\n\t\tcase \"bridge\": {\n\t\t\treturn {\n\t\t\t\t...formatTokenAmounts({\n\t\t\t\t\ttokenIn: paymentInfo.tokenIn,\n\t\t\t\t\ttokenInAmount: paymentInfo.tokenInAmount,\n\t\t\t\t\ttokenOut: paymentInfo.tokenOut,\n\t\t\t\t\ttokenOutAmountGross: paymentInfo.tokenOutAmountGross,\n\t\t\t\t\ttokenOutAmountNet: paymentInfo.amount,\n\t\t\t\t\tinChainId: paymentInfo.originChainId,\n\t\t\t\t\toutChainId: paymentInfo.destinationChainId,\n\t\t\t\t}),\n\t\t\t\toriginChainId: paymentInfo.originChainId,\n\t\t\t\toriginTxHash: paymentInfo.originTxHash,\n\t\t\t\tdestinationChainId: paymentInfo.destinationChainId,\n\t\t\t\tdestinationTxHash: paymentInfo.destinationTxHash,\n\t\t\t\tsolver: paymentInfo.service ?? null,\n\t\t\t};\n\t\t}\n\t}\n}\n\nexport async function decodeYodlPayment(\n\ttxHash: Hex,\n\tchainId: number,\n\tclients: ChainClients,\n): Promise<YodlPayment> {\n\tconst paymentInfo = await decodePayment(txHash, chainId, clients);\n\n\tconst firstWebhook = paymentInfo.webhooks[0];\n\tconst processorAddress = firstWebhook?.webhookAddress ?? zeroAddress;\n\tconst processorMemo = firstWebhook?.memo ?? \"\";\n\n\tconst tokenInfo = extractTokenInfo(paymentInfo, chainId, txHash);\n\n\treturn {\n\t\tsenderAddress: paymentInfo.sender,\n\t\treceiverAddress: paymentInfo.receiver,\n\t\tmemo: paymentInfo.memo,\n\t\tprocessorMemo,\n\t\tprocessorAddress,\n\t\tdata: {},\n\t\t...tokenInfo,\n\t\tblockTimestamp: paymentInfo.blockTimestamp,\n\t};\n}\n"],"mappings":"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","names":["getRouter","chains","chains","decodeEventLog","isAddressEqual","isAddressEqual","decodeEventLog","getRouter","bridgeResult","getTokenByAddress","getTokenByAddress"]}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@yodlpay/payment-decoder",
3
+ "version": "0.1.0",
4
+ "description": "Decode Yodl payment hashes into structured payment data",
5
+ "keywords": [
6
+ "yodl",
7
+ "payment",
8
+ "hash",
9
+ "decode",
10
+ "crypto"
11
+ ],
12
+ "author": "Yodl",
13
+ "license": "SEE LICENSE IN LICENSE.md",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/yodlpay/payment-decoder"
17
+ },
18
+ "type": "module",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "import": "./dist/index.js"
23
+ }
24
+ },
25
+ "main": "./dist/index.js",
26
+ "types": "./dist/index.d.ts",
27
+ "files": [
28
+ "dist"
29
+ ],
30
+ "scripts": {
31
+ "dev": "bun run index.ts",
32
+ "decode": "bun run src/cli.ts",
33
+ "build": "tsup",
34
+ "test": "bun test --concurrent",
35
+ "format": "biome check --write",
36
+ "lint": "biome check",
37
+ "typecheck": "tsc --noEmit",
38
+ "prepublishOnly": "bun run build"
39
+ },
40
+ "devDependencies": {
41
+ "@biomejs/biome": "^2.3.14",
42
+ "@semantic-release/changelog": "^6.0.3",
43
+ "@semantic-release/git": "^10.0.1",
44
+ "@types/bun": "latest",
45
+ "semantic-release": "^25.0.3",
46
+ "tsup": "^8.5.1"
47
+ },
48
+ "peerDependencies": {
49
+ "typescript": "^5"
50
+ },
51
+ "dependencies": {
52
+ "@relay-vaults/client": "^0.2.1",
53
+ "@relayprotocol/relay-sdk": "^5.1.0",
54
+ "@yodlpay/tokenlists": "^1.1.5",
55
+ "viem": "^2.45.1",
56
+ "zod": "^4.3.6"
57
+ }
58
+ }