Using assembly to revert with an error message
When optimizing gas usage in smart contracts, using assembly for revert statements can lead to gas savings. While Solidity's require
and revert
statements are convenient, implementing the same functionality with assembly can be more gas-efficient.
Solidity charges additional gas for memory expansion and type checking when using standard revert statements. By using assembly, we can bypass these overhead costs while maintaining the same functionality.
Gas Comparison Example
Here's a comparative example showing both approaches:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract SolidityRevert {
address owner;
uint256 specialNumber = 1;
constructor() {
owner = msg.sender;
}
function restrictedAction(uint256 num) external {
require(owner == msg.sender, "caller is not owner");
specialNumber = num;
}
}
contract AssemblyRevert {
address owner;
uint256 specialNumber = 1;
constructor() {
owner = msg.sender;
}
function restrictedAction(uint256 num) external {
assembly {
if sub(caller(), sload(owner.slot)) {
// Store offset to error message length
mstore(0x00, 0x20)
// Store length of error message
mstore(0x20, 0x13)
// Store the error message
mstore(0x40, 0x63616c6c6572206973206e6f74206f776e657200000000000000000000000000)
// Revert with data (offset, size)
revert(0x00, 0x60)
}
}
specialNumber = num;
}
}
Gas Analysis
Implementation | Gas Cost | Gas Saved |
---|---|---|
Solidity Revert | 24,042 | - |
Assembly Revert | 23,734 | 308 |
Understanding the Assembly Implementation
The assembly revert implementation consists of several key components:
- Condition Check:
if sub(caller(), sload(owner.slot))
- Memory Layout:
0x00
: Stores the offset (0x20)0x20
: Stores the error message length (0x13 = 19 bytes)0x40
: Stores the actual error message in hex
- Revert Operation:
revert(0x00, 0x60)
The first parameter (0x00) is the memory offset, and the second (0x60) is the size of the data to revert with.
Key Points:
- Assembly revert statements are more gas-efficient than Solidity's
require
andrevert
- Gas savings come from avoiding memory expansion costs and compiler type checks
- The same error messages can be preserved while reducing gas costs