Solidity合约编译报错:address类型无mint成员的解决咨询
编译Compound兼容的ERC4626合约报错解决
我尝试编译以下Solidity合约但失败了。我知道可以为address指定mint和redeem方法,但由于这些方法来自Compound,请问该如何处理才能让合约编译通过?
原合约代码
// SPDX-License-Identifier: MIT pragma solidity <0.9.0; import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC4626Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; contract Myvault is ERC4626Upgradeable, OwnableUpgradeable { //compound variable to store address address _cAsset; function initialize( IERC20MetadataUpgradeable asset_, string memory name_, string memory symbol_ ) public initializer { __MyVault_init(asset_, name_, symbol_); _cAsset = 0x00000000000000000000000; //put here cAsset address } function __MyVault_init( IERC20MetadataUpgradeable asset_, string memory name_, string memory symbol_ ) internal onlyInitializing { __ERC4626_init_unchained(asset_); __ERC20_init_unchained(name_, symbol_); __Ownable_init_unchained(); } function depositCompound( IERC20MetadataUpgradeable asset_, address cAsset_, uint256 _amount ) public onlyOwner returns (uint) { asset_.approve(cAsset_, _amount); // Mint cTokens uint mintResult = cAsset_.mint(_amount); return mintResult; } function withdrawCompound( uint256 amount, bool redeemType, address cAsset_ ) public onlyOwner returns (bool) { uint256 redeemResult; if (redeemType == true) { redeemResult = cAsset_.redeem(amount); } else { redeemResult = cAsset_.redeemUnderlying(amount); } return true; } }
报错信息
TypeError: Member "mint" not found or not visible after argument-dependent lookup in address. | 38 | uint mintResult = cAsset_.mint(_amount); | ^^^^^^^^^^^^ Error HH600: Compilation failed
解决方法
核心问题是Solidity编译器不知道address类型的变量有mint/redeem这些方法——这些是Compound cToken合约的专属方法,必须通过定义接口来让编译器识别。
1. 定义Compound cToken接口
先写一个包含所需方法的接口,方法签名必须和Compound官方cToken合约完全一致:interface ICompoundCToken { function mint(uint256 amount) external returns (uint256); function redeem(uint256 amount) external returns (uint256); function redeemUnderlying(uint256 amount) external returns (uint256); }2. 替换所有cAsset的类型为接口类型
把合约里所有存储或传递cAsset的address类型改成ICompoundCToken:- 成员变量
address _cAsset;→ICompoundCToken _cAsset; depositCompound的参数address cAsset_→ICompoundCToken cAsset_withdrawCompound的参数address cAsset_→ICompoundCToken cAsset_
- 成员变量
3. 修正初始化赋值
给_cAsset赋值时,把地址转成接口类型:_cAsset = ICompoundCToken(0x你的cToken实际地址);4. 调整方法调用的细节
调用approve时,需要把接口类型转成address:asset_.approve(address(cAsset_), _amount);其他方法调用直接用接口变量即可,编译器会自动识别方法。
修改后的完整合约
// SPDX-License-Identifier: MIT pragma solidity <0.9.0; import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC4626Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; // 定义Compound cToken接口 interface ICompoundCToken { function mint(uint256 amount) external returns (uint256); function redeem(uint256 amount) external returns (uint256); function redeemUnderlying(uint256 amount) external returns (uint256); } contract Myvault is ERC4626Upgradeable, OwnableUpgradeable { // 使用接口类型存储cAsset地址 ICompoundCToken _cAsset; function initialize( IERC20MetadataUpgradeable asset_, string memory name_, string memory symbol_ ) public initializer { __MyVault_init(asset_, name_, symbol_); // 替换为实际的Compound cToken地址 _cAsset = ICompoundCToken(0x0000000000000000000000000000000000000000); } function __MyVault_init( IERC20MetadataUpgradeable asset_, string memory name_, string memory symbol_ ) internal onlyInitializing { __ERC4626_init_unchained(asset_); __ERC20_init_unchained(name_, symbol_); __Ownable_init_unchained(); } function depositCompound( IERC20MetadataUpgradeable asset_, ICompoundCToken cAsset_, uint256 _amount ) public onlyOwner returns (uint) { asset_.approve(address(cAsset_), _amount); // Mint cTokens uint mintResult = cAsset_.mint(_amount); return mintResult; } function withdrawCompound( uint256 amount, bool redeemType, ICompoundCToken cAsset_ ) public onlyOwner returns (bool) { uint256 redeemResult; if (redeemType) { redeemResult = cAsset_.redeem(amount); } else { redeemResult = cAsset_.redeemUnderlying(amount); } return true; } }
内容的提问来源于stack exchange,提问作者Tsss
相关产品推荐
相关产品推荐

