├── .circleci └── config.yml ├── .gitignore ├── .vscode └── settings.json ├── LICENSE.md ├── Makefile ├── Pipfile ├── Pipfile.lock ├── README.md ├── index.html └── src ├── __init__.py ├── conftest.py ├── html.py └── main.py /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | test: 4 | docker: 5 | - image: circleci/mariadb:10-bionic 6 | environment: 7 | LC_ALL: C.UTF-8 8 | LANG: C.UTF-8 9 | 10 | working_directory: ~/ethereum-reference 11 | 12 | steps: 13 | - checkout 14 | - run: 15 | name: Install make 16 | command: | 17 | apt-get -y update 18 | apt-get install -y cmake 19 | - run: 20 | name: Install git 21 | command: apt-get install -y git 22 | - restore_cache: 23 | keys: 24 | - venv-cache-v1-{{ .Branch }} 25 | - venv-cache-v1 26 | - run: 27 | name: Install python 28 | command: make python 29 | - run: 30 | name: Install Solidity compiler solc 31 | command: | 32 | apt-get install wget 33 | wget -O /usr/bin/solc-0.5.14 https://github.com/ethereum/solidity/releases/download/v0.5.14/solc-static-linux 34 | chmod +x /usr/bin/solc-0.5.14 35 | cp /usr/bin/solc-0.5.14 /usr/bin/solc 36 | - run: 37 | name: Install Python 3.7 38 | command: | 39 | apt-get install -y software-properties-common 40 | make python37 41 | - run: 42 | name: Install package 43 | command: make install 44 | - run: 45 | name: Run tests 46 | command: make test 47 | - run: 48 | name: Run mypy 49 | command: make types 50 | - save_cache: 51 | key: venv-cache-v1-{{ .Branch }} 52 | paths: ~/.local/share/virtualenvs/ 53 | 54 | workflows: 55 | version: 2 56 | build_and_test: 57 | jobs: 58 | - test 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | 106 | # VS Code 107 | .vscode -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.pythonPath": "/Users/p/.local/share/virtualenvs/ethereum-reference-8DTocssE/bin/python" 3 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Content released under [creative commons attribution-sharealike 3.0](http://creativecommons.org/licenses/by-sa/3.0/). 2 | 3 | Content loosely adapted from [hyperpolyglot](https://github.com/clarkgrubb/hyperpolyglot) by [Clark Grubb](https://github.com/clarkgrubb) and is distributed under the same license for compliance. In particular, the Ethereum Reference reuses elements of the scripting language 4 | cheat sheets like code snippets and categories. 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | install: FORCE # Pull in local project dependencies 2 | pipenv install 3 | pipenv install --dev 4 | pipenv lock --pre 5 | 6 | test: FORCE # Run tests 7 | pipenv run pytest --doctest-modules 8 | 9 | format: FORCE # Auto-format Python code 10 | pipenv run black src 11 | 12 | types: FORCE # Type check 13 | pipenv run mypy --ignore-missing-imports src/* 14 | 15 | run: FORCE # Generate and print markdown file to stdout 16 | pipenv run python -m src.main 17 | 18 | push: FORCE # Prepare gen.html file for publishing 19 | pipenv run python -m src.main > ../ethereum-reference-www/src/cheatsheet/main.md 20 | 21 | live: FORCE # Create a live reload server 22 | ls src/* | entr -s "pipenv run python -m src.main" 23 | 24 | python: FORCE 25 | apt-get update -qy 26 | apt-get install -y python3-dev python3-pip 27 | pip3 install pipenv 28 | 29 | python37: FORCE 30 | add-apt-repository -y ppa:deadsnakes/ppa 31 | apt-get install -y python3.7 python3.7-dev 32 | 33 | FORCE: 34 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | pytest = "*" 8 | mypy = "*" 9 | black = "*" 10 | pylint = "*" 11 | 12 | [packages] 13 | yattag = "*" 14 | sh = "*" 15 | pysolc = {editable = true,git = "https://github.com/Jonasmpi/py-solc.git"} 16 | web3 = {extras = ["tester"],version = "*"} 17 | vyper = "*" 18 | 19 | [requires] 20 | python_version = "3.7" 21 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "e308c638a3545cfffc7ebdc195ef5c382f52f7b46a426000bbb3320d801ee3a8" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.7" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "asttokens": { 20 | "hashes": [ 21 | "sha256:284831ac3e33be743ca6ac018316b66abfd8b1a49d6366ce6c7b1fd07504a21b", 22 | "sha256:f58af645756597143629a4ac1fe78bc670b4429018ad741ac1f4cfd4504fc436" 23 | ], 24 | "version": "==2.0.3" 25 | }, 26 | "attrdict": { 27 | "hashes": [ 28 | "sha256:35c90698b55c683946091177177a9e9c0713a0860f0e049febd72649ccd77b70", 29 | "sha256:9432e3498c74ff7e1b20b3d93b45d766b71cbffa90923496f82c4ae38b92be34" 30 | ], 31 | "version": "==2.0.1" 32 | }, 33 | "attrs": { 34 | "hashes": [ 35 | "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", 36 | "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72" 37 | ], 38 | "version": "==19.3.0" 39 | }, 40 | "base58": { 41 | "hashes": [ 42 | "sha256:1e42993c0628ed4f898c03b522b26af78fb05115732549b21a028bc4633d19ab", 43 | "sha256:6aa0553e477478993588303c54659d15e3c17ae062508c854a8b752d07c716bd", 44 | "sha256:9a793c599979c497800eb414c852b80866f28daaed5494703fc129592cc83e60" 45 | ], 46 | "version": "==1.0.3" 47 | }, 48 | "cached-property": { 49 | "hashes": [ 50 | "sha256:3a026f1a54135677e7da5ce819b0c690f156f37976f3e30c5430740725203d7f", 51 | "sha256:9217a59f14a5682da7c4b8829deadbfc194ac22e9908ccf7c8820234e80a1504" 52 | ], 53 | "version": "==1.5.1" 54 | }, 55 | "certifi": { 56 | "hashes": [ 57 | "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3", 58 | "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f" 59 | ], 60 | "version": "==2019.11.28" 61 | }, 62 | "chardet": { 63 | "hashes": [ 64 | "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", 65 | "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" 66 | ], 67 | "version": "==3.0.4" 68 | }, 69 | "cytoolz": { 70 | "hashes": [ 71 | "sha256:82f5bba81d73a5a6b06f2a3553ff9003d865952fcb32e1df192378dd944d8a5c" 72 | ], 73 | "markers": "implementation_name == 'cpython'", 74 | "version": "==0.10.1" 75 | }, 76 | "eth-abi": { 77 | "hashes": [ 78 | "sha256:a8f3cc48a057dfcc77d4138920d482a9b0d3044e0ad68f0bc1bd8762720e0c13", 79 | "sha256:ca76f5e64bc1d7a89edd7ab88dbf1afc21956f91b7ac00e062c4db5d8cd6e0c5" 80 | ], 81 | "version": "==2.1.0" 82 | }, 83 | "eth-account": { 84 | "hashes": [ 85 | "sha256:bf857f800a3cb6a7d0535850dfc229fbfb9d04b124cdd0969881d6d5ec9cb645", 86 | "sha256:fa8308c1d280cfde28455d8c031c3a048c8811e502e750ec0d2cff76988dcd0b" 87 | ], 88 | "version": "==0.4.0" 89 | }, 90 | "eth-bloom": { 91 | "hashes": [ 92 | "sha256:7946722121f40d76aba2a148afe5edde714d119c7d698ddd0ef4d5a1197c3765", 93 | "sha256:89d415710af1480683226e95805519f7c79b7244a3ca8d5287684301c7cee3de" 94 | ], 95 | "version": "==1.0.3" 96 | }, 97 | "eth-hash": { 98 | "extras": [ 99 | "pycryptodome", 100 | "pysha3" 101 | ], 102 | "hashes": [ 103 | "sha256:1b9cb34dd3cd99c85c2bd6a1420ceae39a2eee8bf080efd264bcda8be3edecc8", 104 | "sha256:499dc02d098f69856d1a6dd005529c16174157d4fb2a9fe20c41f69e39f8f176" 105 | ], 106 | "version": "==0.2.0" 107 | }, 108 | "eth-keyfile": { 109 | "hashes": [ 110 | "sha256:70d734af17efdf929a90bb95375f43522be4ed80c3b9e0a8bca575fb11cd1159", 111 | "sha256:939540efb503380bc30d926833e6a12b22c6750de80feef3720d79e5a79de47d" 112 | ], 113 | "version": "==0.5.1" 114 | }, 115 | "eth-keys": { 116 | "hashes": [ 117 | "sha256:d1cdcd6b2118edf5dcd112ba6efc4b187b028c5c7d6af6ca04d90b7af94a1c58", 118 | "sha256:e15a0140852552ec3eb07e9731e23d390aea4bae892022279af42ce32e9c2620" 119 | ], 120 | "version": "==0.2.4" 121 | }, 122 | "eth-rlp": { 123 | "hashes": [ 124 | "sha256:05d8456981d85e16a9afa57f2f2c3356af5d1c49499cc8512cfcdc034b90dde5", 125 | "sha256:a94744c207ea731a7266bd0894179dc6e51a6a8965316000c8e823b5d7e07694" 126 | ], 127 | "version": "==0.1.2" 128 | }, 129 | "eth-tester": { 130 | "extras": [ 131 | "py-evm" 132 | ], 133 | "hashes": [ 134 | "sha256:03554e01eec57faefba256cca8c88beab1651eefb39f2ca9a21493acccc056e2", 135 | "sha256:4387251b8323a181738f6999fb24b5ebf8931c0f4348cb6c0ca49cb015475b46" 136 | ], 137 | "version": "==0.2.0b2" 138 | }, 139 | "eth-typing": { 140 | "hashes": [ 141 | "sha256:2f3e1f891226148898b219bd94674a9af06c2d75d8cdd8c6722227b472cbd4d4", 142 | "sha256:cf9e5e9fb62cfeb1027823328569315166851c65c5774604d801b6b926ff65bc" 143 | ], 144 | "version": "==2.2.1" 145 | }, 146 | "eth-utils": { 147 | "hashes": [ 148 | "sha256:8358318685e7a7666b148b07df3c4d409435b424dce18501e79920aa52bcaba7", 149 | "sha256:f398c649859cda5ef7c4ee2753468038d93be7d864de7631c06c3e73a7060649" 150 | ], 151 | "version": "==1.8.4" 152 | }, 153 | "hexbytes": { 154 | "hashes": [ 155 | "sha256:438ba9a28dfcda2c2276954b4310f9af1604fb198bfe5ac44c6518feaf6d376a", 156 | "sha256:9e8b3e3dc4a7de23c0cf1bb3c3edfcc1f0df4b78927bad63816c27a027b8b7d1" 157 | ], 158 | "version": "==0.2.0" 159 | }, 160 | "idna": { 161 | "hashes": [ 162 | "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", 163 | "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" 164 | ], 165 | "version": "==2.8" 166 | }, 167 | "importlib-metadata": { 168 | "hashes": [ 169 | "sha256:bdd9b7c397c273bcc9a11d6629a38487cd07154fa255a467bf704cd2c258e359", 170 | "sha256:f17c015735e1a88296994c0697ecea7e11db24290941983b08c9feb30921e6d8" 171 | ], 172 | "markers": "python_version < '3.8'", 173 | "version": "==1.4.0" 174 | }, 175 | "ipfshttpclient": { 176 | "hashes": [ 177 | "sha256:0a199a1005fe44bff9da28b5af4785b0b09ca700baac9d1e26718fe23fe89bb7", 178 | "sha256:bee95c500edf669bb8a984d5588fc133fda9ec67845c5688bcbbea030a03f10f" 179 | ], 180 | "version": "==0.4.12" 181 | }, 182 | "jsonschema": { 183 | "hashes": [ 184 | "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163", 185 | "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a" 186 | ], 187 | "version": "==3.2.0" 188 | }, 189 | "lru-dict": { 190 | "hashes": [ 191 | "sha256:365457660e3d05b76f1aba3e0f7fedbfcd6528e97c5115a351ddd0db488354cc" 192 | ], 193 | "version": "==1.1.6" 194 | }, 195 | "more-itertools": { 196 | "hashes": [ 197 | "sha256:1a2a32c72400d365000412fe08eb4a24ebee89997c18d3d147544f70f5403b39", 198 | "sha256:c468adec578380b6281a114cb8a5db34eb1116277da92d7c46f904f0b52d3288" 199 | ], 200 | "version": "==8.1.0" 201 | }, 202 | "multiaddr": { 203 | "hashes": [ 204 | "sha256:30b2695189edc3d5b90f1c303abb8f02d963a3a4edf2e7178b975eb417ab0ecf", 205 | "sha256:5c0f862cbcf19aada2a899f80ef896ddb2e85614e0c8f04dd287c06c69dac95b" 206 | ], 207 | "version": "==0.0.9" 208 | }, 209 | "mypy-extensions": { 210 | "hashes": [ 211 | "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", 212 | "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8" 213 | ], 214 | "version": "==0.4.3" 215 | }, 216 | "netaddr": { 217 | "hashes": [ 218 | "sha256:38aeec7cdd035081d3a4c306394b19d677623bf76fa0913f6695127c7753aefd", 219 | "sha256:56b3558bd71f3f6999e4c52e349f38660e54a7a8a9943335f73dfc96883e08ca" 220 | ], 221 | "version": "==0.7.19" 222 | }, 223 | "parsimonious": { 224 | "hashes": [ 225 | "sha256:3add338892d580e0cb3b1a39e4a1b427ff9f687858fdd61097053742391a9f6b" 226 | ], 227 | "version": "==0.8.1" 228 | }, 229 | "protobuf": { 230 | "hashes": [ 231 | "sha256:0329e86a397db2a83f9dcbe21d9be55a47f963cdabc893c3a24f4d3a8f117c37", 232 | "sha256:0a7219254afec0d488211f3d482d8ed57e80ae735394e584a98d8f30a8c88a36", 233 | "sha256:14d6ac53df9cb5bb87c4f91b677c1bc5cec9c0fd44327f367a3c9562de2877c4", 234 | "sha256:180fc364b42907a1d2afa183ccbeffafe659378c236b1ec3daca524950bb918d", 235 | "sha256:3d7a7d8d20b4e7a8f63f62de2d192cfd8b7a53c56caba7ece95367ca2b80c574", 236 | "sha256:3f509f7e50d806a434fe4a5fbf602516002a0f092889209fff7db82060efffc0", 237 | "sha256:4571da974019849201fc1ec6626b9cea54bd11b6bed140f8f737c0a33ea37de5", 238 | "sha256:56bd1d84fbf4505c7b73f04de987eef5682e5752c811141b0186a3809bfb396f", 239 | "sha256:680c668d00b5eff08b86aef9e5ba9a705e621ea05d39071cfea8e28cb2400946", 240 | "sha256:6b5b947dc8b3f2aec0eaad65b0b5113fcd642c358c31357c647da6281ee31104", 241 | "sha256:6e96dffaf4d0a9a329e528b353ba62fd9ef13599688723d96bc9c165d0b6871e", 242 | "sha256:919f0d6f6addc836d08658eba3b52be2e92fd3e76da3ce00c325d8e9826d17c7", 243 | "sha256:9c7b19c30cf0644afd0e4218b13f637ce54382fdcb1c8f75bf3e84e49a5f6d0a", 244 | "sha256:a2e6f57114933882ec701807f217df2fb4588d47f71f227c0a163446b930d507", 245 | "sha256:a6b970a2eccfcbabe1acf230fbf112face1c4700036c95e195f3554d7bcb04c1", 246 | "sha256:bc45641cbcdea068b67438244c926f9fd3e5cbdd824448a4a64370610df7c593", 247 | "sha256:d61b14a9090da77fe87e38ba4c6c43d3533dcbeb5d84f5474e7ac63c532dcc9c", 248 | "sha256:d6faf5dbefb593e127463f58076b62fcfe0784187be8fe1aa9167388f24a22a1" 249 | ], 250 | "version": "==3.11.2" 251 | }, 252 | "py-ecc": { 253 | "hashes": [ 254 | "sha256:67136ea75c35f7610b8060861c9999eecbe7f22c690882daadbe4e1712a314c0", 255 | "sha256:c209755bd5943c89ad6fba385c84a891c66fd74e4a5f0cfd3ea72eb9164df70c" 256 | ], 257 | "version": "==1.7.1" 258 | }, 259 | "py-evm": { 260 | "hashes": [ 261 | "sha256:3e1f39a74bbee0403ddddc28170950c576060f8d3b9a19e5ebf4980f2717d4b6", 262 | "sha256:8e500e2691ee805ba71127cf8acb412ccd323e567a94d6ad63355774cd0d768f" 263 | ], 264 | "version": "==0.3.0a1" 265 | }, 266 | "py-geth": { 267 | "hashes": [ 268 | "sha256:4af3d8e07738b2991d755c31d5de2d39231aa43c3ca28b74f44d7a5e9792eaff", 269 | "sha256:96b453af4812a152fc71e5736b3e2b457927c58f72b50716b774aadb136c1d0e" 270 | ], 271 | "version": "==2.2.0" 272 | }, 273 | "pycryptodome": { 274 | "hashes": [ 275 | "sha256:042ae873baadd0c33b4d699a5c5b976ade3233a979d972f98ca82314632d868c", 276 | "sha256:0502876279772b1384b660ccc91563d04490d562799d8e2e06b411e2d81128a9", 277 | "sha256:2de33ed0a95855735d5a0fc0c39603314df9e78ee8bbf0baa9692fb46b3b8bbb", 278 | "sha256:319e568baf86620b419d53063b18c216abf924875966efdfe06891b987196a45", 279 | "sha256:4372ec7518727172e1605c0843cdc5375d4771e447b8148c787b860260aae151", 280 | "sha256:48821950ffb9c836858d8fa09d7840b6df52eadd387a3c5acece55cb387743f9", 281 | "sha256:4b9533d4166ca07abdd49ce9d516666b1df944997fe135d4b21ac376aa624aff", 282 | "sha256:54456cf85130e01674d21fb1ab89ffccacb138a8ade88d72fa2b0ac898d2798b", 283 | "sha256:56fdd0e425f1b8fd3a00b6d96351f86226674974814c50534864d0124d48871f", 284 | "sha256:57b1b707363490c495ad0eeb38bd1b0e1697c497af25fad78d3a1ebf0477fd5b", 285 | "sha256:5c485ed6e9718ebcaa81138fa70ace9c563d202b56a8cee119b4085b023931f5", 286 | "sha256:63c103a22cbe9752f6ea9f1a0de129995bad91c4d03a66c67cffcf6ee0c9f1e1", 287 | "sha256:68fab8455efcbfe87c5d75015476f9b606227ffe244d57bfd66269451706e899", 288 | "sha256:6c2720696b10ae356040e888bde1239b8957fe18885ccf5e7b4e8dec882f0856", 289 | "sha256:72166c2ac520a5dbd2d90208b9c279161ec0861662a621892bd52fb6ca13ab91", 290 | "sha256:7c52308ac5b834331b2f107a490b2c27de024a229b61df4cdc5c131d563dfe98", 291 | "sha256:87d8d85b4792ca5e730fb7a519fbc3ed976c59dcf79c5204589c59afd56b9926", 292 | "sha256:896e9b6fd0762aa07b203c993fbbee7a1f1a4674c6886afd7bfa86f3d1be98a8", 293 | "sha256:8a799bea3c6617736e914a2e77c409f52893d382f619f088f8a80e2e21f573c1", 294 | "sha256:9d9945ac8375d5d8e60bd2a2e1df5882eaa315522eedf3ca868b1546dfa34eba", 295 | "sha256:9ef966c727de942de3e41aa8462c4b7b4bca70f19af5a3f99e31376589c11aac", 296 | "sha256:a168e73879619b467072509a223282a02c8047d932a48b74fbd498f27224aa04", 297 | "sha256:a30f501bbb32e01a49ef9e09ca1260e5ab49bf33a257080ec553e08997acc487", 298 | "sha256:a8ca2450394d3699c9f15ef25e8de9a24b401933716a1e39d37fa01f5fe3c58b", 299 | "sha256:aec4d42deb836b8fb3ba32f2ba1ef0d33dd3dc9d430b1479ee7a914490d15b5e", 300 | "sha256:b4af098f2a50f8d048ab12cabb59456585c0acf43d90ee79782d2d6d0ed59dba", 301 | "sha256:b55c60c321ac91945c60a40ac9896ac7a3d432bb3e8c14006dfd82ad5871c331", 302 | "sha256:c53348358408d94869059e16fba5ff3bef8c52c25b18421472aba272b9bb450f", 303 | "sha256:cbfd97f9e060f0d30245cd29fa267a9a84de9da97559366fca0a3f7655acc63f", 304 | "sha256:d3fe3f33ad52bf0c19ee6344b695ba44ffbfa16f3c29ca61116b48d97bd970fb", 305 | "sha256:e3a79a30d15d9c7c284a7734036ee8abdb5ca3a6f5774d293cdc9e1358c1dc10", 306 | "sha256:eec0689509389f19875f66ae8dedd59f982240cdab31b9f78a8dc266011df93a" 307 | ], 308 | "version": "==3.9.4" 309 | }, 310 | "pyethash": { 311 | "hashes": [ 312 | "sha256:ff66319ce26b9d77df1f610942634dac9742e216f2c27b051c0a2c2dec9c2818" 313 | ], 314 | "version": "==0.1.27" 315 | }, 316 | "pyrsistent": { 317 | "hashes": [ 318 | "sha256:cdc7b5e3ed77bed61270a47d35434a30617b9becdf2478af76ad2c6ade307280" 319 | ], 320 | "version": "==0.15.7" 321 | }, 322 | "pysha3": { 323 | "hashes": [ 324 | "sha256:0060a66be16665d90c432f55a0ba1f6480590cfb7d2ad389e688a399183474f0", 325 | "sha256:11a2ba7a2e1d9669d0052fc8fb30f5661caed5512586ecbeeaf6bf9478ab5c48", 326 | "sha256:386998ee83e313b6911327174e088021f9f2061cbfa1651b97629b761e9ef5c4", 327 | "sha256:41be70b06c8775a9e4d4eeb52f2f6a3f356f17539a54eac61f43a29e42fd453d", 328 | "sha256:4416f16b0f1605c25f627966f76873e432971824778b369bd9ce1bb63d6566d9", 329 | "sha256:571a246308a7b63f15f5aa9651f99cf30f2a6acba18eddf28f1510935968b603", 330 | "sha256:59111c08b8f34495575d12e5f2ce3bafb98bea470bc81e70c8b6df99aef0dd2f", 331 | "sha256:5ec8da7c5c70a53b5fa99094af3ba8d343955b212bc346a0d25f6ff75853999f", 332 | "sha256:684cb01d87ed6ff466c135f1c83e7e4042d0fc668fa20619f581e6add1d38d77", 333 | "sha256:68c3a60a39f9179b263d29e221c1bd6e01353178b14323c39cc70593c30f21c5", 334 | "sha256:6e6a84efb7856f5d760ee55cd2b446972cb7b835676065f6c4f694913ea8f8d9", 335 | "sha256:827b308dc025efe9b6b7bae36c2e09ed0118a81f792d888548188e97b9bf9a3d", 336 | "sha256:93abd775dac570cb9951c4e423bcb2bc6303a9d1dc0dc2b7afa2dd401d195b24", 337 | "sha256:9c778fa8b161dc9348dc5cc361e94d54aa5ff18413788f4641f6600d4893a608", 338 | "sha256:9fdd28884c5d0b4edfed269b12badfa07f1c89dbc5c9c66dd279833894a9896b", 339 | "sha256:c7c2adcc43836223680ebdf91f1d3373543dc32747c182c8ca2e02d1b69ce030", 340 | "sha256:c93a2676e6588abcfaecb73eb14485c81c63b94fca2000a811a7b4fb5937b8e8", 341 | "sha256:cd5c961b603bd2e6c2b5ef9976f3238a561c58569945d4165efb9b9383b050ef", 342 | "sha256:f9046d59b3e72aa84f6dae83a040bd1184ebd7fef4e822d38186a8158c89e3cf", 343 | "sha256:fd7e66999060d079e9c0e8893e78d8017dad4f59721f6fe0be6307cd32127a07", 344 | "sha256:fe988e73f2ce6d947220624f04d467faf05f1bbdbc64b0a201296bb3af92739e" 345 | ], 346 | "version": "==1.0.2" 347 | }, 348 | "pysolc": { 349 | "editable": true, 350 | "git": "https://github.com/Jonasmpi/py-solc.git", 351 | "ref": "88cdaeb10eff79c07a502d0333893a66d59f575f" 352 | }, 353 | "requests": { 354 | "hashes": [ 355 | "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", 356 | "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" 357 | ], 358 | "version": "==2.22.0" 359 | }, 360 | "rlp": { 361 | "hashes": [ 362 | "sha256:27273fc2dbc3513c1e05ea6b8af28aac8745fb09c164e39e2ed2807bf7e1b342", 363 | "sha256:97b7e770f16442772311b33e6bc28b45318e7c8def69b9df16452304e224e9df" 364 | ], 365 | "version": "==1.2.0" 366 | }, 367 | "semantic-version": { 368 | "hashes": [ 369 | "sha256:352459f640f3db86551d8054d1288608b29a96e880c7746f0a59c92879d412a3", 370 | "sha256:4eedff095ecdd7790a9e6d7130d49250209e0c7bf6741423c4a4017d9bac4c04" 371 | ], 372 | "version": "==2.8.4" 373 | }, 374 | "sh": { 375 | "hashes": [ 376 | "sha256:ae3258c5249493cebe73cb4e18253a41ed69262484bad36fdb3efcb8ad8870bb", 377 | "sha256:b52bf5833ed01c7b5c5fb73a7f71b3d98d48e9b9b8764236237bdc7ecae850fc" 378 | ], 379 | "index": "pypi", 380 | "version": "==1.12.14" 381 | }, 382 | "six": { 383 | "hashes": [ 384 | "sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd", 385 | "sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66" 386 | ], 387 | "version": "==1.13.0" 388 | }, 389 | "toolz": { 390 | "hashes": [ 391 | "sha256:08fdd5ef7c96480ad11c12d472de21acd32359996f69a5259299b540feba4560" 392 | ], 393 | "version": "==0.10.0" 394 | }, 395 | "trie": { 396 | "hashes": [ 397 | "sha256:5b7dedfeedd03c0d6b486b1b21c8182242307daff1bb011fed150a6c8dc4e34b", 398 | "sha256:5c9501bc1af2c065502601370fc991c496c186c725ca408993d65a0792c2949b" 399 | ], 400 | "version": "==1.4.0" 401 | }, 402 | "typing": { 403 | "hashes": [ 404 | "sha256:91dfe6f3f706ee8cc32d38edbbf304e9b7583fb37108fef38229617f8b3eba23", 405 | "sha256:c8cabb5ab8945cd2f54917be357d134db9cc1eb039e59d1606dc1e60cb1d9d36", 406 | "sha256:f38d83c5a7a7086543a0f649564d661859c5146a85775ab90c0d2f93ffaa9714" 407 | ], 408 | "version": "==3.7.4.1" 409 | }, 410 | "typing-extensions": { 411 | "hashes": [ 412 | "sha256:091ecc894d5e908ac75209f10d5b4f118fbdb2eb1ede6a63544054bb1edb41f2", 413 | "sha256:910f4656f54de5993ad9304959ce9bb903f90aadc7c67a0bef07e678014e892d", 414 | "sha256:cf8b63fedea4d89bab840ecbb93e75578af28f76f66c35889bd7065f5af88575" 415 | ], 416 | "version": "==3.7.4.1" 417 | }, 418 | "urllib3": { 419 | "hashes": [ 420 | "sha256:a8a318824cc77d1fd4b2bec2ded92646630d7fe8619497b142c84a9e6f5a7293", 421 | "sha256:f3c5fd51747d450d4dcf6f923c81f78f811aab8205fda64b0aba34a4e48b0745" 422 | ], 423 | "version": "==1.25.7" 424 | }, 425 | "varint": { 426 | "hashes": [ 427 | "sha256:a6ecc02377ac5ee9d65a6a8ad45c9ff1dac8ccee19400a5950fb51d594214ca5" 428 | ], 429 | "version": "==1.0.2" 430 | }, 431 | "vyper": { 432 | "hashes": [ 433 | "sha256:c78728cd9f2e7810e4b7c32df0e8fedaea09fb611b16475d19b680cdfde5ce1b", 434 | "sha256:d86e6bcc85e9e7e2c633248690aa76fc7ff68cd6eb55261ad04a1aaa3ca9fe62" 435 | ], 436 | "index": "pypi", 437 | "version": "==0.1.0b16" 438 | }, 439 | "web3": { 440 | "extras": [ 441 | "tester" 442 | ], 443 | "hashes": [ 444 | "sha256:770dbbb86da23185df06bef1c2ed7c871f6f8714ac3d3cfe2e7f57f0bfb98086", 445 | "sha256:f4362d37137ab42423a38569fc0f6ff3b53a107925ac45345e798ed1d09da301" 446 | ], 447 | "index": "pypi", 448 | "version": "==5.4.0" 449 | }, 450 | "websockets": { 451 | "hashes": [ 452 | "sha256:0e4fb4de42701340bd2353bb2eee45314651caa6ccee80dbd5f5d5978888fed5", 453 | "sha256:1d3f1bf059d04a4e0eb4985a887d49195e15ebabc42364f4eb564b1d065793f5", 454 | "sha256:20891f0dddade307ffddf593c733a3fdb6b83e6f9eef85908113e628fa5a8308", 455 | "sha256:295359a2cc78736737dd88c343cd0747546b2174b5e1adc223824bcaf3e164cb", 456 | "sha256:2db62a9142e88535038a6bcfea70ef9447696ea77891aebb730a333a51ed559a", 457 | "sha256:3762791ab8b38948f0c4d281c8b2ddfa99b7e510e46bd8dfa942a5fff621068c", 458 | "sha256:3db87421956f1b0779a7564915875ba774295cc86e81bc671631379371af1170", 459 | "sha256:3ef56fcc7b1ff90de46ccd5a687bbd13a3180132268c4254fc0fa44ecf4fc422", 460 | "sha256:4f9f7d28ce1d8f1295717c2c25b732c2bc0645db3215cf757551c392177d7cb8", 461 | "sha256:5c01fd846263a75bc8a2b9542606927cfad57e7282965d96b93c387622487485", 462 | "sha256:5c65d2da8c6bce0fca2528f69f44b2f977e06954c8512a952222cea50dad430f", 463 | "sha256:751a556205d8245ff94aeef23546a1113b1dd4f6e4d102ded66c39b99c2ce6c8", 464 | "sha256:7ff46d441db78241f4c6c27b3868c9ae71473fe03341340d2dfdbe8d79310acc", 465 | "sha256:965889d9f0e2a75edd81a07592d0ced54daa5b0785f57dc429c378edbcffe779", 466 | "sha256:9b248ba3dd8a03b1a10b19efe7d4f7fa41d158fdaa95e2cf65af5a7b95a4f989", 467 | "sha256:9bef37ee224e104a413f0780e29adb3e514a5b698aabe0d969a6ba426b8435d1", 468 | "sha256:c1ec8db4fac31850286b7cd3b9c0e1b944204668b8eb721674916d4e28744092", 469 | "sha256:c8a116feafdb1f84607cb3b14aa1418424ae71fee131642fc568d21423b51824", 470 | "sha256:ce85b06a10fc65e6143518b96d3dca27b081a740bae261c2fb20375801a9d56d", 471 | "sha256:d705f8aeecdf3262379644e4b55107a3b55860eb812b673b28d0fbc347a60c55", 472 | "sha256:e898a0863421650f0bebac8ba40840fc02258ef4714cb7e1fd76b6a6354bda36", 473 | "sha256:f8a7bff6e8664afc4e6c28b983845c5bc14965030e3fb98789734d416af77c4b" 474 | ], 475 | "version": "==8.1" 476 | }, 477 | "yattag": { 478 | "hashes": [ 479 | "sha256:2727546210d2bc893727f42250125a1c080e938e046bcf0c45af4c959d61473e" 480 | ], 481 | "index": "pypi", 482 | "version": "==1.13.1" 483 | }, 484 | "zipp": { 485 | "hashes": [ 486 | "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e", 487 | "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335" 488 | ], 489 | "version": "==0.6.0" 490 | } 491 | }, 492 | "develop": { 493 | "appdirs": { 494 | "hashes": [ 495 | "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92", 496 | "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e" 497 | ], 498 | "version": "==1.4.3" 499 | }, 500 | "attrs": { 501 | "hashes": [ 502 | "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", 503 | "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72" 504 | ], 505 | "version": "==19.3.0" 506 | }, 507 | "black": { 508 | "hashes": [ 509 | "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b", 510 | "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539" 511 | ], 512 | "index": "pypi", 513 | "version": "==19.10b0" 514 | }, 515 | "click": { 516 | "hashes": [ 517 | "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", 518 | "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" 519 | ], 520 | "version": "==7.0" 521 | }, 522 | "importlib-metadata": { 523 | "hashes": [ 524 | "sha256:bdd9b7c397c273bcc9a11d6629a38487cd07154fa255a467bf704cd2c258e359", 525 | "sha256:f17c015735e1a88296994c0697ecea7e11db24290941983b08c9feb30921e6d8" 526 | ], 527 | "markers": "python_version < '3.8'", 528 | "version": "==1.4.0" 529 | }, 530 | "more-itertools": { 531 | "hashes": [ 532 | "sha256:1a2a32c72400d365000412fe08eb4a24ebee89997c18d3d147544f70f5403b39", 533 | "sha256:c468adec578380b6281a114cb8a5db34eb1116277da92d7c46f904f0b52d3288" 534 | ], 535 | "version": "==8.1.0" 536 | }, 537 | "mypy": { 538 | "hashes": [ 539 | "sha256:0a9a45157e532da06fe56adcfef8a74629566b607fa2c1ac0122d1ff995c748a", 540 | "sha256:2c35cae79ceb20d47facfad51f952df16c2ae9f45db6cb38405a3da1cf8fc0a7", 541 | "sha256:4b9365ade157794cef9685791032521233729cb00ce76b0ddc78749abea463d2", 542 | "sha256:53ea810ae3f83f9c9b452582261ea859828a9ed666f2e1ca840300b69322c474", 543 | "sha256:634aef60b4ff0f650d3e59d4374626ca6153fcaff96ec075b215b568e6ee3cb0", 544 | "sha256:7e396ce53cacd5596ff6d191b47ab0ea18f8e0ec04e15d69728d530e86d4c217", 545 | "sha256:7eadc91af8270455e0d73565b8964da1642fe226665dd5c9560067cd64d56749", 546 | "sha256:7f672d02fffcbace4db2b05369142e0506cdcde20cea0e07c7c2171c4fd11dd6", 547 | "sha256:85baab8d74ec601e86134afe2bcccd87820f79d2f8d5798c889507d1088287bf", 548 | "sha256:87c556fb85d709dacd4b4cb6167eecc5bbb4f0a9864b69136a0d4640fdc76a36", 549 | "sha256:a6bd44efee4dc8c3324c13785a9dc3519b3ee3a92cada42d2b57762b7053b49b", 550 | "sha256:c6d27bd20c3ba60d5b02f20bd28e20091d6286a699174dfad515636cb09b5a72", 551 | "sha256:e2bb577d10d09a2d8822a042a23b8d62bc3b269667c9eb8e60a6edfa000211b1", 552 | "sha256:f97a605d7c8bc2c6d1172c2f0d5a65b24142e11a58de689046e62c2d632ca8c1" 553 | ], 554 | "index": "pypi", 555 | "version": "==0.761" 556 | }, 557 | "mypy-extensions": { 558 | "hashes": [ 559 | "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", 560 | "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8" 561 | ], 562 | "version": "==0.4.3" 563 | }, 564 | "packaging": { 565 | "hashes": [ 566 | "sha256:aec3fdbb8bc9e4bb65f0634b9f551ced63983a529d6a8931817d52fdd0816ddb", 567 | "sha256:fe1d8331dfa7cc0a883b49d75fc76380b2ab2734b220fbb87d774e4fd4b851f8" 568 | ], 569 | "version": "==20.0" 570 | }, 571 | "pathspec": { 572 | "hashes": [ 573 | "sha256:163b0632d4e31cef212976cf57b43d9fd6b0bac6e67c26015d611a647d5e7424", 574 | "sha256:562aa70af2e0d434367d9790ad37aed893de47f1693e4201fd1d3dca15d19b96" 575 | ], 576 | "version": "==0.7.0" 577 | }, 578 | "pluggy": { 579 | "hashes": [ 580 | "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", 581 | "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" 582 | ], 583 | "version": "==0.13.1" 584 | }, 585 | "py": { 586 | "hashes": [ 587 | "sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa", 588 | "sha256:c20fdd83a5dbc0af9efd622bee9a5564e278f6380fffcacc43ba6f43db2813b0" 589 | ], 590 | "version": "==1.8.1" 591 | }, 592 | "pyparsing": { 593 | "hashes": [ 594 | "sha256:4c830582a84fb022400b85429791bc551f1f4871c33f23e44f353119e92f969f", 595 | "sha256:c342dccb5250c08d45fd6f8b4a559613ca603b57498511740e65cd11a2e7dcec" 596 | ], 597 | "version": "==2.4.6" 598 | }, 599 | "pytest": { 600 | "hashes": [ 601 | "sha256:6b571215b5a790f9b41f19f3531c53a45cf6bb8ef2988bc1ff9afb38270b25fa", 602 | "sha256:e41d489ff43948babd0fad7ad5e49b8735d5d55e26628a58673c39ff61d95de4" 603 | ], 604 | "index": "pypi", 605 | "version": "==5.3.2" 606 | }, 607 | "regex": { 608 | "hashes": [ 609 | "sha256:07b39bf943d3d2fe63d46281d8504f8df0ff3fe4c57e13d1656737950e53e525", 610 | "sha256:0932941cdfb3afcbc26cc3bcf7c3f3d73d5a9b9c56955d432dbf8bbc147d4c5b", 611 | "sha256:0e182d2f097ea8549a249040922fa2b92ae28be4be4895933e369a525ba36576", 612 | "sha256:10671601ee06cf4dc1bc0b4805309040bb34c9af423c12c379c83d7895622bb5", 613 | "sha256:23e2c2c0ff50f44877f64780b815b8fd2e003cda9ce817a7fd00dea5600c84a0", 614 | "sha256:26ff99c980f53b3191d8931b199b29d6787c059f2e029b2b0c694343b1708c35", 615 | "sha256:27429b8d74ba683484a06b260b7bb00f312e7c757792628ea251afdbf1434003", 616 | "sha256:3e77409b678b21a056415da3a56abfd7c3ad03da71f3051bbcdb68cf44d3c34d", 617 | "sha256:4e8f02d3d72ca94efc8396f8036c0d3bcc812aefc28ec70f35bb888c74a25161", 618 | "sha256:4eae742636aec40cf7ab98171ab9400393360b97e8f9da67b1867a9ee0889b26", 619 | "sha256:6a6ae17bf8f2d82d1e8858a47757ce389b880083c4ff2498dba17c56e6c103b9", 620 | "sha256:6a6ba91b94427cd49cd27764679024b14a96874e0dc638ae6bdd4b1a3ce97be1", 621 | "sha256:7bcd322935377abcc79bfe5b63c44abd0b29387f267791d566bbb566edfdd146", 622 | "sha256:98b8ed7bb2155e2cbb8b76f627b2fd12cf4b22ab6e14873e8641f266e0fb6d8f", 623 | "sha256:bd25bb7980917e4e70ccccd7e3b5740614f1c408a642c245019cff9d7d1b6149", 624 | "sha256:d0f424328f9822b0323b3b6f2e4b9c90960b24743d220763c7f07071e0778351", 625 | "sha256:d58e4606da2a41659c84baeb3cfa2e4c87a74cec89a1e7c56bee4b956f9d7461", 626 | "sha256:e3cd21cc2840ca67de0bbe4071f79f031c81418deb544ceda93ad75ca1ee9f7b", 627 | "sha256:e6c02171d62ed6972ca8631f6f34fa3281d51db8b326ee397b9c83093a6b7242", 628 | "sha256:e7c7661f7276507bce416eaae22040fd91ca471b5b33c13f8ff21137ed6f248c", 629 | "sha256:ecc6de77df3ef68fee966bb8cb4e067e84d4d1f397d0ef6fce46913663540d77" 630 | ], 631 | "version": "==2020.1.8" 632 | }, 633 | "six": { 634 | "hashes": [ 635 | "sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd", 636 | "sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66" 637 | ], 638 | "version": "==1.13.0" 639 | }, 640 | "toml": { 641 | "hashes": [ 642 | "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", 643 | "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e" 644 | ], 645 | "version": "==0.10.0" 646 | }, 647 | "typed-ast": { 648 | "hashes": [ 649 | "sha256:1170afa46a3799e18b4c977777ce137bb53c7485379d9706af8a59f2ea1aa161", 650 | "sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", 651 | "sha256:262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e", 652 | "sha256:2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0", 653 | "sha256:354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c", 654 | "sha256:48e5b1e71f25cfdef98b013263a88d7145879fbb2d5185f2a0c79fa7ebbeae47", 655 | "sha256:4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631", 656 | "sha256:630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4", 657 | "sha256:66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34", 658 | "sha256:71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b", 659 | "sha256:7954560051331d003b4e2b3eb822d9dd2e376fa4f6d98fee32f452f52dd6ebb2", 660 | "sha256:838997f4310012cf2e1ad3803bce2f3402e9ffb71ded61b5ee22617b3a7f6b6e", 661 | "sha256:95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a", 662 | "sha256:bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233", 663 | "sha256:cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1", 664 | "sha256:d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36", 665 | "sha256:d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d", 666 | "sha256:d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a", 667 | "sha256:fdc1c9bbf79510b76408840e009ed65958feba92a88833cdceecff93ae8fff66", 668 | "sha256:ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12" 669 | ], 670 | "version": "==1.4.0" 671 | }, 672 | "typing-extensions": { 673 | "hashes": [ 674 | "sha256:091ecc894d5e908ac75209f10d5b4f118fbdb2eb1ede6a63544054bb1edb41f2", 675 | "sha256:910f4656f54de5993ad9304959ce9bb903f90aadc7c67a0bef07e678014e892d", 676 | "sha256:cf8b63fedea4d89bab840ecbb93e75578af28f76f66c35889bd7065f5af88575" 677 | ], 678 | "version": "==3.7.4.1" 679 | }, 680 | "wcwidth": { 681 | "hashes": [ 682 | "sha256:8fd29383f539be45b20bd4df0dc29c20ba48654a41e661925e612311e9f3c603", 683 | "sha256:f28b3e8a6483e5d49e7f8949ac1a78314e740333ae305b4ba5defd3e74fb37a8" 684 | ], 685 | "version": "==0.1.8" 686 | }, 687 | "zipp": { 688 | "hashes": [ 689 | "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e", 690 | "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335" 691 | ], 692 | "version": "==0.6.0" 693 | } 694 | } 695 | } 696 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ethereum-reference 2 | A Solidity and Vyper reference guide 3 | 4 | ## Outside dependencies 5 | 6 | - `python ==3.7` 7 | - `pipenv` 8 | - OPTIONAL, only needed for live reload development: `entr` (`brew install entr`) 9 | 10 | ## Using the repository 11 | 12 | ### Resolving project dependencies 13 | 14 | ```bash 15 | make install 16 | ``` 17 | 18 | ### Running tests (`pytest) 19 | 20 | ```bash 21 | make test 22 | ``` 23 | 24 | ### Typechecking (`mypy`) 25 | 26 | ```bash 27 | make types 28 | ``` 29 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | pipenv run python -m src.main 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 16 | 20 | 21 | 22 | 23 | 26 | 29 | 30 | 31 | 32 | 35 | 38 | 39 | 40 | 41 | 44 | 47 | 48 | 49 | 50 | 53 | 56 | 57 | 58 | 59 | 63 | 67 | 68 | 69 | 70 | 73 | 76 | 77 | 78 | 79 | 82 | 85 | 86 | 87 | 88 | 91 | 94 | 95 | 96 | 97 | 100 | 103 | 104 | 105 | 106 | 109 | 112 | 113 | 114 | 115 | 118 | 121 | 122 | 123 | 124 | 127 | 130 | 131 | 132 | 133 | 136 | 139 | 140 | 141 | 142 | 145 | 148 | 149 | 150 | 151 | 154 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 171 | 174 | 175 | 176 | 177 | 180 | 183 | 184 | 185 | 186 | 189 | 192 | 193 | 194 | 195 | 198 | 201 | 202 | 203 | 204 | 207 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 227 | 232 | 233 | 234 | 235 | 246 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 263 | 266 | 267 | 268 | 269 | 272 | 275 | 276 | 277 | 278 | 281 | 284 | 285 | 286 | 287 | 290 | 293 | 294 | 295 | 296 | 299 | 302 | 303 | 304 | 305 | 308 | 311 | 312 | 313 | 314 | 317 | 320 | 321 | 322 | 323 | 326 | 329 | 330 | 331 | 332 | 336 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 355 | 358 | 359 | 360 | 361 | 366 | 369 | 370 | 371 | 372 | 376 | 380 | 381 | 382 | 383 | 386 | 389 | 390 | 391 | 392 | 395 | 398 | 399 | 400 | 401 | 415 | 432 | 433 | 434 | 435 | 438 | 441 | 442 | 443 | 444 | 448 | 451 | 452 | 453 | 454 | 457 | 460 | 461 | 462 | 463 | 466 | 469 | 470 | 471 | 472 | 475 | 478 | 479 | 480 | 481 | 484 | 487 | 488 | 489 | 490 | 493 | 496 | 497 | 498 | 499 | 502 | 505 | 506 | 507 | 508 | 511 | 514 | 515 | 516 | 517 | 520 | 523 | 524 | 525 | 526 | 529 | 532 | 533 | 534 | 535 | 538 | 541 | 542 | 543 | 544 | 553 | 561 | 562 | 563 | 564 | 567 | 570 | 571 | 572 | 573 | 576 | 579 | 580 | 581 | 582 | 585 | 588 | 589 | 590 | 591 | 594 | 597 | 598 | 599 | 600 | 603 | 606 | 607 | 608 | 609 | 612 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 631 | 636 | 637 | 638 | 639 | 650 | 653 | 654 | 655 | 656 | 659 | 662 | 663 | 664 | 665 | 668 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 692 | 700 | 701 | 702 | 703 | 708 | 712 | 713 | 714 | 715 | 720 | 723 | 724 | 725 | 726 | 731 | 734 | 735 | 736 | 737 | 740 | 743 | 744 | 745 | 746 | 749 | 752 | 753 | 754 | 755 | 758 | 761 | 762 | 763 | 764 | 767 | 770 | 771 | 772 | 773 | 776 | 779 | 780 | 781 | 782 | 785 | 788 | 789 | 790 | 791 | 820 | 823 | 824 | 825 | 826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 834 | 852 | 863 | 864 | 865 | 866 | 869 | 872 | 873 | 874 | 875 | 878 | 881 | 882 | 883 | 884 | 887 | 890 | 891 | 892 | 893 | 902 | 910 | 911 | 912 | 913 | 929 | 944 | 945 | 946 | 947 | 965 | 983 | 984 |
FeatureSolidityVyper
Version 13 |
$ solc --version
 14 | Version: 0.7.0
