@yodlpay/payment-decoder 0.1.0 → 1.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/dist/index.js CHANGED
@@ -275,7 +275,8 @@ import {
275
275
  import { entryPoint08Address } from "viem/account-abstraction";
276
276
 
277
277
  // src/relay-client.ts
278
- import { MAINNET_RELAY_API, TESTNET_RELAY_API } from "@relayprotocol/relay-sdk";
278
+ var MAINNET_RELAY_API = "https://api.relay.link";
279
+ var TESTNET_RELAY_API = "https://api.testnets.relay.link";
279
280
  async function getRelayRequests(params, options) {
280
281
  const baseUrl = options?.testnet ? TESTNET_RELAY_API : MAINNET_RELAY_API;
281
282
  const url = new URL(`${baseUrl}/requests/v2`);
@@ -581,4 +582,3 @@ export {
581
582
  decodeYodlFromLogs,
582
583
  decodeYodlPayment
583
584
  };
584
- //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yodlpay/payment-decoder",
3
- "version": "0.1.0",
3
+ "version": "1.1.0",
4
4
  "description": "Decode Yodl payment hashes into structured payment data",
5
5
  "keywords": [
6
6
  "yodl",
@@ -39,20 +39,20 @@
39
39
  },
40
40
  "devDependencies": {
41
41
  "@biomejs/biome": "^2.3.14",
42
+ "@relayprotocol/relay-sdk": "^5.1.0",
42
43
  "@semantic-release/changelog": "^6.0.3",
43
44
  "@semantic-release/git": "^10.0.1",
44
45
  "@types/bun": "latest",
45
46
  "semantic-release": "^25.0.3",
46
- "tsup": "^8.5.1"
47
- },
48
- "peerDependencies": {
49
- "typescript": "^5"
47
+ "tsup": "^8.5.1",
48
+ "zod": "^4.3.6"
50
49
  },
51
50
  "dependencies": {
52
- "@relay-vaults/client": "^0.2.1",
53
- "@relayprotocol/relay-sdk": "^5.1.0",
54
- "@yodlpay/tokenlists": "^1.1.5",
51
+ "@yodlpay/tokenlists": "^1.1.7"
52
+ },
53
+ "peerDependencies": {
54
+ "typescript": "^5",
55
55
  "viem": "^2.45.1",
56
- "zod": "^4.3.6"
56
+ "zod": "^4.0.0"
57
57
  }
58
58
  }
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
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"]}