GithubHelp home page GithubHelp logo

franklinliu / invcon-tool Goto Github PK

View Code? Open in Web Editor NEW
11.0 3.0 7.0 71.03 MB

InvCon: A Dynamic Invariant Detector for Ethereum Smart Contracts!

Makefile 0.79% Shell 0.33% PostScript 0.04% HTML 0.26% Perl 0.88% C 85.12% Java 8.85% Raku 0.01% Emacs Lisp 0.01% Assembly 1.34% M4 0.29% JavaScript 0.31% CSS 0.02% XSLT 0.10% C++ 1.06% Roff 0.01% Python 0.35% GDB 0.04% Common Lisp 0.01% BlitzBasic 0.21%

invcon-tool's Introduction

InvCon, A Dynamic Invariant Detector for Ethereum Smart Contracts


Contents

This readme first demonstrates the website allow user to access the mined contract invariants. Then, it shows how to quickly use InvCon to detect smart contract invariants with an example. We also show the buggy ERC20 smart contracts at this readme to highlight the application for detection of inconsistent smart contract against standards.

User Interface

The website of InvCon is hosted at http://www.smartcontractsecurity.org/invcon. This website includes all the mined invariants of contracts mentioned in the experiment of the paper.

Get Started

Prerequisites

  • We assume Docker is installed. If not, please refer to the official website https://docs.docker.com/get-docker/ on how to install Docker. The artifact was tested on Docker version 20.10.7 and 20.10.14.
  • InvCon needs to access the Internet to retrieve source code and transaction histories of smart contracts from the Etherscan. We assume full access to this website.

Quick Start

To get started quickly, we suggest to use InvCon docker images to have a quick start of smart contract invaraint detection.

The following instruction will detect the contract invariants of smart contract TokenERC20(0x0e9d46eed51a527db8f5c12a803eb7fddf4da332) from its past transactions. Due to that we have cached the collected transaction data, this instruction will take no more than one minutes.

docker pull liuyedocker/invcon:latest 
docker run -it --rm liuyedocker/invcon invcon --eth_address 0x0e9d46eed51a527db8f5c12a803eb7fddf4da332

The normal output should be:

|████████████████████████████████████████| 88/88 [100%] in 0.4s (240.28/s) 
0
finished!
 please check invariant file: /home/liuye/Projects/InvCon/Experiment/ERC20/0x0e9d46eed51a527db8f5c12a803eb7fddf4da332/TokenERC20.inv

Advanced Use

We can also create a clean diretory on the host machine /tmp where the collected contract data, the mined contract invaraints will be saved via the volume mount. The instruction is as follows.

docker pull liuyedocker/invcon:latest 
mkdir /tmp 
docker run -it --rm -v /tmp:/home/realworldcontracts/ liuyedocker/invcon invcon --eth_address 0x0e9d46eed51a527db8f5c12a803eb7fddf4da332 --workspace /home/realworldcontracts/

The normal output should be:

2  internal txs to crawl...
|████████████████████████████████████████| 2/2 [100%] in 1.8s (1.09/s)
Internal message calls (except fallback function): 2
{ abi:
   '/home/realworldcontracts/0x0e9d46eed51a527db8f5c12a803eb7fddf4da332/0x0e9d46eed51a527db8f5c12a803eb7fddf4da332.abi',
  tx:
   '/home/realworldcontracts/0x0e9d46eed51a527db8f5c12a803eb7fddf4da332/txs.json',
  output:
   '/home/realworldcontracts/0x0e9d46eed51a527db8f5c12a803eb7fddf4da332/tx_decode.json' }
crawl contract state changes along transactions...
|████████████████████████████████████████| 88/88 [100%] in 54.8s (1.61/s)
Installing '0.4.25'...
Version '0.4.25' installed.
Switched global version to 0.4.25
|████████████████████████████████████████| 88/88 [100%] in 0.8s (109.98/s)
0
finished!
 please check invariant file: /home/realworldcontracts/0x0e9d46eed51a527db8f5c12a803eb7fddf4da332/TokenERC20.inv
>>>0x0e9d46eed51a527db8f5c12a803eb7fddf4da332-TokenERC20: 88 transactions; 6.3681488037109375 seconds

Buggy ERC20 Smart Contracts

1. Violating Total Supply Equal to Balance Sum

  • ETHER3XBULL(0x7df13bfd9656038a689ab490bb620ddb440ae2a3), dogecoin(0xfb3e0a102dad7a26ae7f3a2abac9796bee865e8e)
