Solidity Vulnerability Issues

Overflows and Underflows

Problem

The function is calculating a multiplication. If you're using very big numbers, the variables will overflow resulting in 0 instead of a big number.

function calculateSum(uint24 a, uint24 b) returns(uint24) {

  return a * b;

}
Solution

Check that the result of the calculation is not overflowing:

function calculateSum(uint24 a, uint24 b) returns(uint24) {

  assert(a == 0 || a * b / a == b);
  return a * b;

}

Erroneous Function Visibility

Problem

This function can only be executed by the owner of the contract because of the modifier `onlyOwner` which is usually an external user, but it's declared `public`. This is a problem because it uses more gas than needed.

function example() public onlyOwner {

  // Do something

}
Solution

Declare the function as external to limit it's scope to external users and contracts. This reduces the amount of gas used and clarifies who should be executing it:

function example() external onlyOwner {

  // Do something

}

Incorrect Function Body

Problem: the function isn't doing what it's supposed to do

The function is called `nonZeroSum()` indicating that it's used to sum numbers that are not zero. However the content of the function isn't checking for that condition.

function nonZeroSum(uint256 a, uint256 b) {

  return a + b;

}
Solution

Use machine learning systems to understand human language and implement what the intention of the function really is. Check that the numbers are bigger than zero because the name of the function `nonZeroSum()` says so:

function nonZeroSum(uint256 a, uint256 b) {

  require(a > 0 && b > 0);
  return a + b;

}

Open Solidity Version

Problem

You're telling the Solidity compiler to use the latest version of solidity bigger than 0.4.11. This is a problem because you're writing code with the way of doing things in an older version. Newer versions of Solidity deprecate functions like `throw;` and break your program if you're using them.

pragma solidity ^0.4.11;
Solution

Specify a fixed version without the caret (^) symbol to use the indicated version and not the latest one of the Solidity compiler to avoid breaking your code:

pragma solidity 0.4.11;

Call to the unknown

Problem

This refers to any use of `call`, `delegatecall`, `send`, or any direct call to another contract that results in the execution of an unknown, possibly malicious, fallback function.

Example newContract;
function sendEther() {

  // Don't use this function because it's dangerous
  newContract.delegatecall(msg.sender);

}
Solution

Make a direct call to the contract's functions instead of using those methods since they allow the other contract to execute unknown code.

Type casts error

Problem

If the arguments to a direct call from one contract to a function of another contract is incorrectly typed, or the address of the called contract is incorrect, either nothing will happen, or the wrong code will execute. In neither case is an exception thrown, and the caller is not made aware.

function sendEther(address recipient) internal {

  recipient.transfer(this.balance);

}
Solution

Always check that the parameters of the function are valid variables. If it's an address, make sure it's a variable that holds 20 bytes values.

Reentrancy

Problem

In some cases, a contract’s fallback function allows it to re-enter a caller function before it has terminated. This can result in the repeated execution of functions intended only to be executed once per transaction.

mapping(address => uint) balances;
function sendEther() payable {

  // Don't use this function because it's dangerous
  msg.sender.call.value(msg.value)();
  balances[msg.sender] = 0;

}
Solution

Don't use any of those functions specially `.call.value()()` since it allows anybody to execute malicious code on the fallback function. Use instead `.transfer()` which limits the amount of gas that can be sent to the function.

Keeping secrets

Problem

By the public nature of the blockchain, contract fields marked private are not guaranteed to remain secret to set a private field, a contract owner must broadcast a transaction. Cryptographic protocols are required to guarantee that fields are not visible to anyone mining or inspecting the blockchain.

uint private balance;
address private owner;
string private secretKey;
Solution

Encrypt all the private variables that you truly need to hide from the public eye by using the standard `keccack256()` method or any other that allows you to un-crypt the code at your will. Usually on the client-side.

Immutability

Problem

When a contract is added to the blockchain, there is no way to edit it. If a contract is found to be defective, there is often nothing to be done short of killing the contract (assuming measures were taken by the contract creator to make this possible). In this case the contract doesn't have a method to extract the ether received.

contract Lost {

  function () payable {}

}
Solution