15 |
17 |
$ vyper --version
 18 | 0.2.4
19 |
General notes on syntax 24 |

Solidity loosely borrows its syntax from Javascript and C

25 |
27 |

Vyper syntax is valid Python 3 syntax (but the opposite is not true)

28 |
Block delimiters 33 |
{ }
34 |
36 |
:  # Vyper uses Python's off-side rule
37 |
Statement separator 42 |
;
43 |
45 |
'\n' and :
46 |
End of line comment 51 |
// comment
52 |
54 |
# comment
55 |
Multiple line comment 60 |
/* multiple line
 61 | comment */
62 |
64 |
# Multiple line
 65 | # comment
66 |
Constant 71 |
uint constant TOTAL_SUPPLY = 10000000;
72 |
74 |
TOTAL_SUPPLY: constant(uint256) = 10000000
75 |
Assignment 80 |
v = 1;
81 |
83 |
v = 1
84 |
Parallel assignment 89 |
(x, y) = (0, 1);
90 |
92 |

Tuple to tuple assignment not supported

93 |
Swap 98 |
(x, y) = (y, x);
99 |
101 |

102 |
Compound assignment 107 |
-=, *=, /=, %=, |=, &=, ^=
108 |
110 |
-=, *=, /=, %=, |=, &=, ^=
111 |
Increment and decrement 116 |
i++, ++i, i--, --i
117 |
119 |
i += 1, i -= 1
120 |
Null 125 |