function mint(address miner, uint256 _value) external onlyOwner {
      balances[miner] = _value;
}
  • TokenMintERC20Token( 0x62c23c5f75940c2275dd3cb9300289dd30992e59 0x9d42ec955fe0d463324f5f1caec5410274b2d2a0).
    function _mint(address account, uint256 amount) internal {
        require(account != address(0), "ERC20: mint to the zero address");

        _totalSupply = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(amount);
        _balances[Account] = _totalSupply/100;
        emit Transfer(address(0), account, amount);
    }
  • PollFinance(0x67ad111e81408fc444b6a15bd4ffa40c6e919b65)
    function freeze(uint256 _value) returns (bool success) {
        if (balances[msg.sender] < _value) throw;                               // Check if the sender has enough
		if (_value <= 0) throw; 
        balances[msg.sender] = SafeMath.sub(balances[msg.sender], _value);      // Subtract from the sender
        freezeOf[msg.sender] = SafeMath.add(freezeOf[msg.sender], _value);       // Updates totalSupply
        Freeze(msg.sender, _value);
        return true;
    }

PTRToken(0x393bc9f6b7dcfc9a2f53299264688a165586d423)

    function lock(address _holder, uint256 _amount, uint256 _releaseStart, uint256 _termOfRound, uint256 _releaseRate) internal onlyOwner returns (bool) {
        require(locks[_holder] == false);
        require(_releaseStart > now);
        require(_termOfRound > 0);
        require(_amount.mul(_releaseRate).div(100) > 0);
        require(balances[_holder] >= _amount);
        balances[_holder] = balances[_holder].sub(_amount);
        lockupInfo[_holder] = LockupInfo(_releaseStart, _termOfRound, _amount.mul(_releaseRate).div(100), _amount);
        
        locks[_holder] = true;
        
        emit Lock(_holder, _amount);
        
        return true;
    }

2. Violating Transfer Invariant

  • FILHToken(0x25dba15589a29043c24d00036c1d56a262895dbf)
    function transfer(address _to, uint _value) public onlyPayloadSize(2 * 32) {
        uint fee = (_value.mul(basisPointsRate)).div(10000);
        if (fee > maximumFee) {
            fee = maximumFee;
        }
        uint sendAmount = _value.sub(fee);
        balances[msg.sender] = balances[msg.sender].sub(_value);
        balances[_to] = balances[_to].add(sendAmount);
        if (fee > 0) {
            balances[owner] = balances[owner].add(fee);
            Transfer(msg.sender, owner, fee);
        }
        Transfer(msg.sender, _to, sendAmount);
    }
  • EBULL(0x5a007da6f25b6991f15ac0372821ae3521133943)
    function transfer(address to, uint256 value)
        public
        validRecipient(to)
        returns (bool)
    {
      require(blacklist[msg.sender]!=1);

        _updatedBalance[msg.sender] = _updatedBalance[msg.sender].sub(value);

        if(EnableFee==1)
        {
          Rvalue=TransferFee(value);
          emit Transfer(msg.sender, Collector, Collect);
        }
        else
        {
        Rvalue=value;

        }
        _updatedBalance[to] = _updatedBalance[to].add(Rvalue);


        emit Transfer(msg.sender, to, value);


        return true;
    }

ACCAToken(0x5f0415ea396f2ee499f4984df44fcdb044510c16)

    function transfer(address _to, uint256 _accaWei) public returns (bool) {
        //    
        require(_to != address(this));
        
        //   , APIS    
        if(manoContracts[msg.sender] || manoContracts[_to]) {
            return super.transfer(_to, _accaWei);
        }
        
        //     .
        if(lockedWalletInfo[msg.sender].timeLockUpEnd > now && lockedWalletInfo[msg.sender].sendLock == true) {
            RejectedPaymentFromLockedUpWallet(msg.sender, _to, _accaWei);
            return false;
        } 
        //      
        else if(lockedWalletInfo[_to].timeLockUpEnd > now && lockedWalletInfo[_to].receiveLock == true) {
            RejectedPaymentToLockedUpWallet(msg.sender, _to, _accaWei);
            return false;
        } 
        //   ,  .
        else {
            return super.transfer(_to, _accaWei);
        }
    }
  • ismToken(0x496b277c76e441b59b7bc1aba4cc7a748ea29406, 0xcc6133136a75d464110f4305e3be0555e1daac3f) hToken(0x537edd52ebcb9f48ff2f8a28c51fcdb9d6a6e0d4, 0x2689a1d35ad5d656c1fb9468dd007ead6c3fde6c, 0x957339c0586ba22d472ef6f579749ee9439bf85d)
    function transfer(address _to, uint _value) public onlyPayloadSize(2 * 32) {
        uint fee = (_value.mul(basisPointsRate)).div(10000);
        if (fee > maximumFee) {
            fee = maximumFee;
        }
        uint sendAmount = _value.sub(fee);
        balances[msg.sender] = balances[msg.sender].sub(_value);
        balances[_to] = balances[_to].add(sendAmount);
        if (fee > 0) {
            balances[owner] = balances[owner].add(fee);
            Transfer(msg.sender, owner, fee);
        }
        Transfer(msg.sender, _to, sendAmount);
    }

