
本文详解 ethers.js v6 升级后因 approve 等合约方法要求严格 BigNumberish 类型(如 BigInt)而导致的 INVALID_ARGUMENT 错误,并提供兼容写法、最佳实践与避坑指南。
本文详解 ethers.js v6 升级后因 `approve` 等合约方法要求严格 `bignumberish` 类型(如 `bigint`)而导致的 `invalid_argument` 错误,并提供兼容写法、最佳实践与避坑指南。
在 ethers.js v6 中,所有涉及链上数值(如 amount、gasLimit、value)的参数均被强制要求为 BigNumberish 类型——即 number、string、bigint、BigNumber 或带 hex/type 字段的兼容对象。但关键点在于:普通 JavaScript number 类型在超出安全整数范围(2^53 - 1)时会丢失精度,因此 v6 默认拒绝裸 number 字面量(如 6500000000000000),即使它未超限,也会因类型校验失败而抛出 INVALID_ARGUMENT 错误。
你遇到的报错:
TypeError: invalid BigNumberish value (argument="value", value={ "hex": "0xb3e3", "type": "BigNumber" }, ...)表面看 value 是一个合法 BigNumber 对象,实则根源常在于:你在调用 approve(...) 时传入了非 BigNumberish 类型的 amount(例如 JS number),而 ethers 内部在构造交易时尝试将其转换为 BigNumber 的过程中,意外接收了一个已被污染或结构异常的对象(如从旧版缓存、调试日志误传的 BigNumber 实例),触发了类型断言失败。
✅ 正确做法是:显式使用 BigInt 字符串构造或 ethers.parseUnits 等工具函数生成合规值。
✅ 推荐写法(v6 兼容且安全)
import { Contract, JsonRpcProvider, parseUnits } from "ethers";
const provider = new JsonRpcProvider(PROVIDER_URL);
const approvalContract = new Contract(wethAddress, erc20Abi, provider);
// ✅ 方式 1:使用 BigInt 字符串(最直接,适合已知精确数值)
await approvalContract.connect(wallet).approve(
routerAddress,
BigInt("6500000000000000") // ← 必须是字符串转 BigInt,不可写 BigInt(6500000000000000)
);
// ✅ 方式 2:使用 ethers 内置工具(推荐用于代币金额,自动处理小数位)
// 假设 WETH 小数位为 18,则 "0.0000065" ETH = 6500000000000000 wei
await approvalContract.connect(wallet).approve(
routerAddress,
parseUnits("0.0000065", 18) // 返回 BigNumber,100% 兼容
);⚠️ 注意事项与常见陷阱
-
❌ 错误示范:
approve(routerAddress, 6500000000000000); // 普通 number → 触发 INVALID_ARGUMENT approve(routerAddress, BigInt(6500000000000000)); // BigInt() 不接受 number 参数 → TypeError
✅ 正确构造 BigInt:必须传入字符串:BigInt("6500000000000000")
(JS BigInt 构造函数不支持数字字面量,仅支持字符串或 bigint)-
? 显式指定函数签名(进阶场景):
当 ABI 中存在重载函数(如多个 approve)时,可显式调用以避免解析歧义:await approvalContract.connect(wallet)["approve(address,uint256)"]( routerAddress, parseUnits("0.0000065", 18) );注:签名中 uint256 无需空格,括号为英文半角;此写法在 v6+ 中稳定支持。
-
? 调试建议:
在传参前打印类型验证:const amount = parseUnits("0.0000065", 18); console.log("amount type:", typeof amount, "isBigNumber:", amount instanceof BigNumber); // 输出应为: "object" true
✅ 总结
| 场景 | 推荐方案 |
|---|---|
| 精确 wei 值(如 gas、固定 wei) | BigInt("1234567890123456789") |
| 代币金额(含小数) | parseUnits("1.23", decimals)(自动转为 BigNumber) |
| 动态计算结果 | 先用 parseUnits 或 BigInt() 构造,再参与运算,全程避免裸 number |
升级至 ethers.js v6 后,数值安全成为默认契约。放弃对 number 的依赖,拥抱 BigNumber / BigInt 是规避此类错误的根本之道。一次修正,永久规避精度与类型风险。


