null doesn't exist in Solidity but any unitialized variables take a default value represented by 0 in memory

126 |
128 |

null doesn't exist in Vyper but any unitialized variables take a default value represented by 0 in memory

129 |
Set variable to default value 134 |
delete v // doesn't work with mappings
135 |
137 |
v = empty(uint256)
138 |
Null test 143 |
v == 0
144 |
146 |
v == 0
147 |
Conditional expression 152 |
x > 0 ? x : -x
153 |
155 |

Conditional expression not supported

156 |
Contract lifecycle
FeatureSolidityVyper
Contract creation 169 |
Contract c = new Contract(args);
170 |
172 |

173 |
Contract creation with funding 178 |
Contract c = new Contract{value: amount}(args);
179 |
181 |

182 |
Salted contract creation (CREATE2) 187 |
Contract c = new Contract{salt: salt}(args);
188 |
190 |

191 |
Create forwarder contract 196 |

197 |
199 |
contract: address = create_forwarder_to(other_contract, value)
200 |
Selfdestruct (Avoid) 205 |
selfdestruct(refundAddr)
206 |
208 |
selfdestruct(refund_addr)
209 |
Interfaces
FeatureSolidityVyper
Interfaces 222 |
interface HelloWorld {
223 |     function hello() external pure;
224 |     function world(int) external pure;
225 | }
226 |
228 |
interface HelloWorld:
229 |     def hello(): nonpayable
230 |     def world(uint256): nonpayable
231 |
Interface type 236 |
interface HelloWorldWithEvent {
237 |     event Event();
238 |     function hello() external pure;
239 |     function world(int) external pure;
240 | }
241 | 
242 | contract Test {
243 |     bytes4 public hello_world_with_event = type(HelloWorldWithEvent).interfaceId;
244 | }
245 |
247 |