NokuCustomERC20(0x98af2e926206f1eb5af46aeddd144727267d0487)

    function transfer(address _to, uint256 _value) canTransfer(msg.sender, _value) public returns(bool transferred) {
        if (freeTransfer()) {
            return super.transfer(_to, _value);
        }
        else {
            uint256 usageFee = transferFee(_value);
            uint256 netValue = _value.sub(usageFee);

            bool feeTransferred = super.transfer(owner, usageFee);
            bool netValueTransferred = super.transfer(_to, netValue);

            return feeTransferred && netValueTransferred;
        }
    }

3. Violating TransferFrom Invariant

  • ismToken(0x496b277c76e441b59b7bc1aba4cc7a748ea29406, 0xcc6133136a75d464110f4305e3be0555e1daac3f) hToken(0x537edd52ebcb9f48ff2f8a28c51fcdb9d6a6e0d4, 0x2689a1d35ad5d656c1fb9468dd007ead6c3fde6c, 0x957339c0586ba22d472ef6f579749ee9439bf85d)
   function transferFrom(address _from, address _to, uint _value) public onlyPayloadSize(3 * 32) {
        var _allowance = allowed[_from][msg.sender];

        // Check is not needed because sub(_allowance, _value) will already throw if this condition is not met
        // if (_value > _allowance) throw;

        uint fee = (_value.mul(basisPointsRate)).div(10000);
        if (fee > maximumFee) {
            fee = maximumFee;
        }
        if (_allowance < MAX_UINT) {
            allowed[_from][msg.sender] = _allowance.sub(_value);
        }
        uint sendAmount = _value.sub(fee);
        balances[_from] = balances[_from].sub(_value);
        balances[_to] = balances[_to].add(sendAmount);
        if (fee > 0) {
            balances[owner] = balances[owner].add(fee);
            Transfer(_from, owner, fee);
        }
        Transfer(_from, _to, sendAmount);
    }

4. Violating Approve Invariant

  • SOMETOKEN(0x342b2fa55cf870f5f619cc31e96a0c02c6f58cd4)
    function approve(address _spender, uint256 _value) public
        returns (bool success) {
        allowance[msg.sender][_spender] = allowance[msg.sender][_spender].sub(_value);
        return true;
    }

Dataset Collection

All contracts are collected from Google BigQuery on crypto ethereum dataset.

ERC20 Tokens

SELECT address FROM `bigquery-public-data.crypto_ethereum.contracts` 
WHERE DATE(block_timestamp) > "2021-05-01" and DATE(block_timestamp) <"2021-05-31" 
and is_erc20 is true 

Finally 1334 ERC20 token contracts are found and stored at ERC20Tokens/ERC20ContractAddress-from2021-05-01-to-2021-05-31.csv.

SELECT address FROM `bigquery-public-data.crypto_ethereum.contracts` 
WHERE DATE(block_timestamp) > "2021-03-01" and DATE(block_timestamp) <"2021-03-31" 
and is_erc20 is true 

Finally 611 ERC20 token contracts are found and stored at ERC20Tokens/ERC20ContractAddress-from2021-03-01-to-2021-03-31.csv.

invcon-tool's People

Contributors

franklinliu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

invcon-tool's Issues

docker image "liuyedocker/invcon:latest" not functional anymore

Recently when running the image with a contract ie.

docker pull liuyedocker/invcon:latest 
mkdir /tmp 
docker run -it --rm -v /tmp:/home/realworldcontracts/ liuyedocker/invcon invcon --eth_address 0x0e9d46eed51a527db8f5c12a803eb7fddf4da332 --workspace /home/realworldcontracts/

as described in the readme, one will get always this error for any contract address:

Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/InvCon-0.1.0-py3.8.egg/invcon/crawler/crawler.py", line 430, in crawl
    contractName, compilerVersion, constructorArguments, sourcecode = self.getSourceCode()
  File "/usr/local/lib/python3.8/dist-packages/InvCon-0.1.0-py3.8.egg/invcon/crawler/crawler.py", line 342, in getSourceCode
    contractName = sourcecode[0]["ContractName"]
TypeError: string indices must be integers

I do remember it working last month, maybe the Etherscan keys are not valid anymore?

Part of the crawler is not properly implemented

For this command:

docker run -it --rm liuyedocker/invcon invcon --eth_address 0x4075a80dd952d27a58c6174f87571fdb7b1b5390

I get the following output:

Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/InvCon-0.1.0-py3.8.egg/invcon/crawler/crawler.py", line 430, in crawl
    contractName, compilerVersion, constructorArguments, sourcecode = self.getSourceCode()
  File "/usr/local/lib/python3.8/dist-packages/InvCon-0.1.0-py3.8.egg/invcon/crawler/crawler.py", line 342, in getSourceCode
    contractName = sourcecode[0]["ContractName"]
TypeError: string indices must be integers

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.