{"id":13791859,"url":"https://github.com/sec-bit/tokenlibs-with-proofs","last_synced_at":"2025-10-25T16:30:46.320Z","repository":{"id":84493399,"uuid":"139952193","full_name":"sec-bit/tokenlibs-with-proofs","owner":"sec-bit","description":"Correctness proofs of Ethereum token contracts","archived":false,"fork":false,"pushed_at":"2019-06-05T11:01:49.000Z","size":274,"stargazers_count":98,"open_issues_count":0,"forks_count":23,"subscribers_count":15,"default_branch":"master","last_synced_at":"2024-10-30T01:43:37.463Z","etag":null,"topics":["coq","erc20","formal-verification","proof","token"],"latest_commit_sha":null,"homepage":"","language":"Coq","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sec-bit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2018-07-06T07:55:31.000Z","updated_at":"2024-01-17T08:40:56.000Z","dependencies_parsed_at":"2023-03-07T15:15:32.283Z","dependency_job_id":null,"html_url":"https://github.com/sec-bit/tokenlibs-with-proofs","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sec-bit%2Ftokenlibs-with-proofs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sec-bit%2Ftokenlibs-with-proofs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sec-bit%2Ftokenlibs-with-proofs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sec-bit%2Ftokenlibs-with-proofs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sec-bit","download_url":"https://codeload.github.com/sec-bit/tokenlibs-with-proofs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238174122,"owners_count":19428629,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["coq","erc20","formal-verification","proof","token"],"created_at":"2024-08-03T22:01:05.294Z","updated_at":"2025-10-25T16:30:45.893Z","avatar_url":"https://github.com/sec-bit.png","language":"Coq","readme":"# Token Libraries with Proofs\n[![Build Status](https://travis-ci.org/sec-bit/tokenlibs-with-proofs.svg)](https://travis-ci.org/sec-bit/tokenlibs-with-proofs)\n\nThis repository collects correctness proofs of Ethereum token contracts *wrt.* given specifications and high-level properties. All of them are accomplished in Coq. \n\nProofs of following contracts are included, and more will be added in the future.\n* Basic ERC20 contract: [`erc20`](erc20)\n* Burnable ERC20 contract: [`erc20_burnable`](erc20_burnable)\n\n## Requirements\n\n[Coq](https://coq.inria.fr/) is required if you are going to check the correctness of proofs in this repo. [ProofGeneral](https://proofgeneral.github.io/) or CoqIde is required if you are going to read the definitions and the proofs in this repo thoroughly.\n\n### Coq 8.8.0\n\n[Coq](https://coq.inria.fr/) is an interactive proof assistant, which, as its name suggested, assists users to construct proofs. Its also provides a small proof checker that checks the correctness of the proof. It is required if you desire to check the correctness of proofs in this repo.\n\nThe definitions and the proofs are implemented in Coq **8.8.0** (other versions may or may not work), which can be installed by following the [official instructions](https://github.com/coq/coq/wiki#coq-installation).\n\n### CoqIde\n\nCoqIde is the official graphic front-end of Coq. It's usually installed along with Coq as shown in the above [Coq installation instructions](https://github.com/coq/coq/wiki#coq-installation). It does not require further configurations after installation. If any, you can refer to the [official instructions](https://github.com/coq/coq/wiki/Configuration%20of%20CoqIDE).\n\n### ProofGeneral\n\nIf you are an [Emacs](https://www.gnu.org/software/emacs/) user, a more convenient front-end of Coq is [ProofGeneral](https://proofgeneral.github.io/). The installation instructions of ProofGeneral can be found at https://proofgeneral.github.io/ and https://github.com/ProofGeneral/PG/blob/master/INSTALL.\n\n## Repo Structure\n\n* [`config.mk`](config.mk) defines the commands that are used to build/check the proofs in this repo.\n* [`erc20/`](erc20) contains contract-specific definitions and proofs for an ERC20 token contract. The further proofs of other contracts will go to separate directories.\n  * [`erc20.sol`](erc20/erc20.sol) is the proved ERC20 contract in Solidity.\n  * [`_CoqProject`](erc20/_CoqProject) is a recommended way to manage a Coq project. It lists files in the project and is used to generate a makefile to build  them.\n  * [`Model.v`](erc20/Model.v) models storage variables, events, message calls and the runtime environment of the contract.\n  * [`Spec.v`](erc20/Spec.v) formally defines the specification of the ERC20 contract.\n  * [`DSL.v`](erc20/DSL.v) represents the Solidity implementation of the ERC20 contract in a domain specific language, and  proves the implementation agrees with the specification in [`Spec.v`](erc20/Spec.v).\n  * [`Prop.v`](erc20/Prop.v) defines several high-level properties of the ERC20 contract, and proves they are guaranteed by the contract implementation.\n* [`libs/`](libs) contains contract-independent definitions, tactics and lemmas.\n  * [`BNat.v`](libs/BNat.v) provides convenient tactics, lemmas and theorems to prove goals about boolean and integers.\n  * [`TMap.v`](libs/TMap.v) and [`TMapLib.v`](libs/TMapLib.v) define a total map and provide convenient tactics and lemmas to prove goals related to total maps.\n  * [`Mapping.v`](libs/Mapping.v) defines a structure based on the above total map to represent the Solidity ```mapping`` type in Coq. Several relevant tactics and lemmas are provided as well.\n  * [`Types.v`](libs/Types.v) defines some other types of Solidity in Coq.\n  * [`AbsModel.v`](libs/AbsModel.v) abstracts the contract model definitions. [`Model.v`](erc20/Model.v) defines the model for the ERC20 contract by instantiating this abstract model.\n  * [`LibEx.v`](libs/LibEx.v) contains all miscellaneous stuffs.\n\n## Quick Check Proofs\n\nCoq proof checker can be invoked to check whether proofs are correct by the following command,\n\n```shell\nmake\n```\n\nor if you want to check the proof of an individual contract,\n\n```shell\ncd erc20; make\n```\n\n## Proving Process\n\nGiven a contract in Solidity, the proving process can be divided into following steps and may involve the change of the contract as shown in the following diagram. We take an [ERC20 contract](erc20/erc20.sol) and its proof in [`erc20/`](erc20) as an example to explain the process.\n\n![Proving Process](prove_flow.png)\n\n### Define the Contract Model\n\nThe contract model abstracts the storage, the events, the message calls, and the external environment. The specification, high-level properties and proofs are all based on the contract model.\n\nThe model of different contracts can be defined in a similar form, so we separate the common definitions into the contract-independent part or the *abstract model* in [`AbsModel.v`](libs/AbsModel.v) and the contract-specific part or the *concrete model* in [`Model.v`](erc20/Model.v) under each contract directory. When proving a contract, we only need to generate the concrete model from the reused abstract model.\n\nFor example, the state of every contract can be composed of a contract address and values of storage variables, while the latter component is contract-specific. Thus, the contract state in the abstract model can be defined as below in [`AbsModel.v`](libs/AbsModel.v) :\n\n```ocaml\n(* Abstract type of the contract *)\nRecord TContract(TState: Type): Type :=\n  mk_contract {\n      w_a: address; (* contract address *)\n      w_st: TState; (* contract storage state *)\n    }.\n```\n\nwhich requires a state ```TState``` of concrete storage variables to instantiate.\n\nCorrespondingly, the concrete contract state of a ERC20 can be defined from the abstract one as below in [`Model.v`](erc20/Model.v):\n\n```ocaml\n(* State of storage variables in ERC20 contract. *)\nRecord state: Type :=\n  mk_st {\n      st_symbol     : string;  (* symbol      *)\n      st_name       : string;  (* name        *)\n      st_decimals   : uint8;   (* decimals    *)\n      st_totalSupply: uint256; (* totalSupply *)\n\n      st_balances: a2v;        (* balances    *)\n      st_allowed: aa2v;        (* allowed     *)\n   }.\n\n(* ERC20 contract state instantiated from TContract with state. *)\nDefinition contract := TContract state.\n```\n\n**Note** The current model in this repository only covers components that are neccesary to define and prove the following specifications and high-level properties. Other components, such the gas price and limit, nonce and a comprehensive block descriptions, will be added later.\n\n\n### Represent the Solidity Implementation in Coq\n\nIn order to prove a contract, we need to first represent it in Coq. Instead of supporting every syntax structure of Solidity, we choose to design a domain specific language in Coq whose syntax is simple but enough to express most Solidity contracts. [`DSL.v`](erc20/DSL.v) includes a definition of such domain specific language. By carefully manipulating notations in Coq, DSL can event present a close look as Solidity. For example, ```transfer()``` in DSL is defined as below in [`DSL.v`](erc20/DSL.v):\n\n```ocaml\n  (* DSL representation of transfer(), generated from solidity *)\n  Definition transfer_dsl : Stmt :=\n    ((@require(balances[msg.sender] \u003e= value)) ;\n     (@require((msg.sender == to) || (balances[to] \u003c= max_uint256 - value))) ;\n     (@balances[msg.sender] -= value) ;\n     (@balances[to] += value) ;\n     (@emit Transfer(msg.sender, to, value)) ;\n     (@return true)\n    ).\n```\n\nBesides the syntax, it also needs to define the semantics of DSL as close to Solidity as possible. Because DSL is now generated per-contract, its semantics only needs to model a small portion of Solidity, such as  ```dsl_exec``` and ```dsl_exec_prim``` in [`DSL.v`](erc20/DSL.v).\n\nBoth the generation of DSL definition and the conversion from Solidity to DSL can be automated.\n\n### Define the Contract Specification\n\nThe specification in this repo defines the expected behavior of each contract function. The specification is defined in a form like Hoare tuple  composed of two parts:\n\n* **Invariant** defines conditions that must hold before and after every execution of every contract function. For simple contracts like ERC20 token contract. it can be as easy as True.\n\n* **Function specifications** define the function-specific behavior of individual functions, each of which is further compose of the following components.\n\n  * **Requirements** define the conditions besides the invariant that must hold before the execution of the specified function. It can be used to capture semantics of ```require``` statements in the specified function.\n  * **Rules** define expected behavior of the specified function in each case. For different combinations of arguments, a contract function can behave differently, which may be too complicated to be described all together monolithically.  In such cases, we can separate them into exclusive and simple rules.  Two categories of behaviors are  described by a rule.\n    * *State changes before and after the execution of a function*, such as how storage variables are changed.\n    * *Logged events*.\n\n  For example, the specification rule of ERC20 ```transfer()``` is defined as below in [`Spec.v`](erc20/Spec.v):\n\n  ```ocaml\n  Definition funcspec_transfer\n             (to: address)\n             (value: value) :=\n    fun (this: address) (env: env) (msg: message) =\u003e\n      (mk_spec\n         (* require(balances[msg.sender] \u003e= _value); *)\n         (fun S : state =\u003e\n            (st_balances S (m_sender msg )) \u003e= value /\\\n         (* require(msg.sender == _to || balances[_to] \u003c= MAX_UINT256 - _value); *)\n            ((m_sender msg = to) \\/ (m_sender msg \u003c\u003e to /\\ st_balances S to \u003c= MAX_UINT256 - value)))\n  \n         (* emit Transfer(msg.sender, _to, _value); *)\n         (* return True; *)\n         (fun S E =\u003e E = (ev_Transfer (m_sender msg) (m_sender msg) to value) :: (ev_return _ True) :: nil)\n  \n         (* State transition: *)\n         (fun S S' : state =\u003e\n         (* totalSupply, name, decimals, symbol, allowed are not changed. *)\n            st_totalSupply S' = st_totalSupply S /\\\n            st_name S' = st_name S /\\\n            st_decimals S' = st_decimals S /\\\n            st_symbol S' = st_symbol S /\\\n            st_allowed S' = st_allowed S /\\\n         (* balances[msg.sender] -= _value; *)\n            st_balances S' = (st_balances S) $+{ (m_sender msg) \u003c- -= value }\n         (* balances[_to] += _value; *)\n                                             $+{ to \u003c- += value })\n  \n      ).\n  ```\n\n### Prove Against the Specification\n\nProofs in this step is to show each contract function in DSL does implement the corresponding specification. For example, we prove the following lemma in [`DSL.v`](erc20/DSL.v) to verify ```transfer()``` function.\n\n```ocaml\n  Lemma transfer_dsl_sat_spec:\n    forall st env msg this,\n      spec_require (funcspec_transfer _to _value this env msg) st -\u003e\n      forall st0 result,\n        dsl_exec transfer_dsl st0 st env msg this nil = result -\u003e\n        spec_trans (funcspec_transfer _to _value this env msg) st (ret_st result) /\\\n        spec_events (funcspec_transfer _to _value this env msg) (ret_st result) (ret_evts result).\n```\n\nThe proving is accomplished by constructing the starting state, the ending states and the logged events from definitions of ```dsl_exec``` and ```transfer_dsl```, and then checking whether those states and events can satisfy the conditions required by the specification ```spec_trans``` and ```spec_events```.\n\nIf the proving cannot be accomplished, it may imply bugs in the Solidity implementation. By analyzing the location where the proving gets stuck and the reason, we can get what modifications are required. After the necessary update, we can restart from the first step.\n\n### Define the High-level Properties\n\nThe high-level properties define the expected behavior when all functions in a contract work as a whole. For example, the total supply in a ERC20 contract should always be the same as the sum of all balances, which can be defined as below in [`Prop.v`](erc20/Prop.v):\n\n```ocaml\nTheorem Property_totalSupply_equal_to_sum_balances :\n  forall env0 env msg ml C E C' E',\n    create env0 msg C E\n    -\u003e env_step env0 env\n    -\u003e run env C ml C' E'\n    -\u003e Sum (st_balances (w_st C')) (st_totalSupply (w_st C')).\n```\n\n### Prove Against the High-Level Properties\n\nThe proving of high-level properties is accomplished upon specifications. Because it has been proved that each contract function does implement its specifications, we can imply that the contract as a whole satisfies the high level properties. The proofs of above properties and other high-level ERC20 contract properties can be found in [`Prop.v`](erc20/Prop.v).\n\nIf the proving cannot be accomplished, it may imply bugs in the Solidity implementation. By analyzing the location where the proving gets stuck and the reason, we can get what modifications are required. After the necessary update, we can restart from the first step.\n\n## How to Contribute\n\nThe correctness of proofs in this repo still relies on the correctness of all definitions, the conversion from Solidity to DSL, and Coq, which can not be verified in the same logical system. If you find any errors and/or have any suggestions, you are very appreciated to open issues and/or send us pull requests.\n\n## Related Work\n\n* KEVM: Semantics of EVM in K. https://github.com/kframework/evm-semantics\n* DSLs for Ethereum Contracts. https://www.michaelburge.us/2018/05/15/ethereum-chess-engine.html\n* Formal Verification of Ethereum Contracts (Yoichi's attempts). https://github.com/pirapira/ethereum-formal-verification-overview\n\n## Acknowledgement\n\nWe would like to thank Yi Tang ([ConsenSys](https://consensys.net/)), Yuhui Wu ([轻信科技](http://www.ledgergo.com/)), and Zhong Zhuang ([DEx.top](https://dex.top/)) for their suggestions and help.\n\n## Disclaimers\n\nThis repository is to demonstrate how the real world smart contracts can be formally proved in Coq, rather than providing smart contracts that can be used in arbitrary usage scenarios. \n\n1. The correctness of every proved contracts in this repo is defined against the given specifications and high-level properties, which may or may not fit a specific usage scenarios. \n2. The proof is only valid for the given contract implementation. Any changes in the contract implementation may invalidate the proof.\n3. The reliability and the correctness of proved contracts depend on the correctness of all definitions in this repo, the conversion from Solidity to DSL, and Coq, which cannot be verified in the same logical system where proofs are checked. Any errors in those components would invalidate the contract correctness.\n\nIn addition, as licensed as LGPL v3, all artifacts in this repository are distributed in the hope it will be useful, but without any warranty, without even the implied warranty of merchantability or fitness for a particular purpose.\n","funding_links":[],"categories":["Roadmap","Libraries"],"sub_categories":["Standard contracts"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsec-bit%2Ftokenlibs-with-proofs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsec-bit%2Ftokenlibs-with-proofs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsec-bit%2Ftokenlibs-with-proofs/lists"}