抽象合约
如果智能合约中未实现合约中的至少一个函数,即某个函数缺少主体{}中的内容,或者合约没有为其所有的基类合约构造函数提供参数时,则必须将合约标记为 abstract。未实现的函数必须用virtual标记,以便继承它的合约能够重写此函数。
//SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
// 抽象合约
abstract contract Abstract {
function add(uint x, uint y) external pure virtual returns(uint);
}
// 继承并实现
contract Math is Abstract {
function add(uint x, uint y) external pure override returns(uint){
return x+y;
}
}
接口
接口类似于抽象合约,但是它们不能实现任何函数。还有进一步的限制:
- 无法继承其他合约,可以继承其他接口。
- 接口中所有的函数都需要是 external,尽管在合约里可以是public
- 无法定义构造函数。
- 无法定义状态变量。
- 不可以声明修改器
- 继承接口的合约必须实现接口定义的所有功能
接口基本上仅限于合约 ABI 可以表示的内容,编译接口可以得到合约的ABI,利用abi-to-sol工具也可以将ABI json文件转换为接口sol文件。
下面定义IMath接口,包含加减乘除4个函数:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IMath {
function add(uint x, uint y) external view returns (uint);
function sub(uint x, uint y) external view returns (uint);
function mul(uint x, uint y) external view returns (uint);
function div(uint x, uint y) external view returns (uint);
}
实现IMath接口:
contract Math is IMath {
function add(uint x, uint y) external pure returns (uint) {
return x+y;
}
function sub(uint x, uint y) external pure returns (uint) {
return x-y;
}
function mul(uint x, uint y) external pure returns (uint) {
return x*y;
}
function div(uint x, uint y) external pure returns (uint) {
return x/y;
}
}
如果我们知道一个合约实现了某接口,我们不需要知道它具体代码实现只需知道它的合约地址,用该接口就可以与它交互。下面用一个合约通过接口调用IMath接口中的方法:
// 参数_mathAddr为Math合约地址
contract CallMath{
function add(address _mathAddr, uint x, uint y) external pure returns (uint) {
return IMath(_mathAddr).add(x, y);
}
function sub(address _mathAddr,uint x, uint y) external pure returns (uint) {
return IMath(_mathAddr).sub(x, y);
}
function mul(address _mathAddr,uint x, uint y) external pure returns (uint) {
return IMath(_mathAddr).mul(x, y);
}
function div(address _mathAddr,uint x, uint y) external pure returns (uint) {
return IMath(_mathAddr).div(x, y);
}
}
在Remix上验证: