This article explains how to secure your smart contracts against arithmetic overflows and underflows
Prerequisites: A basic understanding of the Ethereum Blockchain and Smart Contracts.
Introduction
This is part 2 of a series on securing your Smart Contracts. Part 1 discussed reentrancy and owner-logic theft attacks.
Here, we’ll go through arithmetic overflows and underflows, a type of logic weakness that can sometimes creep into our code. We’ll describe what they mean, examples of how they might appear, and how to prevent them from appearing in our smart contracts.
What Are They?
To understand arithmetic over- and underflows, we must first understand the data types in which they appear.
Ethereum Virtual Machine (EVM) integers are always of a fixed size. For example, unit8
can only store values between (and including) 0 and 255. Trying to store the value 256 in a uint8
variable will result in a value of 0. This is ripe for exploitation if no checks are made before execution.
Underflows
An underflow can appear when a value is subtracted from an integer, where the current value of that integer is less than the value being subtracted. For example:
uint8 myValue = 2;
uint8 subValue = 3;
uint8 result = myValue - subValue;
Here, our result
variable would not equal -1 as we think it should; result
would equal 255.
Counting backwards from 2, the EVM goes … 1 … 0 … 255. This is known as an underflow.
Overflows
An overflow is the opposite of an underflow. It can appear when a value is added to an integer variable, where the result is greater than the maximum limit of that variable’s data type. For example:
uint8 myValue = 254;
uint8 addValue = 3;
uint8 result = myValue + addValue;
Here, our result
variable does not equal 257 as we think it should. It gets calculated to 1 because 255 is the maximum value of uint8
.
Counting upward from 254, the EVM goes … 255 … 0 … 1. This is known as an overflow.
Example
Consider this piece of Solidity code, and before scrolling to the explanation, can you spot the problem?
mapping(address => uint) balances;function withdraw(uint _value) external {
require(balances[msg.sender] - _value >= 0);
balances[msg.sender] -= _value;
msg.sender.transfer(_value);
}
The require
statement requires that the balance of the sender minus the withdraw value is greater than or equal to 0. This makes sense to us logically since we don’t want to allow anyone to withdraw more than they have in their balance. However, this is vulnerable to underflow exploitation.
If the attacker had two Ether stored in the contract and attempted to withdraw ten, the require
statement would allow it. This is because the subtraction would cause the result of balances[msg.sender] — _value
to be greater than or equal to 0 by underflowing to the maximum. Because the integer is unsigned, the require
statement will always pass as long as the msg.sender
has a balance.
By this logic, anyone who has deposited a balance at any point can completely rinse the contract of funds.
Preventative Measures
Always use libraries that provide safer functions to perform basic arithmetic. OpenZeppelin’s SafeMath library is the most commonly used in the Solidity community. It provides functions for addition, subtraction, multiplication, division, and modulus.
The library is thoroughly scrutinized by the community before being released, so we can have confidence in its ability to prevent arithmetic logic bugs. Here’s an example of how to use SafeMath’s sub()
function instead of using the minus arithmetic operator in our smart contract:
using SafeMath for uint;function withdraw(uint _value) external {
require(balances[msg.sender].sub(_value) >= 0);
balances[msg.sender] -= _value;
msg.sender.transfer(_value);
}
In this scenario, the require
statement would fail if we attempted to withdraw more than our balance. This is because the sub()
function requires the balance to be greater than or equal to _value
.
Learn More
If you’re interested in Blockchain Development, I write tutorials, walkthroughs, hints, and tips on how to get started and build a portfolio. Check out this evolving list of Blockchain Development Resources.
If you enjoyed this post and want to learn more about Smart Contract Security, Blockchain Development or the Blockchain Space in general, I highly recommend signing up to the Blockgeeks platform. They have courses on a wide range of topics in the industry, from Coding to Marketing to Trading. It has proven to be an invaluable tool for my development in the Blockchain space.