mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Use errors in examples.
This commit is contained in:
parent
0c1be06cba
commit
786ae2ceec
@ -28,7 +28,7 @@ you receive the funds of the person who is now the richest.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.7.0 <0.9.0;
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
contract WithdrawalContract {
|
||||
address public richest;
|
||||
@ -36,13 +36,17 @@ you receive the funds of the person who is now the richest.
|
||||
|
||||
mapping (address => uint) pendingWithdrawals;
|
||||
|
||||
/// The amount of Ether sent was not higher than
|
||||
/// the currently highest amount.
|
||||
error NotEnoughEther();
|
||||
|
||||
constructor() payable {
|
||||
richest = msg.sender;
|
||||
mostSent = msg.value;
|
||||
}
|
||||
|
||||
function becomeRichest() public payable {
|
||||
require(msg.value > mostSent, "Not enough money sent.");
|
||||
if (msg.value <= mostSent) revert NotEnoughEther();
|
||||
pendingWithdrawals[richest] += msg.value;
|
||||
richest = msg.sender;
|
||||
mostSent = msg.value;
|
||||
@ -62,19 +66,23 @@ This is as opposed to the more intuitive sending pattern:
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.7.0 <0.9.0;
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
contract SendContract {
|
||||
address payable public richest;
|
||||
uint public mostSent;
|
||||
|
||||
/// The amount of Ether sent was not higher than
|
||||
/// the currently highest amount.
|
||||
error NotEnoughEther();
|
||||
|
||||
constructor() payable {
|
||||
richest = payable(msg.sender);
|
||||
mostSent = msg.value;
|
||||
}
|
||||
|
||||
function becomeRichest() public payable {
|
||||
require(msg.value > mostSent, "Not enough money sent.");
|
||||
if (msg.value <= mostSent) revert NotEnoughEther();
|
||||
// This line can cause problems (explained below).
|
||||
richest.transfer(msg.value);
|
||||
richest = payable(msg.sender);
|
||||
@ -124,7 +132,7 @@ restrictions highly readable.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.0 <0.9.0;
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
contract AccessRestriction {
|
||||
// These will be assigned at the construction
|
||||
@ -133,6 +141,21 @@ restrictions highly readable.
|
||||
address public owner = msg.sender;
|
||||
uint public creationTime = block.timestamp;
|
||||
|
||||
// Now follows a list of errors that
|
||||
// this contract can generate together
|
||||
// with a textual explanation in special
|
||||
// comments.
|
||||
|
||||
/// Sender not authorized for this
|
||||
/// operation.
|
||||
error Unauthorized();
|
||||
|
||||
/// Function called too early.
|
||||
error TooEarly();
|
||||
|
||||
/// Not enough Ether sent with function call.
|
||||
error NotEnoughEther();
|
||||
|
||||
// Modifiers can be used to change
|
||||
// the body of a function.
|
||||
// If this modifier is used, it will
|
||||
@ -141,10 +164,8 @@ restrictions highly readable.
|
||||
// a certain address.
|
||||
modifier onlyBy(address _account)
|
||||
{
|
||||
require(
|
||||
msg.sender == _account,
|
||||
"Sender not authorized."
|
||||
);
|
||||
if (msg.sender != _account)
|
||||
revert Unauthorized();
|
||||
// Do not forget the "_;"! It will
|
||||
// be replaced by the actual function
|
||||
// body when the modifier is used.
|
||||
@ -161,10 +182,8 @@ restrictions highly readable.
|
||||
}
|
||||
|
||||
modifier onlyAfter(uint _time) {
|
||||
require(
|
||||
block.timestamp >= _time,
|
||||
"Function called too early."
|
||||
);
|
||||
if (block.timestamp < _time)
|
||||
revert TooEarly();
|
||||
_;
|
||||
}
|
||||
|
||||
@ -186,10 +205,9 @@ restrictions highly readable.
|
||||
// This was dangerous before Solidity version 0.4.0,
|
||||
// where it was possible to skip the part after `_;`.
|
||||
modifier costs(uint _amount) {
|
||||
require(
|
||||
msg.value >= _amount,
|
||||
"Not enough Ether provided."
|
||||
);
|
||||
if (msg.value < _amount)
|
||||
revert NotEnoughEther();
|
||||
|
||||
_;
|
||||
if (msg.value > _amount)
|
||||
payable(msg.sender).transfer(msg.value - _amount);
|
||||
@ -277,7 +295,7 @@ function finishes.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.22 <0.9.0;
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
contract StateMachine {
|
||||
enum Stages {
|
||||
@ -287,6 +305,8 @@ function finishes.
|
||||
AreWeDoneYet,
|
||||
Finished
|
||||
}
|
||||
/// Function cannot be called at this time.
|
||||
error FunctionInvalidAtThisStage();
|
||||
|
||||
// This is the current stage.
|
||||
Stages public stage = Stages.AcceptingBlindedBids;
|
||||
@ -294,10 +314,8 @@ function finishes.
|
||||
uint public creationTime = block.timestamp;
|
||||
|
||||
modifier atStage(Stages _stage) {
|
||||
require(
|
||||
stage == _stage,
|
||||
"Function cannot be called at this time."
|
||||
);
|
||||
if (stage != _stage)
|
||||
revert FunctionInvalidAtThisStage();
|
||||
_;
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ to receive their money - contracts cannot activate themselves.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.7.0 <0.9.0;
|
||||
pragma solidity ^0.8.4;
|
||||
contract SimpleAuction {
|
||||
// Parameters of the auction. Times are either
|
||||
// absolute unix timestamps (seconds since 1970-01-01)
|
||||
@ -48,10 +48,21 @@ to receive their money - contracts cannot activate themselves.
|
||||
event HighestBidIncreased(address bidder, uint amount);
|
||||
event AuctionEnded(address winner, uint amount);
|
||||
|
||||
// The following is a so-called natspec comment,
|
||||
// recognizable by the three slashes.
|
||||
// It will be shown when the user is asked to
|
||||
// confirm a transaction.
|
||||
// Errors that describe failures.
|
||||
|
||||
// The triple-slash comments are so-called natspec
|
||||
// comments. They will be shown when the user
|
||||
// is asked to confirm a transaction or
|
||||
// when an error is displayed.
|
||||
|
||||
/// The auction has already ended.
|
||||
error AuctionAlreadyEnded();
|
||||
/// There is already a higher or equal bid.
|
||||
error BidNotHighEnough(uint highestBid);
|
||||
/// The auction has not ended yet.
|
||||
error AuctionNotYetEnded();
|
||||
/// The function auctionEnd has already been called.
|
||||
error AuctionEndAlreadyCalled();
|
||||
|
||||
/// Create a simple auction with `_biddingTime`
|
||||
/// seconds bidding time on behalf of the
|
||||
@ -77,20 +88,16 @@ to receive their money - contracts cannot activate themselves.
|
||||
|
||||
// Revert the call if the bidding
|
||||
// period is over.
|
||||
require(
|
||||
block.timestamp <= auctionEndTime,
|
||||
"Auction already ended."
|
||||
);
|
||||
if (block.timestamp > auctionEndTime)
|
||||
revert AuctionAlreadyEnded();
|
||||
|
||||
// If the bid is not higher, send the
|
||||
// money back (the failing require
|
||||
// money back (the revert statement
|
||||
// will revert all changes in this
|
||||
// function execution including
|
||||
// it having received the money).
|
||||
require(
|
||||
msg.value > highestBid,
|
||||
"There already is a higher bid."
|
||||
);
|
||||
if (msg.value <= highestBid)
|
||||
revert BidNotHighEnough(highestBid);
|
||||
|
||||
if (highestBid != 0) {
|
||||
// Sending back the money by simply using
|
||||
@ -140,8 +147,10 @@ to receive their money - contracts cannot activate themselves.
|
||||
// external contracts.
|
||||
|
||||
// 1. Conditions
|
||||
require(block.timestamp >= auctionEndTime, "Auction not yet ended.");
|
||||
require(!ended, "auctionEnd has already been called.");
|
||||
if (block.timestamp < auctionEndTime)
|
||||
revert AuctionNotYetEnded();
|
||||
if (ended)
|
||||
revert AuctionEndAlreadyCalled();
|
||||
|
||||
// 2. Effects
|
||||
ended = true;
|
||||
@ -185,7 +194,7 @@ invalid bids.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.3;
|
||||
pragma solidity ^0.8.4;
|
||||
contract BlindAuction {
|
||||
struct Bid {
|
||||
bytes32 blindedBid;
|
||||
@ -207,12 +216,29 @@ invalid bids.
|
||||
|
||||
event AuctionEnded(address winner, uint highestBid);
|
||||
|
||||
/// Modifiers are a convenient way to validate inputs to
|
||||
/// functions. `onlyBefore` is applied to `bid` below:
|
||||
/// The new function body is the modifier's body where
|
||||
/// `_` is replaced by the old function body.
|
||||
modifier onlyBefore(uint _time) { require(block.timestamp < _time); _; }
|
||||
modifier onlyAfter(uint _time) { require(block.timestamp > _time); _; }
|
||||
// Errors that describe failures.
|
||||
|
||||
/// The function has been called too early.
|
||||
/// Try again at `time`.
|
||||
error TooEarly(uint time);
|
||||
/// The function has been called too late.
|
||||
/// It cannot be called after `time`.
|
||||
error TooLate(uint time);
|
||||
/// The function auctionEnd has already been called.
|
||||
error AuctionEndAlreadyCalled();
|
||||
|
||||
// Modifiers are a convenient way to validate inputs to
|
||||
// functions. `onlyBefore` is applied to `bid` below:
|
||||
// The new function body is the modifier's body where
|
||||
// `_` is replaced by the old function body.
|
||||
modifier onlyBefore(uint _time) {
|
||||
if (block.timestamp >= _time) revert TooLate(_time);
|
||||
_;
|
||||
}
|
||||
modifier onlyAfter(uint _time) {
|
||||
if (block.timestamp <= _time) revert TooEarly(_time);
|
||||
_;
|
||||
}
|
||||
|
||||
constructor(
|
||||
uint _biddingTime,
|
||||
@ -303,7 +329,7 @@ invalid bids.
|
||||
public
|
||||
onlyAfter(revealEnd)
|
||||
{
|
||||
require(!ended);
|
||||
if (ended) revert AuctionEndAlreadyCalled();
|
||||
emit AuctionEnded(highestBidder, highestBid);
|
||||
ended = true;
|
||||
beneficiary.transfer(highestBid);
|
||||
|
@ -26,7 +26,7 @@ you can use state machine-like constructs inside a contract.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.7.0 <0.9.0;
|
||||
pragma solidity ^0.8.4;
|
||||
contract Purchase {
|
||||
uint public value;
|
||||
address payable public seller;
|
||||
@ -41,27 +41,30 @@ you can use state machine-like constructs inside a contract.
|
||||
_;
|
||||
}
|
||||
|
||||
/// Only the buyer can call this function.
|
||||
error OnlyBuyer();
|
||||
/// Only the seller can call this function.
|
||||
error OnlySeller();
|
||||
/// The function cannot be called at the current state.
|
||||
error InvalidState();
|
||||
/// The provided value has to be even.
|
||||
error ValueNotEven();
|
||||
|
||||
modifier onlyBuyer() {
|
||||
require(
|
||||
msg.sender == buyer,
|
||||
"Only buyer can call this."
|
||||
);
|
||||
if (msg.sender != buyer)
|
||||
revert OnlyBuyer();
|
||||
_;
|
||||
}
|
||||
|
||||
modifier onlySeller() {
|
||||
require(
|
||||
msg.sender == seller,
|
||||
"Only seller can call this."
|
||||
);
|
||||
if (msg.sender != seller)
|
||||
revert OnlySeller();
|
||||
_;
|
||||
}
|
||||
|
||||
modifier inState(State _state) {
|
||||
require(
|
||||
state == _state,
|
||||
"Invalid state."
|
||||
);
|
||||
if (state != _state)
|
||||
revert InvalidState();
|
||||
_;
|
||||
}
|
||||
|
||||
@ -76,7 +79,8 @@ you can use state machine-like constructs inside a contract.
|
||||
constructor() payable {
|
||||
seller = payable(msg.sender);
|
||||
value = msg.value / 2;
|
||||
require((2 * value) == msg.value, "Value has to be even.");
|
||||
if ((2 * value) != msg.value)
|
||||
revert ValueNotEven();
|
||||
}
|
||||
|
||||
/// Abort the purchase and reclaim the ether.
|
||||
|
@ -83,7 +83,7 @@ registering with a username and password, all you need is an Ethereum keypair.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.3;
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
contract Coin {
|
||||
// The keyword "public" makes variables
|
||||
@ -109,11 +109,20 @@ registering with a username and password, all you need is an Ethereum keypair.
|
||||
balances[receiver] += amount;
|
||||
}
|
||||
|
||||
// Errors allow you to provide information about
|
||||
// why an operation failed. They are returned
|
||||
// to the caller of the function.
|
||||
error InsufficientBalance(uint requested, uint available);
|
||||
|
||||
// Sends an amount of existing coins
|
||||
// from any caller to an address
|
||||
function send(address receiver, uint amount) public {
|
||||
// TODO use an error here
|
||||
require(amount <= balances[msg.sender], "Insufficient balance.");
|
||||
if (amount > balances[msg.sender])
|
||||
revert InsufficientBalance({
|
||||
requested: amount,
|
||||
available: balances[msg.sender]
|
||||
});
|
||||
|
||||
balances[msg.sender] -= amount;
|
||||
balances[receiver] += amount;
|
||||
emit Sent(msg.sender, receiver, amount);
|
||||
@ -201,6 +210,14 @@ The :ref:`require <assert-and-require>` function call defines conditions that re
|
||||
In this example, ``require(msg.sender == minter);`` ensures that only the creator of the contract can call ``mint``,
|
||||
and ``require(amount < 1e60);`` ensures a maximum amount of tokens. This ensures that there are no overflow errors in the future.
|
||||
|
||||
:ref:`Errors <errors>` allow you to provide more information to the caller about
|
||||
why a condition or operation failed. Errors are used together with the
|
||||
:ref:`revert statement <revert-statement>`. The revert statement unconditionally
|
||||
aborts and reverts all changes similar to the ``require`` function, but it also
|
||||
allows you to provide the name of an error and additional data which will be supplied to the caller
|
||||
(and eventually to the front-end application or block explorer) so that
|
||||
a failure can more easily be debugged or reacted upon.
|
||||
|
||||
The ``send`` function can be used by anyone (who already
|
||||
has some of these coins) to send coins to anyone else. If the sender does not have
|
||||
enough coins to send, the ``require`` call fails and provides the
|
||||
|
Loading…
Reference in New Issue
Block a user