epfl-lara / smart

Verification and Generation of Smart Contracts using Stainless and Scala

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Stainless for Smart Contracts

Release Build Status Gitter chat Apache 2.0 License

Stainless for Smart Contracts 0.7.4s is a fork of Stainless which showcases formal verification of smart contracts written in a subset of Scala, and the compiler of this subset to Solidity.

Installation

$ git clone https://github.com/epfl-lara/smart.git
$ cd smart
$ sbt clean universal:stage

You can then create a symbolic link (e.g. for Linux & Mac OS-X) to have access to a stainless command-line.

 ln -s frontends/scalac/target/universal/stage/bin/stainless-scalac stainless

Fore more information, you can refer to the Stainless documentation:

Formal Verification

To get the flavor of verification of smart contracts, consult the examples in the repository.

Candy is a simple smart contract written in our language. The constructor of the contract takes an initial number of candies, which can then be eaten by the eatCandy function. The contract maintains the invariant that the sum of eaten and remaining candies equals the initial candies.

import stainless.smartcontracts._
import stainless.lang.StaticChecks._
import stainless.annotation._

trait Candy extends Contract {
  var initialCandies: Uint256
  var remainingCandies: Uint256
  var eatenCandies: Uint256

  @solidityPublic
  final def constructor(_candies: Uint256) = {
    initialCandies = _candies
    remainingCandies = _candies
    eatenCandies = Uint256.ZERO
  }

  @solidityPublic
  final def eatCandy(candies: Uint256) = {
    dynRequire(candies <= remainingCandies)

    remainingCandies -= candies
    eatenCandies += candies
  }

  @ghost @inline
  final def invariant(): Boolean = {
    eatenCandies <= initialCandies &&
    remainingCandies <= initialCandies &&
    initialCandies - eatenCandies == remainingCandies
  }
}

Stainless is able to verify that the constructor creates a state where the invariant holds, and the eatCandy function modifies the state in a way that preserves the invariant. Verification for Uint256 examples is faster if you configure stainless to use the external CVC4 solver (which needs to be downloaded separately and added to your path):

./stainless frontends/benchmarks/smartcontracts/valid/Candy.scala --solvers=smt-cvc4

[  Info  ]   ┌───────────────────┐
[  Info  ] ╔═╡ stainless summary ╞═════════════════════════╗
[  Info  ] ║ └───────────────────┘                         ║
[  Info  ] ║ constructor  body assertion  valid ... 0.122  ║
[  Info  ] ║ eatCandy     body assertion  valid ... 11.109 ║
[  Info  ] ╟┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╢
[  Info  ] ║ total: 2    valid: 2 ... invalid: 0  ...      ║
[  Info  ] ╚═══════════════════════════════════════════════╝

Compilation to Solidity

The contract can be compiled to Solidity using

stainless frontends/benchmarks/smartcontracts/valid/Candy.scala --solidity

which produces a file Candy.sol. The compiler drops the assertions, but compiles the dynRequire (dynamic require) commands to require in Solidity. The compiler also drops the function invariant which is marked with @ghost.

pragma solidity ^0.7.2;

contract Candy {
    // Fields
    uint256 initialCandies;
    uint256 remainingCandies;
    uint256 eatenCandies;

    // Constructor
    constructor (uint256 _candies) public {
        initialCandies = _candies;
        remainingCandies = _candies;
        eatenCandies = 0;
    }

    // Public functions
    function eatCandy (uint256 candies) public {
        require(candies <= remainingCandies, "error");
        remainingCandies = remainingCandies - candies;
        eatenCandies = eatenCandies + candies;
    }

    // Private functions
    function invariant () view private returns (bool) {
        return eatenCandies <= initialCandies && remainingCandies <= initialCandies &&
          initialCandies - eatenCandies == remainingCandies;
    }
}

Disclaimer

IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

See also the license.

About

Verification and Generation of Smart Contracts using Stainless and Scala

License:Apache License 2.0


Languages

Language:HTML 61.1%Language:Scala 36.6%Language:JavaScript 0.8%Language:CSS 0.7%Language:Coq 0.5%Language:Shell 0.2%Language:Python 0.1%Language:Makefile 0.1%Language:Dockerfile 0.0%Language:Nix 0.0%