Network
Launch Date
Consensus
Note
Sepolia
Oct 2021
PoW
Like-for-like representation of Ethereum
Görli
Jan 2019
PoA
Proof-of-Authority
Kiln
Mar 2022
PoS
Post-Merge (for ETH2), shadow fork of the mainnet
Kintsugi
Dec 2021
PoS
DEPRECATED, use Kiln; post-Merge (for ETH2)
Ropsten
Nov 2016
PoW
DEPRECATED, use Sepolia; the Merge to happen on Jun 8, 2022
Rinkeby
Apr 2017
PoA
DEPRECATED, use Görli and Görli Faucet
Kovan
Mar 2017
PoA
DEPRECATED, use Sepolia or Görli
List of active and deprecated Ethereum testnets, including Kintsugi.
Features
Optimistic rollup 
ZK-rollup 
Proof
Uses fraud proofs to prove transaction validity. 
Uses validity (zero-knowledge) proofs to prove transaction validity. 
Capital efficiency
Requires waiting through a 1-week delay (dispute period) before withdrawing funds. 
Users can withdraw funds immediately because validity proofs provide incontrovertible evidence of the authenticity of off-chain transactions. 
Data compression
Publishes full transaction data as calldata to Ethereum Mainnet, which increases rollup costs. 
Doesn't need to publish transaction data on Ethereum because ZK-SNARKs and ZK-STARKs already guarantee the accuracy of the rollup state. 
EVM compatibility
Uses a simulation of the Ethereum Virtual Machine (EVM), which allows it to run arbitrary logic and support smart contracts. 
Doesn't widely support EVM computation, although a few EVM-compatible ZK-rollups have appeared. 
Rollup costs
Reduces costs since it publishes minimal data on Ethereum and doesn't have to post proofs for transactions, except in special circumstances. 
Faces higher overhead from costs involved in generating and verifying proofs for every transaction block. ZK proofs require specialized, expensive hardware to create and have high on-chain verification costs. 
Trust assumptions
Doesn't require a trusted setup. 
Requires a trusted setup to work. 
Liveness requirements
Verifiers are needed to keep tabs on the actual rollup state and the one referenced in the state root to detect fraud. 
Users don't need someone to watch the L2 chain to detect fraud. 
Security properties 
Relies on cryptoeconomic incentives to assure users of rollup security. 
Relies on cryptographic guarantees for security. 
Start building
on Alchemy.
Sign up for free
Start building on Optimism.
Sign up for free
Start building on Arbitrum.
Sign up for free
Start building on Ethereum.
Sign up for free
Start building on Polygon.
Sign up for free
Start building on Starknet.
Sign up for free
Start building on Flow.
Sign up for free
kiln faucet
Get free Kiln ETH.
Start building today
Goerli faucet
Get free Goerli ETH.
Start building today
SEPOLIA FAUCET
Get free Sepolia ETH.
Start Building Today
mumbai faucet
Get free Mumbai Matic.
Start building today
rinkeby faucet
Get free Rinkeby
ETH.
Start building today
Start building on Ethereum.
Get started for free
Start building on Ethereum.
Get started for free
Start building on Flow.
Get started for free
Start building on Polygon.
Get started for free
Start building on Starknet.
Get started for free
Start building on Optimism.
Get started for free
Start building on Solana.
Get started for free
Start building on Solana.
Sign up for beta access
Start building on Solana.
Join the waitlist
Arbitrum logo
Start building on Arbitrum.
Get started for free
Build with Alchemy's
Gas Manager & Bundler APIs
Learn
Solidity at
Alchemy
University
Get started today
Build with Alchemy's
Gas Manager & Bundler APIs
curl 
https://release.solana.com/v1.10.32/solana-install-init-x86_64-pc-windows-msvc.exe 
--output 
C:\solana-install-tmp\solana-install-init.exe 
--create-dirs
Learn Solidity
SECURITY OVERVIEW

6 Solidity Smart Contract Security Best Practices

Secure Your Smart Contracts With These Expert Security Tips and Tools
Last Updated:
October 20, 2022
Table of Contents
Table of Contents
Table of Contents

{{learn-solidity}}

Blockchain's distinguishing characteristic, smart contracts, allows it to function as more than just a decentralized financial system and a trustless store of value. However, security is a challenge that needs to be solved in a fundamentally new way if blockchain is truly the technology that shifts paradigms.

Technically, smart contract security operates using the same principles as software security. A secure application's very first step begins with the code itself because if the code was not written using best programming techniques the attack surface of a prospective attacker increases.

This article will focus on explaining smart contracts security, providing a list of patterns and mistakes you should avoid to ensure your Solidity smart contracts code is more secure. 

What is smart contract security?  

On the Ethereum network, smart contracts are in place to manage and execute the blockchain operations that occur when users (addresses) interact with one another. Smart contracts are especially useful when there is a transfer or exchange of funds between two or more parties. Smart contracts increase transparency while decreasing operational costs, and they can also increase efficiency and reduce bureaucratic costs, depending on how they are implemented.

Smart contract security refers to the security guidelines and best practices developers, users, and exchanges apply when creating or interacting with smart contracts. Security entails developers examining their code, paying attention to common Solidity mistakes, and guaranteeing that a dapp's security is robust to be mainnet-ready.

Why is security important to developers?

With vast amounts of value transacted through or locked in smart contracts, they become attractive targets for malicious attacks from hackers. Minor coding errors can lead to huge sums of funds being lost. Since blockchain transactions are irreversible, making sure that a project's code is secure is essential. Blockchain technology's highly secure nature makes it difficult to retrieve funds and resolve issues hence, securing your smart contract.

1. Use Delegatecall Carefully

Delegatecall is identical to a message call except that the code at the target address is executed in the context of the calling contract and the values of msg.sender and msg.value are not changed.

Delegatecall has been extremely useful because it serves as the foundation for implementing libraries and modularizing code. Delegatecall also allows a contract to dynamically load code from a different address, however it introduces vulnerabilities because a contract essentially allows anyone to do anything they want with their state resulting in unexpected code execution.

In the example below, when contract B executes the delegatecall function to contract A, the code of contract A is executed but with contract B’s storage.


