今天在运行UniswapV2合约调用getReserves()函数时,报"function call to a non-contract account"错误,如图(1)所示:
![](https://img-blog.csdnimg.cn/efd37caaec624bd384f475ce80d37c61.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAc2FucWltYQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
出现这种情况的原因是:函数调用的合约找不到,可能的原因有:
- 合约没有部署;
- 合约地址错误;
- api-key缺少访问权限;
- codeHash没有配置;
- 调用的合约在主网,而被调用的合约在测试网,即两合约没有在同一个网络。
本例中,是由于UniswapV2Router02.sol里的pairFor()函数其codeHash没有更新,导致合约找不到。UniswapV2Router02.sol 根据 factory、token0、token1、codeHash来生成pair地址,而codeHash使用的mainnet网络,应该使用本地网络的codeHash。
可通过web3.utils.keccak256(UniswapV2Pair.bytecode)计算codeHash,例子如下:
const Web3 = require('web3')
//配对合约的json文件
const UniswapV2Pair = require('../../artifacts/contracts/UniswapV2Factory.sol/UniswapV2Pair.json')
//设置网段 localhost、Rinkeby、mainnet
const web3 = new Web3(new Web3.providers.HttpProvider("http://127.0.0.1:8545"))
let initCodeHash = null
let data = UniswapV2Pair.bytecode
if (!data.startsWith('0x')) data = '0x' + data
console.info('INIT_CODE_HASH:', initCodeHash = web3.utils.keccak256(data))
得到codehash如下:
INIT_CODE_HASH: 0x36da00333ba9396db7d539011cd1c469351d4c58d439e5e918c9a07228bf291c
注意:这个codeHash是通过配对合约的bytecode进行keccak256()生成的。在添加流动性时,工厂合约会检测这个pair合约是否存在,若不存在,则调用createPair()创建pair合约。
在FlashLoanOne.sol,或者UniswapV2Router02.sol的pairFor()函数里,修改codehash,然后重新编译、部署智能合约。
//FlashLoanOne.sol
// calculates the CREATE2 address for a pair without making any external calls
// codehash要根据factory合约,进行修改
function pairFor(address factory, address tokenA, address tokenB) internal pure returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = address(uint(keccak256(abi.encodePacked(
hex'ff',
factory,
keccak256(abi.encodePacked(token0, token1)),
hex'36da00333ba9396db7d539011cd1c469351d4c58d439e5e918c9a07228bf291c' //修改此处
))));
}
// fetches and sorts the reserves for a pair
function getReserves(address factory, address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) {
(address token0,) = sortTokens(tokenA, tokenB);
(uint reserve0, uint reserve1,) = IUniswapV2Pair(pairFor(factory, tokenA, tokenB)).getReserves();
(reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
}
## 编译智能合约
npx hardhat compile
## 部署智能合约
npx hardhat run script/deploy_flashloan.js