Dai自动循环兑换机器人报错:dai.balanceOf()不是函数求排查
自动兑换机器人问题排查与修复建议
一、核心错误:dai.balanceOf() is not a function 修复
问题根源:ethers.getContractAt() 是异步函数,直接同步赋值会导致dai是Promise对象而非合约实例,无法调用balanceOf方法。同时你误用了主网DAI地址,Goerli测试网有专属的DAI合约。
修复步骤:
- 将
dai合约实例的初始化移到main异步函数内部,用await获取 - 替换为Goerli测试网DAI地址:
0x11fE4B6AE13d2a6055C8D9cF65c55bac32B5d844
修改后代码片段:
async function main() { // ... 其他代码 ... const DAI = '0x11fE4B6AE13d2a6055C8D9cF65c55bac32B5d844'; const dai = await ethers.getContractAt("IERC20", DAI); // ... 其他代码 ... }
二、脚本逻辑问题修复
1. 循环内余额未更新
循环外获取的初始余额未在循环中刷新,导致每次兑换都用初始值,无法触发终止条件,也看不到真实余额变化。
修复:每次循环开始时重新获取当前余额
for (let i = 0; i < 111; i++) { const currentBalance = await dai.balanceOf(signer.address); const amountIn = currentBalance; // ... 后续逻辑 ... }
2. 终止条件逻辑颠倒
原代码if (amountIn.mul(10).lte(balance.mul(9)))逻辑错误,因为amountIn等于balance,等式永远不成立(除非余额为0)。正确逻辑是当当前余额≤初始余额的90%时终止循环。
修复:
// 循环前保存初始余额 const initialBalance = await dai.balanceOf(signer.address); for (let i = 0; i < 111; i++) { const currentBalance = await dai.balanceOf(signer.address); if (currentBalance.lte(initialBalance.mul(90).div(100))) { console.log("DAI余额已减少10%,终止循环"); break; } // ... 后续逻辑 ... }
3. 多余的deposit调用
DAI是ERC20代币,没有deposit()方法,原代码中该调用会触发额外错误,直接删除即可。
4. 余额打印错误
原代码打印的是初始余额变量,需改为打印最新获取的余额:
console.log("当前DAI余额:", ethers.utils.formatEther(currentBalance));
三、合约部署问题修复
合约中使用了主网的SwapRouter和USDC地址,Goerli测试网需替换为对应测试网地址:
- Goerli测试网Uniswap V3 SwapRouter:
0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45 - Goerli测试网USDC:
0x07865c6E87B9F70255377e024ace6630C1Eaa37F
修改合约常量:
contract SwapExamples { ISwapRouter public constant swapRouter = ISwapRouter(0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45); address public constant DAI = 0x11fE4B6AE13d2a6055C8D9cF65c55bac32B5d844; address public constant USDC = 0x07865c6E87B9F70255377e024ace6630C1Eaa37F; // ... 其他函数逻辑 ... }
四、完整修复后的机器人脚本
require("@nomiclabs/hardhat-ethers"); require("dotenv").config(); const fs = require('fs'); const { ethers } = require("hardhat"); const fsPromises = fs.promises; const ABI_FILE_PATH = 'artifacts/contracts/SwapExamples.sol/SwapExamples.json'; const DEPLOYED_CONTRACT_ADDRESS = '0xAb54Bf58D1cf4F6E5fe14917fa909AaAc4c4cE91'; function waitforme(milisec) { return new Promise(resolve => { setTimeout(() => { resolve('') }, milisec); }) } async function getABI() { const data = await fsPromises.readFile(ABI_FILE_PATH, 'utf8'); const abi = JSON.parse(data)['abi']; return abi } async function main() { const {PRIVATE_KEY, INFURA_GORELI_ENDPOINT_KEY} = process.env; const provider = ethers.getDefaultProvider(`https://eth-goerli.g.alchemy.com/v2/${INFURA_GORELI_ENDPOINT_KEY}`); const signer = new ethers.Wallet(PRIVATE_KEY, provider); const abi = await getABI(); const UniContract = new ethers.Contract(DEPLOYED_CONTRACT_ADDRESS, abi, signer); const DAI = '0x11fE4B6AE13d2a6055C8D9cF65c55bac32B5d844'; const dai = await ethers.getContractAt("IERC20", DAI); const initialBalance = await dai.balanceOf(signer.address); console.log("初始DAI余额:", ethers.utils.formatEther(initialBalance)); for (let i = 0; i < 111; i++) { const currentBalance = await dai.balanceOf(signer.address); if (currentBalance.lte(initialBalance.mul(90).div(100))) { console.log("DAI余额已减少10%,终止循环"); break; } const amountIn = currentBalance; console.log(`第${i+1}次兑换,兑换金额:`, ethers.utils.formatEther(amountIn)); const approveTx = await dai.connect(signer).approve(UniContract.address, amountIn); await approveTx.wait(); const swapTx = await UniContract.swapExactInputMultihop(amountIn); await swapTx.wait(); console.log("兑换完成,当前DAI余额:", ethers.utils.formatEther(await dai.balanceOf(signer.address))); await waitforme(1000); } } main() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); });
内容的提问来源于stack exchange,提问作者Shuayb Ahmed
相关产品推荐
相关产品推荐

