Smart Contract : Security Patterns

Seungwon Go
Dec 20, 2018 · 4 min read

By Seungwon Go, CEO & Founder at ReturnValues (seungwon.go@returnvalues.com)

Checks Effects Interaction Patern

Checks Effects Interaction Pattern is a basic coding pattern that prevents an unexpected execution of a contract. This is a programming pattern that checks all the prerequisites before executing a feature in a certain function.

The following code is an example where Checks Effects Interaction pattern.

function auctionEnd() public { 
// 1. Checks require(now >= auctionEnd);
require(!ended);
// 2. Effects
ended = true;
// 3. Interaction
beneficiary.transfer(highestBid);
}

The code below is vulnerable to re-entrancy attack since Checks Effects Interaction pattern is not used.

// INSECURE
mapping (address => uint) private userBalances;
function withdrawBalance() public {
uint amountToWithdraw = userBalances[msg.sender];
if (!(msg.sender.call.value(amountToWithdraw)())) { throw; } // At this point, the caller's code is executed, and can call withdrawBalance again
userBalances[msg.sender] = 0;
}

In the example above, you can withdraw more amount than there is left by calling withdrawBalance() recursively before userBalances[msg.sender]=0; gets run.

You can prevent reculsive calling of withdrawBalance() by managing the reentrancy state as in the code below.

bool private reentrancyLock = false;modifier nonReentrancy() {
require(!reentrancyLock);
reentrancyLock = true;
_;
reentrancyLock = false;
}
mapping (address => uint) private userBalances;function withdrawBalance() public nonReentrancy() {
uint amountToWithdraw = userBalances[msg.sender];
if (!(msg.sender.call.value(amountToWithdraw)())) { throw; } // At this point, the caller's code is executed, and can call withdrawBalance again
userBalances[msg.sender] = 0;
}

Emergency Stop Pattern

Once a smart contract is deployed to blockchain, it cannot be changed. That’s why an unexpected bug can cause a lot of damage. Emergency Stop pattern stops certain functions from executing when an unexpected bug occurs.

You might be familiar with Pausable contracts but it is more useful to use halt, which is much stronger and permanent. Pausable provides a feature that stops the contract from executing according to the intention of the contract owner for a while. The reason doesn’t have to be a bug.

contract EmergencyStop is Owned { 
bool public contractStopped = false;
modifier haltInEmergency {
require(contractStopped)
_;
}
modifier enableInEmergency {
require(!contractStopped)
_;
}
function toggleContractStopped() public onlyOwner {
contractStopped = !contractStopped;
}
function deposit() public payable haltInEmergency {
// some code
}
function withdraw() public view enableInEmergency {
// some code
}
}

Speed Bump Pattern

Speed bumps on the road are meant to slow down the speed of a car on the road. They are usually located in the neighborhood of a school or a residential complex, where there’s a need to protect pedestrians.

Speed Bump pattern is a programming pattern where you set a limit to withdrawal by setting a time interval or a maximum amount. It is for preventing many users from calling a certain function endless causing malfunction of the contract.

In the code below, we call a requestWithdrawal function to save how much has been withdrawn before actual withdrawal. And the actual withdrawal is executed through the withdraw function. And when withdraw function is called, it checks if 7 days have been passed since the withdrawal was requested by calling requestWithdrawal.

contract SpeedBump { 
struct Withdrawal {
uint amount;
uint requestedAt;
}
mapping (address => uint) private balances;
mapping (address => Withdrawal) private withdrawals;
uint constant WAIT_PERIOD = 7 days;
function deposit() public payable {
if(!(withdrawals[msg.sender].amount > 0)) {
balances[msg.sender] += msg.value;
}
}
function requestWithdrawal() public {
if (balances[msg.sender] > 0) {
uint amountToWithdraw = balances[msg.sender];
balances[msg.sender] = 0;
withdrawals[msg.sender] = Withdrawal({ amount: amountToWithdraw, requestedAt: now });
}
}
function withdraw() public {
if(withdrawals[msg.sender].amount > 0 && now > withdrawals[msg.sender].requestedAt + WAIT_PERIOD) {
uint amount = withdrawals[msg.sender].amount;
withdrawals[msg.sender].amount = 0;
msg.sender.transfer(amount);
}
}
}

Rate Limit Pattern

Rate Limit pattern is a programming pattern that limits the frequency of calling a certain function. The code below is programmed so that function f can be executed only after 1 minute has passed since the last execution.

contract RateLimit { 
uint enabledAt = now;
modifier enabledEvery(uint t) {
if (now >= enabledAt) {
enabledAt = now + t;
_;
}
}
function f() public enabledEvery(1 minutes) {
// some code
}
}

Mutex Pattern

Mutex pattern is to prevent recursive calls from external contracts.

contract Mutex { 
bool locked;
modifier noReentrancy() {
require(!locked);
locked = true;
_;
locked = false;
}
// f is protected by a mutex, thus reentrant calls
// from within msg.sender.call cannot call f again
function f() noReentrancy public returns (uint) {
require(msg.sender.call());
return 1;
}
}

Balance Limit Pattern

This pattern prevents sending more amount than the balance by setting the maximum amount of a balance of a smart contract. In the code below, we set the maximum amount of a balance in a smart contract by using LimitBalance function so that deposit function can be executed only when the balance is less than the maximum balance.

contract LimitBalance { 
uint256 public limit;
function LimitBalance(uint256 value) public {
limit = value;
}
modifier limitedPayable() {
require(this.balance <= limit);
_;
}
function deposit() public payable limitedPayable {
// some code
}
}

ReturnValues

Seungwon Go

Written by

Founder & CEO at ReturnValues

ReturnValues

ReturnValues Blogs

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade