如何监听Uniswap V2(Base/以太坊链)上的addLiquidityETH交易?
监听Uniswap V2 Router02交易的解决方案
核心思路
Uniswap V2 Router02的addLiquidityETH方法本身没有专属触发事件,但可以通过两种可靠方式追踪这类交易:监听交易日志中的函数签名,或者监听Pair合约的Mint事件(添加流动性最终会在Pair合约中铸造LP代币)。
方法1:通过函数签名过滤Router02交易
以太坊兼容链上的智能合约调用都有函数签名(前4字节的Keccak256哈希),addLiquidityETH的函数签名为0xf305d719。直接监听链上发送到Router02地址的交易,过滤出调用该函数的请求即可。
实现步骤
- 确认目标链的Router02地址:
- 以太坊主网:
0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D - Base主网:
0x3a6d8cA21D1CF76F653A67577FA0D27453350dD8
- 以太坊主网:
- 使用链节点(自建或第三方服务)的交易订阅API,过滤两个条件:
- 交易的
to字段等于Router02地址 - 交易数据的前4字节等于
0xf305d719
- 交易的
- 符合条件的交易,用Web3.js/Ethers.js的ABI解码功能解析代币地址、ETH金额等参数。
代码示例(Ethers.js v6)
import { ethers } from "ethers"; const provider = new ethers.JsonRpcProvider("你的Base/以太坊节点URL"); const routerAddress = "0x3a6d8cA21D1CF76F653A67577FA0D27453350dD8"; // Base链Router02 const addLiquidityETHSelector = "0xf305d719"; // 订阅新块交易 provider.on("block", async (blockNumber) => { const block = await provider.getBlock(blockNumber, true); for (const tx of block.transactions) { if (tx.to === routerAddress && tx.data.startsWith(addLiquidityETHSelector)) { // 解析交易参数 const iface = new ethers.Interface([ "function addLiquidityETH(address token, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline) payable returns (uint amountToken, uint amountETH, uint liquidity)" ]); const params = iface.decodeFunctionData("addLiquidityETH", tx.data); console.log("新增流动性代币:", params.token); console.log("ETH金额:", ethers.formatEther(tx.value)); } } });
方法2:监听Pair合约的Mint事件
所有新增流动性操作都会在对应Uniswap V2 Pair合约中触发Mint事件(签名:event Mint(address indexed sender, uint amount0, uint amount1))。这种方式更直接,还能覆盖直接调用Pair合约的流动性添加操作。
实现步骤
- 先订阅Uniswap V2 Factory合约的
PairCreated事件,发现新创建的Pair合约 - 对每个新Pair,动态订阅其
Mint事件 - 获取
Mint事件关联的交易,确认是否由Router02发起(检查交易的to字段)
代码示例(Ethers.js v6)
import { ethers } from "ethers"; const provider = new ethers.JsonRpcProvider("你的Base/以太坊节点URL"); const factoryAddress = "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f"; // Uniswap V2 Factory(Base/以太坊通用) const routerAddress = "0x3a6d8cA21D1CF76F653A67577FA0D27453350dD8"; // Base链Router02 // 订阅新Pair创建事件 const factoryIface = new ethers.Interface([ "event PairCreated(address indexed token0, address indexed token1, address pair, uint)" ]); provider.on(factoryAddress, (log) => { try { const event = factoryIface.parseLog(log); const pairAddress = event.args.pair; // 订阅该Pair的Mint事件 const pairIface = new ethers.Interface([ "event Mint(address indexed sender, uint amount0, uint amount1)" ]); provider.on(pairAddress, (log) => { const mintEvent = pairIface.parseLog(log); // 验证交易是否来自Router02 provider.getTransaction(log.transactionHash).then(tx => { if (tx.to === routerAddress) { console.log("Router02新增流动性,Pair地址:", pairAddress); console.log("代币0:", event.args.token0, "金额:", ethers.formatUnits(mintEvent.args.amount0, 18)); console.log("代币1:", event.args.token1, "金额:", ethers.formatUnits(mintEvent.args.amount1, 18)); } }); }); } catch (e) { // 忽略非PairCreated事件 } });
注意事项
- 确保节点支持全交易日志订阅,部分免费节点可能限制订阅频率或历史数据访问
- Base链区块生成速度更快,需优化代码性能避免阻塞
- 可同时结合两种方法,互相验证提升监听准确性
内容的提问来源于stack exchange,提问作者TiltedGamer
相关产品推荐
相关产品推荐