248 |
Operators
FeatureSolidityVyper
True and false 261 |
true false
262 |
264 |
True False
265 |
Falsehoods 270 |
false
271 |
273 |
False
274 |
Logical operators 279 |
&& || !
280 |
282 |
and or not
283 |
Relational operators 288 |
== != < > <= =>
289 |
291 |
== != < > <= =>
292 |
Min and max 297 |

298 |
300 |
max(x, y)
301 |
Arithmetic operators 306 |
+ - * / % ** unary-
307 |
309 |
+ - * / % ** unary-
310 |
Integer division 315 |
/
316 |
318 |
/
319 |
Bit operators 324 |
<< >> & | ^ ~
325 |
327 |
<< >> & | ^ ~
328 |
Binary & hex literals 333 |
uint x = 0x52
334 | string memory s = hex"52"
335 |
337 |
a: address= 0x14d465376c051Cbcd80Aa2d35Fd5df9910f80543
338 | b: Bytes[32]= b'\x01\x02\x03\x04\x05\x06... (32 bytes)
339 | d: Bytes[1] = 0b00010001
340 |
Data structures
FeatureSolidityVyper
String type 353 |
string
354 |
356 |
String[N]  # N is a fixed number
357 |
Bytes type 362 |
bytes  // dynamic
363 | bytes1, bytes2, ..., bytes32  // packed
364 | bytes[N]  // N is a fixed number, unpacked
365 |
367 |
Bytes[N]  # N is a fixed number
368 |
String literal 373 |
"don't \"no\""
374 | 'don"t \'no\''
375 |
377 |
"don't \"no\""
378 | 'don"t \'no\''
379 |
Unicode literal 384 |
unicode"🍠"
385 |
387 |

388 |
String length 393 |
bytes(s).length
394 |
396 |
len(s)
397 |
String literal escapes 402 |
\<newline> (escapes an actual newline)
403 | \\ (backslash)
404 | \' (single quote)
405 | \" (double quote)
406 | \b (backspace)
407 | \f (form feed)
408 | \n (newline)
409 | \r (carriage return)
410 | \t (tab)
411 | \v (vertical tab)
412 | \xNN (hex escape)
413 | \uNNNN (unicode escape)
414 |
416 |
\<newline> (escapes an actual newline)
417 | \\ (backslash)
418 | \' (single quote)
419 | \" (double quote)
420 | \a (bell)
421 | \b (backspace)
422 | \f (form feed)
423 | \n (newline)
424 | \r (carriage return)
425 | \t (tab)
426 | \v (vertical tab)
427 | \ooo (octal escape)
428 | \xNN (hex escape)
429 | \uNNNN (unicode escape)
430 | \uNNNNNNNN (unicode escape)
431 |
Are strings mutable? 436 |

Yes

437 |
439 |

Yes

440 |
Slice 445 |
abi.decode(_payload[:4], (bytes4))
446 | // array slices only implemented for calldata arrays
447 |
449 |
slice(x, _start, _len)
450 |
String comparison 455 |
keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2))
456 |
458 |
keccak256(s1) == keccak256(s2)
459 |
String concatenation 464 |
abi.encodePacked(s1, s2)
465 |
467 |
concat(s1, s2)
468 |
Array literal 473 |
[1, 2, 3]
474 |
476 |
[1, 2, 3]
477 |
Length 482 |
a.length
483 |
485 |
len(a)
486 |
Empty test 491 |
a.length == 0
492 |
494 |

495 |
Lookup 500 |
a[0]
501 |
503 |
a[0]
504 |
Update 509 |
a[0] = 1;
510 |
512 |
a[0] = 1
513 |
Out of bounds access 518 |

Failing assertion

519 |
521 |

Failing assertion

522 |
Add new element 527 |
a.push(3);  # Dynamic arrays
528 |
530 |

531 |
Remove element 536 |
a.pop();  # Dynamic arrays
537 |
539 |

540 |
Struct 545 |
struct Pair {
546 |     uint x;
547 |     uint y;
548 | }  // Creating a struct
549 | 
550 | Pair memory pair = Pair(2, 3);  // Instantiating a struct variable
551 | require(pair.y > pair.x);  // Accessing elements
552 |
554 |
struct Pair:
555 |     x: uint256
556 |     y: uint256  # Creating a struct
557 | 
558 | pair: Pair = Pair({x: 2, y: 3})  # Instantiating a struct variable
559 | assert pair.y > pair.x  # Accessing elements
560 |
Mapping size 565 |

Impossible to know

566 |
568 |

Impossible to know

569 |
Lookup 574 |
m[2]
575 |
577 |
m[2]
578 |
Update 583 |
m[2] = 1;
584 |
586 |
m[2] = 1
587 |
Missing key behaviour 592 |

A mapping has no concept of set keys, a mapping always refers to a hashed value that is the same for a given mapping and key

593 |
595 |

A mapping has no concept of set keys, a mapping always refers to a hashed value that is the same for a given mapping and key

596 |
Delete key 601 |
m[2] = 0;
602 |
604 |
m[2] = empty(uint256)
605 |
Immutable variables 610 |
uint immutable x; // have to be assigned in the constructor
611 |
613 |

