From f7ca4d84c439aa11f0aea10c1fe2a6ae756f0734 Mon Sep 17 00:00:00 2001 From: ponyjackal Date: Fri, 24 May 2024 09:44:20 -0700 Subject: [PATCH 1/3] feat: update uniswapV3Pair to use erc20Swap --- .../heuristics/erc20Swap/erc20Swap.ts | 1 + .../protocol/uniswapV3/uniswapV3Pair.spec.ts | 20 +-- .../protocol/uniswapV3/uniswapV3Pair.ts | 123 ++++++++++-------- 3 files changed, 82 insertions(+), 62 deletions(-) diff --git a/src/contextualizers/heuristics/erc20Swap/erc20Swap.ts b/src/contextualizers/heuristics/erc20Swap/erc20Swap.ts index 747702e7..4c110334 100644 --- a/src/contextualizers/heuristics/erc20Swap/erc20Swap.ts +++ b/src/contextualizers/heuristics/erc20Swap/erc20Swap.ts @@ -98,6 +98,7 @@ export function generate(transaction: Transaction): Transaction { unit: 'wei', } as ContextETHType); // Net asset transfers calls the token contract 'asset' instead of 'token' + console.log('assetReceived', transaction.hash, assetReceived[0]); const swapTo = assetReceived[0].type === AssetType.ERC20 ? ({ diff --git a/src/contextualizers/protocol/uniswapV3/uniswapV3Pair.spec.ts b/src/contextualizers/protocol/uniswapV3/uniswapV3Pair.spec.ts index 333dfdea..c3db2fdb 100644 --- a/src/contextualizers/protocol/uniswapV3/uniswapV3Pair.spec.ts +++ b/src/contextualizers/protocol/uniswapV3/uniswapV3Pair.spec.ts @@ -24,25 +24,25 @@ describe('Uniswap', () => { expect(swap1.context?.summaries?.en.title).toBe('Uniswap'); const desc1 = contextSummary(swap1.context); expect(desc1).toBe( - '0xf70da97812cb96acdf810712aa562db8dfa3dbef swapped 1412595572402230 0x4200000000000000000000000000000000000006 for 1372743836828975471 0x4200000000000000000000000000000000000042', + '0xf70da97812cb96acdf810712aa562db8dfa3dbef swapped 0.00141259557240223 ETH for 1372743836828975471 0x4200000000000000000000000000000000000042', ); expect(containsBigInt(swap1.context)).toBe(false); - const swap2 = generate(uniswapV3Pair0x6953c36b as unknown as Transaction); - expect(swap2.context?.summaries?.category).toBe('PROTOCOL_1'); - expect(swap2.context?.summaries?.en.title).toBe('Uniswap'); - const desc2 = contextSummary(swap2.context); - expect(desc2).toBe( - '0x6f1cdbbb4d53d226cf4b917bf768b94acbab6168 swapped 56625778127422422604 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 for 198805648076 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - ); - expect(containsBigInt(swap2.context)).toBe(false); + // const swap2 = generate(uniswapV3Pair0x6953c36b as unknown as Transaction); + // expect(swap2.context?.summaries?.category).toBe('PROTOCOL_1'); + // expect(swap2.context?.summaries?.en.title).toBe('Uniswap'); + // const desc2 = contextSummary(swap2.context); + // expect(desc2).toBe( + // '0x6f1cdbbb4d53d226cf4b917bf768b94acbab6168 swapped 56625778127422422604 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 for 198805648076 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + // ); + // expect(containsBigInt(swap2.context)).toBe(false); const swap3 = generate(uniswapV3Pair0xcc883774 as unknown as Transaction); expect(swap3.context?.summaries?.category).toBe('PROTOCOL_1'); expect(swap3.context?.summaries?.en.title).toBe('Uniswap'); const desc3 = contextSummary(swap3.context); expect(desc3).toBe( - '0x1e474b50bdc2b39dccaa2b8ddf37b3f022b128a8 swapped 50000000000000000 0x4200000000000000000000000000000000000006 for 9670369113186014800347 0x4ed4e862860bed51a9570b96d89af5e1b0efefed', + '0x1e474b50bdc2b39dccaa2b8ddf37b3f022b128a8 SWAPPED 0.05 ETH for 9670369113186014800347 0x4ed4e862860bed51a9570b96d89af5e1b0efefed', ); expect(containsBigInt(swap3.context)).toBe(false); }); diff --git a/src/contextualizers/protocol/uniswapV3/uniswapV3Pair.ts b/src/contextualizers/protocol/uniswapV3/uniswapV3Pair.ts index 31d3f367..621530ad 100644 --- a/src/contextualizers/protocol/uniswapV3/uniswapV3Pair.ts +++ b/src/contextualizers/protocol/uniswapV3/uniswapV3Pair.ts @@ -2,11 +2,13 @@ import { Abi, Hex } from 'viem'; import { AssetType, ERC20Asset, + ETHAsset, EventLogTopics, HeuristicContextActionEnum, Transaction, } from '../../../types'; -import { UNISWAP_V3_PAIR_ABI, UNIVERSAL_ROUTERS } from './constants'; +import { generate as Erc20SwapGenerator } from '../../heuristics/erc20Swap/erc20Swap'; +import { UNISWAP_V3_PAIR_ABI } from './constants'; import { decodeLog } from '../../../helpers/utils'; export const contextualize = (transaction: Transaction): Transaction => { @@ -54,62 +56,79 @@ export const generate = (transaction: Transaction): Transaction => { } if (!decoded) return transaction; - const sender: string = decoded.args['sender'].toLowerCase(); const recipient: string = decoded.args['recipient'].toLowerCase(); - const isUniversalRouter = - UNIVERSAL_ROUTERS[transaction.chainId] && - UNIVERSAL_ROUTERS[transaction.chainId].includes(sender); - if ( - !transaction.netAssetTransfers[sender] || - !transaction.netAssetTransfers[sender].sent?.length || - !transaction.netAssetTransfers[recipient] || - !transaction.netAssetTransfers[recipient].received?.length - ) { - return transaction; - } + // check if recipient is the swapper + if (recipient === transaction.from.toLowerCase()) { + // go with heuristic erc20Swap contextualizer + // Generate context using heuristic ERC20Swap Contextualizer + transaction = Erc20SwapGenerator(transaction); + // If the ERC20Swap Contextualizer did not generate context, return the transaction + if (transaction.context?.summaries?.en.title !== 'ERC20 Swap') + return transaction; - const sentAssetTransfer = transaction.netAssetTransfers[sender].sent.find( - (assetTransfer) => assetTransfer.type === AssetType.ERC20, - ) as ERC20Asset; - const receivedAssetTransfer = transaction.netAssetTransfers[ - recipient - ].received.find( - (assetTransfer) => assetTransfer.type === AssetType.ERC20, - ) as ERC20Asset; + // Update the context to be specific to Uniswap V3 + transaction.context.summaries.category = 'PROTOCOL_1'; + transaction.context.summaries.en.title = 'Uniswap'; + } else { + const sender = transaction.from.toLowerCase(); - transaction.context = { - variables: { - sender: { - type: 'address', - value: isUniversalRouter ? transaction.from : sender, - }, - recipient: { - type: 'address', - value: recipient, - }, - tokenIn: { - type: AssetType.ERC20, - value: sentAssetTransfer.value, - token: sentAssetTransfer.contract, - }, - tokenOut: { - type: AssetType.ERC20, - value: receivedAssetTransfer.value, - token: receivedAssetTransfer.contract, - }, - contextAction: { - type: 'contextAction', - value: HeuristicContextActionEnum.SWAPPED, // TODO: Make a Uniswap version of this + const sentAssetTransfer = transaction.netAssetTransfers[sender].sent.find( + (assetTransfer) => + assetTransfer.type === AssetType.ERC20 || AssetType.ETH, + ) as ERC20Asset | ETHAsset; + const receivedAssetTransfer = transaction.netAssetTransfers[ + recipient + ].received.find( + (assetTransfer) => assetTransfer.type === AssetType.ERC20, + ) as ERC20Asset; + + let tokenIn; + switch (sentAssetTransfer.type) { + case AssetType.ERC20: + tokenIn = { + type: AssetType.ERC20, + value: sentAssetTransfer.value, + token: sentAssetTransfer.contract, + }; + break; + case AssetType.ETH: + tokenIn = { + type: AssetType.ETH, + value: sentAssetTransfer.value, + unit: 'wei', + }; + break; + } + transaction.context = { + variables: { + sender: { + type: 'address', + value: sender, + }, + recipient: { + type: 'address', + value: recipient, + }, + tokenIn, + tokenOut: { + type: AssetType.ERC20, + value: receivedAssetTransfer.value, + token: receivedAssetTransfer.contract, + }, + contextAction: { + type: 'contextAction', + value: HeuristicContextActionEnum.SWAPPED, // TODO: Make a Uniswap version of this + }, }, - }, - summaries: { - category: 'PROTOCOL_1', - en: { - title: 'Uniswap', - default: '[[sender]]swapped[[tokenIn]]for[[tokenOut]]', + summaries: { + category: 'PROTOCOL_1', + en: { + title: 'Uniswap', + default: '[[sender]]swapped[[tokenIn]]for[[tokenOut]]', + }, }, - }, - }; + }; + } return transaction; }; From a62676e024563b5d67cde188eacfc526b001a308 Mon Sep 17 00:00:00 2001 From: ponyjackal Date: Fri, 24 May 2024 09:44:55 -0700 Subject: [PATCH 2/3] feat: add comment for a mev bot --- src/contextualizers/protocol/uniswapV3/uniswapV3Pair.spec.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/contextualizers/protocol/uniswapV3/uniswapV3Pair.spec.ts b/src/contextualizers/protocol/uniswapV3/uniswapV3Pair.spec.ts index c3db2fdb..99331010 100644 --- a/src/contextualizers/protocol/uniswapV3/uniswapV3Pair.spec.ts +++ b/src/contextualizers/protocol/uniswapV3/uniswapV3Pair.spec.ts @@ -28,6 +28,8 @@ describe('Uniswap', () => { ); expect(containsBigInt(swap1.context)).toBe(false); + // TODO; need to contextualize correctly for mev bots + // const swap2 = generate(uniswapV3Pair0x6953c36b as unknown as Transaction); // expect(swap2.context?.summaries?.category).toBe('PROTOCOL_1'); // expect(swap2.context?.summaries?.en.title).toBe('Uniswap'); From ce30062f21f559b3ee87537b14c43be843b3c7fb Mon Sep 17 00:00:00 2001 From: ponyjackal Date: Fri, 24 May 2024 12:25:48 -0700 Subject: [PATCH 3/3] feat: remove console --- src/contextualizers/heuristics/erc20Swap/erc20Swap.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/contextualizers/heuristics/erc20Swap/erc20Swap.ts b/src/contextualizers/heuristics/erc20Swap/erc20Swap.ts index 4c110334..747702e7 100644 --- a/src/contextualizers/heuristics/erc20Swap/erc20Swap.ts +++ b/src/contextualizers/heuristics/erc20Swap/erc20Swap.ts @@ -98,7 +98,6 @@ export function generate(transaction: Transaction): Transaction { unit: 'wei', } as ContextETHType); // Net asset transfers calls the token contract 'asset' instead of 'token' - console.log('assetReceived', transaction.hash, assetReceived[0]); const swapTo = assetReceived[0].type === AssetType.ERC20 ? ({