引き続き、Solidity v0.5.0 Breaking Changes から気になったものをピックアップしていくシリーズです。
今回は address について。
address と contract
contract は address のメンバーを含まなくなりました。
すなわち、c を contract としたとき、今までは c.transfer(...) や c.balance が実行できましたが、v0.5.0 では、address(c).transfer(...) や address(c).balance などのように、明示的に address に変換してから実行する必要があります。
address と address payable
address が、address と address payable に分類されるようになりました。以下、関連する仕様をまとめます。
address payableに対してのみ.transfer()や.send()が実行可能<address payable>.transfer(...)や<address payable>.send(...)は OK<address>.transfer(...)や<address>.send(...)は NG
address payableはaddressに直接変換可能addressはaddress payableに直接変換不可能uint160を介せば変換可能
- contract
cが payable fallback function を有する場合のみaddress(c)はaddress payableになる msg.senderはaddress payable
以下、上記の文章だけでは分かりにくい部分についてコードを交えながら補足します。
address から address payable への変換
address から address payable への暗黙的な直接変換は許してもらえないので、例えば、以下のような function はコンパイルエラーとなります。
function f(address _addr) public pure returns(address payable) {
return _addr;
}
以下のように uint160 を介せば変換可能です。
function f(address _addr) public pure returns(address payable) {
return address(uint160(_addr));
}
contract から address への変換
冒頭で述べた通り、contract に対して .transfer() などを実行する場合は明示的に address に変換する必要があります。このとき、contract が payable fallback function を有しているかどうかで、address と address payable のどちらに変換されるかが決まります。
まず、以下のようなコードを考えます。
pragma solidity >0.4.99 <0.6.0;
contract A {}
contract B {
function f() payable public {
A a = new A();
address(a).transfer(msg.value);
}
}
A は payable fallback function を有さないので、address(a) は address payable ではありません。すなわち、address(a) に対して .transfer() を実行することはできません。よって、上記コードはコンパイルエラーとなります。
次に、以下のようなコードを考えます。
pragma solidity >0.4.99 <0.6.0;
contract A {
function () payable external {}
}
contract B {
function f() payable public {
A a = new A();
address(a).transfer(msg.value);
}
}
A は payable fallback function を有するので、address(a) は address payable です。よって、上記コードのコンパイルは成功します。