2019-01-07 12:52:17 +00:00
|
|
|
.. index:: ! function;modifier
|
|
|
|
|
|
|
|
.. _modifiers:
|
|
|
|
|
|
|
|
******************
|
|
|
|
Function Modifiers
|
|
|
|
******************
|
|
|
|
|
2019-12-05 14:23:02 +00:00
|
|
|
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>`.
|
2019-01-07 12:52:17 +00:00
|
|
|
|
2021-06-25 10:25:29 +00:00
|
|
|
.. code-block:: solidity
|
2019-01-07 12:52:17 +00:00
|
|
|
|
2020-05-13 15:45:58 +00:00
|
|
|
// SPDX-License-Identifier: GPL-3.0
|
2020-09-08 08:48:04 +00:00
|
|
|
pragma solidity >0.7.0 <0.9.0;
|
2019-01-07 12:52:17 +00:00
|
|
|
|
|
|
|
contract owned {
|
2020-12-03 22:05:05 +00:00
|
|
|
constructor() { owner = payable(msg.sender); }
|
2019-01-07 12:52:17 +00:00
|
|
|
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 {
|
2019-01-07 12:52:17 +00:00
|
|
|
// 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
|
2019-01-07 12:52:17 +00:00
|
|
|
// they are made by the stored owner.
|
2020-01-08 08:17:59 +00:00
|
|
|
function destroy() public onlyOwner {
|
2019-01-07 12:52:17 +00:00
|
|
|
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 {
|
2019-01-07 12:52:17 +00:00
|
|
|
mapping (address => bool) registeredAddresses;
|
|
|
|
uint price;
|
|
|
|
|
2020-06-23 16:11:34 +00:00
|
|
|
constructor(uint initialPrice) { price = initialPrice; }
|
2019-01-07 12:52:17 +00:00
|
|
|
|
|
|
|
// 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.
|
|
|
|
|
2019-01-07 12:52:17 +00:00
|
|
|
Multiple modifiers are applied to a function by specifying them in a
|
|
|
|
whitespace-separated list and are evaluated in the order presented.
|
|
|
|
|
2021-03-25 16:55:41 +00:00
|
|
|
Modifiers cannot implicitly access or change the arguments and return values of functions they modify.
|
|
|
|
Their values can only be passed to them explicitly at the point of invocation.
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
2019-01-07 12:52:17 +00:00
|
|
|
.. warning::
|
|
|
|
In an earlier version of Solidity, ``return`` statements in functions
|
|
|
|
having modifiers behaved differently.
|
|
|
|
|
2021-03-25 16:55:41 +00:00
|
|
|
An explicit return from a modifier with ``return;`` does not affect the values returned by the function.
|
|
|
|
The modifier can, however, choose not to execute the function body at all and in that case the return
|
|
|
|
variables are set to their :ref:`default values<default-value>` just as if the function had an empty
|
|
|
|
body.
|
|
|
|
|
|
|
|
The ``_`` symbol can appear in the modifier multiple times. Each occurrence is replaced with
|
|
|
|
the function body.
|
2019-01-07 12:52:17 +00:00
|
|
|
|
|
|
|
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).
|