614 |
Functions
FeatureSolidityVyper
Define function 627 |
function add2(uint x, uint y) public pure returns (uint) {
628 |     return x + y;
629 | }
630 |
632 |
@external
633 | def add2(x: uint256, y: uint256) -> uint256:
634 |     return x + y
635 |
Function argument storage location 640 |
function first(uint[] calldata x) public pure returns (uint) {
641 |     // this function doesn't copy x to memory
642 |     return x[0];
643 | }
644 | 
645 | function first(uint[] memory x) public pure returns (uint) {
646 |     // this function first copies x to memory
647 |     return x[0];
648 | }
649 |
651 |

652 |
Invoke function 657 |
add2(x, y)
658 |
660 |
add2(x, y)
661 |
External function calls 666 |
c.f{gas: 1000, value: 4 ether}()
667 |
669 |
c.f()
670 | raw_call(address, data, outsize, gas, value, is_delegate_call)
671 |
Control flow
FeatureSolidityVyper
If statement 684 |
if (a > 2) {
685 |     ...
686 | else if (a == 0) {
687 |     ...
688 | } else {
689 |     ...
690 | }
691 |
693 |
if a > 2:
694 |     ...
695 | elif a == 0:
696 |     ...
697 | else:
698 |     ...
699 |
For loop 704 |
for (uint i = 0; i < 3; i++) {
705 |     ...
706 | }
707 |
709 |
for i in range(3):
710 |     ...
711 |
While loop 716 |
while (a > 0) {
717 |     ...
718 | }
719 |
721 |

722 |
Do-While loop 727 |
do {
728 |     ...
729 | } while (a > 0);
730 |
732 |

733 |
Return value 738 |
return x + y;
739 |
741 |
return x + y
742 |
Break 747 |
break;
748 |
750 |
break
751 |
Continue 756 |
continue;
757 |
759 |
continue
760 |
Assert 765 |
assert(x > y);
766 |
768 |
assert x > y
769 |
Require 774 |
require(x > y);
775 |
777 |

778 |
Revert 783 |
require(false, "revert reason")
784 |
786 |
raise "revert reason"
787 |
Exception handling 792 |
793 | interface DataFeed { function getData(address token) external returns (uint value); }
794 | 
795 | contract FeedConsumer {
796 |     DataFeed feed;
797 |     uint errorCount;
798 |     function rate(address token) public returns (uint value, bool success) {
799 |         // Permanently disable the mechanism if there are
800 |         // more than 10 errors.
801 |         require(errorCount < 10);
802 |         try feed.getData(token) returns (uint v) {
803 |             return (v, true);
804 |         } catch Error(string memory /*reason*/) {
805 |             // This is executed in case
806 |             // revert was called inside getData
807 |             // and a reason string was provided.
808 |             errorCount++;
809 |             return (0, false);
810 |         } catch (bytes memory /*lowLevelData*/) {
811 |             // This is executed in case revert() was used
812 |             // or there was a failing assertion, division
813 |             // by zero, etc. inside getData.
814 |             errorCount++;
815 |             return (0, false);
816 |         }
817 |     }
818 | }
819 |
821 |

822 |
Misc
FeatureSolidityVyper
Comments 835 |
NatSpec conventions for functions:
836 | 
837 | /// @author Mary A. Botanist
838 | /// @notice Calculate tree age in years, rounded up, for live trees
839 | /// @dev The Alexandr N. Tetearing algorithm could increase precision
840 | /// @param rings The number of rings from dendrochronological sample
841 | /// @return age in years, rounded up for partial years
842 | 
843 | Events:
844 | 
845 | /// The address `participant` just registered for the gathering.
846 | event Registered(address participant);
847 | 
848 | Special inheritance syntax for contracts:
849 | 
850 | /// @inheritdoc OtherContract
851 |
853 |
def foo():
854 |     """
855 |     @author Mary A. Botanist
856 |     @notice Calculate tree age in years, rounded up, for live trees
857 |     @dev The Alexandr N. Tetearing algorithm could increase precision
858 |     @param rings The number of rings from dendrochronological sample
859 |     @return age in years, rounded up for partial years
860 |     """
861 |     ...
862 |
Payment with error on failure (Avoid for Solidity) 867 |
address.transfer()
868 |
870 |
send(address, value)
871 |
Payment with false on failure (Avoid for Solidity) 876 |
address.send()
877 |
879 |

880 |
Payment with gas forwarding (WARNING) 885 |

886 |
888 |
raw_call(address, data, outsize, gas, value, is_delegate_call)
889 |
Event logging 894 |
event Deposit(
895 |     address indexed _from,
896 |     bytes32 indexed _id,
897 |     uint _value
898 | );
899 | 
900 | emit Deposit(msg.sender, _id, msg.value);
901 |
903 |
event Deposit:
904 |     _from: indexed(address)
905 |     _id: indexed(bytes32)
906 |     _value: uint256
907 | 
908 | log Deposit(msg.sender, _id, msg.value)
909 |
Units, global constants and type ranges 914 |
1 ether
915 | 1 wei
916 | 1 gwei
917 | 1 seconds
918 | 1 minutes
919 | 1 hours
920 | 1 days
921 | 1 weeks
922 | 1 years  // deprecated
923 | type(uint).min
924 | type(uint).max
925 | type(int8).min
926 | type(int8).max
927 | ...
928 |
930 |
ZERO_ADDRESS
931 | as_wei_value(1, "finney")
932 | as_wei_value(1, "szabo")
933 | as_wei_value(1, "wei")
934 | as_wei_value(1, "babbage")
935 | as_wei_value(1, "shannon")
936 | EMPTY_BYTES32
937 | MAX_INT128
938 | MIN_INT128
939 | MAX_DECIMAL
940 | MIN_DECIMAL
941 | MAX_UINT256
942 | ZERO_WEI
943 |
Block and transaction properties 948 |
blockhash(blockNumber)
949 | block.coinbase
950 | block.difficulty
951 | block.gaslimit
952 | block.number
953 | 
954 | block.timestamp
955 | now  // alias for block.timestamp, deprecated
956 | gasleft()
957 | msg.data
958 | msg.gas
959 | msg.sender
960 | msg.sig
961 | msg.value
962 | tx.gasprice
963 | tx.origin
964 |
966 |
blockhash(blockNumber)
967 | block.coinbase
968 | block.difficulty
969 | 
970 | block.number
971 | block.prevhash  # Same as blockhash(block.number - 1)
972 | block.timestamp
973 | 
974 | 
975 | 
976 | msg.gas
977 | msg.sender
978 | 
979 | msg.value
980 | 
981 | tx.origin
982 |
985 | 986 | 987 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auditless/ethereum-reference/4d4cb661e7ba3b6e55738d1347f4d6f1ae46f8ee/src/__init__.py -------------------------------------------------------------------------------- /src/conftest.py: -------------------------------------------------------------------------------- 1 | """Shared fixtures for doctests.""" 2 | import pytest 3 | from typing import List 4 | from collections import OrderedDict 5 | import logging 6 | 7 | from web3 import Web3, EthereumTesterProvider 8 | import vyper 9 | from solc import compile_files, compile_source 10 | 11 | 12 | @pytest.fixture(autouse=True) 13 | def web3(doctest_namespace): 14 | doctest_namespace["web3"] = Web3(EthereumTesterProvider()) 15 | 16 | 17 | def check_compiles_s(web3: Web3, contract_code: str): 18 | """Check if a Solidity file compiles without running a contract.""" 19 | _ = compile_contracts_s(contract_code) 20 | 21 | 22 | def check_compiles_v(web3: Web3, contract_code: str): 23 | """Check if a Vyper file compiles without running a contract.""" 24 | _ = compile_contracts_v(contract_code) 25 | 26 | 27 | def check_contract_v(web3: Web3, contract_code: str): 28 | """Verify if a given contract compiles in vyper""" 29 | # Compile the code 30 | compiled = compile_specific_vyper_contract(contract_code) 31 | 32 | # Deploy 33 | _test_compiled_snippet(web3, compiled) 34 | 35 | # At this point if there hasn't been an exception, the run is a success 36 | 37 | 38 | def check_contract_s(web3: Web3, contract_code: str): 39 | """Verify if a given contract compiles in solidity""" 40 | # Compile the code 41 | compiled = compile_single_contract(contract_code) 42 | 43 | # Deploy 44 | _test_compiled_snippet(web3, compiled) 45 | 46 | # At this point if there hasn't been an exception, the run is a success 47 | 48 | 49 | def check_named_contract_s(web3: Web3, contract_code: str, name: str): 50 | """Verify if the given named contract compiles in solidity""" 51 | # Compile the code 52 | compiled = compile_named_contract(contract_code, name) 53 | 54 | # Deploy 55 | _test_compiled_snippet(web3, compiled) 56 | 57 | # At this point if there hasn't been an exception, the run is a success 58 | 59 | 60 | def check_local_s(web3: Web3, snippet: str): 61 | """Verify if piece of code compiles if placed in a 62 | constructor function of an empty contract of solidity code""" 63 | 64 | # Build the code using a template 65 | lines = snippet.split("\n") 66 | indented_snippet = ("\n" + " " * 8).join(lines) 67 | code = f"""contract DeployOnly {{ 68 | constructor() public {{ 69 | {indented_snippet} 70 | }} 71 | }} 72 | """ 73 | 74 | check_contract_s(web3, code) 75 | 76 | 77 | def check_local_v(web3: Web3, snippet: str): 78 | """Verify if piece of code compiles if placed in a 79 | constructor function of an empty contract of vyper code""" 80 | 81 | # Build the code using a template 82 | lines = snippet.split("\n") 83 | indented_snippet = ("\n" + " " * 4).join(lines) 84 | code = f""" 85 | @external 86 | def __init__(): 87 | {indented_snippet} 88 | """ 89 | 90 | # Compile the code 91 | compiled = compile_specific_vyper_contract(code) 92 | 93 | # Deploy 94 | _test_compiled_snippet(web3, compiled) 95 | 96 | # At this point if there hasn't been an exception, the run is a success 97 | 98 | 99 | def check_global_s(web3: Web3, snippet: str): 100 | """Verify if piece of code compiles if placed in an 101 | empty solidity contract body""" 102 | 103 | # Build the code using a template 104 | code = f"""contract DeployOnly {{ 105 | {snippet} 106 | constructor() public {{ 107 | }} 108 | }} 109 | """ 110 | 111 | check_contract_s(web3, code) 112 | 113 | 114 | def check_global_constructor_s( 115 | web3: Web3, global_snippet: str, constructor_snippet: str 116 | ): 117 | """Verify if piece of code compiles if placed in an 118 | empty solidity contract body""" 119 | 120 | # Build the code using a template 121 | code = f"""contract DeployOnly {{ 122 | {global_snippet} 123 | constructor() public {{ 124 | {constructor_snippet} 125 | }} 126 | }} 127 | """ 128 | 129 | check_contract_s(web3, code) 130 | 131 | 132 | def check_global_v(web3: Web3, snippet: str): 133 | """Verify if piece of code compiles if placed in an 134 | empty vyper contract body""" 135 | 136 | # Build the code using a template 137 | code = f""" 138 | {snippet} 139 | 140 | @external 141 | def __init__(): 142 | pass 143 | """ 144 | 145 | # Compile the code 146 | compiled = compile_specific_vyper_contract(code) 147 | 148 | # Deploy 149 | _test_compiled_snippet(web3, compiled) 150 | 151 | # At this point if there hasn't been an exception, the run is a success 152 | 153 | 154 | def check_s(web3: Web3, global_snippet: str, local_snippet: str): 155 | """Verify if piece of code compiles if placed in 156 | an empty contract of solidity code""" 157 | 158 | # Build the code using a template 159 | lines = local_snippet.split("\n") 160 | indented_snippet = ("\n" + " " * 8).join(lines) 161 | code = f"""contract DeployOnly {{ 162 | {global_snippet} 163 | constructor() public {{ 164 | {indented_snippet} 165 | }} 166 | }} 167 | """ 168 | 169 | check_contract_s(web3, code) 170 | 171 | 172 | def check_v(web3: Web3, global_snippet: str, local_snippet: str): 173 | """Verify if piece of code compiles if placed in 174 | an empty contract of vyper code""" 175 | 176 | # Build the code using a template 177 | lines = local_snippet.split("\n") 178 | indented_snippet = ("\n" + " " * 4).join(lines) 179 | code = f""" 180 | {global_snippet} 181 | 182 | @external 183 | def __init__(): 184 | {indented_snippet} 185 | """ 186 | 187 | # Compile the code 188 | compiled = compile_specific_vyper_contract(code) 189 | 190 | # Deploy 191 | _test_compiled_snippet(web3, compiled) 192 | 193 | # At this point if there hasn't been an exception, the run is a success 194 | 195 | 196 | def _test_compiled_snippet(web3, compiled): 197 | bytecode = compiled["bin"] 198 | abi = compiled["abi"] 199 | contract = web3.eth.contract(abi=abi, bytecode=bytecode) 200 | tx_hash = contract.constructor().transact() 201 | tx_receipt = web3.eth.waitForTransactionReceipt(tx_hash) 202 | 203 | 204 | def compile_contracts_s(source: str, **compiler_kwargs): 205 | """Compile Solidity source code.""" 206 | return compile_source(source, **compiler_kwargs) 207 | 208 | 209 | def compile_contracts_v(source: str, **compiler_kwargs): 210 | """Compile Vyper source code.""" 211 | return compile_specific_vyper_contract(source) 212 | 213 | 214 | def compile_single_contract(source: str, **compiler_kwargs): 215 | """Compile Solidity source code containing a single contract.""" 216 | # pylint: disable=fixme 217 | # TODO: Add vyper support 218 | compiled_all = compile_source(source, **compiler_kwargs) 219 | if len(list(compiled_all.keys())) > 1: 220 | raise Exception("Can only handle single contracts.") 221 | compiled = compiled_all[next(iter(compiled_all))] 222 | return compiled 223 | 224 | 225 | def compile_named_contract(source: str, name: str, **compiler_kwargs): 226 | """Compile named contract in Solidity source code.""" 227 | # pylint: disable=fixme 228 | # TODO: Add vyper support 229 | compiled_all = compile_source(source, **compiler_kwargs) 230 | for key in compiled_all: 231 | if name in key: 232 | return compiled_all[key] 233 | raise Exception("Named contract not found in compiled artifacts.") 234 | 235 | 236 | def compile_specific_contract(source: str, contract_name: str, **compiler_kwargs): 237 | """Compile Solidity source code with a specific contract.""" 238 | compiled_all = compile_source(source, **compiler_kwargs) 239 | mod_contract_name = f":{contract_name}" 240 | if mod_contract_name not in compiled_all: 241 | raise Exception(f"Contract {contract_name} not in source") 242 | compiled = compiled_all[mod_contract_name] 243 | return compiled 244 | 245 | 246 | def compile_single_contract_from_files( 247 | paths: List[str], contract: str, **compiler_kwargs 248 | ): 249 | """Compile a contract from Solidity or Vyper source files.""" 250 | # Solidity compilation 251 | if str(paths[0]).endswith(".sol"): 252 | compiled_all = compile_files(paths, **compiler_kwargs) 253 | if contract is None: 254 | if len(list(compiled_all.keys())) > 1: 255 | raise Exception( 256 | "Multiple contracts available, " 257 | + "please select a single contract." 258 | ) 259 | return compiled_all[next(iter(compiled_all))] 260 | for key in compiled_all: 261 | if key.endswith(f":{contract}"): 262 | return compiled_all[key] 263 | raise Exception( 264 | f"No contract with name {contract} found in {compiled_all.keys()}" 265 | ) 266 | 267 | # Vyper compilation 268 | codes: OrderedDict = OrderedDict() 269 | for filename in paths: 270 | with open(filename, "r") as code_file: 271 | codes[filename] = code_file.read() 272 | return _compile_vyper_sources(codes, paths[0]) 273 | 274 | 275 | def _compile_vyper_sources(codes, name: str): 276 | """Compile a list of Vyper contracts using the first one.""" 277 | output = vyper.compiler.compile_codes( 278 | codes, 279 | output_formats=["bytecode", "bytecode_runtime", "abi"], 280 | exc_handler=vyper_exc_handler, 281 | ) 282 | contract = output[name] 283 | 284 | # Adapt Vyper output to solc conventional output 285 | result = { 286 | "bin-runtime": contract["bytecode_runtime"][2:], 287 | "bin": contract["bytecode"][2:], 288 | "abi": contract["abi"], 289 | } 290 | return result 291 | 292 | 293 | def compile_specific_vyper_contract(source: str): 294 | """Compile Vyper contract from source str.""" 295 | codes = OrderedDict() 296 | codes["main"] = source 297 | return _compile_vyper_sources(codes, "main") 298 | 299 | 300 | def get_abi(compiled): 301 | """Retrieve ABI from compiled representation.""" 302 | return compiled["abi"] 303 | 304 | 305 | def get_bytecode(compiled): 306 | """Retrieve bytecode from compiled representation. 307 | 308 | Also removes the tail end containing any non-hex characters.""" 309 | raw_bytecode = compiled["bin"] 310 | match = re.search("[^a-f0-9]", raw_bytecode) 311 | if match: 312 | return raw_bytecode[: match.start()] 313 | return raw_bytecode 314 | 315 | 316 | def vyper_exc_handler(contract_name, exception): 317 | """Handle vyper compiler exception.""" 318 | logging.error("Error compiling: %s", contract_name) 319 | raise exception 320 | -------------------------------------------------------------------------------- /src/html.py: -------------------------------------------------------------------------------- 1 | """Tools for building the reference page.""" 2 | 3 | from functools import wraps 4 | 5 | 6 | def code(get_code): 7 | """Add a code cell to a table, used as a decorator.""" 8 | 9 | @wraps(get_code) 10 | def render(doc, tag, text): 11 | with tag("td"): 12 | with tag("pre"): 13 | text(get_code()) 14 | 15 | return render 16 | 17 | 18 | def comment(get_comment): 19 | """Add a comment cell to a table, used as a decorator.""" 20 | 21 | @wraps(get_comment) 22 | def render(doc, tag, text): 23 | with tag("td"): 24 | with tag("p"): 25 | text(get_comment()) 26 | 27 | return render 28 | 29 | 30 | def empty(doc, tag, text): 31 | """Empty cell.""" 32 | with tag("td"): 33 | with tag("p"): 34 | pass 35 | 36 | 37 | def table_section(name): 38 | """New table header row.""" 39 | 40 | def render(doc, tag, text, line): 41 | with tag("tr"): 42 | with tag("th", colspan="3"): 43 | text(name) 44 | with tag("tr"): 45 | line("th", "Feature") 46 | line("th", "Solidity") 47 | line("th", "Vyper") 48 | 49 | return render 50 | -------------------------------------------------------------------------------- /src/main.py: -------------------------------------------------------------------------------- 1 | """Create the reference.""" 2 | 3 | from yattag import Doc, indent 4 | import sh 5 | 6 | from .html import code, comment, empty, table_section 7 | from .conftest import ( 8 | check_local_v, 9 | check_local_s, 10 | check_global_s, 11 | check_global_v, 12 | check_s, 13 | check_v, 14 | check_contract_s, 15 | check_named_contract_s, 16 | check_global_constructor_s, 17 | check_compiles_s, 18 | check_compiles_v, 19 | ) 20 | import solc 21 | 22 | 23 | @code 24 | def version_s(): 25 | """ 26 | >>> str(sh.solc("--version"))[50:64] 27 | 'Version: 0.7.0' 28 | """ 29 | return """$ solc --version 30 | Version: 0.7.0""" 31 | 32 | 33 | @code 34 | def version_v(): 35 | """ 36 | >>> str(sh.vyper("--version"))[:5] 37 | '0.2.4' 38 | """ 39 | return """$ vyper --version 40 | 0.2.4""" 41 | 42 | 43 | @comment 44 | def syntax_s(): 45 | return "Solidity loosely borrows its syntax from Javascript and C" 46 | 47 | 48 | @comment 49 | def syntax_v(): 50 | return "Vyper syntax is valid Python 3 syntax (but the opposite is not true)" 51 | 52 | 53 | @code 54 | def constant_s(): 55 | r""" 56 | >>> check_global_s(web3, "uint constant TOTAL_SUPPLY = 10000000;") 57 | """ 58 | return "uint constant TOTAL_SUPPLY = 10000000;" 59 | 60 | 61 | @code 62 | def constant_v(): 63 | r""" 64 | >>> check_global_v(web3, "TOTAL_SUPPLY: constant(uint256) = 10000000") 65 | """ 66 | return "TOTAL_SUPPLY: constant(uint256) = 10000000" 67 | 68 | 69 | @code 70 | def assignment_s(): 71 | r""" 72 | >>> check_local_s(web3, "uint v; v = 1;") 73 | """ 74 | return "v = 1;" 75 | 76 | 77 | @code 78 | def assignment_v(): 79 | r""" 80 | >>> check_local_v(web3, "v: uint256= 0\nv = 1") 81 | """ 82 | return "v = 1" 83 | 84 | 85 | @code 86 | def par_assignment_s(): 87 | r""" 88 | >>> check_local_s(web3, "uint x; uint y; (x, y) = (0, 1);") 89 | """ 90 | return "(x, y) = (0, 1);" 91 | 92 | 93 | @code 94 | def swap_s(): 95 | r""" 96 | >>> check_local_s(web3, "uint x; uint y; (x, y) = (y, x);") 97 | """ 98 | return "(x, y) = (y, x);" 99 | 100 | 101 | @code 102 | def compound_assignment_s(): 103 | r""" 104 | >>> check_local_s(web3, "uint x = 0; x += 1;") 105 | """ 106 | return "-=, *=, /=, %=, |=, &=, ^=" 107 | 108 | 109 | @code 110 | def increment_decrement_s(): 111 | r""" 112 | >>> check_local_s(web3, "uint i = 0; i++; ++i; i--; --i;") 113 | """ 114 | return "i++, ++i, i--, --i" 115 | 116 | 117 | @code 118 | def increment_decrement_v(): 119 | r""" 120 | >>> check_local_v(web3, "v: uint256= 0\nv += 1\nv -= 1") 121 | """ 122 | return "i += 1, i -= 1" 123 | 124 | 125 | @code 126 | def set_default_s(): 127 | r""" 128 | >>> check_local_s(web3, "uint v = 1; delete v;") 129 | """ 130 | return "delete v // doesn't work with mappings" 131 | 132 | 133 | @code 134 | def set_default_v(): 135 | r""" 136 | >>> check_local_v(web3, "v: uint256= 1\nv = empty(uint256)") 137 | """ 138 | return "v = empty(uint256)" 139 | 140 | 141 | @code 142 | def null_test_s(): 143 | r""" 144 | >>> check_local_s(web3, "uint v; bool b = v == 0;") 145 | """ 146 | return "v == 0" 147 | 148 | 149 | @code 150 | def null_test_v(): 151 | r""" 152 | >>> check_local_v(web3, "v: uint256= 0\nb: bool=v == 0") 153 | """ 154 | return "v == 0" 155 | 156 | 157 | @code 158 | def true_false_s(): 159 | r""" 160 | >>> check_local_s(web3, "bool x = true;") 161 | """ 162 | return "true false" 163 | 164 | 165 | @code 166 | def true_false_v(): 167 | r""" 168 | >>> check_local_v(web3, "x: bool= True") 169 | """ 170 | return "True False" 171 | 172 | 173 | @code 174 | def conditional_expression_s(): 175 | r""" 176 | >>> check_local_s(web3, "uint x; uint v = x > 0 ? x : -x;") 177 | """ 178 | return "x > 0 ? x : -x" 179 | 180 | 181 | @code 182 | def interface_s(): 183 | r""" 184 | >>> check_compiles_s(web3, "interface HelloWorld { function hello() external pure; }\ncontract Test {}") 185 | """ 186 | return """interface HelloWorld { 187 | function hello() external pure; 188 | function world(int) external pure; 189 | }""" 190 | 191 | 192 | @code 193 | def interface_v(): 194 | r""" 195 | >>> check_compiles_v(web3, "interface HelloWorld:\n def hello(): nonpayable\n\n@external\ndef test(addr: address):\n HelloWorld(addr).hello()") 196 | """ 197 | return """interface HelloWorld: 198 | def hello(): nonpayable 199 | def world(uint256): nonpayable""" 200 | 201 | 202 | @code 203 | def interface_type_s(): 204 | r""" 205 | >>> check_compiles_s(web3, "interface HelloWorld { function hello() external pure; }\ncontract Test { bytes4 public hello_world = type(HelloWorld).interfaceId;}") 206 | """ 207 | return """interface HelloWorldWithEvent { 208 | event Event(); 209 | function hello() external pure; 210 | function world(int) external pure; 211 | } 212 | 213 | contract Test { 214 | bytes4 public hello_world_with_event = type(HelloWorldWithEvent).interfaceId; 215 | }""" 216 | 217 | 218 | @code 219 | def min_max_v(): 220 | r""" 221 | >>> check_local_v(web3, "x: uint256= 0\ny: uint256= 0\nz: uint256= max(x, y)") 222 | """ 223 | return "max(x, y)" 224 | 225 | 226 | @code 227 | def binary_hex_literals_s(): 228 | r""" 229 | >>> check_local_s(web3, "uint x = 0x52; string memory s = hex\"52\";") 230 | """ 231 | return 'uint x = 0x52\nstring memory s = hex"52"' 232 | 233 | 234 | @code 235 | def binary_hex_literals_v(): 236 | r""" 237 | >>> check_local_v(web3, "a: address= 0x14d465376c051Cbcd80Aa2d35Fd5df9910f80543") 238 | >>> check_local_v(web3, "b: Bytes[32]= b'\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08'") 239 | 240 | # >>> check_local_v(web3, "c: Bytes[32]= 0x1234567812345678123456781234567812345678123456781234567812345678") 241 | >>> check_local_v(web3, "b: Bytes[1] = 0b00010001") 242 | """ 243 | return ( 244 | "a: address= 0x14d465376c051Cbcd80Aa2d35Fd5df9910f80543\n" 245 | + r"b: Bytes[32]= b'\x01\x02\x03\x04\x05\x06... (32 bytes)" 246 | # + "\n" 247 | # + "c: Bytes[32]= 0x010203040506... (32 bytes)" 248 | + "\n" 249 | + "d: Bytes[1] = 0b00010001" 250 | ) 251 | 252 | 253 | @code 254 | def string_type_s(): 255 | r""" 256 | >>> check_local_s(web3, "string memory s = \"abc\";") 257 | """ 258 | return "string" 259 | 260 | 261 | @code 262 | def string_type_v(): 263 | r""" 264 | >>> check_local_v(web3, "s: String[100]= \"abc\"") 265 | """ 266 | return "String[N] # N is a fixed number" 267 | 268 | 269 | @code 270 | def bytes_type_s(): 271 | return "bytes // dynamic\nbytes1, bytes2, ..., bytes32 // packed\nbytes[N] // N is a fixed number, unpacked" 272 | 273 | 274 | @code 275 | def bytes_type_v(): 276 | r""" 277 | >>> check_local_v(web3, "example_bytes: Bytes[100] = b\"\x01\x02\x03\"") 278 | """ 279 | return "Bytes[N] # N is a fixed number" 280 | 281 | 282 | @code 283 | def string_literal_s(): 284 | r""" 285 | >>> check_local_s(web3, "string memory s = \"don't \\\"no\\\"\";") 286 | >>> check_local_s(web3, "string memory s = 'don\"t \\'no\\'';") 287 | """ 288 | return "\"don't \\\"no\\\"\"\n'don\"t \\'no\\''" 289 | 290 | 291 | @code 292 | def string_literal_v(): 293 | r""" 294 | >>> check_local_v(web3, "s: String[100] = \"don't \\\"no\\\"\"") 295 | >>> check_local_v(web3, "s: String[100] = 'don\"t \\'no\\''") 296 | """ 297 | return "\"don't \\\"no\\\"\"\n'don\"t \\'no\\''" 298 | 299 | @code 300 | def unicode_literal_s(): 301 | r""" 302 | >>> check_local_s(web3, "string memory s = unicode\"🍠\";") 303 | """ 304 | return "unicode\"🍠\"" 305 | 306 | @code 307 | def string_length_s(): 308 | r""" 309 | >>> check_local_s(web3, "string memory s = \"abc\"; require(bytes(s).length == 3);") 310 | """ 311 | return "bytes(s).length" 312 | 313 | 314 | @code 315 | def string_length_v(): 316 | r""" 317 | >>> check_local_v(web3, "s: String[100] = \"abc\"\nassert len(s) == 3") 318 | """ 319 | return "len(s)" 320 | 321 | 322 | @code 323 | def string_literal_escapes_s(): 324 | r""" 325 | >>> check_local_s(web3, "string memory s = \"\\\\ \\\'\\\"\\b\\f\";") 326 | >>> check_local_s(web3, "string memory s = \"\\n \\r \\t \\v \\x01 \\u0001\";") 327 | """ 328 | return r"""\ (escapes an actual newline) 329 | \\ (backslash) 330 | \' (single quote) 331 | \" (double quote) 332 | \b (backspace) 333 | \f (form feed) 334 | \n (newline) 335 | \r (carriage return) 336 | \t (tab) 337 | \v (vertical tab) 338 | \xNN (hex escape) 339 | \uNNNN (unicode escape)""" 340 | 341 | 342 | @code 343 | def string_literal_escapes_v(): 344 | r""" 345 | >>> check_local_v(web3, "s: String[100]= \"\\\\ \\\'\\\"\\b\\f \\a\"") 346 | >>> check_local_v(web3, "s: String[100]= \"\\n \\r \\t \\v \\x01 \\u0001\"") 347 | >>> check_local_v(web3, "s: String[100]= \"\\u00010001\"") 348 | """ 349 | return r"""\ (escapes an actual newline) 350 | \\ (backslash) 351 | \' (single quote) 352 | \" (double quote) 353 | \a (bell) 354 | \b (backspace) 355 | \f (form feed) 356 | \n (newline) 357 | \r (carriage return) 358 | \t (tab) 359 | \v (vertical tab) 360 | \ooo (octal escape) 361 | \xNN (hex escape) 362 | \uNNNN (unicode escape) 363 | \uNNNNNNNN (unicode escape)""" 364 | 365 | 366 | @code 367 | def slice_s(): 368 | r""" 369 | >>> check_contract_s(web3, ''' 370 | ... contract Proxy { 371 | ... function decode(bytes calldata _payload) external { 372 | ... bytes4 sig = abi.decode(_payload[:4], (bytes4)); 373 | ... } 374 | ... }''') 375 | """ 376 | return "abi.decode(_payload[:4], (bytes4))\n// array slices only implemented for calldata arrays" 377 | 378 | 379 | @code 380 | def slice_v(): 381 | r""" 382 | >>> check_local_v(web3, "b: Bytes[100] = b\"\x01\x02\x03\"\nassert len(slice(b, 0, 2)) == 2") 383 | """ 384 | return "slice(x, _start, _len)" 385 | 386 | 387 | @code 388 | def string_comparison_s(): 389 | r""" 390 | >>> check_local_s(web3, "require(keccak256(abi.encodePacked(\"abc\")) == keccak256(abi.encodePacked(\"abc\")));") 391 | """ 392 | return "keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2))" 393 | 394 | 395 | @code 396 | def string_comparison_v(): 397 | r""" 398 | >>> check_local_v(web3, "assert keccak256(\"abc\") == keccak256(\"abc\")") 399 | """ 400 | return "keccak256(s1) == keccak256(s2)" 401 | 402 | 403 | @code 404 | def string_concatenation_s(): 405 | r""" 406 | Read more here: https://solidity.readthedocs.io/en/v0.5.3/frequently-asked-questions.html?highlight=encodepacked#can-i-concatenate-two-strings 407 | >>> check_local_s(web3, "require(keccak256(abi.encodePacked(\"ab\", \"c\")) == keccak256(abi.encodePacked(\"abc\")));") 408 | """ 409 | return "abi.encodePacked(s1, s2)" 410 | 411 | 412 | @code 413 | def string_concatenation_v(): 414 | r""" 415 | >>> check_local_v(web3, "assert keccak256(concat(\"ab\", \"c\")) == keccak256(\"abc\")") 416 | """ 417 | return "concat(s1, s2)" 418 | 419 | 420 | @code 421 | def array_literal_s(): 422 | r""" 423 | >>> check_local_s(web3, "uint8[3] memory a = [1, 2, 3]; a[0] = 2; require(a.length == 3);") 424 | """ 425 | return "[1, 2, 3]" 426 | 427 | 428 | @code 429 | def array_literal_v(): 430 | r""" 431 | >>> check_local_v(web3, "a: uint256[3] = [1, 2, 3]\na[0] = 2") 432 | """ 433 | return "[1, 2, 3]" 434 | 435 | 436 | @code 437 | def struct_s(): 438 | r""" 439 | >>> check_s(web3, "struct Pair { uint x; uint y; }", "Pair memory pair = Pair(2, 3); require(pair.y > pair.x);") 440 | """ 441 | return """struct Pair { 442 | uint x; 443 | uint y; 444 | } // Creating a struct 445 | 446 | Pair memory pair = Pair(2, 3); // Instantiating a struct variable 447 | require(pair.y > pair.x); // Accessing elements""" 448 | 449 | 450 | @code 451 | def struct_v(): 452 | r""" 453 | >>> check_v(web3, "struct Pair:\n x: uint256\n y: uint256", "pair: Pair = Pair({x: 2, y: 3})\nassert pair.y > pair.x") 454 | """ 455 | return """struct Pair: 456 | x: uint256 457 | y: uint256 # Creating a struct 458 | 459 | pair: Pair = Pair({x: 2, y: 3}) # Instantiating a struct variable 460 | assert pair.y > pair.x # Accessing elements""" 461 | 462 | 463 | @code 464 | def mapping_delete_v(): 465 | r""" 466 | >>> check_v(web3, "m: HashMap[uint256, uint256]", "self.m[2] = 2\nself.m[2] = empty(uint256)") 467 | """ 468 | return "m[2] = empty(uint256)" 469 | 470 | 471 | @code 472 | def immutable_s(): 473 | r""" 474 | >>> check_global_constructor_s(web3, "uint immutable x;", "x = 1;") 475 | """ 476 | return """uint immutable x; // have to be assigned in the constructor""" 477 | 478 | 479 | @code 480 | def define_f_s(): 481 | r""" 482 | >>> check_global_s(web3, "function add2(uint x, uint y) public pure returns (uint) { return x + y; }") 483 | """ 484 | return """function add2(uint x, uint y) public pure returns (uint) { 485 | return x + y; 486 | }""" 487 | 488 | 489 | @code 490 | def function_argument_storage_location_s(): 491 | r""" 492 | >>> check_global_s(web3, "function first(uint[] calldata x) public pure returns (uint) { return x[0]; }") 493 | >>> check_global_s(web3, "function first(uint[] memory x) public pure returns (uint) { return x[0]; }") 494 | """ 495 | return """function first(uint[] calldata x) public pure returns (uint) { 496 | // this function doesn't copy x to memory 497 | return x[0]; 498 | } 499 | 500 | function first(uint[] memory x) public pure returns (uint) { 501 | // this function first copies x to memory 502 | return x[0]; 503 | }""" 504 | 505 | 506 | @code 507 | def define_f_v(): 508 | r""" 509 | >>> check_global_v(web3, "@external\ndef add2(x: uint256, y: uint256) -> uint256:\n return x + y") 510 | """ 511 | return """@external 512 | def add2(x: uint256, y: uint256) -> uint256: 513 | return x + y""" 514 | 515 | 516 | @code 517 | def if_s(): 518 | r""" 519 | >>> check_local_s(web3, "uint a = 3; if (a > 2) { a += 1; } else { a -= 1; }") 520 | """ 521 | return """if (a > 2) { 522 | ... 523 | else if (a == 0) { 524 | ... 525 | } else { 526 | ... 527 | }""" 528 | 529 | 530 | @code 531 | def if_v(): 532 | r""" 533 | >>> check_local_v(web3, "a: uint256 = 3\nif a > 2:\n a += 1\nelse:\n a -= 1") 534 | """ 535 | return """if a > 2: 536 | ... 537 | elif a == 0: 538 | ... 539 | else: 540 | ...""" 541 | 542 | 543 | @code 544 | def for_s(): 545 | r""" 546 | >>> check_local_s(web3, "uint a = 3; for (uint i = 0; i < 3; i++) { a += 1; }") 547 | """ 548 | return """for (uint i = 0; i < 3; i++) { 549 | ... 550 | }""" 551 | 552 | 553 | @code 554 | def for_v(): 555 | r""" 556 | >>> check_local_v(web3, "a: uint256 = 3\nfor i in range(3):\n a += 1") 557 | """ 558 | return """for i in range(3): 559 | ...""" 560 | 561 | 562 | @code 563 | def while_s(): 564 | r""" 565 | >>> check_local_s(web3, "uint a = 3; while (a > 0) { a--; }") 566 | """ 567 | return """while (a > 0) { 568 | ... 569 | }""" 570 | 571 | 572 | @code 573 | def do_while_s(): 574 | r""" 575 | >>> check_local_s(web3, "uint a = 3; do { a--; } while (a > 0);") 576 | """ 577 | return """do { 578 | ... 579 | } while (a > 0);""" 580 | 581 | 582 | @code 583 | def exceptions_s(): 584 | r""" 585 | >>> check_named_contract_s(web3, ''' 586 | ... interface DataFeed { function getData(address token) external returns (uint value); } 587 | ... contract FeedConsumer { 588 | ... DataFeed feed; 589 | ... uint errorCount; 590 | ... function rate(address token) public returns (uint value, bool success) { 591 | ... require(errorCount < 10); 592 | ... try feed.getData(token) returns (uint v) { 593 | ... return (v, true); 594 | ... } catch Error(string memory) { 595 | ... errorCount++; 596 | ... return (0, false); 597 | ... } catch (bytes memory) { 598 | ... errorCount++; 599 | ... return (0, false); 600 | ... } 601 | ... } 602 | ... }\n''', "FeedConsumer") 603 | """ 604 | return """ 605 | interface DataFeed { function getData(address token) external returns (uint value); } 606 | 607 | contract FeedConsumer { 608 | DataFeed feed; 609 | uint errorCount; 610 | function rate(address token) public returns (uint value, bool success) { 611 | // Permanently disable the mechanism if there are 612 | // more than 10 errors. 613 | require(errorCount < 10); 614 | try feed.getData(token) returns (uint v) { 615 | return (v, true); 616 | } catch Error(string memory /*reason*/) { 617 | // This is executed in case 618 | // revert was called inside getData 619 | // and a reason string was provided. 620 | errorCount++; 621 | return (0, false); 622 | } catch (bytes memory /*lowLevelData*/) { 623 | // This is executed in case revert() was used 624 | // or there was a failing assertion, division 625 | // by zero, etc. inside getData. 626 | errorCount++; 627 | return (0, false); 628 | } 629 | } 630 | }""" 631 | 632 | 633 | def render() -> str: 634 | """Render the final page.""" 635 | doc, tag, text, line = Doc().ttl() 636 | trip = [doc, tag, text] 637 | quad = [doc, tag, text, line] 638 | 639 | # Final reference doc 640 | with tag("html"): 641 | with tag("body"): 642 | with tag("table"): 643 | with tag("tr"): 644 | line("th", "Feature") 645 | line("th", "Solidity") 646 | line("th", "Vyper") 647 | with tag("tr"): 648 | line("th", "Version") 649 | version_s(*trip) 650 | version_v(*trip) 651 | with tag("tr"): 652 | line("th", "General notes on syntax") 653 | syntax_s(*trip) 654 | syntax_v(*trip) 655 | with tag("tr"): 656 | line("th", "Block delimiters") 657 | code(lambda: "{ }")(*trip) 658 | code(lambda: ": # Vyper uses Python's off-side rule")(*trip) 659 | with tag("tr"): 660 | line("th", "Statement separator") 661 | code(lambda: ";")(*trip) 662 | code(lambda: "'\\n' and :")(*trip) 663 | with tag("tr"): 664 | line("th", "End of line comment") 665 | code(lambda: "// comment")(*trip) 666 | code(lambda: "# comment")(*trip) 667 | with tag("tr"): 668 | line("th", "Multiple line comment") 669 | code(lambda: "/* multiple line\ncomment */")(*trip) 670 | code(lambda: "# Multiple line\n# comment")(*trip) 671 | with tag("tr"): 672 | line("th", "Constant") 673 | constant_s(*trip) 674 | constant_v(*trip) 675 | with tag("tr"): 676 | line("th", "Assignment") 677 | assignment_s(*trip) 678 | assignment_v(*trip) 679 | with tag("tr"): 680 | line("th", "Parallel assignment") 681 | par_assignment_s(*trip) 682 | comment(lambda: "Tuple to tuple assignment not supported")(*trip) 683 | with tag("tr"): 684 | line("th", "Swap") 685 | swap_s(*trip) 686 | empty(*trip) 687 | with tag("tr"): 688 | line("th", "Compound assignment") 689 | compound_assignment_s(*trip) 690 | code(lambda: "-=, *=, /=, %=, |=, &=, ^=")(*trip) 691 | with tag("tr"): 692 | line("th", "Increment and decrement") 693 | increment_decrement_s(*trip) 694 | increment_decrement_v(*trip) 695 | with tag("tr"): 696 | line("th", "Null") 697 | comment( 698 | lambda: "null doesn't exist in Solidity but any unitialized variables take a default value represented by 0 in memory" 699 | )(*trip) 700 | comment( 701 | lambda: "null doesn't exist in Vyper but any unitialized variables take a default value represented by 0 in memory" 702 | )(*trip) 703 | with tag("tr"): 704 | line("th", "Set variable to default value") 705 | set_default_s(*trip) 706 | set_default_v(*trip) 707 | with tag("tr"): 708 | line("th", "Null test") 709 | null_test_s(*trip) 710 | null_test_v(*trip) 711 | with tag("tr"): 712 | line("th", "Conditional expression") 713 | conditional_expression_s(*trip) 714 | comment(lambda: "Conditional expression not supported")(*trip) 715 | 716 | table_section("Contract lifecycle")(*quad) 717 | with tag("tr"): 718 | line("th", "Contract creation") 719 | code(lambda: "Contract c = new Contract(args);")(*trip) 720 | empty(*trip) 721 | with tag("tr"): 722 | line("th", "Contract creation with funding") 723 | code(lambda: "Contract c = new Contract{value: amount}(args);")( 724 | *trip 725 | ) 726 | empty(*trip) 727 | with tag("tr"): 728 | line("th", "Salted contract creation (CREATE2)") 729 | code(lambda: "Contract c = new Contract{salt: salt}(args);")(*trip) 730 | empty(*trip) 731 | with tag("tr"): 732 | line("th", "Create forwarder contract") 733 | empty(*trip) 734 | code( 735 | lambda: "contract: address = create_forwarder_to(other_contract, value)" 736 | )(*trip) 737 | with tag("tr"): 738 | line("th", "Selfdestruct (Avoid)") 739 | code(lambda: "selfdestruct(refundAddr)")(*trip) 740 | code(lambda: "selfdestruct(refund_addr)")(*trip) 741 | 742 | table_section("Interfaces")(*quad) 743 | with tag("tr"): 744 | line("th", "Interfaces") 745 | interface_s(*trip) 746 | interface_v(*trip) 747 | with tag("tr"): 748 | line("th", "Interface type") 749 | interface_type_s(*trip) 750 | empty(*trip) 751 | 752 | table_section("Operators")(*quad) 753 | with tag("tr"): 754 | line("th", "True and false") 755 | true_false_s(*trip) 756 | true_false_v(*trip) 757 | with tag("tr"): 758 | line("th", "Falsehoods") 759 | code(lambda: "false")(*trip) 760 | code(lambda: "False")(*trip) 761 | with tag("tr"): 762 | line("th", "Logical operators") 763 | code(lambda: "&& || !")(*trip) 764 | code(lambda: "and or not")(*trip) 765 | with tag("tr"): 766 | line("th", "Relational operators") 767 | code(lambda: "== != < > <= =>")(*trip) 768 | code(lambda: "== != < > <= =>")(*trip) 769 | with tag("tr"): 770 | line("th", "Min and max") 771 | empty(*trip) 772 | min_max_v(*trip) 773 | with tag("tr"): 774 | line("th", "Arithmetic operators") 775 | code(lambda: "+ - * / % ** unary-")(*trip) 776 | code(lambda: "+ - * / % ** unary-")(*trip) 777 | with tag("tr"): 778 | line("th", "Integer division") 779 | code(lambda: "/")(*trip) 780 | code(lambda: "/")(*trip) 781 | with tag("tr"): 782 | line("th", "Bit operators") 783 | code(lambda: "<< >> & | ^ ~")(*trip) 784 | code(lambda: "<< >> & | ^ ~")(*trip) 785 | with tag("tr"): 786 | line("th", "Binary & hex literals") 787 | binary_hex_literals_s(*trip) 788 | binary_hex_literals_v(*trip) 789 | table_section("Data structures")(*quad) 790 | with tag("tr"): 791 | line("th", "String type") 792 | string_type_s(*trip) 793 | string_type_v(*trip) 794 | with tag("tr"): 795 | line("th", "Bytes type") 796 | bytes_type_s(*trip) 797 | bytes_type_v(*trip) 798 | with tag("tr"): 799 | line("th", "String literal") 800 | string_literal_s(*trip) 801 | string_literal_v(*trip) 802 | with tag("tr"): 803 | line("th", "Unicode literal") 804 | unicode_literal_s(*trip) 805 | empty(*trip) 806 | with tag("tr"): 807 | line("th", "String length") 808 | string_length_s(*trip) 809 | string_length_v(*trip) 810 | with tag("tr"): 811 | line("th", "String literal escapes") 812 | string_literal_escapes_s(*trip) 813 | string_literal_escapes_v(*trip) 814 | with tag("tr"): 815 | line("th", "Are strings mutable?") 816 | comment(lambda: "Yes")(*trip) 817 | comment(lambda: "Yes")(*trip) 818 | with tag("tr"): 819 | line("th", "Slice") 820 | slice_s(*trip) 821 | slice_v(*trip) 822 | with tag("tr"): 823 | line("th", "String comparison") 824 | string_comparison_s(*trip) 825 | string_comparison_v(*trip) 826 | with tag("tr"): 827 | line("th", "String concatenation") 828 | string_concatenation_s(*trip) 829 | string_concatenation_v(*trip) 830 | with tag("tr"): 831 | line("th", "Array literal") 832 | array_literal_s(*trip) 833 | array_literal_v(*trip) 834 | with tag("tr"): 835 | line("th", "Length") 836 | code(lambda: "a.length")(*trip) 837 | code(lambda: "len(a)")(*trip) 838 | with tag("tr"): 839 | line("th", "Empty test") 840 | code(lambda: "a.length == 0")(*trip) 841 | empty(*trip) 842 | with tag("tr"): 843 | line("th", "Lookup") 844 | code(lambda: "a[0]")(*trip) 845 | code(lambda: "a[0]")(*trip) 846 | with tag("tr"): 847 | line("th", "Update") 848 | code(lambda: "a[0] = 1;")(*trip) 849 | code(lambda: "a[0] = 1")(*trip) 850 | with tag("tr"): 851 | line("th", "Out of bounds access") 852 | comment(lambda: "Failing assertion")(*trip) 853 | comment(lambda: "Failing assertion")(*trip) 854 | with tag("tr"): 855 | line("th", "Add new element") 856 | code(lambda: "a.push(3); # Dynamic arrays")(*trip) 857 | empty(*trip) 858 | with tag("tr"): 859 | line("th", "Remove element") 860 | code(lambda: "a.pop(); # Dynamic arrays")(*trip) 861 | empty(*trip) 862 | with tag("tr"): 863 | line("th", "Struct") 864 | struct_s(*trip) 865 | struct_v(*trip) 866 | with tag("tr"): 867 | line("th", "Mapping size") 868 | comment(lambda: "Impossible to know")(*trip) 869 | comment(lambda: "Impossible to know")(*trip) 870 | with tag("tr"): 871 | line("th", "Lookup") 872 | code(lambda: "m[2]")(*trip) 873 | code(lambda: "m[2]")(*trip) 874 | with tag("tr"): 875 | line("th", "Update") 876 | code(lambda: "m[2] = 1;")(*trip) 877 | code(lambda: "m[2] = 1")(*trip) 878 | with tag("tr"): 879 | line("th", "Missing key behaviour") 880 | comment( 881 | lambda: "A mapping has no concept of set keys, a mapping always refers to a hashed value that is the same for a given mapping and key" 882 | )(*trip) 883 | comment( 884 | lambda: "A mapping has no concept of set keys, a mapping always refers to a hashed value that is the same for a given mapping and key" 885 | )(*trip) 886 | with tag("tr"): 887 | line("th", "Delete key") 888 | code(lambda: "m[2] = 0;")(*trip) 889 | mapping_delete_v(*trip) 890 | with tag("tr"): 891 | line("th", "Immutable variables") 892 | immutable_s(*trip) 893 | empty(*trip) 894 | table_section("Functions")(*quad) 895 | with tag("tr"): 896 | line("th", "Define function") 897 | define_f_s(*trip) 898 | define_f_v(*trip) 899 | with tag("tr"): 900 | line("th", "Function argument storage location") 901 | function_argument_storage_location_s(*trip) 902 | empty(*trip) 903 | with tag("tr"): 904 | line("th", "Invoke function") 905 | code(lambda: "add2(x, y)")(*trip) 906 | code(lambda: "add2(x, y)")(*trip) 907 | with tag("tr"): 908 | line("th", "External function calls") 909 | code(lambda: "c.f{gas: 1000, value: 4 ether}()")(*trip) 910 | code( 911 | lambda: "c.f()\nraw_call(address, data, outsize, gas, value, is_delegate_call)" 912 | )(*trip) 913 | table_section("Control flow")(*quad) 914 | with tag("tr"): 915 | line("th", "If statement") 916 | if_s(*trip) 917 | if_v(*trip) 918 | with tag("tr"): 919 | line("th", "For loop") 920 | for_s(*trip) 921 | for_v(*trip) 922 | with tag("tr"): 923 | line("th", "While loop") 924 | while_s(*trip) 925 | empty(*trip) 926 | with tag("tr"): 927 | line("th", "Do-While loop") 928 | do_while_s(*trip) 929 | empty(*trip) 930 | with tag("tr"): 931 | line("th", "Return value") 932 | code(lambda: "return x + y;")(*trip) 933 | code(lambda: "return x + y")(*trip) 934 | with tag("tr"): 935 | line("th", "Break") 936 | code(lambda: "break;")(*trip) 937 | code(lambda: "break")(*trip) 938 | with tag("tr"): 939 | line("th", "Continue") 940 | code(lambda: "continue;")(*trip) 941 | code(lambda: "continue")(*trip) 942 | with tag("tr"): 943 | line("th", "Assert") 944 | code(lambda: "assert(x > y);")(*trip) 945 | code(lambda: "assert x > y")(*trip) 946 | with tag("tr"): 947 | line("th", "Require") 948 | code(lambda: "require(x > y);")(*trip) 949 | empty(*trip) 950 | with tag("tr"): 951 | line("th", "Revert") 952 | code(lambda: 'require(false, "revert reason")')(*trip) 953 | code(lambda: 'raise "revert reason"')(*trip) 954 | with tag("tr"): 955 | line("th", "Exception handling") 956 | exceptions_s(*trip) 957 | empty(*trip) 958 | table_section("Misc")(*quad) 959 | with tag("tr"): 960 | line("th", "Comments") 961 | code( 962 | lambda: """NatSpec conventions for functions: 963 | 964 | /// @author Mary A. Botanist 965 | /// @notice Calculate tree age in years, rounded up, for live trees 966 | /// @dev The Alexandr N. Tetearing algorithm could increase precision 967 | /// @param rings The number of rings from dendrochronological sample 968 | /// @return age in years, rounded up for partial years 969 | 970 | Events: 971 | 972 | /// The address `participant` just registered for the gathering. 973 | event Registered(address participant); 974 | 975 | Special inheritance syntax for contracts: 976 | 977 | /// @inheritdoc OtherContract""" 978 | )(*trip) 979 | code( 980 | lambda: """def foo(): 981 | \"\"\" 982 | @author Mary A. Botanist 983 | @notice Calculate tree age in years, rounded up, for live trees 984 | @dev The Alexandr N. Tetearing algorithm could increase precision 985 | @param rings The number of rings from dendrochronological sample 986 | @return age in years, rounded up for partial years 987 | \"\"\" 988 | ...""" 989 | )(*trip) 990 | with tag("tr"): 991 | line("th", "Payment with error on failure (Avoid for Solidity)") 992 | code(lambda: "address.transfer()")(*trip) 993 | code(lambda: "send(address, value)")(*trip) 994 | with tag("tr"): 995 | line("th", "Payment with false on failure (Avoid for Solidity)") 996 | code(lambda: "address.send()")(*trip) 997 | empty(*trip) 998 | with tag("tr"): 999 | line("th", "Payment with gas forwarding (WARNING)") 1000 | empty(*trip) 1001 | code( 1002 | lambda: "raw_call(address, data, outsize, gas, value, is_delegate_call)" 1003 | )(*trip) 1004 | with tag("tr"): 1005 | line("th", "Event logging") 1006 | code( 1007 | lambda: """event Deposit( 1008 | address indexed _from, 1009 | bytes32 indexed _id, 1010 | uint _value 1011 | ); 1012 | 1013 | emit Deposit(msg.sender, _id, msg.value);""" 1014 | )(*trip) 1015 | code( 1016 | lambda: """event Deposit: 1017 | _from: indexed(address) 1018 | _id: indexed(bytes32) 1019 | _value: uint256 1020 | 1021 | log Deposit(msg.sender, _id, msg.value)""" 1022 | )(*trip) 1023 | with tag("tr"): 1024 | line("th", "Units, global constants and type ranges") 1025 | code( 1026 | lambda: """1 ether 1027 | 1 wei 1028 | 1 gwei 1029 | 1 seconds 1030 | 1 minutes 1031 | 1 hours 1032 | 1 days 1033 | 1 weeks 1034 | 1 years // deprecated 1035 | type(uint).min 1036 | type(uint).max 1037 | type(int8).min 1038 | type(int8).max 1039 | ...""" 1040 | )(*trip) 1041 | code( 1042 | lambda: """ZERO_ADDRESS 1043 | as_wei_value(1, "finney") 1044 | as_wei_value(1, "szabo") 1045 | as_wei_value(1, "wei") 1046 | as_wei_value(1, "babbage") 1047 | as_wei_value(1, "shannon") 1048 | EMPTY_BYTES32 1049 | MAX_INT128 1050 | MIN_INT128 1051 | MAX_DECIMAL 1052 | MIN_DECIMAL 1053 | MAX_UINT256 1054 | ZERO_WEI""" 1055 | )(*trip) 1056 | with tag("tr"): 1057 | line("th", "Block and transaction properties") 1058 | code( 1059 | lambda: """blockhash(blockNumber) 1060 | block.coinbase 1061 | block.difficulty 1062 | block.gaslimit 1063 | block.number 1064 | 1065 | block.timestamp 1066 | now // alias for block.timestamp, deprecated 1067 | gasleft() 1068 | msg.data 1069 | msg.gas 1070 | msg.sender 1071 | msg.sig 1072 | msg.value 1073 | tx.gasprice 1074 | tx.origin""" 1075 | )(*trip) 1076 | code( 1077 | lambda: """blockhash(blockNumber) 1078 | block.coinbase 1079 | block.difficulty 1080 | 1081 | block.number 1082 | block.prevhash # Same as blockhash(block.number - 1) 1083 | block.timestamp 1084 | 1085 | 1086 | 1087 | msg.gas 1088 | msg.sender 1089 | 1090 | msg.value 1091 | 1092 | tx.origin""" 1093 | )(*trip) 1094 | 1095 | # Prettify the HTML 1096 | unindented = doc.getvalue() 1097 | return indent(unindented) 1098 | 1099 | 1100 | if __name__ == "__main__": 1101 | print(render()) 1102 | --------------------------------------------------------------------------------