solidity/docs/contracts/function-modifiers.rst

123 lines
4.1 KiB
ReStructuredText
Raw Normal View History

.. index:: ! function;modifier
.. _modifiers:
******************
Function Modifiers
******************
Modifiers can be used to change the behaviour of functions in a declarative way.
For example,
you can use a modifier to automatically check a condition prior to executing the function.
Modifiers are
inheritable properties of contracts and may be overridden by derived contracts, but only
if they are marked ``virtual``. For details, please see
:ref:`Modifier Overriding <modifier-overriding>`.
::
// SPDX-License-Identifier: GPL-3.0
pragma solidity >0.7.0 <0.9.0;
contract owned {
constructor() { owner = payable(msg.sender); }
address payable owner;
// This contract only defines a modifier but does not use
// it: it will be used in derived contracts.
// The function body is inserted where the special symbol
// `_;` in the definition of a modifier appears.
// This means that if the owner calls this function, the
// function is executed and otherwise, an exception is
// thrown.
modifier onlyOwner {
require(
msg.sender == owner,
"Only owner can call this function."
);
_;
}
}
2020-01-08 08:17:59 +00:00
contract destructible is owned {
// This contract inherits the `onlyOwner` modifier from
2020-01-08 17:37:46 +00:00
// `owned` and applies it to the `destroy` function, which
// causes that calls to `destroy` only have an effect if
// they are made by the stored owner.
2020-01-08 08:17:59 +00:00
function destroy() public onlyOwner {
selfdestruct(owner);
}
}
contract priced {
// Modifiers can receive arguments:
modifier costs(uint price) {
if (msg.value >= price) {
_;
}
}
}
2020-01-08 08:17:59 +00:00
contract Register is priced, destructible {
mapping (address => bool) registeredAddresses;
uint price;
2020-06-23 16:11:34 +00:00
constructor(uint initialPrice) { price = initialPrice; }
// It is important to also provide the
// `payable` keyword here, otherwise the function will
// automatically reject all Ether sent to it.
function register() public payable costs(price) {
registeredAddresses[msg.sender] = true;
}
function changePrice(uint _price) public onlyOwner {
price = _price;
}
}
contract Mutex {
bool locked;
modifier noReentrancy() {
require(
!locked,
"Reentrant call."
);
locked = true;
_;
locked = false;
}
/// This function is protected by a mutex, which means that
/// reentrant calls from within `msg.sender.call` cannot call `f` again.
/// The `return 7` statement assigns 7 to the return value but still
/// executes the statement `locked = false` in the modifier.
function f() public noReentrancy returns (uint) {
(bool success,) = msg.sender.call("");
require(success);
return 7;
}
}
2020-11-17 16:11:12 +00:00
If you want to access a modifier ``m`` defined in a contract ``C``, you can use ``C.m`` to
reference it without virtual lookup. It is only possible to use modifiers defined in the current
contract or its base contracts. Modifiers can also be defined in libraries but their use is
limited to functions of the same library.
Multiple modifiers are applied to a function by specifying them in a
whitespace-separated list and are evaluated in the order presented.
.. warning::
In an earlier version of Solidity, ``return`` statements in functions
having modifiers behaved differently.
Explicit returns from a modifier or function body only leave the current
modifier or function body. Return variables are assigned and
control flow continues after the "_" in the preceding modifier.
Arbitrary expressions are allowed for modifier arguments and in this context,
all symbols visible from the function are visible in the modifier. Symbols
introduced in the modifier are not visible in the function (as they might
change by overriding).