目次
前提
EthereumのスマートコントラクトはSolidityという言語で書かれたものが多いです。
Ethereumのスマートコントラクトは、それぞれにコントラクトアドレスという固有のアドレスを持っています。
Ethereumのスマートコントラクトは、Ethを受け取ることができます。つまり、コントラクトがEthを保有できます。
コントラクトがEthを受け取る3つの方法
- マイニングによる報酬を受け取るアドレスに指定する
- コントラクト内部のpayable関数を通して受け取る
- コントラクトを破壊したときに残高を受け取る
1. マイニングによる報酬を受け取る
マイニングをすると報酬が貰えますが、その受け取り先のアドレスをコントラクトアドレスにすると、コントラクトはEthを受け取ることができます。
2. コントラクト内部のpayable関数を通して受け取る
コントラクト内部に、payable修飾子がついている関数を定義します。
function receiveEth() public payable {
// 何か
}
payable修飾子がついた関数を実行すると、コントラクトアドレスに対してEthを送金することができます。
勘違いしていたpayable修飾子の役割
自分自身勘違いしていたポイントとして、
コントラクトでEthを扱う(送金や受領をする)ならpayable関数をつける❌
と誤った解釈をしていた時がありました。
payable修飾子が意味しているのは、コントラクトでEthを扱うことではなく、
コントラクトのコントラクトアドレスにEthを送金できるか⭕️
どうかということです。
例えば、以下のような関数を実行した時の挙動を考えます。
function deposit() public payable {
// 中身の処理は何もありません!
}
関数の中身は全く何もありません。従ってこのコントラクト関数を実行したところで何も起きません。
しかし、payable修飾子がついているということは、「コントラクトアドレスにEthを送金する」ことは可能です。
⏫のような関数を利用してコントラクトアドレスにEthを送金することは、メインネットでは無意味なので理解しづらいですが、この関数をEthとともに実行すると、そのコントラクトのアドレスにEthが入ります。
address(this).balanceを信用して何かの取引を行うと、外部から勝手にコントラクトアドレスに対してEthの送金が行われた場合に予期せぬ結果になってしまう場合があります。depositを伴う処理を行う際は、その残高を管理する変数を用意しなければなりません。
3. コントラクトを破壊した時に残高を受け取る
これは、コントラクトをselfdestructを使用してnetworkから削除したときに、残高を受け取るようにすることで実現します。
コントラクトは、selfdestructする(networkから削除する)ことができます。
削除されるコントラクトのコントラクトアドレスが所有しているEthは、selfdestructが実行された後に、指定のアドレスに送金されます。
function selfDestroy() {
// 指定アドレスはEOAでもコントラクトアドレスでも良い
selfdestruct(指定アドレス)
}
- selfdestructを実行する
- 実行しているコントラクトが削除される
- 削除されるコントラクトに溜まっているeth残高が、引数に指定されたアドレスに送金される
このような流れです。
指定されるアドレスはEOAでもコントラクトアドレスでも良いです。
ここにコントラクトアドレスを指定した場合、そのコントラクトがpayable修飾子を持たないコントラクトであったとしても、無条件にEthを送金できます。
ここが面白いところです。payable修飾子のところで書きましたが、
address(this).balance
この記述はコントラクトアドレスの残高を参照するものです。この値は、外部のユーザーが自由に変更することが可能であるということです。
外部のユーザーが自由に変更可能なこの値を使って、送金処理をしていたりすると、よきせぬ結果になってしまう可能性があるのです。
ですから、depositを伴う処理を行う際は、その残高を管理する変数を用意しなければなりません。(2回目)
まとめ
「SolidityのコントラクトアドレスにEthを送金する」ということ自体、パッとこないので理解しにくかったです。
コントラクトアドレスにEthを送金する方法は3つもあり、その性質上コントラクトを作成するときに注意するべき記述があることがわかりました。
自分が分散取引所を利用するときやスマートコントラクトを利用するときに中身を見る際はここにも注意してみてみようと思いました。