如何在Web3单交易中完成买卖以检测蜜罐代币?
单次交易完成代币买卖检测蜜罐方案及优化检测方法
一、单交易内完成买入+卖出的可行性与实现方案
完全可以通过Web3实现,核心是将买入、授权、卖出操作打包进同一笔交易,两种常用方案如下:
方式1:Multicall批量调用(无需自定义合约)
利用Multicall合约将多个操作合并,步骤为授权Router花费代币→买入代币→卖出代币,适合快速验证:
from web3 import Web3 import time # 初始化配置 web3 = Web3(Web3.HTTPProvider("YOUR_BSC_RPC_URL")) pan_router = web3.eth.contract(address=panRouterContractAddress, abi=panabi) # BSC官方Multicall地址 multicall_addr = web3.toChecksumAddress("0x1Ee38d535d541c55C9dae27B12edf090C608E6Fb") multicall_contract = web3.eth.contract(address=multicall_addr, abi=MULTICALL_ABI) wbnb_addr = web3.toChecksumAddress("0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c") sender_addr = web3.toChecksumAddress("YOUR_WALLET_ADDRESS") private_key = "YOUR_PRIVATE_KEY" def buy_sell_single_tx(token, wbnb_amount): token_addr = web3.toChecksumAddress(token) nonce = web3.eth.get_transaction_count(sender_addr) # 1. 授权Router无限额度使用代币(避免重复授权) approve_data = pan_router.encodeABI( fn_name="approve", args=[panRouterContractAddress, web3.toWei(2**256 - 1, 'wei')] ) # 2. 买入代币:swapExactETHForTokens buy_data = pan_router.encodeABI( fn_name="swapExactETHForTokens", args=[ 0, [wbnb_addr, token_addr], sender_addr, int(time.time()) + 10000 ] ) # 3. 估算买入所得代币数量,设置卖出参数 buy_amount_out = pan_router.functions.getAmountsOut( web3.toWei(wbnb_amount, 'ether'), [wbnb_addr, token_addr] ).call()[1] # 留1%滑点,避免因价格波动交易失败 min_eth_out = int(buy_amount_out * 0.99) sell_data = pan_router.encodeABI( fn_name="swapExactTokensForETH", args=[ buy_amount_out, min_eth_out, [token_addr, wbnb_addr], sender_addr, int(time.time()) + 10000 ] ) # 打包三个操作进Multicall calls = [ (panRouterContractAddress, approve_data), (panRouterContractAddress, buy_data), (panRouterContractAddress, sell_data) ] # 构建Multicall交易 multicall_txn = multicall_contract.functions.aggregate(calls).buildTransaction({ 'from': sender_addr, 'value': web3.toWei(wbnb_amount, 'ether'), 'gasPrice': web3.toWei('5', 'gwei'), 'nonce': nonce, 'gas': web3.eth.estimate_gas({ 'from': sender_addr, 'to': multicall_addr, 'data': multicall_contract.encodeABI(fn_name="aggregate", args=[calls]), 'value': web3.toWei(wbnb_amount, 'ether') }) + 150000 # 预留额外gas }) # 签名并发送 signed_txn = web3.eth.account.sign_transaction(multicall_txn, private_key=private_key) tx_hash = web3.eth.send_raw_transaction(signed_txn.rawTransaction) return web3.toHex(tx_hash)
方式2:自定义封装合约(更可靠)
编写Solidity合约封装完整逻辑,避免批量调用的参数错误,还能规避部分蜜罐的合约检测:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IUniswapV2Router02 { function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts); function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts); } interface IERC20 { function balanceOf(address account) external view returns (uint); function approve(address spender, uint amount) external returns (bool); } contract HoneypotChecker { IUniswapV2Router02 public immutable router; address public constant WBNB = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c; constructor(address _router) { router = IUniswapV2Router02(_router); } function check(address token) external payable returns (bool) { // 买入代币 address[] memory path = new address[](2); path[0] = WBNB; path[1] = token; router.swapExactETHForTokens{value: msg.value}(0, path, address(this), block.timestamp + 10000); uint256 tokenBal = IERC20(token).balanceOf(address(this)); require(tokenBal > 0, "No tokens received"); // 授权并卖出 IERC20(token).approve(address(router), tokenBal); path[0] = token; path[1] = WBNB; router.swapExactTokensForETH(tokenBal, 0, path, msg.sender, block.timestamp + 10000); return true; // 执行到此处则非蜜罐 } receive() external payable {} }
Web3调用示例:
def check_with_contract(token, wbnb_amount): checker_addr = web3.toChecksumAddress("YOUR_CHECKER_CONTRACT_ADDRESS") checker_contract = web3.eth.contract(address=checker_addr, abi=CHECKER_ABI) nonce = web3.eth.get_transaction_count(sender_addr) txn = checker_contract.functions.check( web3.toChecksumAddress(token) ).buildTransaction({ 'from': sender_addr, 'value': web3.toWei(wbnb_amount, 'ether'), 'gasPrice': web3.toWei('5', 'gwei'), 'nonce': nonce, 'gas': web3.eth.estimate_gas(txn) + 200000 }) signed_txn = web3.eth.account.sign_transaction(txn, private_key=private_key) tx_hash = web3.eth.send_raw_transaction(signed_txn.rawTransaction) return web3.toHex(tx_hash)
二、更优的蜜罐检测方法
除了单交易实测,这些手段更高效且成本更低:
- 静态合约分析:直接解析代币合约代码,重点检查:
transfer/transferFrom函数是否限制普通地址转出(如白名单判断)- 是否存在卖出时收取超过50%的手续费、或直接销毁代币的逻辑
- 是否有隐藏的
_beforeTokenTransfer钩子,拦截转出操作
- 链下模拟交易:用
web3.eth.call()模拟卖出操作,无需真实上链,比如调用swapExactTokensForETH的模拟请求,看是否返回错误 - 流动性与交易历史检查:
- 通过Factory合约查询LP代币流向,确认是否被锁定到黑洞地址
- 查看代币交易记录,若只有项目方地址能转出,大概率是蜜罐
三、注意事项
- 实测时用极小金额(如0.0001 BNB),避免不必要损失
- 部分蜜罐会检测调用者是否为合约,此时优先用EOA地址的Multicall方案
- 模拟交易时要确保参数完整(如授权状态、滑点设置)
内容的提问来源于stack exchange,提问作者Soma Juice
相关产品推荐
相关产品推荐

