Modifier
modifier бол функц ажиллахаас өмнө эсвэл дараа автоматаар ажилладаг кодын хэсэг. require(msg.sender == owner) шалгалтыг функц бүрд давтаж бичихийн оронд нэг modifier-д нэгтгэж, олон функцэд хавсаргана.
Modifier тодорхойлох
modifier modifierName() {
// өмнөх шалгалт
require(..., "алдааны мессеж");
_; // ← функцийн бие энд ажиллана
// дараах код (хэрэв байвал)
}
_; нь функцийн бие орох байрыг заана. Энэ тэмдэггүй бол modifier compile хийгдэхгүй.
onlyOwner загвар
Хамгийн түгээмэл modifier — зөвхөн owner үйлдэл хийж болно:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
contract Ownable {
address public owner;
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner, "Зөвхөн эзэмшигч");
_;
}
// modifier хавсаргасан функцүүд
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0), "Хүчингүй хаяг");
owner = newOwner;
}
function withdraw() public onlyOwner {
payable(owner).transfer(address(this).balance);
}
function pause() public onlyOwner {
// зогсоох логик
}
}
onlyOwner modifier байхгүй бол:
// ❌ давтагдсан код — засах хэцүү
function transferOwnership(address newOwner) public {
require(msg.sender == owner, "Зөвхөн эзэмшигч"); // ← давтагдана
owner = newOwner;
}
function withdraw() public {
require(msg.sender == owner, "Зөвхөн эзэмшигч"); // ← давтагдана
payable(owner).transfer(address(this).balance);
}
Параметртэй modifier
Modifier параметр авч болно — илүү уян хатан шалгалт хийх боломж олгодог:
contract TokenSale {
mapping(address => uint256) public balances;
uint256 public constant MAX_BUY = 1000;
modifier minAmount(uint256 amount, uint256 minimum) {
require(amount >= minimum, "Дүн хэт бага байна");
_;
}
modifier maxAmount(uint256 amount, uint256 maximum) {
require(amount <= maximum, "Дүн хэт их байна");
_;
}
modifier validAddress(address addr) {
require(addr != address(0), "Хүчингүй хаяг");
require(addr != msg.sender, "Өөртөө илгээх боломжгүй");
_;
}
function buy(uint256 amount)
public
payable
minAmount(amount, 10)
maxAmount(amount, MAX_BUY)
{
balances[msg.sender] += amount;
}
function transfer(address to, uint256 amount)
public
validAddress(to)
minAmount(amount, 1)
{
require(balances[msg.sender] >= amount, "Үлдэгдэл хүрэлцэхгүй");
balances[msg.sender] -= amount;
balances[to] += amount;
}
}
Олон modifier хослуулах
Функцэд хэд хэдэн modifier хавсаргаж болно — зүүнээс баруун тийш дарааллаар ажиллана:
contract Auction {
address public owner;
bool public isActive;
uint256 public endTime;
constructor() {
owner = msg.sender;
isActive = false;
}
modifier onlyOwner() {
require(msg.sender == owner, "Зөвхөн эзэмшигч");
_;
}
modifier whenActive() {
require(isActive, "Дуусгавар биш байна");
_;
}
modifier notEnded() {
require(block.timestamp < endTime, "Хугацаа дууссан");
_;
}
modifier whenNotActive() {
require(!isActive, "Аль хэдийн идэвхтэй байна");
_;
}
// modifier дараалал: onlyOwner → whenNotActive
function start(uint256 duration) public onlyOwner whenNotActive {
isActive = true;
endTime = block.timestamp + duration;
}
// modifier дараалал: whenActive → notEnded
function bid() public payable whenActive notEnded {
require(msg.value > 0, "ETH илгээх ёстой");
// дуусгавар биш логик
}
// modifier дараалал: onlyOwner → whenActive
function cancel() public onlyOwner whenActive {
isActive = false;
}
}
Modifier-ийн ажиллах дараалал:
bid() дуудагдахад:
1. whenActive шалгана → isActive == true?
↓ тийм
2. notEnded шалгана → timestamp < endTime?
↓ тийм
3. bid()-ийн бие ажиллана
Modifier-ийн _; байрлал
_; нь функцийн бие хаана ажиллах-г тодорхойлно. Өмнө эсвэл дараа тавьж болно:
// Өмнө шалгаад функц ажиллуулах (хамгийн түгээмэл)
modifier checkBefore() {
require(condition, "Шалгалт амжилтгүй");
_; // функцийн бие энд
}
// Функц ажиллуулаад дараа нь шалгах / цэвэрлэх
modifier checkAfter() {
_; // функцийн бие энд
require(result > 0, "Үр дүн хүчингүй");
}
// Өмнө тохируулж, функц ажиллуулж, дараа нь цэвэрлэх (reentrancy guard)
modifier nonReentrant() {
require(!locked, "Reentrancy хориглогдсон");
locked = true;
_; // функцийн бие энд
locked = false;
}
Бодит жишээ: Crowdfund contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
contract Crowdfund {
address public owner;
uint256 public goal;
uint256 public deadline;
uint256 public raised;
bool public finalized;
mapping(address => uint256) public contributions;
event Contributed(address indexed contributor, uint256 amount);
event Finalized(bool goalReached, uint256 totalRaised);
constructor(uint256 _goalWei, uint256 _durationSeconds) {
owner = msg.sender;
goal = _goalWei;
deadline = block.timestamp + _durationSeconds;
}
modifier onlyOwner() {
require(msg.sender == owner, "Зөвхөн эзэмшигч");
_;
}
modifier beforeDeadline() {
require(block.timestamp < deadline, "Хугацаа дууссан");
_;
}
modifier afterDeadline() {
require(block.timestamp >= deadline, "Хугацаа дуусаагүй");
_;
}
modifier notFinalized() {
require(!finalized, "Аль хэдийн дуусгавар болсон");
_;
}
function contribute() public payable beforeDeadline notFinalized {
require(msg.value > 0, "ETH илгээх ёстой");
contributions[msg.sender] += msg.value;
raised += msg.value;
emit Contributed(msg.sender, msg.value);
}
function finalize() public onlyOwner afterDeadline notFinalized {
finalized = true;
if (raised >= goal) {
payable(owner).transfer(raised);
}
emit Finalized(raised >= goal, raised);
}
function refund() public afterDeadline {
require(raised < goal, "Зорилго биелсэн — буцаалт байхгүй");
require(contributions[msg.sender] > 0, "Оруулсан хувь байхгүй");
uint256 amount = contributions[msg.sender];
contributions[msg.sender] = 0;
payable(msg.sender).transfer(amount);
}
}
Дараагийн хичээлд:
require, revert, assert — алдааг зохицуулах гурван механизм, тэдгээрийн ялгаа, хэзээ аль нэгийг ашиглахыг судална.