以太币 单位
以太币 单位之间的换算就是在数字后边加上 wei , gwei 或 ether 来实现的,如果后面没有单位,缺省为 wei。
assert(1 wei == 1);
assert(1 gwei == 1e9);
assert(1 ether == 1e18);
时间单位
秒是缺省时间单位,在时间单位之间,数字后面带有 seconds、 minutes、 hours、 days 和 weeks 的可以进行换算,基本换算关系如下:
1 == 1 seconds1 minutes == 60 seconds1 hours == 60 minutes1 days == 24 hours1 weeks == 7 days
这些后缀不能直接用在变量后边。如果想用时间单位(例如 days)来将输入变量换算为时间,你可以用如下方式来完成:
function f(uint start, uint daysAfter) public {
if (block.timestamp >= start + daysAfter * 1 days) {
// ...
}
}
特殊变量和函数
在全局命名空间中已经存在了(预设了)一些特殊的变量和函数,他们主要用来提供关于区块链的信息或一些通用的工具函数。
区块和交易属性
blockhash(uint blockNumber) returns (bytes32):指定区块的区块哈希 —— 仅可用于最新的 256 个区块且不包括当前区块,否则返回 0 。block.basefee(uint): 当前区块的基础费用block.chainid(uint): 当前链 idblock.coinbase(address): 挖出当前区块的矿工地址block.difficulty(uint): 当前区块难度block.gaslimit(uint): 当前区块 gas 限额block.number(uint): 当前区块号block.timestamp(uint): 自 unix epoch 起始当前区块以秒计的时间戳gasleft() returns (uint256):剩余的 gasmsg.data(bytes): 完整的 calldatamsg.sender(address): 消息发送者(当前调用)msg.sig(bytes4): calldata 的前 4 字节(也就是函数标识符)msg.value(uint): 随消息发送的 wei 的数量tx.gasprice(uint): 交易的 gas 价格tx.origin(address): 交易发起者(完全的调用链)
ABI 编码及解码函数
abi.decode(bytes memory encodedData, (...)) returns (...): 对给定的数据进行ABI解码,而数据的类型在括号中第二个参数给出 。 例如:(uint a, uint[2] memory b, bytes memory c) = abi.decode(data, (uint, uint[2], bytes))abi.encode(...) returns (bytes): ABI - 对给定参数进行编码abi.encodePacked(...) returns (bytes):对给定参数执行 紧打包编码 ,注意,可以不明确打包编码。abi.encodeWithSelector(bytes4 selector, ...) returns (bytes): ABI - 对给定第二个开始的参数进行编码,并以给定的函数选择器作为起始的 4 字节数据一起返回abi.encodeWithSignature(string signature, ...) returns (bytes):等价于abi.encodeWithSelector(bytes4(keccak256(signature), ...)abi.encodeCall(function functionPointer, (...)) returns (bytes memory): 使用tuple类型参数ABI 编码调用functionPointer。执行完整的类型检查, 确保类型匹配函数签名。结果和abi.encodeWithSelector(functionPointer.selector, (...))一致。
这些编码函数可以用来构造函数调用数据,而不用实际进行调用。
错误处理
assert(bool condition)
如果不满足条件,则会导致Panic 错误,则撤销状态更改 - 用于检查内部错误。
require(bool condition)
如果条件不满足则撤销状态更改 - 用于检查由输入或者外部组件引起的错误。
require(bool condition, string memory message)
如果条件不满足则撤销状态更改 - 用于检查由输入或者外部组件引起的错误,可以同时提供一个错误消息。
revert()
终止运行并撤销状态更改。
revert(string memory reason)
终止运行并撤销状态更改,可以同时提供一个解释性的字符串。
数学和密码学函数
addmod(uint x, uint y, uint k) returns (uint)
计算 (x + y) % k,加法会在任意精度下执行,并且加法的结果即使超过 2**256 也不会被截取。从 0.5.0 版本的编译器开始会加入对 k != 0 的校验(assert)。
mulmod(uint x, uint y, uint k) returns (uint)
计算 (x * y) % k,乘法会在任意精度下执行,并且乘法的结果即使超过 2**256 也不会被截取。从 0.5.0 版本的编译器开始会加入对 k != 0 的校验(assert)。
keccak256((bytes memory) returns (bytes32)
计算 Keccak-256 哈希。
sha256(bytes memory) returns (bytes32)
计算参数的 SHA-256 哈希。
ripemd160(bytes memory) returns (bytes20)
计算参数的 RIPEMD-160 哈希。
ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)
利用椭圆曲线签名恢复与公钥相关的地址,错误返回零值。
函数参数对应于 ECDSA签名的值:
r= 签名的前 32 字节s= 签名的第2个32 字节v= 签名的最后一个字节
ecrecover 返回一个 address, 而不是 address payable 。他们之前的转换参考 address payable ,如果需要转移资金到恢复的地址。
合约相关
-
this(当前的合约类型)当前合约,可以显示转换为 地址类型 Address。
-
selfdestruct(address payable recipient)销毁合约,并把余额发送到指定 地址类型 Address。请注意,
selfdestruct具有从EVM继承的一些特性:
- 接收合约的 receive 函数 不会执行。 - 合约仅在交易结束时才真正被销毁,并且 revert 可能会“撤消”销毁。
此外,当前合约内的所有函数都可以被直接调用,包括当前函数。
类型信息
表达式 type(X) 可用于检索参数 X 的类型信息。 目前,此功能还比较有限( X 仅能是合约和整型),但是未来应该会扩展。
用于合约类型 C 支持以下属性:
-
type(C).name:获得合约名
-
type(C).creationCode:获得包含创建合约字节码的内存字节数组。它可以在内联汇编中构建自定义创建例程,尤其是使用
create2操作码。 不能在合约本身或派生的合约访问此属性。 因为会引起循环引用。 -
type(C).runtimeCode获得合约的运行时字节码的内存字节数组。这是通常由
C的构造函数部署的代码。 如果C有一个使用内联汇编的构造函数,那么可能与实际部署的字节码不同。 还要注意库在部署时修改其运行时字节码以防范定期调用(guard against regular calls)。 与.creationCode有相同的限制,不能在合约本身或派生的合约访问此属性。 因为会引起循环引用。
除上面的属性, 下面的属性在接口类型I下可使用:
-
type(I).interfaceId:返回接口
I的bytes4类型的接口 ID,接口 ID 参考: EIP-165 定义的, 接口 ID 被定义为XOR(异或) 接口内所有的函数的函数选择器(除继承的函数。
对于整型 T 有下面的属性可访问:
-
type(T).minT的最小值。 -
type(T).maxT的最大值。
保留关键字
以下是保留关键字,可能是将来的语法中的一部分:
after, alias, apply, auto, byte, case, copyof, default, define, final, implements, in, inline, let, macro, match, mutable, null, of, partial, promise, reference, relocatable, sealed, sizeof, static, supports, switch, typedef, typeof, var.