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

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

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 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

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

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

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

ReturnValues Blogs