PancakeSwap调用ethers.js的swapExactETHForTokens/swapExactTokensForTokens失败排查
故障原因
- swapExactETHForTokens 调用缺少value参数:该函数为payable类型,用于原生BNB兑换代币,需要在交易的可选参数中传入你要支付的BNB数量(也就是你定义的amountIn),你当前代码未传该参数,相当于调用时没有附带BNB,直接触发失败。
- gasLimit设置过低:你兑换的Safemoon属于带交易税费、代币反射机制的特殊代币,swap交易的gas消耗远高于普通ERC20代币交易,你设置的100000gas完全不足以覆盖交易执行的消耗。
- 滑点计算逻辑错误:你当前的滑点计算方式为
amounts[1].sub(amounts[1].div(${config.slippage})),当slippage设为12时,实际仅允许8.3%的滑点,和你预期的12%滑点完全不符,且Safemoon本身自带10%左右的交易税费,叠加链上滑点后,你设置的最低输出金额高于实际可兑换的金额,触发滑点校验失败。 - gasPrice未正确获取:
provider.getGasPrice()是异步方法,你没有加await关键字,导致传入交易参数的是Promise对象而非实际的gasPrice数值,导致交易手续费设置异常。
修复方案
- 调整
swapExactETHForTokens的交易参数,补充value字段,传入你要支付的amountIn - 将gasLimit上调到300000~500000区间,适配高消耗的代币交易
- 修正滑点计算逻辑,正确计算对应滑点下的最低输出金额
- 给
provider.getGasPrice()加上await,正确获取gasPrice数值 - 移除多余的approve调用:
swapExactETHForTokens使用原生BNB支付,不需要提前授权WBNB的使用权限
修复后核心代码示例
const buyToken = async () => { try { const deadline = Math.floor(Date.now() / 1000) + 60 * 20 const tokenIn = config.wbnb const tokenOut = config.safemoon const amountIn = ethers.utils.parseUnits('0.001', 'ether') const amounts = await pancakeswap.getAmountsOut(amountIn, [ tokenIn, tokenOut, ]) // 修正滑点计算:12%滑点即最低拿到原预期的88% const amountOutMin = amounts[1].mul(100 - config.slippage).div(100) console.log(` Buying new token tokenIn: ${amountIn} ${tokenIn} (WBNB) tokenOut: ${amountOutMin} ${tokenOut} `) const tx = await pancakeswap.swapExactETHForTokens( amountOutMin, [tokenIn, tokenOut], account.address, deadline, { value: amountIn, // 补充value参数,传入要支付的BNB数量 gasPrice: await provider.getGasPrice(), // 加await获取实际gasPrice gasLimit: 400000, // 上调gasLimit } ) const receipt = await tx.wait() console.log('buyToken receipt') console.log(receipt) } catch (error) { console.log(error) } } // 移除main函数里的approve调用,swapExactETHForTokens不需要授权 const main = async () => { await buyToken() process.exit() }
内容的提问来源于stack exchange,提问作者TheDayIsDone
相关产品推荐
相关产品推荐

