概要

はい、Solidityにおけるmodifierとrequireの違いと使い方について解説します。
簡単に言うと、modifierは関数の振る舞いを「修飾」するための再利用可能なコードで、requireは関数内で特定の条件を「検証」するためのステートメントです。
目次
modifier
と require
の違い
特徴 | modifier (修飾子) | require (検証) |
目的 | 関数の実行前後に共通のチェックや処理を追加する(コードの再利用) | 関数内の特定の時点で、条件が真であるか検証する |
使い方 | 関数定義に付与して使用する | 関数本体の中に記述する |
主な用途 | アクセス制御(例:onlyOwner )、状態チェックの共通化 | 入力値の検証、関数の実行条件チェック |
コード構造 | 独立したコードブロックとして定義 | 関数内の1行のステートメント |
エラー処理 | 内部でrequire などを用いて条件をチェックし、失敗するとリバート | 条件がfalse の場合、トランザクションをリバート(実行を取り消す) |
modifier
の使い方
modifier
は、特に関数の実行権限をチェックするような、複数の関数で繰り返し使われるロジックをまとめるのに非常に便利です。これにより、コードがDRY (Don't Repeat Yourself) になり、可読性と保守性が向上します。
modifier
の重要な要素は _
(アンダースコア) です。これは「修飾された関数の本体コード」を表し、modifier
内のロジックのどこで元の関数を実行するかを示します。
具体例:onlyOwner
コントラクトの所有者だけが実行できる関数を定義する際によく使われます。
Solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract OwnerExample {
address public owner;
// イベントを定義
event OwnerChanged(address indexed oldOwner, address indexed newOwner);
// modifierを定義
modifier onlyOwner() {
// msg.senderがownerでなければエラーメッセージと共にリバート
require(msg.sender == owner, "Caller is not the owner");
_; // このmodifierが付いた関数の本体がここで実行される
}
// コンストラクタで初期のownerを設定
constructor() {
owner = msg.sender;
}
// 新しいownerを設定する関数。onlyOwner modifierが付いている
function changeOwner(address _newOwner) public onlyOwner {
address oldOwner = owner;
owner = _newOwner;
emit OwnerChanged(oldOwner, _newOwner);
}
// 誰でも呼び出せる関数
function getOwner() public view returns (address) {
return owner;
}
}
この例では、changeOwner
関数にonlyOwner
modifier
が付与されています。これにより、changeOwner
が呼び出されると、まずonlyOwner
内のrequire
が実行され、呼び出し元がowner
であることが確認されます。条件を満たした場合にのみ、_
の部分、つまりchangeOwner
関数本体のロジックが実行されます。
require
の使い方
require
は、関数の実行を続けるための前提条件をチェックするために使います。条件が満たされない(false
になる)場合、トランザクションは即座に停止(リバート)され、残りのガスはユーザーに返還されます。
require(条件, "エラーメッセージ");
の形式で使います。
具体例:入金額のチェック
ユーザーがETHを入金する際に、その額が0より大きいことを保証する場面で使われます。
Solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract VendingMachine {
mapping(address => uint) public balances;
// ETHを入金する関数
function deposit() public payable {
// requireを使って、入金額が0より大きいことを検証
require(msg.value > 0, "Deposit amount must be greater than 0.");
balances[msg.sender] += msg.value;
}
// 残高を引き出す関数
function withdraw(uint _amount) public {
// requireを使って、引き出し額が残高以下であることを検証
require(_amount <= balances[msg.sender], "Insufficient balance.");
balances[msg.sender] -= _amount;
payable(msg.sender).transfer(_amount);
}
}
この例では、deposit
関数はmsg.value
(送られてきたETHの量)が0より大きいことをrequire
でチェックします。もし0ETHでこの関数を呼び出した場合、トランザクションは"Deposit amount must be greater than 0."というメッセージと共に失敗します。同様にwithdraw
関数では、引き出し額が残高を超えていないかをチェックしています。
まとめ
modifier
: 複数の関数にまたがる共通の事前・事後チェック(特にアクセス制御)に使います。コードをすっきりと保つための「飾り付け」のようなものです。require
: ある関数内での一度きりの特定の条件検証(入力値の正当性チェックなど)に使います。関数の実行を許可するための「関所」のようなものです。
これらを適切に使い分けることで、安全で読みやすいスマートコントラクトを記述することができます。