導入
コントラクトの中で何が起きたかを外部に知らせ、履歴として残すのが 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/>取引履歴を表示]
やってみよう
「状態として保存する(高い・コントラクトから読める)」か「イベントとして記録する(安い・コントラクトからは読めない/外部監視向け)」かは、設計の分かれ道です。コントラクトのロジックで使う値は状態変数、履歴や通知はイベント、という使い分けを意識しましょう。