合约类型
每一个合约,合约本身也是一个数据类型, 称为合约类型,如下代码定义了一个Hello
合约类型:
pragma solidity ^0.8.0;
contract Hello {
function sayHi() public view returns (uint) {
return 10;
}
}
使用合约类型
我们要如何使用合约类型呢,我们可以通过合约类型创建出一个合约事例(即部署一个合约)。
这里是一个例子:
pragma solidity ^0.8.0;
contract Hello {
function sayHi() public view returns (uint) {
return 10;
}
}
contract HelloCreator {
uint public x;
Hello public h;
function createHello() public returns (address) {
h = new Hello();
return address(h);
}
}
上面的代码,调用 HelloCreator
合约的 createHello
函数可以创建一个合约(new Hello()
)。
我们在 Remix 演练一下,先部署HelloCreator
合约(注意不是部署Hello):
然后调用createHello
在链上创建一个Hello
合约:
右下角的日志中,可以看到创建的合约地址0x93Ff8fe9BF4005...
。让我们在Remix 加载该合约,并调用 sayHi
来验证该合约确实部署成功了。
在 Remix 使用 Hello
的地址加载Hello
, 选择Hello
合约, 在At Address 处填入合约地址,如图:
然后调用sayHi()
:
createHello
函数中,创建的合约赋值给了状态变量 h
, 在 HelloCreator
合约,也可以利用h
来调用sayHi
函数, 例如,可以在HelloCreator
合约中,添加如下函数:
function callHi() public returns (uint) {
x = h.sayHi();
return x;
}
合约类型元数据成员
Solidity 从 0.6 版本开始,Solidity 增加了一些属性来获取合约类型类似的元信息。
如:对于合约C,可以通过type(C)来获得合约的类型信息,这些信息包含以下内容:
(1)type(C).name
:获得合约的名字。
(2)type(C).creationCode
:获得创建合约的字节码。
(3)type(C).runtimeCode
:获得合约运行时的字节码。
字节码是什么东西? 先留一个坑, 以后有机会介绍 EVM 时,在详细介绍。
额外知识点:如何区分合约及外部地址
经常需要区分一个地址是合约地址还是外部账号地址,区分的关键是看这个地址有没有与之相关联的代码。EVM提供了一个操作码EXTCODESIZE
,用来获取地址相关联的代码大小(长度),如果是外部账号地址,则没有代码返回。因此我们可以使用以下方法判断合约地址及外部账号地址。
function isContract(address addr) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(addr) }
return size > 0;
}
如果是在合约外部判断,则可以使用web3.eth.getCode()
(一个Web3的API),或者是对应的JSON-RPC方法——eth_getcode。getCode()用来获取参数地址所对应合约的代码,如果参数是一个外部账号地址,则返回“0x”;如果参数是合约,则返回对应的字节码,下面两行代码分别对应无代码和有代码的输出。
>web3.eth.getCode(“0xa5Acc472597C1e1651270da9081Cc5a0b38258E3”)
“0x”
>web3.eth.getCode(“0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8”) “0x600160008035811a818181146012578301005b601b6001356025565b8060005260206000f25b600060078202905091905056”
这时候,通过对比getCode()
的输出内容,就可以很容易判断出是哪一种地址。
小结
提炼本节的重点:合约是一个类型,我们可以通过这个合约类型来创建合约(即部署合约),然后与合约里的函数交互。
------
来 DeCert.me 码一个未来,DeCert 让每一位开发者轻松构建自己的可信履历。
DeCert.me 由登链社区 @UpchainDAO 孵化,欢迎 Discord 频道 一起交流。
本教程来自贡献者 @Tiny熊。