UniswapV2 pairFor返回错误合约地址致添加流动性失败
问题产生原因
- 核心错误是init code hash的传参格式错误。原代码中
hex'96e8ac42...'是Solidity原生的十六进制字面量写法,会被直接解析为32字节的原始二进制值参与哈希计算;但你修改后的代码传入的是带0x前缀的普通字符串'0x932b4f40...',abi.encodePacked处理字符串时会将每个字符按ASCII编码逐字节打包,最终会传入66字节的无效数据(2个字符的0x+64个十六进制字符,共66个ASCII字符),直接导致哈希计算结果完全错误。 - 本地计算init code hash的方式可能存在偏差。如果UniswapV2Pair合约存在自定义修改、构造函数带参数、编译版本/优化选项和实际部署时不一致,
type(UniswapV2Pair).creationCode计算出的哈希会和链上实际部署用的字节码哈希不匹配。 - 额外常见诱因:旧版Ganache等测试环境存在CREATE2地址计算的兼容性bug,或者传入的factory地址错误、
sortTokens排序逻辑不符合UniswapV2的排序规则(按地址大小升序排列),也会导致最终计算的pair地址错误。
修复方法
- 修正init code hash的传参格式:去掉hash值的
0x前缀,使用Solidity十六进制字面量语法传值,同时修正地址类型转换逻辑适配Solidity 0.8+版本的类型检查,修正后的代码如下:
function pairFor(address factory, address tokenA, address tokenB) internal pure returns (address pair) { (address token0, address token1) = sortTokens(tokenA, tokenB); pair = address(uint160(uint256(keccak256(abi.encodePacked( hex'ff', factory, keccak256(abi.encodePacked(token0, token1)), hex'932b4f40ffd7547443affda5e84a39f3efc69f2ca17d46f0f9427e015f0fb178' ))))); }
*注意:从uint256类型转换为address类型时,需要先截断为uint160类型,避免高版本Solidity抛出类型截断错误。
- 校验init code hash的准确性:最稳妥的hash获取方式不是本地编译计算,而是在Factory合约部署完成后,直接调用Factory合约暴露的
INIT_CODE_PAIR_HASH公共常量读取链上实际存储的哈希值,用该值替换代码中的hash参数,保证和部署的合约逻辑完全一致。 - 增加校验逻辑:测试阶段可以在计算完pair地址后,调用Factory合约的
getPair方法读取合约实际记录的pair地址,和本地计算结果做比对,确认计算逻辑正确后再接入添加流动性的业务逻辑。 - 测试环境兼容:如果使用Ganache做本地测试,升级到v7及以上版本,旧版本Ganache对CREATE2 opcode的实现存在已知偏差,会导致地址计算结果不符合EVM标准。
内容的提问来源于stack exchange,提问作者diamondhare
相关产品推荐
相关产品推荐

