From fe20856ac831acb233e45ac9fcafeaa0a1b4a5e4 Mon Sep 17 00:00:00 2001 From: hzhu Date: Sat, 17 Aug 2024 00:21:01 -0700 Subject: [PATCH] f --- src/index.ts | 87 +++ src/tests/index.test.ts | 1213 +++++++++++++++++++++------------------ src/utils/index.ts | 63 +- 3 files changed, 791 insertions(+), 572 deletions(-) diff --git a/src/index.ts b/src/index.ts index 0649ea6..fe2c62f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,6 +16,7 @@ import { transferLogs, isChainIdSupported, extractNativeTransfer, + extractNativeTransfer2, } from "./utils"; import type { Hash, Chain, Address, Transport, PublicClient } from "viem"; import type { TraceTransactionSchema } from "./types"; @@ -23,9 +24,11 @@ import type { TraceTransactionSchema } from "./types"; export async function parseSwap({ publicClient, transactionHash: hash, + smartContractWalletAddress, }: { publicClient: PublicClient; transactionHash: Address; + smartContractWalletAddress?: Address; }) { const chainId = await publicClient.getChainId(); @@ -42,12 +45,16 @@ export async function parseSwap({ }, })); + const ERC_4337_ENTRY_POINT = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; + const trace = await client.traceCall({ hash }); const transaction = await publicClient.getTransaction({ hash }); const { from: taker, value, to } = transaction; + const isToERC4337 = to === ERC_4337_ENTRY_POINT.toLowerCase(); + const nativeTransferAmount = extractNativeTransfer(trace, taker); const transactionReceipt = await publicClient.getTransactionReceipt({ hash }); @@ -59,6 +66,86 @@ export async function parseSwap({ transactionReceipt, }); + if (isToERC4337) { + if (!smartContractWalletAddress) { + throw new Error( + "This is an ERC-4337 transaction. You must provide a smart contract wallet address to 0x-parser." + ); + } + + const transfersFromSmartContractWallet = logs.reduce((acc, curr) => { + if (curr.to === smartContractWalletAddress) { + return { + ...acc, + output: curr, + }; + } + + if (curr.from === smartContractWalletAddress) { + return { + ...acc, + input: curr, + }; + } + + return acc; + }, {}); + + let { input, output } = transfersFromSmartContractWallet as any; + + const nativeTransferAmount = extractNativeTransfer( + trace, + smartContractWalletAddress + ); + + const nativeTransferAmount2 = extractNativeTransfer2( + trace, + smartContractWalletAddress + ); + + if (!output && nativeTransferAmount !== "0") { + return { + tokenIn: { + address: input.address, + amount: input.amount, + symbol: input.symbol, + }, + tokenOut: { + address: NATIVE_TOKEN_ADDRESS, + amount: nativeTransferAmount, + symbol: NATIVE_SYMBOL_BY_CHAIN_ID[chainId], + }, + }; + } else if (!input && nativeTransferAmount2 !== "0") { + const inputLog = logs.filter((log) => log.symbol === "WETH")[0]; + return { + tokenIn: { + address: NATIVE_TOKEN_ADDRESS, + amount: inputLog?.amount, + symbol: NATIVE_SYMBOL_BY_CHAIN_ID[chainId], + }, + tokenOut: { + address: output.address, + amount: output.amount, + symbol: output.symbol, + }, + }; + } else { + return { + tokenIn: { + address: input.address, + amount: input.amount, + symbol: input.symbol, + }, + tokenOut: { + address: output.address, + amount: output.amount, + symbol: output.symbol, + }, + }; + } + } + const fromTaker = logs.filter( (log) => log.from.toLowerCase() === taker.toLowerCase() ); diff --git a/src/tests/index.test.ts b/src/tests/index.test.ts index 3dea4b0..31aec09 100644 --- a/src/tests/index.test.ts +++ b/src/tests/index.test.ts @@ -23,306 +23,638 @@ const publicClient = createPublicClient({ ), }); -// https://etherscan.io/tx/0x2fc205711fc933ef6e5bcc0bf6e6a9bfc220b2d8073aea4f41305882f485669d -test("parses swapped amounts case 0 (default)", async () => { - const transactionHash = - "0x2fc205711fc933ef6e5bcc0bf6e6a9bfc220b2d8073aea4f41305882f485669d"; - - const result = await parseSwap({ - publicClient, - transactionHash, - }); - - expect(result).toEqual({ - tokenIn: { - symbol: "KAI", - amount: "12124969884.736401754", - address: "0xA045Fe936E26e1e1e1Fb27C1f2Ae3643acde0171", - }, - tokenOut: { - symbol: "USDC", - amount: "340.919143", - address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - }, - }); -}); - -// https://etherscan.io/tx/0x2b9a12398613887e9813594e8583f488f0e8392d8e6e0ba8d9e140065826dd00 -test("parses swapped amounts case 1 (default)", async () => { - const transactionHash = - "0x2b9a12398613887e9813594e8583f488f0e8392d8e6e0ba8d9e140065826dd00"; - - const result = await parseSwap({ - publicClient, - transactionHash, - }); - - expect(result).toEqual({ - tokenIn: { - symbol: "USDC", - amount: "30.084159", - address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - }, - tokenOut: { - symbol: "USDT", - amount: "30.069172", - address: "0xdAC17F958D2ee523a2206206994597C13D831ec7", - }, - }); -}); - -// https://etherscan.io/tx/0x76b744ab42b05b30624bd5027b4f7da841cdc357bb1d6ee74e3d9e049dd8a126 -test("parses swapped amounts case 2 (default)", async () => { - const transactionHash = - "0x76b744ab42b05b30624bd5027b4f7da841cdc357bb1d6ee74e3d9e049dd8a126"; - - const result = await parseSwap({ - publicClient, - transactionHash, - }); - - expect(result).toEqual({ - tokenIn: { - symbol: "USDC", - amount: "1", - address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - }, - tokenOut: { - symbol: "WETH", - amount: "0.000280757770903965", - address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", - }, - }); -}); - -// https://etherscan.io/tx/0x565e8e0582b620ee06618ee0b7705dc0e7f56dfd88b5eb3e008c0858f6f806d8 -test("parses swapped amounts case 3 (default)", async () => { - const transactionHash = - "0x565e8e0582b620ee06618ee0b7705dc0e7f56dfd88b5eb3e008c0858f6f806d8"; - - const result = await parseSwap({ - publicClient, - transactionHash, - }); - - expect(result).toEqual({ - tokenIn: { - symbol: "USDC", - amount: "8.15942", - address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - }, - tokenOut: { - symbol: "WBTC", - amount: "0.00013188", - address: "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", - }, - }); -}); - -// https://etherscan.io/tx/0xd024750c7dcb99ace02c6b083c68d73dcfebdee252ccbeb1b83981b609693271 -test("parses swapped amounts case 4 (default)", async () => { - const transactionHash = - "0xd024750c7dcb99ace02c6b083c68d73dcfebdee252ccbeb1b83981b609693271"; - - const result = await parseSwap({ - publicClient, - transactionHash, - }); - - expect(result).toEqual({ - tokenIn: { - symbol: "USDC", - amount: "335.142587", - address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - }, - tokenOut: { - symbol: "WETH", - amount: "0.105662100963455883", - address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", - }, - }); -}); - -// https://etherscan.io/tx/0x4cbcf2e2512adb7e28f19f8cf28ddc29a9f9fea93c842cf3b735eeb526fe34b3 -test("parses swapped amounts case 5 (native sell token)", async () => { - const transactionHash = - "0x4cbcf2e2512adb7e28f19f8cf28ddc29a9f9fea93c842cf3b735eeb526fe34b3"; - - const result = await parseSwap({ - publicClient, - transactionHash, - }); - - expect(result).toEqual({ - tokenIn: { - symbol: "ETH", - amount: "0.04", - address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", - }, - tokenOut: { - symbol: "USDC", - amount: "126.580558", - address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - }, - }); -}); - -// https://etherscan.io/tx/0x28c5bb3768bb64e81e1f3753ed1a8c30f0484a434d6c2b4af825d258ecb3bcf0 -test("parses swapped amounts case 6 (buy DNT 404 token)", async () => { - const transactionHash = - "0x28c5bb3768bb64e81e1f3753ed1a8c30f0484a434d6c2b4af825d258ecb3bcf0"; - - const result = await parseSwap({ - publicClient, - transactionHash, - }); - - expect(result).toEqual({ - tokenIn: { - symbol: "USDC", - amount: "95", - address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - }, - tokenOut: { - symbol: "CHIB", - amount: "10.527633901274097318", - address: "0x7068263EDa099fB93BB3215c05e728c0b54b3137", - }, - }); -}); - -// https://etherscan.io/tx/0xb8beef6bf857f2fc22905b2872120abc634900b45941478aa9cf0ad1ceffcd67 -// https://gopluslabs.io/token-security/1/0xcf0c122c6b73ff809c693db761e7baebe62b6a2e -test("parses swapped amounts case 6 (buy FoT token, FLOKI)", async () => { - const transactionHash = - "0xb8beef6bf857f2fc22905b2872120abc634900b45941478aa9cf0ad1ceffcd67"; - - const result = await parseSwap({ - publicClient, - transactionHash, - }); - - expect(result).toEqual({ - tokenIn: { - symbol: "USDC", - amount: "31.580558", - address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - }, - tokenOut: { - symbol: "FLOKI", - amount: "172036.330384861", - address: "0xcf0C122c6b73ff809C693DB761e7BaeBe62b6a2E", - }, - }); -}); - -// Gasless RFQ -// https://etherscan.io/tx/0x5dd4579b5709b405d6df935d516563e1db09453f37431639ae7e1358ec8f834d -test("parses swapped amounts from tx settled by gasless rfq)", async () => { - const transactionHash = - "0x5dd4579b5709b405d6df935d516563e1db09453f37431639ae7e1358ec8f834d"; - - const result = await parseSwap({ - publicClient, - transactionHash, - }); - - expect(result).toEqual({ - tokenIn: { - symbol: "USDC", - amount: "20", - address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - }, - tokenOut: { - symbol: "USDT", - amount: "11.604822", - address: "0xdAC17F958D2ee523a2206206994597C13D831ec7", - }, - }); -}); - -// https://explorer.celo.org/tx/0x615c5089f772a8f2074750e8c6070013d288af7681435aba1771f6bfc63d1286 -test("throws an error for unsupported chains)", async () => { - const transactionHash = - "0x615c5089f772a8f2074750e8c6070013d288af7681435aba1771f6bfc63d1286"; - - const publicClient = createPublicClient({ - chain: mainnet, - transport: http("https://rpc.ankr.com/celo"), - }); - - expect(async () => { - await parseSwap({ - publicClient, - transactionHash, - }); - }).rejects.toThrowError("chainId 42220 is unsupported…"); -}); - -// https://basescan.org/tx/0x314ea35ef3120934ee4714f4815dc3b08dc2ab0e32e0662bfba3cdbcff14d79b -test("parse a gasless swap on Base (DAI for USDC)", async () => { - const publicClient = createPublicClient({ - chain: base, - transport: http( - `https://base-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` - ), - }) as PublicClient; - - const transactionHash = - "0x314ea35ef3120934ee4714f4815dc3b08dc2ab0e32e0662bfba3cdbcff14d79b"; - - const result = await parseSwap({ - publicClient, - transactionHash, - }); - - expect(result).toEqual({ - tokenIn: { - symbol: "DAI", - amount: "1.998484821908329022", - address: "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb", - }, - tokenOut: { - symbol: "USDC", - amount: "1.982641", - address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", - }, - }); -}); - -// https://basescan.org/tx/0xa09cb1606e30c3aed8a842723fd6c23cecd838a59f750ab3dbc5ef2c7486e696 -test("parse a swap on Base (USDC for DAI)", async () => { - const publicClient = createPublicClient({ - chain: base, - transport: http( - `https://base-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` - ), - }) as PublicClient; - - const transactionHash = - "0xa09cb1606e30c3aed8a842723fd6c23cecd838a59f750ab3dbc5ef2c7486e696"; - - const result = await parseSwap({ - publicClient, - transactionHash, - }); - - expect(result).toEqual({ - tokenIn: { - symbol: "USDC", - amount: "17.834287", - address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", - }, - tokenOut: { - symbol: "DAI", - amount: "17.843596331665784515", - address: "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb", - }, - }); -}); - -// https://basescan.org/tx/0xea8bca6e13f2c3e6c1e956308003b8d5da5fca44e03eac7ddbdcea271186ab37 -test("parse a swap on Base (DEGEN for ETH)", async () => { +// // https://etherscan.io/tx/0x2fc205711fc933ef6e5bcc0bf6e6a9bfc220b2d8073aea4f41305882f485669d +// test("parses swapped amounts case 0 (default)", async () => { +// const transactionHash = +// "0x2fc205711fc933ef6e5bcc0bf6e6a9bfc220b2d8073aea4f41305882f485669d"; + +// const result = await parseSwap({ +// publicClient, +// transactionHash, +// }); + +// expect(result).toEqual({ +// tokenIn: { +// symbol: "KAI", +// amount: "12124969884.736401754", +// address: "0xA045Fe936E26e1e1e1Fb27C1f2Ae3643acde0171", +// }, +// tokenOut: { +// symbol: "USDC", +// amount: "340.919143", +// address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", +// }, +// }); +// }); + +// // https://etherscan.io/tx/0x2b9a12398613887e9813594e8583f488f0e8392d8e6e0ba8d9e140065826dd00 +// test("parses swapped amounts case 1 (default)", async () => { +// const transactionHash = +// "0x2b9a12398613887e9813594e8583f488f0e8392d8e6e0ba8d9e140065826dd00"; + +// const result = await parseSwap({ +// publicClient, +// transactionHash, +// }); + +// expect(result).toEqual({ +// tokenIn: { +// symbol: "USDC", +// amount: "30.084159", +// address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", +// }, +// tokenOut: { +// symbol: "USDT", +// amount: "30.069172", +// address: "0xdAC17F958D2ee523a2206206994597C13D831ec7", +// }, +// }); +// }); + +// // https://etherscan.io/tx/0x76b744ab42b05b30624bd5027b4f7da841cdc357bb1d6ee74e3d9e049dd8a126 +// test("parses swapped amounts case 2 (default)", async () => { +// const transactionHash = +// "0x76b744ab42b05b30624bd5027b4f7da841cdc357bb1d6ee74e3d9e049dd8a126"; + +// const result = await parseSwap({ +// publicClient, +// transactionHash, +// }); + +// expect(result).toEqual({ +// tokenIn: { +// symbol: "USDC", +// amount: "1", +// address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", +// }, +// tokenOut: { +// symbol: "WETH", +// amount: "0.000280757770903965", +// address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", +// }, +// }); +// }); + +// // https://etherscan.io/tx/0x565e8e0582b620ee06618ee0b7705dc0e7f56dfd88b5eb3e008c0858f6f806d8 +// test("parses swapped amounts case 3 (default)", async () => { +// const transactionHash = +// "0x565e8e0582b620ee06618ee0b7705dc0e7f56dfd88b5eb3e008c0858f6f806d8"; + +// const result = await parseSwap({ +// publicClient, +// transactionHash, +// }); + +// expect(result).toEqual({ +// tokenIn: { +// symbol: "USDC", +// amount: "8.15942", +// address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", +// }, +// tokenOut: { +// symbol: "WBTC", +// amount: "0.00013188", +// address: "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", +// }, +// }); +// }); + +// // https://etherscan.io/tx/0xd024750c7dcb99ace02c6b083c68d73dcfebdee252ccbeb1b83981b609693271 +// test("parses swapped amounts case 4 (default)", async () => { +// const transactionHash = +// "0xd024750c7dcb99ace02c6b083c68d73dcfebdee252ccbeb1b83981b609693271"; + +// const result = await parseSwap({ +// publicClient, +// transactionHash, +// }); + +// expect(result).toEqual({ +// tokenIn: { +// symbol: "USDC", +// amount: "335.142587", +// address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", +// }, +// tokenOut: { +// symbol: "WETH", +// amount: "0.105662100963455883", +// address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", +// }, +// }); +// }); + +// // https://etherscan.io/tx/0x4cbcf2e2512adb7e28f19f8cf28ddc29a9f9fea93c842cf3b735eeb526fe34b3 +// test("parses swapped amounts case 5 (native sell token)", async () => { +// const transactionHash = +// "0x4cbcf2e2512adb7e28f19f8cf28ddc29a9f9fea93c842cf3b735eeb526fe34b3"; + +// const result = await parseSwap({ +// publicClient, +// transactionHash, +// }); + +// expect(result).toEqual({ +// tokenIn: { +// symbol: "ETH", +// amount: "0.04", +// address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", +// }, +// tokenOut: { +// symbol: "USDC", +// amount: "126.580558", +// address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", +// }, +// }); +// }); + +// // https://etherscan.io/tx/0x28c5bb3768bb64e81e1f3753ed1a8c30f0484a434d6c2b4af825d258ecb3bcf0 +// test("parses swapped amounts case 6 (buy DNT 404 token)", async () => { +// const transactionHash = +// "0x28c5bb3768bb64e81e1f3753ed1a8c30f0484a434d6c2b4af825d258ecb3bcf0"; + +// const result = await parseSwap({ +// publicClient, +// transactionHash, +// }); + +// expect(result).toEqual({ +// tokenIn: { +// symbol: "USDC", +// amount: "95", +// address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", +// }, +// tokenOut: { +// symbol: "CHIB", +// amount: "10.527633901274097318", +// address: "0x7068263EDa099fB93BB3215c05e728c0b54b3137", +// }, +// }); +// }); + +// // https://etherscan.io/tx/0xb8beef6bf857f2fc22905b2872120abc634900b45941478aa9cf0ad1ceffcd67 +// // https://gopluslabs.io/token-security/1/0xcf0c122c6b73ff809c693db761e7baebe62b6a2e +// test("parses swapped amounts case 6 (buy FoT token, FLOKI)", async () => { +// const transactionHash = +// "0xb8beef6bf857f2fc22905b2872120abc634900b45941478aa9cf0ad1ceffcd67"; + +// const result = await parseSwap({ +// publicClient, +// transactionHash, +// }); + +// expect(result).toEqual({ +// tokenIn: { +// symbol: "USDC", +// amount: "31.580558", +// address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", +// }, +// tokenOut: { +// symbol: "FLOKI", +// amount: "172036.330384861", +// address: "0xcf0C122c6b73ff809C693DB761e7BaeBe62b6a2E", +// }, +// }); +// }); + +// // Gasless RFQ +// // https://etherscan.io/tx/0x5dd4579b5709b405d6df935d516563e1db09453f37431639ae7e1358ec8f834d +// test("parses swapped amounts from tx settled by gasless rfq)", async () => { +// const transactionHash = +// "0x5dd4579b5709b405d6df935d516563e1db09453f37431639ae7e1358ec8f834d"; + +// const result = await parseSwap({ +// publicClient, +// transactionHash, +// }); + +// expect(result).toEqual({ +// tokenIn: { +// symbol: "USDC", +// amount: "20", +// address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", +// }, +// tokenOut: { +// symbol: "USDT", +// amount: "11.604822", +// address: "0xdAC17F958D2ee523a2206206994597C13D831ec7", +// }, +// }); +// }); + +// // https://explorer.celo.org/tx/0x615c5089f772a8f2074750e8c6070013d288af7681435aba1771f6bfc63d1286 +// test("throws an error for unsupported chains)", async () => { +// const transactionHash = +// "0x615c5089f772a8f2074750e8c6070013d288af7681435aba1771f6bfc63d1286"; + +// const publicClient = createPublicClient({ +// chain: mainnet, +// transport: http("https://rpc.ankr.com/celo"), +// }); + +// expect(async () => { +// await parseSwap({ +// publicClient, +// transactionHash, +// }); +// }).rejects.toThrowError("chainId 42220 is unsupported…"); +// }); + +// // https://basescan.org/tx/0x314ea35ef3120934ee4714f4815dc3b08dc2ab0e32e0662bfba3cdbcff14d79b +// test("parse a gasless swap on Base (DAI for USDC)", async () => { +// const publicClient = createPublicClient({ +// chain: base, +// transport: http( +// `https://base-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` +// ), +// }) as PublicClient; + +// const transactionHash = +// "0x314ea35ef3120934ee4714f4815dc3b08dc2ab0e32e0662bfba3cdbcff14d79b"; + +// const result = await parseSwap({ +// publicClient, +// transactionHash, +// }); + +// expect(result).toEqual({ +// tokenIn: { +// symbol: "DAI", +// amount: "1.998484821908329022", +// address: "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb", +// }, +// tokenOut: { +// symbol: "USDC", +// amount: "1.982641", +// address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", +// }, +// }); +// }); + +// // https://basescan.org/tx/0xa09cb1606e30c3aed8a842723fd6c23cecd838a59f750ab3dbc5ef2c7486e696 +// test("parse a swap on Base (USDC for DAI)", async () => { +// const publicClient = createPublicClient({ +// chain: base, +// transport: http( +// `https://base-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` +// ), +// }) as PublicClient; + +// const transactionHash = +// "0xa09cb1606e30c3aed8a842723fd6c23cecd838a59f750ab3dbc5ef2c7486e696"; + +// const result = await parseSwap({ +// publicClient, +// transactionHash, +// }); + +// expect(result).toEqual({ +// tokenIn: { +// symbol: "USDC", +// amount: "17.834287", +// address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", +// }, +// tokenOut: { +// symbol: "DAI", +// amount: "17.843596331665784515", +// address: "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb", +// }, +// }); +// }); + +// // https://basescan.org/tx/0xea8bca6e13f2c3e6c1e956308003b8d5da5fca44e03eac7ddbdcea271186ab37 +// test("parse a swap on Base (DEGEN for ETH)", async () => { +// const publicClient = createPublicClient({ +// chain: base, +// transport: http( +// `https://base-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` +// ), +// }) as PublicClient; + +// const transactionHash = +// "0xea8bca6e13f2c3e6c1e956308003b8d5da5fca44e03eac7ddbdcea271186ab37"; + +// const result = await parseSwap({ +// publicClient, +// transactionHash, +// }); + +// expect(result).toEqual({ +// tokenIn: { +// symbol: "DEGEN", +// amount: "3173.454530222930443426", +// address: "0x4ed4E862860beD51a9570b96d89aF5E1B0Efefed", +// }, +// tokenOut: { +// symbol: "ETH", +// amount: "0.006410046715601835", +// address: NATIVE_ETH_ADDRESS, +// }, +// }); +// }); + +// // https://basescan.org/tx/0x9e81eee3f09b79fe1e3700fdb79bf78098b6073ec17e3524498177407ac33a00 +// test("parse a swap on Base (ETH for BRETT)", async () => { +// const publicClient = createPublicClient({ +// chain: base, +// transport: http( +// `https://base-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` +// ), +// }) as PublicClient; + +// const transactionHash = +// "0x9e81eee3f09b79fe1e3700fdb79bf78098b6073ec17e3524498177407ac33a00"; + +// const result = await parseSwap({ +// publicClient, +// transactionHash, +// }); + +// expect(result).toEqual({ +// tokenIn: { +// symbol: "ETH", +// amount: "0.027500863104380774", +// address: NATIVE_ETH_ADDRESS, +// }, +// tokenOut: { +// symbol: "BRETT", +// amount: "698.405912537092209301", +// address: "0x532f27101965dd16442E59d40670FaF5eBB142E4", +// }, +// }); +// }); + +// // https://polygonscan.com/tx/0x438517b81f50858035f4b8e0870f5d797616509b5102c28814bcc378559c213d +// test("parse a gasless approval + gasless swap on Polygon (USDC for MATIC)", async () => { +// const publicClient = createPublicClient({ +// chain: polygon, +// transport: http( +// `https://polygon-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` +// ), +// }) as PublicClient; + +// const transactionHash = +// "0x438517b81f50858035f4b8e0870f5d797616509b5102c28814bcc378559c213d"; + +// const result = await parseSwap({ +// publicClient, +// transactionHash, +// }); + +// expect(result).toEqual({ +// tokenIn: { +// symbol: "USDC", +// amount: "7.79692", +// address: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", +// }, +// tokenOut: { +// symbol: "MATIC", +// amount: "15.513683571865599415", +// address: NATIVE_ETH_ADDRESS, +// }, +// }); +// }); + +// // https://basescan.org/tx/0x40fc248824e11c11debb307a68ba04ff0f068c67de07e6817f5405e055b91c44 +// test("parse a gasless swap on Base (USDC for DEGEN)", async () => { +// const publicClient = createPublicClient({ +// chain: base, +// transport: http( +// `https://base-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` +// ), +// }) as PublicClient; + +// const transactionHash = +// "0x40fc248824e11c11debb307a68ba04ff0f068c67de07e6817f5405e055b91c44"; + +// const result = await parseSwap({ +// publicClient, +// transactionHash, +// }); + +// expect(result).toEqual({ +// tokenIn: { +// symbol: "USDC", +// amount: "42.001841", +// address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", +// }, +// tokenOut: { +// symbol: "DEGEN", +// amount: "6570.195174245277347697", +// address: "0x4ed4E862860beD51a9570b96d89aF5E1B0Efefed", +// }, +// }); +// }); + +// // https://basescan.org/tx/0x14416958953850c5c5a572d6e8cb832c032d0678b3ce9da6cdce891a20864b99 +// test("parse a gasless swap on Base (USDC for ETH) for SettlerMetaTxn", async () => { +// const publicClient = createPublicClient({ +// chain: base, +// transport: http( +// `https://base-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` +// ), +// }) as PublicClient; + +// const transactionHash = +// "0x14416958953850c5c5a572d6e8cb832c032d0678b3ce9da6cdce891a20864b99"; + +// const result = await parseSwap({ +// publicClient, +// transactionHash, +// }); + +// expect(result).toEqual({ +// tokenIn: { +// symbol: "USDC", +// amount: "21.27865", +// address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", +// }, +// tokenOut: { +// symbol: "ETH", +// amount: "0.006847116541535933", +// address: NATIVE_ETH_ADDRESS, +// }, +// }); +// }); + +// // https://basescan.org/tx/0xe595dec22a7e2c2c5bdb0c1a7e59b2302ede72e5d2210c6cd7071222ea6dc2b2 +// test("parse a gasless swap on Base (DEGEN for USDC) for SettlerMetaTxn", async () => { +// const publicClient = createPublicClient({ +// chain: base, +// transport: http( +// `https://base-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` +// ), +// }) as PublicClient; + +// const transactionHash = +// "0xe595dec22a7e2c2c5bdb0c1a7e59b2302ede72e5d2210c6cd7071222ea6dc2b2"; + +// const result = await parseSwap({ +// publicClient, +// transactionHash, +// }); + +// expect(result).toEqual({ +// tokenIn: { +// symbol: "DEGEN", +// amount: "1392.424785087824779911", +// address: "0x4ed4E862860beD51a9570b96d89aF5E1B0Efefed", +// }, +// tokenOut: { +// symbol: "USDC", +// amount: "9.915288", +// address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", +// }, +// }); +// }); + +// // https://arbiscan.io/tx/0xb2c05194e4ec9ae0f82098ec82a606df544e87c8d6b7726bbb4b1dcc023cb9d7 +// test("parse a gasless swap on on Arbitrum (ARB for ETH)", async () => { +// const publicClient = createPublicClient({ +// chain: arbitrum, +// transport: http( +// `https://arb-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` +// ), +// }) as PublicClient; + +// const transactionHash = +// "0xb2c05194e4ec9ae0f82098ec82a606df544e87c8d6b7726bbb4b1dcc023cb9d7"; + +// const result = await parseSwap({ +// publicClient, +// transactionHash, +// }); + +// expect(result).toEqual({ +// tokenIn: { +// symbol: "ARB", +// amount: "1.337", +// address: "0x912CE59144191C1204E64559FE8253a0e49E6548", +// }, +// tokenOut: { +// symbol: "ETH", +// amount: "0.000304461782666722", +// address: NATIVE_ETH_ADDRESS, +// }, +// }); +// }); + +// // https://optimistic.etherscan.io/tx/0xdfd5180c9f84d8f7381f48550dd14df86dd704489c251a10a67bd3cfdb0ae626 +// test("parse a gasless swap on Optimism (USDC for OP) for executeMetaTxn", async () => { +// const publicClient = createPublicClient({ +// chain: optimism, +// transport: http( +// `https://opt-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` +// ), +// }) as PublicClient; + +// const transactionHash = +// "0xdfd5180c9f84d8f7381f48550dd14df86dd704489c251a10a67bd3cfdb0ae626"; + +// const result = await parseSwap({ +// publicClient, +// transactionHash, +// }); + +// expect(result).toEqual({ +// tokenIn: { +// symbol: "USDC", +// amount: "5", +// address: "0x7F5c764cBc14f9669B88837ca1490cCa17c31607", +// }, +// tokenOut: { +// symbol: "OP", +// amount: "2.744026666231502743", +// address: "0x4200000000000000000000000000000000000042", +// }, +// }); +// }); + +// // https://optimistic.etherscan.io/tx/0x9abc33ffc67ff9348af9a29f109c4f27b36ee5bc80dd81ae3814e69309449a61 +// test("parse a gasless swap on Optimism (USDC for OP) for execute", async () => { +// const publicClient = createPublicClient({ +// chain: optimism, +// transport: http( +// `https://opt-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` +// ), +// }) as PublicClient; + +// const transactionHash = +// "0x9abc33ffc67ff9348af9a29f109c4f27b36ee5bc80dd81ae3814e69309449a61"; + +// const result = await parseSwap({ +// publicClient, +// transactionHash, +// }); + +// expect(result).toEqual({ +// tokenIn: { +// symbol: "USDC", +// amount: "5", +// address: "0x7F5c764cBc14f9669B88837ca1490cCa17c31607", +// }, +// tokenOut: { +// symbol: "OP", +// amount: "2.73214427938472425", +// address: "0x4200000000000000000000000000000000000042", +// }, +// }); +// }); + +// // https://bscscan.com/tx/0xdda12da1e32c3320082355c985d6f2c6559169989de51e3cc83123395516c057 +// test("parse a swap on BNB Chain (ETH for USDC) for execute", async () => { +// const publicClient = createPublicClient({ +// chain: optimism, +// transport: http( +// `https://bnb-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` +// ), +// }) as PublicClient; + +// const transactionHash = +// "0xdda12da1e32c3320082355c985d6f2c6559169989de51e3cc83123395516c057"; + +// const result = await parseSwap({ +// publicClient, +// transactionHash, +// }); + +// expect(result).toEqual({ +// tokenIn: { +// symbol: "ETH", +// amount: "0.728252933682622857", +// address: "0x2170Ed0880ac9A755fd29B2688956BD959F933F8", +// }, +// tokenOut: { +// symbol: "USDC", +// amount: "2260.511889276471849176", +// address: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d", +// }, +// }); +// }); + +// // Smart Contract Wallet +// test("throws when smart contract wallet is not passed", async () => { +// const publicClient = createPublicClient({ +// chain: base, +// transport: http( +// `https://base-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` +// ), +// }) as PublicClient; + +// const transactionHash = +// "0x756289cdedd4c007268ef208fe2758a9fb6efd49fb241397b67089512b497662"; + +// expect(async () => { +// await parseSwap({ +// publicClient, +// transactionHash, +// }); +// }).rejects.toThrowError( +// "This is an ERC-4337 transaction. You must provide a smart contract wallet address to 0x-parser." +// ); +// }); + +// https://basescan.org/tx/0x756289cdedd4c007268ef208fe2758a9fb6efd49fb241397b67089512b497662 +test("parse a swap on Base (DEGEN for BRETT) with smart contract wallet", async () => { const publicClient = createPublicClient({ chain: base, transport: http( @@ -331,122 +663,30 @@ test("parse a swap on Base (DEGEN for ETH)", async () => { }) as PublicClient; const transactionHash = - "0xea8bca6e13f2c3e6c1e956308003b8d5da5fca44e03eac7ddbdcea271186ab37"; + "0x756289cdedd4c007268ef208fe2758a9fb6efd49fb241397b67089512b497662"; const result = await parseSwap({ publicClient, transactionHash, + smartContractWalletAddress: "0x3F6dAB60Cc16377Df9684959e20962f44De20988", }); expect(result).toEqual({ tokenIn: { symbol: "DEGEN", - amount: "3173.454530222930443426", + amount: "882.414233540058884907", address: "0x4ed4E862860beD51a9570b96d89aF5E1B0Efefed", }, - tokenOut: { - symbol: "ETH", - amount: "0.006410046715601835", - address: NATIVE_ETH_ADDRESS, - }, - }); -}); - -// https://basescan.org/tx/0x9e81eee3f09b79fe1e3700fdb79bf78098b6073ec17e3524498177407ac33a00 -test("parse a swap on Base (ETH for BRETT)", async () => { - const publicClient = createPublicClient({ - chain: base, - transport: http( - `https://base-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` - ), - }) as PublicClient; - - const transactionHash = - "0x9e81eee3f09b79fe1e3700fdb79bf78098b6073ec17e3524498177407ac33a00"; - - const result = await parseSwap({ - publicClient, - transactionHash, - }); - - expect(result).toEqual({ - tokenIn: { - symbol: "ETH", - amount: "0.027500863104380774", - address: NATIVE_ETH_ADDRESS, - }, tokenOut: { symbol: "BRETT", - amount: "698.405912537092209301", + amount: "48.014669721245576995", address: "0x532f27101965dd16442E59d40670FaF5eBB142E4", }, }); }); -// https://polygonscan.com/tx/0x438517b81f50858035f4b8e0870f5d797616509b5102c28814bcc378559c213d -test("parse a gasless approval + gasless swap on Polygon (USDC for MATIC)", async () => { - const publicClient = createPublicClient({ - chain: polygon, - transport: http( - `https://polygon-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` - ), - }) as PublicClient; - - const transactionHash = - "0x438517b81f50858035f4b8e0870f5d797616509b5102c28814bcc378559c213d"; - - const result = await parseSwap({ - publicClient, - transactionHash, - }); - - expect(result).toEqual({ - tokenIn: { - symbol: "USDC", - amount: "7.79692", - address: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", - }, - tokenOut: { - symbol: "MATIC", - amount: "15.513683571865599415", - address: NATIVE_ETH_ADDRESS, - }, - }); -}); - -// https://basescan.org/tx/0x40fc248824e11c11debb307a68ba04ff0f068c67de07e6817f5405e055b91c44 -test("parse a gasless swap on Base (USDC for DEGEN)", async () => { - const publicClient = createPublicClient({ - chain: base, - transport: http( - `https://base-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` - ), - }) as PublicClient; - - const transactionHash = - "0x40fc248824e11c11debb307a68ba04ff0f068c67de07e6817f5405e055b91c44"; - - const result = await parseSwap({ - publicClient, - transactionHash, - }); - - expect(result).toEqual({ - tokenIn: { - symbol: "USDC", - amount: "42.001841", - address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", - }, - tokenOut: { - symbol: "DEGEN", - amount: "6570.195174245277347697", - address: "0x4ed4E862860beD51a9570b96d89aF5E1B0Efefed", - }, - }); -}); - -// https://basescan.org/tx/0x14416958953850c5c5a572d6e8cb832c032d0678b3ce9da6cdce891a20864b99 -test("parse a gasless swap on Base (USDC for ETH) for SettlerMetaTxn", async () => { +// https://basescan.org/tx/0xaa09479aafdb1a33815fb3842c350ccedf5e3f9eaec31b8cba1f41eea674a8f3 +test("parse a swap on Base (BRETT for ETH) with smart contract wallet", async () => { const publicClient = createPublicClient({ chain: base, transport: http( @@ -455,29 +695,30 @@ test("parse a gasless swap on Base (USDC for ETH) for SettlerMetaTxn", async () }) as PublicClient; const transactionHash = - "0x14416958953850c5c5a572d6e8cb832c032d0678b3ce9da6cdce891a20864b99"; + "0xaa09479aafdb1a33815fb3842c350ccedf5e3f9eaec31b8cba1f41eea674a8f3"; const result = await parseSwap({ publicClient, transactionHash, + smartContractWalletAddress: "0x3F6dAB60Cc16377Df9684959e20962f44De20988", }); expect(result).toEqual({ tokenIn: { - symbol: "USDC", - amount: "21.27865", - address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + symbol: "BRETT", + amount: "48.014669721245576995", + address: "0x532f27101965dd16442E59d40670FaF5eBB142E4", }, tokenOut: { symbol: "ETH", - amount: "0.006847116541535933", + amount: "0.001482901054900327", address: NATIVE_ETH_ADDRESS, }, }); }); -// https://basescan.org/tx/0x29b3f7bcd154e20e050793aa62d90309a860296aa846fd1158dc21356d1a3deb -test("parse a gasless swap on Base (weirdo for ETH) for SettlerMetaTxn", async () => { +// https://basescan.org/tx/0xe289a22987dcedfacb13584211c1d723ef5c42ea6e0dfd5c4d3271d20dec9ddc +test("parse a swap on Base (ETH for USDC) with smart contract wallet", async () => { const publicClient = createPublicClient({ chain: base, transport: http( @@ -486,178 +727,24 @@ test("parse a gasless swap on Base (weirdo for ETH) for SettlerMetaTxn", async ( }) as PublicClient; const transactionHash = - "0x29b3f7bcd154e20e050793aa62d90309a860296aa846fd1158dc21356d1a3deb"; + "0xe289a22987dcedfacb13584211c1d723ef5c42ea6e0dfd5c4d3271d20dec9ddc"; const result = await parseSwap({ publicClient, transactionHash, + smartContractWalletAddress: "0x3F6dAB60Cc16377Df9684959e20962f44De20988", }); expect(result).toEqual({ tokenIn: { - symbol: "weirdo", - amount: "3145398.30971883", - address: "0x76734B57dFe834F102fB61E1eBF844Adf8DD931e", - }, - tokenOut: { symbol: "ETH", - amount: "0.039633073597929391", + amount: "0.001", address: NATIVE_ETH_ADDRESS, }, - }); -}); - -// https://basescan.org/tx/0xe595dec22a7e2c2c5bdb0c1a7e59b2302ede72e5d2210c6cd7071222ea6dc2b2 -test("parse a gasless swap on Base (DEGEN for USDC) for SettlerMetaTxn", async () => { - const publicClient = createPublicClient({ - chain: base, - transport: http( - `https://base-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` - ), - }) as PublicClient; - - const transactionHash = - "0xe595dec22a7e2c2c5bdb0c1a7e59b2302ede72e5d2210c6cd7071222ea6dc2b2"; - - const result = await parseSwap({ - publicClient, - transactionHash, - }); - - expect(result).toEqual({ - tokenIn: { - symbol: "DEGEN", - amount: "1392.424785087824779911", - address: "0x4ed4E862860beD51a9570b96d89aF5E1B0Efefed", - }, tokenOut: { symbol: "USDC", - amount: "9.915288", + amount: "2.600807", address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", }, }); }); - -// https://arbiscan.io/tx/0xb2c05194e4ec9ae0f82098ec82a606df544e87c8d6b7726bbb4b1dcc023cb9d7 -test("parse a gasless swap on on Arbitrum (ARB for ETH)", async () => { - const publicClient = createPublicClient({ - chain: arbitrum, - transport: http( - `https://arb-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` - ), - }) as PublicClient; - - const transactionHash = - "0xb2c05194e4ec9ae0f82098ec82a606df544e87c8d6b7726bbb4b1dcc023cb9d7"; - - const result = await parseSwap({ - publicClient, - transactionHash, - }); - - expect(result).toEqual({ - tokenIn: { - symbol: "ARB", - amount: "1.337", - address: "0x912CE59144191C1204E64559FE8253a0e49E6548", - }, - tokenOut: { - symbol: "ETH", - amount: "0.000304461782666722", - address: NATIVE_ETH_ADDRESS, - }, - }); -}); - -// https://optimistic.etherscan.io/tx/0xdfd5180c9f84d8f7381f48550dd14df86dd704489c251a10a67bd3cfdb0ae626 -test("parse a gasless swap on Optimism (USDC for OP) for executeMetaTxn", async () => { - const publicClient = createPublicClient({ - chain: optimism, - transport: http( - `https://opt-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` - ), - }) as PublicClient; - - const transactionHash = - "0xdfd5180c9f84d8f7381f48550dd14df86dd704489c251a10a67bd3cfdb0ae626"; - - const result = await parseSwap({ - publicClient, - transactionHash, - }); - - expect(result).toEqual({ - tokenIn: { - symbol: "USDC", - amount: "5", - address: "0x7F5c764cBc14f9669B88837ca1490cCa17c31607", - }, - tokenOut: { - symbol: "OP", - amount: "2.744026666231502743", - address: "0x4200000000000000000000000000000000000042", - }, - }); -}); - -// https://optimistic.etherscan.io/tx/0x9abc33ffc67ff9348af9a29f109c4f27b36ee5bc80dd81ae3814e69309449a61 -test("parse a gasless swap on Optimism (USDC for OP) for execute", async () => { - const publicClient = createPublicClient({ - chain: optimism, - transport: http( - `https://opt-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` - ), - }) as PublicClient; - - const transactionHash = - "0x9abc33ffc67ff9348af9a29f109c4f27b36ee5bc80dd81ae3814e69309449a61"; - - const result = await parseSwap({ - publicClient, - transactionHash, - }); - - expect(result).toEqual({ - tokenIn: { - symbol: "USDC", - amount: "5", - address: "0x7F5c764cBc14f9669B88837ca1490cCa17c31607", - }, - tokenOut: { - symbol: "OP", - amount: "2.73214427938472425", - address: "0x4200000000000000000000000000000000000042", - }, - }); -}); - -// https://bscscan.com/tx/0xdda12da1e32c3320082355c985d6f2c6559169989de51e3cc83123395516c057 -test("parse a swap on BNB Chain (ETH for USDC) for execute", async () => { - const publicClient = createPublicClient({ - chain: optimism, - transport: http( - `https://bnb-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}` - ), - }) as PublicClient; - - const transactionHash = - "0xdda12da1e32c3320082355c985d6f2c6559169989de51e3cc83123395516c057"; - - const result = await parseSwap({ - publicClient, - transactionHash, - }); - - expect(result).toEqual({ - tokenIn: { - symbol: "ETH", - amount: "0.728252933682622857", - address: "0x2170Ed0880ac9A755fd29B2688956BD959F933F8", - }, - tokenOut: { - symbol: "USDC", - amount: "2260.511889276471849176", - address: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d", - }, - }); -}); diff --git a/src/utils/index.ts b/src/utils/index.ts index 9057ba5..84b9785 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,5 +1,5 @@ import { fromHex, erc20Abi, getAddress, formatUnits, formatEther } from "viem"; -import type { Address } from "viem"; +import type { Address, TransactionReceipt } from "viem"; import type { Trace, EnrichLogsArgs, SupportedChainId } from "../types"; export function isChainIdSupported( @@ -13,12 +13,16 @@ export function extractNativeTransfer(trace: Trace, recipient: Address) { function traverseCalls(calls: Trace[]) { calls.forEach((call) => { + if (call.value === undefined) { + return; + } if ( call.to.toLowerCase() === recipient.toLowerCase() && fromHex(call.value, "bigint") > 0n ) { totalTransferred = totalTransferred + fromHex(call.value, "bigint"); } + if (call.calls && call.calls.length > 0) { traverseCalls(call.calls); } @@ -30,6 +34,51 @@ export function extractNativeTransfer(trace: Trace, recipient: Address) { return formatEther(totalTransferred); } +export function extractNativeTransfer2(trace: Trace, recipient: Address) { + let totalTransferred = 0n; + + function traverseCalls(calls: Trace[]) { + calls.forEach((call) => { + if (call.value === undefined) { + return; + } + if ( + call.from.toLowerCase() === recipient.toLowerCase() && + fromHex(call.value, "bigint") > 0n + ) { + totalTransferred = totalTransferred + fromHex(call.value, "bigint"); + } + + if (call.calls && call.calls.length > 0) { + traverseCalls(call.calls); + } + }); + } + + traverseCalls(trace.calls); + + return formatEther(totalTransferred); +} + +export function getTransferLogs({ + transactionReceipt, +}: { + transactionReceipt: TransactionReceipt; +}) { + const EVENT_SIGNATURES = { + Transfer: + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + } as const; + const { logs } = transactionReceipt; + + return logs + .filter((log) => log.topics[0] === EVENT_SIGNATURES.Transfer) + .map((log) => ({ + ...log, + address: getAddress(log.address), + })); +} + export async function transferLogs({ publicClient, transactionReceipt, @@ -43,14 +92,10 @@ export async function transferLogs({ decimals: number; }[] > { - const EVENT_SIGNATURES = { - Transfer: - "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", - } as const; - const { logs } = transactionReceipt; - const transferLogsAddresses = logs - .filter((log) => log.topics[0] === EVENT_SIGNATURES.Transfer) - .map((log) => ({ ...log, address: getAddress(log.address) })); + const transferLogsAddresses = getTransferLogs({ + transactionReceipt, + }); + const contracts = [ ...transferLogsAddresses.map((log) => ({ abi: erc20Abi,