UNPKG

mev-inspect

Version:

A JS port of 'mev-inspect-py' optimised for ease of use.

267 lines 7.97 kB
import { Contract } from 'ethcall'; import poolAbi from '../../abi/uniswapV3Pool.js'; import { equalWithTolerance } from '../../utils.js'; import { getLatestPoolTransfer, } from '../base.js'; function isSwapValid(event) { return event.name === 'Swap'; } function isLiquidityDepositValid(event) { return event.name === 'Mint'; } function isLiquidityWithdrawalValid(event) { return event.name === 'Collect'; } function getPoolCalls(address) { const poolContract = new Contract(address, poolAbi); const factoryCall = poolContract.factory(); const asset0Call = poolContract.token0(); const asset1Call = poolContract.token1(); return [factoryCall, asset0Call, asset1Call]; } function processPoolCalls(result) { const factory = result[0]; const asset0 = result[1]; const asset1 = result[2]; if (!factory || !asset0 || !asset1) { return null; } const assets = [asset0.toLowerCase(), asset1.toLowerCase()]; return { factoryAddress: factory.toLowerCase(), assets, }; } function parseSwap(pool, event, transfers) { const { values, transactionFrom, transactionHash: hash, transactionIndex, gasUsed, logIndex, address, blockHash, blockNumber, } = event; const { address: poolAddress, assets } = pool; const poolTransfer = getLatestPoolTransfer(poolAddress, logIndex, transfers); if (!poolTransfer) { return null; } const from = poolTransfer.from; const to = values.recipient.toLowerCase(); const amount0 = values.amount0; const amount1 = values.amount1; const tick = values.tick; const assetOut = amount0 < 0 ? assets[0] : assets[1]; const amountOut = amount0 < 0 ? amount0 * -1n : amount1 * -1n; const assetIn = amount0 > 0 ? assets[0] : assets[1]; const amountIn = amount0 > 0 ? amount0 : amount1; if (poolTransfer.event.address !== assetIn) { return null; } if (!equalWithTolerance(poolTransfer.value, amountIn, 0.001)) { return null; } return { contract: { address: pool.address, protocol: { abi: 'UniswapV3', factory: pool.factory, }, }, block: { hash: blockHash, number: blockNumber, }, transaction: { from: transactionFrom.toLowerCase(), hash, index: transactionIndex, gasUsed, }, event: { address: address.toLowerCase(), logIndex, }, from, to, assetIn: { type: 'erc20', address: assetIn, }, amountIn, assetOut: { type: 'erc20', address: assetOut, }, amountOut, metadata: { tick, }, }; } function parseLiquidityDeposit(pool, event, transfers) { const { values, transactionFrom, transactionHash: hash, transactionIndex, gasUsed, logIndex, address, blockHash, blockNumber, } = event; const { assets } = pool; const amount0 = values.amount0; const amount1 = values.amount1; const tickLower = values.tickLower; const tickUpper = values.tickUpper; const amounts = [amount0, amount1]; const depositor = getDepositor(assets, amounts, logIndex, address, transfers); if (!depositor) { return null; } return { contract: { address: pool.address, protocol: { abi: 'UniswapV3', factory: pool.factory, }, }, block: { hash: blockHash, number: blockNumber, }, transaction: { from: transactionFrom.toLowerCase(), hash, index: transactionIndex, gasUsed, }, event: { address: address.toLowerCase(), logIndex, }, depositor, assets: assets.map((asset) => { return { type: 'erc20', address: asset, }; }), amounts, metadata: { tickLower, tickUpper, }, }; } function parseLiquidityWithdrawal(pool, event, transfers) { const { values, transactionFrom, transactionHash: hash, transactionIndex, gasUsed, logIndex, address, blockHash, blockNumber, } = event; const { assets } = pool; const amount0 = values.amount0; const amount1 = values.amount1; const tickLower = values.tickLower; const tickUpper = values.tickUpper; const amounts = [amount0, amount1]; const withdrawer = getWithdrawer(assets, amounts, logIndex, address, transfers); if (!withdrawer) { return null; } return { contract: { address: pool.address, protocol: { abi: 'UniswapV3', factory: pool.factory, }, }, block: { hash: blockHash, number: blockNumber, }, transaction: { from: transactionFrom.toLowerCase(), hash, index: transactionIndex, gasUsed, }, event: { address: address.toLowerCase(), logIndex, }, withdrawer, assets: assets.map((asset) => { return { type: 'erc20', address: asset, }; }), amounts, metadata: { tickLower, tickUpper, }, }; } function getDepositor(assets, amounts, logIndex, address, transfers) { const transferA = transfers.find((transfer) => transfer.event.logIndex === logIndex - 2); const transferB = transfers.find((transfer) => transfer.event.logIndex === logIndex - 1); if (!transferA || !transferB) { return null; } if (transferA.to !== address || transferB.to !== address) { return null; } if (transferA.asset !== assets[0] || transferB.asset !== assets[1]) { return null; } if (transferA.value !== amounts[0] || transferB.value !== amounts[1]) { return null; } if (transferA.from !== transferB.from) { return null; } return transferA.from; } function getWithdrawer(assets, amounts, logIndex, address, transfers) { const transferA = transfers.find((transfer) => transfer.event.logIndex === logIndex - 2); const transferB = transfers.find((transfer) => transfer.event.logIndex === logIndex - 1); if (!transferA || !transferB) { return null; } if (transferA.from !== address || transferB.from !== address) { return null; } if (transferA.asset !== assets[0] || transferB.asset !== assets[1]) { return null; } if (transferA.value !== amounts[0] || transferB.value !== amounts[1]) { return null; } if (transferA.to !== transferB.to) { return null; } return transferA.to; } const CLASSIFIER = { swap: { type: 'swap', protocol: 'UniswapV3', abi: poolAbi, isValid: isSwapValid, parse: parseSwap, pool: { getCalls: getPoolCalls, processCalls: processPoolCalls, }, }, liquidityDeposit: { type: 'liquidity_deposit', protocol: 'UniswapV3', abi: poolAbi, isValid: isLiquidityDepositValid, parse: parseLiquidityDeposit, pool: { getCalls: getPoolCalls, processCalls: processPoolCalls, }, }, liquidityWithdrawal: { type: 'liquidity_withdrawal', protocol: 'UniswapV3', abi: poolAbi, isValid: isLiquidityWithdrawalValid, parse: parseLiquidityWithdrawal, pool: { getCalls: getPoolCalls, processCalls: processPoolCalls, }, }, }; export default CLASSIFIER; //# sourceMappingURL=uniswapV3.js.map