Make sure to include a function that has `selfdestruct(owner)` to recover the funds and to kill the contract in extreme cases. Create a way to extract the ether that may be stored on the contract by the owner.

Ether lost in transfer

Problem

If you send Ether to an invalid address that it's not existing or if the address is ill-formed, then you'll lose the ether sent without a way to recover it.

function transferEther(address sender) payable {

  sender.tranfer(msg.value);

}
Solution

Make sure that you're sending ether to a valid address and that the address is correctly written with all the characters. You can also check that in the functions.

Transaction Ordering Dependence

Problem

This occurs when the assumed state of the blockchain is not the blockchain’s actual state when a transaction is executed. The order in which transactions are mined can have adverse effects on the execution of any given transaction. This bug is said to be present in up to %15.8 of all contracts on the blockchain. In this contract, you can only `extractReward()` once and if the reward has not been send. It could happen that you try to extract the reward and it's already too late.

bool rewardSent = false;
uint time;
function activateReward() {

  if(now > time) rewardSent = true;

}

function extractReward() onlyOnce {

  require(rewardSent == false) msg.sender.tranfer(this.balance);

}
Solution

Whatever you do, check that conditions have been met. Don't rely on the transactions being mined at the right order.

Exception

Problem

Here we are not checking what claimThrone Function returns and exceptions are not handled.

module Exception where
import Control.Exception
newtype Address = Address {sender::String, value::Number}
newtype Monarch = Monarch{ ethAddr::Address,
  name::String,
  claimPrice::Number,
  coronationTimeStamp::Number
}

type MyState = State Monarch

claimThrone::String -> Unit
claimThrone name = do
  monarch <- get
  put(monarch.ethAddr, name, monarch.claimPrice, monarch.coronationTimeStamp)
  unit

claimThrone "FluidAI"

claimThroneWithException :: String -> Unit
claimThrone name = do
  monarch <- get
  put(
    monarch.ethAddr,
    name,
    monarch.claimPrice,
    monarch.coronationTimeStamp
  )
  unit
catch (claimThroneWithException "FluidAI") (e -> let err = show (e :: Exception)
  hPutStr stderr ("Warning: Couldn't open " ++ f ++ ": " ++ err)
  return ""))
Solution

Handle the exception and check the return type for every function

Recursive

Problem

Here we can again call tokenHandler which would increase the tokenholder value because balance of sender was not yet updated.

module Recursive where

newtype Address = Address {sender:: String, value :: Number}

type MyState = State Address

tokenHandler ::Address -> Unit
tokenHandler address = do
  tokenHolders <- get
  tokenHolders.value += (address.value / 10)
  updateBalanceOfSender address address.value/10

updateBalaneOfSender :: Address-> Number -> Unit
updateBalaneOfSender address value = do
  unit
Solution

Try to run the balance update and tokenholder value update one line after one such that recursive cannot be possible or else add guard that will be satisfied after updating the balance before you cannot make recursive call.

Transaction Order Dependence TOD

Problem

No text found

module TOD where
import Control.Monad.State
newtype Address = Address {sender:: String, value:: Number}
type MyState = (Number,Number)
startState :: MyState
startState = (0.0,0.0)

updatePrice :: Number -> Address  -> Eff Unit
updatePrice price sender  = do
  if sender.sender == "owner" then do
    (quantity,price1) <- get
    put (quantity,price)
    else
      unit

buy :: Number -> Address -> Eff Unit
buy quantity sender = do
  (total,totalPrice) <- get
  if sender.value > quantity * price then do
    put (total-quantiy,totalPrice+(quantity*price))
    else
      unit
Solution

Solution add current state to the MyState.

Reentrancy

Problem

There is possiblity of make call to send money after calling withdrawbalance because we are setting the value to zero at last line of function.

module reentrancy where
newtype Address = Address {sender :: String, value :: Number}
getBalance :: Address -> Number
getBalance address = do
  address.value

addToBalance :: Address -> Number -> Unit
addToBalance address amount = do
  address.value = address.value + amount
  unit

withDrawBalance :: Address -> Unit
withDrawBalance address = do
  address.value = 0
  unit
Solution

We need to either add guard condition or set the first statement to set the value to zero in withdraw such that this bug won't occur.