本文へスキップ
BecomeCoder

Solidityコース · 第4章 制御・お金・安全性 ― require・payable・event · レッスン19

event ― ブロックチェーンのログ

ブラウザで完結

導入

コントラクトの中で何が起きたかを外部に知らせ、履歴として残すのが event(イベント) です。アプリの画面更新や、取引履歴の表示に不可欠な仕組みです。

説明

送金があったことをイベントで記録してみます。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract Ledger {
    // イベントの定義(indexed は後から検索しやすくする印)
    event Transfer(address indexed from, address indexed to, uint256 amount);

    mapping(address => uint256) public balances;

    // デプロイした人に初期残高を配っておく(動かして試せるように)
    constructor() {
        balances[msg.sender] = 1000;
    }

    function send(address to, uint256 amount) public {
        require(balances[msg.sender] >= amount, "not enough");
        balances[msg.sender] -= amount;
        balances[to] += amount;

        emit Transfer(msg.sender, to, amount);   // イベントを発火
    }
}
  • event Transfer(...) … イベントの定義。「何を記録するか」を宣言する。
  • emit Transfer(...) … 実際にイベントを発火する。これがブロックチェーンログに残る。
  • indexed … その引数を検索キーにできる印(最大3つまで)。「このアドレスが関わった送金だけ」を後から効率よく絞り込める。

イベントの利点は ガスが安く、外部から監視しやすいこと。DApp のフロントエンド(ブラウザ側の画面)は、このイベントを購読して「送金がありました」とリアルタイムに表示を更新します。状態変数に全履歴を配列で貯めるより、ずっと安価です。

graph LR
    C["コントラクト<br/>emit Transfer(...)"] --> L[(ブロックチェーンの<br/>イベントログ)]
    L --> F[フロントエンド<br/>画面を更新]
    L --> E[エクスプローラ<br/>取引履歴を表示]

やってみよう

「状態として保存する(高い・コントラクトから読める)」か「イベントとして記録する(安い・コントラクトからは読めない/外部監視向け)」かは、設計の分かれ道です。コントラクトのロジックで使う値は状態変数、履歴や通知はイベント、という使い分けを意識しましょう。

実際に動かしてみよう

下のエディタのコントラクトを「コンパイル & デプロイ」すると、ブラウザ内で本物のSolidityコンパイラ(solc)がコンパイルし、EVM(@ethereumjs)にデプロイされます。デプロイ後は public な関数がボタンになって並ぶので、引数を入れて呼び出すと戻り値・イベント・require のエラー(revert理由)まで確認できます。本文のコントラクトを書き換えて動きを試しながら進めましょう(コンパイラ本体は初回だけ読み込みに数秒かかります)。

Solidity — ブラウザ内でコンパイル & 実行

ブラウザ内で本物のSolidityコンパイラ(solc)とEVM(@ethereumjs)を動かす環境を読み込みます(コンパイラ本体は初回のコンパイル時に読み込むため、最初の実行だけ数秒かかります)。
スクロールして表示された時点でも自動で読み込まれます。