You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Base链用Ethers.js调用Uniswap Universal Router购币报错排查

问题描述

在Base链上使用Node.js + Ethers.js通过Uniswap Universal Router购买新上线代币时,调用execute函数编码路径和输入时触发报错,错误信息如下:

if (types.length !== values.length) {
^

TypeError: Cannot read properties of undefined (reading 'length')
    at AbiCoder.encode (/home/oriok/DEV/degen/Arbitrum/node_modules/@ethersproject/abi/lib/abi-coder.js:82:37)
    at Object.<anonymous> (/home/oriok/DEV/degen/Arbitrum/B_Base/testinUni.js:52:24)
    at Module._compile (node:internal/modules/cjs/loader:1103:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
    at node:internal/main/run_main_module:17:47

使用的代码如下:

const {ethers} = require("ethers")

const AbiCoder = new ethers.utils.AbiCoder()

// const tokenToBuy = '0xe67aB9Efb46d987d2aF816597F6716069A8a7426' //KIF

//Router
const routerAddress = '0x198EF79F1F515F02dFE9e3115eD9fC07183f02fC' // router
const file = fs.readFileSync("./B_Base/ABIUniversal.json", 'utf8') // Calls sushi ABI
const routerAbi = JSON.parse(file)
const routerContract = new ethers.Contract(routerAddress, routerAbi, signer)

// token input
const prompt = ps()
const tokenToBuy = String(prompt("Enter token name: ")) 

//wbnb to spend
const spend = ethers.utils.parseEther("0.0001")

const commands = 0x00

const path = [AbiCoder.encode(WETH), AbiCoder.encode(5000), AbiCoder.encode(tokenToBuy)]

 // Encode the parameters
const inputs = AbiCoder.encode(WALLET_ADDRESS, spend, 0, path, false)

const buy = async () => { // .execute execute(bytes commands,bytes[] inputs,uint256 deadline)
    const buy = await routerContract.execute(
      commands,
      inputs,
      Date.now() + 1000 * 60 * 10)
      
    receipt = await buy.wait()
    transactionHash = receipt.transactionHash
    console.log(transactionHash)
    
}


buy()

此前使用SwapRouterV2无法购买部分代币,希望明确错误原因,同时了解其他支持购买各类代币的路由方案。


错误原因及修复方案

1. AbiCoder.encode 调用格式错误

ethers.utils.AbiCoder.encode要求第一个参数为类型数组,第二个为对应的值数组,你直接传入值而未指定类型,导致types参数为undefined,触发types.length读取错误。

修复路径编码

Uniswap V3的路径格式为tokenIn -> fee -> tokenOut,正确做法是使用solidityPack一次性编码三个元素,而非单独编码后再组合:

// Base链WETH固定地址
const WETH = "0x4200000000000000000000000000000000000006";
// 编码V3路径:地址 + 24位手续费 + 地址
const path = ethers.utils.solidityPack(
  ["address", "uint24", "address"],
  [WETH, 5000, tokenToBuy]
);

修复execute的inputs编码

commands = 0x00对应V3_SWAP_EXACT_IN命令,该命令的参数类型为(address recipient, uint256 amountIn, uint256 amountOutMinimum, bytes path, bool payerIsUser),需按类型编码为bytes,且inputs参数要求是bytes数组(每个命令对应一个元素):

// 替换原inputs编码逻辑
const inputs = [
  AbiCoder.encode(
    ["address", "uint256", "uint256", "bytes", "bool"],
    [WALLET_ADDRESS, spend, 0, path, true] // payerIsUser设为true,代表用自身钱包支付ETH
  )
];

2. 补充代码缺失依赖与初始化

代码中存在未定义的变量和依赖,需补充:

  • 引入fs模块:const fs = require("fs");
  • 引入prompt-sync并初始化:const ps = require("prompt-sync")();
  • 初始化Provider和Signer:
// 使用Base链RPC节点(如Alchemy/Infura)
const provider = new ethers.providers.JsonRpcProvider("https://base-mainnet.g.alchemy.com/v2/你的API_KEY");
// 用私钥初始化签名者
const signer = new ethers.Wallet("你的钱包私钥", provider);
const WALLET_ADDRESS = signer.address;

3. 修复后的完整代码

const {ethers} = require("ethers");
const fs = require("fs");
const ps = require("prompt-sync")();

const AbiCoder = new ethers.utils.AbiCoder();
const WETH = "0x4200000000000000000000000000000000000006"; // Base链WETH地址
const routerAddress = '0x198EF79F1F515F02dFE9e3115eD9fC07183f02fC'; // Universal Router地址

// 初始化Provider与Signer
const provider = new ethers.providers.JsonRpcProvider("https://base-mainnet.g.alchemy.com/v2/你的API_KEY");
const signer = new ethers.Wallet("你的钱包私钥", provider);
const WALLET_ADDRESS = signer.address;

// 读取Router ABI
const file = fs.readFileSync("./B_Base/ABIUniversal.json", 'utf8');
const routerAbi = JSON.parse(file);
const routerContract = new ethers.Contract(routerAddress, routerAbi, signer);

// 获取目标代币地址(注意输入地址而非代币名称)
const tokenToBuy = ps("Enter token address: ");
const spend = ethers.utils.parseEther("0.0001");
const commands = "0x00"; // V3_SWAP_EXACT_IN命令

// 编码V3交易路径
const path = ethers.utils.solidityPack(
  ["address", "uint24", "address"],
  [WETH, 5000, tokenToBuy]
);

// 编码命令输入参数
const inputs = [
  AbiCoder.encode(
    ["address", "uint256", "uint256", "bytes", "bool"],
    [WALLET_ADDRESS, spend, 0, path, true]
  )
];

const buy = async () => {
  try {
    // deadline需传入秒级时间戳(Date.now()返回毫秒,需除以1000)
    const tx = await routerContract.execute(
      commands,
      inputs,
      Math.floor(Date.now() / 1000) + 60 * 10
    );
    const receipt = await tx.wait();
    console.log("交易哈希:", receipt.transactionHash);
  } catch (err) {
    console.error("交易失败:", err);
  }
};

buy();

其他可选路由方案

如果Uniswap Universal Router仍有兼容性问题,可尝试以下路由:

  • Uniswap SwapRouterV3:专门针对V3流动性池的路由,兼容性比V2更好,支持更多新上线代币
  • 1inch Router:聚合多个DEX的路由,自动扫描最优流动性路径,对新代币的支持更友好
  • SushiSwap Router:与Uniswap接口兼容,部分Uniswap无流动性的代币可能在SushiSwap存在交易对
  • PancakeSwap Router(Base版):若目标代币在Base链的PancakeSwap有流动性,可使用该路由

内容的提问来源于stack exchange,提问作者0xDegen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 20:06:01