function calculateSum(uint24 a, uint24 b) returns(uint24) {
return a * b;
}
Solidity Vulnerability Issues
Overflows and Underflows
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.
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
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
}
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
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;
}
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
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;
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
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);
}
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
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);
}
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
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;
}
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
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;
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
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 {}
}
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
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);
}
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
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);
}
Whatever you do, check that conditions have been met. Don't rely on the transactions being mined at the right order.
Exception
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 ""))
Handle the exception and check the return type for every function
Recursive
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
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
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 add current state to the MyState.
Reentrancy
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
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.