contract A{
  uint8 public num;
  address public owner;
  uint256 public time;
  string public message;
  bytes public data;


  function callOne() public{
      num = 100;
      owner = msg.sender;
      time = block.timestamp;
      message = "Darah";
      data = abi.encodePacked(num, msg.sender, block.timestamp);

  }


contract B{

  uint8 public num;
  address public owner;
  uint256 public time;
  string public message;
  bytes public data;

  function callTwo(address contractAddress) public returns(bool){

      (bool success,) = contractAddress.delegatecall(
          abi.encodeWithSignature("callOne()")
      );
      }
     
}

delegatecall affects the state variables of the contract that calls a function with delegatecall. The state variables of the contract that holds the functions that are borrowed are not read or written.

2. Use a Reentrancy Guard

Reentrancy is a programming method where an external function call causes the execution of a function to pause. Conditions in the logic of the external function call allow it to call itself repeatedly before the original function execution is finished.

A reentrancy attack takes advantage of unprotected external calls and can be a particularly damaging exploit, draining all of the funds in your contract if not handled properly.

Here is a simple example of a contract that is susceptible to re-entrancy:


//Victim

contract Victim {
  mapping (address => uint) public balances;

function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw() public {
        uint bal = balances[msg.sender];
        require(bal > 0);

        (bool sent, ) = msg.sender.call{value: bal}("");
        require(sent, "Failed to send Ether");

        balances[msg.sender] = 0;
    }

//Attack

contract Attack {
    Victim public victim;
    
    constructor(address _victim) {
        victim = Victim(_victim);
    }
    
    fallback() external payable {
        if (address(victim).balance >= 1 ether){
            victim.withdraw(1 ether);
        }
    }
    
    function attack() external payable {
        require(msg.value >= 1 ether);
        victim.deposit{value: 1 ether}();
        victim.withdraw(1 ether);
    }
}

A reentrancy guard is a modifier that causes execution to fail whenever a reenterancy act is discovered. This also prevents more than one function from being executed at a time by locking the contract.


contract ReEntrancyGuard {
    bool internal locked;

    modifier noReentrant() {
        require(!locked, "No re-entrancy");
        locked = true;
        _;
        locked = false;
    }
}

3. Use msg.sender Instead of tx.origin for Authentication

In Solidity, tx.origin is a global variable that returns the address of the account that sent the transaction. Using the tx.origin variable for authorization may expose a contract to compromise if an authorized account calls into a malicious contract.

Avoiding the use of tx.origin for authentication purposes is the best method to guard against tx.origin attacks instead use msg.sender in its place.

The difference between tx.origin and msg.sender is msg.sender, the owner, can be a contract while tx.origin the owner can never be a contract.


contract Wallet {

   address owner;

   function Wallet() public {
       owner = msg.sender;
   }

   function sendTo(address receiver, uint amount) public {
       require(tx.origin == owner);
       (bool success, ) = receiver.call.value(amount)("");
       require(success);
   }

}

Implementing msg.sender here:


contract Attack {

   Wallet wallet; 
   address attack;

   function AttackingContract(address myContractAddress) public {
       myContract = MyContract(myContractAddress);
       attacker = msg.sender;
   }

   function() public {
       myContract.sendTo(attacker, msg.sender.balance);
   }

}

4. Properly Use Solidity Visibility Modifiers

Function visibility can be set to be either internal, external, private, or public. It's crucial to think about which visibility is appropriate for your smart contract function.

Here is a brief description of each visibility modifier:

  • Public - can be accessed by the main contract, derived contracts, and third party contracts
  • External - can only be called by a third party.
  • Internal - can be called by the main contract and any of its derived contracts
  • Private - can only be called by the main contract in which it was specified

A developer's failure to utilize a visibility modifier frequently results in smart contract attacks. The function is thus by default set to be public, which may result in unintentional state changes.

5. Avoid Block Timestamp Manipulation

Block timestamps have been used historically for a number of purposes, including entropy for random numbers locking funds for a set amount of time, and different state-changing, time-dependent conditional statements. Because validators have the capacity to slightly alter timestamps, using block timestamps wrong in smart contracts can be quite risky.

The time difference between events can be estimated using block.number and the average block time. However, because block times can change and break functionality, it's best to avoid its use.


contract MyContract {
    uint public pastBlockTime; 
    
    constructor() public payable {} 
    
    function () public payable {
        require(msg.value == 10 ether); 
        require(now != pastBlockTime); 
        pastBlockTime = now;
        if(now % 15 == 0) { 
            msg.sender.transfer(this.balance);
        }
    }
}

6. Avoid Arithmetic Overflow and Underflow

An integer would automatically roll over to a lower or higher number in Solidity versions prior to 0.8.0. If you decremented 0 by 1 (0-1) on an unsigned number, the outcome would simply be: MAX instead of -1 or an error.


pragma solidity 0.7.0;

contract MyContract {
    uint8 public level;

    function decrement() public {
        myUint8--;
    }

    function increment() public {
        myUint8++;
    }
}

The easiest way is to use at least a 0.8 version of the Solidity compiler. In Solidity 0.8, the compiler will automatically take care of checking for overflows and underflows.


pragma solidity 0.8.0;

contract  {
    uint8 public level;

    function decrement() public {
        myUint8--;
    }

    function increment() public {
        myUint8++;
    }
}

3 Popular Smart Contract Security Tools

Three of the most popular smart contract security tools are Slither, Mythril, and Securify.

1. Slither

Slither is a static analyzer that features more than 40 built-in vulnerability detectors for widespread flaws. Slither executes a number of vulnerability scanners, outputs visual information about the terms of the contract, and offers an API for quickly creating unique studies.

This amazing security tool gives developers the ability to identify vulnerabilities, improve their understanding of the code, and quickly prototype unique analysis.

2. Mythril

Mythril is an open-source element of MythX and an EVM bytecode security analysis tool that supports smart contracts created for the Tron, Roostock, Vechain, Quorum, and other EVM-compatible blockchains.

3. Securify 

Securify is a smart contract vulnerability checker supported by the Ethereum Foundation and ChainSecurity. This well-known Ethereum smart contract scanner employs context-specific static analysis for more precise security assessments and can find up to 37 smart contract flaws.

Secure Your Smart Contracts

The future of blockchain technology is dependent on the developers who work on it. Because smart contract security is widely perceived as blockchain security, the actions of independent developers influence public perception of the blockchain. When creating smart contracts, project teams must consider proper security best practices.

ALCHEMY SUPERNODE - ETHEREUM NODE API

Scale to any size, without any errors

Alchemy Supernode finally makes it possible to scale blockchain applications without all the headaches. Plus, our legendary support will guide you every step of the way.

Get started for free
Supernode footer
Learn Solidity
SECURITY OVERVIEW

6 Solidity Smart Contract Security Best Practices

Secure Your Smart Contracts With These Expert Security Tips and Tools
Last Updated:
October 20, 2022
Last Updated:
September 21, 2022
Don't miss an update
Sign up for our newsletter to get alpha, key insights, and killer resources.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Table of Contents

Talk to an Expert

Learn how Alchemy's blockchain developer tools can help your business succeed in web3!
Valid number
Thank you! An Alchemy expert will be in touch with you shortly!
Oops! Something went wrong while submitting the form.

{{learn-solidity}}

Table of Contents

Blockchain's distinguishing characteristic, smart contracts, allows it to function as more than just a decentralized financial system and a trustless store of value. However, security is a challenge that needs to be solved in a fundamentally new way if blockchain is truly the technology that shifts paradigms.

Technically, smart contract security operates using the same principles as software security. A secure application's very first step begins with the code itself because if the code was not written using best programming techniques the attack surface of a prospective attacker increases.

This article will focus on explaining smart contracts security, providing a list of patterns and mistakes you should avoid to ensure your Solidity smart contracts code is more secure. 

What is smart contract security?  

On the Ethereum network, smart contracts are in place to manage and execute the blockchain operations that occur when users (addresses) interact with one another. Smart contracts are especially useful when there is a transfer or exchange of funds between two or more parties. Smart contracts increase transparency while decreasing operational costs, and they can also increase efficiency and reduce bureaucratic costs, depending on how they are implemented.

Smart contract security refers to the security guidelines and best practices developers, users, and exchanges apply when creating or interacting with smart contracts. Security entails developers examining their code, paying attention to common Solidity mistakes, and guaranteeing that a dapp's security is robust to be mainnet-ready.

Why is security important to developers?

With vast amounts of value transacted through or locked in smart contracts, they become attractive targets for malicious attacks from hackers. Minor coding errors can lead to huge sums of funds being lost. Since blockchain transactions are irreversible, making sure that a project's code is secure is essential. Blockchain technology's highly secure nature makes it difficult to retrieve funds and resolve issues hence, securing your smart contract.

1. Use Delegatecall Carefully

Delegatecall is identical to a message call except that the code at the target address is executed in the context of the calling contract and the values of msg.sender and msg.value are not changed.

Delegatecall has been extremely useful because it serves as the foundation for implementing libraries and modularizing code. Delegatecall also allows a contract to dynamically load code from a different address, however it introduces vulnerabilities because a contract essentially allows anyone to do anything they want with their state resulting in unexpected code execution.

In the example below, when contract B executes the delegatecall function to contract A, the code of contract A is executed but with contract B’s storage.


contract A{
  uint8 public num;
  address public owner;
  uint256 public time;
  string public message;
  bytes public data;


  function callOne() public{
      num = 100;
      owner = msg.sender;
      time = block.timestamp;
      message = "Darah";
      data = abi.encodePacked(num, msg.sender, block.timestamp);

  }


contract B{

  uint8 public num;
  address public owner;
  uint256 public time;
  string public message;
  bytes public data;

  function callTwo(address contractAddress) public returns(bool){

      (bool success,) = contractAddress.delegatecall(
          abi.encodeWithSignature("callOne()")
      );
      }
     
}

delegatecall affects the state variables of the contract that calls a function with delegatecall. The state variables of the contract that holds the functions that are borrowed are not read or written.

2. Use a Reentrancy Guard

Reentrancy is a programming method where an external function call causes the execution of a function to pause. Conditions in the logic of the external function call allow it to call itself repeatedly before the original function execution is finished.

A reentrancy attack takes advantage of unprotected external calls and can be a particularly damaging exploit, draining all of the funds in your contract if not handled properly.

Here is a simple example of a contract that is susceptible to re-entrancy:


//Victim

contract Victim {
  mapping (address => uint) public balances;

function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw() public {
        uint bal = balances[msg.sender];
        require(bal > 0);

        (bool sent, ) = msg.sender.call{value: bal}("");
        require(sent, "Failed to send Ether");

        balances[msg.sender] = 0;
    }

//Attack

contract Attack {
    Victim public victim;
    
    constructor(address _victim) {
        victim = Victim(_victim);
    }
    
    fallback() external payable {
        if (address(victim).balance >= 1 ether){
            victim.withdraw(1 ether);
        }
    }
    
    function attack() external payable {
        require(msg.value >= 1 ether);
        victim.deposit{value: 1 ether}();
        victim.withdraw(1 ether);
    }
}

A reentrancy guard is a modifier that causes execution to fail whenever a reenterancy act is discovered. This also prevents more than one function from being executed at a time by locking the contract.


contract ReEntrancyGuard {
    bool internal locked;

    modifier noReentrant() {
        require(!locked, "No re-entrancy");
        locked = true;
        _;
        locked = false;
    }
}

3. Use msg.sender Instead of tx.origin for Authentication

In Solidity, tx.origin is a global variable that returns the address of the account that sent the transaction. Using the tx.origin variable for authorization may expose a contract to compromise if an authorized account calls into a malicious contract.

Avoiding the use of tx.origin for authentication purposes is the best method to guard against tx.origin attacks instead use msg.sender in its place.

The difference between tx.origin and msg.sender is msg.sender, the owner, can be a contract while tx.origin the owner can never be a contract.


contract Wallet {

   address owner;

   function Wallet() public {
       owner = msg.sender;
   }

   function sendTo(address receiver, uint amount) public {
       require(tx.origin == owner);
       (bool success, ) = receiver.call.value(amount)("");
       require(success);
   }

}

Implementing msg.sender here:


contract Attack {

   Wallet wallet; 
   address attack;

   function AttackingContract(address myContractAddress) public {
       myContract = MyContract(myContractAddress);
       attacker = msg.sender;
   }

   function() public {
       myContract.sendTo(attacker, msg.sender.balance);
   }

}

4. Properly Use Solidity Visibility Modifiers

Function visibility can be set to be either internal, external, private, or public. It's crucial to think about which visibility is appropriate for your smart contract function.

Here is a brief description of each visibility modifier:

  • Public - can be accessed by the main contract, derived contracts, and third party contracts
  • External - can only be called by a third party.
  • Internal - can be called by the main contract and any of its derived contracts
  • Private - can only be called by the main contract in which it was specified

A developer's failure to utilize a visibility modifier frequently results in smart contract attacks. The function is thus by default set to be public, which may result in unintentional state changes.

5. Avoid Block Timestamp Manipulation

Block timestamps have been used historically for a number of purposes, including entropy for random numbers locking funds for a set amount of time, and different state-changing, time-dependent conditional statements. Because validators have the capacity to slightly alter timestamps, using block timestamps wrong in smart contracts can be quite risky.

The time difference between events can be estimated using block.number and the average block time. However, because block times can change and break functionality, it's best to avoid its use.


contract MyContract {
    uint public pastBlockTime; 
    
    constructor() public payable {} 
    
    function () public payable {
        require(msg.value == 10 ether); 
        require(now != pastBlockTime); 
        pastBlockTime = now;
        if(now % 15 == 0) { 
            msg.sender.transfer(this.balance);
        }
    }
}

6. Avoid Arithmetic Overflow and Underflow

An integer would automatically roll over to a lower or higher number in Solidity versions prior to 0.8.0. If you decremented 0 by 1 (0-1) on an unsigned number, the outcome would simply be: MAX instead of -1 or an error.


pragma solidity 0.7.0;

contract MyContract {
    uint8 public level;

    function decrement() public {
        myUint8--;
    }

    function increment() public {
        myUint8++;
    }
}

The easiest way is to use at least a 0.8 version of the Solidity compiler. In Solidity 0.8, the compiler will automatically take care of checking for overflows and underflows.


pragma solidity 0.8.0;

contract  {
    uint8 public level;

    function decrement() public {
        myUint8--;
    }

    function increment() public {
        myUint8++;
    }
}

3 Popular Smart Contract Security Tools

Three of the most popular smart contract security tools are Slither, Mythril, and Securify.

1. Slither

Slither is a static analyzer that features more than 40 built-in vulnerability detectors for widespread flaws. Slither executes a number of vulnerability scanners, outputs visual information about the terms of the contract, and offers an API for quickly creating unique studies.

This amazing security tool gives developers the ability to identify vulnerabilities, improve their understanding of the code, and quickly prototype unique analysis.

2. Mythril

Mythril is an open-source element of MythX and an EVM bytecode security analysis tool that supports smart contracts created for the Tron, Roostock, Vechain, Quorum, and other EVM-compatible blockchains.

3. Securify 

Securify is a smart contract vulnerability checker supported by the Ethereum Foundation and ChainSecurity. This well-known Ethereum smart contract scanner employs context-specific static analysis for more precise security assessments and can find up to 37 smart contract flaws.

Secure Your Smart Contracts

The future of blockchain technology is dependent on the developers who work on it. Because smart contract security is widely perceived as blockchain security, the actions of independent developers influence public perception of the blockchain. When creating smart contracts, project teams must consider proper security best practices.

Blockchain's distinguishing characteristic, smart contracts, allows it to function as more than just a decentralized financial system and a trustless store of value. However, security is a challenge that needs to be solved in a fundamentally new way if blockchain is truly the technology that shifts paradigms.

Technically, smart contract security operates using the same principles as software security. A secure application's very first step begins with the code itself because if the code was not written using best programming techniques the attack surface of a prospective attacker increases.

This article will focus on explaining smart contracts security, providing a list of patterns and mistakes you should avoid to ensure your Solidity smart contracts code is more secure. 

What is smart contract security?  

On the Ethereum network, smart contracts are in place to manage and execute the blockchain operations that occur when users (addresses) interact with one another. Smart contracts are especially useful when there is a transfer or exchange of funds between two or more parties. Smart contracts increase transparency while decreasing operational costs, and they can also increase efficiency and reduce bureaucratic costs, depending on how they are implemented.

Smart contract security refers to the security guidelines and best practices developers, users, and exchanges apply when creating or interacting with smart contracts. Security entails developers examining their code, paying attention to common Solidity mistakes, and guaranteeing that a dapp's security is robust to be mainnet-ready.

Why is security important to developers?

With vast amounts of value transacted through or locked in smart contracts, they become attractive targets for malicious attacks from hackers. Minor coding errors can lead to huge sums of funds being lost. Since blockchain transactions are irreversible, making sure that a project's code is secure is essential. Blockchain technology's highly secure nature makes it difficult to retrieve funds and resolve issues hence, securing your smart contract.

1. Use Delegatecall Carefully

Delegatecall is identical to a message call except that the code at the target address is executed in the context of the calling contract and the values of msg.sender and msg.value are not changed.

Delegatecall has been extremely useful because it serves as the foundation for implementing libraries and modularizing code. Delegatecall also allows a contract to dynamically load code from a different address, however it introduces vulnerabilities because a contract essentially allows anyone to do anything they want with their state resulting in unexpected code execution.

In the example below, when contract B executes the delegatecall function to contract A, the code of contract A is executed but with contract B’s storage.


contract A{
  uint8 public num;
  address public owner;
  uint256 public time;
  string public message;
  bytes public data;


  function callOne() public{
      num = 100;
      owner = msg.sender;
      time = block.timestamp;
      message = "Darah";
      data = abi.encodePacked(num, msg.sender, block.timestamp);

  }


contract B{

  uint8 public num;
  address public owner;
  uint256 public time;
  string public message;
  bytes public data;

  function callTwo(address contractAddress) public returns(bool){

      (bool success,) = contractAddress.delegatecall(
          abi.encodeWithSignature("callOne()")
      );
      }
     
}

delegatecall affects the state variables of the contract that calls a function with delegatecall. The state variables of the contract that holds the functions that are borrowed are not read or written.

2. Use a Reentrancy Guard

Reentrancy is a programming method where an external function call causes the execution of a function to pause. Conditions in the logic of the external function call allow it to call itself repeatedly before the original function execution is finished.

A reentrancy attack takes advantage of unprotected external calls and can be a particularly damaging exploit, draining all of the funds in your contract if not handled properly.

Here is a simple example of a contract that is susceptible to re-entrancy:


//Victim

contract Victim {
  mapping (address => uint) public balances;

function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw() public {
        uint bal = balances[msg.sender];
        require(bal > 0);

        (bool sent, ) = msg.sender.call{value: bal}("");
        require(sent, "Failed to send Ether");

        balances[msg.sender] = 0;
    }

//Attack

contract Attack {
    Victim public victim;
    
    constructor(address _victim) {
        victim = Victim(_victim);
    }
    
    fallback() external payable {
        if (address(victim).balance >= 1 ether){
            victim.withdraw(1 ether);
        }
    }
    
    function attack() external payable {
        require(msg.value >= 1 ether);
        victim.deposit{value: 1 ether}();
        victim.withdraw(1 ether);
    }
}

A reentrancy guard is a modifier that causes execution to fail whenever a reenterancy act is discovered. This also prevents more than one function from being executed at a time by locking the contract.


contract ReEntrancyGuard {
    bool internal locked;

    modifier noReentrant() {
        require(!locked, "No re-entrancy");
        locked = true;
        _;
        locked = false;
    }
}

3. Use msg.sender Instead of tx.origin for Authentication

In Solidity, tx.origin is a global variable that returns the address of the account that sent the transaction. Using the tx.origin variable for authorization may expose a contract to compromise if an authorized account calls into a malicious contract.

Avoiding the use of tx.origin for authentication purposes is the best method to guard against tx.origin attacks instead use msg.sender in its place.

The difference between tx.origin and msg.sender is msg.sender, the owner, can be a contract while tx.origin the owner can never be a contract.


contract Wallet {

   address owner;

   function Wallet() public {
       owner = msg.sender;
   }

   function sendTo(address receiver, uint amount) public {
       require(tx.origin == owner);
       (bool success, ) = receiver.call.value(amount)("");
       require(success);
   }

}

Implementing msg.sender here:


contract Attack {

   Wallet wallet; 
   address attack;

   function AttackingContract(address myContractAddress) public {
       myContract = MyContract(myContractAddress);
       attacker = msg.sender;
   }

   function() public {
       myContract.sendTo(attacker, msg.sender.balance);
   }

}

4. Properly Use Solidity Visibility Modifiers

Function visibility can be set to be either internal, external, private, or public. It's crucial to think about which visibility is appropriate for your smart contract function.

Here is a brief description of each visibility modifier:

  • Public - can be accessed by the main contract, derived contracts, and third party contracts
  • External - can only be called by a third party.
  • Internal - can be called by the main contract and any of its derived contracts
  • Private - can only be called by the main contract in which it was specified

A developer's failure to utilize a visibility modifier frequently results in smart contract attacks. The function is thus by default set to be public, which may result in unintentional state changes.

5. Avoid Block Timestamp Manipulation

Block timestamps have been used historically for a number of purposes, including entropy for random numbers locking funds for a set amount of time, and different state-changing, time-dependent conditional statements. Because validators have the capacity to slightly alter timestamps, using block timestamps wrong in smart contracts can be quite risky.

The time difference between events can be estimated using block.number and the average block time. However, because block times can change and break functionality, it's best to avoid its use.


contract MyContract {
    uint public pastBlockTime; 
    
    constructor() public payable {} 
    
    function () public payable {
        require(msg.value == 10 ether); 
        require(now != pastBlockTime); 
        pastBlockTime = now;
        if(now % 15 == 0) { 
            msg.sender.transfer(this.balance);
        }
    }
}

6. Avoid Arithmetic Overflow and Underflow

An integer would automatically roll over to a lower or higher number in Solidity versions prior to 0.8.0. If you decremented 0 by 1 (0-1) on an unsigned number, the outcome would simply be: MAX instead of -1 or an error.


pragma solidity 0.7.0;

contract MyContract {
    uint8 public level;

    function decrement() public {
        myUint8--;
    }

    function increment() public {
        myUint8++;
    }
}

The easiest way is to use at least a 0.8 version of the Solidity compiler. In Solidity 0.8, the compiler will automatically take care of checking for overflows and underflows.


pragma solidity 0.8.0;

contract  {
    uint8 public level;

    function decrement() public {
        myUint8--;
    }

    function increment() public {
        myUint8++;
    }
}

3 Popular Smart Contract Security Tools

Three of the most popular smart contract security tools are Slither, Mythril, and Securify.

1. Slither

Slither is a static analyzer that features more than 40 built-in vulnerability detectors for widespread flaws. Slither executes a number of vulnerability scanners, outputs visual information about the terms of the contract, and offers an API for quickly creating unique studies.

This amazing security tool gives developers the ability to identify vulnerabilities, improve their understanding of the code, and quickly prototype unique analysis.

2. Mythril

Mythril is an open-source element of MythX and an EVM bytecode security analysis tool that supports smart contracts created for the Tron, Roostock, Vechain, Quorum, and other EVM-compatible blockchains.

3. Securify 

Securify is a smart contract vulnerability checker supported by the Ethereum Foundation and ChainSecurity. This well-known Ethereum smart contract scanner employs context-specific static analysis for more precise security assessments and can find up to 37 smart contract flaws.

Secure Your Smart Contracts

The future of blockchain technology is dependent on the developers who work on it. Because smart contract security is widely perceived as blockchain security, the actions of independent developers influence public perception of the blockchain. When creating smart contracts, project teams must consider proper security best practices.

{{learn-solidity}}

Contact Us

Talk to an expert at Alchemy to answer all of your product questions.
Valid number
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Build blockchain magic with Alchemy

Alchemy combines the most powerful web3 developer products and tools with resources, community and legendary support.

Get started for free