Revert
- We talk to a contract with message calls
- A contract can
REVERTa call, negating all state changes - Each calling contract can choose to handle that success, or
REVERTas well

Message Call Revert
- 🙅♀️ No state changes occur
- 🙅♀️ No value is transfered
- 🙅♀️ No logs are emitted
- ⛽️ Gas is still spent
Require
Often you’ll see require used like this:
contract X {
// shorthand!
address owner = msg.sender;
function ownerOnly() external {
// REVERT if not the owner
require(msg.sender == owner, "only owner!");
// do something owner-y
}
}Revert
Revert can be used with a string revert("Unauthorized") or, better yet:
contract X {
// @notice a non-privileged user attempted to access an admin-only method
error Unauthorized();
function adminOnly() external {
if (!isAdmin(msg.sender)) {
revert Unauthorized();
}
}
}👆⛽️ Gas Efficient!
Assert
Use assert with things that should not happen:
contract X {
function withdraw() external {
uint balance = getBalance(msg.sender);
sendBalance(msg.sender);
// they should not still have a balance!
assert(getBalance(msg.sender) == 0);
}
}Hands-on
learn-solidity-presentations\3-reverting-transactions\examples\0-revert-require\src\Example.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
import "forge-std/console.sol";
// REVERT
// no state changes should have occured
// no value should have been transferred
// gas will still be paid for
contract A {
address b;
uint256 public errorsCount = 0;
constructor(address _b) {
b = _b;
}
function callB() external payable {
(bool success, bytes memory returnData) = b.call{value: 1 ether}("");
if (!success) {
console.logBytes(returnData);
console.logBytes32(keccak256("DoNotPayMe(uint256)"));
errorsCount++;
}
}
}
contract B {
uint256 public x = 0;
// @notice nobody should ever pay this contract
// 4 byte
error DoNotPayMe(uint256);
receive() external payable {
x = 15;
revert DoNotPayMe(msg.value);
}
}learn-solidity-presentations\3-reverting-transactions\examples\0-revert-require\test\Example.t.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
import "../src/Example.sol";
contract ExampleTest is Test {
A public a;
B public b;
function setUp() public {
b = new B();
a = new A(address(b));
}
function testExample() public {
a.callB{value: 1.5 ether}();
assertEq(address(a).balance, 1.5 ether);
assertEq(a.errorsCount(), 1);
assertEq(b.x(), 0);
}
}edo@DESKTOP-4POSOVK:/mnt/e/Programming/Solidity/learn-solidity-presentations/3-reverting-transactions/examples/0-revert-require/src$ forge test -vv
[⠑] Compiling...
[⠔] Compiling 20 files with 0.8.25
[⠃] Solc 0.8.25 finished in 1.73s
Compiler run successful!
Ran 1 test for test/Example.t.sol:ExampleTest
[PASS] testExample() (gas: 77397)
Logs:
0x568804630000000000000000000000000000000000000000000000000de0b6b3a7640000
0x568804639171345705b794b2fd1a938758dc6b678c203b630b224e0da48a84ad
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 14.10ms (3.07ms CPU time)
Ran 1 test suite in 55.17ms (14.10ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)
Learn Solidity. Alchemy University.
Accessed January 1, 2025
https://university.alchemy.com/overview/solidity