├── .gitignore ├── LICENSE ├── README.md ├── docs ├── .texpadtmp │ ├── main.log │ └── main.synctex.gz ├── images │ ├── example-1.pdf │ ├── example-1.xml │ ├── example-2.pdf │ └── example-2.xml ├── main.pdf └── main.tex ├── src ├── DEA.hs ├── DEA │ ├── DEA.hs │ ├── Instrumentation.hs │ └── Parsing.hs ├── Main.hs ├── Parseable.hs ├── Solidity.hs ├── Solidity │ ├── Instrumentation.hs │ ├── Parsing.hs │ └── Solidity.hs └── TODO.txt ├── template.dea └── use-cases ├── Casino ├── Casino.sol ├── CasinoSpec.dea └── monitoredCasino.sol ├── CourierService ├── CourierService.sol ├── courierservicespec.dea └── monitoredCourierService.sol ├── ERC20Interface ├── ERC20Interface.sol ├── ERC20InterfaceSpec.dea └── MonitoredERC20Interface.sol ├── FixedSupplyToken ├── FixedSupplyToken.sol ├── FixedSupplyTokenSpec.dea └── MonitoredFixedSupplyToken.sol ├── InsuredCourierService ├── InsuredCourierService.sol ├── InsuredCourierServiceSpec.dea └── MonitoredInsuredCourierService.sol ├── MultiOwnersWallet ├── MultiOwnersWallet.sol ├── MultiOwnersWalletSpec.dea └── monitoredMultiOwnersWallet.sol ├── Procurement ├── MonitoredProcurement.sol ├── Procurement.sol └── ProcurementSpec.dea ├── README.md ├── SmartAuctionHouse ├── SmartAuctionHouse.sol ├── SmartAuctionHouseSpec.dea └── monitoredSmartAuctionHouse.sol ├── WalletWithDeposit ├── MonitoredWalletWithDeposit.sol ├── WalletWithDeposit.sol └── WalletWithDepositSpec.dea └── tutorial ├── dea-latex-highlighting.tex ├── main.pdf ├── main.tex └── solidity-latex-highlighting.tex /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | dist-* 3 | cabal-dev 4 | *.o 5 | *.hi 6 | *.chi 7 | *.chs.h 8 | *.dyn_o 9 | *.dyn_hi 10 | .hpc 11 | .hsenv 12 | .cabal-sandbox/ 13 | cabal.sandbox.config 14 | *.prof 15 | *.aux 16 | *.hp 17 | *.eventlog 18 | .stack-work/ 19 | cabal.project.local 20 | .HTF/ 21 | *.aux 22 | *.bbl 23 | *.blg 24 | *.log 25 | *.txt 26 | *.exe 27 | *.gz 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # contractLarva: Runtime Verification of Solidity Smart Contracts 2 | Gordon J. Pace <gordon.pace@um.edu.mt> 3 | 4 | Joshua Ellul <joshua.ellul@um.edu.mt> 5 | 6 | Shaun Azzopardi <shaun.azzopardi@um.edu.mt> 7 | 8 | ## Overview 9 | 10 | contractLarva is a runtime verification tool for Solidity contracts. For more details about the tool check out the user manual in the docs folder. 11 | 12 | The code is currently undocumented and not well organised. Hopefully, it will be cleaned up for the next major release. 13 | 14 | If you would like to ask any questions, report any bugs or make any feature requests, contact us using one of the emails above. 15 | 16 | ## Building the tool 17 | 18 | To compile contractLarva, you need a recent version of [GHC](https://www.haskell.org/ghc/). The easiest option is to install the [Haskell Platform](https://www.haskell.org/platform/) which comes with all the necessary libraries included (make sure that you choose to install the full platform, not the minimal one). To compile contractLarva, then simply run the following command in the src folder: 19 | 20 | > ghc -o contractlarva Main.hs 21 | 22 | ## Tool usage: 23 | 24 | > contractlarva <specification.dae> <input.sol> <output.sol> 25 | 26 | or to prevent the initialisation block from being executed as part of the smart contract constructor add the `--init-not-inlined` flag: 27 | 28 | > contractlarva <specification.dae> <input.sol> <output.sol> --init-not-inlined 29 | 30 | ## License 31 | This project is licensed under the terms of the [Apache 2.0 license](LICENSE). 32 | 33 | ---- 34 | # FAQ and Common Problems 35 | 36 | ### When compiling the code I get the error: Could not find module ‘Text.Parsec’. 37 | Make sure you have installed parsec. Also, see this stackoverflow thread (https://stackoverflow.com/questions/9058914/cant-find-parsec-modules-in-ghci) 38 | >cabal install parsec 39 | -------------------------------------------------------------------------------- /docs/.texpadtmp/main.log: -------------------------------------------------------------------------------- 1 | This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017) (preloaded format=pdflatex 2017.10.19) 14 DEC 2017 17:25 2 | entering extended mode 3 | restricted \write18 enabled. 4 | file:line:error style messages enabled. 5 | %&-line parsing enabled. 6 | **main.tex 7 | (./main.tex 8 | LaTeX2e <2017-04-15> 9 | Babel <3.10> and hyphenation patterns for 84 language(s) loaded. 10 | (/usr/local/texlive/2017/texmf-dist/tex/latex/base/article.cls 11 | Document Class: article 2014/09/29 v1.4h Standard LaTeX document class 12 | (/usr/local/texlive/2017/texmf-dist/tex/latex/base/size10.clo 13 | File: size10.clo 2014/09/29 v1.4h Standard LaTeX file (size option) 14 | ) 15 | \c@part=\count79 16 | \c@section=\count80 17 | \c@subsection=\count81 18 | \c@subsubsection=\count82 19 | \c@paragraph=\count83 20 | \c@subparagraph=\count84 21 | \c@figure=\count85 22 | \c@table=\count86 23 | \abovecaptionskip=\skip41 24 | \belowcaptionskip=\skip42 25 | \bibindent=\dimen102 26 | ) (/usr/local/texlive/2017/texmf-dist/tex/latex/todonotes/todonotes.sty 27 | Package: todonotes 2015/07/09 .dtx Todonotes source and documentation. 28 | Package: todonotes 2012/07/25 29 | (/usr/local/texlive/2017/texmf-dist/tex/latex/base/ifthen.sty 30 | Package: ifthen 2014/09/29 v1.1c Standard LaTeX ifthen package (DPC) 31 | ) (/usr/local/texlive/2017/texmf-dist/tex/latex/xkeyval/xkeyval.sty 32 | Package: xkeyval 2014/12/03 v2.7a package option processing (HA) 33 | (/usr/local/texlive/2017/texmf-dist/tex/generic/xkeyval/xkeyval.tex (/usr/local/texlive/2017/texmf-dist/tex/generic/xkeyval/xkvutils.tex 34 | \XKV@toks=\toks14 35 | \XKV@tempa@toks=\toks15 36 | (/usr/local/texlive/2017/texmf-dist/tex/generic/xkeyval/keyval.tex)) 37 | \XKV@depth=\count87 38 | File: xkeyval.tex 2014/12/03 v2.7a key=value parser (HA) 39 | )) (/usr/local/texlive/2017/texmf-dist/tex/latex/xcolor/xcolor.sty 40 | Package: xcolor 2016/05/11 v2.12 LaTeX color extensions (UK) 41 | (/usr/local/texlive/2017/texmf-dist/tex/latex/graphics-cfg/color.cfg 42 | File: color.cfg 2016/01/02 v1.6 sample color configuration 43 | ) 44 | Package xcolor Info: Driver file: pdftex.def on input line 225. 45 | (/usr/local/texlive/2017/texmf-dist/tex/latex/graphics-def/pdftex.def 46 | File: pdftex.def 2017/01/12 v0.06k Graphics/color for pdfTeX 47 | (/usr/local/texlive/2017/texmf-dist/tex/generic/oberdiek/infwarerr.sty 48 | Package: infwarerr 2016/05/16 v1.4 Providing info/warning/error messages (HO) 49 | ) (/usr/local/texlive/2017/texmf-dist/tex/generic/oberdiek/ltxcmds.sty 50 | Package: ltxcmds 2016/05/16 v1.23 LaTeX kernel commands for general use (HO) 51 | ) 52 | \Gread@gobject=\count88 53 | ) 54 | Package xcolor Info: Model `cmy' substituted by `cmy0' on input line 1348. 55 | Package xcolor Info: Model `hsb' substituted by `rgb' on input line 1352. 56 | Package xcolor Info: Model `RGB' extended on input line 1364. 57 | Package xcolor Info: Model `HTML' substituted by `rgb' on input line 1366. 58 | Package xcolor Info: Model `Hsb' substituted by `hsb' on input line 1367. 59 | Package xcolor Info: Model `tHsb' substituted by `hsb' on input line 1368. 60 | Package xcolor Info: Model `HSB' substituted by `hsb' on input line 1369. 61 | Package xcolor Info: Model `Gray' substituted by `gray' on input line 1370. 62 | Package xcolor Info: Model `wave' substituted by `hsb' on input line 1371. 63 | ) (/usr/local/texlive/2017/texmf-dist/tex/latex/pgf/frontendlayer/tikz.sty (/usr/local/texlive/2017/texmf-dist/tex/latex/pgf/basiclayer/pgf.sty (/usr/local/texlive/2017/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/utilities/pgfutil-common.tex 64 | \pgfutil@everybye=\toks16 65 | \pgfutil@tempdima=\dimen103 66 | \pgfutil@tempdimb=\dimen104 67 | (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/utilities/pgfutil-common-lists.tex)) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/utilities/pgfutil-latex.def 68 | \pgfutil@abb=\box26 69 | (/usr/local/texlive/2017/texmf-dist/tex/latex/ms/everyshi.sty 70 | Package: everyshi 2001/05/15 v3.00 EveryShipout Package (MS) 71 | )) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/utilities/pgfrcs.code.tex 72 | Package: pgfrcs 2015/08/07 v3.0.1a (rcs-revision 1.31) 73 | )) 74 | Package: pgf 2015/08/07 v3.0.1a (rcs-revision 1.15) 75 | (/usr/local/texlive/2017/texmf-dist/tex/latex/pgf/basiclayer/pgfcore.sty (/usr/local/texlive/2017/texmf-dist/tex/latex/graphics/graphicx.sty 76 | Package: graphicx 2014/10/28 v1.0g Enhanced LaTeX Graphics (DPC,SPQR) 77 | (/usr/local/texlive/2017/texmf-dist/tex/latex/graphics/graphics.sty 78 | Package: graphics 2017/04/14 v1.1b Standard LaTeX Graphics (DPC,SPQR) 79 | (/usr/local/texlive/2017/texmf-dist/tex/latex/graphics/trig.sty 80 | Package: trig 2016/01/03 v1.10 sin cos tan (DPC) 81 | ) (/usr/local/texlive/2017/texmf-dist/tex/latex/graphics-cfg/graphics.cfg 82 | File: graphics.cfg 2016/06/04 v1.11 sample graphics configuration 83 | ) 84 | Package graphics Info: Driver file: pdftex.def on input line 99. 85 | ) 86 | \Gin@req@height=\dimen105 87 | \Gin@req@width=\dimen106 88 | ) (/usr/local/texlive/2017/texmf-dist/tex/latex/pgf/systemlayer/pgfsys.sty (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/systemlayer/pgfsys.code.tex 89 | Package: pgfsys 2014/07/09 v3.0.1a (rcs-revision 1.48) 90 | (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/utilities/pgfkeys.code.tex 91 | \pgfkeys@pathtoks=\toks17 92 | \pgfkeys@temptoks=\toks18 93 | 94 | (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/utilities/pgfkeysfiltered.code.tex 95 | \pgfkeys@tmptoks=\toks19 96 | )) 97 | \pgf@x=\dimen107 98 | \pgf@y=\dimen108 99 | \pgf@xa=\dimen109 100 | \pgf@ya=\dimen110 101 | \pgf@xb=\dimen111 102 | \pgf@yb=\dimen112 103 | \pgf@xc=\dimen113 104 | \pgf@yc=\dimen114 105 | \w@pgf@writea=\write3 106 | \r@pgf@reada=\read1 107 | \c@pgf@counta=\count89 108 | \c@pgf@countb=\count90 109 | \c@pgf@countc=\count91 110 | \c@pgf@countd=\count92 111 | \t@pgf@toka=\toks20 112 | \t@pgf@tokb=\toks21 113 | \t@pgf@tokc=\toks22 114 | (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/systemlayer/pgf.cfg 115 | File: pgf.cfg 2008/05/14 (rcs-revision 1.7) 116 | ) 117 | Driver file for pgf: pgfsys-pdftex.def 118 | (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/systemlayer/pgfsys-pdftex.def 119 | File: pgfsys-pdftex.def 2014/10/11 (rcs-revision 1.35) 120 | (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/systemlayer/pgfsys-common-pdf.def 121 | File: pgfsys-common-pdf.def 2013/10/10 (rcs-revision 1.13) 122 | ))) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/systemlayer/pgfsyssoftpath.code.tex 123 | File: pgfsyssoftpath.code.tex 2013/09/09 (rcs-revision 1.9) 124 | \pgfsyssoftpath@smallbuffer@items=\count93 125 | \pgfsyssoftpath@bigbuffer@items=\count94 126 | ) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/systemlayer/pgfsysprotocol.code.tex 127 | File: pgfsysprotocol.code.tex 2006/10/16 (rcs-revision 1.4) 128 | )) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/basiclayer/pgfcore.code.tex 129 | Package: pgfcore 2010/04/11 v3.0.1a (rcs-revision 1.7) 130 | (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/math/pgfmathcalc.code.tex (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/math/pgfmathutil.code.tex) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/math/pgfmathparser.code.tex 131 | \pgfmath@dimen=\dimen115 132 | \pgfmath@count=\count95 133 | \pgfmath@box=\box27 134 | \pgfmath@toks=\toks23 135 | \pgfmath@stack@operand=\toks24 136 | \pgfmath@stack@operation=\toks25 137 | ) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.code.tex (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.basic.code.tex) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.trigonometric.code.tex) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.random.code.tex) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.comparison.code.tex) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.base.code.tex) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.round.code.tex) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.misc.code.tex) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.integerarithmetics.code.tex))) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/math/pgfmathfloat.code.tex 138 | \c@pgfmathroundto@lastzeros=\count96 139 | )) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepoints.code.tex 140 | File: pgfcorepoints.code.tex 2013/10/07 (rcs-revision 1.27) 141 | \pgf@picminx=\dimen116 142 | \pgf@picmaxx=\dimen117 143 | \pgf@picminy=\dimen118 144 | \pgf@picmaxy=\dimen119 145 | \pgf@pathminx=\dimen120 146 | \pgf@pathmaxx=\dimen121 147 | \pgf@pathminy=\dimen122 148 | \pgf@pathmaxy=\dimen123 149 | \pgf@xx=\dimen124 150 | \pgf@xy=\dimen125 151 | \pgf@yx=\dimen126 152 | \pgf@yy=\dimen127 153 | \pgf@zx=\dimen128 154 | \pgf@zy=\dimen129 155 | ) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathconstruct.code.tex 156 | File: pgfcorepathconstruct.code.tex 2013/10/07 (rcs-revision 1.29) 157 | \pgf@path@lastx=\dimen130 158 | \pgf@path@lasty=\dimen131 159 | ) 160 | (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathusage.code.tex 161 | File: pgfcorepathusage.code.tex 2014/11/02 (rcs-revision 1.24) 162 | \pgf@shorten@end@additional=\dimen132 163 | \pgf@shorten@start@additional=\dimen133 164 | ) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/basiclayer/pgfcorescopes.code.tex 165 | File: pgfcorescopes.code.tex 2015/05/08 (rcs-revision 1.46) 166 | \pgfpic=\box28 167 | \pgf@hbox=\box29 168 | \pgf@layerbox@main=\box30 169 | \pgf@picture@serial@count=\count97 170 | ) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/basiclayer/pgfcoregraphicstate.code.tex 171 | File: pgfcoregraphicstate.code.tex 2014/11/02 (rcs-revision 1.12) 172 | \pgflinewidth=\dimen134 173 | ) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/basiclayer/pgfcoretransformations.code.tex 174 | File: pgfcoretransformations.code.tex 2015/08/07 (rcs-revision 1.20) 175 | \pgf@pt@x=\dimen135 176 | \pgf@pt@y=\dimen136 177 | \pgf@pt@temp=\dimen137 178 | ) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/basiclayer/pgfcorequick.code.tex 179 | File: pgfcorequick.code.tex 2008/10/09 (rcs-revision 1.3) 180 | ) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreobjects.code.tex 181 | File: pgfcoreobjects.code.tex 2006/10/11 (rcs-revision 1.2) 182 | ) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathprocessing.code.tex 183 | File: pgfcorepathprocessing.code.tex 2013/09/09 (rcs-revision 1.9) 184 | ) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/basiclayer/pgfcorearrows.code.tex 185 | File: pgfcorearrows.code.tex 2015/05/14 (rcs-revision 1.43) 186 | \pgfarrowsep=\dimen138 187 | ) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreshade.code.tex 188 | File: pgfcoreshade.code.tex 2013/07/15 (rcs-revision 1.15) 189 | \pgf@max=\dimen139 190 | \pgf@sys@shading@range@num=\count98 191 | ) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreimage.code.tex 192 | File: pgfcoreimage.code.tex 2013/07/15 (rcs-revision 1.18) 193 | (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreexternal.code.tex 194 | File: pgfcoreexternal.code.tex 2014/07/09 (rcs-revision 1.21) 195 | \pgfexternal@startupbox=\box31 196 | )) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/basiclayer/pgfcorelayers.code.tex 197 | File: pgfcorelayers.code.tex 2013/07/18 (rcs-revision 1.7) 198 | ) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/basiclayer/pgfcoretransparency.code.tex 199 | File: pgfcoretransparency.code.tex 2013/09/30 (rcs-revision 1.5) 200 | ) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepatterns.code.tex 201 | File: pgfcorepatterns.code.tex 2013/11/07 (rcs-revision 1.5) 202 | ))) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/modules/pgfmoduleshapes.code.tex 203 | File: pgfmoduleshapes.code.tex 2014/03/21 (rcs-revision 1.35) 204 | \pgfnodeparttextbox=\box32 205 | ) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/modules/pgfmoduleplot.code.tex 206 | File: pgfmoduleplot.code.tex 2015/08/03 (rcs-revision 1.13) 207 | ) (/usr/local/texlive/2017/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-0-65.sty 208 | Package: pgfcomp-version-0-65 2007/07/03 v3.0.1a (rcs-revision 1.7) 209 | \pgf@nodesepstart=\dimen140 210 | \pgf@nodesepend=\dimen141 211 | ) (/usr/local/texlive/2017/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-1-18.sty 212 | Package: pgfcomp-version-1-18 2007/07/23 v3.0.1a (rcs-revision 1.1) 213 | )) (/usr/local/texlive/2017/texmf-dist/tex/latex/pgf/utilities/pgffor.sty (/usr/local/texlive/2017/texmf-dist/tex/latex/pgf/utilities/pgfkeys.sty (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/utilities/pgfkeys.code.tex)) (/usr/local/texlive/2017/texmf-dist/tex/latex/pgf/math/pgfmath.sty (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex)) 214 | (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/utilities/pgffor.code.tex 215 | Package: pgffor 2013/12/13 v3.0.1a (rcs-revision 1.25) 216 | (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex) 217 | \pgffor@iter=\dimen142 218 | \pgffor@skip=\dimen143 219 | \pgffor@stack=\toks26 220 | \pgffor@toks=\toks27 221 | )) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/frontendlayer/tikz/tikz.code.tex 222 | Package: tikz 2015/08/07 v3.0.1a (rcs-revision 1.151) 223 | (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/libraries/pgflibraryplothandlers.code.tex 224 | File: pgflibraryplothandlers.code.tex 2013/08/31 v3.0.1a (rcs-revision 1.20) 225 | \pgf@plot@mark@count=\count99 226 | \pgfplotmarksize=\dimen144 227 | ) 228 | \tikz@lastx=\dimen145 229 | \tikz@lasty=\dimen146 230 | \tikz@lastxsaved=\dimen147 231 | \tikz@lastysaved=\dimen148 232 | \tikzleveldistance=\dimen149 233 | \tikzsiblingdistance=\dimen150 234 | \tikz@figbox=\box33 235 | \tikz@figbox@bg=\box34 236 | \tikz@tempbox=\box35 237 | \tikz@tempbox@bg=\box36 238 | \tikztreelevel=\count100 239 | \tikznumberofchildren=\count101 240 | \tikznumberofcurrentchild=\count102 241 | \tikz@fig@count=\count103 242 | (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/modules/pgfmodulematrix.code.tex 243 | File: pgfmodulematrix.code.tex 2013/09/17 (rcs-revision 1.8) 244 | \pgfmatrixcurrentrow=\count104 245 | \pgfmatrixcurrentcolumn=\count105 246 | \pgf@matrix@numberofcolumns=\count106 247 | ) 248 | \tikz@expandcount=\count107 249 | (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrarytopaths.code.tex 250 | File: tikzlibrarytopaths.code.tex 2008/06/17 v3.0.1a (rcs-revision 1.2) 251 | ))) (/usr/local/texlive/2017/texmf-dist/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrarypositioning.code.tex 252 | File: tikzlibrarypositioning.code.tex 2008/10/06 v3.0.1a (rcs-revision 1.7) 253 | ) (/usr/local/texlive/2017/texmf-dist/tex/latex/tools/calc.sty 254 | Package: calc 2014/10/28 v4.3 Infix arithmetic (KKT,FJ) 255 | \calc@Acount=\count108 256 | \calc@Bcount=\count109 257 | \calc@Adimen=\dimen151 258 | \calc@Bdimen=\dimen152 259 | \calc@Askip=\skip43 260 | \calc@Bskip=\skip44 261 | LaTeX Info: Redefining \setlength on input line 80. 262 | LaTeX Info: Redefining \addtolength on input line 81. 263 | \calc@Ccount=\count110 264 | \calc@Cskip=\skip45 265 | ) 266 | \c@@todonotes@numberoftodonotes=\count111 267 | ) (/usr/local/texlive/2017/texmf-dist/tex/latex/tools/xspace.sty 268 | Package: xspace 2014/10/28 v1.13 Space after command names (DPC,MH) 269 | ) (/usr/local/texlive/2017/texmf-dist/tex/latex/url/url.sty 270 | \Urlmuskip=\muskip10 271 | Package: url 2013/09/16 ver 3.4 Verb mode for urls, etc. 272 | ) (/usr/local/texlive/2017/texmf-dist/tex/latex/base/alltt.sty 273 | Package: alltt 1997/06/16 v2.0g defines alltt environment 274 | ) (/usr/local/texlive/2017/texmf-dist/tex/latex/geometry/geometry.sty 275 | Package: geometry 2010/09/12 v5.6 Page Geometry 276 | (/usr/local/texlive/2017/texmf-dist/tex/generic/oberdiek/ifpdf.sty 277 | Package: ifpdf 2017/03/15 v3.2 Provides the ifpdf switch 278 | ) (/usr/local/texlive/2017/texmf-dist/tex/generic/oberdiek/ifvtex.sty 279 | Package: ifvtex 2016/05/16 v1.6 Detect VTeX and its facilities (HO) 280 | Package ifvtex Info: VTeX not detected. 281 | ) (/usr/local/texlive/2017/texmf-dist/tex/generic/ifxetex/ifxetex.sty 282 | Package: ifxetex 2010/09/12 v0.6 Provides ifxetex conditional 283 | ) 284 | \Gm@cnth=\count112 285 | \Gm@cntv=\count113 286 | \c@Gm@tempcnt=\count114 287 | \Gm@bindingoffset=\dimen153 288 | \Gm@wd@mp=\dimen154 289 | \Gm@odd@mp=\dimen155 290 | \Gm@even@mp=\dimen156 291 | \Gm@layoutwidth=\dimen157 292 | \Gm@layoutheight=\dimen158 293 | \Gm@layouthoffset=\dimen159 294 | \Gm@layoutvoffset=\dimen160 295 | \Gm@dimlist=\toks28 296 | ) (/usr/local/texlive/2017/texmf-dist/tex/latex/enumitem/enumitem.sty 297 | Package: enumitem 2011/09/28 v3.5.2 Customized lists 298 | \enitkv@toks@=\toks29 299 | \labelindent=\skip46 300 | \enit@outerparindent=\dimen161 301 | \enit@toks=\toks30 302 | \enit@inbox=\box37 303 | \enitdp@description=\count115 304 | ) (/Users/gordon/Dropbox/Data/Desktop/contractLarva-github/docs/.texpadtmp/main.aux) 305 | \openout1 = `main.aux'. 306 | 307 | LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 16. 308 | LaTeX Font Info: ... okay on input line 16. 309 | LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 16. 310 | LaTeX Font Info: ... okay on input line 16. 311 | LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 16. 312 | LaTeX Font Info: ... okay on input line 16. 313 | LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 16. 314 | LaTeX Font Info: ... okay on input line 16. 315 | LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 16. 316 | LaTeX Font Info: ... okay on input line 16. 317 | LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 16. 318 | LaTeX Font Info: ... okay on input line 16. 319 | (/usr/local/texlive/2017/texmf-dist/tex/context/base/mkii/supp-pdf.mkii 320 | [Loading MPS to PDF converter (version 2006.09.02).] 321 | \scratchcounter=\count116 322 | \scratchdimen=\dimen162 323 | \scratchbox=\box38 324 | \nofMPsegments=\count117 325 | \nofMParguments=\count118 326 | \everyMPshowfont=\toks31 327 | \MPscratchCnt=\count119 328 | \MPscratchDim=\dimen163 329 | \MPnumerator=\count120 330 | \makeMPintoPDFobject=\count121 331 | \everyMPtoPDFconversion=\toks32 332 | ) (/usr/local/texlive/2017/texmf-dist/tex/generic/oberdiek/pdftexcmds.sty 333 | Package: pdftexcmds 2017/03/19 v0.25 Utility functions of pdfTeX for LuaTeX (HO) 334 | (/usr/local/texlive/2017/texmf-dist/tex/generic/oberdiek/ifluatex.sty 335 | Package: ifluatex 2016/05/16 v1.4 Provides the ifluatex switch (HO) 336 | Package ifluatex Info: LuaTeX not detected. 337 | ) 338 | Package pdftexcmds Info: LuaTeX not detected. 339 | Package pdftexcmds Info: \pdf@primitive is available. 340 | Package pdftexcmds Info: \pdf@ifprimitive is available. 341 | Package pdftexcmds Info: \pdfdraftmode found. 342 | ) (/usr/local/texlive/2017/texmf-dist/tex/latex/oberdiek/epstopdf-base.sty 343 | Package: epstopdf-base 2016/05/15 v2.6 Base part for package epstopdf 344 | (/usr/local/texlive/2017/texmf-dist/tex/latex/oberdiek/grfext.sty 345 | Package: grfext 2016/05/16 v1.2 Manage graphics extensions (HO) 346 | (/usr/local/texlive/2017/texmf-dist/tex/generic/oberdiek/kvdefinekeys.sty 347 | Package: kvdefinekeys 2016/05/16 v1.4 Define keys (HO) 348 | )) (/usr/local/texlive/2017/texmf-dist/tex/latex/oberdiek/kvoptions.sty 349 | Package: kvoptions 2016/05/16 v3.12 Key value format for package options (HO) 350 | (/usr/local/texlive/2017/texmf-dist/tex/generic/oberdiek/kvsetkeys.sty 351 | Package: kvsetkeys 2016/05/16 v1.17 Key value parser (HO) 352 | (/usr/local/texlive/2017/texmf-dist/tex/generic/oberdiek/etexcmds.sty 353 | Package: etexcmds 2016/05/16 v1.6 Avoid name clashes with e-TeX commands (HO) 354 | Package etexcmds Info: Could not find \expanded. 355 | (etexcmds) That can mean that you are not using pdfTeX 1.50 or 356 | (etexcmds) that some package has redefined \expanded. 357 | (etexcmds) In the latter case, load this package earlier. 358 | ))) 359 | Package epstopdf-base Info: Redefining graphics rule for `.eps' on input line 438. 360 | Package grfext Info: Graphics extension search list: 361 | (grfext) [.png,.pdf,.jpg,.mps,.jpeg,.jbig2,.jb2,.PNG,.PDF,.JPG,.JPEG,.JBIG2,.JB2,.eps] 362 | (grfext) \AppendGraphicsExtensions on input line 456. 363 | (/usr/local/texlive/2017/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg 364 | File: epstopdf-sys.cfg 2010/07/13 v1.3 Configuration of (r)epstopdf for TeX Live 365 | )) ABD: EveryShipout initializing macros 366 | *geometry* driver: auto-detecting 367 | *geometry* detected driver: pdftex 368 | *geometry* verbose mode - [ preamble ] result: 369 | * driver: pdftex 370 | * paper: a4paper 371 | * layout: 372 | * layoutoffset:(h,v)=(0.0pt,0.0pt) 373 | * modes: 374 | * h-part:(L,W,R)=(72.26999pt, 452.9679pt, 72.26999pt) 375 | * v-part:(T,H,B)=(72.26999pt, 700.50687pt, 72.26999pt) 376 | * \paperwidth=597.50787pt 377 | * \paperheight=845.04684pt 378 | * \textwidth=452.9679pt 379 | * \textheight=700.50687pt 380 | * \oddsidemargin=0.0pt 381 | * \evensidemargin=0.0pt 382 | * \topmargin=-37.0pt 383 | * \headheight=12.0pt 384 | * \headsep=25.0pt 385 | * \topskip=10.0pt 386 | * \footskip=30.0pt 387 | * \marginparwidth=65.0pt 388 | * \marginparsep=11.0pt 389 | * \columnsep=10.0pt 390 | * \skip\footins=9.0pt plus 4.0pt minus 2.0pt 391 | * \hoffset=0.0pt 392 | * \voffset=0.0pt 393 | * \mag=1000 394 | * \@twocolumnfalse 395 | * \@twosidefalse 396 | * \@mparswitchfalse 397 | * \@reversemarginfalse 398 | * (1in=72.27pt=25.4mm, 1cm=28.453pt) 399 | 400 | LaTeX Font Info: External font `cmex10' loaded for size 401 | (Font) <17.28> on input line 20. 402 | LaTeX Font Info: External font `cmex10' loaded for size 403 | (Font) <12> on input line 20. 404 | LaTeX Font Info: External font `cmex10' loaded for size 405 | (Font) <8> on input line 20. 406 | LaTeX Font Info: External font `cmex10' loaded for size 407 | (Font) <6> on input line 20. 408 | LaTeX Font Info: Try loading font information for OMS+cmtt on input line 20. 409 | LaTeX Font Info: No file OMScmtt.fd. on input line 20. 410 | 411 | LaTeX Font Warning: Font shape `OMS/cmtt/m/n' undefined 412 | (Font) using `OMS/cmsy/m/n' instead 413 | (Font) for symbol `textbraceleft' on input line 20. 414 | 415 | LaTeX Font Info: External font `cmex10' loaded for size 416 | (Font) <7> on input line 24. 417 | LaTeX Font Info: External font `cmex10' loaded for size 418 | (Font) <5> on input line 24. 419 | [1 420 | 421 | {/usr/local/texlive/2017/texmf-var/fonts/map/pdftex/updmap/pdftex.map}] 422 | File: images/example-1.pdf Graphic file (type pdf) 423 | 424 | Package pdftex.def Info: images/example-1.pdf used on input line 55. 425 | (pdftex.def) Requested size: 408.02338pt x 65.24358pt. 426 | 427 | File: images/example-2.pdf Graphic file (type pdf) 428 | 429 | Package pdftex.def Info: images/example-2.pdf used on input line 57. 430 | (pdftex.def) Requested size: 283.05681pt x 101.3785pt. 431 | [2 <./images/example-1.pdf> <./images/example-2.pdf>] 432 | LaTeX Font Info: External font `cmex10' loaded for size 433 | (Font) <9> on input line 77. 434 | 435 | Overfull \hbox (11.99641pt too wide) in paragraph at lines 105--106 436 | []\OT1/cmr/m/it/10 Control-flow trig-gers \OT1/cmr/m/n/10 which trig-ger when a func-tion is called or re-turns a value: (a) \OT1/cmtt/m/n/10 before(function)\OT1/cmr/m/n/10 , 437 | [] 438 | 439 | 440 | Overfull \hbox (12.6936pt too wide) in paragraph at lines 105--106 441 | \OT1/cmr/m/n/10 trig-gers when-ever \OT1/cmtt/m/n/10 function \OT1/cmr/m/n/10 is called and be-fore any of its code is ex-e-cuted[]; and (b) \OT1/cmtt/m/n/10 after(function)\OT1/cmr/m/n/10 , 442 | [] 443 | 444 | 445 | Overfull \hbox (12.52226pt too wide) in paragraph at lines 105--106 446 | \OT1/cmr/m/n/10 to read the value of the pa-ram-e-ters, they can be spec-i-fied in the event e.g. \OT1/cmtt/m/n/10 before(payAmount(value)) 447 | [] 448 | 449 | [3] 450 | LaTeX Font Info: Try loading font information for OMS+cmr on input line 164. 451 | (/usr/local/texlive/2017/texmf-dist/tex/latex/base/omscmr.fd 452 | File: omscmr.fd 2014/09/29 v2.5h Standard LaTeX font definitions 453 | ) 454 | LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10> not available 455 | (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 164. 456 | [4] [5] [6] [7] (/Users/gordon/Dropbox/Data/Desktop/contractLarva-github/docs/.texpadtmp/main.aux) 457 | 458 | LaTeX Font Warning: Some font shapes were not available, defaults substituted. 459 | 460 | ) 461 | Here is how much of TeX's memory you used: 462 | 12855 strings out of 492995 463 | 258662 string characters out of 6132703 464 | 304993 words of memory out of 5000000 465 | 16142 multiletter control sequences out of 15000+600000 466 | 12183 words of font info for 46 fonts, out of 8000000 for 9000 467 | 1141 hyphenation exceptions out of 8191 468 | 62i,8n,65p,1398b,282s stack positions out of 5000i,500n,10000p,200000b,80000s 469 | 470 | Output written on /Users/gordon/Dropbox/Data/Desktop/contractLarva-github/docs/.texpadtmp/main.pdf (7 pages, 348946 bytes). 471 | PDF statistics: 472 | 123 PDF objects out of 1000 (max. 8388607) 473 | 90 compressed objects within 1 object stream 474 | 0 named destinations out of 1000 (max. 500000) 475 | 23 words of extra memory for PDF output out of 10000 (max. 10000000) 476 | 477 | -------------------------------------------------------------------------------- /docs/.texpadtmp/main.synctex.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gordonpace/contractLarva/5a2febd1c9ba4763b30def3a96bb07f2fef8a9dc/docs/.texpadtmp/main.synctex.gz -------------------------------------------------------------------------------- /docs/images/example-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gordonpace/contractLarva/5a2febd1c9ba4763b30def3a96bb07f2fef8a9dc/docs/images/example-1.pdf -------------------------------------------------------------------------------- /docs/images/example-1.xml: -------------------------------------------------------------------------------- 1 | 5Vrfc6M2EP5b+uCZ68N5EEKAH+0kvT60nZvm5np9ulGwjNViRIX86/76SpYwCDDxxUriNnkgaJF2l93v065sj+DNaveB42L5K5uTbOR7890I3o58P5p48qoEey0IJrEWpJzOtQjUgnv6jRihWZeu6ZyU1kTBWCZoYQsTluckEZYMc8629rQFy2yrBU5JR3Cf4Kwr/YPOxVJLY+TV8p8JTZeVZeCZJw84+TvlbJ0beyMfLg5/+vEKV7qMhXKJ52yrRQcV8G4EbzhjQt+tdjckU6Gtwqbt/HTi6dFvTnJxzgJfL9jgbE0qjw9+iX0VC7lAhl0OZtslFeS+wIl6spWJl7KlWGVyBOQtLgudiwXdEal/1nXG+LchXJBdQ2Sc+0DYigi+l1MMcGCkV2wbWTChXjYSUMmwyXt6VFS/u7wxr98fCnRGKPL5VKFLjpIMlyVN7AjI9+T7L3LgjVE1/FMNh4IhME+JsNJB5hY8u9FphAP1hKOScZJhQTc2qPtiZCx8ZFQ653smNdCoMbkAka2gZGueELOmibGWGmCraWnRr9/RIuOM941phZpQnvY16PW1Tr3WVwPhGMyzsBFdK03M0/brvyBtYge02VHxpXFfUaamU5tMf61Xxb0xkLOcVCJdSEAsx8mab1R4D1pPhlhj2CJfk4/RVfFx0sJ4m0pnE7KFluh5KAlALyhPedXeJ6BbClfaXQDVawDV2vdBE6jguYAaXXvh8BEch2DiBZG+BrGV2Uk8niAfxp65hk+DceSNZUsWgcBc/e8x4grjYYuT0Oq3LkdtVQqaqA0zma7Zgh0cWWADi/CfteoaZzcyfJRw+eg3sq3F8i5V//FCEP6OFST/hB8y8mOlTnqiNeppHW7ISiRsNnBS0m9Kh2GEiZWcjWYjdKtsrQUrDdTVMKNpLu8zslCqVHmjsueeGrFgqlKWsnDSPP2kBrfvAzf1sb0VAdSpj1XmLD74DgokOKfHvt4KeSVbCgTAZruVT+SPm1xH/tN2lGASWPsW+h4jjnYUiKBlNQDDLg9Ov3z/CR4HrzzDFuq2XK/ujk1wQTiVduQ+BG9Na/yxFj3WIzugfARtiLxgSwxcHCXfPOMRiocYD5wwPgrAEOOHjThifOjZxSnwhl0enH4548MzwPuaZ90gjmxixy9HbIeH3Vc4Q1wJsYerLPDQGDb+/CeeDoYbhsesOPtUyq7Oro8HFf6cAHI88VGz2oxjEJhxo3QPVCHwpNNsteE0j7NV23EliA399vGhtZmcC8owainyWopclRTUsuM7xl1fW+jgWJpkrCT/rXNpp3D1AP70udRrbX6gW8yOn9a5Ppj2fuPhIIlFJpfNiDiZQS2WAc2tVFba1OT3C7yimYzKdKReNcSr4rAUQhX55OhGfnDDftr1qwkmbfb/CCbY/g6k50MO/7mw1Nc1OsCSDD/LNgpNb2NDgPA1N4S+r7kuSuIDWTBO3ty2juLHmdjXrjhJYt8Z5cIkilHgvftl+vvn6deCkw1l6/KrkvreDwdF3sNb4Sc6g5++I37KYf1DEN2k1T+2gXf/Ag== -------------------------------------------------------------------------------- /docs/images/example-2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gordonpace/contractLarva/5a2febd1c9ba4763b30def3a96bb07f2fef8a9dc/docs/images/example-2.pdf -------------------------------------------------------------------------------- /docs/images/example-2.xml: -------------------------------------------------------------------------------- 1 | 5VpLb+M2EP41BraHFSRSz+M6SXcvLRbIAt0eGZmW1cqiStGvPfS3l4xIi6Tkx8Z06iBGIJMjcmY0882Diifwbrn9TFGz+I3McDUB/mw7gfcTAJLM51dB2HWEMEs7QkHLWUcKesJj+QNLotxXrMoZbo2FjJCKlY1JzEld45wZNEQp2ZjL5qQypTaowAPCY46qIfWPcsYWHTWN/J7+BZfFQkkOfHnnCeV/F5SsailvAuD8+dPdXiLFS0poF2hGNh3pmQV8mMA7SgjrRsvtHa6EaZXZOjm/Hri715vimp2zAXQb1qhaYaXxs15sp2zBN3Cz88l0sygZfmxQLu5suOM5bcGWFZ8FfIjapvPFvNxizn86VEbqt8aU4a1Gksp9xmSJGd3xJVsTEDtlaKnfRvOKXLLQHKJoSOKg2DPubcEH0hzjponOME09+yTQxmd5hdq2zE2L8Oemu+984nuRmv4ppseMwxAtMDPcg2cGXIfW0swRjZhD0SiuECvXJsjHbCQlfCUlV27vjNB0RgZMBi1Z0RzLPTrmLDbAZJNabLrnH7DhhkY7bVkjFrSHlY1Gle193/HrkbC35lngSG48buzHf83ASR0EzrZk37WxCpo+oOxw+mu1bB6lgJrUWJG60hKkfJ6v6FrY95nrQRt3KDbCT4/I5KYicl93diq0XhiTgY2X6DpRGYBxXB7MFcfXXxzHqr64AKuvgdXI/oEO1uBaYE1uvXyAGHpxkPlh0l0j07MJ9LIIwNSX1/hlSE59jzdqSRDKK/gpKa5gnthxabRhl8NWFQQdtnHF/TWdk2dF5kjiIv5nJZrJ6R23X4kpv/U73vRkPirEN5ozTD+QBtff0FOFf1HsuCYdx27ZIDh4PWJmOFDclj8EDxkS0lZ8dTSdRPdC1oqRVmJdTKuyqPm4wnPBShS5krfinySZEVEvW14+y7r4Jib3H0NH3aXVXqbJoEgGcCQggIMqqQqyk8zjgTDWS6Xnp+elGbHjK6YlV59jwy6yXhKHRqHlfGNFsLc5yVi3VV5BYiUTM5cA6OmpxC6Z52asMDqaF09IcZSxgJWxsuh4Xc7M5cnx5VAlrFHul6fD8HQs8ZN2I4btavmw78wbDcOyX9dgfapxd5CBwgyO9jev0ae7bNTfUAa6ldwSZ16fWNIossI+jT0tJ8RB9LLkwiPP06QkwUBKrH/gqyQX1Xafm10APL7eTi8W/4vzC4TuIuV/ONLeCOIhOFVNdbxnFhTPBXzkn6qmx6Q4AjyMrYc7ccwNj6+/HMBnFMgbPua+DQDzk6evny2TqwD4hBRHAA7B0Yx9OSDHXqA6OMDmFWmxOsH6k4Qr4ueCjcDtGznSDrrHkZg42FDG1vuyLJsMjrTZlY60cKyhdOBUbn5SrfEUM92pQuMYLYUlpR/FSxb/3wFV+D//2CWYd4CAIB5vnnQI7Bsy1xAIr/Riqqn4NgmAMQ+Dqfh7Jx4GvlkToqGDg7FDoxMHA9cOfsJzQvGBIH9HmRva/xcdvoxUr5Hde3XsgOPCq+P12Ijf9+ndaxZmPu1/QdI1Z/2vdODDfw== -------------------------------------------------------------------------------- /docs/main.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gordonpace/contractLarva/5a2febd1c9ba4763b30def3a96bb07f2fef8a9dc/docs/main.pdf -------------------------------------------------------------------------------- /src/DEA.hs: -------------------------------------------------------------------------------- 1 | -- Copyright 2017 Gordon J. Pace and Joshua Ellul 2 | -- 3 | -- Licensed under the Apache License, Version 2.0 (the "License"); 4 | -- you may not use this file except in compliance with the License. 5 | -- You may obtain a copy of the License at 6 | -- 7 | -- http://www.apache.org/licenses/LICENSE-2.0 8 | -- 9 | -- Unless required by applicable law or agreed to in writing, software 10 | -- distributed under the License is distributed on an "AS IS" BASIS, 11 | -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | -- See the License for the specific language governing permissions and 13 | -- limitations under the License. 14 | 15 | module DEA (module DEA.DEA, module DEA.Parsing, module DEA.Instrumentation) where 16 | 17 | import DEA.DEA 18 | import DEA.Parsing 19 | import DEA.Instrumentation 20 | -------------------------------------------------------------------------------- /src/DEA/DEA.hs: -------------------------------------------------------------------------------- 1 | -- Copyright 2017 Gordon J. Pace and Joshua Ellul 2 | -- 3 | -- Licensed under the Apache License, Version 2.0 (the "License"); 4 | -- you may not use this file except in compliance with the License. 5 | -- You may obtain a copy of the License at 6 | -- 7 | -- http://www.apache.org/licenses/LICENSE-2.0 8 | -- 9 | -- Unless required by applicable law or agreed to in writing, software 10 | -- distributed under the License is distributed on an "AS IS" BASIS, 11 | -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | -- See the License for the specific language governing permissions and 13 | -- limitations under the License. 14 | 15 | module DEA.DEA ( 16 | Event (..), FunctionCall (..), isControlFlowEvent, isDataFlowEvent, 17 | getFunctionNameFromEvent, getVariableNameFromEvent, 18 | GCL (..), State (..), Transition (..), 19 | DEA (..), getEventsFromDEA, getFunctionsFromDEA, initialState, 20 | 21 | getVariablesFromDEA, getVariablesFromContractSpecification, 22 | 23 | functionCallEventHasParameters, getFunctionParametersFromEvent, 24 | problemsSpecification, problemsContractSpecification, problemsDEA, 25 | warningsSpecificationCode, 26 | ContractSpecification (..), Specification (..), 27 | module Solidity 28 | ) where 29 | 30 | import Data.List 31 | import Data.Maybe 32 | 33 | import Solidity 34 | 35 | data Event 36 | = UponEntry FunctionCall 37 | | UponExit FunctionCall 38 | | BeforeTransfer 39 | | AfterTransfer 40 | | BeforeSelfDestruct 41 | | AfterSelfDestruct 42 | | VariableAssignment VariableName (Maybe Expression) 43 | deriving (Eq, Ord, Show) 44 | 45 | data FunctionCall = 46 | FunctionCall { 47 | functionName :: FunctionName, 48 | parametersPassed :: Maybe UntypedParameterList 49 | } deriving (Eq, Ord, Show) 50 | 51 | isControlFlowEvent :: Event -> Bool 52 | isControlFlowEvent (VariableAssignment _ _) = False 53 | isControlFlowEvent _ = True 54 | 55 | isDataFlowEvent :: Event -> Bool 56 | isDataFlowEvent = not . isControlFlowEvent 57 | 58 | getFunctionNameFromEvent :: Event -> FunctionName 59 | getFunctionNameFromEvent (UponEntry fc) = functionName fc 60 | getFunctionNameFromEvent (UponExit fc) = functionName fc 61 | 62 | functionCallEventHasParameters :: Event -> Bool 63 | functionCallEventHasParameters (UponEntry fc) = isJust (parametersPassed fc) 64 | functionCallEventHasParameters (UponExit fc) = isJust (parametersPassed fc) 65 | 66 | getFunctionParametersFromEvent :: Event -> UntypedParameterList 67 | getFunctionParametersFromEvent (UponEntry fc) = fromJust (parametersPassed fc) 68 | getFunctionParametersFromEvent (UponExit fc) = fromJust (parametersPassed fc) 69 | 70 | getVariableNameFromEvent :: Event -> VariableName 71 | getVariableNameFromEvent (VariableAssignment v _) = v 72 | 73 | data GCL = GCL { 74 | event :: Event, 75 | guard :: Maybe Expression, 76 | action :: Maybe Statement 77 | } deriving (Eq, Ord, Show) 78 | 79 | newtype State = State { unState :: String } deriving (Eq, Ord, Show) 80 | 81 | data Transition = 82 | Transition { 83 | src, dst :: State, 84 | label :: GCL 85 | } deriving (Eq, Ord, Show) 86 | 87 | data DEA = DEA { 88 | deaName :: String, 89 | allStates :: [State], 90 | initialStates :: [State], 91 | transitions :: [Transition], 92 | badStates :: [State], 93 | acceptanceStates :: [State] 94 | } deriving (Eq, Ord, Show) 95 | 96 | data ContractSpecification = ContractSpecification { 97 | contractName :: ContractName, 98 | declarations :: [ContractPart], 99 | initialisation :: Block, 100 | satisfaction :: Block, 101 | reparation :: Block, 102 | deas :: [DEA] 103 | } deriving (Eq, Ord, Show) 104 | 105 | newtype Specification = Specification { contractSpecifications :: [ContractSpecification] } deriving (Eq, Ord, Show) 106 | 107 | initialState :: DEA -> State 108 | initialState = head . initialStates 109 | 110 | getEventsFromDEA :: DEA -> [Event] 111 | getEventsFromDEA = nub . map (event . label) . transitions 112 | 113 | getFunctionsFromDEA :: DEA -> [FunctionName] 114 | getFunctionsFromDEA = nub . map getFunctionNameFromEvent . filter isControlFlowEvent . map (event . label) . transitions 115 | 116 | getVariablesFromDEA :: DEA -> [VariableName] 117 | getVariablesFromDEA = nub . map getVariableNameFromEvent . filter isDataFlowEvent . map (event . label) . transitions 118 | 119 | getVariablesFromContractSpecification :: ContractSpecification -> [VariableName] 120 | getVariablesFromContractSpecification = 121 | nub . map getVariableNameFromEvent . filter isDataFlowEvent . map (event . label) . concat . map transitions . deas 122 | 123 | 124 | problemsSpecification :: Specification -> [String] 125 | problemsSpecification spec = 126 | [ "Error: Multiple specifications for contract <"++display c++">" | c <- nub cnames, length (filter (c==) cnames) > 1 ] ++ 127 | concat (map problemsContractSpecification cspecs) 128 | where 129 | cspecs = contractSpecifications spec 130 | cnames = map contractName cspecs 131 | 132 | problemsContractSpecification :: ContractSpecification -> [String] 133 | problemsContractSpecification cspec 134 | | null problems = [] 135 | | otherwise = ("Errors in definition of specification of contract <"++display (contractName cspec)++">"):problems 136 | where 137 | problems = 138 | [ " Multiple DEAs named <"++d++">" 139 | | d <- nub dnames, length (filter (d==) dnames) > 1 140 | ] ++ 141 | concat 142 | [ (" In definition of DEA <"++deaName dea++">"):map (" - "++) ps 143 | | dea <- deas cspec 144 | , let ps = problemsDEA dea 145 | , not (null ps) 146 | ] 147 | where 148 | dnames = map deaName (deas cspec) 149 | 150 | problemsDEA :: DEA -> [String] 151 | problemsDEA dea = 152 | [ "DEA has no initial state" | length (initialStates dea) == 0 ] ++ 153 | [ "DEA has more than one initial state" | length (initialStates dea) > 1 ] ++ 154 | [ "State <"++unState s++"> defined multiple times" 155 | | s <- nub (allStates dea), length (filter (s==) (allStates dea)) > 1 156 | ] ++ 157 | [ "State <"++unState s++"> used in a transition but not declared" 158 | | s <- tstates, s `notElem` allStates dea 159 | ] 160 | where 161 | tstates = nub $ concat [ [src transition, dst transition] | transition <- transitions dea ] 162 | 163 | warningsSpecificationCode :: Specification -> SolidityCode -> [String] 164 | warningsSpecificationCode spec code = let warnings = [s | sp <- contractSpecifications spec, s <- warningsContractSpecificationCode sp code] 165 | in if warnings /= [] 166 | then ["Warnings:"] ++ warnings 167 | else warnings 168 | 169 | warningsContractSpecificationCode :: ContractSpecification -> SolidityCode -> [String] 170 | warningsContractSpecificationCode spec code = [s | dea <- deas spec, s <- warningsDEACode dea code] 171 | 172 | warningsDEACode :: DEA -> SolidityCode -> [String] 173 | warningsDEACode dea (SolidityCode (SourceUnit units)) = 174 | [ "Variable <"++unIdentifier vn++"> passed to internal functions and/or modifiers <" ++ (intercalate "," (functionsPassedTo vn)) ++">, and thus not all modifications to it may be caught" 175 | | vn <- mappingArrayOrStructVariableAssignments, [] /= functionsPassedTo vn] ++ 176 | [ "Variable <"++unIdentifier vn++"> has a range that is a struct, mapping, or array" 177 | | vn <- mappingArrayOrStructVariableAssignments, hasMappingArrayOrStructAsRange vn] 178 | where 179 | mappingArrayOrStructVariableAssignments = removeDuplicates [vn | t <- transitions dea, VariableAssignment vn _ <- [event $ label t], isMappingArrayOrStruct vn] 180 | removeDuplicates [] = [] 181 | removeDuplicates (x:xs) = if x `elem` xs 182 | then removeDuplicates xs 183 | else (x:removeDuplicates xs) 184 | getVariableTypesInContract vn = 185 | [ typename vd | (SourceUnit1_ContractDefinition c) <- units, ContractPartStateVariableDeclaration vd <- contractParts c, variableName vd == vn ] 186 | isMappingArrayOrStruct vn = [] /= ([vn | TypeNameMapping _ _ <- getVariableTypesInContract vn] 187 | ++ [vn | TypeNameArrayTypeName _ _ <- getVariableTypesInContract vn] 188 | ++ [vn | TypeNameUserDefinedTypeName _ <- getVariableTypesInContract vn]) 189 | hasMappingArrayOrStructAsRange vn = [] /= [vn | TypeNameMapping _ (TypeNameMapping _ _) <- getVariableTypesInContract vn] 190 | functionsPassedTo vn = (removeItems ["require", "assert", "payable", "address"] $ variablePassedToFunction vn (SolidityCode (SourceUnit units))) 191 | removeItems _ [] = [] 192 | removeItems xs (y:ys) = if y `elem` xs 193 | then removeItems xs ys 194 | else (y: (removeItems xs ys)) -------------------------------------------------------------------------------- /src/DEA/Instrumentation.hs: -------------------------------------------------------------------------------- 1 | -- Copyright 2017 Gordon J. Pace and Joshua Ellul 2 | -- 3 | -- Licensed under the Apache License, Version 2.0 (the "License"); 4 | -- you may not use this file except in compliance with the License. 5 | -- You may obtain a copy of the License at 6 | -- 7 | -- http://www.apache.org/licenses/LICENSE-2.0 8 | -- 9 | -- Unless required by applicable law or agreed to in writing, software 10 | -- distributed under the License is distributed on an "AS IS" BASIS, 11 | -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | -- See the License for the specific language governing permissions and 13 | -- limitations under the License. 14 | 15 | module DEA.Instrumentation (instrumentSpecification, warningsSpecification) where 16 | 17 | 18 | import Control.Monad hiding (guard) 19 | import Text.Parsec hiding (State, label) 20 | import Text.Parsec.String 21 | 22 | import Data.List 23 | import Data.Maybe 24 | import Data.Either 25 | 26 | import DEA.DEA 27 | import DEA.Parsing 28 | import Solidity 29 | 30 | import Debug.Trace 31 | 32 | instrumentContractSpecification :: ContractSpecification -> Bool -> Instrumentation 33 | instrumentContractSpecification monitor notInlined = 34 | -- (i) Rename contract to LARVA_contract 35 | renameContract (contract, contract') |> 36 | --rename old-style constructor to new contract name 37 | renameFunctionInContract contract' (contract, contract') |> 38 | 39 | -- (ii) Add LARVA_Status handlers 40 | 41 | -- Add the modifier to check that the contract is enabled to all functions (except to any old style constructors) 42 | addTopModifierToAllButTheseFunctionInContract 43 | contract' [contract'] (Identifier "LARVA_ContractIsEnabled", ExpressionList []) |> 44 | 45 | addContractParts contract' ( 46 | map parser' 47 | [ 48 | -- Enumerated type to keep track whether contract is enabled or not. 49 | "enum LARVA_STATUS { RUNNING, STOPPED }" 50 | -- Functionality to enable and disable the original contract 51 | , "function LARVA_EnableContract() private { LARVA_Status = LARVA_STATUS.RUNNING; }" 52 | , "function LARVA_DisableContract() private { LARVA_Status = LARVA_STATUS.STOPPED; }" 53 | -- LARVA_status keeps track of the current status of the contract 54 | ,"LARVA_STATUS private LARVA_Status = LARVA_STATUS.STOPPED;" 55 | -- Modifier to ensure that the contract has been enabled 56 | , "modifier LARVA_ContractIsEnabled { require(LARVA_Status == LARVA_STATUS.RUNNING); _; }" ]) |> 57 | 58 | --(iii)-Add constructor if constructor not defined and inlining intended 59 | (\x -> if not inliningFlag 60 | then x 61 | else if constructorIsDefinedInContract contract' x 62 | then x 63 | else if useNewStyleConstructor x 64 | then addContractParts contract' 65 | [ ContractPartConstructorDefinition 66 | (ParameterList []) 67 | [FunctionDefinitionTagPublic] 68 | (Just $ Block []) 69 | ] x 70 | else addContractParts contract' 71 | [ ContractPartFunctionDefinition 72 | (Just contract') (ParameterList []) 73 | [FunctionDefinitionTagPublic] 74 | Nothing 75 | (Just $ Block []) 76 | ] x) 77 | |> 78 | 79 | -- (iv) Add reparation and satisfaction functions if they are not empty and there are respectively bad and acceptance states, 80 | -- and the declaration code of monitored contract 81 | addContractParts contract' ( 82 | [ContractPartFunctionDefinition 83 | (Just $ Identifier "LARVA_reparation") (ParameterList []) 84 | [FunctionDefinitionTagPrivate] 85 | Nothing 86 | (Just $ reparation monitor) 87 | | reparation monitor /= Block [] && [s | dea <- deas monitor, s <- badStates dea] /= []] 88 | ++ [ContractPartFunctionDefinition 89 | (Just $ Identifier "LARVA_satisfaction") (ParameterList []) 90 | [FunctionDefinitionTagPrivate] 91 | Nothing 92 | (Just $ satisfaction monitor) 93 | | satisfaction monitor /= Block [] && [s | dea <- deas monitor, s <- acceptanceStates dea] /= []] 94 | ++ declarations monitor 95 | ) |> 96 | 97 | -- (v.0) Add setters for transfer and selfdestruct 98 | defineAndUseSetterFunctionForTransferInContract contract' |> 99 | defineAndUseSetterFunctionForSelfDestructInContract contract' |> 100 | 101 | -- (v) Add setters for relevant variables 102 | foldl (.) id 103 | [ defineAndUseSetterFunctionForVariableInContract contract' v 104 | (Identifier ("LARVA_set_"++vn++"_pre"), Identifier ("LARVA_set_"++vn++"_post")) 105 | | v <- getVariablesFromContractSpecification monitor 106 | , let vn = display v 107 | ] |> 108 | 109 | 110 | -- Start instrumenting the DEAs 111 | -- (vi) Add variables to store state of each DEA: LARVA_STATE_n, all initialised to 0. 112 | addContractParts contract' 113 | [ parser' ("int8 "++larva_state_variable n++" = 0;") | n <- [1..deaCount] ] |> 114 | 115 | -- (vii) Create modifiers to catch events and change state + attach modifiers to relevant functions 116 | foldl (|>) id [ instrumentForDEA contract' (n,d) | (n,d) <- zip [1..] ds ] 117 | |> 118 | 119 | -- (viii) Inline or not the contract initialisation code 120 | if not inliningFlag && not (initialisation monitor == (Block [])) 121 | then addContractParts contract' 122 | (map parser' [ 123 | -- Non-inlined monitor initilisation function 124 | "function LARVA_Constructor() public {" ++ display (initialisation monitor) ++ " }"]) 125 | else (addContractParts contract' 126 | (map parser' [ 127 | -- Inlined monitor initilisation function as modifier 128 | "modifier LARVA_Constructor {" ++ "_; " ++ display (initialisation monitor) ++ " }"]) 129 | |> 130 | addTopModifierToContractConstructor contract' (Identifier "LARVA_Constructor", ExpressionList [])) 131 | 132 | where 133 | inliningFlag = not notInlined 134 | contract = contractName monitor 135 | contract' = Identifier $ "LARVA_" ++ display contract 136 | 137 | ds = deas monitor 138 | deaCount = length ds 139 | 140 | larva_state_variable n = "LARVA_STATE_"++show n 141 | 142 | parser' = fromRight undefined . parse parser "" 143 | 144 | f |> g = g . f 145 | 146 | instrumentForDEA :: ContractName -> (Int, DEA) -> Instrumentation 147 | instrumentForDEA contractName (deaNumber, dea) code = 148 | foldl (|>) id ( 149 | map (instrumentForEvent . 150 | (\ ets -> (fst $ head ets, map snd ets))) 151 | (groupBy (\ (e, _) (e', _) -> sameEvent e e') $ 152 | sortOn fst [(event $ label t, t) | t <- transitions dea]) 153 | ) code 154 | where 155 | -- distributeNameMatch :: [[(Event, Transition)]] -> [[(Event, Transition)]] 156 | -- distributeNameMatch [e,ts]:ets = 157 | -- distributeNameMatchForEvent :: Event -> [[(Event, Transition)]] -> [[(Event, Transition)]] 158 | -- distributeNameMatchForEvent (UponEntry f) ets = if parametersPassed f = Nothing 159 | -- then ets 160 | -- else 161 | 162 | -- pushNothingToBack ((UponEntry f, t):es) = if parametersPassed f == Nothing 163 | -- then (pushNothingToBack es) ++ [(UponEntry f, t)] 164 | -- else ((UponEntry f, t):es) 165 | -- pushNothingToBack ((UponExit f,t):es) = if parametersPassed f == Nothing 166 | -- then (pushNothingToBack es) ++ [(UponExit f, t)] 167 | -- else ((UponExit f, t):es) 168 | -- pushNothingToBack [] = [] 169 | 170 | sameEvent (UponEntry f) (UponEntry f') = f==f' 171 | sameEvent (UponExit f) (UponExit f') = f==f' 172 | sameEvent (BeforeTransfer) (BeforeTransfer) = True 173 | sameEvent (AfterTransfer) (AfterTransfer) = True 174 | sameEvent (BeforeSelfDestruct) (BeforeSelfDestruct) = True 175 | sameEvent (AfterSelfDestruct) (AfterSelfDestruct) = True 176 | sameEvent (VariableAssignment v _) (VariableAssignment v' _) = v==v' 177 | sameEvent _ _ = False 178 | 179 | modifierCode :: SolidityCode -> ContractName -> String -> Maybe ParameterList -> Bool -> [Transition] -> String 180 | modifierCode code contract modifierName mps before ts = 181 | unlines $ 182 | [ "modifier "++modifierName++maybe "" display mps++" {"] ++ 183 | (if before then [] else ["_;"]) ++ 184 | [ "if (("++larva_state_variable deaNumber++" == "++stateNumber (src t)++")"++ 185 | maybe "" (\cond -> " && ("++display cond++")") (guard gcl) ++ 186 | maybe "" (\cond -> " && ("++display cond++")") condition ++ 187 | ") { "++larva_state_variable deaNumber++" = "++stateNumber (dst t)++";"++ 188 | display (action gcl)++reparationCode++satisfactionCode++"} else {" 189 | | t <- ts, let gcl = label t 190 | , let condition = variableAssignmentExpression gcl 191 | , let reparationCode = if dst t `elem` badStates dea && functionIsDefinedInContract contract (Identifier "LARVA_reparation") code then " LARVA_reparation(); " else "" 192 | , let satisfactionCode = if dst t `elem` acceptanceStates dea && functionIsDefinedInContract contract (Identifier "LARVA_satisfaction") code then " LARVA_satisfaction(); " else "" 193 | ] ++ 194 | [ " "++ replicate (length ts) '}' ] ++ 195 | ["_;" | before] ++ 196 | [ "}" ] 197 | where 198 | variableAssignmentExpression gcl = 199 | case event gcl of 200 | VariableAssignment _ e -> e 201 | _ -> Nothing 202 | 203 | nameModifier :: Event -> String 204 | nameModifier (UponEntry fc) = 205 | "LARVA_DEA_"++show deaNumber++"_handle_before_"++display (functionName fc)++ 206 | maybe "__no_parameters" (\ps -> "__parameters_"++intercalate "_" (map display $ fromUntypedParameterList ps)) (parametersPassed fc) 207 | nameModifier (UponExit fc) = 208 | "LARVA_DEA_"++show deaNumber++"_handle_after_"++display (functionName fc)++ 209 | maybe "__no_parameters" (\ps -> "__parameters_"++intercalate "_" (map display $ fromUntypedParameterList ps)) (parametersPassed fc) 210 | nameModifier (BeforeTransfer) = 211 | "LARVA_DEA_"++show deaNumber++"_handle_before_transfer" 212 | nameModifier (AfterTransfer) = 213 | "LARVA_DEA_"++show deaNumber++"_handle_after_transfer" 214 | nameModifier (BeforeSelfDestruct) = 215 | "LARVA_DEA_"++show deaNumber++"_handle_before_selfdestruct" 216 | nameModifier (AfterSelfDestruct) = 217 | "LARVA_DEA_"++show deaNumber++"_handle_after_selfdestruct" 218 | nameModifier (VariableAssignment vn _) = 219 | "LARVA_DEA_"++show deaNumber++"_handle_after_assignment_"++display vn 220 | 221 | 222 | instrumentForEvent :: (Event, [Transition]) -> Instrumentation 223 | instrumentForEvent (e@(UponEntry functionCall), ts) = 224 | let function = functionName functionCall 225 | 226 | functionTypedParameters = getFunctionParameters contractName function code 227 | functionParameters = 228 | ExpressionList $ 229 | maybe [] 230 | (const $ map (Literal . PrimaryExpressionIdentifier) $ 231 | fromUntypedParameterList $ untypeParameterList functionTypedParameters) 232 | eventUntypedParameters 233 | 234 | eventUntypedParameters = parametersPassed functionCall 235 | eventTypedParameters = 236 | maybe Nothing (\ps -> Just (addMemoryLocationToParametersList $ typeParameterList ps functionTypedParameters)) eventUntypedParameters 237 | 238 | modifierName = nameModifier e 239 | in -- Add modifier to function 240 | addTopModifierToFunctionInContract contractName function 241 | (Identifier modifierName, functionParameters) |> ( 242 | -- Define modifier to trigger transitions 243 | \x -> (addContractPart contractName $ parser' $ modifierCode x contractName modifierName eventTypedParameters True ts) x 244 | ) 245 | 246 | instrumentForEvent (e@(UponExit functionCall), ts) = 247 | let function = functionName functionCall 248 | 249 | functionTypedParameters = getFunctionParameters contractName function code 250 | functionParameters = 251 | ExpressionList $ 252 | maybe [] 253 | (const $ map (Literal . PrimaryExpressionIdentifier) $ 254 | fromUntypedParameterList $ untypeParameterList functionTypedParameters) 255 | eventUntypedParameters 256 | 257 | eventUntypedParameters = parametersPassed functionCall 258 | eventTypedParameters = 259 | maybe Nothing (\ps -> Just (addMemoryLocationToParametersList $ typeParameterList ps functionTypedParameters)) eventUntypedParameters 260 | 261 | modifierName = nameModifier e 262 | in -- Add modifier to function 263 | addTopModifierToFunctionInContract contractName function 264 | (Identifier modifierName, functionParameters) |> ( 265 | -- Define modifier to trigger transitions 266 | \x -> (addContractPart contractName $ parser' $ modifierCode x contractName modifierName eventTypedParameters False ts) x 267 | ) 268 | instrumentForEvent (e@(VariableAssignment variableName _), ts) = 269 | let modifierName = nameModifier e 270 | in -- Define modifier to trigger transitions 271 | (\x -> (addContractPart contractName $ parser' $ modifierCode x contractName modifierName Nothing False ts) x)|> 272 | -- Add modifier to setter functions 273 | addTopModifierToFunctionsInContract contractName 274 | [ Identifier ("LARVA_set_"++display variableName++"_pre") 275 | , Identifier ("LARVA_set_"++display variableName++"_post") 276 | ] 277 | (Identifier modifierName, ExpressionList []) 278 | instrumentForEvent (e@(BeforeTransfer), ts) = 279 | let modifierName = nameModifier e 280 | in -- Define modifier to trigger transitions 281 | (\x -> (addContractPart contractName $ parser' $ modifierCode x contractName modifierName Nothing False ts) x)|> 282 | -- Add modifier to setter functions 283 | addTopModifierToFunctionsInContract contractName 284 | [ Identifier ("LARVA_transfer") 285 | ] 286 | (Identifier modifierName, ExpressionList []) 287 | instrumentForEvent (e@(AfterTransfer), ts) = 288 | let modifierName = nameModifier e 289 | in -- Define modifier to trigger transitions 290 | (\x -> (addContractPart contractName $ parser' $ modifierCode x contractName modifierName Nothing False ts) x)|> 291 | -- Add modifier to setter functions 292 | addTopModifierToFunctionsInContract contractName 293 | [ Identifier ("LARVA_transfer") 294 | ] 295 | (Identifier modifierName, ExpressionList []) 296 | instrumentForEvent (e@(BeforeSelfDestruct), ts) = 297 | let modifierName = nameModifier e 298 | in -- Define modifier to trigger transitions 299 | (\x -> (addContractPart contractName $ parser' $ modifierCode x contractName modifierName Nothing False ts) x)|> 300 | -- Add modifier to setter functions 301 | addTopModifierToFunctionsInContract contractName 302 | [ Identifier ("LARVA_selfdestruct") 303 | ] 304 | (Identifier modifierName, ExpressionList []) 305 | instrumentForEvent (e@(AfterSelfDestruct), ts) = 306 | let modifierName = nameModifier e 307 | in -- Define modifier to trigger transitions 308 | (\x -> (addContractPart contractName $ parser' $ modifierCode x contractName modifierName Nothing False ts) x)|> 309 | -- Add modifier to setter functions 310 | addTopModifierToFunctionsInContract contractName 311 | [ Identifier ("LARVA_selfdestruct") 312 | ] 313 | (Identifier modifierName, ExpressionList []) 314 | 315 | 316 | stateNumber stateName = show $ fromJust $ elemIndex stateName ss 317 | where 318 | s0 = initialState dea 319 | ss = s0: (allStates dea \\ [s0]) 320 | 321 | 322 | instrumentSpecification :: Specification -> Bool -> Instrumentation 323 | instrumentSpecification specification inliningFlag = 324 | foldl (\f c -> instrumentContractSpecification c inliningFlag . f) id (contractSpecifications specification) 325 | 326 | ----------------------- 327 | 328 | -- IfStatement Expression Statement (Maybe Statement) 329 | -- | WhileStatement Expression Statement 330 | -- | InlineAssemblyStatement (Maybe StringLiteral) InlineAssemblyBlock 331 | -- | ForStatement (Maybe Statement, Maybe Expression, Maybe Expression) Statement 332 | -- | BlockStatement Block 333 | 334 | -- | DoWhileStatement Statement Expression 335 | -- | PlaceholderStatement 336 | -- | Continue 337 | -- | Break 338 | -- | Return (Maybe Expression) 339 | -- | Throw 340 | -- | EmitStatement Expression 341 | 342 | -- | SimpleStatementExpression Expression 343 | -- | SimpleStatementVariableList IdentifierList (Maybe Expression) 344 | -- -- | SimpleStatementVariableDeclaration VariableDeclaration (Maybe Expression) 345 | -- | SimpleStatementVariableDeclarationList [Maybe VariableDeclaration] [Expression] 346 | -- | SimpleStatementVariableAssignmentList [Maybe Identifier] [Expression] 347 | 348 | monitorDeclarationsHasCustomEnablingLogic :: ContractSpecification -> Bool 349 | monitorDeclarationsHasCustomEnablingLogic monitor = ["" | (ContractPartFunctionDefinition _ _ _ _ (Just b)) <- declarations monitor, containsCallToFunction (Identifier "LARVA_EnableContract") (BlockStatement b)] /= [] 350 | 351 | monitorInitialisationHasCustomEnablingLogic :: ContractSpecification -> Bool 352 | monitorInitialisationHasCustomEnablingLogic monitor = containsCallToFunction (Identifier "LARVA_EnableContract") (BlockStatement (initialisation monitor)) 353 | 354 | containsCallToFunction :: FunctionName -> Statement -> Bool 355 | containsCallToFunction f (IfStatement _ stmt Nothing) = containsCallToFunction f stmt 356 | containsCallToFunction f (IfStatement _ stmt (Just stmtt)) = containsCallToFunction f stmt || containsCallToFunction f stmtt 357 | containsCallToFunction f (WhileStatement _ stmt) = containsCallToFunction f stmt 358 | containsCallToFunction f (DoWhileStatement stmt _) = containsCallToFunction f stmt 359 | containsCallToFunction f (ForStatement (Nothing, _, _) stmt) = containsCallToFunction f stmt 360 | containsCallToFunction f (ForStatement (Just stmtt , _, _) stmt) = containsCallToFunction f stmt || containsCallToFunction f stmtt 361 | containsCallToFunction f (SimpleStatementExpression expr) = exprContainsCallToFunction f expr 362 | containsCallToFunction f (BlockStatement (Block (s:stmts))) = containsCallToFunction f s || containsCallToFunction f (BlockStatement (Block stmts)) 363 | containsCallToFunction _ _ = False 364 | 365 | exprContainsCallToFunction :: FunctionName -> Expression -> Bool 366 | exprContainsCallToFunction f (Unary _ ex) = exprContainsCallToFunction f ex 367 | exprContainsCallToFunction f (Binary _ e1 e2) = exprContainsCallToFunction f e1 || exprContainsCallToFunction f e2 368 | exprContainsCallToFunction f (Ternary _ e1 e2 e3) = exprContainsCallToFunction f e1 || exprContainsCallToFunction f e2 || exprContainsCallToFunction f e3 369 | exprContainsCallToFunction f (FunctionCallNameValueList e1 Nothing) = exprContainsCallToFunction f e1 370 | exprContainsCallToFunction f (FunctionCallNameValueList e1 (Just (NameValueList nameValueList))) = exprContainsCallToFunction f e1 || nameValueListContainsCall f nameValueList 371 | where nameValueListContainsCall f [] = False 372 | nameValueListContainsCall f ((_,e):rest) = exprContainsCallToFunction f e || nameValueListContainsCall f (rest) 373 | 374 | exprContainsCallToFunction f (FunctionCallExpressionList e Nothing) = exprContainsCallToFunction f e 375 | exprContainsCallToFunction f (FunctionCallExpressionList e (Just (ExpressionList exs))) = exprContainsCallToFunction f e || foldr ((||) . exprContainsCallToFunction f) False exs 376 | exprContainsCallToFunction f (Literal (PrimaryExpressionIdentifier ff)) = f == ff 377 | exprContainsCallToFunction _ _ = False 378 | 379 | 380 | warningsSpecification :: Specification -> [String] 381 | warningsSpecification spec = 382 | concat (map warningsContractSpecification cspecs) 383 | where 384 | cspecs = contractSpecifications spec 385 | 386 | warningsContractSpecification :: ContractSpecification -> [String] 387 | warningsContractSpecification cspec 388 | | null warnings = [] 389 | | otherwise = ("\n\nWarnings in definition of specification of contract <"++display (contractName cspec)++">:"):warnings 390 | where 391 | warnings = 392 | 393 | [ "\n You seem to be lacking logic to enable the instrumented smart contract. Ensure you have a call to LARVA_EnableContract in the initialisation block or in a function the declarations block.\n\n" 394 | | not (monitorDeclarationsHasCustomEnablingLogic cspec ||monitorInitialisationHasCustomEnablingLogic cspec) 395 | ] 396 | -------------------------------------------------------------------------------- /src/DEA/Parsing.hs: -------------------------------------------------------------------------------- 1 | -- Copyright 2017 Gordon J. Pace and Joshua Ellul 2 | -- 3 | -- Licensed under the Apache License, Version 2.0 (the "License"); 4 | -- you may not use this file except in compliance with the License. 5 | -- You may obtain a copy of the License at 6 | -- 7 | -- http://www.apache.org/licenses/LICENSE-2.0 8 | -- 9 | -- Unless required by applicable law or agreed to in writing, software 10 | -- distributed under the License is distributed on an "AS IS" BASIS, 11 | -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | -- See the License for the specific language governing permissions and 13 | -- limitations under the License. 14 | 15 | module DEA.Parsing ( 16 | module Parseable, module DEA.DEA 17 | ) where 18 | 19 | import Data.List 20 | import Control.Monad hiding (guard) 21 | import Text.Parsec hiding (State, label) 22 | import Text.Parsec.String 23 | 24 | import Parseable 25 | import Solidity 26 | import DEA.DEA 27 | 28 | -- ------------------------------------ 29 | readComment :: Parser () 30 | readComment = 31 | try (string "//" *> manyTill anyChar (eof <|> (newline *> return ())) *> return ()) <|> 32 | (string "/*" *> manyTill anyChar (string "*/") *> return ()) 33 | 34 | whitespace :: Parser () 35 | whitespace = void $ many ((space *> return ()) <|> readComment) 36 | 37 | endOfWord :: Parser () 38 | endOfWord = eof <|> notFollowedBy (alphaNum <|> char '_') 39 | 40 | readIdentifier :: Parser String 41 | readIdentifier = (:) <$> (letter <|> char '_') <*> many (alphaNum <|> char '_') <* endOfWord 42 | 43 | readKeyword :: String -> Parser String 44 | readKeyword word = string word <* endOfWord 45 | 46 | readAnyKeyword :: Parser String 47 | readAnyKeyword = many letter <* endOfWord 48 | 49 | commaSep1 :: Parser a -> Parser [a] 50 | commaSep1 p = 51 | do 52 | x <- p <* whitespace 53 | xs <- many (char ',' *> whitespace *> p <* whitespace) 54 | return (x:xs) 55 | 56 | 57 | instance Parseable Specification where 58 | display = intercalate "\n" . map display . contractSpecifications 59 | parser = whitespace *> (Specification <$> (many parser <* whitespace)) <* eof 60 | 61 | instance Parseable ContractSpecification where 62 | display monitor = unlines $ 63 | [ "monitor " ++ display (contractName monitor) ++ " {" 64 | , "declarations {" 65 | ] ++ map display (declarations monitor) ++ 66 | [ "}" 67 | , "initialisation ", display (initialisation monitor) 68 | , "reparation ", display (reparation monitor) 69 | , "satisfaction ", display (satisfaction monitor) 70 | ] ++ map display (deas monitor) ++ ["}"] 71 | where 72 | indentLineList = map (" "++) 73 | indentLines line = concat [ if (c=='\n') then "\n " else [c] | c <- line ] 74 | 75 | parser = 76 | do 77 | _contractName <- readKeyword "monitor" *> whitespace *> parser <* whitespace <* char '{' <* whitespace 78 | _declarations <- 79 | (try ( 80 | readKeyword "declarations" *> whitespace *> char '{' *> whitespace *> many (parser <* whitespace) <* char '}' 81 | ) <|> return []) <* whitespace 82 | _initialisation <- 83 | (try (readKeyword "initialisation" *> whitespace *> parser) <|> return (Block [])) <* whitespace 84 | _reparation <- 85 | (try (readKeyword "reparation" *> whitespace *> parser) <|> return (Block [])) <* whitespace 86 | _satisfaction <- 87 | (try (readKeyword "satisfaction" *> whitespace *> parser) <|> return (Block [])) <* whitespace 88 | _deas <- many (parser <* whitespace) 89 | _ <- char '}' 90 | return $ ContractSpecification { 91 | contractName = _contractName, 92 | declarations = _declarations, 93 | initialisation = _initialisation, 94 | satisfaction = _satisfaction, 95 | reparation = _reparation, 96 | deas = _deas 97 | } 98 | 99 | instance Parseable DEA where 100 | parser = 101 | do 102 | _deaName <- readKeyword "DEA" *> whitespace *> readIdentifier <* whitespace <* char '{' <* whitespace 103 | (_allStates, _initialStates, _badStates, _acceptanceStates) <- readStates <* whitespace 104 | _transitions <- 105 | readKeyword "transitions" *> whitespace *> char '{' *> whitespace *> 106 | many (parser <* whitespace) <* char '}' <* whitespace 107 | _ <- char '}' <* whitespace 108 | return DEA { 109 | deaName = _deaName, 110 | allStates = _allStates, 111 | initialStates = _initialStates, 112 | transitions = _transitions, 113 | badStates = _badStates, 114 | acceptanceStates = _acceptanceStates 115 | } 116 | where 117 | readStates = 118 | processStates <$> ( 119 | readKeyword "states" *> whitespace *> char '{' *> whitespace *> 120 | many ( 121 | do 122 | s <- parser <* whitespace 123 | t <- ((char ':' *> whitespace *> readStateTag) <|> return "") <* whitespace <* char ';' <* whitespace 124 | return (s,t) 125 | ) <* char '}' 126 | ) 127 | where 128 | processStates :: [(State, String)] -> ([State],[State], [State], [State]) 129 | processStates stateList = (allStates, initialStates, badStates, acceptanceStates) 130 | where 131 | allStates = map fst stateList 132 | initialStates = [ s | (s,"initial") <- stateList ] 133 | badStates = [ s | (s,"bad") <- stateList ] 134 | acceptanceStates = [ s | (s,"accept") <- stateList ] 135 | 136 | display dea = 137 | unlines $ 138 | [ "DEA "++deaName dea ++" {" 139 | , " states {" 140 | ] ++ 141 | [ " " ++ display state ++ describe state ++ ";" 142 | | state <- allStates dea 143 | ] ++ 144 | [ " }" 145 | , " transitions {" 146 | ] ++ 147 | [ " " ++ display t++";" | t <- transitions dea ] ++ 148 | [ " }" 149 | , "}" 150 | ] 151 | where 152 | describe state 153 | | null keywords = "" 154 | | otherwise = ": "++intercalate ", " keywords 155 | where 156 | keywords = 157 | ["initial" | state == initialState dea]++ 158 | ["bad" | state `elem` badStates dea]++ 159 | ["accept" | state `elem` acceptanceStates dea] 160 | 161 | 162 | instance Parseable State where 163 | parser = State <$> readAnyKeyword 164 | display = unState 165 | 166 | readStateTag :: Parser String 167 | readStateTag = choice $ map readKeyword ["initial", "bad", "accept"] 168 | 169 | instance Parseable Transition where 170 | parser = 171 | do 172 | _src <- parser <* whitespace 173 | _label <- string "-[" *> whitespace *> parser <* whitespace <* string "]->" <* whitespace 174 | _dst <- parser <* whitespace <* char ';' 175 | return Transition { src = _src, dst = _dst, label = _label } 176 | display transition = 177 | display (src transition)++" -["++display (label transition)++"]-> "++display (dst transition) 178 | 179 | instance Parseable GCL where 180 | parser = 181 | do 182 | _event <- parser <* whitespace 183 | _guard <- 184 | ( try (Just <$> (char '|' *> whitespace *> parser)) <|> 185 | try (const Nothing <$> char '|') <|> 186 | return Nothing 187 | ) <* whitespace 188 | _action <- 189 | ( try (Just <$> (string "~>" *> whitespace *> parser)) <|> 190 | try (const Nothing <$> string "~>") <|> 191 | return Nothing 192 | ) 193 | return GCL { event = _event, guard = _guard, action = _action } 194 | display rule = concat $ 195 | [ display (event rule) ] ++ 196 | [ " | (" ++display c++")" | Just c <- [guard rule] ] ++ 197 | [ " ~> {"++lineDisplay a++"}" | Just a <- [action rule]] 198 | 199 | 200 | instance Parseable Event where 201 | parser = 202 | try (UponEntry <$> (readKeyword "before" *> whitespace *> char '(' *> whitespace *> parser <* whitespace <* char ')')) <|> 203 | try (UponExit <$> (readKeyword "after" *> whitespace *> char '(' *> whitespace *> parser <* whitespace <* char ')')) <|> 204 | try ((readKeyword "beforetransfer" <* whitespace *> return BeforeTransfer)) <|> 205 | try ((readKeyword "aftertransfer" <* whitespace *> return AfterTransfer)) <|> 206 | try ((readKeyword "beforeselfdestruct" <* whitespace *> return BeforeSelfDestruct)) <|> 207 | try ((readKeyword "afterselfdestruct" <* whitespace *> return AfterSelfDestruct)) <|> 208 | (VariableAssignment <$> 209 | (parser <* whitespace <* char '@' <* whitespace <* char '(' <* whitespace) <*> 210 | (try (Just <$> parser <* whitespace <* char ')') <|> return Nothing) 211 | ) 212 | 213 | display (UponEntry fn) = "before("++display fn++")" 214 | display (UponExit fn) = "after("++display fn++")" 215 | display (BeforeTransfer) = "beforetransfer" 216 | display (AfterTransfer) = "aftertransfer" 217 | display (BeforeSelfDestruct) = "beforeselfdestruct" 218 | display (AfterSelfDestruct) = "afterselfdestruct" 219 | display (VariableAssignment vn e) = display vn ++maybe "" (\e -> "@("++display e++")") e 220 | 221 | instance Parseable FunctionCall where 222 | parser = 223 | do 224 | fn <- parser <* whitespace 225 | maybe_el <- parser 226 | return (FunctionCall { functionName = fn, parametersPassed = maybe_el }) 227 | 228 | display fc = display (functionName fc) ++ maybe "" display (parametersPassed fc) 229 | 230 | -------------------------------------------------------------------------------- /src/Main.hs: -------------------------------------------------------------------------------- 1 | -- Copyright 2017 Gordon J. Pace and Joshua Ellul 2 | -- 3 | -- Licensed under the Apache License, Version 2.0 (the "License"); 4 | -- you may not use this file except in compliance with the License. 5 | -- You may obtain a copy of the License at 6 | -- 7 | -- http://www.apache.org/licenses/LICENSE-2.0 8 | -- 9 | -- Unless required by applicable law or agreed to in writing, software 10 | -- distributed under the License is distributed on an "AS IS" BASIS, 11 | -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | -- See the License for the specific language governing permissions and 13 | -- limitations under the License. 14 | 15 | module Main where 16 | 17 | import System.Environment 18 | import System.Exit 19 | import Control.Exception.Base 20 | import System.IO 21 | import System.IO.Error 22 | import Data.List 23 | 24 | import Text.Parsec hiding (try) 25 | import Text.Parsec.String 26 | import Solidity 27 | import DEA 28 | 29 | type Filename = String 30 | 31 | failWith :: IO a -> String -> IO a 32 | io `failWith` e = io `catch` (const $ (fail e) :: IOError -> IO a) 33 | 34 | ifNot :: Bool -> String -> IO () 35 | ifNot c e = if c then return () else fail e 36 | 37 | parseIO :: Parseable a => Filename -> String -> IO a 38 | parseIO filename = either (fail . (parseError ++) . show) return . parse parser "" 39 | where 40 | parseError = "Error during parsing of <"++filename++">\n" 41 | 42 | main = 43 | do 44 | contractLarva <- getProgName 45 | arguments <- getArgs 46 | ifNot (length arguments >= 3 || (length arguments == 4 && (elem "--init-not-inlined" arguments))) 47 | ("Usage: "++contractLarva++" <--init-not-inlined>?") 48 | let ([specificationFile, inFile, outFile], flag) = if length arguments == 3 49 | then (arguments, False) 50 | else (delete "--init-not-inlined" arguments, True) 51 | specificationText <- readFile specificationFile 52 | `failWith` ("Cannot read specification file <"++specificationFile++">") 53 | specification <- parseIO specificationFile specificationText 54 | putStrLn (concat $ warningsSpecification specification) 55 | 56 | let problems = problemsSpecification specification 57 | ifNot (null problems) (unlines problems) 58 | 59 | inputText <- readFile inFile 60 | `failWith` ("Cannot read Solidity file <"++inFile++">") 61 | inCode <- parseIO inFile inputText 62 | 63 | let warnings = warningsSpecificationCode specification inCode 64 | ifNot (null warnings) (unlines warnings) 65 | 66 | let outCode = instrumentSpecification specification flag inCode 67 | writeFile outFile (display outCode) 68 | `failWith` ("Cannot write to Solidity file <"++outFile++">") 69 | putStrLn ("Created safe contract file <"++outFile++">") 70 | `catch` (putStrLn . ioeGetErrorString) 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/Parseable.hs: -------------------------------------------------------------------------------- 1 | -- Copyright 2017 Gordon J. Pace and Joshua Ellul 2 | -- 3 | -- Licensed under the Apache License, Version 2.0 (the "License"); 4 | -- you may not use this file except in compliance with the License. 5 | -- You may obtain a copy of the License at 6 | -- 7 | -- http://www.apache.org/licenses/LICENSE-2.0 8 | -- 9 | -- Unless required by applicable law or agreed to in writing, software 10 | -- distributed under the License is distributed on an "AS IS" BASIS, 11 | -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | -- See the License for the specific language governing permissions and 13 | -- limitations under the License. 14 | 15 | module Parseable (Parseable (..), _display, lineDisplay) where 16 | 17 | import Data.Char 18 | import Text.Parsec 19 | import Text.Parsec.String 20 | 21 | class Parseable a where 22 | display :: a -> String 23 | parser :: Parser a 24 | 25 | instance Parseable a => Parseable (Maybe a) where 26 | parser = (Just <$> try parser) <|> return Nothing 27 | display Nothing = "" 28 | display (Just x) = display x 29 | 30 | _display :: Parseable a => a -> String 31 | _display = (' ':) . display 32 | 33 | lineDisplay :: Parseable a => a -> String 34 | lineDisplay = filter (not . isSpace) . display 35 | -------------------------------------------------------------------------------- /src/Solidity.hs: -------------------------------------------------------------------------------- 1 | -- Copyright 2017 Gordon J. Pace and Joshua Ellul 2 | -- 3 | -- Licensed under the Apache License, Version 2.0 (the "License"); 4 | -- you may not use this file except in compliance with the License. 5 | -- You may obtain a copy of the License at 6 | -- 7 | -- http://www.apache.org/licenses/LICENSE-2.0 8 | -- 9 | -- Unless required by applicable law or agreed to in writing, software 10 | -- distributed under the License is distributed on an "AS IS" BASIS, 11 | -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | -- See the License for the specific language governing permissions and 13 | -- limitations under the License. 14 | 15 | module Solidity ( module Solidity.Solidity, module Solidity.Parsing, module Solidity.Instrumentation ) where 16 | import Solidity.Solidity 17 | import Solidity.Parsing 18 | import Solidity.Instrumentation 19 | -------------------------------------------------------------------------------- /src/TODO.txt: -------------------------------------------------------------------------------- 1 | Still to do: 2 | 3 | 4 | Known bugs: 5 | * Runtime error if the name of the contract referred to in the specification file is not found in the Solidity source. 6 | 7 | *** Solidity.hs 8 | * 9 | * 10 | *---- Solidity.Parsing.hs --------------- 11 | * 12 | * - Better error handling in parsing 13 | * 14 | *---- Solidity.Instrumentation.hs ------- 15 | * 16 | * 17 | ***************************************** 18 | 19 | *** DAE.hs ***************************** 20 | * 21 | * 22 | *---- DAE.DAE.hs ---------------------- 23 | * 24 | * 25 | *---- DAE.Parsing.hs ------------------- 26 | * 27 | * - Better error handling in parsing 28 | * - Check that functions used in the DAEs are defined and have the right number of parameters 29 | * 30 | *---- DAE.Instrumentation.hs ----------- 31 | * 32 | * 33 | ***************************************** 34 | 35 | *** Main.hs ***************************** 36 | * 37 | * 38 | ***************************************** 39 | 40 | *** GENERAL ***************************** 41 | * 42 | * 43 | ***************************************** 44 | 45 | 46 | -------------------------------------------------------------------------------- /template.dea: -------------------------------------------------------------------------------- 1 | monitor MonitorToContractName{ 2 | declarations{ 3 | // declare any global variables and functions 4 | } 5 | 6 | initialisation{ 7 | // put here any code that you want to act as the constructor of the monitored contract 8 | // if you use this code block remember to allow the smart contract to be enabled by calling LARVA_EnableContract() here or through some additional logic declared in the block 9 | } 10 | 11 | reparation{ 12 | // enter here any code that you want executed upon a bad state of the monitor being reached 13 | } 14 | 15 | satisfaction{ 16 | // enter here any code that you want executed upon an accepting state of the monitor being reached 17 | } 18 | 19 | 20 | DEA MonitorName1{ 21 | states{ 22 | // here declare any states you wish to use in your monitor here 23 | // in the following format: (: (initial|bad|accept))?; 24 | // e.g. the following is a valid state list: 25 | // 26 | // 0: initial; 27 | // 1; 28 | // 2; 29 | // bad: bad; 30 | // accepting: accept; 31 | } 32 | 33 | transitions{ 34 | // here declare the transitions you wish the monitor to trigger, conditional on an event and the state of the smart contract, and possibly transforming the same state 35 | // in the following format: -[(before|after)\(\) | ~> ]-> ; 36 | // e.g. the following is a valud transition: 37 | // 0 -[after(functionA()) | count == 5 ~> count++]-> 1; 38 | } 39 | } 40 | 41 | DEA MonitorName2{ 42 | // ... 43 | } 44 | 45 | //Hint: multiple DEA monitors can be declared in the same file, which will be wrapped around the same smart contract 46 | 47 | } -------------------------------------------------------------------------------- /use-cases/Casino/Casino.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.11; 2 | 3 | contract Casino{ 4 | 5 | mapping(uint => mapping (uint => address payable[])) placedBets; 6 | mapping(uint => mapping(address => uint)) potShare; 7 | 8 | uint[] numbersGuessed; 9 | 10 | uint pot; 11 | 12 | uint tableID; 13 | uint tableOpenTime; 14 | 15 | address owner; 16 | 17 | constructor() public{ 18 | owner = msg.sender; 19 | } 20 | 21 | function openTable() public{ 22 | require(msg.sender == owner); 23 | require(tableOpenTime == 0); 24 | 25 | tableOpenTime = now; 26 | tableID++; 27 | } 28 | 29 | function closeTable() public{ 30 | require(msg.sender == owner); 31 | require(pot == 0); 32 | 33 | delete numbersGuessed; 34 | } 35 | 36 | function timeoutBet() public{ 37 | require(msg.sender == owner); 38 | require(now - tableOpenTime > 60 minutes); 39 | require(pot != 0); 40 | 41 | for (uint i = 0; i < numbersGuessed.length; i++) { 42 | uint l = placedBets[tableID][numbersGuessed[i]].length; 43 | 44 | for (uint j = 0; j < l; j++) { 45 | address payable better = placedBets[tableID][numbersGuessed[i]][l]; 46 | better.transfer(potShare[tableID][better]); 47 | delete placedBets[tableID][numbersGuessed[i]]; 48 | } 49 | } 50 | 51 | closeTable(); 52 | } 53 | 54 | function placeBet(uint guessNo) payable public{ 55 | require(msg.value > 1 ether); 56 | 57 | potShare[tableID][msg.sender] += msg.value; 58 | placedBets[tableID][guessNo].push(msg.sender); 59 | numbersGuessed.push(guessNo); 60 | pot += msg.value; 61 | } 62 | 63 | //we assume owner is trusted 64 | function resolveBet(uint _secretNumber) public{ 65 | require(msg.sender == owner); 66 | 67 | uint l = placedBets[tableID][_secretNumber].length; 68 | if(l != 0){ 69 | for (uint i = 0; i < l; i++) { 70 | placedBets[tableID][_secretNumber][i].transfer(pot/l); 71 | } 72 | } 73 | 74 | pot = 0; 75 | 76 | closeTable(); 77 | } 78 | } -------------------------------------------------------------------------------- /use-cases/Casino/CasinoSpec.dea: -------------------------------------------------------------------------------- 1 | monitor Casino{ 2 | 3 | declarations{ 4 | uint total; 5 | } 6 | 7 | initialisation{ 8 | LARVA_EnableContract(); 9 | } 10 | 11 | DEA NoReduction { 12 | states { 13 | TableOpen: initial; 14 | TableClosed: accept; 15 | BetPlaced; 16 | PotReduced: bad; 17 | } 18 | transitions { 19 | TableOpen -[after(closeTable) | pot == 0 ]-> TableClosed; 20 | TableOpen -[after(placeBet(_value)) | _value <= pot ~> total += _value;]-> BetPlaced; 21 | BetPlaced -[after(timeoutBet)]-> TableOpen; 22 | BetPlaced -[after(resolveBet)]-> TableOpen; 23 | BetPlaced -[pot@(LARVA_previous_pot > pot)]-> PotReduced; 24 | } 25 | } 26 | 27 | DEA OpenUntilResolution { 28 | states { 29 | TableClosed: initial; 30 | TableOpen; 31 | BetPlaced; 32 | TableCloseDuringBet: bad; 33 | } 34 | transitions { 35 | TableClosed -[after(openTable)]-> TableOpen; 36 | TableOpen -[after(closeTable)]-> TableClosed; 37 | TableOpen -[after(placeBet)]-> BetPlaced; 38 | BetPlaced -[after(resolveBet)]-> TableOpen; 39 | BetPlaced -[after(timeoutBet)]-> TableOpen; 40 | BetPlaced -[after(closeTable)]-> TableCloseDuringBet; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /use-cases/Casino/monitoredCasino.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.11; 2 | contract LARVA_Casino { 3 | modifier LARVA_Constructor { 4 | _; 5 | { 6 | LARVA_EnableContract(); 7 | } 8 | } 9 | modifier LARVA_DEA_2_handle_after_timeoutBet__no_parameters { 10 | if ((LARVA_STATE_2 == 2)) { 11 | LARVA_STATE_2 = 1; 12 | } 13 | _; 14 | } 15 | modifier LARVA_DEA_2_handle_after_resolveBet__no_parameters { 16 | if ((LARVA_STATE_2 == 2)) { 17 | LARVA_STATE_2 = 1; 18 | } 19 | _; 20 | } 21 | modifier LARVA_DEA_2_handle_after_placeBet__no_parameters { 22 | if ((LARVA_STATE_2 == 1)) { 23 | LARVA_STATE_2 = 2; 24 | } 25 | _; 26 | } 27 | modifier LARVA_DEA_2_handle_after_openTable__no_parameters { 28 | if ((LARVA_STATE_2 == 0)) { 29 | LARVA_STATE_2 = 1; 30 | } 31 | _; 32 | } 33 | modifier LARVA_DEA_2_handle_after_closeTable__no_parameters { 34 | if ((LARVA_STATE_2 == 1)) { 35 | LARVA_STATE_2 = 0; 36 | } else { 37 | if ((LARVA_STATE_2 == 2)) { 38 | LARVA_STATE_2 = 3; 39 | } 40 | } 41 | _; 42 | } 43 | modifier LARVA_DEA_1_handle_after_assignment_pot { 44 | _; 45 | if ((LARVA_STATE_1 == 2) && (LARVA_previous_pot > pot)) { 46 | LARVA_STATE_1 = 3; 47 | } 48 | } 49 | modifier LARVA_DEA_1_handle_after_timeoutBet__no_parameters { 50 | if ((LARVA_STATE_1 == 2)) { 51 | LARVA_STATE_1 = 0; 52 | } 53 | _; 54 | } 55 | modifier LARVA_DEA_1_handle_after_resolveBet__no_parameters { 56 | if ((LARVA_STATE_1 == 2)) { 57 | LARVA_STATE_1 = 0; 58 | } 59 | _; 60 | } 61 | modifier LARVA_DEA_1_handle_after_placeBet__parameters__value (uint _value) { 62 | if ((LARVA_STATE_1 == 0) && (_value <= pot)) { 63 | LARVA_STATE_1 = 2; 64 | total += _value; 65 | } 66 | _; 67 | } 68 | modifier LARVA_DEA_1_handle_after_closeTable__no_parameters { 69 | if ((LARVA_STATE_1 == 0) && (pot == 0)) { 70 | LARVA_STATE_1 = 1; 71 | } 72 | _; 73 | } 74 | int8 LARVA_STATE_1 = 0; 75 | int8 LARVA_STATE_2 = 0; 76 | function LARVA_set_pot_pre (uint _pot) LARVA_DEA_1_handle_after_assignment_pot public returns (uint) { 77 | LARVA_previous_pot = pot; 78 | pot = _pot; 79 | return LARVA_previous_pot; 80 | } 81 | function LARVA_set_pot_post (uint _pot) LARVA_DEA_1_handle_after_assignment_pot public returns (uint) { 82 | LARVA_previous_pot = pot; 83 | pot = _pot; 84 | return pot; 85 | } 86 | uint private LARVA_previous_pot; 87 | uint total; 88 | enum LARVA_STATUS {RUNNING, STOPPED} 89 | function LARVA_EnableContract () private { 90 | LARVA_Status = LARVA_STATUS.RUNNING; 91 | } 92 | function LARVA_DisableContract () private { 93 | LARVA_Status = LARVA_STATUS.STOPPED; 94 | } 95 | LARVA_STATUS private LARVA_Status = LARVA_STATUS.STOPPED; 96 | modifier LARVA_ContractIsEnabled { 97 | require(LARVA_Status == LARVA_STATUS.RUNNING); 98 | _; 99 | } 100 | mapping (uint => mapping (uint => address payable[])) placedBets; 101 | mapping (uint => mapping (address => uint)) potShare; 102 | uint[] numbersGuessed; 103 | uint private pot; 104 | uint tableID; 105 | uint tableOpenTime; 106 | address owner; 107 | constructor () LARVA_Constructor public { 108 | owner = msg.sender; 109 | } 110 | function openTable () LARVA_DEA_2_handle_after_openTable__no_parameters LARVA_ContractIsEnabled public { 111 | require(msg.sender == owner); 112 | require(tableOpenTime == 0); 113 | tableOpenTime = now; 114 | tableID++; 115 | } 116 | function closeTable () LARVA_DEA_2_handle_after_closeTable__no_parameters LARVA_DEA_1_handle_after_closeTable__no_parameters LARVA_ContractIsEnabled public { 117 | require(msg.sender == owner); 118 | require(pot == 0); 119 | delete numbersGuessed; 120 | } 121 | function timeoutBet () LARVA_DEA_2_handle_after_timeoutBet__no_parameters LARVA_DEA_1_handle_after_timeoutBet__no_parameters LARVA_ContractIsEnabled public { 122 | require(msg.sender == owner); 123 | require(now - tableOpenTime > 60 minutes); 124 | require(pot != 0); 125 | for (uint i = 0; i < numbersGuessed.length; i++) { 126 | uint l = placedBets[tableID][numbersGuessed[i]].length; 127 | for (uint j = 0; j < l; j++) { 128 | address payable better = placedBets[tableID][numbersGuessed[i]][l]; 129 | better.transfer(potShare[tableID][better]); 130 | delete placedBets[tableID][numbersGuessed[i]]; 131 | } 132 | } 133 | closeTable(); 134 | } 135 | function placeBet (uint guessNo) LARVA_DEA_2_handle_after_placeBet__no_parameters LARVA_DEA_1_handle_after_placeBet__parameters__value(guessNo) LARVA_ContractIsEnabled payable public { 136 | require(msg.value > 1 ether); 137 | potShare[tableID][msg.sender] += msg.value; 138 | placedBets[tableID][guessNo].push(msg.sender); 139 | numbersGuessed.push(guessNo); 140 | LARVA_set_pot_post((pot) + (msg.value)); 141 | } 142 | function resolveBet (uint _secretNumber) LARVA_DEA_2_handle_after_resolveBet__no_parameters LARVA_DEA_1_handle_after_resolveBet__no_parameters LARVA_ContractIsEnabled public { 143 | require(msg.sender == owner); 144 | uint l = placedBets[tableID][_secretNumber].length; 145 | if (l != 0) { 146 | for (uint i = 0; i < l; i++) { 147 | placedBets[tableID][_secretNumber][i].transfer(pot / l); 148 | } 149 | } 150 | pot = 0; 151 | closeTable(); 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /use-cases/CourierService/CourierService.sol: -------------------------------------------------------------------------------- 1 | contract CourierService{ 2 | 3 | uint fees; 4 | 5 | address customer; 6 | uint orderETA; 7 | uint orderDeliveryTime; 8 | bool delivered; 9 | bool ordered; 10 | 11 | bool cancelled; 12 | 13 | uint extraTimeAllowance; 14 | uint cost; 15 | 16 | function order(uint eta) payable public{ 17 | require(msg.value >= cost); 18 | require(!ordered); 19 | 20 | customer = msg.sender; 21 | orderETA = eta; 22 | ordered = true; 23 | } 24 | 25 | function delivery() public{ 26 | require(msg.sender == customer); 27 | require(ordered && !delivered); 28 | 29 | delivered = true; 30 | 31 | orderDeliveryTime = now; 32 | } 33 | 34 | function requestRefund() public payable{ 35 | require(ordered && !delivered && !cancelled); 36 | require(now - orderETA > 5 days); 37 | 38 | transferTo(cost); 39 | cancelled = true; 40 | } 41 | 42 | function transferTo(uint val) public payable{ 43 | require(msg.sender == address(this)); 44 | 45 | customer.call.value(val); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /use-cases/CourierService/courierservicespec.dea: -------------------------------------------------------------------------------- 1 | monitor CourierService{ 2 | 3 | initialisation{ 4 | LARVA_EnableContract(); 5 | } 6 | 7 | DEA WellBehaviour { 8 | states { 9 | Start: initial; 10 | Ordered; 11 | Delivered; 12 | Refunding; 13 | Paid; 14 | Refunded; 15 | Bad: bad; 16 | } 17 | 18 | transitions { 19 | Start -[after(order(eta)) | customer != msg.sender ]-> Bad; 20 | Start -[after(delivery()) | ]-> Bad; 21 | Start -[after(refund()) | ]-> Bad; 22 | 23 | Start -[after(order(eta)) | customer == msg.sender ]-> Ordered; 24 | 25 | Ordered -[after(order(eta)) | ]-> Bad; 26 | Ordered -[after(delivery()) | customer != msg.sender ]-> Bad; 27 | Ordered -[before(refund()) | customer != msg.sender ]-> Bad; 28 | 29 | Ordered -[after(delivery()) | customer == msg.sender ]-> Delivered; 30 | 31 | Delivered -[after(order(eta)) | ]-> Bad; 32 | Delivered -[after(delivery()) | ]-> Bad; 33 | Delivered -[after(refund()) | ]-> Bad; 34 | 35 | Ordered -[before(refund()) | msg.sender == customer ]-> Refunding; 36 | 37 | Refunding -[after(order(eta)) | ]-> Bad; 38 | Refunding -[after(delivery()) | ]-> Bad; 39 | Refunding -[after(refund()) | ]-> Bad; 40 | 41 | Refunding -[before(transferTo(val)) | ]-> Paid; 42 | 43 | Paid -[after(order(eta)) | ]-> Bad; 44 | Paid -[after(delivery()) | ]-> Bad; 45 | 46 | Paid -[after(refund()) | ]-> Refunded; 47 | 48 | Refunded -[after(order(eta)) | ]-> Bad; 49 | Refunded -[after(delivery()) | ]-> Bad; 50 | Refunded -[after(refund()) | ]-> Bad; 51 | 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /use-cases/CourierService/monitoredCourierService.sol: -------------------------------------------------------------------------------- 1 | contract LARVA_CourierService { 2 | modifier LARVA_Constructor { 3 | _; 4 | { 5 | LARVA_EnableContract(); 6 | } 7 | } 8 | modifier LARVA_DEA_1_handle_after_refund__parameters_ () { 9 | if ((LARVA_STATE_1 == 0)) { 10 | LARVA_STATE_1 = 6; 11 | } else { 12 | if ((LARVA_STATE_1 == 2)) { 13 | LARVA_STATE_1 = 6; 14 | } else { 15 | if ((LARVA_STATE_1 == 3)) { 16 | LARVA_STATE_1 = 6; 17 | } else { 18 | if ((LARVA_STATE_1 == 4)) { 19 | LARVA_STATE_1 = 5; 20 | } else { 21 | if ((LARVA_STATE_1 == 5)) { 22 | LARVA_STATE_1 = 6; 23 | } 24 | } 25 | } 26 | } 27 | } 28 | _; 29 | } 30 | modifier LARVA_DEA_1_handle_after_order__parameters_eta (uint eta) { 31 | if ((LARVA_STATE_1 == 0) && (customer != msg.sender)) { 32 | LARVA_STATE_1 = 6; 33 | } else { 34 | if ((LARVA_STATE_1 == 0) && (customer == msg.sender)) { 35 | LARVA_STATE_1 = 1; 36 | } else { 37 | if ((LARVA_STATE_1 == 1)) { 38 | LARVA_STATE_1 = 6; 39 | } else { 40 | if ((LARVA_STATE_1 == 2)) { 41 | LARVA_STATE_1 = 6; 42 | } else { 43 | if ((LARVA_STATE_1 == 3)) { 44 | LARVA_STATE_1 = 6; 45 | } else { 46 | if ((LARVA_STATE_1 == 4)) { 47 | LARVA_STATE_1 = 6; 48 | } else { 49 | if ((LARVA_STATE_1 == 5)) { 50 | LARVA_STATE_1 = 6; 51 | } 52 | } 53 | } 54 | } 55 | } 56 | } 57 | } 58 | _; 59 | } 60 | modifier LARVA_DEA_1_handle_after_delivery__parameters_ () { 61 | if ((LARVA_STATE_1 == 0)) { 62 | LARVA_STATE_1 = 6; 63 | } else { 64 | if ((LARVA_STATE_1 == 1) && (customer != msg.sender)) { 65 | LARVA_STATE_1 = 6; 66 | } else { 67 | if ((LARVA_STATE_1 == 1) && (customer == msg.sender)) { 68 | LARVA_STATE_1 = 2; 69 | } else { 70 | if ((LARVA_STATE_1 == 2)) { 71 | LARVA_STATE_1 = 6; 72 | } else { 73 | if ((LARVA_STATE_1 == 3)) { 74 | LARVA_STATE_1 = 6; 75 | } else { 76 | if ((LARVA_STATE_1 == 4)) { 77 | LARVA_STATE_1 = 6; 78 | } else { 79 | if ((LARVA_STATE_1 == 5)) { 80 | LARVA_STATE_1 = 6; 81 | } 82 | } 83 | } 84 | } 85 | } 86 | } 87 | } 88 | _; 89 | } 90 | modifier LARVA_DEA_1_handle_before_transferTo__parameters_val (uint val) { 91 | if ((LARVA_STATE_1 == 3)) { 92 | LARVA_STATE_1 = 4; 93 | } 94 | _; 95 | } 96 | modifier LARVA_DEA_1_handle_before_refund__parameters_ () { 97 | if ((LARVA_STATE_1 == 1) && (customer != msg.sender)) { 98 | LARVA_STATE_1 = 6; 99 | } else { 100 | if ((LARVA_STATE_1 == 1) && (msg.sender == customer)) { 101 | LARVA_STATE_1 = 3; 102 | } 103 | } 104 | _; 105 | } 106 | int8 LARVA_STATE_1 = 0; 107 | constructor () LARVA_Constructor public { 108 | } 109 | enum LARVA_STATUS {RUNNING, STOPPED} 110 | function LARVA_EnableContract () private { 111 | LARVA_Status = LARVA_STATUS.RUNNING; 112 | } 113 | function LARVA_DisableContract () private { 114 | LARVA_Status = LARVA_STATUS.STOPPED; 115 | } 116 | LARVA_STATUS private LARVA_Status = LARVA_STATUS.STOPPED; 117 | modifier LARVA_ContractIsEnabled { 118 | require(LARVA_Status == LARVA_STATUS.RUNNING); 119 | _; 120 | } 121 | uint fees; 122 | address customer; 123 | uint orderETA; 124 | uint orderDeliveryTime; 125 | bool delivered; 126 | bool ordered; 127 | bool cancelled; 128 | uint extraTimeAllowance; 129 | uint cost; 130 | function order (uint eta) LARVA_DEA_1_handle_after_order__parameters_eta(eta) LARVA_ContractIsEnabled payable public { 131 | require(msg.value >= cost); 132 | require(!ordered); 133 | customer = msg.sender; 134 | orderETA = eta; 135 | ordered = true; 136 | } 137 | function delivery () LARVA_DEA_1_handle_after_delivery__parameters_ LARVA_ContractIsEnabled public { 138 | require(msg.sender == customer); 139 | require(ordered && !delivered); 140 | delivered = true; 141 | orderDeliveryTime = now; 142 | } 143 | function requestRefund () LARVA_ContractIsEnabled public payable { 144 | require(ordered && !delivered && !cancelled); 145 | require(now - orderETA > 5 days); 146 | transferTo(cost); 147 | cancelled = true; 148 | } 149 | function transferTo (uint val) LARVA_DEA_1_handle_before_transferTo__parameters_val(val) LARVA_ContractIsEnabled public payable { 150 | require(msg.sender == address(this)); 151 | customer.call.value(val); 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /use-cases/ERC20Interface/ERC20Interface.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.26; 2 | 3 | // ---------------------------------------------------------------------------- 4 | // ERC Token Standard #20 Interface 5 | // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md 6 | // ---------------------------------------------------------------------------- 7 | interface ERC20TokenImplementation { 8 | function totalSupply () external constant returns (uint); 9 | function balanceOf (address tokenOwner) external constant returns (uint balance); 10 | function allowance (address tokenOwner, address spender) external constant returns (uint remaining); 11 | function transfer (address caller, address to, uint tokens) external returns (bool success); 12 | function approve (address caller, address spender, uint tokens) external returns (bool success); 13 | function transferFrom (address caller, address from, address to, uint tokens) external returns (bool success); 14 | event Transfer (address indexed from, address indexed to, uint tokens); 15 | event Approval (address indexed tokenOwner, address indexed spender, uint tokens); 16 | 17 | } 18 | contract ERC20Interface{ 19 | 20 | ERC20TokenImplementation impl; 21 | address owner; 22 | 23 | constructor(ERC20TokenImplementation _impl, address _owner) public{ 24 | impl = _impl; 25 | owner = _owner; 26 | } 27 | 28 | function updateImplementation(address newImpl) public{ 29 | require(msg.sender == owner); 30 | impl = ERC20TokenImplementation(newImpl); 31 | } 32 | 33 | function totalSupply() public constant returns (uint){ 34 | return impl.totalSupply(); 35 | } 36 | 37 | function balanceOf(address tokenOwner) public constant returns (uint balance){ 38 | return impl.balanceOf(tokenOwner); 39 | } 40 | 41 | function allowance(address tokenOwner, address spender) public constant returns (uint remaining){ 42 | return impl.allowance(tokenOwner, spender); 43 | } 44 | 45 | function transfer(address to, uint tokens) public returns (bool success){ 46 | return impl.transfer(msg.sender, to, tokens); 47 | } 48 | 49 | function approve(address spender, uint tokens) public returns (bool success){ 50 | return impl.approve(msg.sender, spender, tokens); 51 | } 52 | 53 | function transferFrom(address from, address to, uint tokens) public returns (bool success){ 54 | return impl.transferFrom(msg.sender, from, to, tokens); 55 | } 56 | } -------------------------------------------------------------------------------- /use-cases/ERC20Interface/ERC20InterfaceSpec.dea: -------------------------------------------------------------------------------- 1 | monitor ERC20Interface{ 2 | declarations { 3 | uint transferPreFrom; 4 | uint transferPreTo; 5 | 6 | uint transferFromPreFrom; 7 | uint transferFromPreTo; 8 | uint preAllowance; 9 | 10 | } 11 | 12 | initialisation{ 13 | LARVA_EnableContract(); 14 | } 15 | 16 | reparation { 17 | revert(); 18 | } 19 | 20 | DEA TransferWellBehaviour { 21 | states { 22 | Before: initial; 23 | After; 24 | Bad: bad; 25 | } 26 | 27 | transitions { 28 | 29 | Before -[before(transfer(to, tokens)) | ~> {transferPreFrom = balanceOf(msg.sender); transferPreTo = balanceOf(to);}]-> After; 30 | 31 | After -[before(transfer(to, tokens))]-> Bad; 32 | 33 | After -[after(transfer(to, tokens)) | transferPreFrom < tokens && (balanceOf(msg.sender) != transferPreFrom || balanceOf(to) != transferPreTo)]-> Bad; 34 | 35 | After -[after(transfer(to, tokens)) | transferPreFrom < tokens && (balanceOf(msg.sender) == transferPreFrom && balanceOf(to) == transferPreTo)]-> Before; 36 | 37 | After -[after(transfer(to, tokens)) | transferPreFrom >= tokens && (balanceOf(msg.sender) != (transferPreFrom - tokens) || balanceOf(to) != (transferPreTo - tokens))]-> Bad; 38 | 39 | After -[after(transfer(to, tokens)) | transferPreFrom >= tokens && (balanceOf(msg.sender) == (transferPreFrom - tokens) && balanceOf(to) == (transferPreTo - tokens))]-> Before; 40 | } 41 | } 42 | 43 | DEA TransferFromWellBehaviour { 44 | states { 45 | Before: initial; 46 | After; 47 | Bad: bad; 48 | } 49 | 50 | transitions { 51 | Before -[before(transferFrom(from, to, tokens)) | ~> {transferFromPreFrom = balanceOf(from); transferFromPreTo = balanceOf(to); preAllowance = allowance(msg.sender, from);}]-> After; 52 | 53 | After -[before(transferFrom(from, to, tokens))]-> Bad; 54 | 55 | After -[after(transferFrom(from, to, tokens)) | (transferFromPreFrom < tokens || preAllowance < tokens) && (balanceOf(msg.sender) != transferFromPreFrom || balanceOf(to) != transferFromPreTo || allowance(msg.sender, from) != preAllowance)]-> Bad; 56 | 57 | After -[after(transferFrom(from, to, tokens)) | (transferFromPreFrom < tokens || preAllowance < tokens) && (balanceOf(msg.sender) == transferFromPreFrom && balanceOf(to) == transferFromPreTo && allowance(msg.sender, from) == preAllowance)]-> Before; 58 | 59 | After -[after(transferFrom(from, to, tokens)) | (transferFromPreFrom >= tokens && preAllowance >= tokens) && (balanceOf(msg.sender) != (transferFromPreFrom - tokens) || balanceOf(to) != (transferFromPreTo - tokens) || allowance(msg.sender, from) != preAllowance - tokens)]-> Bad; 60 | 61 | After -[after(transferFrom(from, to, tokens)) | (transferFromPreFrom >= tokens && preAllowance >= tokens) && (balanceOf(msg.sender) == (transferFromPreFrom - tokens) && balanceOf(to) == (transferFromPreTo - tokens) && allowance(msg.sender, from) == preAllowance - tokens)]-> Before; 62 | 63 | } 64 | } 65 | 66 | DEA ApproveWellBehaviour { 67 | states { 68 | Before: initial; 69 | After; 70 | Bad: bad; 71 | } 72 | 73 | transitions { 74 | Before -[before(approve(spender, tokens))]-> After; 75 | 76 | After -[before(approve(spender, tokens))]-> Bad; 77 | 78 | After -[after(approve(spender, tokens)) | allowance(msg.sender, spender) == tokens]-> Before; 79 | 80 | After -[after(approve(spender, tokens)) | allowance(msg.sender, spender) != tokens]-> Bad; 81 | 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /use-cases/ERC20Interface/MonitoredERC20Interface.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.26; 2 | interface ERC20TokenImplementation { 3 | function totalSupply () external constant returns (uint); 4 | function balanceOf (address tokenOwner) external constant returns (uint balance); 5 | function allowance (address tokenOwner, address spender) external constant returns (uint remaining); 6 | function transfer (address caller, address to, uint tokens) external returns (bool success); 7 | function approve (address caller, address spender, uint tokens) external returns (bool success); 8 | function transferFrom (address caller, address from, address to, uint tokens) external returns (bool success); 9 | event Transfer (address indexed from, address indexed to, uint tokens); 10 | event Approval (address indexed tokenOwner, address indexed spender, uint tokens); 11 | 12 | } 13 | contract LARVA_ERC20Interface { 14 | modifier LARVA_Constructor { 15 | _; 16 | { 17 | LARVA_EnableContract(); 18 | } 19 | } 20 | modifier LARVA_DEA_3_handle_after_approve__parameters_spender_tokens (address spender, uint tokens) { 21 | if ((LARVA_STATE_3 == 1) && (allowance(msg.sender, spender) == tokens)) { 22 | LARVA_STATE_3 = 0; 23 | } else { 24 | if ((LARVA_STATE_3 == 1) && (allowance(msg.sender, spender) != tokens)) { 25 | LARVA_STATE_3 = 2; 26 | LARVA_reparation(); 27 | } 28 | } 29 | _; 30 | } 31 | modifier LARVA_DEA_3_handle_before_approve__parameters_spender_tokens (address spender, uint tokens) { 32 | if ((LARVA_STATE_3 == 0)) { 33 | LARVA_STATE_3 = 1; 34 | } else { 35 | if ((LARVA_STATE_3 == 1)) { 36 | LARVA_STATE_3 = 2; 37 | LARVA_reparation(); 38 | } 39 | } 40 | _; 41 | } 42 | modifier LARVA_DEA_2_handle_after_transferFrom__parameters_from_to_tokens (address from, address to, uint tokens) { 43 | if ((LARVA_STATE_2 == 1) && ((transferFromPreFrom < tokens || preAllowance < tokens) && (balanceOf(msg.sender) != transferFromPreFrom || balanceOf(to) != transferFromPreTo || allowance(msg.sender, from) != preAllowance))) { 44 | LARVA_STATE_2 = 2; 45 | LARVA_reparation(); 46 | } else { 47 | if ((LARVA_STATE_2 == 1) && ((transferFromPreFrom < tokens || preAllowance < tokens) && (balanceOf(msg.sender) == transferFromPreFrom && balanceOf(to) == transferFromPreTo && allowance(msg.sender, from) == preAllowance))) { 48 | LARVA_STATE_2 = 0; 49 | } else { 50 | if ((LARVA_STATE_2 == 1) && ((transferFromPreFrom >= tokens && preAllowance >= tokens) && (balanceOf(msg.sender) != (transferFromPreFrom - tokens) || balanceOf(to) != (transferFromPreTo - tokens) || allowance(msg.sender, from) != preAllowance - tokens))) { 51 | LARVA_STATE_2 = 2; 52 | LARVA_reparation(); 53 | } else { 54 | if ((LARVA_STATE_2 == 1) && ((transferFromPreFrom >= tokens && preAllowance >= tokens) && (balanceOf(msg.sender) == (transferFromPreFrom - tokens) && balanceOf(to) == (transferFromPreTo - tokens) && allowance(msg.sender, from) == preAllowance - tokens))) { 55 | LARVA_STATE_2 = 0; 56 | } 57 | } 58 | } 59 | } 60 | _; 61 | } 62 | modifier LARVA_DEA_2_handle_before_transferFrom__parameters_from_to_tokens (address from, address to, uint tokens) { 63 | if ((LARVA_STATE_2 == 0)) { 64 | LARVA_STATE_2 = 1; 65 | { 66 | transferFromPreFrom = balanceOf(from); 67 | transferFromPreTo = balanceOf(to); 68 | preAllowance = allowance(msg.sender, from); 69 | } 70 | } else { 71 | if ((LARVA_STATE_2 == 1)) { 72 | LARVA_STATE_2 = 2; 73 | LARVA_reparation(); 74 | } 75 | } 76 | _; 77 | } 78 | modifier LARVA_DEA_1_handle_after_transfer__parameters_to_tokens (address to, uint tokens) { 79 | if ((LARVA_STATE_1 == 1) && (transferPreFrom < tokens && (balanceOf(msg.sender) != transferPreFrom || balanceOf(to) != transferPreTo))) { 80 | LARVA_STATE_1 = 2; 81 | LARVA_reparation(); 82 | } else { 83 | if ((LARVA_STATE_1 == 1) && (transferPreFrom < tokens && (balanceOf(msg.sender) == transferPreFrom && balanceOf(to) == transferPreTo))) { 84 | LARVA_STATE_1 = 0; 85 | } else { 86 | if ((LARVA_STATE_1 == 1) && (transferPreFrom >= tokens && (balanceOf(msg.sender) != (transferPreFrom - tokens) || balanceOf(to) != (transferPreTo - tokens)))) { 87 | LARVA_STATE_1 = 2; 88 | LARVA_reparation(); 89 | } else { 90 | if ((LARVA_STATE_1 == 1) && (transferPreFrom >= tokens && (balanceOf(msg.sender) == (transferPreFrom - tokens) && balanceOf(to) == (transferPreTo - tokens)))) { 91 | LARVA_STATE_1 = 0; 92 | } 93 | } 94 | } 95 | } 96 | _; 97 | } 98 | modifier LARVA_DEA_1_handle_before_transfer__parameters_to_tokens (address to, uint tokens) { 99 | if ((LARVA_STATE_1 == 0)) { 100 | LARVA_STATE_1 = 1; 101 | { 102 | transferPreFrom = balanceOf(msg.sender); 103 | transferPreTo = balanceOf(to); 104 | } 105 | } else { 106 | if ((LARVA_STATE_1 == 1)) { 107 | LARVA_STATE_1 = 2; 108 | LARVA_reparation(); 109 | } 110 | } 111 | _; 112 | } 113 | int8 LARVA_STATE_1 = 0; 114 | int8 LARVA_STATE_2 = 0; 115 | int8 LARVA_STATE_3 = 0; 116 | function LARVA_reparation () private { 117 | revert(); 118 | } 119 | uint transferPreFrom; 120 | uint transferPreTo; 121 | uint transferFromPreFrom; 122 | uint transferFromPreTo; 123 | uint preAllowance; 124 | enum LARVA_STATUS {RUNNING, STOPPED} 125 | function LARVA_EnableContract () private { 126 | LARVA_Status = LARVA_STATUS.RUNNING; 127 | } 128 | function LARVA_DisableContract () private { 129 | LARVA_Status = LARVA_STATUS.STOPPED; 130 | } 131 | LARVA_STATUS private LARVA_Status = LARVA_STATUS.STOPPED; 132 | modifier LARVA_ContractIsEnabled { 133 | require(LARVA_Status == LARVA_STATUS.RUNNING); 134 | _; 135 | } 136 | ERC20TokenImplementation impl; 137 | address owner; 138 | constructor (ERC20TokenImplementation _impl, address _owner) LARVA_Constructor public { 139 | impl = _impl; 140 | owner = _owner; 141 | } 142 | function updateImplementation (address newImpl) LARVA_ContractIsEnabled public { 143 | require(msg.sender == owner); 144 | impl = ERC20TokenImplementation(newImpl); 145 | } 146 | function totalSupply () LARVA_ContractIsEnabled public constant returns (uint) { 147 | return impl.totalSupply(); 148 | } 149 | function balanceOf (address tokenOwner) LARVA_ContractIsEnabled public constant returns (uint balance) { 150 | return impl.balanceOf(tokenOwner); 151 | } 152 | function allowance (address tokenOwner, address spender) LARVA_ContractIsEnabled public constant returns (uint remaining) { 153 | return impl.allowance(tokenOwner, spender); 154 | } 155 | function transfer (address to, uint tokens) LARVA_DEA_1_handle_after_transfer__parameters_to_tokens(to, tokens) LARVA_DEA_1_handle_before_transfer__parameters_to_tokens(to, tokens) LARVA_ContractIsEnabled public returns (bool success) { 156 | return impl.transfer(msg.sender, to, tokens); 157 | } 158 | function approve (address spender, uint tokens) LARVA_DEA_3_handle_after_approve__parameters_spender_tokens(spender, tokens) LARVA_DEA_3_handle_before_approve__parameters_spender_tokens(spender, tokens) LARVA_ContractIsEnabled public returns (bool success) { 159 | return impl.approve(msg.sender, spender, tokens); 160 | } 161 | function transferFrom (address from, address to, uint tokens) LARVA_DEA_2_handle_after_transferFrom__parameters_from_to_tokens(from, to, tokens) LARVA_DEA_2_handle_before_transferFrom__parameters_from_to_tokens(from, to, tokens) LARVA_ContractIsEnabled public returns (bool success) { 162 | return impl.transferFrom(msg.sender, from, to, tokens); 163 | } 164 | 165 | } 166 | -------------------------------------------------------------------------------- /use-cases/FixedSupplyToken/FixedSupplyToken.sol: -------------------------------------------------------------------------------- 1 | //FROM: https://theethereum.wiki/w/index.php/ERC20_Token_Standard 2 | //EDITED: Shaun Azzopardi, July 2018 3 | 4 | pragma solidity ^0.4.24; 5 | 6 | // ---------------------------------------------------------------------------- 7 | // 'FIXED' 'Example Fixed Supply Token' token contract 8 | // 9 | // Symbol : FIXED 10 | // Name : Example Fixed Supply Token 11 | // Total supply: 1,000,000.000000000000000000 12 | // Decimals : 18 13 | // 14 | // Enjoy. 15 | // 16 | // (c) BokkyPooBah / Bok Consulting Pty Ltd 2018. The MIT Licence. 17 | // ---------------------------------------------------------------------------- 18 | 19 | 20 | // ---------------------------------------------------------------------------- 21 | // Safe maths 22 | // ---------------------------------------------------------------------------- 23 | // library SafeMath { 24 | // function add(uint a, uint b) internal pure returns (uint c) { 25 | // c = a + b; 26 | // require(c >= a); 27 | // } 28 | // function sub(uint a, uint b) internal pure returns (uint c) { 29 | // require(b <= a); 30 | // c = a - b; 31 | // } 32 | // function mul(uint a, uint b) internal pure returns (uint c) { 33 | // c = a * b; 34 | // require(a == 0 || c / a == b); 35 | // } 36 | // function div(uint a, uint b) internal pure returns (uint c) { 37 | // require(b > 0); 38 | // c = a / b; 39 | // } 40 | // } 41 | 42 | 43 | // ---------------------------------------------------------------------------- 44 | // ERC Token Standard #20 Interface 45 | // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md 46 | // ---------------------------------------------------------------------------- 47 | interface ERC20TokenImplementation { 48 | function totalSupply () public constant returns (uint); 49 | function balanceOf (address tokenOwner) public constant returns (uint balance); 50 | function allowance (address tokenOwner, address spender) public constant returns (uint remaining); 51 | function transfer (address caller, address to, uint tokens) public returns (bool success); 52 | function approve (address caller, address spender, uint tokens) public returns (bool success); 53 | function transferFrom (address caller, address from, address to, uint tokens) public returns (bool success); 54 | event Transfer (address indexed from, address indexed to, uint tokens); 55 | event Approval (address indexed tokenOwner, address indexed spender, uint tokens); 56 | 57 | } 58 | 59 | 60 | 61 | // ---------------------------------------------------------------------------- 62 | // Contract function to receive approval and execute function in one call 63 | // 64 | // Borrowed from MiniMeToken 65 | // ---------------------------------------------------------------------------- 66 | contract ApproveAndCallFallBack { 67 | function receiveApproval(address from, uint256 tokens, address token, bytes data) public; 68 | } 69 | 70 | 71 | // ---------------------------------------------------------------------------- 72 | // Owned contract 73 | // ---------------------------------------------------------------------------- 74 | contract Owned { 75 | address public owner; 76 | address public newOwner; 77 | 78 | event OwnershipTransferred(address indexed _from, address indexed _to); 79 | 80 | constructor() public { 81 | owner = msg.sender; 82 | } 83 | 84 | modifier onlyOwner { 85 | require(msg.sender == owner); 86 | _; 87 | } 88 | 89 | function transferOwnership(address _newOwner) public onlyOwner { 90 | owner = _newOwner; 91 | } 92 | } 93 | 94 | 95 | // ---------------------------------------------------------------------------- 96 | // ERC20 Token, with the addition of symbol, name and decimals and a 97 | // fixed supply 98 | // ---------------------------------------------------------------------------- 99 | contract FixedSupplyToken is ERC20TokenImplementation, Owned { 100 | 101 | string public symbol; 102 | string public name; 103 | uint8 public decimals; 104 | uint _totalSupply; 105 | 106 | mapping(address => uint) balances; 107 | mapping(address => mapping(address => uint)) allowed; 108 | 109 | 110 | // ------------------------------------------------------------------------ 111 | // Constructor 112 | // ------------------------------------------------------------------------ 113 | constructor() public { 114 | symbol = "FIXED"; 115 | name = "Example Fixed Supply Token"; 116 | decimals = 18; 117 | _totalSupply = 1000000 * 10**uint(decimals); 118 | balances[owner] = _totalSupply; 119 | emit Transfer(address(0), owner, _totalSupply); 120 | } 121 | 122 | 123 | // ------------------------------------------------------------------------ 124 | // Total supply 125 | // ------------------------------------------------------------------------ 126 | function totalSupply() public view returns (uint) { 127 | return sub(_totalSupply,balances[address(0)]); 128 | } 129 | 130 | 131 | // ------------------------------------------------------------------------ 132 | // Get the token balance for account `tokenOwner` 133 | // ------------------------------------------------------------------------ 134 | function balanceOf(address tokenOwner) public view returns (uint balance) { 135 | return balances[tokenOwner]; 136 | } 137 | 138 | 139 | // ------------------------------------------------------------------------ 140 | // Transfer the balance from token owner's account to `to` account 141 | // - Owner's account must have sufficient balance to transfer 142 | // - 0 value transfers are allowed 143 | // ------------------------------------------------------------------------ 144 | function transfer(address to, uint tokens) onlyOwner public returns (bool success) { 145 | balances[msg.sender] = sub(balances[msg.sender],tokens); 146 | balances[to] = add(balances[to],tokens); 147 | emit Transfer(caller, to, tokens); 148 | return true; 149 | } 150 | 151 | 152 | // ------------------------------------------------------------------------ 153 | // Token owner can approve for `spender` to transferFrom(...) `tokens` 154 | // from the token owner's account 155 | // 156 | // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md 157 | // recommends that there are no checks for the approval double-spend attack 158 | // as this should be implemented in user interfaces 159 | // ------------------------------------------------------------------------ 160 | function approve(address caller, address spender, uint tokens) onlyOwner public returns (bool success) { 161 | allowed[caller][spender] = tokens; 162 | emit Approval(caller, spender, tokens); 163 | return true; 164 | } 165 | 166 | 167 | // ------------------------------------------------------------------------ 168 | // Transfer `tokens` from the `from` account to the `to` account 169 | // 170 | // The calling account must already have sufficient tokens approve(...)-d 171 | // for spending from the `from` account and 172 | // - From account must have sufficient balance to transfer 173 | // - Spender must have sufficient allowance to transfer 174 | // - 0 value transfers are allowed 175 | // ------------------------------------------------------------------------ 176 | function transferFrom(address caller, address from, address to, uint tokens) onlyOwner public returns (bool success) { 177 | balances[from] = sub(balances[from], tokens); 178 | allowed[from][caller] = sub(allowed[from][caller], tokens); 179 | balances[to] = add(balances[to], tokens); 180 | emit Transfer(from, to, tokens); 181 | return true; 182 | } 183 | 184 | 185 | // ------------------------------------------------------------------------ 186 | // Returns the amount of tokens approved by the owner that can be 187 | // transferred to the spender's account 188 | // ------------------------------------------------------------------------ 189 | function allowance(address tokenOwner, address spender) public view returns (uint remaining) { 190 | return allowed[tokenOwner][spender]; 191 | } 192 | 193 | 194 | // ------------------------------------------------------------------------ 195 | // Token owner can approve for `spender` to transferFrom(...) `tokens` 196 | // from the token owner's account. The `spender` contract function 197 | // `receiveApproval(...)` is then executed 198 | // ------------------------------------------------------------------------ 199 | function approveAndCall(address caller, address spender, uint tokens, bytes data) onlyOwner public returns (bool success) { 200 | allowed[caller][spender] = tokens; 201 | emit Approval(caller, spender, tokens); 202 | ApproveAndCallFallBack(spender).receiveApproval(caller, tokens, this, data); 203 | return true; 204 | } 205 | 206 | 207 | // ------------------------------------------------------------------------ 208 | // Don't accept ETH 209 | // ------------------------------------------------------------------------ 210 | function () public payable { 211 | revert(); 212 | } 213 | 214 | 215 | // ------------------------------------------------------------------------ 216 | // Owner can transfer out any accidentally sent ERC20 tokens 217 | // ------------------------------------------------------------------------ 218 | function transferAnyERC20Token(address tokenAddress, uint tokens) public onlyOwner returns (bool success) { 219 | return ERC20TokenImplementation(tokenAddress).transfer(msg.sender, owner, tokens); 220 | } 221 | 222 | function add(uint a, uint b) internal view returns (uint c) { 223 | c = a + b; 224 | require(c >= a); 225 | } 226 | function sub(uint a, uint b) internal view returns (uint c) { 227 | require(b <= a); 228 | c = a - b; 229 | } 230 | function mul(uint a, uint b) internal view returns (uint c) { 231 | c = a * b; 232 | require(a == 0 || c / a == b); 233 | } 234 | function div(uint a, uint b) internal view returns (uint c) { 235 | require(b > 0); 236 | c = a / b; 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /use-cases/FixedSupplyToken/FixedSupplyTokenSpec.dea: -------------------------------------------------------------------------------- 1 | monitor FixedSupplyToken{ 2 | 3 | declarations{ 4 | uint currentTokens; 5 | } 6 | 7 | initialisation{ 8 | LARVA_EnableContract(); 9 | } 10 | 11 | reparation{ 12 | revert(); 13 | } 14 | 15 | //This property checks that any addition to the balance must be coupled immediately with a subtraction, 16 | //ensuring tokens are only moved around, while ensuring that any change is immediately (modulo one step) reflected in the total sum. 17 | DEA AdditionOfBalanceMustBeAccompaniedBySubstituion{ 18 | states{ 19 | Before: initial; 20 | StartTransfer; 21 | SubAfterAdd; 22 | AddAfterSub; 23 | EndTransfer; 24 | UnMatchedModification: bad; 25 | } 26 | 27 | transitions{ 28 | Before -[before(transfer(caller, to, tokens)) | ~> currentTokens = tokens;]-> StartTransfer; 29 | 30 | StartTransfer -[after(add(a, tokens)) | currentTokens == tokens]-> SubAfterAdd; 31 | StartTransfer -[after(add(a, tokens)) | currentTokens != tokens]-> UnMatchedModification; 32 | StartTransfer -[after(sub(a, tokens)) | currentTokens == tokens]-> AddAfterSub; 33 | StartTransfer -[after(sub(a, tokens)) | currentTokens != tokens]-> UnMatchedModification; 34 | 35 | SubAfterAdd -[after(sub(a, tokens)) | currentTokens == tokens]-> EndTransfer; 36 | SubAfterAdd -[after(sub(a, tokens)) | currentTokens != tokens]-> UnMatchedModification; 37 | SubAfterAdd -[after(add(a, tokens))]-> UnMatchedModification; 38 | 39 | SubAfterAdd -[after(add(a, tokens)) | currentTokens == tokens]-> EndTransfer; 40 | SubAfterAdd -[after(add(a, tokens)) | currentTokens != tokens]-> UnMatchedModification; 41 | SubAfterAdd -[after(sub(a, tokens))]-> UnMatchedModification; 42 | 43 | EndTransfer -[after(transfer(caller, to, tokens)) | ~> currentTokens = 0;]-> Before; 44 | SubAfterAdd -[after(transfer(caller, to, tokens))]-> UnMatchedModification; 45 | AddAfterSub -[after(transfer(caller, to, tokens))]-> UnMatchedModification; 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /use-cases/FixedSupplyToken/MonitoredFixedSupplyToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | interface ERC20TokenImplementation { 3 | function totalSupply () public constant returns (uint); 4 | function balanceOf (address tokenOwner) public constant returns (uint balance); 5 | function allowance (address tokenOwner, address spender) public constant returns (uint remaining); 6 | function transfer (address caller, address to, uint tokens) public returns (bool success); 7 | function approve (address caller, address spender, uint tokens) public returns (bool success); 8 | function transferFrom (address caller, address from, address to, uint tokens) public returns (bool success); 9 | event Transfer (address indexed from, address indexed to, uint tokens); 10 | event Approval (address indexed tokenOwner, address indexed spender, uint tokens); 11 | 12 | } 13 | contract ApproveAndCallFallBack { 14 | function receiveApproval (address from, uint256 tokens, address token, bytes data) public; 15 | 16 | } 17 | contract Owned { 18 | address public owner; 19 | address public newOwner; 20 | event OwnershipTransferred (address indexed _from, address indexed _to); 21 | constructor () public { 22 | owner = msg.sender; 23 | } 24 | modifier onlyOwner { 25 | require(msg.sender == owner); 26 | _; 27 | } 28 | function transferOwnership (address _newOwner) public onlyOwner { 29 | owner = _newOwner; 30 | } 31 | 32 | } 33 | contract LARVA_FixedSupplyToken is ERC20TokenImplementation, Owned { 34 | modifier LARVA_Constructor { 35 | _; 36 | { 37 | LARVA_EnableContract(); 38 | } 39 | } 40 | modifier LARVA_DEA_1_handle_after_transfer__parameters_caller_to_tokens (address caller, uint to, undefined tokens) { 41 | if ((LARVA_STATE_1 == 4)) { 42 | LARVA_STATE_1 = 0; 43 | currentTokens = 0; 44 | } else { 45 | if ((LARVA_STATE_1 == 2)) { 46 | LARVA_STATE_1 = 5; 47 | LARVA_reparation(); 48 | } else { 49 | if ((LARVA_STATE_1 == 3)) { 50 | LARVA_STATE_1 = 5; 51 | LARVA_reparation(); 52 | } 53 | } 54 | } 55 | _; 56 | } 57 | modifier LARVA_DEA_1_handle_after_sub__parameters_a_tokens (uint a, uint tokens) { 58 | if ((LARVA_STATE_1 == 1) && (currentTokens == tokens)) { 59 | LARVA_STATE_1 = 3; 60 | } else { 61 | if ((LARVA_STATE_1 == 1) && (currentTokens != tokens)) { 62 | LARVA_STATE_1 = 5; 63 | LARVA_reparation(); 64 | } else { 65 | if ((LARVA_STATE_1 == 2) && (currentTokens == tokens)) { 66 | LARVA_STATE_1 = 4; 67 | } else { 68 | if ((LARVA_STATE_1 == 2) && (currentTokens != tokens)) { 69 | LARVA_STATE_1 = 5; 70 | LARVA_reparation(); 71 | } else { 72 | if ((LARVA_STATE_1 == 2)) { 73 | LARVA_STATE_1 = 5; 74 | LARVA_reparation(); 75 | } 76 | } 77 | } 78 | } 79 | } 80 | _; 81 | } 82 | modifier LARVA_DEA_1_handle_after_add__parameters_a_tokens (uint a, uint tokens) { 83 | if ((LARVA_STATE_1 == 1) && (currentTokens == tokens)) { 84 | LARVA_STATE_1 = 2; 85 | } else { 86 | if ((LARVA_STATE_1 == 1) && (currentTokens != tokens)) { 87 | LARVA_STATE_1 = 5; 88 | LARVA_reparation(); 89 | } else { 90 | if ((LARVA_STATE_1 == 2)) { 91 | LARVA_STATE_1 = 5; 92 | LARVA_reparation(); 93 | } else { 94 | if ((LARVA_STATE_1 == 2) && (currentTokens == tokens)) { 95 | LARVA_STATE_1 = 4; 96 | } else { 97 | if ((LARVA_STATE_1 == 2) && (currentTokens != tokens)) { 98 | LARVA_STATE_1 = 5; 99 | LARVA_reparation(); 100 | } 101 | } 102 | } 103 | } 104 | } 105 | _; 106 | } 107 | modifier LARVA_DEA_1_handle_before_transfer__parameters_caller_to_tokens (address caller, uint to, undefined tokens) { 108 | if ((LARVA_STATE_1 == 0)) { 109 | LARVA_STATE_1 = 1; 110 | currentTokens = tokens; 111 | } 112 | _; 113 | } 114 | int8 LARVA_STATE_1 = 0; 115 | function LARVA_reparation () private { 116 | revert(); 117 | } 118 | uint currentTokens; 119 | enum LARVA_STATUS {RUNNING, STOPPED} 120 | function LARVA_EnableContract () private { 121 | LARVA_Status = LARVA_STATUS.RUNNING; 122 | } 123 | function LARVA_DisableContract () private { 124 | LARVA_Status = LARVA_STATUS.STOPPED; 125 | } 126 | LARVA_STATUS private LARVA_Status = LARVA_STATUS.STOPPED; 127 | modifier LARVA_ContractIsEnabled { 128 | require(LARVA_Status == LARVA_STATUS.RUNNING); 129 | _; 130 | } 131 | string public symbol; 132 | string public name; 133 | uint8 public decimals; 134 | uint _totalSupply; 135 | mapping (address => uint) balances; 136 | mapping (address => mapping (address => uint)) allowed; 137 | constructor () LARVA_Constructor public { 138 | symbol = "FIXED"; 139 | name = "Example Fixed Supply Token"; 140 | decimals = 18; 141 | _totalSupply = 1000000 * 10 ** uint(decimals); 142 | balances[owner] = _totalSupply; 143 | emit Transfer(address(0), owner, _totalSupply); 144 | } 145 | function totalSupply () LARVA_ContractIsEnabled public view returns (uint) { 146 | return sub(_totalSupply, balances[address(0)]); 147 | } 148 | function balanceOf (address tokenOwner) LARVA_ContractIsEnabled public view returns (uint balance) { 149 | return balances[tokenOwner]; 150 | } 151 | function transfer (address to, uint tokens) LARVA_DEA_1_handle_after_transfer__parameters_caller_to_tokens(to, tokens) LARVA_DEA_1_handle_before_transfer__parameters_caller_to_tokens(to, tokens) LARVA_ContractIsEnabled onlyOwner public returns (bool success) { 152 | balances[msg.sender] = sub(balances[msg.sender], tokens); 153 | balances[to] = add(balances[to], tokens); 154 | emit Transfer(caller, to, tokens); 155 | return true; 156 | } 157 | function approve (address caller, address spender, uint tokens) LARVA_ContractIsEnabled onlyOwner public returns (bool success) { 158 | allowed[caller][spender] = tokens; 159 | emit Approval(caller, spender, tokens); 160 | return true; 161 | } 162 | function transferFrom (address caller, address from, address to, uint tokens) LARVA_ContractIsEnabled onlyOwner public returns (bool success) { 163 | balances[from] = sub(balances[from], tokens); 164 | allowed[from][caller] = sub(allowed[from][caller], tokens); 165 | balances[to] = add(balances[to], tokens); 166 | emit Transfer(from, to, tokens); 167 | return true; 168 | } 169 | function allowance (address tokenOwner, address spender) LARVA_ContractIsEnabled public view returns (uint remaining) { 170 | return allowed[tokenOwner][spender]; 171 | } 172 | function approveAndCall (address caller, address spender, uint tokens, bytes data) LARVA_ContractIsEnabled onlyOwner public returns (bool success) { 173 | allowed[caller][spender] = tokens; 174 | emit Approval(caller, spender, tokens); 175 | ApproveAndCallFallBack(spender).receiveApproval(caller, tokens, this, data); 176 | return true; 177 | } 178 | function () public payable { 179 | revert(); 180 | } 181 | function transferAnyERC20Token (address tokenAddress, uint tokens) LARVA_ContractIsEnabled public onlyOwner returns (bool success) { 182 | return ERC20TokenImplementation(tokenAddress).transfer(msg.sender, owner, tokens); 183 | } 184 | function add (uint a, uint b) LARVA_DEA_1_handle_after_add__parameters_a_tokens(a, b) LARVA_ContractIsEnabled internal view returns (uint c) { 185 | c = a + b; 186 | require(c >= a); 187 | } 188 | function sub (uint a, uint b) LARVA_DEA_1_handle_after_sub__parameters_a_tokens(a, b) LARVA_ContractIsEnabled internal view returns (uint c) { 189 | require(b <= a); 190 | c = a - b; 191 | } 192 | function mul (uint a, uint b) LARVA_ContractIsEnabled internal view returns (uint c) { 193 | c = a * b; 194 | require(a == 0 || c / a == b); 195 | } 196 | function div (uint a, uint b) LARVA_ContractIsEnabled internal view returns (uint c) { 197 | require(b > 0); 198 | c = a / b; 199 | } 200 | 201 | } 202 | -------------------------------------------------------------------------------- /use-cases/InsuredCourierService/InsuredCourierService.sol: -------------------------------------------------------------------------------- 1 | contract InsuredCourierService{ 2 | bool ordered; 3 | bool delivered; 4 | uint value = 1 ether; 5 | address buyer; 6 | 7 | function order(uint _eta, address _buyer, string memory _address) payable public{ 8 | require(!ordered && msg.value == value); 9 | ordered = true; 10 | buyer = _buyer; 11 | } 12 | 13 | function deliver(address _signer, string memory _address) public{ 14 | require(!delivered); 15 | delivered = true; 16 | } 17 | 18 | function complain() public{ 19 | require(msg.sender == buyer && !delivered); 20 | } 21 | } -------------------------------------------------------------------------------- /use-cases/InsuredCourierService/InsuredCourierServiceSpec.dea: -------------------------------------------------------------------------------- 1 | monitor InsuredCourierService { 2 | 3 | declarations { 4 | uint orderedTime; 5 | uint minimumInsuredDeliveryTime = 24*30 hours; 6 | 7 | address payable private insurer_address; 8 | address payable private customer; 9 | function getStake() private returns(uint) { return value; } 10 | function getInsurer() private returns(address payable) { return insurer_address; } 11 | function getInsured() private returns(address payable) { return customer; } 12 | 13 | enum STAKE_STATUS { UNPAID, PAID } 14 | STAKE_STATUS private stake_status = STAKE_STATUS.UNPAID; 15 | 16 | function payStake() payable public{ 17 | require (stake_status == STAKE_STATUS.UNPAID); 18 | require (msg.value == getStake()); 19 | require (msg.sender == getInsurer()); 20 | stake_status = STAKE_STATUS.PAID; 21 | LARVA_EnableContract(); 22 | } 23 | } 24 | 25 | initialisation { 26 | insurer_address = msg.sender; 27 | } 28 | 29 | reparation { 30 | getInsured().transfer(getStake()); 31 | LARVA_DisableContract(); 32 | } 33 | 34 | satisfaction { 35 | getInsurer().transfer(getStake()); 36 | } 37 | 38 | DEA UnDelivered{ 39 | states{ 40 | Start: initial; 41 | Ordered; 42 | Delivered: accept; 43 | Undelivered: bad; 44 | } 45 | 46 | transitions{ 47 | Start -[after(order) | ~> orderedTime = now;]-> Ordered; 48 | Ordered -[after(deliver) | now - orderedTime <= minimumInsuredDeliveryTime]-> Delivered; 49 | Ordered -[after(deliver) | now - orderedTime >= minimumInsuredDeliveryTime]-> Undelivered; 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /use-cases/InsuredCourierService/MonitoredInsuredCourierService.sol: -------------------------------------------------------------------------------- 1 | contract LARVA_InsuredCourierService { 2 | modifier LARVA_Constructor { 3 | _; 4 | { 5 | insurer_address = msg.sender; 6 | } 7 | } 8 | modifier LARVA_DEA_1_handle_after_order__no_parameters { 9 | if ((LARVA_STATE_1 == 0)) { 10 | LARVA_STATE_1 = 1; 11 | orderedTime = now; 12 | } 13 | _; 14 | } 15 | modifier LARVA_DEA_1_handle_after_deliver__no_parameters { 16 | if ((LARVA_STATE_1 == 1) && (now - orderedTime <= minimumInsuredDeliveryTime)) { 17 | LARVA_STATE_1 = 2; 18 | LARVA_satisfaction(); 19 | } else { 20 | if ((LARVA_STATE_1 == 1) && (now - orderedTime >= minimumInsuredDeliveryTime)) { 21 | LARVA_STATE_1 = 3; 22 | LARVA_reparation(); 23 | } 24 | } 25 | _; 26 | } 27 | int8 LARVA_STATE_1 = 0; 28 | function LARVA_reparation () private { 29 | getInsured().transfer(getStake()); 30 | LARVA_DisableContract(); 31 | } 32 | function LARVA_satisfaction () private { 33 | getInsurer().transfer(getStake()); 34 | } 35 | uint orderedTime; 36 | uint minimumInsuredDeliveryTime = 24 * 30 hours; 37 | address payable private insurer_address; 38 | address payable private customer; 39 | function getStake () private returns (uint) { 40 | return value; 41 | } 42 | function getInsurer () private returns (address payable) { 43 | return insurer_address; 44 | } 45 | function getInsured () private returns (address payable) { 46 | return customer; 47 | } 48 | enum STAKE_STATUS {UNPAID, PAID} 49 | STAKE_STATUS private stake_status = STAKE_STATUS.UNPAID; 50 | function payStake () payable public { 51 | require(stake_status == STAKE_STATUS.UNPAID); 52 | require(msg.value == getStake()); 53 | require(msg.sender == getInsurer()); 54 | stake_status = STAKE_STATUS.PAID; 55 | LARVA_EnableContract(); 56 | } 57 | constructor () LARVA_Constructor public { 58 | } 59 | enum LARVA_STATUS {RUNNING, STOPPED} 60 | function LARVA_EnableContract () private { 61 | LARVA_Status = LARVA_STATUS.RUNNING; 62 | } 63 | function LARVA_DisableContract () private { 64 | LARVA_Status = LARVA_STATUS.STOPPED; 65 | } 66 | LARVA_STATUS private LARVA_Status = LARVA_STATUS.STOPPED; 67 | modifier LARVA_ContractIsEnabled { 68 | require(LARVA_Status == LARVA_STATUS.RUNNING); 69 | _; 70 | } 71 | bool ordered; 72 | bool delivered; 73 | uint value = 1 ether; 74 | address buyer; 75 | function order (uint _eta, address _buyer, string memory _address) LARVA_DEA_1_handle_after_order__no_parameters LARVA_ContractIsEnabled payable public { 76 | require(!ordered && msg.value == value); 77 | ordered = true; 78 | buyer = _buyer; 79 | } 80 | function deliver (address _signer, string memory _address) LARVA_DEA_1_handle_after_deliver__no_parameters LARVA_ContractIsEnabled public { 81 | require(!delivered); 82 | delivered = true; 83 | } 84 | function complain () LARVA_ContractIsEnabled public { 85 | require(msg.sender == buyer && !delivered); 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /use-cases/MultiOwnersWallet/MultiOwnersWallet.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.11; 2 | 3 | 4 | contract MultiOwners { 5 | mapping(address => bool) public owners; 6 | address[] ownerList; 7 | uint ownerCount; 8 | mapping(uint => mapping(address => bool)) actionSignOffs; 9 | 10 | 11 | constructor(address[] memory _owners) public{ 12 | for(uint i = 0; i < _owners.length; i++){ 13 | owners[_owners[i]] = true; 14 | } 15 | 16 | ownerList = _owners; 17 | ownerCount = ownerList.length; 18 | } 19 | 20 | modifier anyOwner { 21 | require(owners[msg.sender]); 22 | _; 23 | } 24 | 25 | modifier allOwners (uint _id){ 26 | require(owners[msg.sender]); 27 | actionSignOffs[_id][msg.sender] = true; 28 | 29 | for(uint i = 0 ; i < ownerList.length; i++){ 30 | if(ownerList[i] != address(0) && !actionSignOffs[_id][ownerList[i]]){ 31 | return; 32 | } 33 | } 34 | _; 35 | } 36 | 37 | mapping(address => mapping(address => bool)) votesToRemove; 38 | mapping(address => address[]) votesToRemoveKeys; 39 | 40 | function removeOwner(address _address) anyOwner public{ 41 | votesToRemove[_address][msg.sender] = true; 42 | votesToRemoveKeys[_address].push(msg.sender); 43 | 44 | uint countInFavour = 0; 45 | uint totalCount = ownerCount; 46 | 47 | for(uint i = 0; i < totalCount; i++){ 48 | if(votesToRemove[_address][votesToRemoveKeys[_address][i]]){ 49 | countInFavour++; 50 | } 51 | } 52 | 53 | uint limit = 2*totalCount/3; 54 | 55 | if(countInFavour >= limit){ 56 | owners[_address] = false; 57 | ownerCount--; 58 | for(uint i = 0; i < ownerList.length; i++){ 59 | if(ownerList[i] != address(0) && ownerList[i] == _address){ 60 | ownerList[i] = address(0); 61 | } 62 | } 63 | } 64 | } 65 | 66 | mapping(uint => address payable) idTo; 67 | mapping(uint => uint) idVal; 68 | uint id; 69 | 70 | function proposeTransaction(address payable _to, uint _val) public anyOwner{ 71 | idTo[id] = _to; 72 | idVal[id] = _val; 73 | id++; 74 | } 75 | 76 | function transfer(uint _id) allOwners(_id) public{ 77 | idTo[_id].transfer(idVal[_id]); 78 | } 79 | 80 | function () external payable {} 81 | } -------------------------------------------------------------------------------- /use-cases/MultiOwnersWallet/MultiOwnersWalletSpec.dea: -------------------------------------------------------------------------------- 1 | monitor MultiOwners { 2 | 3 | declarations{ 4 | mapping(uint => address) idRequestedBy; 5 | mapping(address => mapping(address => bool)) votes; 6 | } 7 | 8 | initialisation{ 9 | LARVA_EnableContract(); 10 | } 11 | 12 | reparation { 13 | revert(); 14 | } 15 | 16 | DEA IgnoreTransactionsStartedByExOwners{ 17 | states{ 18 | BeforeTransfer: initial; 19 | BadTransfer: bad; 20 | } 21 | 22 | transitions{ 23 | BeforeTransfer -[after(proposeTransaction(_to,_val)) | ~> idRequestedBy[--id] = msg.sender;]-> BeforeTransfer; 24 | BeforeTransfer -[before(transfer(_id)) | !owners[idRequestedBy[id]]]-> BadTransfer; 25 | } 26 | } 27 | 28 | DEA NeutraliseDoubleVote{ 29 | states{ 30 | BeforeVote: initial; 31 | DoubleVote: bad; 32 | } 33 | 34 | transitions{ 35 | BeforeVote -[after(removeOwner(_address)) | ~> votes[_address][msg.sender] = true;]-> BeforeVote; 36 | BeforeVote -[before(removeOwner(_address)) | votes[_address][msg.sender]]-> DoubleVote; 37 | } 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /use-cases/MultiOwnersWallet/monitoredMultiOwnersWallet.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.11; 2 | contract LARVA_MultiOwners { 3 | modifier LARVA_Constructor { 4 | _; 5 | { 6 | LARVA_EnableContract(); 7 | } 8 | } 9 | modifier LARVA_DEA_2_handle_after_removeOwner__parameters__address (address _address) { 10 | if ((LARVA_STATE_2 == 0)) { 11 | LARVA_STATE_2 = 0; 12 | votes[_address][msg.sender] = true; 13 | } 14 | _; 15 | } 16 | modifier LARVA_DEA_2_handle_before_removeOwner__parameters__address (address _address) { 17 | if ((LARVA_STATE_2 == 0) && (votes[_address][msg.sender])) { 18 | LARVA_STATE_2 = 1; 19 | LARVA_reparation(); 20 | } 21 | _; 22 | } 23 | modifier LARVA_DEA_1_handle_after_proposeTransaction__parameters__to__val (address payable _to, uint _val) { 24 | if ((LARVA_STATE_1 == 0)) { 25 | LARVA_STATE_1 = 0; 26 | idRequestedBy[--id] = msg.sender; 27 | } 28 | _; 29 | } 30 | modifier LARVA_DEA_1_handle_before_transfer__parameters__id (uint _id) { 31 | if ((LARVA_STATE_1 == 0) && (!owners[idRequestedBy[id]])) { 32 | LARVA_STATE_1 = 1; 33 | LARVA_reparation(); 34 | } 35 | _; 36 | } 37 | int8 LARVA_STATE_1 = 0; 38 | int8 LARVA_STATE_2 = 0; 39 | function LARVA_reparation () private { 40 | revert(); 41 | } 42 | mapping (uint => address) idRequestedBy; 43 | mapping (address => mapping (address => bool)) votes; 44 | enum LARVA_STATUS {RUNNING, STOPPED} 45 | function LARVA_EnableContract () private { 46 | LARVA_Status = LARVA_STATUS.RUNNING; 47 | } 48 | function LARVA_DisableContract () private { 49 | LARVA_Status = LARVA_STATUS.STOPPED; 50 | } 51 | LARVA_STATUS private LARVA_Status = LARVA_STATUS.STOPPED; 52 | modifier LARVA_ContractIsEnabled { 53 | require(LARVA_Status == LARVA_STATUS.RUNNING); 54 | _; 55 | } 56 | mapping (address => bool) public owners; 57 | address[] ownerList; 58 | uint ownerCount; 59 | mapping (uint => mapping (address => bool)) actionSignOffs; 60 | constructor (address[] memory _owners) LARVA_Constructor public { 61 | for (uint i = 0; i < _owners.length; i++) { 62 | owners[_owners[i]] = true; 63 | } 64 | ownerList = _owners; 65 | ownerCount = ownerList.length; 66 | } 67 | modifier anyOwner { 68 | require(owners[msg.sender]); 69 | _; 70 | } 71 | modifier allOwners (uint _id) { 72 | require(owners[msg.sender]); 73 | actionSignOffs[_id][msg.sender] = true; 74 | for (uint i = 0; i < ownerList.length; i++) { 75 | if (ownerList[i] != address(0) && !actionSignOffs[_id][ownerList[i]]) { 76 | return; 77 | } 78 | } 79 | _; 80 | } 81 | mapping (address => mapping (address => bool)) votesToRemove; 82 | mapping (address => address[]) votesToRemoveKeys; 83 | function removeOwner (address _address) LARVA_DEA_2_handle_after_removeOwner__parameters__address(_address) LARVA_DEA_2_handle_before_removeOwner__parameters__address(_address) LARVA_ContractIsEnabled anyOwner public { 84 | votesToRemove[_address][msg.sender] = true; 85 | votesToRemoveKeys[_address].push(msg.sender); 86 | uint countInFavour = 0; 87 | uint totalCount = ownerCount; 88 | for (uint i = 0; i < totalCount; i++) { 89 | if (votesToRemove[_address][votesToRemoveKeys[_address][i]]) { 90 | countInFavour++; 91 | } 92 | } 93 | uint limit = 2 * totalCount / 3; 94 | if (countInFavour >= limit) { 95 | owners[_address] = false; 96 | (ownerCount)--; 97 | for (uint i = 0; i < ownerList.length; i++) { 98 | if (ownerList[i] != address(0) && ownerList[i] == _address) { 99 | ownerList[i] = address(0); 100 | } 101 | } 102 | } 103 | } 104 | mapping (uint => address payable) idTo; 105 | mapping (uint => uint) idVal; 106 | uint id; 107 | function proposeTransaction (address payable _to, uint _val) LARVA_DEA_1_handle_after_proposeTransaction__parameters__to__val(_to, _val) LARVA_ContractIsEnabled public anyOwner { 108 | idTo[id] = _to; 109 | idVal[id] = _val; 110 | id++; 111 | } 112 | function transfer (uint _id) LARVA_DEA_1_handle_before_transfer__parameters__id(_id) LARVA_ContractIsEnabled allOwners(_id) public { 113 | idTo[_id].transfer(idVal[_id]); 114 | } 115 | function () external payable { 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /use-cases/Procurement/MonitoredProcurement.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.15; 2 | contract LARVA_Procurement { 3 | modifier LARVA_Constructor { 4 | _; 5 | { 6 | mediator = address(uint160(msg.sender)); 7 | LARVA_EnableContract(); 8 | } 9 | } 10 | modifier LARVA_DEA_2_handle_after_assignment_minimumItemsToBeOrdered { 11 | _; 12 | if ((LARVA_STATE_2 == 0) && (LARVA_previous_minimumItemsToBeOrdered != minimumItemsToBeOrdered)) { 13 | LARVA_STATE_2 = 1; 14 | LARVA_reparation(); 15 | } 16 | } 17 | modifier LARVA_DEA_2_handle_after_assignment_maximumItemsToBeOrdered { 18 | _; 19 | if ((LARVA_STATE_2 == 0) && (LARVA_previous_minimumItemsToBeOrdered != minimumItemsToBeOrdered)) { 20 | LARVA_STATE_2 = 1; 21 | LARVA_reparation(); 22 | } 23 | } 24 | modifier LARVA_DEA_2_handle_after_terminateContract__parameters_ () { 25 | if ((LARVA_STATE_2 == 0) && (orderCount < minimumItemsToBeOrdered || orderCount > maximumItemsToBeOrdered)) { 26 | LARVA_STATE_2 = 2; 27 | LARVA_reparation(); 28 | } else { 29 | if ((LARVA_STATE_2 == 0) && (orderCount >= minimumItemsToBeOrdered && orderCount <= maximumItemsToBeOrdered)) { 30 | LARVA_STATE_2 = 3; 31 | } 32 | } 33 | _; 34 | } 35 | modifier LARVA_DEA_2_handle_after_createOrder__parameters__orderNumber__orderSize__orderDeliveryTimeLeft (uint8 _orderNumber, uint8 _orderSize, uint _orderDeliveryTimeLeft) { 36 | if ((LARVA_STATE_2 == 0)) { 37 | LARVA_STATE_2 = 0; 38 | orderCount += _orderNumber; 39 | } 40 | _; 41 | } 42 | modifier LARVA_DEA_1_handle_after_terminateContract__no_parameters { 43 | if ((LARVA_STATE_1 == 0) && (this.balance != 0)) { 44 | LARVA_STATE_1 = 1; 45 | enoughItemsOrderedBadStateReached = true; 46 | LARVA_reparation(); 47 | } else { 48 | if ((LARVA_STATE_1 == 0) && (this.balance == 0)) { 49 | LARVA_STATE_1 = 2; 50 | } 51 | } 52 | _; 53 | } 54 | int8 LARVA_STATE_1 = 0; 55 | int8 LARVA_STATE_2 = 0; 56 | function LARVA_set_minimumItemsToBeOrdered_pre (uint _minimumItemsToBeOrdered) LARVA_DEA_2_handle_after_assignment_minimumItemsToBeOrdered public returns (uint) { 57 | LARVA_previous_minimumItemsToBeOrdered = minimumItemsToBeOrdered; 58 | minimumItemsToBeOrdered = _minimumItemsToBeOrdered; 59 | return LARVA_previous_minimumItemsToBeOrdered; 60 | } 61 | function LARVA_set_minimumItemsToBeOrdered_post (uint _minimumItemsToBeOrdered) LARVA_DEA_2_handle_after_assignment_minimumItemsToBeOrdered public returns (uint) { 62 | LARVA_previous_minimumItemsToBeOrdered = minimumItemsToBeOrdered; 63 | minimumItemsToBeOrdered = _minimumItemsToBeOrdered; 64 | return minimumItemsToBeOrdered; 65 | } 66 | uint private LARVA_previous_minimumItemsToBeOrdered; 67 | function LARVA_set_maximumItemsToBeOrdered_pre (uint _maximumItemsToBeOrdered) LARVA_DEA_2_handle_after_assignment_maximumItemsToBeOrdered public returns (uint) { 68 | LARVA_previous_maximumItemsToBeOrdered = maximumItemsToBeOrdered; 69 | maximumItemsToBeOrdered = _maximumItemsToBeOrdered; 70 | return LARVA_previous_maximumItemsToBeOrdered; 71 | } 72 | function LARVA_set_maximumItemsToBeOrdered_post (uint _maximumItemsToBeOrdered) LARVA_DEA_2_handle_after_assignment_maximumItemsToBeOrdered public returns (uint) { 73 | LARVA_previous_maximumItemsToBeOrdered = maximumItemsToBeOrdered; 74 | maximumItemsToBeOrdered = _maximumItemsToBeOrdered; 75 | return maximumItemsToBeOrdered; 76 | } 77 | uint private LARVA_previous_maximumItemsToBeOrdered; 78 | function LARVA_reparation () private { 79 | enoughItemsOrderedBadStateReached?mediator.transfer(this.balance):(); 80 | } 81 | address mediator; 82 | uint orderCount; 83 | bool enoughItemsOrderedBadStateReached; 84 | enum LARVA_STATUS {RUNNING, STOPPED} 85 | function LARVA_EnableContract () private { 86 | LARVA_Status = LARVA_STATUS.RUNNING; 87 | } 88 | function LARVA_DisableContract () private { 89 | LARVA_Status = LARVA_STATUS.STOPPED; 90 | } 91 | LARVA_STATUS private LARVA_Status = LARVA_STATUS.STOPPED; 92 | modifier LARVA_ContractIsEnabled { 93 | require(LARVA_Status == LARVA_STATUS.RUNNING); 94 | _; 95 | } 96 | enum ContractStatus {Proposed, Open, Closed} 97 | enum OrderStatus {Ordered, Delivered} 98 | struct Order { 99 | bool exists; 100 | uint cost; 101 | OrderStatus status; 102 | uint deliveryTimeDue; 103 | } 104 | address public seller; 105 | address public buyer; 106 | uint private minimumItemsToBeOrdered; 107 | uint private maximumItemsToBeOrdered; 108 | uint public costPerUnit; 109 | uint public performanceGuarantee; 110 | uint public endOfContractTimestamp; 111 | ContractStatus public contractStatus; 112 | uint8 public itemsOrderedCount; 113 | uint public moneyLeftInContract; 114 | mapping (uint8 => Order) public orders; 115 | uint8 public pendingOrderCount; 116 | uint public pendingOrderCost; 117 | uint public lateOrdersCount; 118 | uint public inTimeOrdersCount; 119 | modifier bySeller { 120 | require(msg.sender == seller); 121 | _; 122 | } 123 | modifier byBuyer { 124 | require(msg.sender == buyer); 125 | _; 126 | } 127 | function LARVA_Procurement (address _seller, address _buyer, uint _minimumItemsToBeOrdered, uint _maximumItemsToBeOrdered, uint _costPerUnit, uint _performanceGuarantee, uint _contractDuration) LARVA_Constructor public payable { 128 | require(msg.value >= _costPerUnit * _minimumItemsToBeOrdered); 129 | seller = _seller; 130 | buyer = _buyer; 131 | minimumItemsToBeOrdered = _minimumItemsToBeOrdered; 132 | maximumItemsToBeOrdered = _maximumItemsToBeOrdered; 133 | costPerUnit = _costPerUnit; 134 | endOfContractTimestamp = now + _contractDuration; 135 | performanceGuarantee = _performanceGuarantee; 136 | contractStatus = ContractStatus.Proposed; 137 | itemsOrderedCount = 0; 138 | moneyLeftInContract = msg.value; 139 | pendingOrderCount = 0; 140 | pendingOrderCost = 0; 141 | lateOrdersCount = 0; 142 | inTimeOrdersCount = 0; 143 | } 144 | function acceptContract () LARVA_ContractIsEnabled public payable bySeller { 145 | require(msg.value >= performanceGuarantee); 146 | contractStatus = ContractStatus.Open; 147 | } 148 | function createOrder (uint8 _orderNumber, uint8 _orderSize, uint _orderDeliveryTimeLeft) LARVA_DEA_2_handle_after_createOrder__parameters__orderNumber__orderSize__orderDeliveryTimeLeft(_orderNumber, _orderSize, _orderDeliveryTimeLeft) LARVA_ContractIsEnabled public payable byBuyer { 149 | require(!orders[_orderNumber].exists); 150 | require(itemsOrderedCount + _orderSize <= maximumItemsToBeOrdered); 151 | require(now + _orderDeliveryTimeLeft <= endOfContractTimestamp); 152 | uint orderCost = _orderSize * costPerUnit; 153 | moneyLeftInContract += msg.value; 154 | require(orderCost <= moneyLeftInContract); 155 | moneyLeftInContract -= orderCost; 156 | itemsOrderedCount += _orderSize; 157 | pendingOrderCount++; 158 | pendingOrderCost += orderCost; 159 | orders[_orderNumber] = Order(true, orderCost, OrderStatus.Ordered, now + _orderDeliveryTimeLeft); 160 | } 161 | function deliveryMade (uint8 _orderNumber) LARVA_ContractIsEnabled public byBuyer { 162 | Order memory order = orders[_orderNumber]; 163 | require(order.exists && order.status == OrderStatus.Ordered); 164 | order.status = OrderStatus.Delivered; 165 | if (order.deliveryTimeDue < now) { 166 | lateOrdersCount++; 167 | } else { 168 | inTimeOrdersCount++; 169 | } 170 | (pendingOrderCount)--; 171 | pendingOrderCost -= order.cost; 172 | seller.transfer(order.cost); 173 | } 174 | function terminateContract () LARVA_DEA_2_handle_after_terminateContract__parameters_ LARVA_DEA_1_handle_after_terminateContract__no_parameters LARVA_ContractIsEnabled public { 175 | require(msg.sender == seller || msg.sender == buyer); 176 | require(now > endOfContractTimestamp); 177 | if (msg.sender == seller) { 178 | require(pendingOrderCount == 0); 179 | } 180 | if (pendingOrderCount > 0) { 181 | buyer.transfer(pendingOrderCost); 182 | } else { 183 | if (itemsOrderedCount < minimumItemsToBeOrdered) { 184 | seller.transfer((itemsOrderedCount - minimumItemsToBeOrdered) * costPerUnit); 185 | } 186 | } 187 | if ((pendingOrderCount > 0) || (lateOrdersCount * 3 >= inTimeOrdersCount)) { 188 | buyer.transfer(performanceGuarantee); 189 | } else { 190 | seller.transfer(performanceGuarantee); 191 | } 192 | } 193 | 194 | } 195 | -------------------------------------------------------------------------------- /use-cases/Procurement/Procurement.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.15; 2 | 3 | 4 | contract Procurement { 5 | enum ContractStatus { Proposed, Open, Closed } 6 | enum OrderStatus { Ordered, Delivered } 7 | 8 | struct Order { 9 | bool exists; 10 | uint cost; 11 | OrderStatus status; 12 | uint deliveryTimeDue; 13 | } 14 | 15 | // Addresses of buyer and seller in contract 16 | address public seller; 17 | address public buyer; 18 | 19 | // Contract parameters 20 | uint public minimumItemsToBeOrdered; 21 | uint public maximumItemsToBeOrdered; 22 | uint public costPerUnit; 23 | uint public performanceGuarantee; 24 | uint public endOfContractTimestamp; 25 | 26 | // Contract status 27 | ContractStatus public contractStatus; 28 | uint8 public itemsOrderedCount; 29 | uint public moneyLeftInContract; 30 | 31 | // Orders 32 | mapping (uint8 => Order) public orders; 33 | uint8 public pendingOrderCount; 34 | uint public pendingOrderCost; 35 | uint public lateOrdersCount; 36 | uint public inTimeOrdersCount; 37 | 38 | modifier bySeller { 39 | require(msg.sender == seller); 40 | _; 41 | } 42 | 43 | modifier byBuyer { 44 | require(msg.sender == buyer); 45 | _; 46 | } 47 | 48 | function Procurement( 49 | address _seller, address _buyer, 50 | uint _minimumItemsToBeOrdered, uint _maximumItemsToBeOrdered, 51 | uint _costPerUnit, 52 | uint _performanceGuarantee, 53 | uint _contractDuration 54 | ) public payable 55 | { 56 | // The minimum order size must be put in escrow at signing time 57 | require(msg.value >= _costPerUnit * _minimumItemsToBeOrdered); 58 | 59 | // Set the contract parameters 60 | seller = _seller; 61 | buyer = _buyer; 62 | 63 | minimumItemsToBeOrdered = _minimumItemsToBeOrdered; 64 | maximumItemsToBeOrdered = _maximumItemsToBeOrdered; 65 | 66 | costPerUnit = _costPerUnit; 67 | 68 | endOfContractTimestamp = now + _contractDuration; 69 | 70 | performanceGuarantee = _performanceGuarantee; 71 | 72 | // Contract status 73 | contractStatus = ContractStatus.Proposed; 74 | itemsOrderedCount = 0; 75 | moneyLeftInContract = msg.value; 76 | 77 | // Initialise orders 78 | pendingOrderCount = 0; 79 | pendingOrderCost = 0; 80 | lateOrdersCount = 0; 81 | inTimeOrdersCount = 0; 82 | 83 | } 84 | 85 | function acceptContract() public payable bySeller { 86 | require(msg.value >= performanceGuarantee); 87 | contractStatus = ContractStatus.Open; 88 | } 89 | 90 | function createOrder( 91 | uint8 _orderNumber, 92 | uint8 _orderSize, 93 | uint _orderDeliveryTimeLeft 94 | ) public payable byBuyer 95 | { 96 | // Order does not already exist 97 | require(!orders[_orderNumber].exists); 98 | // Number of items ordered does not exceed maximum 99 | require(itemsOrderedCount + _orderSize <= maximumItemsToBeOrdered); 100 | // Order delivery deadline will not be too late 101 | require(now + _orderDeliveryTimeLeft <= endOfContractTimestamp); 102 | 103 | // Ensure there is enough money left in the contract to pay for the order 104 | uint orderCost = _orderSize * costPerUnit; 105 | moneyLeftInContract += msg.value; 106 | require(orderCost <= moneyLeftInContract); 107 | moneyLeftInContract -= orderCost; 108 | 109 | // Update number of items ordered 110 | itemsOrderedCount += _orderSize; 111 | 112 | // Update contract status 113 | pendingOrderCount++; 114 | pendingOrderCost += orderCost; 115 | 116 | // Record the order 117 | orders[_orderNumber] = Order(true, orderCost, OrderStatus.Ordered, now+_orderDeliveryTimeLeft); 118 | } 119 | 120 | function deliveryMade( 121 | uint8 _orderNumber 122 | ) public byBuyer 123 | { 124 | Order memory order = orders[_orderNumber]; 125 | 126 | // Ensure that the order exists and has not yet been delivered 127 | require(order.exists && order.status == OrderStatus.Ordered); 128 | 129 | // Order state update 130 | order.status = OrderStatus.Delivered; 131 | 132 | // Contract state update 133 | if (order.deliveryTimeDue < now) { 134 | lateOrdersCount++; 135 | } else { 136 | inTimeOrdersCount++; 137 | } 138 | 139 | pendingOrderCount--; 140 | pendingOrderCost -= order.cost; 141 | 142 | // Pay the seller 143 | seller.transfer(order.cost); 144 | } 145 | 146 | function terminateContract() public { 147 | // Can only be done by the seller or buyer 148 | require(msg.sender == seller || msg.sender == buyer); 149 | 150 | // Can only be closed after the contract time frame ended 151 | require(now > endOfContractTimestamp); 152 | 153 | if (msg.sender == seller) { 154 | // Can only be closed by seller if there are no pending orders 155 | require(pendingOrderCount == 0); 156 | } 157 | 158 | if (pendingOrderCount > 0) { 159 | // If there are any undelivered orders, return their cost to the buyer 160 | buyer.transfer(pendingOrderCost); 161 | } else { 162 | // If there are no undelivered orders, and not enough orders were made (less 163 | // than minimum) the seller gets money for the unordered items 164 | if (itemsOrderedCount < minimumItemsToBeOrdered) { 165 | seller.transfer((itemsOrderedCount-minimumItemsToBeOrdered)*costPerUnit); 166 | } 167 | } 168 | 169 | // If there are any pending orders or 25%+ of the orders were delivered late 170 | // the buyer gets the performance guarantee, otherwise it is returned to the seller 171 | if ((pendingOrderCount > 0) || (lateOrdersCount * 3 >= inTimeOrdersCount)) { 172 | buyer.transfer(performanceGuarantee); 173 | } else { 174 | seller.transfer(performanceGuarantee); 175 | } 176 | 177 | } 178 | 179 | } -------------------------------------------------------------------------------- /use-cases/Procurement/ProcurementSpec.dea: -------------------------------------------------------------------------------- 1 | monitor Procurement{ 2 | declarations { 3 | address mediator; 4 | uint orderCount; 5 | bool enoughItemsOrderedBadStateReached; 6 | } 7 | 8 | initialisation { 9 | mediator = address(uint160(msg.sender)); 10 | LARVA_EnableContract(); 11 | } 12 | 13 | reparation { 14 | enoughItemsOrderedBadStateReached ? mediator.transfer(this.balance) : (); 15 | } 16 | 17 | //When a contract terminates there should not be any ether left in its balance. 18 | DEA NoEtherAfterTermination{ 19 | states{ 20 | DuringContract: initial; 21 | EndedWithBalance: bad; 22 | EndedWithoutBalance: accept; 23 | } 24 | 25 | transitions{ 26 | DuringContract -[after(terminateContract) | this.balance != 0 ~> enoughItemsOrderedBadStateReached = true;]-> EndedWithBalance; 27 | DuringContract -[after(terminateContract) | this.balance == 0]-> EndedWithoutBalance; 28 | } 29 | } 30 | 31 | //The buyer is obliged to order at least〈minimum-items〉, but no more than〈maximum-items〉items fora fixed price〈price〉before the termination of this contract. 32 | DEA EnoughItemsOrdered{ 33 | states{ 34 | DuringContract: initial; 35 | RangesChanged: bad; 36 | OutsideOfRange: bad; 37 | EnoughItems: accept; 38 | } 39 | 40 | transitions{ 41 | DuringContract -[after(createOrder(_orderNumber, _orderSize, _orderDeliveryTimeLeft)) | ~> orderCount += _orderNumber;]-> DuringContract; 42 | DuringContract -[minimumItemsToBeOrdered@(LARVA_previous_minimumItemsToBeOrdered != minimumItemsToBeOrdered)]-> RangesChanged; 43 | DuringContract -[maximumItemsToBeOrdered@(LARVA_previous_minimumItemsToBeOrdered != minimumItemsToBeOrdered)]-> RangesChanged; 44 | DuringContract -[after(terminateContract()) | orderCount < minimumItemsToBeOrdered || orderCount > maximumItemsToBeOrdered]-> OutsideOfRange; 45 | DuringContract -[after(terminateContract()) | orderCount >= minimumItemsToBeOrdered && orderCount <= maximumItemsToBeOrdered]-> EnoughItems; 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /use-cases/README.md: -------------------------------------------------------------------------------- 1 | This folder contains several Solidity smart contracts and specifications for them, intended both as use cases for users of contractLarva and to serve as a test suite for contributors to contractLarva. 2 | 3 | Each folder __\Name__ is of the following form: 4 | 5 | -__contractLarva\use-cases\Name\Name.sol__ : The original smart contract. 6 | 7 | -__contractLarva\use-cases\Name\NameSpec.dea__: The contractLarva specification for the smart contract. 8 | 9 | -__contractLarva\use-cases\Name\MonitoredName.sol__: The smart contract monitored with the specification. 10 | 11 | A note is that some of the examples may be verifiable by hand or by some light static analysis, while others actually functionality to the smart contract. In contractLarva these are all monitored at runtime, making it less than ideal for statically verifiable use cases. We suggest performing static analysis through other means to reduce runtime overheads. 12 | 13 | Below is a short description of each of these use cases: 14 | 15 | 1. **Casino**: An implementation of a guessing game in Solidity, were the owner is trusted. When __openTable__ is called the users can start betting with __placeBet__, with the amount they bet placed in a __pot__. The owner can stop a game with __resolveBet__, where the winners divide the __pot__ amongst them. Or the owner can __timeoutBet__, where the users are refunded their bets. The specification for the casino specifies two behaviours: (i) While the table is open the pot cannot reduce in value; and (ii) the table remains open until resolution or timeout. 16 | 17 | 2. **CourierService**: An implementation of a courier service contract, where an __order__ and its __delivery__ can be recorded on the blockchain, where if the __order__ is not received on time the client can cancel the order and __requestRefund__ automatically. The specification specifies the correct functional behaviour of this implementation, e.g. ensuring the correct customer is recorded for an __order__, and detecting violation when there is a __delivery__ or __refund__ before there has been an __order__, or when another __order__ is attempted (the smart contract is intended to be used for one order). 18 | 19 | 3. **ERC20Interface**: An implementation of the ERC20 token interface, allowing __transfer__ of tokens. This interface allows for the underlying implementation to be changed at runtime since it performs its functionality by passing on calls to the recorded __impl__ address. The specification specifies the functional contracts required by the ERC20 standard and that must be respected by implementations at runtime. 20 | 21 | 4. **FixedSupplyToken**: An example implementation of an **ERC20Interface** which relies on the supply of tokens not changing. The specification ensures this by specifying that any addition (or subtraction) to a user's wallet must be followed by a substraction (or addition) of the same value to a user's wallet before the __transfer__ function has finished. 22 | 23 | 5. **InsuredCourierService**: This smart contract is similar to that used in 2., however the specification logic does not simply attempt to verify the well-behaviour of the smart contract but adds insurance logic to the business process. 24 | 25 | 6. **MultiOwnersWallet**: This wallet allows transactions to occur if all the owners sign off on it, while they can vote to remove other owners. The specification here ensures that once owners are removed the transactions they started cannot be fulfilled, while it also detects and prevents double voting. 26 | 27 | 7. **Procurement**: An implementation on the blockchain of an agreement between two parties, where the buyer binds themselves to buy some amount of goods at some price, and the seller binds themselves to deliver these items. The specification ensures that: (i) after termination there is no ether left in the smart contract; and (ii) enough items (between the minimum and maximum required amount) are ordered by termination. 28 | 29 | 8. **SmartAuctionHouse**: This smart contract allows users to bid on certain items. The specification ensures: (i) only one auction occurs at a time with the added business logic that if 15 minutes have passed since the last bid the smart contract is forced to declare a winner; and (ii) that winning bids must be fulfilled (i.e. the winning bidder must pay for the item within the day), and any attempt to bid more that 3 times before paying results in the winning bid being cancelled. 30 | -------------------------------------------------------------------------------- /use-cases/SmartAuctionHouse/SmartAuctionHouse.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | contract SmartAuctionHouse{ 4 | 5 | uint currentItem; 6 | uint startingOffer; 7 | 8 | uint currentOffer; 9 | address currentWinner; 10 | 11 | uint ticks; 12 | 13 | mapping(uint => address) winners; 14 | mapping(uint => uint) winningOffer; 15 | mapping(uint => bool) fulfilled; 16 | 17 | address owner; 18 | 19 | function SmartAuctionHouse(){ 20 | owner = msg.sender; 21 | } 22 | 23 | modifier onlyOwner(){ 24 | require(msg.sender == owner); 25 | _; 26 | } 27 | 28 | modifier onlyOwnerOrInternal(){ 29 | require(msg.sender == owner || msg.sender == address(this)); 30 | _; 31 | } 32 | 33 | function auctionOffItem(uint _offerID, uint _startingOffer) public { 34 | require(!ongoingAuction()); 35 | 36 | currentItem = _offerID; 37 | startingOffer = _startingOffer; 38 | } 39 | 40 | function tick() public onlyOwner{ 41 | require(ongoingAuction()); 42 | 43 | ticks++; 44 | 45 | if(ticks > 2) declareWinningOffer(); 46 | } 47 | 48 | function makeOffer(uint _offer) public { 49 | require(_offer > currentOffer); 50 | 51 | currentOffer = _offer; 52 | currentWinner = msg.sender; 53 | } 54 | 55 | function declareWinningOffer() public onlyOwnerOrInternal{ 56 | require(ticks > 2); 57 | 58 | winners[currentItem] = currentWinner; 59 | winningOffer[currentItem] = currentOffer; 60 | reset(); 61 | } 62 | 63 | function fulfillOffer(uint _id) payable public { 64 | require(winners[_id] == msg.sender && winningOffer[_id] == msg.value && !fulfilled[_id]); 65 | fulfilled[_id] = true; 66 | } 67 | 68 | function ongoingAuction() internal returns(bool){ 69 | return startingOffer == 0 && currentOffer == 0; 70 | } 71 | 72 | function reset() internal { 73 | currentItem = 0; 74 | startingOffer = 0; 75 | currentOffer = 0; 76 | currentWinner = address(0); 77 | ticks = 0; 78 | } 79 | 80 | function getItemWinningOffer(uint _id) public returns(address,uint){ 81 | return (winners[_id], winningOffer[_id]); 82 | } 83 | 84 | function getItemWinningBidder(uint _id) public returns(address){ 85 | (address bidder, ) = getItemWinningOffer(_id); 86 | return bidder; 87 | } 88 | 89 | function getItemWinningOffer(uint _id) public returns(uint){ 90 | (, uint winningOffer) = getItemWinningOffer(_id); 91 | return winningOffer; 92 | } 93 | } -------------------------------------------------------------------------------- /use-cases/SmartAuctionHouse/SmartAuctionHouseSpec.dea: -------------------------------------------------------------------------------- 1 | monitor SmartAuctionHouse{ 2 | 3 | declarations{ 4 | mapping(address => uint) attemptsBeforeFullfillment; 5 | mapping(uint => bool) cancelledItems; 6 | mapping(uint => bool) unfulfilled; 7 | mapping(address => uint[]) wonBids; 8 | 9 | uint timeSinceLastOffer; 10 | 11 | function forceDeclareWinner() private{ 12 | ticks = 3; 13 | declareWinningOffer(); 14 | timeSinceLastOffer = 0; 15 | } 16 | 17 | function cancelAnyUnfulfilledBids(address _bidder) private{ 18 | for(uint i = wonBids[_bidder].length - 1; i >= 0; i--){ 19 | if(unfulfilled[wonBids[_bidder][i]]){ 20 | cancelledItems[wonBids[_bidder][i]] = false; 21 | } 22 | } 23 | } 24 | 25 | function areAnyUnfullfilled(address _bidder) private returns(bool){ 26 | for(uint i = wonBids[_bidder].length - 1; i >= 0; i--){ 27 | if(unfulfilled[wonBids[_bidder][i]]){ 28 | return true; 29 | } 30 | } 31 | 32 | return false; 33 | } 34 | } 35 | 36 | initialisation{ 37 | LARVA_EnableContract(); 38 | } 39 | 40 | reparation{ 41 | revert(); 42 | } 43 | 44 | //auctionOffItem cannot occur subsequently without declareWinningOffer in between 45 | //if 15 minutes have passed since the last offer then automatically declare the winner 46 | DEA OneAuctionAtATime{ 47 | states{ 48 | NoOngoingAuction: initial; 49 | AuctionStart; 50 | AuctionAttempted: bad; 51 | } 52 | 53 | transitions{ 54 | NoOngoingAuction -[after(auctionOffItem(_offerID, _startingOffer))]-> AuctionStart; 55 | AuctionStart -[after(makeOffer(_offer)) | ~> timeSinceLastOffer = now;]-> AuctionStart; 56 | AuctionStart -[after(declareWinningOffer())]-> NoOngoingAuction; 57 | AuctionStart -[before(auctionOffItem(_offerID, _startingOffer)) | now - timeSinceLastOffer < 15 minutes]-> AuctionAttempted; 58 | AuctionStart -[before(auctionOffItem(_offerID, _startingOffer)) | now - timeSinceLastOffer >= 15 minutes ~> forceDeclareWinner();]-> AuctionStart; 59 | } 60 | } 61 | 62 | //if winning bid is not fulfilled within a day's time 63 | // then the bidder is not allowed to bid on other items 64 | // and any attempt to bid more than 3 times before paying then the winning bid is cancelled 65 | DEA WinningBidsMustBeFulfilledOrCancelled{ 66 | states{ 67 | Initial: initial; 68 | UnfulfilledBids: bad; 69 | } 70 | 71 | transitions{ 72 | Initial -[before(declareWinningOffer()) | ~> unfulfilled[currentItem] = true;]-> Initial; 73 | Initial -[after(fulfillOffer(_id)) | ~> unfulfilled[_id] = false;]-> Initial; 74 | Initial -[before(fulfillOffer(_id)) | cancelledItems[_id]]-> UnfulfilledBids; 75 | Initial -[after(auctionOffItem(_offerID, _startingOffer)) | areAnyUnfullfilled(msg.sender) && attemptsBeforeFullfillment[msg.sender] < 3 ~> attemptsBeforeFullfillment[msg.sender]++;]-> Initial; 76 | Initial -[after(auctionOffItem(_offerID, _startingOffer)) | areAnyUnfullfilled(msg.sender) && attemptsBeforeFullfillment[msg.sender] > 3 ~> attemptsBeforeFullfillment[msg.sender]++;]-> UnfulfilledBids; 77 | Initial -[after(auctionOffItem(_offerID, _startingOffer)) | !areAnyUnfullfilled(msg.sender) ~> attemptsBeforeFullfillment[msg.sender] = 0;]-> Initial; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /use-cases/SmartAuctionHouse/monitoredSmartAuctionHouse.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | contract LARVA_SmartAuctionHouse { 3 | modifier LARVA_Constructor { 4 | _; 5 | { 6 | LARVA_EnableContract(); 7 | } 8 | } 9 | modifier LARVA_DEA_2_handle_after_fulfillOffer__parameters__id (uint _id) { 10 | if ((LARVA_STATE_2 == 0)) { 11 | LARVA_STATE_2 = 0; 12 | unfulfilled[_id] = false; 13 | } 14 | _; 15 | } 16 | modifier LARVA_DEA_2_handle_after_auctionOffItem__parameters__offerID__startingOffer (uint _offerID, uint _startingOffer) { 17 | if ((LARVA_STATE_2 == 0) && (areAnyUnfullfilled(msg.sender) && attemptsBeforeFullfillment[msg.sender] < 3)) { 18 | LARVA_STATE_2 = 0; 19 | attemptsBeforeFullfillment[msg.sender]++; 20 | } else { 21 | if ((LARVA_STATE_2 == 0) && (areAnyUnfullfilled(msg.sender) && attemptsBeforeFullfillment[msg.sender] > 3)) { 22 | LARVA_STATE_2 = 1; 23 | attemptsBeforeFullfillment[msg.sender]++; 24 | LARVA_reparation(); 25 | } else { 26 | if ((LARVA_STATE_2 == 0) && (!areAnyUnfullfilled(msg.sender))) { 27 | LARVA_STATE_2 = 0; 28 | attemptsBeforeFullfillment[msg.sender] = 0; 29 | } 30 | } 31 | } 32 | _; 33 | } 34 | modifier LARVA_DEA_2_handle_before_fulfillOffer__parameters__id (uint _id) { 35 | if ((LARVA_STATE_2 == 0) && (cancelledItems[_id])) { 36 | LARVA_STATE_2 = 1; 37 | LARVA_reparation(); 38 | } 39 | _; 40 | } 41 | modifier LARVA_DEA_2_handle_before_declareWinningOffer__parameters_ () { 42 | if ((LARVA_STATE_2 == 0)) { 43 | LARVA_STATE_2 = 0; 44 | unfulfilled[currentItem] = true; 45 | } 46 | _; 47 | } 48 | modifier LARVA_DEA_1_handle_after_makeOffer__parameters__offer (uint _offer) { 49 | if ((LARVA_STATE_1 == 1)) { 50 | LARVA_STATE_1 = 1; 51 | timeSinceLastOffer = now; 52 | } 53 | _; 54 | } 55 | modifier LARVA_DEA_1_handle_after_declareWinningOffer__parameters_ () { 56 | if ((LARVA_STATE_1 == 1)) { 57 | LARVA_STATE_1 = 0; 58 | } 59 | _; 60 | } 61 | modifier LARVA_DEA_1_handle_after_auctionOffItem__parameters__offerID__startingOffer (uint _offerID, uint _startingOffer) { 62 | if ((LARVA_STATE_1 == 0)) { 63 | LARVA_STATE_1 = 1; 64 | } 65 | _; 66 | } 67 | modifier LARVA_DEA_1_handle_before_auctionOffItem__parameters__offerID__startingOffer (uint _offerID, uint _startingOffer) { 68 | if ((LARVA_STATE_1 == 1) && (now - timeSinceLastOffer < 15 minutes)) { 69 | LARVA_STATE_1 = 2; 70 | LARVA_reparation(); 71 | } else { 72 | if ((LARVA_STATE_1 == 1) && (now - timeSinceLastOffer >= 15 minutes)) { 73 | LARVA_STATE_1 = 1; 74 | forceDeclareWinner(); 75 | } 76 | } 77 | _; 78 | } 79 | int8 LARVA_STATE_1 = 0; 80 | int8 LARVA_STATE_2 = 0; 81 | function LARVA_reparation () private { 82 | revert(); 83 | } 84 | mapping (address => uint) attemptsBeforeFullfillment; 85 | mapping (uint => bool) cancelledItems; 86 | mapping (uint => bool) unfulfilled; 87 | mapping (address => uint[]) wonBids; 88 | uint timeSinceLastOffer; 89 | function forceDeclareWinner () private { 90 | ticks = 3; 91 | declareWinningOffer(); 92 | timeSinceLastOffer = 0; 93 | } 94 | function cancelAnyUnfulfilledBids (address _bidder) private { 95 | for (uint i = wonBids[_bidder].length - 1; i >= 0; (i)--) { 96 | if (unfulfilled[wonBids[_bidder][i]]) { 97 | cancelledItems[wonBids[_bidder][i]] = false; 98 | } 99 | } 100 | } 101 | function areAnyUnfullfilled (address _bidder) private returns (bool) { 102 | for (uint i = wonBids[_bidder].length - 1; i >= 0; (i)--) { 103 | if (unfulfilled[wonBids[_bidder][i]]) { 104 | return true; 105 | } 106 | } 107 | return false; 108 | } 109 | enum LARVA_STATUS {RUNNING, STOPPED} 110 | function LARVA_EnableContract () private { 111 | LARVA_Status = LARVA_STATUS.RUNNING; 112 | } 113 | function LARVA_DisableContract () private { 114 | LARVA_Status = LARVA_STATUS.STOPPED; 115 | } 116 | LARVA_STATUS private LARVA_Status = LARVA_STATUS.STOPPED; 117 | modifier LARVA_ContractIsEnabled { 118 | require(LARVA_Status == LARVA_STATUS.RUNNING); 119 | _; 120 | } 121 | uint currentItem; 122 | uint startingOffer; 123 | uint currentOffer; 124 | address currentWinner; 125 | uint ticks; 126 | mapping (uint => address) winners; 127 | mapping (uint => uint) winningOffer; 128 | mapping (uint => bool) fulfilled; 129 | address owner; 130 | function LARVA_SmartAuctionHouse () LARVA_Constructor { 131 | owner = msg.sender; 132 | } 133 | modifier onlyOwner () { 134 | require(msg.sender == owner); 135 | _; 136 | } 137 | modifier onlyOwnerOrInternal () { 138 | require(msg.sender == owner || msg.sender == address(this)); 139 | _; 140 | } 141 | function auctionOffItem (uint _offerID, uint _startingOffer) LARVA_DEA_2_handle_after_auctionOffItem__parameters__offerID__startingOffer(_offerID, _startingOffer) LARVA_DEA_1_handle_after_auctionOffItem__parameters__offerID__startingOffer(_offerID, _startingOffer) LARVA_DEA_1_handle_before_auctionOffItem__parameters__offerID__startingOffer(_offerID, _startingOffer) LARVA_ContractIsEnabled public { 142 | require(!ongoingAuction()); 143 | currentItem = _offerID; 144 | startingOffer = _startingOffer; 145 | } 146 | function tick () LARVA_ContractIsEnabled public onlyOwner { 147 | require(ongoingAuction()); 148 | ticks++; 149 | if (ticks > 2) declareWinningOffer(); 150 | } 151 | function makeOffer (uint _offer) LARVA_DEA_1_handle_after_makeOffer__parameters__offer(_offer) LARVA_ContractIsEnabled public { 152 | require(_offer > currentOffer); 153 | currentOffer = _offer; 154 | currentWinner = msg.sender; 155 | } 156 | function declareWinningOffer () LARVA_DEA_2_handle_before_declareWinningOffer__parameters_ LARVA_DEA_1_handle_after_declareWinningOffer__parameters_ LARVA_ContractIsEnabled public onlyOwnerOrInternal { 157 | require(ticks > 2); 158 | winners[currentItem] = currentWinner; 159 | winningOffer[currentItem] = currentOffer; 160 | reset(); 161 | } 162 | function fulfillOffer (uint _id) LARVA_DEA_2_handle_after_fulfillOffer__parameters__id(_id) LARVA_DEA_2_handle_before_fulfillOffer__parameters__id(_id) LARVA_ContractIsEnabled payable public { 163 | require(winners[_id] == msg.sender && winningOffer[_id] == msg.value && !fulfilled[_id]); 164 | fulfilled[_id] = true; 165 | } 166 | function ongoingAuction () LARVA_ContractIsEnabled internal returns (bool) { 167 | return startingOffer == 0 && currentOffer == 0; 168 | } 169 | function reset () LARVA_ContractIsEnabled internal { 170 | currentItem = 0; 171 | startingOffer = 0; 172 | currentOffer = 0; 173 | currentWinner = address(0); 174 | ticks = 0; 175 | } 176 | function getItemWinningOffer (uint _id) LARVA_ContractIsEnabled public returns (address, uint) { 177 | return (winners[_id], winningOffer[_id]); 178 | } 179 | function getItemWinningBidder (uint _id) LARVA_ContractIsEnabled public returns (address) { 180 | (address bidder, ) = (getItemWinningOffer(_id)); 181 | return bidder; 182 | } 183 | function getItemWinningOffer (uint _id) LARVA_ContractIsEnabled public returns (uint) { 184 | (, uint winningOffer) = (getItemWinningOffer(_id)); 185 | return winningOffer; 186 | } 187 | 188 | } 189 | -------------------------------------------------------------------------------- /use-cases/WalletWithDeposit/MonitoredWalletWithDeposit.sol: -------------------------------------------------------------------------------- 1 | contract LARVA_WalletWithDeposit { 2 | modifier LARVA_Constructor { 3 | _; 4 | { 5 | LARVA_EnableContract(); 6 | } 7 | } 8 | modifier LARVA_DEA_1_handle_after_assignment_history { 9 | _; 10 | if ((LARVA_STATE_1 == 0) && (history[depositProvider.wallet] != depositProvider.name)) { 11 | LARVA_STATE_1 = 5; 12 | LARVA_reparation(); 13 | } 14 | } 15 | modifier LARVA_DEA_1_handle_after_assignment_depositProvider { 16 | _; 17 | if ((LARVA_STATE_1 == 0) && (owner == depositProvider.wallet)) { 18 | LARVA_STATE_1 = 4; 19 | LARVA_reparation(); 20 | } 21 | } 22 | modifier LARVA_DEA_1_handle_after_assignment_deposit { 23 | _; 24 | if ((LARVA_STATE_1 == 0) && (true)) { 25 | LARVA_STATE_1 = 3; 26 | LARVA_reparation(); 27 | } 28 | } 29 | modifier LARVA_DEA_1_handle_after_transfer { 30 | _; 31 | if ((LARVA_STATE_1 == 0) && (address(this).balance >= deposit)) { 32 | LARVA_STATE_1 = 2; 33 | LARVA_reparation(); 34 | } 35 | } 36 | modifier LARVA_DEA_1_handle_before_end__parameters_ () { 37 | if ((LARVA_STATE_1 == 0)) { 38 | LARVA_STATE_1 = 1; 39 | } 40 | _; 41 | } 42 | int8 LARVA_STATE_1 = 0; 43 | function LARVA_set_deposit_pre (uint _deposit) LARVA_DEA_1_handle_after_assignment_deposit internal returns (uint) { 44 | LARVA_previous_deposit = deposit; 45 | deposit = _deposit; 46 | return LARVA_previous_deposit; 47 | } 48 | function LARVA_set_deposit_post (uint _deposit) LARVA_DEA_1_handle_after_assignment_deposit internal returns (uint) { 49 | LARVA_previous_deposit = deposit; 50 | deposit = _deposit; 51 | return deposit; 52 | } 53 | uint private LARVA_previous_deposit; 54 | function LARVA_set_depositProvider_pre_wallet (address payable _value) internal returns (address payable) { 55 | LARVA_previous_depositProvider = depositProvider; 56 | depositProvider.wallet = _value; 57 | return LARVA_previous_depositProvider; 58 | } 59 | function LARVA_set_depositProvider_pre_name (string _value) internal returns (string) { 60 | LARVA_previous_depositProvider = depositProvider; 61 | depositProvider.name = _value; 62 | return LARVA_previous_depositProvider; 63 | } 64 | function LARVA_set_depositProvider_pre (Provider _depositProvider) LARVA_DEA_1_handle_after_assignment_depositProvider internal returns (Provider) { 65 | LARVA_previous_depositProvider = depositProvider; 66 | depositProvider = _depositProvider; 67 | return LARVA_previous_depositProvider; 68 | } 69 | function LARVA_set_depositProvider_pre_wallet (address payable _value) internal returns (address payable) { 70 | LARVA_previous_depositProvider = depositProvider; 71 | depositProvider.wallet = _value; 72 | return depositProvider; 73 | } 74 | function LARVA_set_depositProvider_pre_name (string _value) internal returns (string) { 75 | LARVA_previous_depositProvider = depositProvider; 76 | depositProvider.name = _value; 77 | return depositProvider; 78 | } 79 | function LARVA_set_depositProvider_post (Provider _depositProvider) LARVA_DEA_1_handle_after_assignment_depositProvider internal returns (Provider) { 80 | LARVA_previous_depositProvider = depositProvider; 81 | depositProvider = _depositProvider; 82 | return depositProvider; 83 | } 84 | Provider private LARVA_previous_depositProvider; 85 | function LARVA_set_history_pre (address _index, string _history_value) LARVA_DEA_1_handle_after_assignment_history internal returns (string) { 86 | LARVA_previous_history_value = history; 87 | history[_index] = _history_value; 88 | return LARVA_previous_history; 89 | } 90 | function LARVA_set_history_post (address _index, string _history_value) LARVA_DEA_1_handle_after_assignment_history internal returns (string) { 91 | LARVA_previous_history_value = history; 92 | history[_index] = _history_value; 93 | return history; 94 | } 95 | string private LARVA_previous_history; 96 | function LARVA_transfer (address payable _to, uint amount) LARVA_DEA_1_handle_after_transfer internal { 97 | LARVA_set_history_pre(_to, amount); 98 | } 99 | function LARVA_reparation () private { 100 | revert(); 101 | } 102 | enum LARVA_STATUS {RUNNING, STOPPED} 103 | function LARVA_EnableContract () private { 104 | LARVA_Status = LARVA_STATUS.RUNNING; 105 | } 106 | function LARVA_DisableContract () private { 107 | LARVA_Status = LARVA_STATUS.STOPPED; 108 | } 109 | LARVA_STATUS private LARVA_Status = LARVA_STATUS.STOPPED; 110 | modifier LARVA_ContractIsEnabled { 111 | require(LARVA_Status == LARVA_STATUS.RUNNING); 112 | _; 113 | } 114 | uint private deposit; 115 | address payable owner; 116 | struct Provider { 117 | address payable wallet; 118 | string name; 119 | } 120 | Provider private depositProvider; 121 | mapping (address => string) private history; 122 | modifier iss (address _owner) { 123 | require(msg.sender == _owner); 124 | _; 125 | } 126 | constructor (string memory name, address payable _depositProvider) LARVA_Constructor payable { 127 | require(msg.value > 0, "Must be started with a deposit."); 128 | (owner, deposit) = ((payable(msg.sender), msg.value)); 129 | depositProvider = Provider(_depositProvider, name); 130 | history[_depositProvider] = name; 131 | } 132 | function transfer (address payable to, uint tokens) LARVA_ContractIsEnabled iss(owner) external returns (bool success) { 133 | LARVA_transfer(to, tokens); 134 | } 135 | function changeOwnerAndDepositProvider (address payable _owner, string memory name, address payable _depositProvider) LARVA_ContractIsEnabled external iss(_depositProvider) returns (bool success) { 136 | { 137 | Provider depositProvider_LARVA; 138 | (owner, depositProvider_LARVA) = ((_owner, Provider(_depositProvider, name))); 139 | LARVA_set_depositProvider_post(depositProvider_LARVA); 140 | } 141 | LARVA_set_history_post(_depositProvider, name); 142 | } 143 | function end () LARVA_DEA_1_handle_before_end__parameters_ LARVA_ContractIsEnabled external iss(owner) returns (bool success) { 144 | LARVA_transfer(depositProvider.wallet, deposit); 145 | selfdestruct(owner); 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /use-cases/WalletWithDeposit/WalletWithDeposit.sol: -------------------------------------------------------------------------------- 1 | contract WalletWithDeposit{ 2 | 3 | uint deposit; 4 | address payable owner; 5 | struct Provider { 6 | address payable wallet; 7 | string name; 8 | } 9 | 10 | Provider depositProvider; 11 | mapping(address => string) history; 12 | 13 | modifier iss(address _owner) { 14 | require(msg.sender == _owner); 15 | _; 16 | } 17 | 18 | constructor(string memory name, address payable _depositProvider) payable { 19 | require(msg.value > 0, "Must be started with a deposit."); 20 | (owner, deposit) = (payable(msg.sender), msg.value); 21 | depositProvider = Provider(_depositProvider, name); 22 | history[_depositProvider] = name; 23 | } 24 | 25 | function transfer(address payable to, uint tokens) iss(owner) external returns (bool success){ 26 | to.transfer(tokens); 27 | } 28 | 29 | function changeOwnerAndDepositProvider (address payable _owner, string memory name, address payable _depositProvider) external iss(_depositProvider) returns (bool success){ 30 | (owner, depositProvider) = (_owner, Provider(_depositProvider, name)); 31 | history[_depositProvider] = name; 32 | } 33 | 34 | function end () external iss(owner) returns (bool success){ 35 | depositProvider.wallet.transfer(deposit); 36 | selfdestruct(owner); 37 | } 38 | } -------------------------------------------------------------------------------- /use-cases/WalletWithDeposit/WalletWithDepositSpec.dea: -------------------------------------------------------------------------------- 1 | monitor WalletWithDeposit{ 2 | 3 | declarations{ 4 | } 5 | 6 | initialisation{ 7 | LARVA_EnableContract(); 8 | } 9 | 10 | reparation{ 11 | revert(); 12 | } 13 | 14 | DEA ProtectedDeposit{ 15 | states{ 16 | Start: initial; 17 | Ending; 18 | LessThanDeposit: bad; 19 | DepositModified: bad; 20 | OwnerIsSameAsDepositProvider: bad; 21 | BadHistoryModification: bad; 22 | } 23 | 24 | transitions{ 25 | Start -[aftertransfer | address(this).balance >= deposit]-> LessThanDeposit; 26 | Start -[deposit@(true)]-> DepositModified; 27 | Start -[depositProvider@(owner == depositProvider.wallet)]-> OwnerIsSameAsDepositProvider; 28 | Start -[history@(history[depositProvider.wallet] != depositProvider.name)]-> BadHistoryModification; 29 | Start -[before(end())]-> Ending; 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /use-cases/tutorial/dea-latex-highlighting.tex: -------------------------------------------------------------------------------- 1 | % Copyright 2017 Sergei Tikhomirov, MIT License 2 | % https://github.com/s-tikhomirov/solidity-latex-highlighting/ 3 | 4 | \usepackage{listings, xcolor} 5 | 6 | \definecolor{verylightgray}{rgb}{.97,.97,.97} 7 | 8 | \lstdefinelanguage{DEA}{ 9 | keywords=[1]{anonymous, assembly, assert, balance, break, call, callcode, case, catch, class, constant, continue, contract, debugger, default, delegatecall, delete, do, else, emit, event, export, external, false, finally, for, function, gas, if, implements, import, in, indexed, instanceof, interface, internal, is, length, library, log0, log1, log2, log3, log4, memory, modifier, new, payable, pragma, private, protected, public, pure, push, require, return, returns, revert, selfdestruct, send, storage, struct, suicide, super, switch, then, this, throw, true, try, typeof, using, value, view, while, with, addmod, ecrecover, keccak256, mulmod, ripemd160, sha256, sha3}, % generic keywords including crypto operations 10 | keywordstyle=[1]\color{blue}\bfseries, 11 | keywords=[2]{address, bool, byte, bytes, bytes1, bytes2, bytes3, bytes4, bytes5, bytes6, bytes7, bytes8, bytes9, bytes10, bytes11, bytes12, bytes13, bytes14, bytes15, bytes16, bytes17, bytes18, bytes19, bytes20, bytes21, bytes22, bytes23, bytes24, bytes25, bytes26, bytes27, bytes28, bytes29, bytes30, bytes31, bytes32, enum, int, int8, int16, int24, int32, int40, int48, int56, int64, int72, int80, int88, int96, int104, int112, int120, int128, int136, int144, int152, int160, int168, int176, int184, int192, int200, int208, int216, int224, int232, int240, int248, int256, mapping, string, uint, uint8, uint16, uint24, uint32, uint40, uint48, uint56, uint64, uint72, uint80, uint88, uint96, uint104, uint112, uint120, uint128, uint136, uint144, uint152, uint160, uint168, uint176, uint184, uint192, uint200, uint208, uint216, uint224, uint232, uint240, uint248, uint256, var, void, ether, finney, szabo, wei, days, hours, minutes, seconds, weeks, years}, % types; money and time units 12 | keywordstyle=[2]\color{teal}\bfseries, 13 | keywords=[3]{block, blockhash, coinbase, difficulty, gaslimit, number, timestamp, msg, data, gas, sender, sig, value, now, tx, gasprice, origin}, % environment variables 14 | keywordstyle=[3]\color{violet}\bfseries, 15 | keywords=[4]{monitor, DEA, declarations,initialisation, satisfaction, violation, reparation, transitions, states, initial, bad, normal, accept, |, ~>, -[, ]->}, % DEA keywords 16 | keywordstyle=[4]\color{olive}\bfseries, 17 | identifierstyle=\color{black}, 18 | sensitive=true, 19 | comment=[l]{//}, 20 | morecomment=[s]{/*}{*/}, 21 | commentstyle=\color{gray}\ttfamily, 22 | stringstyle=\color{red}\ttfamily, 23 | morestring=[b]', 24 | morestring=[b]" 25 | } 26 | 27 | \lstset{ 28 | language=Solidity, 29 | backgroundcolor=\color{verylightgray}, 30 | extendedchars=true, 31 | basicstyle=\footnotesize\ttfamily, 32 | showstringspaces=false, 33 | showspaces=false, 34 | numbers=left, 35 | numberstyle=\footnotesize, 36 | numbersep=9pt, 37 | tabsize=2, 38 | breaklines=true, 39 | showtabs=false, 40 | captionpos=b 41 | } 42 | 43 | -------------------------------------------------------------------------------- /use-cases/tutorial/main.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gordonpace/contractLarva/5a2febd1c9ba4763b30def3a96bb07f2fef8a9dc/use-cases/tutorial/main.pdf -------------------------------------------------------------------------------- /use-cases/tutorial/solidity-latex-highlighting.tex: -------------------------------------------------------------------------------- 1 | % Copyright 2017 Sergei Tikhomirov, MIT License 2 | % https://github.com/s-tikhomirov/solidity-latex-highlighting/ 3 | 4 | \usepackage{listings, xcolor} 5 | 6 | \definecolor{verylightgray}{rgb}{.97,.97,.97} 7 | 8 | \lstdefinelanguage{Solidity}{ 9 | keywords=[1]{anonymous, assembly, assert, balance, break, call, callcode, case, catch, class, constant, continue, contract, debugger, default, delegatecall, delete, do, else, emit, event, export, external, false, finally, for, function, gas, if, implements, import, in, indexed, instanceof, interface, internal, is, length, library, log0, log1, log2, log3, log4, memory, modifier, new, payable, pragma, private, protected, public, pure, push, require, return, returns, revert, selfdestruct, send, storage, struct, suicide, super, switch, then, this, throw, true, try, typeof, using, value, view, while, with, addmod, ecrecover, keccak256, mulmod, ripemd160, sha256, sha3}, % generic keywords including crypto operations 10 | keywordstyle=[1]\color{blue}\bfseries, 11 | keywords=[2]{address, bool, byte, bytes, bytes1, bytes2, bytes3, bytes4, bytes5, bytes6, bytes7, bytes8, bytes9, bytes10, bytes11, bytes12, bytes13, bytes14, bytes15, bytes16, bytes17, bytes18, bytes19, bytes20, bytes21, bytes22, bytes23, bytes24, bytes25, bytes26, bytes27, bytes28, bytes29, bytes30, bytes31, bytes32, enum, int, int8, int16, int24, int32, int40, int48, int56, int64, int72, int80, int88, int96, int104, int112, int120, int128, int136, int144, int152, int160, int168, int176, int184, int192, int200, int208, int216, int224, int232, int240, int248, int256, mapping, string, uint, uint8, uint16, uint24, uint32, uint40, uint48, uint56, uint64, uint72, uint80, uint88, uint96, uint104, uint112, uint120, uint128, uint136, uint144, uint152, uint160, uint168, uint176, uint184, uint192, uint200, uint208, uint216, uint224, uint232, uint240, uint248, uint256, var, void, ether, finney, szabo, wei, days, hours, minutes, seconds, weeks, years}, % types; money and time units 12 | keywordstyle=[2]\color{teal}\bfseries, 13 | keywords=[3]{block, blockhash, coinbase, difficulty, gaslimit, number, timestamp, msg, data, gas, sender, sig, value, now, tx, gasprice, origin}, % environment variables 14 | keywordstyle=[3]\color{violet}\bfseries, 15 | identifierstyle=\color{black}, 16 | sensitive=false, 17 | comment=[l]{//}, 18 | morecomment=[s]{/*}{*/}, 19 | commentstyle=\color{gray}\ttfamily, 20 | stringstyle=\color{red}\ttfamily, 21 | morestring=[b]', 22 | morestring=[b]" 23 | } 24 | 25 | \lstset{ 26 | language=Solidity, 27 | backgroundcolor=\color{verylightgray}, 28 | extendedchars=true, 29 | basicstyle=\footnotesize\ttfamily, 30 | showstringspaces=false, 31 | showspaces=false, 32 | numbers=left, 33 | numberstyle=\footnotesize, 34 | numbersep=9pt, 35 | tabsize=2, 36 | breaklines=true, 37 | showtabs=false, 38 | captionpos=b 39 | } 40 | 41 | --------------------------------------------------------------------------------