目录
引言
在使用 Hardhat 本地节点进行 Uniswap V2 部署和交互时,可能会遇到 function call to a non-contract account 的错误提示。该错误通常源于 Router 合约在调用 pairFor() 函数时,计算出的交易对合约地址(Pair 地址)与实际部署的 Pair 合约地址不一致,导致调用失败。此问题的根本原因在于 INIT_CODE_PAIR_HASH 的不匹配。
解决报错 function call to a non-contract account 表示在调用的合约地址上,其实并不存在已部署的合约(或初始化 codeHash 不匹配,导致 Router 在 _addLiquidity() 里调用计算得到的 Pair 地址并没有部署合约)
原因分析
Router 使用的 pairFor() 逻辑(或 UniswapV2Library)计算出来的合约地址
pairFor() 内部通过 factory, tokenA, tokenB 以及一个固定的 INIT_CODE_PAIR_HASH(即 Pair contract 的 bytecode 哈希)来计算 Pair 合约的地址。
如果这个 INIT_CODE_PAIR_HASH 是 hardcoded 的 主网默认值,而本地环境部署的是自定义(重新编译)的 Pair 合约,那么这个值就不匹配,也就算不出正确地址,Router 计算后会调用一个空地址,就出现你看到的“非合约账户”错误 。
Factory 的 createPair() 虽然部署了 Pair 合约,但 Router 计算依赖的 hash 错误
创建了 Pair,但 Router 根据错误的 hash 地址调用,等于对不存在的地址调用合约方法,就直接失败了 。
解决方式
1、编写 getPairInitCodeHash.js 脚本,获取 INIT_CODE_HASH
你需要自己计算你对应编译好的 UniswapV2Pair 合约的 keccak256(bytecode)
2、修正 INIT_CODE_PAIR_HASH
在 UniswapV2Factory.sol 中添加用于校验的 INIT_CODE_PAIR_HASH
部署后,你可以在控制台或脚本里通过 factory.INIT_CODE_PAIR_HASH() 查看并打印哈希值;确认它和你脚本中计算的完全一致。这样就验证了 hash 是你本地环境生成的正确值。然后替换掉 Router 或 Library 中硬编码的INIT_CODE_PAIR_HASH。
3、修改 UniswapV2Library.sol 中的 pairFor(),替换 hash
INIT_CODE_PAIR_HASH(你本地算出的 0xd2e7c459…9622)实际上是 UniswapV2Pair 合约的创建字节码哈希,在系统中扮演着关键角色
代表 UniswapV2Pair 合约的 creationCode 的 keccak256 值,是一个常量。部署时,Factory 合约会执行:
create2(..., creationCode, salt)
而 Router 或 Library 则通过 keccak256(0xff + factory + salt + init_code_hash) 计算对应 Pair 的地址。
作用
在链下准确预测 Pair 地址
UniswapV2Library.pairFor(…) 根据这个 hash 和 tokenA、tokenB 排序后的 salt 就能预测未来 Pair 合约的地址,无需 on-chain 查询 。
保障地址一致性与合约调用安全
Router 调用 addLiquidity 时使用计算出的地址进行交互,如果使用了错误的 hash,就会生成不存在的合约地址,从而导致调用失败或 revert,报 “function call to a non‑contract account” 错误。
总结
在本地 Hardhat 环境中部署和交互 Uniswap V2 时,确保 Router 使用正确的 INIT_CODE_PAIR_HASH 是避免 function call to a non-contract account 错误的关键。通过上述步骤,可以确保计算出的 Pair 合约地址与实际部署的地址一致,从而确保交易的顺利执行。